meerk40t 0.9.7030__py2.py3-none-any.whl → 0.9.7050__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 +38 -13
- 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/cutplan.py +101 -78
- meerk40t/core/elements/element_treeops.py +435 -140
- meerk40t/core/elements/elements.py +100 -9
- meerk40t/core/elements/shapes.py +259 -72
- meerk40t/core/elements/tree_commands.py +10 -5
- meerk40t/core/node/blobnode.py +19 -4
- 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 +64 -16
- meerk40t/core/node/refnode.py +2 -1
- meerk40t/core/planner.py +25 -11
- meerk40t/core/svg_io.py +91 -34
- meerk40t/device/dummydevice.py +7 -1
- meerk40t/extra/vtracer.py +222 -0
- meerk40t/grbl/device.py +96 -9
- meerk40t/grbl/driver.py +15 -5
- meerk40t/gui/about.py +20 -0
- meerk40t/gui/devicepanel.py +20 -16
- meerk40t/gui/gui_mixins.py +4 -0
- meerk40t/gui/icons.py +330 -253
- meerk40t/gui/laserpanel.py +27 -3
- meerk40t/gui/laserrender.py +41 -21
- meerk40t/gui/magnetoptions.py +158 -65
- meerk40t/gui/materialtest.py +569 -310
- meerk40t/gui/navigationpanels.py +229 -24
- meerk40t/gui/propertypanels/hatchproperty.py +2 -0
- meerk40t/gui/propertypanels/imageproperty.py +160 -106
- meerk40t/gui/propertypanels/wobbleproperty.py +6 -2
- 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 +27 -7
- meerk40t/gui/statusbarwidgets/defaultoperations.py +84 -48
- meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
- meerk40t/gui/tips.py +15 -1
- meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
- meerk40t/gui/wxmmain.py +242 -114
- meerk40t/gui/wxmscene.py +107 -24
- meerk40t/gui/wxmtree.py +4 -2
- meerk40t/gui/wxutils.py +286 -15
- meerk40t/image/imagetools.py +129 -65
- meerk40t/internal_plugins.py +4 -0
- meerk40t/kernel/kernel.py +67 -18
- meerk40t/kernel/settings.py +28 -9
- meerk40t/lihuiyu/device.py +24 -12
- meerk40t/main.py +14 -9
- 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/loader.py +9 -4
- meerk40t/ruida/rdjob.py +48 -8
- meerk40t/tools/geomstr.py +240 -123
- meerk40t/tools/rasterplotter.py +185 -94
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/RECORD +85 -84
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/zip-safe +0 -0
meerk40t/gui/wxmmain.py
CHANGED
@@ -10,7 +10,7 @@ import wx
|
|
10
10
|
from PIL import Image
|
11
11
|
from wx import aui
|
12
12
|
|
13
|
-
from meerk40t.core.exceptions import BadFileError
|
13
|
+
# from meerk40t.core.exceptions import BadFileError
|
14
14
|
from meerk40t.gui.gui_mixins import FormatPainter, Warnings
|
15
15
|
from meerk40t.gui.statusbarwidgets.defaultoperations import DefaultOperationWidget
|
16
16
|
from meerk40t.gui.statusbarwidgets.infowidget import (
|
@@ -127,12 +127,14 @@ from .mwindow import MWindow
|
|
127
127
|
_ = wx.GetTranslation
|
128
128
|
MULTIPLE = "<Multiple files loaded>"
|
129
129
|
|
130
|
+
|
130
131
|
class GUIThread:
|
131
132
|
"""
|
132
133
|
This will take from any thread a command to be executed and inserts it into the main thread
|
133
|
-
This prevents threading & lock issues exhibited by passing along commands
|
134
|
+
This prevents threading & lock issues exhibited by passing along commands
|
134
135
|
via ``consoleserver`` or ``webserver``
|
135
136
|
"""
|
137
|
+
|
136
138
|
def __init__(self, context, *args, **kwargs):
|
137
139
|
self.context = context
|
138
140
|
self._execution_lock = threading.Lock()
|
@@ -161,7 +163,8 @@ class GUIThread:
|
|
161
163
|
def process_command(self, command):
|
162
164
|
with self._execution_lock:
|
163
165
|
self._execution_buffer.append(command)
|
164
|
-
self.context.kernel.schedule(self._execution_timer)
|
166
|
+
self.context.kernel.schedule(self._execution_timer)
|
167
|
+
|
165
168
|
|
166
169
|
class Autosaver:
|
167
170
|
"""
|
@@ -288,10 +291,10 @@ def register_panel_dpi_bug(window, context):
|
|
288
291
|
pane.hide_menu = True
|
289
292
|
pane.pane_show = True
|
290
293
|
msg = _(
|
291
|
-
"Your system is using a very high userscale value: {scale}% ! "
|
292
|
-
"Unfortunately there is a bug in wxPython (the framework we are using) "
|
293
|
-
"that will cause unwanted upscaling of images in this configuration. You will recognize this by looking at very pixely icons.\n"
|
294
|
-
"As there is only so much we can do about it, we recommend lowering your userscale value to something below 150%."
|
294
|
+
"Your system is using a very high userscale value: {scale}% ! "
|
295
|
+
+ "Unfortunately there is a bug in wxPython (the framework we are using) "
|
296
|
+
+ "that will cause unwanted upscaling of images in this configuration. You will recognize this by looking at very pixely icons.\n"
|
297
|
+
+ "As there is only so much we can do about it, we recommend lowering your userscale value to something below 150%."
|
295
298
|
).format(scale=context.root.user_scale)
|
296
299
|
panel = wx.StaticText(window, wx.ID_ANY, label=msg)
|
297
300
|
panel.SetBackgroundColour(wx.YELLOW)
|
@@ -301,6 +304,7 @@ def register_panel_dpi_bug(window, context):
|
|
301
304
|
window.on_pane_create(pane)
|
302
305
|
context.register("pane/dpi_bug", pane)
|
303
306
|
|
307
|
+
|
304
308
|
class MeerK40t(MWindow):
|
305
309
|
"""MeerK40t main window"""
|
306
310
|
|
@@ -362,15 +366,27 @@ class MeerK40t(MWindow):
|
|
362
366
|
self._mgr.SetManagedWindow(self)
|
363
367
|
bg_col = self.context.themes.get("win_bg")
|
364
368
|
fg_col = self.context.themes.get("win_fg")
|
365
|
-
self._mgr.GetArtProvider().SetColour(
|
366
|
-
|
367
|
-
|
369
|
+
self._mgr.GetArtProvider().SetColour(
|
370
|
+
aui.AUI_DOCKART_ACTIVE_CAPTION_COLOUR, bg_col
|
371
|
+
)
|
372
|
+
self._mgr.GetArtProvider().SetColour(
|
373
|
+
aui.AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR, bg_col
|
374
|
+
)
|
375
|
+
self._mgr.GetArtProvider().SetColour(
|
376
|
+
aui.AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR, fg_col
|
377
|
+
)
|
368
378
|
|
369
379
|
bg_col = self.context.themes.get("inactive_bg")
|
370
380
|
fg_col = self.context.themes.get("inactive_fg")
|
371
|
-
self._mgr.GetArtProvider().SetColour(
|
372
|
-
|
373
|
-
|
381
|
+
self._mgr.GetArtProvider().SetColour(
|
382
|
+
aui.AUI_DOCKART_INACTIVE_CAPTION_COLOUR, bg_col
|
383
|
+
)
|
384
|
+
self._mgr.GetArtProvider().SetColour(
|
385
|
+
aui.AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR, bg_col
|
386
|
+
)
|
387
|
+
self._mgr.GetArtProvider().SetColour(
|
388
|
+
aui.AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR, fg_col
|
389
|
+
)
|
374
390
|
|
375
391
|
self.__set_panes()
|
376
392
|
self.__set_commands()
|
@@ -954,7 +970,7 @@ class MeerK40t(MWindow):
|
|
954
970
|
# print (f"Set Tooltips to {self.tooltips}")
|
955
971
|
try:
|
956
972
|
wx.ToolTip.Enable(self.tooltips)
|
957
|
-
except Exception
|
973
|
+
except Exception:
|
958
974
|
pass
|
959
975
|
|
960
976
|
# --- Listen to external events to toggle regmark visibility
|
@@ -1612,9 +1628,11 @@ class MeerK40t(MWindow):
|
|
1612
1628
|
Addtionally it wraps the command in an undoscope statement to
|
1613
1629
|
make the undo action easier to read and to contain.
|
1614
1630
|
"""
|
1631
|
+
|
1615
1632
|
def handler(*args):
|
1616
1633
|
with kernel.elements.undoscope(scope):
|
1617
1634
|
kernel.elements(command)
|
1635
|
+
|
1618
1636
|
return handler
|
1619
1637
|
|
1620
1638
|
def exec_plain(command):
|
@@ -1623,8 +1641,10 @@ class MeerK40t(MWindow):
|
|
1623
1641
|
This function serves as a command handler that takes a command string
|
1624
1642
|
and forwards them to the kernel's elements execution method on a call.
|
1625
1643
|
"""
|
1644
|
+
|
1626
1645
|
def handler(*args):
|
1627
1646
|
kernel.elements(command)
|
1647
|
+
|
1628
1648
|
return handler
|
1629
1649
|
|
1630
1650
|
def run_job(*args):
|
@@ -1758,8 +1778,11 @@ class MeerK40t(MWindow):
|
|
1758
1778
|
|
1759
1779
|
def contains_a_param():
|
1760
1780
|
from meerk40t.core.elements.element_types import effect_nodes, elem_nodes
|
1781
|
+
|
1761
1782
|
result = False
|
1762
|
-
for e in kernel.elements.flat(
|
1783
|
+
for e in kernel.elements.flat(
|
1784
|
+
types=elem_nodes + effect_nodes, emphasized=True
|
1785
|
+
):
|
1763
1786
|
if (
|
1764
1787
|
hasattr(e, "functional_parameter")
|
1765
1788
|
and e.functional_parameter is not None
|
@@ -2173,10 +2196,9 @@ class MeerK40t(MWindow):
|
|
2173
2196
|
"action": exec_plain("clipboard cut\n"),
|
2174
2197
|
"size": bsize_small,
|
2175
2198
|
"identifier": "editcut",
|
2176
|
-
"rule_enabled": lambda cond:
|
2177
|
-
|
2178
|
-
)
|
2179
|
-
> 0,
|
2199
|
+
"rule_enabled": lambda cond: any(
|
2200
|
+
kernel.elements.elems(emphasized=True)
|
2201
|
+
),
|
2180
2202
|
},
|
2181
2203
|
)
|
2182
2204
|
kernel.register(
|
@@ -2189,10 +2211,9 @@ class MeerK40t(MWindow):
|
|
2189
2211
|
"action": exec_plain("clipboard copy\n"),
|
2190
2212
|
"size": bsize_small,
|
2191
2213
|
"identifier": "editcopy",
|
2192
|
-
"rule_enabled": lambda cond:
|
2193
|
-
|
2194
|
-
)
|
2195
|
-
> 0,
|
2214
|
+
"rule_enabled": lambda cond: any(
|
2215
|
+
kernel.elements.elems(emphasized=True)
|
2216
|
+
),
|
2196
2217
|
},
|
2197
2218
|
)
|
2198
2219
|
|
@@ -2213,9 +2234,7 @@ class MeerK40t(MWindow):
|
|
2213
2234
|
"icon": icons8_paste,
|
2214
2235
|
"tip": _("Paste elements from clipboard"),
|
2215
2236
|
"help": "basicediting",
|
2216
|
-
"action": exec_plain(
|
2217
|
-
"clipboard paste -dx 3mm -dy 3mm\n"
|
2218
|
-
),
|
2237
|
+
"action": exec_plain("clipboard paste -dx 3mm -dy 3mm\n"),
|
2219
2238
|
"size": bsize_small,
|
2220
2239
|
"identifier": "editpaste",
|
2221
2240
|
"rule_enabled": lambda cond: clipboard_filled(),
|
@@ -2244,7 +2263,10 @@ class MeerK40t(MWindow):
|
|
2244
2263
|
"help": "duplicate",
|
2245
2264
|
"label": _("Grid"),
|
2246
2265
|
"action": lambda v: kernel.console("gui grid\n"),
|
2247
|
-
"rule_enabled": lambda cond: len(
|
2266
|
+
"rule_enabled": lambda cond: len(
|
2267
|
+
list(kernel.elements.elems(emphasized=True))
|
2268
|
+
)
|
2269
|
+
> 0,
|
2248
2270
|
},
|
2249
2271
|
{
|
2250
2272
|
"identifier": "copy_circ",
|
@@ -2254,7 +2276,10 @@ class MeerK40t(MWindow):
|
|
2254
2276
|
"label": _("Circular"),
|
2255
2277
|
"action": lambda v: kernel.console("gui circular\n"),
|
2256
2278
|
"action_right": lambda v: kernel.console("gui grid\n"),
|
2257
|
-
"rule_enabled": lambda cond: len(
|
2279
|
+
"rule_enabled": lambda cond: len(
|
2280
|
+
list(kernel.elements.elems(emphasized=True))
|
2281
|
+
)
|
2282
|
+
> 0,
|
2258
2283
|
},
|
2259
2284
|
{
|
2260
2285
|
"identifier": "copy_circ",
|
@@ -2399,6 +2424,7 @@ class MeerK40t(MWindow):
|
|
2399
2424
|
]
|
2400
2425
|
try:
|
2401
2426
|
import pyclipr
|
2427
|
+
|
2402
2428
|
primary_commands = [
|
2403
2429
|
"clipper union",
|
2404
2430
|
"clipper difference",
|
@@ -2415,7 +2441,9 @@ class MeerK40t(MWindow):
|
|
2415
2441
|
"tip": _("Create a union of the selected elements"),
|
2416
2442
|
"help": "cag",
|
2417
2443
|
"action": exec_in_undo_scope("Union", f"{primary_commands[0]}\n"),
|
2418
|
-
"action_right": exec_in_undo_scope(
|
2444
|
+
"action_right": exec_in_undo_scope(
|
2445
|
+
"Union", f"{secondary_commands[0]}\n"
|
2446
|
+
),
|
2419
2447
|
"size": bsize_small,
|
2420
2448
|
"rule_enabled": lambda cond: len(
|
2421
2449
|
list(kernel.elements.elems(emphasized=True))
|
@@ -2431,7 +2459,9 @@ class MeerK40t(MWindow):
|
|
2431
2459
|
"tip": _("Create a difference of the selected elements"),
|
2432
2460
|
"help": "cag",
|
2433
2461
|
"action": exec_in_undo_scope("Difference", f"{primary_commands[1]}\n"),
|
2434
|
-
"action_right": exec_in_undo_scope(
|
2462
|
+
"action_right": exec_in_undo_scope(
|
2463
|
+
"Difference", f"{secondary_commands[1]}\n"
|
2464
|
+
),
|
2435
2465
|
"size": bsize_small,
|
2436
2466
|
"rule_enabled": lambda cond: len(
|
2437
2467
|
list(kernel.elements.elems(emphasized=True))
|
@@ -2462,8 +2492,12 @@ class MeerK40t(MWindow):
|
|
2462
2492
|
"icon": icon_cag_common,
|
2463
2493
|
"tip": _("Create a intersection of the selected elements"),
|
2464
2494
|
"help": "cag",
|
2465
|
-
"action": exec_in_undo_scope(
|
2466
|
-
|
2495
|
+
"action": exec_in_undo_scope(
|
2496
|
+
"Intersection", f"{primary_commands[3]}\n"
|
2497
|
+
),
|
2498
|
+
"action_right": exec_in_undo_scope(
|
2499
|
+
"Intersection", f"{secondary_commands[3]}\n"
|
2500
|
+
),
|
2467
2501
|
"size": bsize_small,
|
2468
2502
|
"rule_enabled": lambda cond: len(
|
2469
2503
|
list(kernel.elements.elems(emphasized=True))
|
@@ -2480,11 +2514,9 @@ class MeerK40t(MWindow):
|
|
2480
2514
|
my_parent = None
|
2481
2515
|
for node in data:
|
2482
2516
|
this_parent = None
|
2483
|
-
if hasattr(node, "parent"):
|
2484
|
-
if
|
2485
|
-
|
2486
|
-
this_parent = node.parent
|
2487
|
-
if my_parent is None:
|
2517
|
+
if hasattr(node, "parent") and hasattr(node.parent, "type"):
|
2518
|
+
if node.parent.type in ("group", "file"):
|
2519
|
+
this_parent = node.parent
|
2488
2520
|
if this_parent is not None:
|
2489
2521
|
my_parent = this_parent
|
2490
2522
|
else:
|
@@ -2506,7 +2538,9 @@ class MeerK40t(MWindow):
|
|
2506
2538
|
with kernel.elements.undoscope("Group"):
|
2507
2539
|
for node in data:
|
2508
2540
|
if group_node is None:
|
2509
|
-
group_node = node.parent.add(
|
2541
|
+
group_node = node.parent.add(
|
2542
|
+
type="group", label="Group", expanded=True
|
2543
|
+
)
|
2510
2544
|
group_node.append_child(node)
|
2511
2545
|
node.emphasized = True
|
2512
2546
|
if group_node is not None:
|
@@ -2540,27 +2574,25 @@ class MeerK40t(MWindow):
|
|
2540
2574
|
with kernel.elements.undoscope("Ungroup"):
|
2541
2575
|
found_some = False
|
2542
2576
|
for node in list(kernel.elements.elems(emphasized=True)):
|
2543
|
-
if node is not None:
|
2544
|
-
|
2545
|
-
|
2546
|
-
release_em(node)
|
2577
|
+
if node is not None and node.type in ("group", "file"):
|
2578
|
+
found_some = True
|
2579
|
+
release_em(node)
|
2547
2580
|
if not found_some:
|
2548
2581
|
# So let's see that we address the parents...
|
2549
2582
|
for node in list(kernel.elements.elems(emphasized=True)):
|
2550
|
-
if
|
2551
|
-
|
2552
|
-
|
2553
|
-
|
2554
|
-
|
2583
|
+
if (
|
2584
|
+
node is not None
|
2585
|
+
and hasattr(node, "parent")
|
2586
|
+
and hasattr(node.parent, "type")
|
2587
|
+
and node.parent.type in ("group", "file")
|
2588
|
+
):
|
2589
|
+
release_em(node.parent)
|
2555
2590
|
|
2556
2591
|
def part_of_group():
|
2557
|
-
result = False
|
2558
2592
|
for node in list(kernel.elements.elems(emphasized=True)):
|
2559
|
-
if hasattr(node, "parent"):
|
2560
|
-
|
2561
|
-
|
2562
|
-
break
|
2563
|
-
return result
|
2593
|
+
if hasattr(node, "parent") and node.parent.type in ("group", "file"):
|
2594
|
+
return True
|
2595
|
+
return False
|
2564
2596
|
|
2565
2597
|
kernel.register(
|
2566
2598
|
"button/group/Ungroup",
|
@@ -2574,21 +2606,22 @@ class MeerK40t(MWindow):
|
|
2574
2606
|
"rule_enabled": lambda cond: part_of_group(),
|
2575
2607
|
},
|
2576
2608
|
)
|
2577
|
-
choices= [
|
2609
|
+
choices = [
|
2578
2610
|
{
|
2579
2611
|
"attr": "align_first",
|
2580
2612
|
"object": kernel.root,
|
2581
2613
|
"default": True,
|
2582
2614
|
"type": bool,
|
2583
2615
|
"label": _("Alignment to first element"),
|
2584
|
-
"tip":
|
2585
|
-
|
2586
|
-
|
2587
|
-
|
2588
|
-
|
2589
|
-
|
2590
|
-
|
2591
|
-
|
2616
|
+
"tip": _(
|
2617
|
+
"When aligning several elements to each other, they will be aligned to the element..."
|
2618
|
+
)
|
2619
|
+
+ "\n"
|
2620
|
+
+ _("Ticked: ...that was selected first")
|
2621
|
+
+ "\n"
|
2622
|
+
+ _("Unticked: ...that was selected last")
|
2623
|
+
+ "\n"
|
2624
|
+
+ _("(Requires a restart to take effect)"),
|
2592
2625
|
"page": "Scene",
|
2593
2626
|
"section": "Alignment",
|
2594
2627
|
"signals": "restart",
|
@@ -2609,12 +2642,8 @@ class MeerK40t(MWindow):
|
|
2609
2642
|
"Align selected elements at the leftmost position (right click: of the bed)"
|
2610
2643
|
),
|
2611
2644
|
"help": "alignment",
|
2612
|
-
"action": exec_plain(
|
2613
|
-
|
2614
|
-
),
|
2615
|
-
"action_right": exec_plain(
|
2616
|
-
"align push bed group left pop\n"
|
2617
|
-
),
|
2645
|
+
"action": exec_plain(f"align push {align_mode} individual left pop\n"),
|
2646
|
+
"action_right": exec_plain("align push bed group left pop\n"),
|
2618
2647
|
"size": bsize_small,
|
2619
2648
|
"rule_enabled": lambda cond: len(
|
2620
2649
|
list(kernel.elements.elems(emphasized=True))
|
@@ -2701,13 +2730,10 @@ class MeerK40t(MWindow):
|
|
2701
2730
|
"action": lambda v: kernel.console("window toggle AutoExec\n"),
|
2702
2731
|
"size": STD_ICON_SIZE,
|
2703
2732
|
},
|
2704
|
-
|
2705
|
-
]
|
2733
|
+
],
|
2706
2734
|
},
|
2707
2735
|
)
|
2708
2736
|
|
2709
|
-
|
2710
|
-
|
2711
2737
|
# Default Size for small buttons
|
2712
2738
|
# buttonsize = STD_ICON_SIZE / 2
|
2713
2739
|
|
@@ -2775,7 +2801,9 @@ class MeerK40t(MWindow):
|
|
2775
2801
|
),
|
2776
2802
|
"help": "alignment",
|
2777
2803
|
"action": exec_in_undo_scope("Align", f"align {align_mode} centerh\n"),
|
2778
|
-
"action_right": exec_in_undo_scope(
|
2804
|
+
"action_right": exec_in_undo_scope(
|
2805
|
+
"Align", "align bed group centerh\n"
|
2806
|
+
),
|
2779
2807
|
"size": bsize_small,
|
2780
2808
|
"rule_enabled": lambda cond: len(
|
2781
2809
|
list(kernel.elements.elems(emphasized=True))
|
@@ -2793,7 +2821,9 @@ class MeerK40t(MWindow):
|
|
2793
2821
|
),
|
2794
2822
|
"help": "alignment",
|
2795
2823
|
"action": exec_in_undo_scope("Align", f"align {align_mode} centerv\n"),
|
2796
|
-
"action_right": exec_in_undo_scope(
|
2824
|
+
"action_right": exec_in_undo_scope(
|
2825
|
+
"Align", "align bed group centerv\n"
|
2826
|
+
),
|
2797
2827
|
"size": bsize_small,
|
2798
2828
|
"rule_enabled": lambda cond: len(
|
2799
2829
|
list(kernel.elements.elems(emphasized=True))
|
@@ -3080,7 +3110,12 @@ class MeerK40t(MWindow):
|
|
3080
3110
|
version = "default"
|
3081
3111
|
kernel = self.context.kernel
|
3082
3112
|
for saver, save_name, sname in kernel.find("save"):
|
3083
|
-
for
|
3113
|
+
for (
|
3114
|
+
description,
|
3115
|
+
extension,
|
3116
|
+
mimetype,
|
3117
|
+
_version,
|
3118
|
+
) in saver.save_types():
|
3084
3119
|
if pathname.lower().endswith(extension) and _version == version:
|
3085
3120
|
clear_save = True
|
3086
3121
|
break
|
@@ -3624,7 +3659,9 @@ class MeerK40t(MWindow):
|
|
3624
3659
|
self.main_menubar.panereset = self.panes_menu.Append(
|
3625
3660
|
wx.ID_ANY, _("Reset Panes"), ""
|
3626
3661
|
)
|
3627
|
-
self.main_menubar.panereset.SetHelp(
|
3662
|
+
self.main_menubar.panereset.SetHelp(
|
3663
|
+
_("Reset pane positions to a default value")
|
3664
|
+
)
|
3628
3665
|
self.Bind(
|
3629
3666
|
wx.EVT_MENU,
|
3630
3667
|
self.on_pane_reset,
|
@@ -3713,7 +3750,9 @@ class MeerK40t(MWindow):
|
|
3713
3750
|
|
3714
3751
|
if suppress:
|
3715
3752
|
continue
|
3716
|
-
menudata.append(
|
3753
|
+
menudata.append(
|
3754
|
+
[submenu_name, caption, name, window, suffix_path, helptext]
|
3755
|
+
)
|
3717
3756
|
# Now that we have everything let's sort...
|
3718
3757
|
menudata.sort(key=lambda row: row[0])
|
3719
3758
|
|
@@ -3961,17 +4000,23 @@ class MeerK40t(MWindow):
|
|
3961
4000
|
local_choices = choices
|
3962
4001
|
return handler
|
3963
4002
|
|
3964
|
-
|
4003
|
+
"""
|
4004
|
+
Old code for separated undo / redo menu entries
|
4005
|
+
|
4006
|
+
def _update_undo_redo_submenu_splitted(self):
|
3965
4007
|
def undo_jump(index):
|
3966
4008
|
def handler(event):
|
3967
4009
|
self.context(f"undo {index}\n")
|
4010
|
+
|
3968
4011
|
return handler
|
3969
4012
|
|
3970
4013
|
def redo_jump(index):
|
3971
4014
|
def handler(event):
|
3972
4015
|
self.context(f"undo {index + 1}\n")
|
4016
|
+
|
3973
4017
|
return handler
|
3974
4018
|
|
4019
|
+
is_windows = platform.system() == "Windows"
|
3975
4020
|
edit_menu = self.edit_menu
|
3976
4021
|
label = _("Undo/Redo States")
|
3977
4022
|
index = edit_menu.FindItem(label)
|
@@ -3985,20 +4030,86 @@ class MeerK40t(MWindow):
|
|
3985
4030
|
undo.validate()
|
3986
4031
|
item, redo_index = edit_menu.FindChildItem(wx.ID_REDO)
|
3987
4032
|
submenu = wx.Menu()
|
3988
|
-
menuitem
|
4033
|
+
menuitem = wx.MenuItem(submenu, wx.ID_ANY, _("Undo"), "")
|
4034
|
+
if is_windows:
|
4035
|
+
font = menuitem.GetFont()
|
4036
|
+
font.MakeBold()
|
4037
|
+
menuitem.SetFont(font)
|
4038
|
+
submenu.Append(menuitem)
|
3989
4039
|
menuitem.Enable(False)
|
4040
|
+
|
3990
4041
|
for idx, state in undo.states("undo"):
|
3991
4042
|
# print (f"{idx}{'*' if idx == undo._undo_index else ' '}: {state.message}")
|
3992
|
-
menuitem =
|
4043
|
+
menuitem = wx.MenuItem(submenu, wx.ID_ANY, f"{idx}: {_(state.message)}")
|
4044
|
+
submenu.Append(menuitem)
|
3993
4045
|
self.Bind(wx.EVT_MENU, undo_jump(idx), id=menuitem.GetId())
|
3994
4046
|
if undo.has_redo():
|
3995
4047
|
submenu.AppendSeparator()
|
3996
|
-
menuitem
|
4048
|
+
menuitem = wx.MenuItem(submenu, wx.ID_ANY, _("Redo"), "")
|
4049
|
+
if is_windows:
|
4050
|
+
font = menuitem.GetFont()
|
4051
|
+
font.MakeBold()
|
4052
|
+
menuitem.SetFont(font)
|
4053
|
+
submenu.Append(menuitem)
|
3997
4054
|
menuitem.Enable(False)
|
3998
4055
|
for idx, state in undo.states("redo"):
|
3999
|
-
menuitem =
|
4056
|
+
menuitem = wx.MenuItem(submenu, wx.ID_ANY, f"{idx}: {_(state.message)}")
|
4057
|
+
submenu.Append(menuitem)
|
4000
4058
|
self.Bind(wx.EVT_MENU, redo_jump(idx), id=menuitem.GetId())
|
4001
4059
|
edit_menu.Insert(redo_index + 1, wx.ID_ANY, label, submenu)
|
4060
|
+
"""
|
4061
|
+
|
4062
|
+
def _update_undo_redo_submenu(self):
|
4063
|
+
def redo_jump(index):
|
4064
|
+
def handler(event):
|
4065
|
+
self.context(f"undo {index + 1}\n")
|
4066
|
+
|
4067
|
+
return handler
|
4068
|
+
|
4069
|
+
is_windows = platform.system() == "Windows"
|
4070
|
+
edit_menu = self.edit_menu
|
4071
|
+
label = _("Editing History")
|
4072
|
+
index = edit_menu.FindItem(label)
|
4073
|
+
if index != -1:
|
4074
|
+
item = edit_menu.Remove(index)
|
4075
|
+
if item:
|
4076
|
+
item.Destroy()
|
4077
|
+
undo = self.context.elements.undo
|
4078
|
+
if not (undo.has_undo() or undo.has_redo()):
|
4079
|
+
return
|
4080
|
+
undo.validate()
|
4081
|
+
# We need the position of the menu to insert
|
4082
|
+
item, redo_index = edit_menu.FindChildItem(wx.ID_REDO)
|
4083
|
+
submenu = wx.Menu()
|
4084
|
+
menuitem = wx.MenuItem(submenu, wx.ID_ANY, _("Recall..."), "")
|
4085
|
+
# if is_windows:
|
4086
|
+
# font = menuitem.GetFont()
|
4087
|
+
# font.MakeBold()
|
4088
|
+
# menuitem.SetFont(font)
|
4089
|
+
submenu.Append(menuitem)
|
4090
|
+
menuitem.Enable(False)
|
4091
|
+
has_entries = False
|
4092
|
+
for idx in range(1, len(undo._undo_stack) - 1):
|
4093
|
+
state = undo._undo_stack[idx]
|
4094
|
+
# print (f"{idx}{'*' if idx == undo._undo_index else ' '}: {state.message}")
|
4095
|
+
trailer = ""
|
4096
|
+
has_entries = True
|
4097
|
+
if idx == undo._undo_index - 1:
|
4098
|
+
trailer = " (*)"
|
4099
|
+
menuitem = wx.MenuItem(
|
4100
|
+
submenu, wx.ID_ANY, f"{idx}: {_(state.message)}{trailer}"
|
4101
|
+
)
|
4102
|
+
if idx == undo._undo_index - 1 and is_windows:
|
4103
|
+
font = menuitem.GetFont()
|
4104
|
+
font.MakeBold()
|
4105
|
+
menuitem.SetFont(font)
|
4106
|
+
|
4107
|
+
submenu.Append(menuitem)
|
4108
|
+
self.Bind(wx.EVT_MENU, redo_jump(idx), id=menuitem.GetId())
|
4109
|
+
if has_entries:
|
4110
|
+
edit_menu.Insert(redo_index + 1, wx.ID_ANY, label, submenu)
|
4111
|
+
else:
|
4112
|
+
submenu.Destroy()
|
4002
4113
|
|
4003
4114
|
def __set_edit_menu(self):
|
4004
4115
|
"""
|
@@ -4950,7 +5061,9 @@ class MeerK40t(MWindow):
|
|
4950
5061
|
matrix = Matrix(f"scale({UNITS_PER_PIXEL}, {UNITS_PER_PIXEL})")
|
4951
5062
|
# _("Export image")
|
4952
5063
|
with elements.undoscope("Export image"):
|
4953
|
-
node = elements.elem_branch.add(
|
5064
|
+
node = elements.elem_branch.add(
|
5065
|
+
image=img, matrix=matrix, type="elem image"
|
5066
|
+
)
|
4954
5067
|
if elements.classify_new:
|
4955
5068
|
elements.classify([node])
|
4956
5069
|
self.context.signal("refresh_scene", "Scene")
|
@@ -5062,7 +5175,7 @@ class MeerK40t(MWindow):
|
|
5062
5175
|
label = f"1&0 "
|
5063
5176
|
else:
|
5064
5177
|
label = f"{idx} "
|
5065
|
-
recents.append(
|
5178
|
+
recents.append((fname, label))
|
5066
5179
|
|
5067
5180
|
for item in self.recent_file_menu.GetMenuItems():
|
5068
5181
|
self.recent_file_menu.Remove(item)
|
@@ -5331,12 +5444,15 @@ class MeerK40t(MWindow):
|
|
5331
5444
|
|
5332
5445
|
self.set_file_as_recently_used(pathname)
|
5333
5446
|
self.set_working_file_name(pathname)
|
5334
|
-
if
|
5447
|
+
if (
|
5448
|
+
old_note != self.context.elements.note
|
5449
|
+
and self.context.elements.auto_note
|
5450
|
+
):
|
5335
5451
|
self.context("window open Notes\n") # open/not toggle.
|
5336
5452
|
if (
|
5337
|
-
execution
|
5338
|
-
self.context.elements.last_file_autoexec
|
5339
|
-
self.context.elements.last_file_autoexec_active
|
5453
|
+
execution
|
5454
|
+
and self.context.elements.last_file_autoexec
|
5455
|
+
and self.context.elements.last_file_autoexec_active
|
5340
5456
|
):
|
5341
5457
|
flag = False
|
5342
5458
|
if self.context.elements.auto_startup == 0:
|
@@ -5345,7 +5461,9 @@ class MeerK40t(MWindow):
|
|
5345
5461
|
elif self.context.elements.auto_startup == 1:
|
5346
5462
|
# ask
|
5347
5463
|
flag = self.context.kernel.yesno(
|
5348
|
-
_(
|
5464
|
+
_(
|
5465
|
+
"This file contains an active autostart sequence!\nDo you wish to execute it?"
|
5466
|
+
),
|
5349
5467
|
option_yes=_("Execute"),
|
5350
5468
|
option_no=_("Ignore"),
|
5351
5469
|
caption=_("Startup-sequence found"),
|
@@ -5594,32 +5712,43 @@ class MeerK40t(MWindow):
|
|
5594
5712
|
self.check_for_crash()
|
5595
5713
|
|
5596
5714
|
def check_for_crash(self):
|
5597
|
-
|
5598
|
-
|
5599
|
-
|
5600
|
-
recovery_file:str = self.autosave.autosave_file
|
5715
|
+
safe_dir: str = os.path.realpath(get_safe_path(APPLICATION_NAME))
|
5716
|
+
crash_indicator: str = os.path.join(safe_dir, "_crash")
|
5717
|
+
recovery_file: str = self.autosave.autosave_file
|
5601
5718
|
# Is there a crash-indicator? The we look for the latest autosave - file
|
5602
5719
|
if os.path.exists(crash_indicator) and os.path.exists(recovery_file):
|
5603
5720
|
try:
|
5604
|
-
filedate = datetime.datetime.fromtimestamp(
|
5721
|
+
filedate = datetime.datetime.fromtimestamp(
|
5722
|
+
os.path.getmtime(recovery_file)
|
5723
|
+
)
|
5605
5724
|
recovery_date = filedate.isoformat(" ")
|
5606
5725
|
except (
|
5607
|
-
|
5608
|
-
|
5609
|
-
|
5610
|
-
|
5611
|
-
|
5612
|
-
|
5613
|
-
|
5614
|
-
|
5726
|
+
PermissionError,
|
5727
|
+
OSError,
|
5728
|
+
RuntimeError,
|
5729
|
+
FileExistsError,
|
5730
|
+
FileNotFoundError,
|
5731
|
+
) as e:
|
5732
|
+
# print (f"Error happened: {e}")
|
5733
|
+
pass
|
5615
5734
|
except Exception as e:
|
5616
5735
|
recovery_date = "???"
|
5617
5736
|
|
5618
|
-
message =
|
5619
|
-
|
5737
|
+
message = (
|
5738
|
+
_(
|
5739
|
+
"Apparently MeerK40t did crash during the last session, we apologize for this invconvenience."
|
5740
|
+
)
|
5741
|
+
+ "\n"
|
5742
|
+
)
|
5743
|
+
message += (
|
5744
|
+
_(
|
5745
|
+
"There is an autosave file ({filename}),\nthat was last saved at {filedate}."
|
5746
|
+
).format(filename=recovery_file, filedate=recovery_date)
|
5747
|
+
+ "\n"
|
5748
|
+
)
|
5620
5749
|
message += _("Do you want to load this file?")
|
5621
5750
|
caption = _("Crash-Recovery")
|
5622
|
-
recover =
|
5751
|
+
recover = self.context.kernel.yesno(
|
5623
5752
|
message,
|
5624
5753
|
option_yes=_("Load work"),
|
5625
5754
|
option_no=_("Start fresh"),
|
@@ -5629,16 +5758,15 @@ class MeerK40t(MWindow):
|
|
5629
5758
|
try:
|
5630
5759
|
os.remove(crash_indicator)
|
5631
5760
|
except (
|
5632
|
-
|
5633
|
-
|
5634
|
-
|
5635
|
-
|
5636
|
-
|
5637
|
-
|
5638
|
-
|
5639
|
-
|
5761
|
+
PermissionError,
|
5762
|
+
OSError,
|
5763
|
+
RuntimeError,
|
5764
|
+
FileExistsError,
|
5765
|
+
FileNotFoundError,
|
5766
|
+
) as e:
|
5767
|
+
# print (f"Error happened: {e}")
|
5768
|
+
pass
|
5640
5769
|
if recover:
|
5641
5770
|
# Load file
|
5642
5771
|
self.context(f'load "{recovery_file}"\n')
|
5643
5772
|
self.set_needs_save_status(True)
|
5644
|
-
|