115 value = property(Setting._get_value, _set_value) |
110 value = property(Setting._get_value, _set_value) |
116 |
111 |
117 def update(self): |
112 def update(self): |
118 self.value = self.widget.GetValue() |
113 self.value = self.widget.GetValue() |
119 |
114 |
|
115 def set_default(self, e): |
|
116 if e.CmdDown() and e.ButtonDClick() and self.default != "": |
|
117 self.widget.SetValue(self.default) |
|
118 else: |
|
119 e.Skip() |
|
120 |
120 class StringSetting(wxSetting): |
121 class StringSetting(wxSetting): |
121 |
122 |
122 def get_specific_widget(self, parent): |
123 def get_specific_widget(self, parent): |
123 import wx |
124 import wx |
124 self.widget = wx.TextCtrl(parent, -1, str(self.value)) |
125 self.widget = wx.TextCtrl(parent, -1, str(self.value)) |
125 return self.widget |
126 return self.widget |
|
127 |
|
128 def wxColorToStr(color, withAlpha = True): |
|
129 # including Alpha seems to be non standard in CSS |
|
130 format = '#{0.red:02X}{0.green:02X}{0.blue:02X}' \ |
|
131 + ('{0.alpha:02X}' if withAlpha else '') |
|
132 return format.format(color) |
|
133 |
|
134 class ColorSetting(wxSetting): |
|
135 def __init__(self, name, default, label = None, help = None, group = None, isRGBA=True): |
|
136 super().__init__(name, default, label, help, group) |
|
137 self.isRGBA = isRGBA |
|
138 |
|
139 def validate(self, value): |
|
140 from .utils import check_rgb_color, check_rgba_color |
|
141 validate = check_rgba_color if self.isRGBA else check_rgb_color |
|
142 validate(value) |
|
143 |
|
144 def get_specific_widget(self, parent): |
|
145 import wx |
|
146 self.widget = wx.ColourPickerCtrl(parent, colour=wx.Colour(self.value), style=wx.CLRP_USE_TEXTCTRL) |
|
147 self.widget.SetValue = self.widget.SetColour |
|
148 self.widget.LayoutDirection = wx.Layout_RightToLeft |
|
149 return self.widget |
|
150 def update(self): |
|
151 self._value = wxColorToStr(self.widget.Colour, self.isRGBA) |
126 |
152 |
127 class ComboSetting(wxSetting): |
153 class ComboSetting(wxSetting): |
128 |
154 |
129 def __init__(self, name, default, choices, label = None, help = None, group = None): |
155 def __init__(self, name, default, choices, label = None, help = None, group = None): |
130 super(ComboSetting, self).__init__(name, default, label, help, group) |
156 super(ComboSetting, self).__init__(name, default, label, help, group) |
131 self.choices = choices |
157 self.choices = choices |
132 |
158 |
133 def get_specific_widget(self, parent): |
159 def get_specific_widget(self, parent): |
134 import wx |
160 import wx |
135 self.widget = wx.ComboBox(parent, -1, str(self.value), choices = self.choices, style = wx.CB_DROPDOWN) |
161 readonly = isinstance(self.choices, tuple) |
|
162 if readonly: |
|
163 # wx.Choice drops its list on click, no need to click down arrow |
|
164 # which is far to the right because of wx.EXPAND |
|
165 self.widget = wx.Choice(parent, -1, choices = self.choices) |
|
166 self.widget.GetValue = lambda: self.choices[self.widget.Selection] |
|
167 self.widget.SetValue = lambda v: self.widget.SetSelection(self.choices.index(v)) |
|
168 self.widget.SetValue(self.value) |
|
169 else: |
|
170 self.widget = wx.ComboBox(parent, -1, str(self.value), choices = self.choices, style = wx.CB_DROPDOWN) |
136 return self.widget |
171 return self.widget |
137 |
172 |
138 class SpinSetting(wxSetting): |
173 class SpinSetting(wxSetting): |
139 |
174 |
140 def __init__(self, name, default, min, max, label = None, help = None, group = None, increment = 0.1): |
175 def __init__(self, name, default, min, max, label = None, help = None, group = None, increment = 0.1): |
141 super(SpinSetting, self).__init__(name, default, label, help, group) |
176 super().__init__(name, default, label, help, group) |
142 self.min = min |
177 self.min = min |
143 self.max = max |
178 self.max = max |
144 self.increment = increment |
179 self.increment = increment |
145 |
180 |
146 def get_specific_widget(self, parent): |
181 def get_specific_widget(self, parent): |
147 from wx.lib.agw.floatspin import FloatSpin |
182 import wx |
148 self.widget = FloatSpin(parent, -1, min_val = self.min, max_val = self.max, digits = 0) |
183 self.widget = wx.SpinCtrlDouble(parent, -1, min = self.min, max = self.max) |
|
184 self.widget.SetDigits(0) |
149 self.widget.SetValue(self.value) |
185 self.widget.SetValue(self.value) |
150 orig = self.widget.GetValue |
186 orig = self.widget.GetValue |
151 self.widget.GetValue = lambda: int(orig()) |
187 self.widget.GetValue = lambda: int(orig()) |
152 return self.widget |
188 return self.widget |
153 |
189 |
|
190 def MySpin(parent, digits, *args, **kw): |
|
191 # in GTK 3.[01], spinner is not large enough to fit text |
|
192 # Could be a class, but use function to avoid load errors if wx |
|
193 # not installed |
|
194 # If native wx.SpinCtrlDouble has problems in different platforms |
|
195 # try agw |
|
196 # from wx.lib.agw.floatspin import FloatSpin |
|
197 import wx |
|
198 sp = wx.SpinCtrlDouble(parent, *args, **kw) |
|
199 # sp = FloatSpin(parent) |
|
200 sp.SetDigits(digits) |
|
201 # sp.SetValue(kw['initial']) |
|
202 def fitValue(ev): |
|
203 text = '%%.%df'% digits % sp.Max |
|
204 # native wx.SpinCtrlDouble does not return good size |
|
205 # in GTK 3.0 |
|
206 tex = sp.GetTextExtent(text) |
|
207 tsz = sp.GetSizeFromTextSize(tex.x) |
|
208 |
|
209 if sp.MinSize.x < tsz.x: |
|
210 # print('fitValue', getattr(sp, 'setting', None), sp.Value, sp.Digits, tsz.x) |
|
211 sp.MinSize = tsz |
|
212 # sp.Size = tsz |
|
213 # sp.Bind(wx.EVT_TEXT, fitValue) |
|
214 fitValue(None) |
|
215 return sp |
|
216 |
154 class FloatSpinSetting(SpinSetting): |
217 class FloatSpinSetting(SpinSetting): |
155 |
218 |
156 def get_specific_widget(self, parent): |
219 def get_specific_widget(self, parent): |
157 from wx.lib.agw.floatspin import FloatSpin |
220 self.widget = MySpin(parent, 2, initial = self.value, min = self.min, max = self.max, inc = self.increment) |
158 self.widget = FloatSpin(parent, -1, value = self.value, min_val = self.min, max_val = self.max, increment = self.increment, digits = 2) |
|
159 return self.widget |
221 return self.widget |
160 |
222 |
161 class BooleanSetting(wxSetting): |
223 class BooleanSetting(wxSetting): |
162 |
224 |
163 def _get_value(self): |
225 def _get_value(self): |
214 def get_widget(self, parent): |
276 def get_widget(self, parent): |
215 from wx.lib.agw.floatspin import FloatSpin |
277 from wx.lib.agw.floatspin import FloatSpin |
216 import wx |
278 import wx |
217 build_dimensions = parse_build_dimensions(self.value) |
279 build_dimensions = parse_build_dimensions(self.value) |
218 self.widgets = [] |
280 self.widgets = [] |
219 w = lambda val, m, M: self.widgets.append(FloatSpin(parent, -1, value = val, min_val = m, max_val = M, digits = 2)) |
281 def w(val, m, M): |
220 addlabel = lambda name, pos: self.widget.Add(wx.StaticText(parent, -1, name), pos = pos, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5) |
282 self.widgets.append(MySpin(parent, 2, initial = val, min = m, max = M)) |
221 addwidget = lambda *pos: self.widget.Add(self.widgets[-1], pos = pos, flag = wx.RIGHT, border = 5) |
283 def addlabel(name, pos): |
|
284 self.widget.Add(wx.StaticText(parent, -1, name), pos = pos, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5) |
|
285 def addwidget(*pos): |
|
286 self.widget.Add(self.widgets[-1], pos = pos, flag = wx.RIGHT | wx.EXPAND, border = 5) |
222 self.widget = wx.GridBagSizer() |
287 self.widget = wx.GridBagSizer() |
223 addlabel(_("Width"), (0, 0)) |
288 addlabel(_("Width"), (0, 0)) |
224 w(build_dimensions[0], 0, 2000) |
289 w(build_dimensions[0], 0, 2000) |
225 addwidget(0, 1) |
290 addwidget(0, 1) |
226 addlabel(_("Depth"), (0, 2)) |
291 addlabel(_("Depth"), (0, 2)) |
238 addlabel(_("Z offset"), (1, 4)) |
303 addlabel(_("Z offset"), (1, 4)) |
239 w(build_dimensions[5], -2000, 2000) |
304 w(build_dimensions[5], -2000, 2000) |
240 addwidget(1, 5) |
305 addwidget(1, 5) |
241 addlabel(_("X home pos."), (2, 0)) |
306 addlabel(_("X home pos."), (2, 0)) |
242 w(build_dimensions[6], -2000, 2000) |
307 w(build_dimensions[6], -2000, 2000) |
243 self.widget.Add(self.widgets[-1], pos = (2, 1)) |
308 addwidget(2, 1) |
244 addlabel(_("Y home pos."), (2, 2)) |
309 addlabel(_("Y home pos."), (2, 2)) |
245 w(build_dimensions[7], -2000, 2000) |
310 w(build_dimensions[7], -2000, 2000) |
246 self.widget.Add(self.widgets[-1], pos = (2, 3)) |
311 addwidget(2, 3) |
247 addlabel(_("Z home pos."), (2, 4)) |
312 addlabel(_("Z home pos."), (2, 4)) |
248 w(build_dimensions[8], -2000, 2000) |
313 w(build_dimensions[8], -2000, 2000) |
249 self.widget.Add(self.widgets[-1], pos = (2, 5)) |
314 addwidget(2, 5) |
250 return self.widget |
315 return self.widget |
251 |
316 |
252 def update(self): |
317 def update(self): |
253 values = [float(w.GetValue()) for w in self.widgets] |
318 values = [float(w.GetValue()) for w in self.widgets] |
254 self.value = "%.02fx%.02fx%.02f%+.02f%+.02f%+.02f%+.02f%+.02f%+.02f" % tuple(values) |
319 self.value = "%.02fx%.02fx%.02f%+.02f%+.02f%+.02f%+.02f%+.02f%+.02f" % tuple(values) |
255 |
320 |
256 class Settings(object): |
321 class Settings: |
257 def __baudrate_list(self): return ["2400", "9600", "19200", "38400", "57600", "115200", "250000"] |
322 def __baudrate_list(self): return ["2400", "9600", "19200", "38400", "57600", "115200", "250000"] |
258 |
323 |
259 def __init__(self, root): |
324 def __init__(self, root): |
260 # defaults here. |
325 # defaults here. |
261 # the initial value determines the type |
326 # the initial value determines the type |
262 self._add(StringSetting("port", "", _("Serial port"), _("Port used to communicate with printer"))) |
327 self._add(StringSetting("port", "", _("Serial port"), _("Port used to communicate with printer"))) |
263 self._add(ComboSetting("baudrate", 115200, self.__baudrate_list(), _("Baud rate"), _("Communications Speed"))) |
328 self._add(ComboSetting("baudrate", 115200, self.__baudrate_list(), _("Baud rate"), _("Communications Speed"))) |
264 self._add(BooleanSetting("tcp_streaming_mode", False, _("TCP streaming mode"), _("When using a TCP connection to the printer, the streaming mode will not wait for acks from the printer to send new commands. This will break things such as ETA prediction, but can result in smoother prints.")), root.update_tcp_streaming_mode) |
329 self._add(BooleanSetting("tcp_streaming_mode", False, _("TCP streaming mode"), _("When using a TCP connection to the printer, the streaming mode will not wait for acks from the printer to send new commands. This will break things such as ETA prediction, but can result in smoother prints.")), root.update_tcp_streaming_mode) |
265 self._add(BooleanSetting("rpc_server", True, _("RPC server"), _("Enable RPC server to allow remotely querying print status")), root.update_rpc_server) |
330 self._add(BooleanSetting("rpc_server", True, _("RPC server"), _("Enable RPC server to allow remotely querying print status")), root.update_rpc_server) |
266 self._add(BooleanSetting("dtr", True, _("DTR"), _("Disabling DTR would prevent Arduino (RAMPS) from resetting upon connection"), "Printer")) |
331 self._add(BooleanSetting("dtr", True, _("DTR"), _("Disabling DTR would prevent Arduino (RAMPS) from resetting upon connection"), "Printer")) |
267 self._add(SpinSetting("bedtemp_abs", 110, 0, 400, _("Bed temperature for ABS"), _("Heated Build Platform temp for ABS (deg C)"), "Printer")) |
332 if sys.platform != "win32": |
268 self._add(SpinSetting("bedtemp_pla", 60, 0, 400, _("Bed temperature for PLA"), _("Heated Build Platform temp for PLA (deg C)"), "Printer")) |
333 self._add(StringSetting("devicepath", "", _("Device name pattern"), _("Custom device pattern: for example /dev/3DP_* "), "Printer")) |
269 self._add(SpinSetting("temperature_abs", 230, 0, 400, _("Extruder temperature for ABS"), _("Extruder temp for ABS (deg C)"), "Printer")) |
334 self._add(SpinSetting("bedtemp_abs", 110, 0, 400, _("Bed temperature for ABS"), _("Heated Build Platform temp for ABS (deg C)"), "Printer"), root.set_temp_preset) |
270 self._add(SpinSetting("temperature_pla", 185, 0, 400, _("Extruder temperature for PLA"), _("Extruder temp for PLA (deg C)"), "Printer")) |
335 self._add(SpinSetting("bedtemp_pla", 60, 0, 400, _("Bed temperature for PLA"), _("Heated Build Platform temp for PLA (deg C)"), "Printer"), root.set_temp_preset) |
|
336 self._add(SpinSetting("temperature_abs", 230, 0, 400, _("Extruder temperature for ABS"), _("Extruder temp for ABS (deg C)"), "Printer"), root.set_temp_preset) |
|
337 self._add(SpinSetting("temperature_pla", 185, 0, 400, _("Extruder temperature for PLA"), _("Extruder temp for PLA (deg C)"), "Printer"), root.set_temp_preset) |
271 self._add(SpinSetting("xy_feedrate", 3000, 0, 50000, _("X && Y manual feedrate"), _("Feedrate for Control Panel Moves in X and Y (mm/min)"), "Printer")) |
338 self._add(SpinSetting("xy_feedrate", 3000, 0, 50000, _("X && Y manual feedrate"), _("Feedrate for Control Panel Moves in X and Y (mm/min)"), "Printer")) |
272 self._add(SpinSetting("z_feedrate", 100, 0, 50000, _("Z manual feedrate"), _("Feedrate for Control Panel Moves in Z (mm/min)"), "Printer")) |
339 self._add(SpinSetting("z_feedrate", 100, 0, 50000, _("Z manual feedrate"), _("Feedrate for Control Panel Moves in Z (mm/min)"), "Printer")) |
273 self._add(SpinSetting("e_feedrate", 100, 0, 1000, _("E manual feedrate"), _("Feedrate for Control Panel Moves in Extrusions (mm/min)"), "Printer")) |
340 self._add(SpinSetting("e_feedrate", 100, 0, 1000, _("E manual feedrate"), _("Feedrate for Control Panel Moves in Extrusions (mm/min)"), "Printer")) |
274 self._add(StringSetting("slicecommand", "python skeinforge/skeinforge_application/skeinforge_utilities/skeinforge_craft.py $s", _("Slice command"), _("Slice command"), "External")) |
341 defaultslicerpath = "" |
275 self._add(StringSetting("sliceoptscommand", "python skeinforge/skeinforge_application/skeinforge.py", _("Slicer options command"), _("Slice settings command"), "External")) |
342 if getattr(sys, 'frozen', False): |
|
343 if sys.platform == "darwin": |
|
344 defaultslicerpath = "/Applications/Slic3r.app/Contents/MacOS/" |
|
345 elif sys.platform == "win32": |
|
346 defaultslicerpath = ".\\slic3r\\" |
|
347 self._add(StringSetting("slicecommandpath", defaultslicerpath, _("Path to slicer"), _("Path to slicer"), "External")) |
|
348 slicer = 'slic3r-console' if sys.platform == 'win32' else 'slic3r' |
|
349 self._add(StringSetting("slicecommand", slicer + ' $s --output $o', _("Slice command"), _("Slice command"), "External")) |
|
350 self._add(StringSetting("sliceoptscommand", "slic3r", _("Slicer options command"), _("Slice settings command"), "External")) |
276 self._add(StringSetting("start_command", "", _("Start command"), _("Executable to run when the print is started"), "External")) |
351 self._add(StringSetting("start_command", "", _("Start command"), _("Executable to run when the print is started"), "External")) |
277 self._add(StringSetting("final_command", "", _("Final command"), _("Executable to run when the print is finished"), "External")) |
352 self._add(StringSetting("final_command", "", _("Final command"), _("Executable to run when the print is finished"), "External")) |
278 self._add(StringSetting("error_command", "", _("Error command"), _("Executable to run when an error occurs"), "External")) |
353 self._add(StringSetting("error_command", "", _("Error command"), _("Executable to run when an error occurs"), "External")) |
279 self._add(StringSetting("log_path", "", _("Log path"), _("Path to the log file. An empty path will log to the console."), "UI")) |
354 self._add(StringSetting("log_path", "", _("Log path"), _("Path to the log file. An empty path will log to the console."), "UI")) |
280 |
355 |