Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
236 lines (191 sloc) 6.97 KB
#!/usr/bin/env python2
# libmypaint - The MyPaint Brush Library
# Copyright (C) 2007-2012 Martin Renold <martinxyz@gmx.ch>
# Copyright (C) 2012-2016 by the MyPaint Development Team.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"Code generator, part of the build process."
from __future__ import absolute_import, division, print_function
import os
import sys
from os.path import basename
import json
from collections import namedtuple
_SETTINGS = [] # brushsettings.settings
_SETTING_ORDER = [
"internal_name", # cname
"displayed_name", # name
"constant",
"minimum", # min
"default",
"maximum", # max
"tooltip",
]
_INPUTS = [] # brushsettings.inputs
_INPUT_ORDER = [
"id", # name
"hard_minimum", # hard_min
"soft_minimum", # soft_min
"normal",
"soft_maximum", # soft_max
"hard_maximum", # hard_max
"displayed_name", # dname
"tooltip",
]
_STATES = [] # brushsettings.states
class _BrushSetting (namedtuple("_BrushSetting", _SETTING_ORDER)):
def validate(self):
msg = "Failed to validate %s: %r" % (self.internal_name, self)
if self.minimum and self.maximum:
assert (self.minimum <= self.default), msg
assert (self.maximum >= self.default), msg
assert (self.minimum < self.maximum), msg
assert self.default is not None
class _BrushInput (namedtuple("_BrushInput", _INPUT_ORDER)):
def validate(self):
msg = "Failed to validate %s: %r" % (self.id, self)
if self.hard_maximum is not None:
assert (self.hard_maximum >= self.soft_maximum), msg
assert (self.hard_maximum >= self.normal), msg
if self.hard_minimum is not None:
assert (self.hard_minimum <= self.soft_minimum), msg
assert (self.hard_minimum <= self.normal), msg
if None not in (self.hard_maximum, self.hard_minimum):
assert (self.hard_minimum < self.hard_maximum), msg
assert self.normal is not None
assert (self.soft_minimum < self.soft_maximum), msg
assert (self.soft_minimum <= self.normal), msg
assert (self.soft_maximum >= self.normal), msg
def _init_globals_from_json(filename):
"""Populate global variables above from the canonical JSON definition."""
with open(filename, "rb") as fp:
defs = json.load(fp)
for input_def in defs["inputs"]:
input = _BrushInput(**input_def)
input.validate()
_INPUTS.append(input)
for setting_def in defs["settings"]:
setting = _BrushSetting(**setting_def)
setting.validate()
_SETTINGS.append(setting)
for state_name in defs["states"]:
_STATES.append(state_name)
def writefile(filename, s):
"""Write generated code if changed."""
bn = basename(sys.argv[0])
s = '// DO NOT EDIT - autogenerated by ' + bn + '\n\n' + s
if os.path.exists(filename) and open(filename).read() == s:
print('Checked {}: up to date, not rewritten'.format(filename))
else:
print('Writing {}'.format(filename))
open(filename, 'w').write(s)
def generate_enum(enum_name, enum_prefix, count_name, items):
indent = " " * 4
begin = "typedef enum {\n"
end = "} %s;\n" % enum_name
entries = []
for idx, name in items:
entries.append(indent + enum_prefix + name)
entries.append(indent + count_name)
return begin + ",\n".join(entries) + "\n" + end
def generate_static_struct_array(struct_type, instance_name, entries_list):
indent = " " * 4
begin = "static %s %s[] = {\n" % (struct_type, instance_name)
end = "};\n"
entries = []
for entry in entries_list:
entries.append(indent + "{%s}" % (", ".join(entry)))
entries.append("\n")
return begin + ", \n".join(entries) + end
def stringify(value):
value = value.replace("\n", "\\n")
value = value.replace('"', '\\"')
return "\"%s\"" % value
def floatify(value, positive_inf=True):
if value is None:
return "FLT_MAX" if positive_inf else "-FLT_MAX"
return str(value)
def gettextify(value):
return "N_(%s)" % stringify(value)
def boolify(value):
return str("TRUE") if value else str("FALSE")
def input_info_struct(i):
return (
stringify(i.id),
floatify(i.hard_minimum, positive_inf=False),
floatify(i.soft_minimum, positive_inf=False),
floatify(i.normal),
floatify(i.soft_maximum),
floatify(i.hard_maximum),
gettextify(i.displayed_name),
gettextify(i.tooltip),
)
def settings_info_struct(s):
return (
stringify(s.internal_name),
gettextify(s.displayed_name),
boolify(s.constant),
floatify(s.minimum, positive_inf=False),
floatify(s.default),
floatify(s.maximum),
gettextify(s.tooltip),
)
def generate_internal_settings_code():
content = ''
content += generate_static_struct_array(
"MyPaintBrushSettingInfo",
"settings_info_array",
[settings_info_struct(i) for i in _SETTINGS],
)
content += "\n"
content += generate_static_struct_array(
"MyPaintBrushInputInfo",
"inputs_info_array",
[input_info_struct(i) for i in _INPUTS],
)
return content
def generate_public_settings_code():
content = ''
content += generate_enum(
"MyPaintBrushInput",
"MYPAINT_BRUSH_INPUT_",
"MYPAINT_BRUSH_INPUTS_COUNT",
enumerate([i.id.upper() for i in _INPUTS]),
)
content += '\n'
content += generate_enum(
"MyPaintBrushSetting",
"MYPAINT_BRUSH_SETTING_",
"MYPAINT_BRUSH_SETTINGS_COUNT",
enumerate([i.internal_name.upper() for i in _SETTINGS]),
)
content += '\n'
content += generate_enum(
"MyPaintBrushState",
"MYPAINT_BRUSH_STATE_",
"MYPAINT_BRUSH_STATES_COUNT",
enumerate([i.upper() for i in _STATES]),
)
content += '\n'
return content
if __name__ == '__main__':
_init_globals_from_json("brushsettings.json")
script = sys.argv[0]
try:
public_header_file, internal_header_file = sys.argv[1:]
except:
msg = "usage: {} PUBLICdotH INTERNALdotH".format(script)
print(msg, file=sys.stderr)
sys.exit(2)
writefile(public_header_file, generate_public_settings_code())
writefile(internal_header_file, generate_internal_settings_code())