|
1 # This file is part of the Printrun suite. |
|
2 # |
|
3 # Printrun is free software: you can redistribute it and/or modify |
|
4 # it under the terms of the GNU General Public License as published by |
|
5 # the Free Software Foundation, either version 3 of the License, or |
|
6 # (at your option) any later version. |
|
7 # |
|
8 # Printrun is distributed in the hope that it will be useful, |
|
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 # GNU General Public License for more details. |
|
12 # |
|
13 # You should have received a copy of the GNU General Public License |
|
14 # along with Printrun. If not, see <http://www.gnu.org/licenses/>. |
|
15 |
|
16 import wx |
|
17 from printrun import gviz |
|
18 |
|
19 from .utils import imagefile, install_locale |
|
20 install_locale('pronterface') |
|
21 |
|
22 class ExcluderWindow(gviz.GvizWindow): |
|
23 |
|
24 def __init__(self, excluder, *args, **kwargs): |
|
25 super(ExcluderWindow, self).__init__(*args, **kwargs) |
|
26 self.SetTitle(_("Part excluder: draw rectangles where print instructions should be ignored")) |
|
27 self.toolbar.AddLabelTool(128, " " + _("Reset selection"), |
|
28 wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), |
|
29 shortHelp = _("Reset selection"), |
|
30 longHelp = "") |
|
31 self.Bind(wx.EVT_TOOL, self.reset_selection, id = 128) |
|
32 self.parent = excluder |
|
33 self.p.paint_overlay = self.paint_selection |
|
34 self.p.layerup() |
|
35 |
|
36 def real_to_gcode(self, x, y): |
|
37 return (x + self.p.build_dimensions[3], |
|
38 self.p.build_dimensions[4] + self.p.build_dimensions[1] - y) |
|
39 |
|
40 def gcode_to_real(self, x, y): |
|
41 return (x - self.p.build_dimensions[3], |
|
42 self.p.build_dimensions[1] - (y - self.p.build_dimensions[4])) |
|
43 |
|
44 def mouse(self, event): |
|
45 if event.ButtonUp(wx.MOUSE_BTN_LEFT) \ |
|
46 or event.ButtonUp(wx.MOUSE_BTN_RIGHT): |
|
47 self.initpos = None |
|
48 elif event.Dragging() and event.RightIsDown(): |
|
49 e = event.GetPositionTuple() |
|
50 if not self.initpos or not hasattr(self, "basetrans"): |
|
51 self.initpos = e |
|
52 self.basetrans = self.p.translate |
|
53 self.p.translate = [self.basetrans[0] + (e[0] - self.initpos[0]), |
|
54 self.basetrans[1] + (e[1] - self.initpos[1])] |
|
55 self.p.dirty = 1 |
|
56 wx.CallAfter(self.p.Refresh) |
|
57 elif event.Dragging() and event.LeftIsDown(): |
|
58 x, y = event.GetPositionTuple() |
|
59 if not self.initpos: |
|
60 self.basetrans = self.p.translate |
|
61 x = (x - self.basetrans[0]) / self.p.scale[0] |
|
62 y = (y - self.basetrans[1]) / self.p.scale[1] |
|
63 x, y = self.real_to_gcode(x, y) |
|
64 if not self.initpos: |
|
65 self.initpos = (x, y) |
|
66 self.parent.rectangles.append((0, 0, 0, 0)) |
|
67 else: |
|
68 pos = (x, y) |
|
69 x0 = min(self.initpos[0], pos[0]) |
|
70 y0 = min(self.initpos[1], pos[1]) |
|
71 x1 = max(self.initpos[0], pos[0]) |
|
72 y1 = max(self.initpos[1], pos[1]) |
|
73 self.parent.rectangles[-1] = (x0, y0, x1, y1) |
|
74 wx.CallAfter(self.p.Refresh) |
|
75 else: |
|
76 event.Skip() |
|
77 |
|
78 def _line_scaler(self, orig): |
|
79 x0, y0 = self.gcode_to_real(orig[0], orig[1]) |
|
80 x0 = self.p.scale[0] * x0 + self.p.translate[0] |
|
81 y0 = self.p.scale[1] * y0 + self.p.translate[1] |
|
82 x1, y1 = self.gcode_to_real(orig[2], orig[3]) |
|
83 x1 = self.p.scale[0] * x1 + self.p.translate[0] |
|
84 y1 = self.p.scale[1] * y1 + self.p.translate[1] |
|
85 width = max(x0, x1) - min(x0, x1) + 1 |
|
86 height = max(y0, y1) - min(y0, y1) + 1 |
|
87 return (min(x0, x1), min(y0, y1), width, height,) |
|
88 |
|
89 def paint_selection(self, dc): |
|
90 dc = wx.GCDC(dc) |
|
91 dc.SetPen(wx.TRANSPARENT_PEN) |
|
92 dc.DrawRectangleList([self._line_scaler(rect) |
|
93 for rect in self.parent.rectangles], |
|
94 None, wx.Brush((200, 200, 200, 150))) |
|
95 |
|
96 def reset_selection(self, event): |
|
97 self.parent.rectangles = [] |
|
98 wx.CallAfter(self.p.Refresh) |
|
99 |
|
100 class Excluder(object): |
|
101 |
|
102 def __init__(self): |
|
103 self.rectangles = [] |
|
104 self.window = None |
|
105 |
|
106 def pop_window(self, gcode, *args, **kwargs): |
|
107 if not self.window: |
|
108 self.window = ExcluderWindow(self, *args, **kwargs) |
|
109 self.window.p.addfile(gcode, True) |
|
110 self.window.Bind(wx.EVT_CLOSE, self.close_window) |
|
111 self.window.Show() |
|
112 else: |
|
113 self.window.Show() |
|
114 self.window.Raise() |
|
115 |
|
116 def close_window(self, event = None): |
|
117 if self.window: |
|
118 self.window.Destroy() |
|
119 self.window = None |
|
120 |
|
121 if __name__ == '__main__': |
|
122 import sys |
|
123 import gcoder |
|
124 gcode = gcoder.GCode(open(sys.argv[1])) |
|
125 app = wx.App(False) |
|
126 ex = Excluder() |
|
127 ex.pop_window(gcode) |
|
128 app.MainLoop() |