Commit f43f2b5f authored by sumpfralle's avatar sumpfralle

splitted all process parameters into seperate plugins

created a framework for processing strategies


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@1139 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 1c7dbc76
......@@ -2,48 +2,27 @@
<interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-naming-policy project-wide -->
<object class="GtkAdjustment" id="EngraveOffsetValue">
<property name="lower">-1000</property>
<property name="upper">1000</property>
<property name="step_increment">0.5</property>
</object>
<object class="GtkAdjustment" id="OverlapPercentValue">
<property name="upper">99</property>
<property name="step_increment">5</property>
</object>
<object class="GtkAdjustment" id="MaxStepDownValue">
<property name="lower">0.01</property>
<property name="upper">100</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="MaterialAllowanceValue">
<property name="upper">100</property>
<property name="step_increment">0.10000000000000001</property>
</object>
<object class="GtkListStore" id="PocketingOptions">
<object class="GtkListStore" id="ProcessList">
<columns>
<!-- column-name ref -->
<column type="gulong"/>
<!-- column-name name -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">none</col>
</row>
<row>
<col id="0" translatable="yes">holes</col>
</row>
<row>
<col id="0" translatable="yes">enclosed</col>
</row>
</data>
</object>
<object class="GtkListStore" id="ProcessList">
<object class="GtkListStore" id="StrategyModel">
<columns>
<!-- column-name ref -->
<column type="gulong"/>
<!-- column-name label -->
<column type="gchararray"/>
<!-- column-name name -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Slicing</col>
<col id="1" translatable="yes">slicing</col>
</row>
</data>
</object>
<object class="GtkWindow" id="window1">
<child>
......@@ -210,103 +189,19 @@
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox29">
<property name="visible">True</property>
<child>
<object class="GtkFrame" id="frame8">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment7">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox21">
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">1</property>
<property name="xscale">0</property>
<property name="yscale">0</property>
<child>
<object class="GtkRadioButton" id="PushRemoveStrategy">
<property name="label" translatable="yes">Slice removal</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="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="ContourPolygonStrategy">
<property name="label" translatable="yes">Contour (polygon)</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">PushRemoveStrategy</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="ContourFollowStrategy">
<property name="label" translatable="yes">Contour (follow)</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">PushRemoveStrategy</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="SurfaceStrategy">
<property name="label" translatable="yes">Surface</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">PushRemoveStrategy</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">3</property>
</packing>
</child>
<property name="spacing">3</property>
<child>
<object class="GtkRadioButton" id="EngraveStrategy">
<property name="label" translatable="yes">Engraving</property>
<object class="GtkLabel" id="label1">
<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">PushRemoveStrategy</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="ToolpathStrategy">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Path Strategy&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
<property name="xalign">0</property>
<property name="label" translatable="yes">Strategy:</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -314,284 +209,23 @@
</packing>
</child>
<child>
<object class="GtkVSeparator" id="vseparator9">
<property name="visible">True</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="PathSettingsFrame">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment9">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table7">
<property name="visible">True</property>
<property name="n_rows">5</property>
<property name="n_columns">2</property>
<property name="column_spacing">2</property>
<property name="row_spacing">2</property>
<child>
<object class="GtkLabel" id="OverlapLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Overlap [%]:</property>
</object>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="OverlapPercent">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">OverlapPercentValue</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>
<child>
<object class="GtkLabel" id="MaterialAllowanceLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Material Allowance:</property>
</object>
<packing>
<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>
<child>
<object class="GtkSpinButton" id="MaterialAllowance">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">MaterialAllowanceValue</property>
<property name="digits">2</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>
<child>
<object class="GtkSpinButton" id="MaxStepDown">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">MaxStepDownValue</property>
<property name="digits">2</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="StepDownLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max. Step Down:</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="EngraveOffsetLabel">
<object class="GtkComboBox" id="StrategySelector">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Engrave Offset:</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<property name="model">StrategyModel</property>
<child>
<object class="GtkSpinButton" id="EngraveOffset">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">EngraveOffsetValue</property>
<property name="digits">2</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="PocketingLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Pocketing:</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="PocketingControl">
<property name="visible">True</property>
<property name="model">PocketingOptions</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext7"/>
<object class="GtkCellRendererText" id="StrategyLabelCell"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</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="PathSettingsFrameLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Path Control&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkHSeparator" id="hseparator4">
<property name="visible">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame11">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment17">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkHBox" id="hbox13">
<property name="visible">True</property>
<child>
<object class="GtkHBox" id="hbox31">
<property name="visible">True</property>
<property name="spacing">4</property>
<child>
<object class="GtkLabel" id="GridDirectionLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">Grid direction:</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox15">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="GridDirectionX">
<property name="label" translatable="yes">x</property>
<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">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="GridDirectionY">
<property name="label" translatable="yes">y</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">GridDirectionX</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="GridDirectionXY">
<property name="label" translatable="yes">both </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">GridDirectionX</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
......@@ -600,103 +234,18 @@
</packing>
</child>
<child>
<object class="GtkVSeparator" id="vseparator8">
<property name="visible">True</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="MillingStyleLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">Milling Style:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox33">
<object class="GtkVBox" id="ProcessParametersBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="MillingStyleConventional">
<property name="label" translatable="yes">conventional / up</property>
<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="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="MillingStyleClimb">
<property name="label" translatable="yes">climb / down</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">MillingStyleConventional</property>
</object>
<packing>
<property name="position">1</property>
</packing>
<placeholder/>
</child>
<child>
<object class="GtkRadioButton" id="MillingStyleIgnore">
<property name="label" translatable="yes">ignore</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">MillingStyleConventional</property>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="PathDirectionFrameLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Path Direction&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">False</property>
......
# -*- 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/>.
"""
# gtk and gobject are imported later (to avoid plugin load failures)
import pycam.Utils.log
_log = pycam.Utils.log.get_logger()
class InputBaseClass(object):
def get_widget(self):
return self.control
def set_visible(self, state):
if state:
self.control.show()
else:
self.control.hide()
class InputNumber(InputBaseClass):
def __init__(self, digits=0, start=0, lower=0, upper=100,
increment=1, change_handler=None):
import gtk
adjustment = gtk.Adjustment(value=start, lower=lower, upper=upper,
step_incr=increment)
self.control = gtk.SpinButton(adjustment, digits=digits)
self.control.set_value(start)
if change_handler:
self.control.connect("changed", change_handler)
def get_value(self):
return self.control.get_value()
def set_value(self, value):
self.control.set_value(value)
class InputChoice(InputBaseClass):
def __init__(self, choices, force_type=None, change_handler=None):
import gtk
import gobject
type_mapper = {int: gobject.TYPE_INT,
long: gobject.TYPE_LONG,
basestring: gobject.TYPE_STRING,
bool: gobject.TYPE_BOOLEAN
}
if force_type is None:
value_sample = choices[0][1]
for key, g_type in type_mapper.iteritems():
if isinstance(value_sample, key):
break
else:
raise TypeError("Invalid sample type give: %s - %s" % \
(sample_value, type(sample_value)))
elif force_type in type_mapper:
g_type = type_mapper[force_type]
else:
raise TypeError("Invalid type forced: %s" % str(force_type))
self.model = gtk.ListStore(gobject.TYPE_STRING, g_type)
self.control = gtk.ComboBox(self.model)
renderer = gtk.CellRendererText()
self.control.pack_start(renderer)
self.control.set_attributes(renderer, text=0)
for label, value in choices:
self.model.append((label, value))
self.control.set_active(0)
if change_handler:
self.control.connect("changed", change_handler)
def get_value(self):
index = self.control.get_active()
if index < 0:
return None
else:
return self.model[index][1]
def set_value(self, value):
if value is None:
self.control.set_active(-1)
else:
for index, row in enumerate(self.model):
if row[1] == value:
self.control.set_active(index)
break
else:
_log.debug("Tried to set an invalid value: %s" % str(value))
def update_choices(self, choices):
# TODO: selection restore does not work currently; there seems to be a glitch during "delete model"
old_selection_index = self.control.get_active()
if old_selection_index < 0:
old_selection = None
else:
old_selection = self.model[old_selection_index][1]
for choice_index, (label, value) in enumerate(choices):
for index, row in enumerate(self.model):
if row[1] == value:
break
else:
# this choice is new
self.model.insert(choice_index, (label, value))
continue
# the current choice is preceded by some obsolete items
while index > choice_index:
m_iter = self.model.get_iter((index,))
self.model.remove(m_iter)
index -= 1
# update the label column
row[0] = label
# check if there are obsolete items after the last one
while len(self.model) > len(choices):
m_iter = self.model.get_iter((len(choices),))
self.model.remove(m_iter)
# restore the previous selection
for index, row in enumerate(self.model):
if row[1] == old_selection:
self.control.set_active(index)
print "Restored: %d" % index
break
else:
self.control.set_active(-1)
class InputCheckBox(InputBaseClass):
def __init__(self, start=False, change_handler=None):
import gtk
self.control = gtk.CheckButton()
self.control.set_active(start)
if change_handler:
self.control.connect("toggled", change_handler)
def get_value(self):
return self.control.get_active()
def set_value(self, value):
self.control.set_active(value)
# -*- 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 PathParamOverlap(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
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)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("overlap")
class PathParamStepDown(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
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)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("step_down")
class PathParamMaterialAllowance(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
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)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("overlap")
class PathParamMillingStyle(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
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)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("milling_style")
class PathParamGridDirection(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
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)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("grid_direction")
class PathParamRadiusCompensation(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("radius_compensation",
"Radius compensation",
pycam.Gui.ControlsGTK.InputCheckBox(
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed")),
weight=80)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("radius_compensation")
class PathParamTraceModel(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "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,
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)
self.core.register_event("model-list-changed", self._update_models)
return True
def _update_models(self):
choices = []
models = self.core.get("models")
for model in models:
if hasattr(model, "get_polygons"):
choices.append((models.get_attr(model, "name"), id(model)))
self.input_control.update_choices(choices)
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("trace_model")
# -*- 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 ProcessStrategyContour(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamStepDown",
"PathParamMaterialAllowance", "PathParamMillingStyle"]
def setup(self):
parameters = {"step_down": 1.0,
"material_allowance": 0,
"milling_style": "ignore",
}
self.core.get("register_strategy")("contour", "Waterline",
self.run_strategy, parameters=parameters, weight=20)
return True
def teardown(self):
self.core.get("unregister_strategy")("contour")
def run_strategy(self):
pass
# -*- 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 ProcessStrategyEngraving(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamStepDown",
"PathParamMillingStyle", "PathParamRadiusCompensation",
"PathParamTraceModel"]
def setup(self):
parameters = {"step_down": 1.0,
"milling_style": "ignore",
"radius_compensation": False,
"trace_model": None
}
self.core.get("register_strategy")("engraving", "Engraving",
self.run_strategy, parameters=parameters, weight=80)
return True
def teardown(self):
self.core.get("unregister_strategy")("engraving")
def run_strategy(self):
pass
# -*- 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()
# -*- 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 ProcessStrategySlicing(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamOverlap",
"PathParamStepDown", "PathParamMaterialAllowance",
"PathParamMillingStyle", "PathParamGridDirection"]
def setup(self):
parameters = {"overlap": 10,
"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)
return True
def teardown(self):
self.core.get("unregister_strategy")("slicing")
def run_strategy(self):
pass
# -*- 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 ProcessStrategySurfacing(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamOverlap",
"PathParamMaterialAllowance", "PathParamMillingStyle",
"PathParamGridDirection"]
def setup(self):
parameters = {"overlap": 60,
"material_allowance": 0,
"milling_style": "ignore",
"grid_direction": "x",
}
self.core.get("register_strategy")("surfacing", "Surfacing",
self.run_strategy, parameters=parameters, weight=50)
return True
def teardown(self):
self.core.get("unregister_strategy")("surfacing")
def run_strategy(self):
pass
......@@ -25,20 +25,11 @@ import pycam.Plugins
class Processes(pycam.Plugins.ListPluginBase):
DEPENDS = ["ProcessStrategyManager"]
UI_FILE = "processes.ui"
COLUMN_REF, COLUMN_NAME = range(2)
LIST_ATTRIBUTE_MAP = {"ref": COLUMN_REF, "name": COLUMN_NAME}
CONTROL_BUTTONS = ("PushRemoveStrategy", "ContourPolygonStrategy",
"ContourFollowStrategy", "SurfaceStrategy", "EngraveStrategy",
"OverlapPercent", "MaterialAllowance",
"MaxStepDown", "EngraveOffset",
"PocketingControl", "GridDirectionX", "GridDirectionY",
"GridDirectionXY", "MillingStyleConventional", "MillingStyleClimb",
"MillingStyleIgnore")
POCKETING_TYPES = ["none", "holes", "enclosed"]
CONTROL_SIGNALS = ("toggled", "value-changed", "changed")
CONTROL_GET = ("get_active", "get_value")
CONTROL_SET = ("set_active", "set_value")
def setup(self):
if self.gui:
......@@ -55,15 +46,31 @@ class Processes(pycam.Plugins.ListPluginBase):
self.gui.get_object(obj_name))
self.gui.get_object("ProcessNew").connect("clicked",
self._process_new)
# parameters
parameters_box = self.gui.get_object("ProcessParametersBox")
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
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, 0, 12, 0)
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)
selection = self._modelview.get_selection()
selection.connect("changed",
lambda widget, event: self.core.emit_event(event),
"process-selection-changed")
self.gui.get_object("NameCell").connect("edited",
self._edit_process_name)
cell = self.gui.get_object("DescriptionCell")
self.gui.get_object("DescriptionColumn").set_cell_data_func(
cell, self._render_process_description)
self._treemodel = self.gui.get_object("ProcessList")
self._treemodel.clear()
def update_model():
......@@ -78,27 +85,23 @@ 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"))
self.core.register_event("process-strategy-list-changed",
self._update_widgets)
self.register_model_update(update_model)
# process settings
self._detail_handlers = []
for obj_name in self.CONTROL_BUTTONS:
obj = self.gui.get_object(obj_name)
for signal in self.CONTROL_SIGNALS:
try:
handler = obj.connect(signal,
lambda *args: self.core.emit_event(args[-1]),
"process-changed")
self._detail_handlers.append((obj, handler))
break
except TypeError:
continue
else:
self.log.info("Failed to connect to widget '%s'" % str(obj_name))
self.core.register_event("process-selection-changed",
self._process_switch)
self.core.register_event("process-changed",
self.core.register_event("pathgenerator-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
......@@ -126,26 +129,7 @@ class Processes(pycam.Plugins.ListPluginBase):
path = model.get_path(m_iter)
data = self[path[0]]
# find the current strategy
for key in ("PushRemoveStrategy", "ContourPolygonStrategy",
"ContourFollowStrategy", "SurfaceStrategy", "EngraveStrategy"):
if data[key]:
strategy = key
break
if strategy == "PushRemoveStrategy":
text = "Slice %g%s %d%%" % (data["MaxStepDown"],
self.core.get("unit"), data["OverlapPercent"])
elif strategy == "ContourPolygonStrategy":
text = "Contour (polygon) %g%s" % (data["MaxStepDown"],
self.core.get("unit"))
elif strategy == "ContourFollowStrategy":
text = "Contour (follow) %g%s" % (data["MaxStepDown"],
self.core.get("unit"))
elif strategy == "SurfaceStrategy":
text = "Surface %d%%" % data["OverlapPercent"]
else:
# EngraveStrategy
text = "Engrave %g%s" % (data["EngraveOffset"],
self.core.get("unit"))
text = "TODO"
cell.set_property("text", text)
def _edit_process_name(self, cell, path, new_text):
......@@ -154,136 +138,96 @@ class Processes(pycam.Plugins.ListPluginBase):
new_text:
self._treemodel[path][self.COLUMN_NAME] = new_text
def _store_process_settings(self):
data = self.get_selected()
if data is None:
self.gui.get_object("ProcessSettingsControlsBox").hide()
return
else:
for obj_name in self.CONTROL_BUTTONS:
obj = self.gui.get_object(obj_name)
for get_func in self.CONTROL_GET:
if hasattr(obj, get_func):
value = getattr(obj, get_func)()
data[obj_name] = value
break
else:
self.log.info("Failed to update value of control %s" % obj_name)
self.gui.get_object("ProcessSettingsControlsBox").show()
while not self._validate_process_consistency():
pass
def _trigger_table_update(self):
# trigger a table update - this is clumsy!
cell = self.gui.get_object("DescriptionColumn")
renderer = self.gui.get_object("DescriptionCell")
cell.set_cell_data_func(renderer, self._render_process_description)
def _update_widgets(self):
# TODO: keep the current selection
model = self.gui.get_object("StrategyModel")
model.clear()
strategies = self.core.get("process-strategies")
for strategy in strategies:
model.append((strategy["label"], strategy["name"]))
# check if any on the processes became obsolete due to a missing plugin
removal = []
strat_names = [strat["name"] for strat in strategies]
for index, process in enumerate(self):
if not process["strategy"] in strat_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("ProcessNew").set_sensitive(len(model) > 0)
def _get_strategy(self, name=None):
strategies = self.core.get("process-strategies")
if name is None:
# find the currently selected one
model = self.gui.get_object("StrategyModel")
selector = self.gui.get_object("StrategySelector")
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
else:
return None
def select_strategy(self, name):
selector = self.gui.get_object("StrategySelector")
for index, row in enumerate(self.gui.get_object("StrategyModel")):
if row[1] == name:
selector.set_active(index)
break
else:
selector.set_active(-1)
def _store_process_settings(self):
process = self.get_selected()
control_box = self.gui.get_object("ProcessSettingsControlsBox")
strategy = self._get_strategy()
if process is None or strategy is None:
control_box.hide()
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()
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:
for obj, handler in self._detail_handlers:
obj.handler_block(handler)
for obj_name, value in process.iteritems():
obj = self.gui.get_object(obj_name)
for set_func in self.CONTROL_SET:
if hasattr(obj, set_func):
if (value is False) and hasattr(obj, "get_group"):
# no "False" for radio buttons
pass
else:
getattr(obj, set_func)(value)
break
else:
self.log.info("Failed to set value of control %s" % obj_name)
for obj, handler in self._detail_handlers:
obj.handler_unblock(handler)
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"]])
control_box.show()
self.core.unblock_event("pathgenerator-parameter-changed")
def _process_new(self, *args):
current_process_index = self.get_selected(index=True)
if current_process_index is None:
current_process_index = 0
new_process = {"PushRemoveStrategy": True,
"ContourPolygonStrategy": False,
"ContourFollowStrategy": False,
"SurfaceStrategy": False,
"EngraveStrategy": False,
"OverlapPercent": 10,
"MaterialAllowance": 0,
"MaxStepDown": 1,
"EngraveOffset": 0,
"PocketingControl": self.POCKETING_TYPES.index("none"),
"GridDirectionX": True,
"GridDirectionY": False,
"GridDirectionXY": False,
"MillingStyleConventional": False,
"MillingStyleClimb": False,
"MillingStyleIgnore": True,
strategy = self.core.get("process-strategies")[0]
new_process = {"strategy": strategy["name"],
"parameters": strategy["parameters"].copy()
}
self.append(new_process)
self.select(new_process)
# loop until the process is valid
while not self._validate_process_consistency():
pass
def _validate_process_consistency(self):
data = self.get_selected()
if not data:
return True
if data["ContourPolygonStrategy"] and not data["MillingStyleIgnore"]:
data["MillingStyleConventional"] = False
data["MillingStyleIgnore"] = True
data["MillingStyleClimb"] = False
self.gui.get_object("MillingStyleIgnore").set_active(True)
return False
if data["ContourPolygonStrategy"] and not data["GridDirectionX"]:
# only "x" direction for ContourPolygon
data["GridDirectionX"] = True
data["GridDirectionY"] = False
data["GridDirectionXY"] = False
self.gui.get_object("GridDirectionX").set_active(True)
return False
if (data["ContourFollowStrategy"] or data["EngraveStrategy"]) \
and data["MillingStyleIgnore"]:
data["MillingStyleConventional"] = True
data["MillingStyleIgnore"] = False
data["MillingStyleClimb"] = False
self.gui.get_object("MillingStyleConventional").set_active(True)
return False
all_controls = ("GridDirectionX", "GridDirectionY", "GridDirectionXY",
"MillingStyleConventional", "MillingStyleClimb",
"MillingStyleIgnore", "MaxStepDown",
"MaterialAllowance", "OverlapPercent",
"EngraveOffset", "PocketingControl")
active_controls = {
"PushRemoveStrategy": ("GridDirectionX", "GridDirectionY",
"GridDirectionXY", "MillingStyleConventional",
"MillingStyleClimb", "MillingStyleIgnore",
"MaxStepDown", "MaterialAllowance",
"OverlapPercent"),
# TODO: direction y and xy currently don't work for ContourPolygonStrategy
"ContourPolygonStrategy": ("GridDirectionX",
"MillingStyleIgnore", "MaxStepDown",
"MaterialAllowance", "OverlapPercent"),
"ContourFollowStrategy": ("MillingStyleConventional",
"MillingStyleClimb", "MaxStepDown"),
"SurfaceStrategy": ("GridDirectionX", "GridDirectionY",
"GridDirectionXY", "MillingStyleConventional",
"MillingStyleClimb", "MillingStyleIgnore",
"MaterialAllowance", "OverlapPercent"),
"EngraveStrategy": ("MaxStepDown", "EngraveOffset",
"MillingStyleConventional", "MillingStyleClimb",
"PocketingControl"),
}
# find the current strategy
for key in active_controls:
if data[key]:
strategy = key
break
# disable all invalid controls
for one_control in all_controls:
self.gui.get_object(one_control).set_sensitive(one_control in active_controls[strategy])
return True
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