Tools.py 13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
# -*- 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 Tools(pycam.Plugins.ListPluginBase):

28
    DEPENDS = ["ParameterGroupManager"]
29
    CATEGORIES = ["Tool"]
30
    UI_FILE = "tools.ui"
31
    COLUMN_REF = 0
32 33

    def setup(self):
34
        self.core.set("tools", self)
35
        if self.gui:
36
            import gtk
37 38 39
            tool_frame = self.gui.get_object("ToolBox")
            tool_frame.unparent()
            self.core.register_ui("main", "Tools", tool_frame, weight=10)
40
            self._gtk_handlers = []
41 42
            self.core.register_chain("get_toolpath_information",
                    self.get_toolpath_information)
43
            self._modelview = self.gui.get_object("ToolTable")
44 45 46 47 48
            for action, obj_name in ((self.ACTION_UP, "ToolMoveUp"),
                    (self.ACTION_DOWN, "ToolMoveDown"),
                    (self.ACTION_DELETE, "ToolDelete")):
                self.register_list_action_button(action, self._modelview,
                        self.gui.get_object(obj_name))
49 50
            self._gtk_handlers.append((self.gui.get_object("ToolNew"),
                    "clicked", self._tool_new))
51 52 53 54 55 56
            # 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):
57
                # create a frame within an alignment and the item inside
58 59
                if item.get_parent():
                    item.unparent()
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
                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)
            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)
76
            self.size_widget = pycam.Gui.ControlsGTK.ParameterSection()
77
            self.core.register_ui("tool_parameters", "Size",
78
                    self.size_widget.widget, weight=10)
79
            self.core.register_ui_section("tool_size",
80 81 82
                    self.size_widget.add_widget,
                    self.size_widget.clear_widgets)
            self.speed_widget = pycam.Gui.ControlsGTK.ParameterSection()
83
            self.core.register_ui("tool_parameters", "Speed",
84
                    self.speed_widget.widget, weight=20)
85
            self.core.register_ui_section("tool_speed",
86 87
                    self.speed_widget.add_widget,
                    self.speed_widget.clear_widgets)
88
            # table updates
89 90
            cell = self.gui.get_object("ShapeCell")
            self.gui.get_object("ShapeColumn").set_cell_data_func(
91
                    cell, self._render_tool_shape)
92
            self._gtk_handlers.append((self.gui.get_object("IDCell"),
93
                    "edited", self._edit_tool_id))
94
            self._gtk_handlers.append((self.gui.get_object("NameCell"),
95
                    "edited", self._edit_tool_name))
96 97 98 99 100 101 102
            self._treemodel = self.gui.get_object("ToolList")
            self._treemodel.clear()
            def update_model():
                if not hasattr(self, "_model_cache"):
                    self._model_cache = {}
                cache = self._model_cache
                for row in self._treemodel:
103
                    cache[row[self.COLUMN_REF]] = list(row)
104 105
                self._treemodel.clear()
                for index, item in enumerate(self):
106
                    if not id(item) in cache:
107
                        cache[id(item)] = [id(item)]
108
                    self._treemodel.append(cache[id(item)])
109
                self.core.emit_event("tool-list-changed")
110
            # selector
111 112
            self._gtk_handlers.append((self._modelview.get_selection(),
                    "changed", "tool-selection-changed"))
113
            # shape selector
114 115 116 117 118 119 120
            self._gtk_handlers.append((
                    self.gui.get_object("ToolShapeSelector"), "changed",
                    "tool-shape-changed"))
            self._event_handlers = (
                    ("tool-shape-list-changed", self._update_widgets),
                    ("tool-selection-changed", self._tool_switch),
                    ("tool-changed", self._store_tool_settings),
121 122
                    ("tool-changed", self._trigger_table_update),
                    ("tool-list-changed", self._trigger_table_update),
123
                    ("tool-shape-changed", self._store_tool_settings))
124
            self.register_model_update(update_model)
125 126
            self.register_gtk_handlers(self._gtk_handlers)
            self.register_event_handlers(self._event_handlers)
127
            self._update_widgets()
128
            self._trigger_table_update()
129
            self._tool_switch()
130 131
        self.core.register_namespace("tools",
                pycam.Plugins.get_filter(self))
132
        self.register_state_item("tools", self)
133 134 135
        return True

    def teardown(self):
136
        self.clear_state_items()
137
        self.core.unregister_namespace("tools")
138 139
        if self.gui:
            self.core.unregister_ui("main", self.gui.get_object("ToolBox"))
140 141 142 143 144
            self.core.unregister_ui_section("tool_speed")
            self.core.unregister_ui_section("tool_size")
            self.core.unregister_ui("tool_parameters", self.size_widget.widget)
            self.core.unregister_ui("tool_parameters", self.speed_widget.widget)
            self.core.unregister_ui_section("tool_parameters")
145 146
            self.unregister_gtk_handlers(self._gtk_handlers)
            self.unregister_event_handlers(self._event_handlers)
147 148
            self.core.unregister_chain("get_toolpath_information",
                    self.get_toolpath_information)
149
        self.core.set("tools", None)
150 151
        while len(self) > 0:
            self.pop()
152 153 154 155 156 157 158 159
        return True

    def get_selected(self, index=False):
        return self._get_selected(self._modelview, index=index)

    def select(self, tool):
        if tool in self:
            selection = self._modelview.get_selection()
160 161
            # check for identity instead of equality
            index = [id(t) for t in self].index(id(tool))
162 163 164
            selection.unselect_all()
            selection.select_path((index,))

165 166
    def get_toolpath_information(self, item, data):
        if item in self:
167 168 169 170 171 172 173 174 175 176 177 178 179 180
            data["tool_id"] = item["id"]

    def _trigger_table_update(self):
        self.gui.get_object("IDColumn").set_cell_data_func(
                self.gui.get_object("IDCell"), self._render_tool_info, "id")
        self.gui.get_object("NameColumn").set_cell_data_func(
                self.gui.get_object("NameCell"), self._render_tool_info, "name")
        self.gui.get_object("ShapeColumn").set_cell_data_func(
                self.gui.get_object("ShapeCell"), self._render_tool_shape)

    def _render_tool_info(self, column, cell, model, m_iter, key):
        path = model.get_path(m_iter)
        tool = self[path[0]]
        cell.set_property("text", str(tool[key]))
181

182
    def _render_tool_shape(self, column, cell, model, m_iter):
183 184
        path = model.get_path(m_iter)
        tool = self[path[0]]
185 186 187 188 189
        parameters = tool["parameters"]
        if "radius" in parameters:
            text = "%g%s" % (2 * parameters["radius"], self.core.get("unit"))
        else:
            text = ""
190 191 192 193
        cell.set_property("text", text)

    def _edit_tool_name(self, cell, path, new_text):
        path = int(path)
194 195 196 197
        tool_ref = self._treemodel[path][self.COLUMN_REF]
        tool = [t for t in self if id(t) == tool_ref][0]
        if (new_text != tool["name"]) and new_text:
            tool["name"] = new_text
198 199 200

    def _edit_tool_id(self, cell, path, new_text):
        path = int(path)
201 202
        tool_ref = self._treemodel[path][self.COLUMN_REF]
        tool = [t for t in self if id(t) == tool_ref][0]
203 204 205 206
        try:
            new_value = int(new_text)
        except ValueError:
            return
207 208
        if new_value != tool["id"]:
            tool["id"] = new_value
209

210 211 212 213 214 215 216 217 218 219 220 221 222 223
    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]
224
        else:
225 226 227 228 229 230 231
            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)
232 233
                break
        else:
234 235 236
            selector.set_active(-1)

    def _update_widgets(self):
237
        selected = self._get_shape()
238 239
        model = self.gui.get_object("ToolShapeList")
        model.clear()
240
        shapes = self.core.get("get_parameter_sets")("tool").values()
241 242 243 244 245 246 247 248 249 250 251 252 253 254
        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)
255 256 257 258 259
        selector_box = self.gui.get_object("ToolSelectorBox")
        if len(model) < 2:
            selector_box.hide()
        else:
            selector_box.show()
260 261
        if selected:
            self.select_shape(selected["name"])
262 263 264 265 266 267 268 269 270 271 272 273 274

    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()
275

276
    def _tool_switch(self, widget=None, data=None):
277 278 279 280 281
        tool = self.get_selected()
        control_box = self.gui.get_object("ToolSettingsControlsBox")
        if not tool:
            control_box.hide()
        else:
282
            self.core.block_event("tool-changed")
283 284 285 286 287
            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"])
288
            control_box.show()
289
            self.core.unblock_event("tool-shape-changed")
290
            self.core.unblock_event("tool-changed")
291 292
            # trigger a widget update
            self.core.emit_event("tool-shape-changed")
293 294 295 296 297 298 299 300

    def _get_new_tool_id_and_name(self):
        tools = self.core.get("tools")
        tool_ids = [tool["id"] for tool in tools]
        tool_id = 1
        while tool_id in tool_ids:
            tool_id += 1
        return (tool_id, "Tool #%d" % tool_id)
301 302
        
    def _tool_new(self, *args):
303 304 305
        shapes = self.core.get("get_parameter_sets")("tool").values()
        shapes.sort(key=lambda item: item["weight"])
        shape = shapes[0]
306
        tool_id, tool_name = self._get_new_tool_id_and_name()
307
        new_tool = ToolEntity({"shape": shape["name"],
308 309
                "parameters": shape["parameters"].copy(),
                "id": tool_id, "name": tool_name})
310
        self.append(new_tool)
311
        self.select(new_tool)
312

313 314 315 316 317 318

class ToolEntity(pycam.Plugins.ObjectWithAttributes):

    def __init__(self, parameters):
        super(ToolEntity, self).__init__("tool", parameters)