Tue, 26 Sep 2017 19:08:02 +0200
SVG options: offset, original scale
SVG Bugfix: "scale" does now really fit to dimensions
15 | 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 logging | |
17 | ||
18 | try: | |
19 | import wx | |
20 | except: | |
21 | logging.error(_("WX is not installed. This program requires WX to run.")) | |
22 | raise | |
23 | ||
24 | from printrun.utils import install_locale | |
25 | install_locale('pronterface') | |
26 | ||
27 | from .controls import ControlsSizer, add_extra_controls | |
28 | from .viz import VizPane | |
29 | from .log import LogPane | |
30 | from .toolbar import MainToolbar | |
31 | ||
32 | class ToggleablePane(wx.BoxSizer): | |
33 | ||
34 | def __init__(self, root, label, parentpanel, parentsizers): | |
35 | super(ToggleablePane, self).__init__(wx.HORIZONTAL) | |
36 | if not parentpanel: parentpanel = root.panel | |
37 | self.root = root | |
38 | self.visible = True | |
39 | self.parentpanel = parentpanel | |
40 | self.parentsizers = parentsizers | |
41 | self.panepanel = root.newPanel(parentpanel) | |
42 | self.button = wx.Button(parentpanel, -1, label, size = (22, 18), style = wx.BU_EXACTFIT) | |
43 | self.button.Bind(wx.EVT_BUTTON, self.toggle) | |
44 | ||
45 | def toggle(self, event): | |
46 | if self.visible: | |
47 | self.Hide(self.panepanel) | |
48 | self.on_hide() | |
49 | else: | |
50 | self.Show(self.panepanel) | |
51 | self.on_show() | |
52 | self.visible = not self.visible | |
53 | self.button.SetLabel(">" if self.button.GetLabel() == "<" else "<") | |
54 | ||
55 | class LeftPaneToggleable(ToggleablePane): | |
56 | def __init__(self, root, parentpanel, parentsizers): | |
57 | super(LeftPaneToggleable, self).__init__(root, "<", parentpanel, parentsizers) | |
58 | self.Add(self.panepanel, 0, wx.EXPAND) | |
59 | self.Add(self.button, 0) | |
60 | ||
61 | def set_sizer(self, sizer): | |
62 | self.panepanel.SetSizer(sizer) | |
63 | ||
64 | def on_show(self): | |
65 | for sizer in self.parentsizers: | |
66 | sizer.Layout() | |
67 | ||
68 | def on_hide(self): | |
69 | for sizer in self.parentsizers: | |
70 | # Expand right splitterwindow | |
71 | if isinstance(sizer, wx.SplitterWindow): | |
72 | if sizer.shrinked: | |
73 | button_width = self.button.GetSize()[0] | |
74 | sizer.SetSashPosition(sizer.GetSize()[0] - button_width) | |
75 | else: | |
76 | sizer.Layout() | |
77 | ||
78 | class LogPaneToggleable(ToggleablePane): | |
79 | def __init__(self, root, parentpanel, parentsizers): | |
80 | super(LogPaneToggleable, self).__init__(root, ">", parentpanel, parentsizers) | |
81 | self.Add(self.button, 0) | |
82 | pane = LogPane(root, self.panepanel) | |
83 | self.panepanel.SetSizer(pane) | |
84 | self.Add(self.panepanel, 1, wx.EXPAND) | |
85 | self.splitter = self.parentpanel.GetParent() | |
86 | ||
87 | def on_show(self): | |
88 | self.splitter.shrinked = False | |
89 | self.splitter.SetSashPosition(self.splitter.GetSize()[0] - self.orig_width) | |
90 | self.splitter.SetMinimumPaneSize(self.orig_min_size) | |
91 | self.splitter.SetSashGravity(self.orig_gravity) | |
92 | if hasattr(self.splitter, "SetSashSize"): self.splitter.SetSashSize(self.orig_sash_size) | |
93 | if hasattr(self.splitter, "SetSashInvisible"): self.splitter.SetSashInvisible(False) | |
94 | for sizer in self.parentsizers: | |
95 | sizer.Layout() | |
96 | ||
97 | def on_hide(self): | |
98 | self.splitter.shrinked = True | |
99 | self.orig_width = self.splitter.GetSize()[0] - self.splitter.GetSashPosition() | |
100 | button_width = self.button.GetSize()[0] | |
101 | self.orig_min_size = self.splitter.GetMinimumPaneSize() | |
102 | self.orig_gravity = self.splitter.GetSashGravity() | |
103 | self.splitter.SetMinimumPaneSize(button_width) | |
104 | self.splitter.SetSashGravity(1) | |
105 | self.splitter.SetSashPosition(self.splitter.GetSize()[0] - button_width) | |
106 | if hasattr(self.splitter, "SetSashSize"): | |
107 | self.orig_sash_size = self.splitter.GetSashSize() | |
108 | self.splitter.SetSashSize(0) | |
109 | if hasattr(self.splitter, "SetSashInvisible"): self.splitter.SetSashInvisible(True) | |
110 | for sizer in self.parentsizers: | |
111 | sizer.Layout() | |
112 | ||
113 | class MainWindow(wx.Frame): | |
114 | ||
115 | def __init__(self, *args, **kwargs): | |
116 | super(MainWindow, self).__init__(*args, **kwargs) | |
117 | # this list will contain all controls that should be only enabled | |
118 | # when we're connected to a printer | |
119 | self.panel = wx.Panel(self, -1) | |
120 | self.reset_ui() | |
121 | self.statefulControls = [] | |
122 | ||
123 | def reset_ui(self): | |
124 | self.panels = [] | |
125 | self.printerControls = [] | |
126 | ||
127 | def newPanel(self, parent, add_to_list = True): | |
128 | panel = wx.Panel(parent) | |
129 | self.registerPanel(panel, add_to_list) | |
130 | return panel | |
131 | ||
132 | def registerPanel(self, panel, add_to_list = True): | |
133 | panel.SetBackgroundColour(self.bgcolor) | |
134 | if add_to_list: self.panels.append(panel) | |
135 | ||
136 | def createTabbedGui(self): | |
137 | self.notesizer = wx.BoxSizer(wx.VERTICAL) | |
138 | self.notebook = wx.Notebook(self.panel) | |
139 | self.notebook.SetBackgroundColour(self.bgcolor) | |
140 | page1panel = self.newPanel(self.notebook) | |
141 | page2panel = self.newPanel(self.notebook) | |
142 | self.mainsizer_page1 = wx.BoxSizer(wx.VERTICAL) | |
143 | page1panel1 = self.newPanel(page1panel) | |
144 | page1panel2 = self.newPanel(page1panel) | |
145 | self.toolbarsizer = MainToolbar(self, page1panel1, use_wrapsizer = True) | |
146 | page1panel1.SetSizer(self.toolbarsizer) | |
147 | self.mainsizer_page1.Add(page1panel1, 0, wx.EXPAND) | |
148 | self.lowersizer = wx.BoxSizer(wx.HORIZONTAL) | |
149 | page1panel2.SetSizer(self.lowersizer) | |
150 | leftsizer = wx.BoxSizer(wx.VERTICAL) | |
151 | controls_sizer = ControlsSizer(self, page1panel2, True) | |
152 | leftsizer.Add(controls_sizer, 1, wx.ALIGN_CENTER) | |
153 | rightsizer = wx.BoxSizer(wx.VERTICAL) | |
154 | extracontrols = wx.GridBagSizer() | |
155 | add_extra_controls(extracontrols, self, page1panel2, controls_sizer.extra_buttons) | |
156 | rightsizer.AddStretchSpacer() | |
157 | rightsizer.Add(extracontrols, 0, wx.ALIGN_CENTER) | |
158 | self.lowersizer.Add(leftsizer, 0, wx.ALIGN_CENTER | wx.RIGHT, border = 10) | |
159 | self.lowersizer.Add(rightsizer, 1, wx.ALIGN_CENTER) | |
160 | self.mainsizer_page1.Add(page1panel2, 1) | |
161 | self.mainsizer = wx.BoxSizer(wx.HORIZONTAL) | |
162 | self.splitterwindow = wx.SplitterWindow(page2panel, style = wx.SP_3D) | |
163 | page2sizer1 = wx.BoxSizer(wx.HORIZONTAL) | |
164 | page2panel1 = self.newPanel(self.splitterwindow) | |
165 | page2sizer2 = wx.BoxSizer(wx.HORIZONTAL) | |
166 | page2panel2 = self.newPanel(self.splitterwindow) | |
167 | vizpane = VizPane(self, page2panel1) | |
168 | page2sizer1.Add(vizpane, 1, wx.EXPAND) | |
169 | page2sizer2.Add(LogPane(self, page2panel2), 1, wx.EXPAND) | |
170 | page2panel1.SetSizer(page2sizer1) | |
171 | page2panel2.SetSizer(page2sizer2) | |
172 | self.splitterwindow.SetMinimumPaneSize(1) | |
173 | self.splitterwindow.SetSashGravity(0.5) | |
174 | self.splitterwindow.SplitVertically(page2panel1, page2panel2, | |
175 | self.settings.last_sash_position) | |
176 | self.mainsizer.Add(self.splitterwindow, 1, wx.EXPAND) | |
177 | page1panel.SetSizer(self.mainsizer_page1) | |
178 | page2panel.SetSizer(self.mainsizer) | |
179 | self.notesizer.Add(self.notebook, 1, wx.EXPAND) | |
180 | self.notebook.AddPage(page1panel, _("Commands")) | |
181 | self.notebook.AddPage(page2panel, _("Status")) | |
182 | if self.settings.uimode == _("Tabbed with platers"): | |
183 | from printrun.stlplater import StlPlaterPanel | |
184 | from printrun.gcodeplater import GcodePlaterPanel | |
185 | page3panel = StlPlaterPanel(parent = self.notebook, | |
186 | callback = self.platecb, | |
187 | build_dimensions = self.build_dimensions_list, | |
188 | circular_platform = self.settings.circular_bed, | |
189 | simarrange_path = self.settings.simarrange_path, | |
190 | antialias_samples = int(self.settings.antialias3dsamples)) | |
191 | page4panel = GcodePlaterPanel(parent = self.notebook, | |
192 | callback = self.platecb, | |
193 | build_dimensions = self.build_dimensions_list, | |
194 | circular_platform = self.settings.circular_bed, | |
195 | antialias_samples = int(self.settings.antialias3dsamples)) | |
196 | self.registerPanel(page3panel) | |
197 | self.registerPanel(page4panel) | |
198 | self.notebook.AddPage(page3panel, _("Plater")) | |
199 | self.notebook.AddPage(page4panel, _("G-Code Plater")) | |
200 | self.panel.SetSizer(self.notesizer) | |
201 | self.panel.Bind(wx.EVT_MOUSE_EVENTS, self.editbutton) | |
202 | self.Bind(wx.EVT_CLOSE, self.kill) | |
203 | ||
204 | # Custom buttons | |
205 | if wx.VERSION > (2, 9): self.cbuttonssizer = wx.WrapSizer(wx.HORIZONTAL) | |
206 | else: self.cbuttonssizer = wx.GridBagSizer() | |
207 | self.cbuttonssizer = wx.GridBagSizer() | |
208 | self.centerpanel = self.newPanel(page1panel2) | |
209 | self.centerpanel.SetSizer(self.cbuttonssizer) | |
210 | rightsizer.Add(self.centerpanel, 0, wx.ALIGN_CENTER) | |
211 | rightsizer.AddStretchSpacer() | |
212 | ||
213 | self.panel.SetSizerAndFit(self.notesizer) | |
214 | ||
215 | self.cbuttons_reload() | |
216 | minsize = self.lowersizer.GetMinSize() # lower pane | |
217 | minsize[1] = self.notebook.GetSize()[1] | |
218 | self.SetMinSize(self.ClientToWindowSize(minsize)) # client to window | |
219 | self.Fit() | |
220 | ||
221 | def createGui(self, compact = False, mini = False): | |
222 | self.mainsizer = wx.BoxSizer(wx.VERTICAL) | |
223 | self.lowersizer = wx.BoxSizer(wx.HORIZONTAL) | |
224 | upperpanel = self.newPanel(self.panel, False) | |
225 | self.toolbarsizer = MainToolbar(self, upperpanel) | |
226 | lowerpanel = self.newPanel(self.panel) | |
227 | upperpanel.SetSizer(self.toolbarsizer) | |
228 | lowerpanel.SetSizer(self.lowersizer) | |
229 | leftpanel = self.newPanel(lowerpanel) | |
230 | left_pane = LeftPaneToggleable(self, leftpanel, [self.lowersizer]) | |
231 | leftpanel.SetSizer(left_pane) | |
232 | left_real_panel = left_pane.panepanel | |
233 | controls_panel = self.newPanel(left_real_panel) | |
234 | controls_sizer = ControlsSizer(self, controls_panel, mini_mode = mini) | |
235 | controls_panel.SetSizer(controls_sizer) | |
236 | left_sizer = wx.BoxSizer(wx.VERTICAL) | |
237 | left_sizer.Add(controls_panel, 1, wx.EXPAND) | |
238 | left_pane.set_sizer(left_sizer) | |
239 | self.lowersizer.Add(leftpanel, 0, wx.EXPAND) | |
240 | if not compact: # Use a splitterwindow to group viz and log | |
241 | rightpanel = self.newPanel(lowerpanel) | |
242 | rightsizer = wx.BoxSizer(wx.VERTICAL) | |
243 | rightpanel.SetSizer(rightsizer) | |
244 | self.splitterwindow = wx.SplitterWindow(rightpanel, style = wx.SP_3D) | |
245 | self.splitterwindow.SetMinimumPaneSize(150) | |
246 | self.splitterwindow.SetSashGravity(0.8) | |
247 | rightsizer.Add(self.splitterwindow, 1, wx.EXPAND) | |
248 | vizpanel = self.newPanel(self.splitterwindow) | |
249 | logpanel = self.newPanel(self.splitterwindow) | |
250 | self.splitterwindow.SplitVertically(vizpanel, logpanel, | |
251 | self.settings.last_sash_position) | |
252 | self.splitterwindow.shrinked = False | |
253 | else: | |
254 | vizpanel = self.newPanel(lowerpanel) | |
255 | logpanel = self.newPanel(left_real_panel) | |
256 | viz_pane = VizPane(self, vizpanel) | |
257 | # Custom buttons | |
258 | if wx.VERSION > (2, 9): self.cbuttonssizer = wx.WrapSizer(wx.HORIZONTAL) | |
259 | else: self.cbuttonssizer = wx.GridBagSizer() | |
260 | self.centerpanel = self.newPanel(vizpanel) | |
261 | self.centerpanel.SetSizer(self.cbuttonssizer) | |
262 | viz_pane.Add(self.centerpanel, 0, flag = wx.ALIGN_CENTER) | |
263 | vizpanel.SetSizer(viz_pane) | |
264 | if compact: | |
265 | log_pane = LogPane(self, logpanel) | |
266 | else: | |
267 | log_pane = LogPaneToggleable(self, logpanel, [self.lowersizer]) | |
268 | left_pane.parentsizers.append(self.splitterwindow) | |
269 | logpanel.SetSizer(log_pane) | |
270 | if not compact: | |
271 | self.lowersizer.Add(rightpanel, 1, wx.EXPAND) | |
272 | else: | |
273 | left_sizer.Add(logpanel, 1, wx.EXPAND) | |
274 | self.lowersizer.Add(vizpanel, 1, wx.EXPAND) | |
275 | self.mainsizer.Add(upperpanel, 0, wx.EXPAND) | |
276 | self.mainsizer.Add(lowerpanel, 1, wx.EXPAND) | |
277 | self.panel.SetSizer(self.mainsizer) | |
278 | self.panel.Bind(wx.EVT_MOUSE_EVENTS, self.editbutton) | |
279 | self.Bind(wx.EVT_CLOSE, self.kill) | |
280 | ||
281 | self.mainsizer.Layout() | |
282 | # This prevents resizing below a reasonnable value | |
283 | # We sum the lowersizer (left pane / viz / log) min size | |
284 | # the toolbar height and the statusbar/menubar sizes | |
285 | minsize = [0, 0] | |
286 | minsize[0] = self.lowersizer.GetMinSize()[0] # lower pane | |
287 | minsize[1] = max(viz_pane.GetMinSize()[1], controls_sizer.GetMinSize()[1]) | |
288 | minsize[1] += self.toolbarsizer.GetMinSize()[1] # toolbar height | |
289 | displaysize = wx.DisplaySize() | |
290 | minsize[0] = min(minsize[0], displaysize[0]) | |
291 | minsize[1] = min(minsize[1], displaysize[1]) | |
292 | self.SetMinSize(self.ClientToWindowSize(minsize)) # client to window | |
293 | ||
294 | self.cbuttons_reload() | |
295 | ||
296 | def gui_set_connected(self): | |
297 | self.xyb.enable() | |
298 | self.zb.enable() | |
299 | for control in self.printerControls: | |
300 | control.Enable() | |
301 | ||
302 | def gui_set_disconnected(self): | |
303 | self.printbtn.Disable() | |
304 | self.pausebtn.Disable() | |
305 | self.recoverbtn.Disable() | |
306 | for control in self.printerControls: | |
307 | control.Disable() | |
308 | self.xyb.disable() | |
309 | self.zb.disable() |