| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | """Utilities for generating C++ code for parameter management using Python Cog""" |
| |
|
| | import cog |
| | import inspect |
| | import re |
| | from os import path |
| |
|
| |
|
| | def quote(txt, indent=0): |
| | lines = [ |
| | " " * indent + '"' + l.replace("\\", "\\\\").replace('"', '\\"') for l in txt.split("\n") |
| | ] |
| | return '\\n"\n'.join(lines) + '"' |
| |
|
| |
|
| | def init_params(params, namespace, class_name, param_path, header_file=None): |
| | for param in params: |
| | param.path = param_path |
| | if not header_file: |
| | header_file = [f"{namespace}/{class_name}.h"] |
| | param.header_file = header_file + getattr(param.proxy, "header_file", []) |
| | param.namespace = namespace |
| | param.class_name = class_name |
| | return params |
| |
|
| |
|
| | def auto_comment(frame=1, msg=None, count=1): |
| | trace = [] |
| | for stack in inspect.stack()[frame : frame + count]: |
| | filename = path.normpath(stack[1]).split("/src/")[-1] |
| | if filename.find("<") >= 0: |
| | break |
| | lineno = stack[2] |
| | trace.insert(0, f"{filename}:{lineno}") |
| | return f'{"// Auto generated code" if msg is None else msg} ({" <- ".join(trace)})' |
| |
|
| |
|
| | def trace_comment(): |
| | return auto_comment(2) |
| |
|
| |
|
| | def get_module_path(module): |
| | return path.dirname(module.__file__.split(f"src{path.sep}")[-1]) |
| |
|
| |
|
| | def declare_begin(module, header=True): |
| | class_name = module.ClassName |
| | namespace = module.NameSpace |
| | params = module.Params |
| | param_path = module.ParamPath |
| | file_path = getattr(module, "FilePath", get_module_path(module)) |
| | param_file = getattr(module, "ParamSource", f"{file_path}/{class_name}.py") |
| | header_file = getattr(module, "HeaderFile", f"{file_path}/{class_name}.h") |
| | source_file = getattr(module, "SourceFile", f"{file_path}/{class_name}.cpp") |
| | class_doc = module.ClassDoc |
| | signal = getattr(module, "Signal", False) |
| |
|
| | if header: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | #include <Base/Parameter.h> |
| | {"#include <fastsignals/signal.h>" if signal else ""} |
| | """ |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | namespace {namespace} {{ |
| | /** {class_doc} |
| | |
| | * The parameters are under group "{param_path}" |
| | * |
| | * This class is auto generated by {param_file}. Modify that file |
| | * instead of this one, if you want to add any parameter. You need |
| | * to install Cog Python package for code generation: |
| | * @code |
| | * pip install cogapp |
| | * @endcode |
| | * |
| | * Once modified, you can regenerate the header and the source file, |
| | * @code |
| | * python3 -m cogapp -r {header_file} {source_file} |
| | * @endcode |
| | * |
| | * You can add a new parameter by adding lines in {param_file}. Available |
| | * parameter types are 'Int, UInt, String, Bool, Float'. For example, to add |
| | * a new Int type parameter, |
| | * @code |
| | * ParamInt(parameter_name, default_value, documentation, on_change=False) |
| | * @endcode |
| | * |
| | * If there is special handling on parameter change, pass in on_change=True. |
| | * And you need to provide a function implementation in {source_file} with |
| | * the following signature. |
| | * @code |
| | * void {class_name}:on<parameter_name>Changed() |
| | * @endcode |
| | */ |
| | class {namespace}Export {class_name} {{ |
| | public: |
| | static ParameterGrp::handle getHandle(); |
| | """ |
| | ) |
| | if signal: |
| | cog.out( |
| | f""" |
| | static fastsignals::signal<void (const char*)> &signalParamChanged(); |
| | static void signalAll(); |
| | """ |
| | ) |
| |
|
| | for param in params: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | //@{{ |
| | /// Accessor for parameter {param.name}""" |
| | ) |
| | if param._doc: |
| | cog.out( |
| | f""" |
| | ///""" |
| | ) |
| | for line in param._doc.split("\n"): |
| | cog.out( |
| | f""" |
| | /// {line}""" |
| | ) |
| | cog.out( |
| | f""" |
| | static const {param.C_Type} & get{param.name}(); |
| | static const {param.C_Type} & default{param.name}(); |
| | static void remove{param.name}(); |
| | static void set{param.name}(const {param.C_Type} &v); |
| | static const char *doc{param.name}();""" |
| | ) |
| | if param.on_change: |
| | cog.out( |
| | f""" |
| | static void on{param.name}Changed();""" |
| | ) |
| | cog.out( |
| | f""" |
| | //@}} |
| | """ |
| | ) |
| |
|
| |
|
| | def declare_end(module): |
| | class_name = module.ClassName |
| | namespace = module.NameSpace |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | }}; // class {class_name} |
| | }} // namespace {namespace} |
| | """ |
| | ) |
| |
|
| |
|
| | def define(module, header=True): |
| | class_name = module.ClassName |
| | namespace = module.NameSpace |
| | params = module.Params |
| | param_path = module.ParamPath |
| | class_doc = module.ClassDoc |
| | signal = getattr(module, "Signal", False) |
| |
|
| | if header: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | #include <unordered_map> |
| | #include <App/Application.h> |
| | #include <App/DynamicProperty.h> |
| | #include "{class_name}.h" |
| | using namespace {namespace}; |
| | """ |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | namespace {{ |
| | class {class_name}P: public ParameterGrp::ObserverType {{ |
| | public: |
| | ParameterGrp::handle handle; |
| | std::unordered_map<const char *,void(*)({class_name}P*),App::CStringHasher,App::CStringHasher> funcs; |
| | """ |
| | ) |
| |
|
| | if signal: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | fastsignals::signal<void (const char*)> signalParamChanged; |
| | void signalAll() |
| | {{""" |
| | ) |
| | for param in params: |
| | cog.out( |
| | f""" |
| | signalParamChanged("{param.name}");""" |
| | ) |
| | cog.out( |
| | f""" |
| | |
| | {trace_comment()} |
| | }}""" |
| | ) |
| |
|
| | for param in params: |
| | cog.out( |
| | f""" |
| | {param.C_Type} {param.name};""" |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | |
| | {trace_comment()} |
| | {class_name}P() {{ |
| | handle = App::GetApplication().GetParameterGroupByPath("{param_path}"); |
| | handle->Attach(this); |
| | """ |
| | ) |
| |
|
| | for param in params: |
| | cog.out( |
| | f""" |
| | {param.name} = {param.getter('handle')}; |
| | funcs["{param.name}"] = &{class_name}P::update{param.name};""" |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | }} |
| | |
| | {trace_comment()} |
| | ~{class_name}P() {{ |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | void OnChange(Base::Subject<const char*> &, const char* sReason) {{ |
| | if(!sReason) |
| | return; |
| | auto it = funcs.find(sReason); |
| | if(it == funcs.end()) |
| | return; |
| | it->second(this); |
| | {"signalParamChanged(sReason);" if signal else ""} |
| | }} |
| | |
| | """ |
| | ) |
| |
|
| | for param in params: |
| | if not param.on_change: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | static void update{param.name}({class_name}P *self) {{ |
| | self->{param.name} = {param.getter('self->handle')}; |
| | }}""" |
| | ) |
| | else: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | static void update{param.name}({class_name}P *self) {{ |
| | auto v = {param.getter('self->handle')}; |
| | if (self->{param.name} != v) {{ |
| | self->{param.name} = v; |
| | {class_name}::on{param.name}Changed(); |
| | }} |
| | }}""" |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | }}; |
| | |
| | {trace_comment()} |
| | {class_name}P *instance() {{ |
| | static {class_name}P *inst = new {class_name}P; |
| | return inst; |
| | }} |
| | |
| | }} // Anonymous namespace |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | ParameterGrp::handle {class_name}::getHandle() {{ |
| | return instance()->handle; |
| | }} |
| | """ |
| | ) |
| |
|
| | if signal: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | fastsignals::signal<void (const char*)> & |
| | {class_name}::signalParamChanged() {{ |
| | return instance()->signalParamChanged; |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | void signalAll() {{ |
| | instance()->signalAll(); |
| | }} |
| | """ |
| | ) |
| |
|
| | for param in params: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | const char *{class_name}::doc{param.name}() {{ |
| | return {param.doc(class_name)}; |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | const {param.C_Type} & {class_name}::get{param.name}() {{ |
| | return instance()->{param.name}; |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | const {param.C_Type} & {class_name}::default{param.name}() {{ |
| | const static {param.C_Type} def = {param.default}; |
| | return def; |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | void {class_name}::set{param.name}(const {param.C_Type} &v) {{ |
| | {param.setter()}; |
| | instance()->{param.name} = v; |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | void {class_name}::remove{param.name}() {{ |
| | instance()->handle->Remove{param.Type}("{param.name}"); |
| | }} |
| | """ |
| | ) |
| |
|
| |
|
| | def widgets_declare(param_set): |
| | param_group = param_set.ParamGroup |
| |
|
| | for title, params in param_group: |
| | name = _regex.sub("", title) |
| | cog.out( |
| | f""" |
| | |
| | {trace_comment()} |
| | QGroupBox * group{name} = nullptr;""" |
| | ) |
| | for param in params: |
| | param.declare_widget() |
| |
|
| |
|
| | def widgets_init(param_set): |
| | param_group = param_set.ParamGroup |
| |
|
| | cog.out( |
| | f""" |
| | auto layout = new QVBoxLayout(this);""" |
| | ) |
| | for title, params in param_group: |
| | name = _regex.sub("", title) |
| | cog.out( |
| | f""" |
| | |
| | |
| | {trace_comment()} |
| | group{name} = new QGroupBox(this); |
| | layout->addWidget(group{name}); |
| | auto layoutHoriz{name} = new QHBoxLayout(group{name}); |
| | auto layout{name} = new QGridLayout(); |
| | layoutHoriz{name}->addLayout(layout{name}); |
| | layoutHoriz{name}->addStretch();""" |
| | ) |
| |
|
| | for row, param in enumerate(params): |
| | cog.out( |
| | f""" |
| | |
| | {trace_comment()}""" |
| | ) |
| | param.init_widget(row, name) |
| |
|
| | cog.out( |
| | """ |
| | layout->addItem(new QSpacerItem(40, 20, QSizePolicy::Fixed, QSizePolicy::Expanding)); |
| | retranslateUi();""" |
| | ) |
| |
|
| |
|
| | def widgets_restore(param_set): |
| | param_group = param_set.ParamGroup |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()}""" |
| | ) |
| | for _, params in param_group: |
| | for param in params: |
| | param.widget_restore() |
| |
|
| |
|
| | def widgets_save(param_set): |
| | param_group = param_set.ParamGroup |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()}""" |
| | ) |
| | for _, params in param_group: |
| | for param in params: |
| | param.widget_save() |
| |
|
| |
|
| | def preference_dialog_declare_begin(param_set, header=True): |
| | namespace = param_set.NameSpace |
| | class_name = param_set.ClassName |
| | dialog_namespace = getattr(param_set, "DialogNameSpace", "Dialog") |
| | param_group = param_set.ParamGroup |
| | file_path = getattr(param_set, "FilePath", get_module_path(param_set)) |
| | param_file = getattr(param_set, "ParamSource", f"{file_path}/{class_name}.py") |
| | header_file = getattr(param_set, "HeaderFile", f"{file_path}/{class_name}.h") |
| | source_file = getattr(param_set, "SourceFile", f"{file_path}/{class_name}.cpp") |
| | class_doc = param_set.ClassDoc |
| |
|
| | if header: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | #include <Gui/PropertyPage.h> |
| | #include <Gui/PrefWidgets.h>""" |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | class QLabel; |
| | class QGroupBox; |
| | |
| | namespace {namespace} {{ |
| | namespace {dialog_namespace} {{ |
| | /** {class_doc} |
| | |
| | * This class is auto generated by {param_file}. Modify that file |
| | * instead of this one, if you want to make any change. You need |
| | * to install Cog Python package for code generation: |
| | * @code |
| | * pip install cogapp |
| | * @endcode |
| | * |
| | * Once modified, you can regenerate the header and the source file, |
| | * @code |
| | * python3 -m cogapp -r {header_file} {source_file} |
| | * @endcode |
| | */ |
| | class {class_name} : public Gui::Dialog::PreferencePage |
| | {{ |
| | Q_OBJECT |
| | |
| | public: |
| | {class_name}( QWidget* parent = 0 ); |
| | ~{class_name}(); |
| | |
| | void saveSettings(); |
| | void loadSettings(); |
| | void retranslateUi(); |
| | |
| | protected: |
| | void changeEvent(QEvent *e); |
| | |
| | private:""" |
| | ) |
| | widgets_declare(param_set) |
| |
|
| |
|
| | def preference_dialog_declare_end(param_set): |
| | class_name = param_set.ClassName |
| | namespace = param_set.NameSpace |
| | dialog_namespace = getattr(param_set, "DialogNameSpace", "Dialog") |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | }}; |
| | }} // namespace {dialog_namespace} |
| | }} // namespace {namespace} |
| | """ |
| | ) |
| |
|
| |
|
| | def preference_dialog_declare(param_set, header=True): |
| | preference_dialog_declare_begin(param_set, header) |
| | preference_dialog_declare_end(param_set) |
| |
|
| |
|
| | _regex = re.compile(r"[^a-zA-Z_]") |
| |
|
| |
|
| | def preference_dialog_define(param_set, header=True): |
| | param_group = param_set.ParamGroup |
| | class_name = param_set.ClassName |
| | dialog_namespace = getattr(param_set, "DialogNameSpace", "Dialog") |
| | namespace = f"{param_set.NameSpace}::{dialog_namespace}" |
| | file_path = getattr(param_set, "FilePath", get_module_path(param_set)) |
| | param_file = getattr(param_set, "ParamSource", f"{file_path}/{class_name}.py") |
| | header_file = getattr(param_set, "HeaderFile", f"{file_path}/{class_name}.h") |
| | source_file = getattr(param_set, "SourceFile", f"{file_path}/{class_name}.cpp") |
| | user_init = getattr(param_set, "UserInit", "") |
| | headers = set() |
| |
|
| | if header: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | # include <QApplication> |
| | # include <QLabel> |
| | # include <QGroupBox> |
| | # include <QGridLayout> |
| | # include <QVBoxLayout> |
| | # include <QHBoxLayout> |
| | """ |
| | ) |
| | for _, params in param_group: |
| | for param in params: |
| | for header in param.header_file: |
| | if header not in headers: |
| | headers.add(header) |
| | cog.out( |
| | f""" |
| | #include <{header}>""" |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | #include "{header_file}" |
| | using namespace {namespace}; |
| | /* TRANSLATOR {namespace}::{class_name} */ |
| | """ |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | {class_name}::{class_name}(QWidget* parent) |
| | : PreferencePage( parent ) |
| | {{ |
| | """ |
| | ) |
| | widgets_init(param_set) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | {user_init} |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | {class_name}::~{class_name}() |
| | {{ |
| | }} |
| | """ |
| | ) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | void {class_name}::saveSettings() |
| | {{""" |
| | ) |
| | widgets_save(param_set) |
| | cog.out( |
| | f""" |
| | }} |
| | |
| | {trace_comment()} |
| | void {class_name}::loadSettings() |
| | {{""" |
| | ) |
| | widgets_restore(param_set) |
| | cog.out( |
| | f""" |
| | }} |
| | |
| | {trace_comment()} |
| | void {class_name}::retranslateUi() |
| | {{ |
| | setWindowTitle(QObject::tr("{param_set.Title}"));""" |
| | ) |
| | for title, params in param_group: |
| | name = _regex.sub("", title) |
| | cog.out( |
| | f""" |
| | group{name}->setTitle(QObject::tr("{title}"));""" |
| | ) |
| | for row, param in enumerate(params): |
| | param.retranslate() |
| | cog.out( |
| | f""" |
| | }} |
| | |
| | {trace_comment()} |
| | void {class_name}::changeEvent(QEvent *e) |
| | {{ |
| | if (e->type() == QEvent::LanguageChange) {{ |
| | retranslateUi(); |
| | }} |
| | QWidget::changeEvent(e); |
| | }} |
| | """ |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | #include "moc_{class_name}.cpp" |
| | """ |
| | ) |
| |
|
| |
|
| | _ParamPrefix = "User parameter:BaseApp/Preferences/" |
| |
|
| |
|
| | class Param: |
| | WidgetPrefix = "" |
| |
|
| | def __init__(self, name, default, doc="", title="", on_change=False, proxy=None, **kwd): |
| | self.name = name |
| | self.title = title if title else name |
| | self._default = default |
| | self._doc = doc |
| | self.on_change = on_change |
| | self.proxy = proxy |
| |
|
| | def _declare_label(self): |
| | cog.out( |
| | f""" |
| | QLabel *label{self.name} = nullptr;""" |
| | ) |
| |
|
| | def declare_label(self): |
| | if self.proxy: |
| | self.proxy.declare_label(self) |
| | else: |
| | self._declare_label() |
| |
|
| | def _init_label(self, row, group_name): |
| | cog.out( |
| | f""" |
| | label{self.name} = new QLabel(this); |
| | layout{group_name}->addWidget(label{self.name}, {row}, 0);""" |
| | ) |
| |
|
| | def init_label(self, row, group_name): |
| | if self.proxy: |
| | self.proxy.init_label(self, row, group_name) |
| | else: |
| | self._init_label(row, group_name) |
| |
|
| | def _declare_widget(self): |
| | self.declare_label() |
| | cog.out( |
| | f""" |
| | {self.widget_type} *{self.widget_name} = nullptr;""" |
| | ) |
| |
|
| | def declare_widget(self): |
| | if self.proxy: |
| | self.proxy.declare_widget(self) |
| | else: |
| | self._declare_widget() |
| |
|
| | def _init_widget(self, row, group_name): |
| | self.init_label(row, group_name) |
| | cog.out( |
| | f""" |
| | {self.widget_name} = new {self.widget_type}(this); |
| | layout{group_name}->addWidget({self.widget_name}, {row}, {self.widget_column});""" |
| | ) |
| | if self.widget_setter: |
| | cog.out( |
| | f""" |
| | {self.widget_name}->{self.widget_setter}({self.namespace}::{self.class_name}::default{self.name}());""" |
| | ) |
| | self._init_pref_widget() |
| |
|
| | def _init_pref_widget(self): |
| | cog.out( |
| | f""" |
| | {self.widget_name}->setEntryName("{self.name}");""" |
| | ) |
| | if self.path.startswith(_ParamPrefix): |
| | cog.out( |
| | f""" |
| | {self.widget_name}->setParamGrpPath("{self.path[len(_ParamPrefix):]}");""" |
| | ) |
| | else: |
| | cog.out( |
| | f""" |
| | {self.widget_name}->setParamGrpPath("{self.path}");""" |
| | ) |
| |
|
| | def init_widget(self, row, group_name): |
| | if self.proxy: |
| | self.proxy.init_widget(self, row, group_name) |
| | else: |
| | self._init_widget(row, group_name) |
| |
|
| | def _widget_save(self): |
| | cog.out( |
| | f""" |
| | {self.widget_name}->onSave();""" |
| | ) |
| |
|
| | def widget_save(self): |
| | if self.proxy: |
| | self.proxy.widget_save(self) |
| | else: |
| | self._widget_save() |
| |
|
| | def _widget_restore(self): |
| | cog.out( |
| | f""" |
| | {self.widget_name}->onRestore();""" |
| | ) |
| |
|
| | def widget_restore(self): |
| | if self.proxy: |
| | self.proxy.widget_restore(self) |
| | else: |
| | self._widget_restore() |
| |
|
| | def _retranslate_label(self): |
| | cog.out( |
| | f""" |
| | label{self.name}->setText(QObject::tr("{self.title}")); |
| | label{self.name}->setToolTip({self.widget_name}->toolTip());""" |
| | ) |
| |
|
| | def retranslate_label(self): |
| | if self.proxy: |
| | self.proxy.retranslate_label(self) |
| | else: |
| | self._retranslate_label() |
| |
|
| | def _retranslate(self): |
| | cog.out( |
| | f""" |
| | {self.widget_name}->setToolTip(QApplication::translate("{self.class_name}", {self.namespace}::{self.class_name}::doc{self.name}()));""" |
| | ) |
| | self.retranslate_label() |
| |
|
| | def retranslate(self): |
| | if self.proxy: |
| | self.proxy.retranslate(self) |
| | else: |
| | self._retranslate() |
| |
|
| | @property |
| | def default(self): |
| | return self._default |
| |
|
| | def doc(self, class_name): |
| | if not self._doc: |
| | return '""' |
| | return f"""QT_TRANSLATE_NOOP("{class_name}", |
| | {quote(self._doc)})""" |
| |
|
| | @property |
| | def widget_type(self): |
| | if self.proxy: |
| | return self.proxy.widget_type(self) |
| | return self.WidgetType |
| |
|
| | @property |
| | def widget_prefix(self): |
| | if self.proxy: |
| | return self.proxy.widget_prefix(self) |
| | return self.WidgetPrefix |
| |
|
| | @property |
| | def widget_setter(self): |
| | if self.proxy: |
| | return self.proxy.widget_setter(self) |
| | return self.WidgetSetter |
| |
|
| | @property |
| | def widget_name(self): |
| | return f"{self.widget_prefix}{self.name}" |
| |
|
| | @property |
| | def widget_column(self): |
| | return 1 |
| |
|
| | def getter(self, handle): |
| | return f'{handle}->Get{self.Type}("{self.name}", {self.default})' |
| |
|
| | def setter(self): |
| | return f'instance()->handle->Set{self.Type}("{self.name}",v)' |
| |
|
| |
|
| | class ParamBool(Param): |
| | Type = "Bool" |
| | C_Type = "bool" |
| | WidgetType = "Gui::PrefCheckBox" |
| | WidgetSetter = "setChecked" |
| |
|
| | @property |
| | def default(self): |
| | if isinstance(self._default, str): |
| | return self._default |
| | return "true" if self._default else "false" |
| |
|
| | def _declare_label(self): |
| | pass |
| |
|
| | def _init_label(self, _row, _group_name): |
| | pass |
| |
|
| | @property |
| | def widget_column(self): |
| | return 0 |
| |
|
| | def _retranslate_label(self): |
| | cog.out( |
| | f""" |
| | {self.widget_name}->setText(QObject::tr("{self.title}"));""" |
| | ) |
| |
|
| |
|
| | class ParamFloat(Param): |
| | Type = "Float" |
| | C_Type = "double" |
| | WidgetType = "Gui::PrefDoubleSpinBox" |
| | WidgetSetter = "setValue" |
| |
|
| |
|
| | class ParamString(Param): |
| | Type = "ASCII" |
| | C_Type = "std::string" |
| | WidgetType = "Gui::PrefLineEdit" |
| | WidgetSetter = "setText" |
| |
|
| | @property |
| | def default(self): |
| | return f'"{self._default}"' |
| |
|
| |
|
| | class ParamQString(Param): |
| | Type = "ASCII" |
| | C_Type = "QString" |
| | WidgetType = "Gui::PrefLineEdit" |
| | WidgetSetter = "setText" |
| |
|
| | @property |
| | def default(self): |
| | return f'QStringLiteral("{self._default}")' |
| |
|
| | def getter(self, handle): |
| | return ( |
| | f'QString::fromUtf8({handle}->Get{self.Type}("{self.name}", "{self._default}").c_str())' |
| | ) |
| |
|
| | def setter(self): |
| | return f'instance()->handle->Set{self.Type}("{self.name}",v.toUtf8().constData())' |
| |
|
| |
|
| | class ParamInt(Param): |
| | Type = "Int" |
| | C_Type = "long" |
| | WidgetType = "Gui::PrefSpinBox" |
| | WidgetSetter = "setValue" |
| |
|
| |
|
| | class ParamUInt(Param): |
| | Type = "Unsigned" |
| | C_Type = "unsigned long" |
| | WidgetType = "Gui::PrefSpinBox" |
| | WidgetSetter = "setValue" |
| |
|
| |
|
| | class ParamHex(ParamUInt): |
| | @property |
| | def default(self): |
| | return "0x%08X" % self._default |
| |
|
| |
|
| | class ParamProxy: |
| | WidgetType = None |
| | WidgetPrefix = "" |
| | WidgetSetter = None |
| |
|
| | def __init__(self, param_bool=None): |
| | self.param_bool = param_bool |
| |
|
| | def declare_label(self, param): |
| | if not self.param_bool: |
| | param._declare_label() |
| |
|
| | def widget_prefix(self, param): |
| | return self.WidgetPrefix if self.WidgetPrefix else param.WidgetPrefix |
| |
|
| | def widget_type(self, param): |
| | return self.WidgetType if self.WidgetType else param.WidgetType |
| |
|
| | def widget_setter(self, param): |
| | return self.WidgetSetter if self.WidgetSetter else param.WidgetSetter |
| |
|
| | def declare_widget(self, param): |
| | if self.param_bool: |
| | self.param_bool.declare_widget() |
| | param._declare_widget() |
| |
|
| | def init_label(self, param, row, group_name): |
| | if not self.param_bool: |
| | param._init_label(row, group_name) |
| |
|
| | def init_widget(self, param, row, group_name): |
| | param._init_widget(row, group_name) |
| | if self.param_bool: |
| | self.param_bool.init_widget(row, group_name) |
| | cog.out( |
| | f""" |
| | {param.widget_name}->setEnabled({self.param_bool.widget_name}->isChecked()); |
| | connect({self.param_bool.widget_name}, SIGNAL(toggled(bool)), {param.widget_name}, SLOT(setEnabled(bool)));""" |
| | ) |
| |
|
| | def retranslate_label(self, param): |
| | if not self.param_bool: |
| | param._retranslate_label() |
| |
|
| | def retranslate(self, param): |
| | param._retranslate() |
| | if self.param_bool: |
| | self.param_bool.retranslate() |
| |
|
| | def widget_save(self, param): |
| | param._widget_save() |
| | if self.param_bool: |
| | self.param_bool.widget_save() |
| |
|
| | def widget_restore(self, param): |
| | param._widget_restore() |
| | if self.param_bool: |
| | self.param_bool.widget_restore() |
| |
|
| |
|
| | class ComboBoxItem: |
| | def __init__(self, text, tooltips=None, data=None): |
| | self.text = text |
| | self.tooltips = tooltips |
| | self._data = data |
| |
|
| | @property |
| | def data(self): |
| | if self._data is None: |
| | return "QVariant()" |
| | if isinstance(self._data, str): |
| | return f'QByteArray("{self._data}")' |
| | return self._data |
| |
|
| |
|
| | class ParamComboBox(ParamProxy): |
| | WidgetType = "Gui::PrefComboBox" |
| |
|
| | def __init__(self, items, translate=True, param_bool=None): |
| | super().__init__(param_bool) |
| | self.translate = translate |
| | self.items = [] |
| | for item in items: |
| | if isinstance(item, str): |
| | item = ComboBoxItem(item) |
| | elif isinstance(item, tuple): |
| | item = ComboBoxItem(*item) |
| | else: |
| | assert isinstance(item, ComboBoxItem) |
| | self.items.append(item) |
| |
|
| | def widget_setter(self, _param): |
| | return None |
| |
|
| | def init_widget(self, param, row, group_name): |
| | super().init_widget(param, row, group_name) |
| | if self.translate: |
| | cog.out( |
| | f""" |
| | for (int i=0; i<{len(self.items)}; ++i) {trace_comment()} |
| | {param.widget_name}->addItem(QString());""" |
| | ) |
| |
|
| | for i, item in enumerate(self.items): |
| | if not self.translate: |
| | cog.out( |
| | f""" |
| | {param.widget_name}->addItem(QStringLiteral("{item.text}"));""" |
| | ) |
| | if item._data is not None: |
| | cog.out( |
| | f""" |
| | {param.widget_name}->setItemData({param.widget_name}->count()-1, {item.data});""" |
| | ) |
| |
|
| | cog.out( |
| | f""" |
| | {param.widget_name}->setCurrentIndex({param.namespace}::{param.class_name}::default{param.name}());""" |
| | ) |
| |
|
| | def retranslate(self, param): |
| | super().retranslate(param) |
| | cog.out( |
| | f""" |
| | {trace_comment()}""" |
| | ) |
| | for i, item in enumerate(self.items): |
| | if self.translate: |
| | cog.out( |
| | f""" |
| | {param.widget_name}->setItemText({i}, QObject::tr("{item.text}"));""" |
| | ) |
| | if item.tooltips: |
| | cog.out( |
| | f""" |
| | {param.widget_name}->setItemData({i}, QObject::tr("{item.tooltips}"), Qt::ToolTipRole);""" |
| | ) |
| |
|
| |
|
| | class ParamLinePattern(ParamProxy): |
| | WidgetType = "Gui::PrefLinePattern" |
| |
|
| | def widget_setter(self, _param): |
| | return None |
| |
|
| | def init_widget(self, param, row, group_name): |
| | super().init_widget(param, row, group_name) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | for (int i=1; i<{param.widget_name}->count(); ++i) {{ |
| | if ({param.widget_name}->itemData(i).toInt() == {param.default}) |
| | {param.widget_name}->setCurrentIndex(i); |
| | }}""" |
| | ) |
| |
|
| |
|
| | class ParamColor(ParamProxy): |
| | WidgetType = "Gui::PrefColorButton" |
| | WidgetSetter = "setPackedColor" |
| |
|
| | def __init__(self, param_bool=None, transparency=True): |
| | super().__init__(param_bool) |
| | self.transparency = transparency |
| |
|
| | def init_widget(self, param, row, group_name): |
| | super().init_widget(param, row, group_name) |
| | if self.transparency: |
| | cog.out( |
| | f""" |
| | {param.widget_name}->setAllowTransparency(true);""" |
| | ) |
| |
|
| |
|
| | class ParamFile(ParamProxy): |
| | WidgetType = "Gui::PrefFileChooser" |
| | WidgetSetter = "setFileNameStd" |
| |
|
| |
|
| | class ParamSpinBox(ParamProxy): |
| | def __init__(self, value_min, value_max, value_step, decimals=0, param_bool=None, suffix=""): |
| | super().__init__(param_bool) |
| | self.value_min = value_min |
| | self.value_max = value_max |
| | self.value_step = value_step |
| | self.decimals = decimals |
| | self.suffix = suffix |
| |
|
| | def init_widget(self, param, row, group_name): |
| | super().init_widget(param, row, group_name) |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | {param.widget_name}->setMinimum({self.value_min}); |
| | {param.widget_name}->setMaximum({self.value_max}); |
| | {param.widget_name}->setSingleStep({self.value_step}); |
| | {param.widget_name}->setAlignment(Qt::AlignRight);""" |
| | ) |
| | if self.decimals: |
| | cog.out( |
| | f""" |
| | {param.widget_name}->setDecimals({self.decimals});""" |
| | ) |
| | if self.suffix: |
| | cog.out( |
| | f""" |
| | {param.widget_name}->setSuffix(QLatin1String("{self.suffix}"));""" |
| | ) |
| |
|
| |
|
| | class ParamShortcutEdit(ParamProxy): |
| | WidgetType = "Gui::PrefAccelLineEdit" |
| | WidgetSetter = "setDisplayText" |
| |
|
| |
|
| | class Property: |
| | def __init__(self, name, property_type, doc, group=None, prop_flags=None, static=False): |
| | self.name = name |
| | self.type_name = property_type |
| | self.doc = doc |
| | self.prop_flags = prop_flags if prop_flags else "App::Prop_None" |
| | self.static = static |
| | self.group = group if group else "" |
| |
|
| | def declare(self): |
| | if self.static: |
| | cog.out( |
| | f""" |
| | static {self.type_name} *get{self.name}Property(App::DocumentObject *obj, bool force=false); |
| | inline {self.type_name} *get{self.name}Property(bool force=false) {{ |
| | return get{self.name}Property(this, force); |
| | }}""" |
| | ) |
| | else: |
| | cog.out( |
| | f""" |
| | {self.type_name} *get{self.name}Property(bool force=false);""" |
| | ) |
| |
|
| | def define(self, class_name): |
| | if self.static: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | {self.type_name} *{class_name}::get{self.name}Property(App::DocumentObject *obj, bool force) |
| | {{""" |
| | ) |
| | else: |
| | cog.out( |
| | f""" |
| | {trace_comment()} |
| | {self.type_name} *{class_name}::get{self.name}Property(bool force) |
| | {{ |
| | auto obj = this;""" |
| | ) |
| | cog.out( |
| | f""" |
| | if (auto prop = Base::freecad_dynamic_cast<{self.type_name}>( |
| | obj->getPropertyByName("{self.name}"))) |
| | {{ |
| | if (prop->getContainer() == obj) |
| | return prop; |
| | }} |
| | if (!force) |
| | return nullptr; |
| | return static_cast<{self.type_name}*>(obj->addDynamicProperty( |
| | "{self.type_name}", "{self.name}", "{self.group}", |
| | {quote(self.doc)}, |
| | {self.prop_flags})); |
| | }} |
| | """ |
| | ) |
| |
|
| |
|
| | def declare_properties(properties): |
| | cog.out( |
| | f""" |
| | {trace_comment()}""" |
| | ) |
| | for prop in properties: |
| | prop.declare() |
| |
|
| |
|
| | def define_properties(properties, class_name): |
| | for prop in properties: |
| | prop.define(class_name) |
| |
|