meerk40t 0.9.7020__py2.py3-none-any.whl → 0.9.7040__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meerk40t/balormk/clone_loader.py +3 -2
- meerk40t/balormk/controller.py +28 -11
- meerk40t/balormk/cylindermod.py +1 -0
- meerk40t/balormk/device.py +13 -9
- meerk40t/balormk/driver.py +9 -2
- meerk40t/balormk/galvo_commands.py +3 -1
- meerk40t/balormk/gui/gui.py +6 -0
- meerk40t/balormk/livelightjob.py +338 -321
- meerk40t/balormk/mock_connection.py +4 -3
- meerk40t/balormk/usb_connection.py +11 -2
- meerk40t/camera/camera.py +19 -14
- meerk40t/camera/gui/camerapanel.py +6 -0
- meerk40t/core/cutcode/cutcode.py +1 -1
- meerk40t/core/cutplan.py +169 -43
- meerk40t/core/elements/element_treeops.py +444 -147
- meerk40t/core/elements/elements.py +100 -9
- meerk40t/core/elements/grid.py +8 -1
- meerk40t/core/elements/offset_mk.py +2 -1
- meerk40t/core/elements/shapes.py +618 -279
- meerk40t/core/elements/tree_commands.py +10 -5
- meerk40t/core/node/elem_ellipse.py +18 -8
- meerk40t/core/node/elem_image.py +51 -19
- meerk40t/core/node/elem_line.py +18 -8
- meerk40t/core/node/elem_path.py +18 -8
- meerk40t/core/node/elem_point.py +10 -4
- meerk40t/core/node/elem_polyline.py +19 -11
- meerk40t/core/node/elem_rect.py +18 -8
- meerk40t/core/node/elem_text.py +11 -5
- meerk40t/core/node/filenode.py +2 -8
- meerk40t/core/node/groupnode.py +11 -11
- meerk40t/core/node/image_processed.py +11 -5
- meerk40t/core/node/image_raster.py +11 -5
- meerk40t/core/node/node.py +70 -19
- meerk40t/core/node/refnode.py +2 -1
- meerk40t/core/planner.py +23 -0
- meerk40t/core/svg_io.py +91 -34
- meerk40t/core/undos.py +1 -1
- meerk40t/core/wordlist.py +1 -0
- meerk40t/device/dummydevice.py +7 -1
- meerk40t/dxf/dxf_io.py +6 -0
- meerk40t/extra/mk_potrace.py +1959 -0
- meerk40t/extra/param_functions.py +1 -1
- meerk40t/extra/potrace.py +14 -10
- meerk40t/extra/vtracer.py +222 -0
- meerk40t/grbl/device.py +81 -8
- meerk40t/grbl/interpreter.py +1 -1
- meerk40t/gui/about.py +21 -3
- meerk40t/gui/basicops.py +3 -3
- meerk40t/gui/choicepropertypanel.py +1 -4
- meerk40t/gui/devicepanel.py +20 -16
- meerk40t/gui/gui_mixins.py +8 -1
- meerk40t/gui/icons.py +330 -253
- meerk40t/gui/laserpanel.py +8 -3
- meerk40t/gui/laserrender.py +41 -21
- meerk40t/gui/magnetoptions.py +158 -65
- meerk40t/gui/materialtest.py +229 -39
- meerk40t/gui/navigationpanels.py +229 -24
- meerk40t/gui/propertypanels/hatchproperty.py +2 -0
- meerk40t/gui/propertypanels/imageproperty.py +160 -106
- meerk40t/gui/ribbon.py +6 -1
- meerk40t/gui/scenewidgets/gridwidget.py +29 -32
- meerk40t/gui/scenewidgets/rectselectwidget.py +190 -192
- meerk40t/gui/simulation.py +75 -77
- meerk40t/gui/spoolerpanel.py +6 -9
- meerk40t/gui/statusbarwidgets/defaultoperations.py +84 -48
- meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
- meerk40t/gui/themes.py +7 -1
- meerk40t/gui/tips.py +15 -1
- meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
- meerk40t/gui/wxmeerk40t.py +26 -0
- meerk40t/gui/wxmmain.py +242 -114
- meerk40t/gui/wxmscene.py +180 -4
- meerk40t/gui/wxmtree.py +4 -2
- meerk40t/gui/wxutils.py +60 -15
- meerk40t/image/imagetools.py +130 -66
- meerk40t/internal_plugins.py +4 -0
- meerk40t/kernel/kernel.py +49 -22
- meerk40t/kernel/settings.py +29 -8
- meerk40t/lihuiyu/device.py +30 -12
- meerk40t/main.py +22 -5
- meerk40t/moshi/device.py +20 -6
- meerk40t/network/console_server.py +22 -6
- meerk40t/newly/device.py +10 -3
- meerk40t/newly/gui/gui.py +10 -0
- meerk40t/ruida/device.py +22 -2
- meerk40t/ruida/gui/gui.py +6 -6
- meerk40t/ruida/gui/ruidaoperationproperties.py +1 -10
- meerk40t/ruida/loader.py +6 -3
- meerk40t/ruida/rdjob.py +3 -3
- meerk40t/tools/geomstr.py +195 -39
- meerk40t/tools/rasterplotter.py +179 -93
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/RECORD +98 -96
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/zip-safe +0 -0
@@ -1,12 +1,13 @@
|
|
1
1
|
# import threading
|
2
2
|
from copy import copy
|
3
|
-
|
3
|
+
|
4
4
|
import numpy as np
|
5
5
|
import wx
|
6
|
-
from
|
7
|
-
|
6
|
+
from PIL import Image, ImageEnhance, ImageOps
|
7
|
+
|
8
8
|
from meerk40t.core.node.elem_image import ImageNode
|
9
9
|
from meerk40t.core.node.elem_path import PathNode
|
10
|
+
from meerk40t.core.node.node import Node
|
10
11
|
from meerk40t.core.units import UNITS_PER_INCH
|
11
12
|
|
12
13
|
# from meerk40t.gui.icons import icon_ignore
|
@@ -30,7 +31,8 @@ from meerk40t.gui.wxutils import (
|
|
30
31
|
wxStaticText,
|
31
32
|
)
|
32
33
|
from meerk40t.image.imagetools import img_to_polygons, img_to_rectangles
|
33
|
-
from meerk40t.
|
34
|
+
from meerk40t.kernel.kernel import Job
|
35
|
+
from meerk40t.svgelements import Color, Matrix
|
34
36
|
|
35
37
|
_ = wx.GetTranslation
|
36
38
|
|
@@ -46,7 +48,15 @@ class ContourPanel(wx.Panel):
|
|
46
48
|
def accepts(node):
|
47
49
|
return hasattr(node, "as_image")
|
48
50
|
|
49
|
-
def __init__(
|
51
|
+
def __init__(
|
52
|
+
self,
|
53
|
+
*args,
|
54
|
+
context=None,
|
55
|
+
node=None,
|
56
|
+
simplified=False,
|
57
|
+
direct_mode=False,
|
58
|
+
**kwds,
|
59
|
+
):
|
50
60
|
# begin wxGlade: LayerSettingPanel.__init__
|
51
61
|
kwds["style"] = kwds.get("style", 0)
|
52
62
|
wx.Panel.__init__(self, *args, **kwds)
|
@@ -74,42 +84,49 @@ class ContourPanel(wx.Panel):
|
|
74
84
|
if simplified:
|
75
85
|
self.check_original.Hide()
|
76
86
|
|
77
|
-
self.text_minimum = TextCtrl(
|
78
|
-
|
79
|
-
)
|
80
|
-
self.text_maximum = TextCtrl(
|
81
|
-
self, wx.ID_ANY, "", limited=True, check="float"
|
82
|
-
)
|
87
|
+
self.text_minimum = TextCtrl(self, wx.ID_ANY, "", limited=True, check="float")
|
88
|
+
self.text_maximum = TextCtrl(self, wx.ID_ANY, "", limited=True, check="float")
|
83
89
|
self.check_inner = wxCheckBox(self, wx.ID_ANY, _("Ignore inner"))
|
84
90
|
self.radio_simplify = wxRadioBox(
|
85
|
-
self,
|
91
|
+
self,
|
92
|
+
wx.ID_ANY,
|
86
93
|
label=_("Contour simplification"),
|
87
|
-
choices
|
94
|
+
choices=(_("None"), _("Visvalingam"), _("Douglas-Peucker")),
|
88
95
|
)
|
89
96
|
self.radio_method = wxRadioBox(
|
90
|
-
self,
|
97
|
+
self,
|
98
|
+
wx.ID_ANY,
|
91
99
|
label=_("Detection Method"),
|
92
|
-
choices
|
100
|
+
choices=(_("Polygons"), _("Bounding rectangles")),
|
93
101
|
)
|
94
102
|
|
95
103
|
self.check_auto = wxCheckBox(self, wx.ID_ANY, _("Automatic update"))
|
96
104
|
self.button_update = wxButton(self, wx.ID_ANY, _("Update"))
|
97
105
|
self.button_create = wxButton(self, wx.ID_ANY, _("Generate contours"))
|
98
|
-
self.button_create_placement = wxButton(
|
106
|
+
self.button_create_placement = wxButton(
|
107
|
+
self, wx.ID_ANY, _("Generate placements")
|
108
|
+
)
|
99
109
|
placement_choices = (
|
100
110
|
_("Edge (prefer short side)"),
|
101
111
|
_("Edge (prefer long side)"),
|
102
112
|
_("Center (unrotated)"),
|
103
113
|
_("Center (rotated)"),
|
104
114
|
)
|
105
|
-
self.combo_placement = wxComboBox(
|
115
|
+
self.combo_placement = wxComboBox(
|
116
|
+
self,
|
117
|
+
wx.ID_ANY,
|
118
|
+
choices=placement_choices,
|
119
|
+
style=wx.CB_DROPDOWN | wx.CB_READONLY,
|
120
|
+
)
|
106
121
|
|
107
122
|
self.bitmap_preview = wxStaticBitmap(self, wx.ID_ANY)
|
108
123
|
self.label_info = wxStaticText(self, wx.ID_ANY)
|
109
124
|
self.list_contours = wxListCtrl(
|
110
|
-
self,
|
125
|
+
self,
|
126
|
+
wx.ID_ANY,
|
111
127
|
style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES | wx.LC_SINGLE_SEL,
|
112
|
-
context=self.context,
|
128
|
+
context=self.context,
|
129
|
+
list_name="list_contours",
|
113
130
|
)
|
114
131
|
self.update_job = Job(
|
115
132
|
process=self.refresh_preview_job,
|
@@ -142,8 +159,12 @@ class ContourPanel(wx.Panel):
|
|
142
159
|
self.check_invert.Bind(wx.EVT_CHECKBOX, self.on_control_update)
|
143
160
|
self.check_inner.Bind(wx.EVT_CHECKBOX, self.on_control_update)
|
144
161
|
self.check_enable_contrast.Bind(wx.EVT_CHECKBOX, self.on_control_update)
|
145
|
-
self.slider_contrast_brightness.Bind(
|
146
|
-
|
162
|
+
self.slider_contrast_brightness.Bind(
|
163
|
+
wx.EVT_SLIDER, self.on_slider_contrast_brightness
|
164
|
+
)
|
165
|
+
self.slider_contrast_contrast.Bind(
|
166
|
+
wx.EVT_SLIDER, self.on_slider_contrast_contrast
|
167
|
+
)
|
147
168
|
self.radio_method.Bind(wx.EVT_RADIOBOX, self.on_control_update)
|
148
169
|
self.radio_simplify.Bind(wx.EVT_RADIOBOX, self.on_control_update)
|
149
170
|
self.text_minimum.SetActionRoutine(self.on_control_update)
|
@@ -164,9 +185,7 @@ class ContourPanel(wx.Panel):
|
|
164
185
|
sizer_right.Add(self.bitmap_preview, 4, wx.EXPAND, 0)
|
165
186
|
sizer_right.Add(self.list_contours, 1, wx.EXPAND, 0)
|
166
187
|
|
167
|
-
sizer_param_picture = StaticBoxSizer(
|
168
|
-
self, wx.ID_ANY, _("Image:"), wx.VERTICAL
|
169
|
-
)
|
188
|
+
sizer_param_picture = StaticBoxSizer(self, wx.ID_ANY, _("Image:"), wx.VERTICAL)
|
170
189
|
sizer_contrast = StaticBoxSizer(self, wx.ID_ANY, _("Contrast"), wx.VERTICAL)
|
171
190
|
|
172
191
|
sizer_contrast_main = wx.BoxSizer(wx.HORIZONTAL)
|
@@ -243,25 +262,57 @@ class ContourPanel(wx.Panel):
|
|
243
262
|
def __do_defaults(self):
|
244
263
|
self.check_auto.SetValue(self.auto_update)
|
245
264
|
self.button_update.Enable(not self.auto_update)
|
246
|
-
last_val = self.context.setting(
|
265
|
+
last_val = self.context.setting(
|
266
|
+
int, "contour_placement", 1
|
267
|
+
) # Long side is default preference
|
247
268
|
if last_val < 0 or last_val >= self.combo_placement.GetCount():
|
248
269
|
last_val = 0
|
249
270
|
self.combo_placement.SetSelection(last_val)
|
250
271
|
|
251
272
|
def __set_properties(self):
|
252
|
-
self.
|
273
|
+
self.check_invert.SetToolTip(_("Invert the image before processing"))
|
274
|
+
self.check_original.SetToolTip(
|
275
|
+
_("Use the original image instead of the dithered one")
|
276
|
+
)
|
277
|
+
self.check_auto.SetToolTip(_("Automatically update the preview"))
|
278
|
+
self.button_update.SetToolTip(_("Update the preview"))
|
279
|
+
self.button_create.SetToolTip(_("Creates the recognized contour elements"))
|
280
|
+
self.button_create_placement.SetToolTip(
|
281
|
+
_("Creates the corresponding placements")
|
282
|
+
)
|
283
|
+
self.combo_placement.SetToolTip(_("Select the placement position"))
|
253
284
|
self.check_enable_contrast.SetToolTip(_("Enable Contrast"))
|
254
285
|
self.check_enable_contrast.SetValue(False)
|
255
286
|
self.button_reset_contrast.SetToolTip(_("Reset Contrast"))
|
256
287
|
self.slider_contrast_contrast.SetToolTip(_("Contrast amount"))
|
257
|
-
self.text_contrast_contrast.SetToolTip(
|
288
|
+
self.text_contrast_contrast.SetToolTip(
|
289
|
+
_("Contrast the lights and darks by how much?")
|
290
|
+
)
|
258
291
|
self.slider_contrast_brightness.SetToolTip(_("Brightness amount"))
|
259
|
-
self.text_contrast_brightness.SetToolTip(
|
260
|
-
|
261
|
-
|
262
|
-
self.
|
263
|
-
|
264
|
-
|
292
|
+
self.text_contrast_brightness.SetToolTip(
|
293
|
+
_("Make the image how much more bright?")
|
294
|
+
)
|
295
|
+
self.text_minimum.SetToolTip(
|
296
|
+
_(
|
297
|
+
"What is the minimal size of objects (as percentage of the overall area)?"
|
298
|
+
)
|
299
|
+
)
|
300
|
+
self.text_maximum.SetToolTip(
|
301
|
+
_(
|
302
|
+
"What is the maximal size of objects (as percentage of the overall area)?"
|
303
|
+
)
|
304
|
+
)
|
305
|
+
self.check_inner.SetToolTip(
|
306
|
+
_("Do you want to recognize objects inside of another object?")
|
307
|
+
)
|
308
|
+
self.radio_method.SetToolTip(
|
309
|
+
_(
|
310
|
+
"Do you want to create the contour itself or the minimal rectangle enclosing it?"
|
311
|
+
)
|
312
|
+
)
|
313
|
+
self.radio_simplify.SetToolTip(
|
314
|
+
_("Shall we try to reduce the number of points for the created contour?")
|
315
|
+
)
|
265
316
|
|
266
317
|
self.slider_contrast_brightness.SetMaxSize(wx.Size(200, -1))
|
267
318
|
self.slider_contrast_contrast.SetMaxSize(wx.Size(200, -1))
|
@@ -321,14 +372,11 @@ class ContourPanel(wx.Panel):
|
|
321
372
|
self.reset_contrast()
|
322
373
|
self.on_control_update(None)
|
323
374
|
|
324
|
-
def on_slider_contrast_contrast(
|
325
|
-
self, event=None
|
326
|
-
):
|
375
|
+
def on_slider_contrast_contrast(self, event=None):
|
327
376
|
contrast = int(self.slider_contrast_contrast.GetValue())
|
328
377
|
self.text_contrast_contrast.SetValue(str(contrast))
|
329
378
|
if event and (
|
330
|
-
not self.context.process_while_sliding
|
331
|
-
and wx.GetMouseState().LeftIsDown()
|
379
|
+
not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
|
332
380
|
):
|
333
381
|
event.Skip()
|
334
382
|
return
|
@@ -339,8 +387,7 @@ class ContourPanel(wx.Panel):
|
|
339
387
|
brightness = int(self.slider_contrast_brightness.GetValue())
|
340
388
|
self.text_contrast_brightness.SetValue(str(brightness))
|
341
389
|
if event and (
|
342
|
-
not self.context.process_while_sliding
|
343
|
-
and wx.GetMouseState().LeftIsDown()
|
390
|
+
not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
|
344
391
|
):
|
345
392
|
event.Skip()
|
346
393
|
return
|
@@ -357,7 +404,7 @@ class ContourPanel(wx.Panel):
|
|
357
404
|
def on_creation(self, event):
|
358
405
|
for idx, (geom, area) in enumerate(self.contours):
|
359
406
|
node = PathNode(
|
360
|
-
geometry
|
407
|
+
geometry=geom,
|
361
408
|
stroke=Color("blue"),
|
362
409
|
label=f"Contour {self.node.display_label()} #{idx+1}",
|
363
410
|
)
|
@@ -366,7 +413,6 @@ class ContourPanel(wx.Panel):
|
|
366
413
|
self.context.elements.signal("refresh_scene", "Scene")
|
367
414
|
|
368
415
|
def on_creation_placement(self, event):
|
369
|
-
|
370
416
|
def get_place_parameters(geom, method):
|
371
417
|
points = list(geom.as_points())
|
372
418
|
nx = None
|
@@ -391,21 +437,21 @@ class ContourPanel(wx.Panel):
|
|
391
437
|
side2 = geom.distance(points[1], points[2])
|
392
438
|
if method in (0, 1):
|
393
439
|
if method == 0:
|
394
|
-
|
440
|
+
# If the preference is for a long side then our reference point is pt0 if side1 is long and pt1 if side1 is short
|
395
441
|
refidx = 0 if side1 < side2 else 1
|
396
442
|
else:
|
397
443
|
# If the preference is for a short side then our reference point is pt1 if side1 is long and pt0 if side1 is short
|
398
444
|
refidx = 1 if side1 < side2 else 0
|
399
445
|
ref_x = points[refidx].real
|
400
446
|
ref_y = points[refidx].imag
|
401
|
-
rotation_angle = geom.angle(points[refidx], points[refidx+1])
|
447
|
+
rotation_angle = geom.angle(points[refidx], points[refidx + 1])
|
402
448
|
place_corner = 0
|
403
|
-
elif method == 2:
|
449
|
+
elif method == 2: # center - unrotated
|
404
450
|
ref_x = (nx + mx) / 2
|
405
451
|
ref_y = (ny + my) / 2
|
406
452
|
rotation_angle = 0
|
407
453
|
place_corner = 4
|
408
|
-
elif method == 3:
|
454
|
+
elif method == 3: # center - rotated
|
409
455
|
ref_x = (nx + mx) / 2
|
410
456
|
ref_y = (ny + my) / 2
|
411
457
|
rotation_angle = geom.angle(points[0], points[1])
|
@@ -416,14 +462,16 @@ class ContourPanel(wx.Panel):
|
|
416
462
|
if method < 0:
|
417
463
|
return
|
418
464
|
for idx, (geom, area) in enumerate(self.contours):
|
419
|
-
ref_x, ref_y, rotation_angle, place_corner = get_place_parameters(
|
465
|
+
ref_x, ref_y, rotation_angle, place_corner = get_place_parameters(
|
466
|
+
geom, method
|
467
|
+
)
|
420
468
|
self.context.elements.op_branch.add(
|
421
469
|
type="place point",
|
422
470
|
label=f"Contour #{idx+1}",
|
423
471
|
x=ref_x,
|
424
472
|
y=ref_y,
|
425
473
|
rotation=rotation_angle,
|
426
|
-
corner=place_corner
|
474
|
+
corner=place_corner,
|
427
475
|
)
|
428
476
|
|
429
477
|
self.context.elements.signal("refresh_scene")
|
@@ -535,6 +583,7 @@ class ContourPanel(wx.Panel):
|
|
535
583
|
|
536
584
|
def calculate_contours(self):
|
537
585
|
import time
|
586
|
+
|
538
587
|
self.contours.clear()
|
539
588
|
if self.image is None:
|
540
589
|
return
|
@@ -557,15 +606,18 @@ class ContourPanel(wx.Panel):
|
|
557
606
|
ignoreinner=self.parameters["cnt_ignoreinner"],
|
558
607
|
needs_invert=True,
|
559
608
|
)
|
609
|
+
if len(self.contours) == 0 or len(self.contours[0]) != 2:
|
610
|
+
self.label_info.SetLabel(_("No contours found."))
|
611
|
+
return
|
560
612
|
for idx, (geom, area) in enumerate(self.contours):
|
561
613
|
if method == 0:
|
562
614
|
simple = self.parameters["cnt_simplify"]
|
563
615
|
# We are on pixel level
|
564
616
|
threshold = self.parameters["cnt_threshold"]
|
565
|
-
if simple==1:
|
617
|
+
if simple == 1:
|
566
618
|
# Let's try Visvalingam line simplification
|
567
619
|
geom = geom.simplify_geometry(threshold=threshold)
|
568
|
-
elif simple==2:
|
620
|
+
elif simple == 2:
|
569
621
|
# Use Douglas-Peucker instead
|
570
622
|
geom = geom.simplify(threshold)
|
571
623
|
geom.transform(self.matrix)
|
@@ -573,10 +625,9 @@ class ContourPanel(wx.Panel):
|
|
573
625
|
|
574
626
|
t_b = time.perf_counter()
|
575
627
|
|
576
|
-
self.label_info.SetLabel
|
628
|
+
self.label_info.SetLabel(
|
577
629
|
_("Contours generated: {count} in {duration}").format(
|
578
|
-
count=len(self.contours),
|
579
|
-
duration=f"{t_b-t_a:.2f} sec"
|
630
|
+
count=len(self.contours), duration=f"{t_b-t_a:.2f} sec"
|
580
631
|
)
|
581
632
|
)
|
582
633
|
|
@@ -587,15 +638,14 @@ class ContourPanel(wx.Panel):
|
|
587
638
|
self.display_contours(highlight_index=idx)
|
588
639
|
|
589
640
|
def on_right_click(self, event):
|
590
|
-
|
591
641
|
def compare_contour(operation, index, this_area, idx, area):
|
592
|
-
if operation ==
|
642
|
+
if operation == "this":
|
593
643
|
return idx == index
|
594
|
-
elif operation ==
|
644
|
+
elif operation == "others":
|
595
645
|
return idx != index
|
596
|
-
elif operation ==
|
646
|
+
elif operation == "smaller":
|
597
647
|
return area < this_area
|
598
|
-
elif operation ==
|
648
|
+
elif operation == "bigger":
|
599
649
|
return area > this_area
|
600
650
|
return False
|
601
651
|
|
@@ -603,13 +653,15 @@ class ContourPanel(wx.Panel):
|
|
603
653
|
def handler(event):
|
604
654
|
this_area = self.contours[index][1]
|
605
655
|
to_be_deleted = [
|
606
|
-
idx
|
656
|
+
idx
|
657
|
+
for idx, (_, area) in enumerate(self.contours)
|
607
658
|
if compare_contour(operation, index, this_area, idx, area)
|
608
659
|
]
|
609
660
|
for idx in reversed(to_be_deleted):
|
610
661
|
self.contours.pop(idx)
|
611
662
|
self.populate_list()
|
612
663
|
self.display_contours()
|
664
|
+
|
613
665
|
return handler
|
614
666
|
|
615
667
|
index = self.list_contours.GetFirstSelected()
|
@@ -617,10 +669,10 @@ class ContourPanel(wx.Panel):
|
|
617
669
|
return
|
618
670
|
menu = wx.Menu()
|
619
671
|
operations = [
|
620
|
-
(
|
621
|
-
(
|
622
|
-
(
|
623
|
-
(
|
672
|
+
("this", _("Delete this contour")),
|
673
|
+
("others", _("Delete all others")),
|
674
|
+
("bigger", _("Delete all bigger")),
|
675
|
+
("smaller", _("Delete all smaller")),
|
624
676
|
]
|
625
677
|
|
626
678
|
for op, label in operations:
|
@@ -638,19 +690,21 @@ class ContourPanel(wx.Panel):
|
|
638
690
|
)
|
639
691
|
self.list_contours.SetItem(list_id, 1, f"{area:.2f}%")
|
640
692
|
|
641
|
-
def display_contours(self, highlight_index
|
693
|
+
def display_contours(self, highlight_index=-1):
|
642
694
|
if self.make_raster is None:
|
643
695
|
return
|
644
696
|
if self.image is None:
|
645
697
|
self.bitmap_preview.SetBitmap(wx.NullBitmap)
|
646
698
|
return
|
647
|
-
copynode = ImageNode(
|
699
|
+
copynode = ImageNode(
|
700
|
+
image=self.image, matrix=self.matrix, dither=False, prevent_crop=True
|
701
|
+
)
|
648
702
|
data = [copynode]
|
649
703
|
for idx, (geom, area) in enumerate(self.contours):
|
650
704
|
node = PathNode(
|
651
|
-
geometry
|
652
|
-
stroke=Color("red") if highlight_index==idx else Color("blue"),
|
653
|
-
fill=Color("yellow") if highlight_index==idx else None,
|
705
|
+
geometry=geom,
|
706
|
+
stroke=Color("red") if highlight_index == idx else Color("blue"),
|
707
|
+
fill=Color("yellow") if highlight_index == idx else None,
|
654
708
|
label=f"Contour {self.node.display_label()} #{idx+1} [{area:.2f}%]",
|
655
709
|
)
|
656
710
|
data.append(node)
|
@@ -678,6 +732,7 @@ class ContourPanel(wx.Panel):
|
|
678
732
|
idx = self.list_contours.GetFirstSelected()
|
679
733
|
self.display_contours(highlight_index=idx)
|
680
734
|
|
735
|
+
|
681
736
|
class KeyholePanel(wx.Panel):
|
682
737
|
name = _("Keyhole")
|
683
738
|
priority = 5
|
@@ -702,9 +757,7 @@ class KeyholePanel(wx.Panel):
|
|
702
757
|
def __do_layout(self):
|
703
758
|
# begin wxGlade: PositionPanel.__do_layout
|
704
759
|
sizer_main = wx.BoxSizer(wx.VERTICAL)
|
705
|
-
sizer_release = StaticBoxSizer(
|
706
|
-
self, wx.ID_ANY, _("Keyhole:"), wx.HORIZONTAL
|
707
|
-
)
|
760
|
+
sizer_release = StaticBoxSizer(self, wx.ID_ANY, _("Keyhole:"), wx.HORIZONTAL)
|
708
761
|
sizer_release.Add(self.button_release, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
709
762
|
|
710
763
|
sizer_main.Add(sizer_release, 0, wx.EXPAND, 0)
|
@@ -715,9 +768,7 @@ class KeyholePanel(wx.Panel):
|
|
715
768
|
|
716
769
|
def __set_properties(self):
|
717
770
|
self.button_release.SetToolTip(
|
718
|
-
_(
|
719
|
-
"Remove the keyhole and show the complete image"
|
720
|
-
)
|
771
|
+
_("Remove the keyhole and show the complete image")
|
721
772
|
)
|
722
773
|
|
723
774
|
def pane_hide(self):
|
@@ -941,7 +992,6 @@ class CropPanel(wx.Panel):
|
|
941
992
|
self.set_slider_limits("lrtb")
|
942
993
|
self.context.elements.do_image_update(self.node, self.context)
|
943
994
|
|
944
|
-
|
945
995
|
def on_check_enable_crop(self, event=None):
|
946
996
|
flag = self.check_enable_crop.GetValue()
|
947
997
|
if flag:
|
@@ -971,8 +1021,7 @@ class CropPanel(wx.Panel):
|
|
971
1021
|
|
972
1022
|
def on_slider_left(self, event=None):
|
973
1023
|
if event and (
|
974
|
-
not self.context.process_while_sliding
|
975
|
-
and wx.GetMouseState().LeftIsDown()
|
1024
|
+
not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
|
976
1025
|
):
|
977
1026
|
event.Skip()
|
978
1027
|
return
|
@@ -980,8 +1029,7 @@ class CropPanel(wx.Panel):
|
|
980
1029
|
|
981
1030
|
def on_slider_right(self, event=None):
|
982
1031
|
if event and (
|
983
|
-
not self.context.process_while_sliding
|
984
|
-
and wx.GetMouseState().LeftIsDown()
|
1032
|
+
not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
|
985
1033
|
):
|
986
1034
|
event.Skip()
|
987
1035
|
return
|
@@ -990,8 +1038,7 @@ class CropPanel(wx.Panel):
|
|
990
1038
|
def on_slider_top(self, event=None):
|
991
1039
|
# Wait until the user has stopped to move the slider
|
992
1040
|
if event and (
|
993
|
-
not self.context.process_while_sliding
|
994
|
-
and wx.GetMouseState().LeftIsDown()
|
1041
|
+
not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
|
995
1042
|
):
|
996
1043
|
event.Skip()
|
997
1044
|
return
|
@@ -999,8 +1046,7 @@ class CropPanel(wx.Panel):
|
|
999
1046
|
|
1000
1047
|
def on_slider_bottom(self, event=None):
|
1001
1048
|
if event and (
|
1002
|
-
not self.context.process_while_sliding
|
1003
|
-
and wx.GetMouseState().LeftIsDown()
|
1049
|
+
not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
|
1004
1050
|
):
|
1005
1051
|
event.Skip()
|
1006
1052
|
return
|
@@ -1052,7 +1098,6 @@ class CropPanel(wx.Panel):
|
|
1052
1098
|
else:
|
1053
1099
|
self.text_bottom.SetValue(f"> {dvalue} px")
|
1054
1100
|
|
1055
|
-
|
1056
1101
|
def _setbounds(self):
|
1057
1102
|
if self.op is None:
|
1058
1103
|
return
|
@@ -1137,6 +1182,7 @@ class CropPanel(wx.Panel):
|
|
1137
1182
|
self.set_slider_limits("t")
|
1138
1183
|
self._setbounds()
|
1139
1184
|
|
1185
|
+
|
1140
1186
|
class ImageModificationPanel(ScrolledPanel):
|
1141
1187
|
name = _("Modification")
|
1142
1188
|
priority = 90
|
@@ -1167,7 +1213,8 @@ class ImageModificationPanel(ScrolledPanel):
|
|
1167
1213
|
self,
|
1168
1214
|
wx.ID_ANY,
|
1169
1215
|
style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES | wx.LC_SINGLE_SEL,
|
1170
|
-
context=self.context,
|
1216
|
+
context=self.context,
|
1217
|
+
list_name="list_imageoperations",
|
1171
1218
|
)
|
1172
1219
|
|
1173
1220
|
self._do_layout()
|
@@ -1187,7 +1234,9 @@ class ImageModificationPanel(ScrolledPanel):
|
|
1187
1234
|
)
|
1188
1235
|
self.list_operations.resize_columns()
|
1189
1236
|
sizer_main = wx.BoxSizer(wx.VERTICAL)
|
1190
|
-
sizer_script = StaticBoxSizer(
|
1237
|
+
sizer_script = StaticBoxSizer(
|
1238
|
+
self, wx.ID_ANY, _("Raster-Wizard"), wx.HORIZONTAL
|
1239
|
+
)
|
1191
1240
|
|
1192
1241
|
sizer_script.Add(self.combo_scripts, 1, wx.EXPAND, 0)
|
1193
1242
|
sizer_script.Add(self.button_apply, 0, wx.EXPAND, 0)
|
@@ -1385,6 +1434,7 @@ class ImageModificationPanel(ScrolledPanel):
|
|
1385
1434
|
def signal(self, signalstr, myargs):
|
1386
1435
|
return
|
1387
1436
|
|
1437
|
+
|
1388
1438
|
class ImageVectorisationPanel(ScrolledPanel):
|
1389
1439
|
name = _("Vectorisation")
|
1390
1440
|
priority = 95
|
@@ -1785,6 +1835,7 @@ class ImageVectorisationPanel(ScrolledPanel):
|
|
1785
1835
|
def signal(self, signalstr, myargs):
|
1786
1836
|
return
|
1787
1837
|
|
1838
|
+
|
1788
1839
|
class ImagePropertyPanel(ScrolledPanel):
|
1789
1840
|
def __init__(self, *args, context=None, node=None, **kwargs):
|
1790
1841
|
# begin wxGlade: ConsolePanel.__init__
|
@@ -1893,15 +1944,11 @@ class ImagePropertyPanel(ScrolledPanel):
|
|
1893
1944
|
self.slider_grayscale_green = wx.Slider(
|
1894
1945
|
self, wx.ID_ANY, 0, -1000, 1000, style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
|
1895
1946
|
)
|
1896
|
-
self.text_grayscale_green = TextCtrl(
|
1897
|
-
self, wx.ID_ANY, "", style=wx.TE_READONLY
|
1898
|
-
)
|
1947
|
+
self.text_grayscale_green = TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
|
1899
1948
|
self.slider_grayscale_blue = wx.Slider(
|
1900
1949
|
self, wx.ID_ANY, 0, -1000, 1000, style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
|
1901
1950
|
)
|
1902
|
-
self.text_grayscale_blue = TextCtrl(
|
1903
|
-
self, wx.ID_ANY, "", style=wx.TE_READONLY
|
1904
|
-
)
|
1951
|
+
self.text_grayscale_blue = TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
|
1905
1952
|
self.slider_grayscale_lightness = wx.Slider(
|
1906
1953
|
self, wx.ID_ANY, 500, 0, 1000, style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
|
1907
1954
|
)
|
@@ -1989,7 +2036,7 @@ class ImagePropertyPanel(ScrolledPanel):
|
|
1989
2036
|
self.combo_dither.SetValue(node.dither_type)
|
1990
2037
|
self.combo_dither.Enable(bool(node.dither))
|
1991
2038
|
self.check_enable_depthmap.SetValue(node.is_depthmap)
|
1992
|
-
resolutions =list((2**p for p in range(8, 1, -1)))
|
2039
|
+
resolutions = list((2**p for p in range(8, 1, -1)))
|
1993
2040
|
try:
|
1994
2041
|
idx = resolutions.index(node.depth_resolution)
|
1995
2042
|
except (IndexError, AttributeError, ValueError) as e:
|
@@ -2002,8 +2049,9 @@ class ImagePropertyPanel(ScrolledPanel):
|
|
2002
2049
|
|
2003
2050
|
def __set_properties(self):
|
2004
2051
|
self.check_keep_size.SetToolTip(
|
2005
|
-
_("Enabled: Keep size and amend internal resolution")
|
2006
|
-
|
2052
|
+
_("Enabled: Keep size and amend internal resolution")
|
2053
|
+
+ "\n"
|
2054
|
+
+ _("Disabled: Keep internal resolution and change size")
|
2007
2055
|
)
|
2008
2056
|
self.check_prevent_crop.SetToolTip(_("Prevent final crop after all operations"))
|
2009
2057
|
self.check_enable_dither.SetToolTip(_("Enable Dither"))
|
@@ -2022,20 +2070,27 @@ class ImagePropertyPanel(ScrolledPanel):
|
|
2022
2070
|
self.text_grayscale_blue.SetToolTip(_("Blue Factor"))
|
2023
2071
|
self.slider_grayscale_lightness.SetToolTip(_("Lightness control"))
|
2024
2072
|
self.text_grayscale_lightness.SetToolTip(_("Lightness"))
|
2025
|
-
self.btn_reset_grayscale.SetToolTip(
|
2073
|
+
self.btn_reset_grayscale.SetToolTip(
|
2074
|
+
_("Reset the grayscale modifiers to standard values")
|
2075
|
+
)
|
2026
2076
|
|
2027
|
-
DEPTH_FLAG_TOOLTIP = _(
|
2077
|
+
DEPTH_FLAG_TOOLTIP = _(
|
2078
|
+
"Do you want to treat this bitmap as depthmap where every greyscal-level corresponds to the amount of times this pixel will be burnt"
|
2079
|
+
)
|
2028
2080
|
self.check_enable_depthmap.SetToolTip(DEPTH_FLAG_TOOLTIP)
|
2029
2081
|
self.check_enable_depthmap.SetValue(False)
|
2030
|
-
DEPTH_RES_TOOLTIP =(
|
2031
|
-
|
2032
|
-
|
2082
|
+
DEPTH_RES_TOOLTIP = (
|
2083
|
+
_("How many grayscales do you want to distinguish?")
|
2084
|
+
+ "\n"
|
2085
|
+
+ _(
|
2033
2086
|
"This operation will step through the image and process it per defined grayscale resolution."
|
2034
|
-
)
|
2035
|
-
|
2087
|
+
)
|
2088
|
+
+ "\n"
|
2089
|
+
+ _(
|
2036
2090
|
"So for full resolution every grayscale level would be processed individually: a black line (or a white line if inverted) would be processed 255 times, a line with grayscale value 128 would be processed 128 times."
|
2037
|
-
)
|
2038
|
-
|
2091
|
+
)
|
2092
|
+
+ "\n"
|
2093
|
+
+ _(
|
2039
2094
|
"You can define a coarser resolution e.g. 64: then very faint lines (grayscale 1-4) would be burned just once, very strong lines (level 252-255) would be burned 64 times."
|
2040
2095
|
)
|
2041
2096
|
)
|
@@ -2217,8 +2272,7 @@ class ImagePropertyPanel(ScrolledPanel):
|
|
2217
2272
|
self, event=None
|
2218
2273
|
): # wxGlade: GrayscalePanel.<event_handler>
|
2219
2274
|
if event and (
|
2220
|
-
not self.context.process_while_sliding
|
2221
|
-
and wx.GetMouseState().LeftIsDown()
|
2275
|
+
not self.context.process_while_sliding and wx.GetMouseState().LeftIsDown()
|
2222
2276
|
):
|
2223
2277
|
event.Skip()
|
2224
2278
|
return
|
meerk40t/gui/ribbon.py
CHANGED
@@ -128,6 +128,7 @@ class Button:
|
|
128
128
|
self.state_unpressed = None
|
129
129
|
self.group = None
|
130
130
|
self.toggle_attr = None
|
131
|
+
self.multi_autoexec = None
|
131
132
|
self.identifier = None
|
132
133
|
self.action = None
|
133
134
|
self.action_right = None
|
@@ -155,6 +156,7 @@ class Button:
|
|
155
156
|
rule_enabled=None,
|
156
157
|
rule_visible=None,
|
157
158
|
object=None,
|
159
|
+
multi_autoexec=None,
|
158
160
|
**kwargs,
|
159
161
|
):
|
160
162
|
"""
|
@@ -205,6 +207,7 @@ class Button:
|
|
205
207
|
self.action_right = action_right
|
206
208
|
self.rule_enabled = rule_enabled
|
207
209
|
self.rule_visible = rule_visible
|
210
|
+
self.multi_autoexec = multi_autoexec
|
208
211
|
if object is not None:
|
209
212
|
self.object = object
|
210
213
|
else:
|
@@ -276,6 +279,7 @@ class Button:
|
|
276
279
|
"rule_visible": self.rule_visible,
|
277
280
|
"toggle_attr": self.toggle_attr,
|
278
281
|
"object": self.object,
|
282
|
+
"multi_autoexec": self.multi_autoexec,
|
279
283
|
}
|
280
284
|
self._update_button_aspect(key, **kwargs)
|
281
285
|
|
@@ -438,7 +442,8 @@ class Button:
|
|
438
442
|
self._restore_button_aspect(key_id)
|
439
443
|
# self.ensure_realize()
|
440
444
|
# And now execute it, provided it would be enabled...
|
441
|
-
auto_execute = self.
|
445
|
+
auto_execute = False if self.multi_autoexec is None else self.multi_autoexec
|
446
|
+
auto_execute = auto_execute and self.context.setting(bool, "button_multi_menu_execute", True)
|
442
447
|
if auto_execute:
|
443
448
|
is_visible = True
|
444
449
|
is_enabled = True
|