Commit ea4da952 authored by sumpfralle's avatar sumpfralle

turned the process parameter manager into a generic parameter manager

migrated the tool parameter handling to use the above manager


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@1143 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 20cee835
......@@ -19,7 +19,7 @@
<object class="GtkListStore" id="BoundsModelsList">
<columns>
<!-- column-name ref_model -->
<column type="guint"/>
<column type="gulong"/>
</columns>
</object>
<object class="GtkListStore" id="ToolLimitModeList">
......
......@@ -24,8 +24,6 @@
</row>
</data>
</object>
<object class="GtkWindow" id="window1">
<child>
<object class="GtkVPaned" id="ProcessBox">
<property name="visible">True</property>
<property name="can_focus">True</property>
......@@ -252,6 +250,4 @@
</packing>
</child>
</object>
</child>
</object>
</interface>
......@@ -255,6 +255,10 @@
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">3</property>
<child>
<object class="GtkFrame" id="TaskModelsFram">
<property name="visible">True</property>
......@@ -303,12 +307,14 @@
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHSeparator" id="hseparator2">
<object class="GtkVSeparator" id="vseparator1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -442,13 +448,19 @@
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHSeparator" id="hseparator1">
<object class="GtkHSeparator" id="hseparator2">
<property name="visible">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">3</property>
<property name="position">1</property>
</packing>
</child>
<child>
......@@ -553,7 +565,7 @@
</object>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
<property name="position">2</property>
</packing>
</child>
</object>
......
......@@ -29,6 +29,20 @@
</row>
</data>
</object>
<object class="GtkListStore" id="ToolShapeList">
<columns>
<!-- column-name label -->
<column type="gchararray"/>
<!-- column-name name -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Ball nose</col>
<col id="1" translatable="yes">ballnose</col>
</row>
</data>
</object>
<object class="GtkVPaned" id="ToolBox">
<property name="visible">True</property>
<property name="can_focus">True</property>
......@@ -199,36 +213,8 @@
<property name="orientation">vertical</property>
<property name="spacing">4</property>
<child>
<object class="GtkHBox" id="hbox3">
<object class="GtkHSeparator" id="hseparator1">
<property name="visible">True</property>
<property name="spacing">3</property>
<child>
<object class="GtkFrame" id="frame6">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment14">
<property name="visible">True</property>
<property name="yalign">0</property>
<property name="yscale">0</property>
<property name="top_padding">3</property>
<property name="bottom_padding">3</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox19">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">4</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkRadioButton" id="CylindricalCutter">
<property name="label" translatable="yes">Flat end</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">SphericalCutter</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -236,153 +222,59 @@
</packing>
</child>
<child>
<object class="GtkRadioButton" id="SphericalCutter">
<property name="label" translatable="yes">Ball nose</property>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<property name="xscale">0</property>
<property name="yscale">0</property>
<child>
<object class="GtkRadioButton" id="ToroidalCutter">
<property name="label" translatable="yes">Bull nose</property>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">SphericalCutter</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="ToolTypeLabel">
<property name="spacing">3</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Shape&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
<property name="label" translatable="yes">Tool shape:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVSeparator" id="vseparator5">
<object class="GtkComboBox" id="ToolShapeSelector">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="model">ToolShapeList</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame10">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment18">
<property name="visible">True</property>
<property name="yalign">0</property>
<property name="yscale">0</property>
<property name="top_padding">3</property>
<property name="bottom_padding">3</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table3">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<property name="column_spacing">2</property>
<property name="row_spacing">4</property>
<child>
<object class="GtkLabel" id="ToolDiameterLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Tool Diameter:</property>
</object>
<packing>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="TorusDiameterLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Torus Diameter:</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="ToolDiameterControl">
<object class="GtkHBox" id="ToolParameterBox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">tooldiameter</property>
<property name="digits">4</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<property name="spacing">3</property>
<child>
<object class="GtkSpinButton" id="TorusDiameterControl">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">torusdiameter</property>
<property name="digits">4</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="DimensionsLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Dimensions&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="position">2</property>
</packing>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
<property name="position">2</property>
</packing>
</child>
</object>
......
......@@ -71,11 +71,6 @@ class Models(pycam.Plugins.ListPluginBase):
self._visualize_visible_state)
self.gui.get_object("ModelNameColumn").connect("edited",
self._edit_model_name)
selection = self._modelview.get_selection()
selection.connect("changed",
lambda widget, event: self.core.emit_event(event),
"model-selection-changed")
selection.set_mode(self._gtk.SELECTION_MULTIPLE)
self._treemodel = self.gui.get_object("ModelList")
self._treemodel.clear()
def update_model():
......@@ -95,6 +90,11 @@ class Models(pycam.Plugins.ListPluginBase):
True, color,
int(self.DEFAULT_COLOR[3] * _GTK_COLOR_MAX)))
self.core.emit_event("model-list-changed")
selection = self._modelview.get_selection()
selection.set_mode(self._gtk.SELECTION_MULTIPLE)
selection.connect("changed",
lambda widget, event: self.core.emit_event(event),
"model-selection-changed")
self._get_colors_of_selected_models()
self.register_model_update(update_model)
self.core.set("models", self)
......@@ -136,6 +136,7 @@ class Models(pycam.Plugins.ListPluginBase):
if (new_text != self._treemodel[path][self.COLUMN_NAME]) and \
new_text:
self._treemodel[path][self.COLUMN_NAME] = new_text
self.core.emit_event("model-list-changed")
def _visualize_visible_state(self, column, cell, model, m_iter):
visible = model.get_value(m_iter, self.COLUMN_VISIBLE)
......
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ParameterGroupManager(pycam.Plugins.PluginBase):
def setup(self):
self._groups = {}
self.core.set("get_parameters", self.get_parameters)
self.core.set("get_parameter_values", self.get_parameter_values)
self.core.set("set_parameter_values", self.set_parameter_values)
self.core.set("get_parameter_sets", self.get_parameter_sets)
self.core.set("register_parameter_group", self.register_parameter_group)
self.core.set("register_parameter_set", self.register_parameter_set)
self.core.set("register_parameter_section", self.register_parameter_section)
self.core.set("register_parameter", self.register_parameter)
self.core.set("unregister_parameter_group",
self.unregister_parameter_section)
self.core.set("unregister_parameter_set",
self.unregister_parameter_section)
self.core.set("unregister_parameter_section",
self.unregister_parameter_section)
self.core.set("unregister_parameter",
self.unregister_parameter)
return True
def teardown(self):
for name in ("get_parameters", "set_parameter_values",
"get_parameter_values", "get_parameter_sets",
"register_parameter_section", "register_parameter_set",
"register_parameter_group", "register_parameter",
"unregister_parameter_section", "unregister_parameter_set",
"unregister_parameter_group", "unregister_parameter"):
self.core.set(name, None)
def register_parameter_group(self, name, changed_set_event=None,
changed_set_list_event=None, get_current_set_func=None):
if name in self._groups:
self.log.debug("Registering parameter group '%s' again" % name)
self._groups[name] = {"changed_set_event": changed_set_event,
"changed_set_list_event": changed_set_list_event,
"get_current_set_func": get_current_set_func,
"sets": {},
"sections": {}}
def register_parameter_set(self, group_name, name, label, func,
parameters=None, weight=100):
if not group_name in self._groups:
self.log.info("Unknown parameter group: %s" % group_name)
return
group = self._groups[group_name]
if name in group["sets"]:
self.log.debug("Registering parameter set '%s' again" % name)
if parameters is None:
parameters = []
group["sets"][name] = {"name": name,
"label": label,
"func": func,
"parameters": parameters,
"weight": weight,
}
event = group["changed_set_list_event"]
if event:
self.core.emit_event(event)
def register_parameter_section(self, group_name, name):
if not group_name in self._groups:
self.log.info("Unknown parameter group: %s" % group_name)
return
group = self._groups[group_name]
if name in group["sections"]:
self.log.debug("Registering section '%s' in group '%s' again" % \
(name, group_name))
widget = ParameterSectionGTK(self.core, group["changed_set_event"],
lambda: self.get_parameters(group_name),
group["get_current_set_func"])
group["sections"][name] = {"widget": widget, "parameters": {}}
return widget.widget
def register_parameter(self, group_name, section_name, name, label,
control, weight=100):
if not group_name in self._groups:
self.log.info("Unknown parameter group: %s" % group_name)
return
group = self._groups[group_name]
if not section_name in group["sections"]:
self.log.info("Unknown parameter section: %s->%s" % \
(group_name, section_name))
return
section = group["sections"][section_name]
if name in section["parameters"]:
self.log.debug("Registering parameter '%s' in group '%s' again" % \
(name, group_name))
section["parameters"][name] = {"name": name, "label": label,
"control": control, "weight": weight }
section["widget"].update_widgets()
def get_parameters(self, group_name):
if not group_name in self._groups:
self.log.info("Unknown parameter group: %s" % group_name)
return []
result = {}
group = self._groups[group_name]
for section in group["sections"].values():
result.update(section["parameters"])
return result
def get_parameter_values(self, group_name):
if not group_name in self._groups:
self.log.info("Unknown parameter group: %s" % group_name)
return {}
result = {}
group = self._groups[group_name]
for section in group["sections"].values():
for parameter in section["parameters"].values():
result[parameter["name"]] = parameter["control"].get_value()
return result
def set_parameter_values(self, group_name, value_dict):
if not group_name in self._groups:
self.log.info("Unknown parameter group: %s" % group_name)
return
group = self._groups[group_name]
for section in group["sections"].values():
for parameter in section["parameters"].values():
if parameter["name"] in value_dict:
parameter["control"].set_value(
value_dict[parameter["name"]])
def get_parameter_sets(self, group_name):
if not group_name in self._groups:
self.log.info("Unknown parameter group: %s" % group_name)
return
group = self._groups[group_name]
return dict(group["sets"])
def unregister_parameter_group(self, group_name):
if not group_name in self._groups:
self.log.debug("Tried to unregister a non-existing parameter " + \
"group: %s" % group_name)
return
group = self._groups[group_name]
if group["sections"]:
self.log.debug(("Unregistering parameter group (%s), but it " + \
"still contains sections") % \
(group_name, ", ".join(group["sections"].keys())))
for section_name in group["sections"]:
self.unregister_parameter_section(group_name, section_name)
if group["sets"]:
self.log.debug(("Unregistering parameter group (%s), but it " + \
"still contains sets: %s") % \
(group_name, ", ".join(group["sets"].keys())))
for set_name in group["sets"]:
self.unregister_parameter_set(group_name, set_name)
del self._groups[group_name]
def unregister_parameter_section(self, group_name, section_name):
if not group_name in self._groups:
self.log.debug(("Tried to unregister section '%s' from a " + \
"non-existing parameter group: %s") % \
(section_name, group_name))
return
group = self._groups[group_name]
if not section_name in group["sections"]:
self.log.debug("Tried to unregister non-existing parameter " + \
"section '%s' from group '%s'" % (section_name, group_name))
return
section = group["sections"][section_name]
if section["parameters"]:
self.log.debug(("Unregistering parameter section (%s->%s), " + \
"but it still contains parameters") % (group_name,
section_name, ", ".join(group["parameters"].keys())))
for parameter_name in section["parameters"]:
self.unregister_parameter(group_name, section_name,
parameter_name)
del group["sections"][section_name]
def unregister_parameter_set(self, group_name, set_name):
if not group_name in self._groups:
self.log.debug(("Tried to unregister set '%s' from a " + \
"non-existing parameter group: %s") % \
(set_name, group_name))
return
group = self._groups[group_name]
if not set_name in group["sets"]:
self.log.debug("Tried to unregister non-existing parameter " + \
"set '%s' from group '%s'" % (set_name, group_name))
return
del group["sets"][set_name]
def unregister_parameter(self, group_name, section_name, name):
if not group_name in self._groups:
self.log.debug(("Tried to unregister parameter '%s' in " + \
"section '%s' from a non-existing parameter group: %s") % \
(name, section_name, group_name))
return
group = self._groups[group_name]
if not section_name in group["sections"]:
self.log.debug(("Tried to unregister parameter '%s' from a " + \
"non-existing parameter section '%s' in group '%s'") % \
(name, section_name, group_name))
return
section = group["sections"][section_name]
if name in section["parameters"]:
del section["parameters"][name]
else:
self.log.debug("Tried to unregister the non-existing " + \
"parameter '%s' from '%s->%s'" % \
(name, group_name, section_name))
class ParameterSectionGTK(object):
def __init__(self, core, update_visibility_event=None,
get_params_dict_func=None,
get_current_set_func=None):
import gtk
self._gtk = gtk
self.core = core
self._table = gtk.Table(rows=1, columns=2)
self._table.set_col_spacings(3)
self._table.set_row_spacings(3)
if update_visibility_event:
self.core.register_event(update_visibility_event,
self._update_widgets_visibility)
self._get_current_set_func = get_current_set_func
self._get_params_dict_func = get_params_dict_func
self.update_widgets()
self._update_widgets_visibility()
self._table.show()
self.widget = self._table
def update_widgets(self):
gtk = self._gtk
params = self._get_params_dict_func().values()
params.sort(key=lambda item: item["weight"])
# remove all widgets from the table
for child in self._table.get_children():
self._table.remove(child)
# add the current controls
for index, param in enumerate(params):
widget = param["control"].get_widget()
if hasattr(widget, "get_label"):
# checkbox
widget.set_label(param["label"])
self._table.attach(widget, 0, 2, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
else:
# spinbutton, combobox, ...
label = gtk.Label("%s:" % param["label"])
label.set_alignment(0.0, 0.5)
self._table.attach(label, 0, 1, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
self._table.attach(widget, 1, 2, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
self._update_widgets_visibility()
def _get_table_row_of_widget(self, widget):
for child in self._table.get_children():
if child is widget:
return self._get_child_row(child)
else:
return -1
def _get_child_row(self, widget):
return self._gtk.Container.child_get_property(self._table, widget,
"top-attach")
def _update_widgets_visibility(self):
params = self._get_params_dict_func()
generator = self._get_current_set_func()
if not generator:
return
for param in params.values():
table_row = self._get_table_row_of_widget(
param["control"].get_widget())
for child in self._table.get_children():
if self._get_child_row(child) == table_row:
if param["name"] in generator["parameters"]:
child.show()
else:
child.hide()
......@@ -27,133 +27,138 @@ import pycam.Gui.ControlsGTK
class PathParamOverlap(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
DEPENDS = ["Processes"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("overlap",
"Overlap [%]", pycam.Gui.ControlsGTK.InputNumber(
lower=0, upper=99, digits=0,
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed")),
weight=10)
# configure the input/output converter
widget = pycam.Gui.ControlsGTK.InputNumber(lower=0, upper=99, digits=0,
increment=10, change_handler=lambda widget=None: \
self.core.emit_event("process-parameter-changed"))
widget.set_conversion(
set_conv=lambda float_value: int(float_value * 100.0),
get_conv=lambda percent: percent / 100.0)
self.core.get("register_parameter")("process", "pathgenerator",
"overlap", "Overlap [%]", widget, weight=10)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("overlap")
self.core.get("unregister_parameter")("process", "pathgenerator",
"overlap")
class PathParamStepDown(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
DEPENDS = ["Processes"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("step_down",
"Step down", pycam.Gui.ControlsGTK.InputNumber(lower=0.01,
upper=1000, digits=2, start=1,
change_handler=lambda widget=None: \
self.core.emit_event("pathgenerator-parameter-changed")),
weight=20)
widget = pycam.Gui.ControlsGTK.InputNumber(lower=0.01, upper=1000,
digits=2, start=1, change_handler=lambda widget=None: \
self.core.emit_event("process-parameter-changed"))
self.core.get("register_parameter")("process", "pathgenerator",
"step_down", "Step down", widget, weight=20)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("step_down")
self.core.get("unregister_parameter")("process", "pathgenerator",
"step_down")
class PathParamMaterialAllowance(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
DEPENDS = ["Processes"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("material_allowance",
"Material allowance", pycam.Gui.ControlsGTK.InputNumber(
start=0, lower=0, upper=100, digits=2,
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed")),
weight=30)
widget = pycam.Gui.ControlsGTK.InputNumber(start=0, lower=0, upper=100,
digits=2, change_handler=lambda widget=None: \
self.core.emit_event("process-parameter-changed"))
self.core.get("register_parameter")("process", "pathgenerator",
"material_allowance", "Material allowance", widget, weight=30)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("overlap")
self.core.get("unregister_parameter")("process", "pathgenerator",
"material_allowance")
class PathParamMillingStyle(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
DEPENDS = ["Processes"]
def setup(self):
# TODO: check if gtk is in use
input_control = pycam.Gui.ControlsGTK.InputChoice(
(("ignore", "ignore"),
("climb / down", "climb"),
("conventional / up", "conventional")),
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed"))
self.core.get("register_pathgenerator_parameter")("milling_style",
"Milling style", input_control, weight=50)
"process-parameter-changed"))
self.core.get("register_parameter")("process", "pathgenerator",
"milling_style", "Milling style", input_control, weight=50)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("milling_style")
self.core.get("unregister_parameter")("process", "pathgenerator",
"milling_style")
class PathParamGridDirection(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
DEPENDS = ["Processes"]
def setup(self):
# TODO: check if gtk is in use
input_control = pycam.Gui.ControlsGTK.InputChoice(
(("x", "x"), ("y", "y"), ("xy", "xy")),
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed"))
self.core.get("register_pathgenerator_parameter")("grid_direction",
"Direction", input_control, weight=40)
"process-parameter-changed"))
self.core.get("register_parameter")("process", "pathgenerator",
"grid_direction", "Direction", input_control, weight=40)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("grid_direction")
self.core.get("unregister_parameter")("process", "pathgenerator",
"grid_direction")
class PathParamRadiusCompensation(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
DEPENDS = ["Processes"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("radius_compensation",
"Radius compensation",
pycam.Gui.ControlsGTK.InputCheckBox(
widget = pycam.Gui.ControlsGTK.InputCheckBox(
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed")),
weight=80)
"process-parameter-changed"))
self.core.get("register_parameter")("process", "pathgenerator",
"radius_compensation", "Radius compensation", widget, weight=80)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("radius_compensation")
self.core.get("unregister_parameter")("process", "pathgenerator",
"radius_compensation")
class PathParamTraceModel(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "Models"]
DEPENDS = ["Processes", "Models"]
def setup(self):
class InputModelSelection(pycam.Gui.ControlsGTK.InputChoice):
def get_value(inner_self):
ref = super(InputModelSelection, inner_self).get_value()
for model in self.core.get("models"):
if id(model) == ref:
return model
return None
# TODO: check if gtk is in use
self.input_control = InputModelSelection([], force_type=long,
self.input_control = pycam.Gui.ControlsGTK.InputTable([], force_type=long,
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed"))
self.input_control
self.core.get("register_pathgenerator_parameter")("trace_model",
"Trace model", self.input_control, weight=5)
"process-parameter-changed"))
# configure the input/output converter
def get_converter(model_refs):
models_dict = {}
for model in self.core.get("models"):
models_dict[id(model)] = model
models = []
for model_ref in model_refs:
models.append(models_dict[model_ref])
return models
def set_converter(models):
return [id(model) for model in models]
self.input_control.set_conversion(set_conv=set_converter,
get_conv=get_converter)
self.core.get("register_parameter")("process", "pathgenerator",
"trace_models", "Trace models (2D)", self.input_control, weight=5)
self.core.register_event("model-list-changed", self._update_models)
return True
......@@ -166,5 +171,6 @@ class PathParamTraceModel(pycam.Plugins.PluginBase):
self.input_control.update_choices(choices)
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("trace_model")
self.core.get("unregister_parameter")("process", "pathgenerator",
"trace_models")
......@@ -26,7 +26,7 @@ import pycam.Plugins
class ProcessStrategyContour(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamStepDown",
DEPENDS = ["Processes", "PathParamStepDown",
"PathParamMaterialAllowance", "PathParamMillingStyle"]
def setup(self):
......@@ -34,15 +34,14 @@ class ProcessStrategyContour(pycam.Plugins.PluginBase):
"material_allowance": 0,
"milling_style": "ignore",
}
self.core.get("register_strategy")("contour", "Waterline",
self.run_strategy, parameters=parameters, weight=20)
self.core.get("register_parameter_set")("process", "contour",
"Waterline", self.run_strategy, parameters=parameters,
weight=20)
return True
def teardown(self):
self.core.get("unregister_strategy")("contour")
self.core.get("unregister_parameter_set")("process", "contour")
def run_strategy(self):
pass
......@@ -26,7 +26,7 @@ import pycam.Plugins
class ProcessStrategyEngraving(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamStepDown",
DEPENDS = ["ParameterGroupManager", "PathParamStepDown",
"PathParamMillingStyle", "PathParamRadiusCompensation",
"PathParamTraceModel"]
......@@ -34,10 +34,11 @@ class ProcessStrategyEngraving(pycam.Plugins.PluginBase):
parameters = {"step_down": 1.0,
"milling_style": "ignore",
"radius_compensation": False,
"trace_model": None
"trace_models": [],
}
self.core.get("register_strategy")("engraving", "Engraving",
self.run_strategy, parameters=parameters, weight=80)
self.core.get("register_parameter_set")("process", "engraving",
"Engraving", self.run_strategy, parameters=parameters,
weight=80)
return True
def teardown(self):
......
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ProcessStrategyManager(pycam.Plugins.PluginBase):
def setup(self):
self.strategies = []
self.parameters = []
self.core.set("process-strategies", self.strategies)
self.core.set("pathgenerator_parameters", self.parameters)
self.core.set("register_strategy", self.register_strategy)
self.core.set("unregister_strategy", self.unregister_strategy)
self.core.set("register_pathgenerator_parameter",
self.register_generator_parameter)
self.core.set("unregister_pathgenerator_parameter",
self.unregister_generator_parameter)
self.core.set("get_pathgenerator_parameter_value",
self.get_parameter_value)
self.core.set("set_pathgenerator_parameter_value",
self.set_parameter_value)
return True
def teardown(self):
for name in ("strategies", "pathgenerator_parameters",
"register_strategy", "register_pathgenerator_parameter",
"unregister_strategy", "unregister_pathgenerator_parameter",
"get_pathgenerator_parameter_value",
"set_pathgenerator_parameter_value"):
self.core.set(name, None)
def register_strategy(self, name, label, func, parameters=None,
model_filter=None, weight=100):
if self.get_by_name(name):
self.log.debug("Registering an existing path generator again: " + \
name)
generator = {}
generator["name"] = name
generator["label"] = label
generator["func"] = func
generator["parameters"] = parameters or []
generator["model_filter"] = model_filter
generator["weight"] = weight
self.strategies.append(generator)
self.strategies.sort(key=lambda item: item["weight"])
self.core.emit_event("process-strategy-list-changed")
def unregister_strategy(self, name):
index = self.get_by_name(name, force_index=True)
if index < 0:
self.log.debug("Tried to unregister a non-existing path " + \
"generator: %s" % name)
else:
self.strategies.pop(index)
self.core.emit_event("process-strategy-list-changed")
def register_generator_parameter(self, name, label, control, weight=100):
if self.get_parameter_by_name(name):
self.log.debug("Registering an existing path generator parameter " + \
"again: %s" % name)
parameter = {}
parameter["name"] = name
parameter["label"] = label
parameter["control"] = control
parameter["weight"] = weight
self.parameters.append(parameter)
self.parameters.sort(key=lambda param: param["weight"])
self.core.emit_event("pathgenerator-parameter-list-changed")
def unregister_generator_parameter(self, name):
index = self.get_parameter_by_name(name, force_index=True)
if index < 0:
self.log.debug("Tried to unregister a non-existing path " + \
"generator parameter: %s" % name)
else:
self.parameters.pop(index)
self.core.emit_event("pathgenerator-parameter-list-changed")
def _get_by_name(self, name, force_index=False, data_list=None):
for index, generator in enumerate(data_list):
if generator["name"] == name:
if force_index:
return index
else:
return generator
else:
if force_index:
return -1
else:
return None
def get_by_name(self, *args, **kwargs):
merged_kw = kwargs.copy()
merged_kw.update({"data_list": self.strategies})
return self._get_by_name(*args, **merged_kw)
def get_parameter_by_name(self, *args, **kwargs):
merged_kw = kwargs.copy()
merged_kw.update({"data_list": self.parameters})
return self._get_by_name(*args, **merged_kw)
def get_parameter_value(self, name):
parameter = self.get_parameter_by_name(name)
if parameter:
return parameter["control"].get_value()
else:
self.log.debug("Unknown path parameter requested: %s" % name)
return None
def set_parameter_value(self, name, value):
parameter = self.get_parameter_by_name(name)
if parameter:
parameter["control"].set_value(value)
else:
self.log.debug("Unknown path parameter requested: %s" % name)
def run_path_generator(self, name, parameters):
generator = self.get_by_name(name)
if generator:
args = {}
for key in parameters:
if not key in generator["parameters"]:
continue
args[key] = parameters[key]
generator["func"](**parameters)
else:
self.log.debug("Tried to run a non-existing path generator:" + \
name)
#TODO: merge with ProcessStrategyManager
class PathParameterGTK(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "Processes"]
def setup(self):
# TODO: check for gtk
if True:
import gtk
self._gtk = gtk
self._table = gtk.Table(rows=1, columns=2)
self._table.set_col_spacings(3)
self._table.set_row_spacings(3)
self.core.register_ui("process_parameters", "Path parameters", self._table, 30)
self.core.register_event("pathgenerator-parameter-changed",
lambda: self.core.emit_event("process-changed"))
self.core.register_event("process-changed",
self._update_parameter_widgets)
self.core.register_event("process-strategy-changed",
self._update_parameter_widgets)
self.core.register_event("pathgenerator-parameter-list-changed",
self._update_parameter_widgets_table)
self._update_parameter_widgets_table()
self._table.show()
return True
def teardown(self):
if self.gui:
self.core.unregister_ui("process_parameters", self._table)
def _update_parameter_widgets_table(self):
# TODO: check for gtk
if True:
gtk = self._gtk
params = self.core.get("pathgenerator_parameters")
# remove all widgets from the table
for child in self._table.get_children():
self._table.remove(child)
# add the current controls
for index, param in enumerate(params):
widget = param["control"].get_widget()
if hasattr(widget, "get_label"):
# checkbox
widget.set_label(param["label"])
self._table.attach(widget, 0, 2, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
else:
# spinbutton, combobox, ...
label = gtk.Label("%s:" % param["label"])
label.set_alignment(0.0, 0.5)
self._table.attach(label, 0, 1, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
self._table.attach(widget, 1, 2, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
self._update_parameter_widgets()
def _get_table_row_of_widget(self, widget):
for child in self._table.get_children():
if child is widget:
return self._get_child_row(child)
else:
return -1
def _get_child_row(self, widget):
return self._gtk.Container.child_get_property(self._table, widget,
"top-attach")
def _update_parameter_widgets(self):
params = self.core.get("pathgenerator_parameters")
generator = self.core.get("current-strategy")
if not generator:
return
for param in params:
table_row = self._get_table_row_of_widget(
param["control"].get_widget())
for child in self._table.get_children():
if self._get_child_row(child) == table_row:
if param["name"] in generator["parameters"]:
child.show()
else:
child.hide()
......@@ -26,19 +26,20 @@ import pycam.Plugins
class ProcessStrategySlicing(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamOverlap",
DEPENDS = ["ParameterGroupManager", "PathParamOverlap",
"PathParamStepDown", "PathParamMaterialAllowance",
"PathParamMillingStyle", "PathParamGridDirection"]
def setup(self):
parameters = {"overlap": 10,
parameters = {"overlap": 0.1,
"step_down": 1.0,
"material_allowance": 0,
"milling_style": "ignore",
"grid_direction": "x",
}
self.core.get("register_strategy")("slicing", "Slice removal",
self.run_strategy, parameters=parameters, weight=10)
self.core.get("register_parameter_set")("process", "slicing",
"Slice removal", self.run_strategy, parameters=parameters,
weight=10)
return True
def teardown(self):
......
......@@ -26,18 +26,19 @@ import pycam.Plugins
class ProcessStrategySurfacing(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamOverlap",
DEPENDS = ["ParameterGroupManager", "PathParamOverlap",
"PathParamMaterialAllowance", "PathParamMillingStyle",
"PathParamGridDirection"]
def setup(self):
parameters = {"overlap": 60,
parameters = {"overlap": 0.6,
"material_allowance": 0,
"milling_style": "ignore",
"grid_direction": "x",
}
self.core.get("register_strategy")("surfacing", "Surfacing",
self.run_strategy, parameters=parameters, weight=50)
self.core.get("register_parameter_set")("process", "surfacing",
"Surfacing", self.run_strategy, parameters=parameters,
weight=50)
return True
def teardown(self):
......
......@@ -25,7 +25,7 @@ import pycam.Plugins
class Processes(pycam.Plugins.ListPluginBase):
DEPENDS = ["ProcessStrategyManager"]
DEPENDS = ["ParameterGroupManager"]
UI_FILE = "processes.ui"
COLUMN_REF, COLUMN_NAME = range(2)
......@@ -59,12 +59,20 @@ class Processes(pycam.Plugins.ListPluginBase):
frame.set_label_widget(frame_label)
align = gtk.Alignment()
frame.add(align)
align.set_padding(0, 0, 12, 0)
align.set_padding(0, 3, 12, 3)
align.add(item)
frame.show_all()
parameters_box.pack_start(frame, expand=False)
self.core.register_ui_section("process_parameters",
add_parameter_widget, clear_parameter_widgets)
self.core.get("register_parameter_group")("process",
changed_set_event="process-strategy-changed",
changed_set_list_event="process-strategy-list-changed",
get_current_set_func=self._get_strategy)
parameter_widget = self.core.get("register_parameter_section")(
"process", "pathgenerator")
self.core.register_ui("process_parameters", "Path parameters",
parameter_widget, weight=10)
selection = self._modelview.get_selection()
selection.connect("changed",
lambda widget, event: self.core.emit_event(event),
......@@ -85,23 +93,18 @@ class Processes(pycam.Plugins.ListPluginBase):
cache[id(item)] = [id(item), "Process #%d" % index]
self._treemodel.append(cache[id(item)])
self.core.emit_event("process-list-changed")
self.gui.get_object("StrategySelector").connect("changed",
lambda widget: self.core.emit_event(
"process-strategy-changed"))
strategy_selector = self.gui.get_object("StrategySelector")
strategy_selector.connect("changed", lambda widget: \
self.core.emit_event("process-strategy-changed"))
self.core.register_event("process-strategy-list-changed",
self._update_widgets)
self.register_model_update(update_model)
self.core.register_event("process-selection-changed",
self._process_switch)
self.core.register_event("pathgenerator-parameter-changed",
self.core.register_event("process-parameter-changed",
self._store_process_settings)
self.core.register_event("process-strategy-changed",
self._store_process_settings)
self.core.add_item("current-strategy", lambda: self._get_strategy())
self._update_widgets()
self._process_switch()
self._store_process_settings()
self._trigger_table_update()
self.core.set("processes", self)
return True
......@@ -148,7 +151,8 @@ class Processes(pycam.Plugins.ListPluginBase):
# TODO: keep the current selection
model = self.gui.get_object("StrategyModel")
model.clear()
strategies = self.core.get("process-strategies")
strategies = list(self.core.get("get_parameter_sets")("process").values())
strategies.sort(key=lambda item: item["weight"])
for strategy in strategies:
model.append((strategy["label"], strategy["name"]))
# check if any on the processes became obsolete due to a missing plugin
......@@ -164,26 +168,25 @@ class Processes(pycam.Plugins.ListPluginBase):
self.gui.get_object("ProcessNew").set_sensitive(len(model) > 0)
def _get_strategy(self, name=None):
strategies = self.core.get("process-strategies")
strategies = self.core.get("get_parameter_sets")("process")
if name is None:
# find the currently selected one
model = self.gui.get_object("StrategyModel")
selector = self.gui.get_object("StrategySelector")
model = selector.get_model()
index = selector.get_active()
if index < 0:
return None
strategy_name = model[index][1]
else:
strategy_name = name
for strategy in strategies:
if strategy_name == strategy["name"]:
return strategy
if strategy_name in strategies:
return strategies[strategy_name]
else:
return None
def select_strategy(self, name):
selector = self.gui.get_object("StrategySelector")
for index, row in enumerate(self.gui.get_object("StrategyModel")):
for index, row in enumerate(selector.get_model()):
if row[1] == name:
selector.set_active(index)
break
......@@ -199,34 +202,33 @@ class Processes(pycam.Plugins.ListPluginBase):
else:
process["strategy"] = strategy["name"]
parameters = process["parameters"]
for parameter in self.core.get("pathgenerator_parameters"):
if parameter["name"] in strategy["parameters"]:
parameters[parameter["name"]] = \
parameter["control"].get_value()
parameters.update(self.core.get("get_parameter_values")("process"))
control_box.show()
self._trigger_table_update()
def _process_switch(self, widget=None, data=None):
process = self.get_selected()
control_box = self.gui.get_object("ProcessSettingsControlsBox")
self.core.block_event("pathgenerator-parameter-changed")
if not process:
control_box.hide()
else:
self.core.block_event("process-parameter-changed")
self.core.block_event("process-strategy-changed")
strategy_name = process["strategy"]
self.select_strategy(strategy_name)
strategy = self._get_strategy(strategy_name)
for parameter in self.core.get("pathgenerator_parameters"):
if parameter["name"] in strategy["parameters"]:
parameter["control"].set_value(
process["parameters"][parameter["name"]])
self.core.get("set_parameter_values")("process", process["parameters"])
control_box.show()
self.core.unblock_event("pathgenerator-parameter-changed")
self.core.unblock_event("process-strategy-changed")
self.core.unblock_event("process-parameter-changed")
self.core.emit_event("process-strategy-changed")
def _process_new(self, *args):
strategy = self.core.get("process-strategies")[0]
strategies = self.core.get("get_parameter_sets")("process").values()
strategies.sort(key=lambda item: item["weight"])
strategy = strategies[0]
new_process = {"strategy": strategy["name"],
"parameters": strategy["parameters"].copy()
"parameters": strategy["parameters"].copy(),
}
self.append(new_process)
self.select(new_process)
......
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
import pycam.Gui.ControlsGTK
class ToolParamRadius(pycam.Plugins.PluginBase):
DEPENDS = ["Tools"]
def setup(self):
control = pycam.Gui.ControlsGTK.InputNumber(lower=0, upper=99, digits=0,
change_handler=lambda widget=None: self.core.emit_event(
"tool-parameter-changed"))
control.set_conversion(set_conv=lambda value: value * 2.0,
get_conv=lambda value: value / 2.0)
self.core.get("register_parameter")("tool", "size", "radius",
"Tool diameter", control, weight=10)
return True
def teardown(self):
self.core.get("unregister_parameter")("tool", "size", "radius")
class ToolParamTorusRadius(pycam.Plugins.PluginBase):
DEPENDS = ["Tools"]
def setup(self):
control = pycam.Gui.ControlsGTK.InputNumber(lower=0, upper=99, digits=0,
change_handler=lambda widget=None: self.core.emit_event(
"tool-parameter-changed"))
self.core.get("register_parameter")("tool", "size", "torus_radius",
"Torus radius", control, weight=20)
return True
def teardown(self):
self.core.get("unregister_parameter")("tool", "size", "torus_radius")
class ToolParamFeedrate(pycam.Plugins.PluginBase):
DEPENDS = ["Tools"]
def setup(self):
control = pycam.Gui.ControlsGTK.InputNumber(lower=0, upper=10000,
digits=0, change_handler=lambda widget=None: \
self.core.emit_event("tool-parameter-changed"))
self.core.get("register_parameter")("tool", "speed", "feedrate",
"Feedrate", control, weight=10)
return True
def teardown(self):
self.core.get("unregister_parameter")("tool", "speed", "feedrate")
class ToolParamSpindleSpeed(pycam.Plugins.PluginBase):
DEPENDS = ["Tools"]
def setup(self):
control = pycam.Gui.ControlsGTK.InputNumber(lower=0, upper=100000,
digits=0, change_handler=lambda widget=None: \
self.core.emit_event("tool-parameter-changed"))
self.core.get("register_parameter")("tool", "speed", "spindle_speed",
"Spindle speed", control, weight=20)
return True
def teardown(self):
self.core.get("unregister_parameter")("tool", "speed", "spindle_speed")
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ToolTypeBallNose(pycam.Plugins.PluginBase):
DEPENDS = ["Tools", "ToolParamRadius", "ToolParamFeedrate"]
def setup(self):
parameters = {"radius": 1.0,
"feedrate": 300,
"spindle_speed": 1000,
}
self.core.get("register_parameter_set")("tool", "ballnose",
"Ball nose", self.get_tool, parameters=parameters,
weight=20)
return True
def teardown(self):
self.core.get("unregister_parameter_set")("tool", "ballnose")
def get_tool(self):
pass
class ToolTypeBullNose(pycam.Plugins.PluginBase):
DEPENDS = ["Tools", "ToolParamRadius", "ToolParamTorusRadius",
"ToolParamFeedrate"]
def setup(self):
parameters = {"radius": 1.0,
"torus_radius": 0.25,
"feedrate": 300,
"spindle_speed": 1000,
}
self.core.get("register_parameter_set")("tool", "bullnose",
"Bull nose", self.get_tool, parameters=parameters,
weight=30)
return True
def teardown(self):
self.core.get("unregister_parameter_set")("tool", "bullnose")
def get_tool(self):
pass
class ToolTypeFlat(pycam.Plugins.PluginBase):
DEPENDS = ["Tools", "ToolParamRadius", "ToolParamFeedrate"]
def setup(self):
parameters = {"radius": 1.0,
"feedrate": 300,
"spindle_speed": 1000,
}
self.core.get("register_parameter_set")("tool", "flat", "Flat bottom",
self.get_tool, parameters=parameters, weight=10)
return True
def teardown(self):
self.core.get("unregister_parameter_set")("tool", "flat")
def get_tool(self):
pass
......@@ -29,14 +29,12 @@ from pycam.Cutters.ToroidalCutter import ToroidalCutter
class Tools(pycam.Plugins.ListPluginBase):
UI_FILE = "tools.ui"
COLUMN_REF, COLUMN_ID, COLUMN_NAME = range(3)
LIST_ATTRIBUTE_MAP = {"id": COLUMN_ID, "name": COLUMN_NAME}
SHAPE_MAP = {CylindricalCutter: ("CylindricalCutter", "Flat end"),
SphericalCutter: ("SphericalCutter", "Ball nose"),
ToroidalCutter: ("ToroidalCutter", "Bull nose")}
COLUMN_REF, COLUMN_TOOL_ID, COLUMN_NAME = range(3)
LIST_ATTRIBUTE_MAP = {"id": COLUMN_TOOL_ID, "name": COLUMN_NAME}
def setup(self):
if self.gui:
import gtk
tool_frame = self.gui.get_object("ToolBox")
tool_frame.unparent()
self.core.register_ui("main", "Tools", tool_frame, weight=10)
......@@ -47,13 +45,44 @@ class Tools(pycam.Plugins.ListPluginBase):
self.register_list_action_button(action, self._modelview,
self.gui.get_object(obj_name))
self.gui.get_object("ToolNew").connect("clicked", self._tool_new)
selection = self._modelview.get_selection()
selection.connect("changed",
lambda widget, event: self.core.emit_event(event),
"tool-selection-changed")
# parameters
parameters_box = self.gui.get_object("ToolParameterBox")
def clear_parameter_widgets():
parameters_box.foreach(
lambda widget: parameters_box.remove(widget))
def add_parameter_widget(item, name):
# create a frame with an align and the item inside
if len(parameters_box.get_children()) > 0:
# add a separator between two content blocks
parameters_box.pack_start(gtk.VSeparator())
frame_label = gtk.Label()
frame_label.set_markup("<b>%s</b>" % name)
frame = gtk.Frame()
frame.set_label_widget(frame_label)
align = gtk.Alignment()
frame.add(align)
align.set_padding(0, 3, 12, 3)
align.add(item)
frame.show_all()
parameters_box.pack_start(frame, expand=True)
self.core.register_ui_section("tool_parameters",
add_parameter_widget, clear_parameter_widgets)
selector = self.gui.get_object("ToolShapeSelector")
self.core.get("register_parameter_group")("tool",
changed_set_event="tool-shape-changed",
changed_set_list_event="tool-shape-list-changed",
get_current_set_func=self._get_shape)
size_parameter_widget = self.core.get("register_parameter_section")(
"tool", "size")
self.core.register_ui("tool_parameters", "Size",
size_parameter_widget, weight=10)
speed_parameter_widget = self.core.get("register_parameter_section")(
"tool", "speed")
self.core.register_ui("tool_parameters", "Speed",
speed_parameter_widget, weight=20)
cell = self.gui.get_object("ToolTableShapeCell")
self.gui.get_object("ToolTableShapeColumn").set_cell_data_func(
cell, self._visualize_tool_size)
cell, self._render_tool_shape)
self.gui.get_object("ToolTableIDCell").connect("edited",
self._edit_tool_id)
self.gui.get_object("ToolTableNameCell").connect("edited",
......@@ -65,7 +94,7 @@ class Tools(pycam.Plugins.ListPluginBase):
self._model_cache = {}
cache = self._model_cache
for row in self._treemodel:
cache[row[self.COLUMN_ID]] = list(row)
cache[row[self.COLUMN_REF]] = list(row)
self._treemodel.clear()
for index, item in enumerate(self):
if not id(item) in cache:
......@@ -73,27 +102,25 @@ class Tools(pycam.Plugins.ListPluginBase):
"Tool #%d" % index]
self._treemodel.append(cache[id(item)])
self.core.emit_event("tool-list-changed")
# selector
selection = self._modelview.get_selection()
selection.connect("changed",
lambda widget, event: self.core.emit_event(event),
"tool-selection-changed")
shape_selector = self.gui.get_object("ToolShapeSelector")
shape_selector.connect("changed", lambda widget: \
self.core.emit_event("tool-shape-changed"))
self.core.register_event("tool-shape-list-changed",
self._update_widgets)
self.register_model_update(update_model)
# drill settings
self._detail_handlers = []
for objname in ("ToolDiameterControl", "TorusDiameterControl"):
obj = self.gui.get_object(objname)
handler = obj.connect("value-changed",
lambda *args: self.core.emit_event(args[-1]),
"tool-changed")
self._detail_handlers.append((obj, handler))
for objname in ("SphericalCutter", "CylindricalCutter",
"ToroidalCutter"):
obj = self.gui.get_object(objname)
handler = obj.connect("toggled",
lambda *args: self.core.emit_event(args[-1]),
"tool-changed")
self._detail_handlers.append((obj, handler))
self.core.register_event("tool-selection-changed",
self._tool_change)
self.core.register_event("tool-changed",
self._update_tool_controls)
self._update_tool_controls()
self.core.register_event("tool-parameter-changed",
self._store_tool_settings)
self.core.register_event("tool-shape-changed",
self._store_tool_settings)
self._update_widgets()
self._tool_change()
self.core.set("tools", self)
return True
......@@ -102,8 +129,6 @@ class Tools(pycam.Plugins.ListPluginBase):
self.core.unregister_ui("main", self.gui.get_object("ToolBox"))
self.core.unregister_event("tool-selection-changed",
self._tool_change)
self.core.unregister_event("tool-changed",
self._update_tool_controls)
self.core.set("tools", None)
return True
......@@ -118,13 +143,14 @@ class Tools(pycam.Plugins.ListPluginBase):
selection.unselect_all()
selection.select_path((index,))
def _visualize_tool_size(self, column, cell, model, m_iter):
def _render_tool_shape(self, column, cell, model, m_iter):
path = model.get_path(m_iter)
tool = self[path[0]]
for cutter_class, (objname, desc) in self.SHAPE_MAP.iteritems():
if isinstance(tool, cutter_class):
break
text = "%s (%g%s)" % (desc, 2 * tool.radius, self.core.get("unit"))
parameters = tool["parameters"]
if "radius" in parameters:
text = "%g%s" % (2 * parameters["radius"], self.core.get("unit"))
else:
text = ""
cell.set_property("text", text)
def _edit_tool_name(self, cell, path, new_text):
......@@ -139,45 +165,73 @@ class Tools(pycam.Plugins.ListPluginBase):
new_value = int(new_text)
except ValueError:
return
if str(new_value) != self._treemodel[path][self.COLUMN_ID]:
self._treemodel[path][self.COLUMN_ID] = new_value
if str(new_value) != self._treemodel[path][self.COLUMN_TOOL_ID]:
self._treemodel[path][self.COLUMN_TOOL_ID] = new_value
def _update_tool_controls(self):
tool_index = self.get_selected(index=True)
if tool_index is None:
self.gui.get_object("ToolSettingsControlsBox").hide()
return
# disable the toroidal radius if the toroidal cutter is not enabled
if self.gui.get_object("ToroidalCutter").get_active():
self.gui.get_object("TorusDiameterControl").show()
self.gui.get_object("TorusDiameterLabel").show()
def _get_shape(self, name=None):
shapes = self.core.get("get_parameter_sets")("tool")
if name is None:
# find the currently selected one
selector = self.gui.get_object("ToolShapeSelector")
model = selector.get_model()
index = selector.get_active()
if index < 0:
return None
shape_name = model[index][1]
else:
shape_name = name
if shape_name in shapes:
return shapes[shape_name]
else:
self.gui.get_object("TorusDiameterControl").hide()
self.gui.get_object("TorusDiameterLabel").hide()
for objname, default_value in (("ToolDiameterControl", 1.0),
("TorusDiameterControl", 0.25)):
obj = self.gui.get_object(objname)
if obj.get_value() == 0:
# set the value to the configured minimum
obj.set_value(default_value)
# update the tool object
for cutter_class, (objname, desc) in self.SHAPE_MAP.iteritems():
if self.gui.get_object(objname).get_active():
return None
def select_shape(self, name):
selector = self.gui.get_object("ToolShapeSelector")
for index, row in enumerate(selector.get_model()):
if row[1] == name:
selector.set_active(index)
break
radius = 0.5 * self.gui.get_object("ToolDiameterControl").get_value()
if cutter_class is ToroidalCutter:
args = [0.5 * self.gui.get_object("TorusDiameterControl").get_value()]
else:
args = []
new_tool = cutter_class(radius, *args)
old_tool = self.pop(tool_index)
self.insert(tool_index, new_tool)
if hasattr(self, "_model_cache"):
# move the cache item
cache = self._model_cache
cache[id(new_tool)] = cache[id(old_tool)]
del cache[id(old_tool)]
self.select(new_tool)
selector.set_active(-1)
def _trigger_table_update(self):
# trigger a table update - this is clumsy!
cell = self.gui.get_object("ToolTableShapeColumn")
renderer = self.gui.get_object("ToolTableShapeCell")
cell.set_cell_data_func(renderer, self._render_tool_shape)
def _update_widgets(self):
# TODO: keep the current selection
model = self.gui.get_object("ToolShapeList")
model.clear()
shapes = list(self.core.get("get_parameter_sets")("tool").values())
shapes.sort(key=lambda item: item["weight"])
for shape in shapes:
model.append((shape["label"], shape["name"]))
# check if any on the processes became obsolete due to a missing plugin
removal = []
shape_names = [shape["name"] for shape in shapes]
for index, tool in enumerate(self):
if not tool["shape"] in shape_names:
removal.append(index)
removal.reverse()
for index in removal:
self.pop(index)
# show "new" only if a strategy is available
self.gui.get_object("ToolNew").set_sensitive(len(model) > 0)
def _store_tool_settings(self):
tool = self.get_selected()
control_box = self.gui.get_object("ToolSettingsControlsBox")
shape = self._get_shape()
if tool is None or shape is None:
control_box.hide()
else:
tool["shape"] = shape["name"]
parameters = tool["parameters"]
parameters.update(self.core.get("get_parameter_values")("tool"))
control_box.show()
self._trigger_table_update()
def _tool_change(self, widget=None, data=None):
tool = self.get_selected()
......@@ -185,33 +239,24 @@ class Tools(pycam.Plugins.ListPluginBase):
if not tool:
control_box.hide()
else:
for obj, handler in self._detail_handlers:
obj.handler_block(handler)
# cutter shapes
for cutter_class, (objname, desc) in self.SHAPE_MAP.iteritems():
if isinstance(tool, cutter_class):
self.gui.get_object(objname).set_active(True)
# radius -> diameter
self.gui.get_object("ToolDiameterControl").set_value(2 * tool.radius)
torus_control = self.gui.get_object("TorusDiameterControl")
torus_label = self.gui.get_object("TorusDiameterLabel")
if hasattr(tool, "minorradius"):
torus_control.set_value(2 * tool.minorradius)
torus_control.show()
torus_label.show()
else:
torus_control.set_value(0.25)
torus_control.hide()
torus_label.hide()
for obj, handler in self._detail_handlers:
obj.handler_unblock(handler)
self.core.block_event("tool-parameter-changed")
self.core.block_event("tool-shape-changed")
shape_name = tool["shape"]
self.select_shape(shape_name)
shape = self._get_shape(shape_name)
self.core.get("set_parameter_values")("tool", tool["parameters"])
control_box.show()
self.core.unblock_event("tool-shape-changed")
self.core.unblock_event("tool-parameter-changed")
# trigger a widget update
self.core.emit_event("tool-shape-changed")
def _tool_new(self, *args):
current_tool_index = self.get_selected(index=True)
if current_tool_index is None:
current_tool_index = 0
new_tool = CylindricalCutter(1.0)
shapes = self.core.get("get_parameter_sets")("tool").values()
shapes.sort(key=lambda item: item["weight"])
shape = shapes[0]
new_tool = {"shape": shape["name"],
"parameters": shape["parameters"].copy(),
}
self.append(new_tool)
self.select(new_tool)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment