meerk40t 0.9.7040__py2.py3-none-any.whl → 0.9.7051__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.
@@ -5,6 +5,7 @@ import wx
5
5
  from wx import aui
6
6
 
7
7
  from meerk40t.core.node.effect_hatch import HatchEffectNode
8
+ from meerk40t.core.node.effect_wobble import WobbleEffectNode
8
9
  from meerk40t.core.node.op_cut import CutOpNode
9
10
  from meerk40t.core.node.op_engrave import EngraveOpNode
10
11
  from meerk40t.core.node.op_image import ImageOpNode
@@ -18,6 +19,7 @@ from meerk40t.gui.wxutils import (
18
19
  dip_size,
19
20
  wxButton,
20
21
  wxCheckBox,
22
+ wxCheckListBox,
21
23
  wxComboBox,
22
24
  wxListBox,
23
25
  wxStaticText,
@@ -183,9 +185,15 @@ class TemplatePanel(wx.Panel):
183
185
  self.SetHelpText("testpattern")
184
186
  self.storage = storage
185
187
  self.callback = None
186
- self.secondary_callback = None
187
188
  self.current_op = None
188
- opchoices = [_("Cut"), _("Engrave"), _("Raster"), _("Image"), _("Hatch")]
189
+ opchoices = [
190
+ _("Cut"),
191
+ _("Engrave"),
192
+ _("Raster"),
193
+ _("Image"),
194
+ _("Hatch"),
195
+ _("Wobble"),
196
+ ]
189
197
  # Setup 5 Op nodes - they aren't saved yet
190
198
  self.default_op = []
191
199
  self.secondary_default_op = []
@@ -213,6 +221,12 @@ class TemplatePanel(wx.Panel):
213
221
  self.secondary_default_op.append(HatchEffectNode())
214
222
  self.color_scheme_free.append(True)
215
223
 
224
+ # Wobble = Cut
225
+ op = CutOpNode()
226
+ self.default_op.append(op)
227
+ self.secondary_default_op.append(WobbleEffectNode())
228
+ self.color_scheme_free.append(True)
229
+
216
230
  self.use_image = [False] * len(self.default_op)
217
231
  self.use_image[3] = True
218
232
 
@@ -269,6 +283,10 @@ class TemplatePanel(wx.Panel):
269
283
  self.text_dim_1.set_range(0, 50)
270
284
  self.text_delta_1 = TextCtrl(self, wx.ID_ANY, limited=True, check="float")
271
285
  self.text_delta_1.set_range(0, 50)
286
+ self.list_options_1 = wxCheckListBox(
287
+ self, wx.ID_ANY, label=_("Pick values"), majorDimension=3
288
+ )
289
+
272
290
  self.unit_param_1a = wxStaticText(self, wx.ID_ANY, "")
273
291
  self.unit_param_1b = wxStaticText(self, wx.ID_ANY, "")
274
292
 
@@ -288,6 +306,9 @@ class TemplatePanel(wx.Panel):
288
306
  self.text_max_2 = TextCtrl(self, wx.ID_ANY, limited=True, check="float")
289
307
  self.text_dim_2 = TextCtrl(self, wx.ID_ANY, limited=True, check="float")
290
308
  self.text_dim_2.set_range(0, 50)
309
+ self.list_options_2 = wxCheckListBox(
310
+ self, wx.ID_ANY, label=_("Pick values"), majorDimension=3
311
+ )
291
312
  self.text_delta_2 = TextCtrl(self, wx.ID_ANY, limited=True, check="float")
292
313
  self.text_delta_2.set_range(0, 50)
293
314
  self.unit_param_2a = wxStaticText(self, wx.ID_ANY, "")
@@ -330,7 +351,7 @@ class TemplatePanel(wx.Panel):
330
351
  sizer_param_optype.Add(sizer_param_check, 1, wx.EXPAND, 0)
331
352
 
332
353
  sizer_param_xy = wx.BoxSizer(wx.HORIZONTAL)
333
- sizer_param_x = StaticBoxSizer(
354
+ self.sizer_param_x = StaticBoxSizer(
334
355
  self, wx.ID_ANY, _("First parameter (X-Axis)"), wx.VERTICAL
335
356
  )
336
357
 
@@ -339,7 +360,7 @@ class TemplatePanel(wx.Panel):
339
360
  size_it(mylbl, LABEL_WIDTH)
340
361
  hline_param_1.Add(mylbl, 0, wx.ALIGN_CENTER_VERTICAL, 0)
341
362
  hline_param_1.Add(self.combo_param_1, 1, wx.ALIGN_CENTER_VERTICAL, 0)
342
-
363
+ self.min_max_container_1 = wx.BoxSizer(wx.VERTICAL)
343
364
  hline_count_1 = wx.BoxSizer(wx.HORIZONTAL)
344
365
  mylbl = wxStaticText(self, wx.ID_ANY, _("Count:"))
345
366
  size_it(mylbl, LABEL_WIDTH)
@@ -362,6 +383,9 @@ class TemplatePanel(wx.Panel):
362
383
  hline_max_1.Add(mylbl, 0, wx.ALIGN_CENTER_VERTICAL, 0)
363
384
  hline_max_1.Add(self.text_max_1, 1, wx.ALIGN_CENTER_VERTICAL, 0)
364
385
  hline_max_1.Add(self.unit_param_1b, 0, wx.ALIGN_CENTER_VERTICAL, 0)
386
+ self.min_max_container_1.Add(hline_count_1, 0, wx.EXPAND, 0)
387
+ self.min_max_container_1.Add(hline_min_1, 0, wx.EXPAND, 0)
388
+ self.min_max_container_1.Add(hline_max_1, 0, wx.EXPAND, 0)
365
389
 
366
390
  hline_dim_1 = wx.BoxSizer(wx.HORIZONTAL)
367
391
  mylbl = wxStaticText(self, wx.ID_ANY, _("Width:"))
@@ -386,15 +410,14 @@ class TemplatePanel(wx.Panel):
386
410
  hline_color_1.Add(self.combo_color_1, 1, wx.ALIGN_CENTER_VERTICAL, 0)
387
411
  hline_color_1.Add(self.check_color_direction_1, 1, wx.ALIGN_CENTER_VERTICAL, 0)
388
412
 
389
- sizer_param_x.Add(hline_param_1, 0, wx.EXPAND, 0)
390
- sizer_param_x.Add(hline_count_1, 0, wx.EXPAND, 0)
391
- sizer_param_x.Add(hline_min_1, 0, wx.EXPAND, 0)
392
- sizer_param_x.Add(hline_max_1, 0, wx.EXPAND, 0)
393
- sizer_param_x.Add(hline_dim_1, 0, wx.EXPAND, 0)
394
- sizer_param_x.Add(hline_delta_1, 0, wx.EXPAND, 0)
395
- sizer_param_x.Add(hline_color_1, 0, wx.EXPAND, 0)
413
+ self.sizer_param_x.Add(hline_param_1, 0, wx.EXPAND, 0)
414
+ self.sizer_param_x.Add(self.min_max_container_1, 0, wx.EXPAND, 0)
415
+ self.sizer_param_x.Add(self.list_options_1, 0, wx.EXPAND, 0)
416
+ self.sizer_param_x.Add(hline_dim_1, 0, wx.EXPAND, 0)
417
+ self.sizer_param_x.Add(hline_delta_1, 0, wx.EXPAND, 0)
418
+ self.sizer_param_x.Add(hline_color_1, 0, wx.EXPAND, 0)
396
419
 
397
- sizer_param_y = StaticBoxSizer(
420
+ self.sizer_param_y = StaticBoxSizer(
398
421
  self, wx.ID_ANY, _("Second parameter (Y-Axis)"), wx.VERTICAL
399
422
  )
400
423
 
@@ -404,6 +427,7 @@ class TemplatePanel(wx.Panel):
404
427
  hline_param_2.Add(mylbl, 0, wx.ALIGN_CENTER_VERTICAL, 0)
405
428
  hline_param_2.Add(self.combo_param_2, 1, wx.ALIGN_CENTER_VERTICAL, 0)
406
429
 
430
+ self.min_max_container_2 = wx.BoxSizer(wx.VERTICAL)
407
431
  hline_count_2 = wx.BoxSizer(wx.HORIZONTAL)
408
432
  mylbl = wxStaticText(self, wx.ID_ANY, _("Count:"))
409
433
  size_it(mylbl, LABEL_WIDTH)
@@ -426,6 +450,10 @@ class TemplatePanel(wx.Panel):
426
450
  hline_max_2.Add(self.text_max_2, 1, wx.ALIGN_CENTER_VERTICAL, 0)
427
451
  hline_max_2.Add(self.unit_param_2b, 0, wx.ALIGN_CENTER_VERTICAL, 0)
428
452
 
453
+ self.min_max_container_2.Add(hline_count_2, 0, wx.EXPAND, 0)
454
+ self.min_max_container_2.Add(hline_min_2, 0, wx.EXPAND, 0)
455
+ self.min_max_container_2.Add(hline_max_2, 0, wx.EXPAND, 0)
456
+
429
457
  hline_dim_2 = wx.BoxSizer(wx.HORIZONTAL)
430
458
  mylbl = wxStaticText(self, wx.ID_ANY, _("Height:"))
431
459
  size_it(mylbl, LABEL_WIDTH)
@@ -449,16 +477,15 @@ class TemplatePanel(wx.Panel):
449
477
  hline_color_2.Add(self.combo_color_2, 1, wx.ALIGN_CENTER_VERTICAL, 0)
450
478
  hline_color_2.Add(self.check_color_direction_2, 1, wx.ALIGN_CENTER_VERTICAL, 0)
451
479
 
452
- sizer_param_y.Add(hline_param_2, 0, wx.EXPAND, 0)
453
- sizer_param_y.Add(hline_count_2, 0, wx.EXPAND, 0)
454
- sizer_param_y.Add(hline_min_2, 0, wx.EXPAND, 0)
455
- sizer_param_y.Add(hline_max_2, 0, wx.EXPAND, 0)
456
- sizer_param_y.Add(hline_dim_2, 0, wx.EXPAND, 0)
457
- sizer_param_y.Add(hline_delta_2, 0, wx.EXPAND, 0)
458
- sizer_param_y.Add(hline_color_2, 0, wx.EXPAND, 0)
480
+ self.sizer_param_y.Add(hline_param_2, 0, wx.EXPAND, 0)
481
+ self.sizer_param_y.Add(self.min_max_container_2, 0, wx.EXPAND, 0)
482
+ self.sizer_param_y.Add(self.list_options_2, 0, wx.EXPAND, 0)
483
+ self.sizer_param_y.Add(hline_dim_2, 0, wx.EXPAND, 0)
484
+ self.sizer_param_y.Add(hline_delta_2, 0, wx.EXPAND, 0)
485
+ self.sizer_param_y.Add(hline_color_2, 0, wx.EXPAND, 0)
459
486
 
460
- sizer_param_xy.Add(sizer_param_x, 1, wx.EXPAND, 0)
461
- sizer_param_xy.Add(sizer_param_y, 1, wx.EXPAND, 0)
487
+ sizer_param_xy.Add(self.sizer_param_x, 1, wx.EXPAND, 0)
488
+ sizer_param_xy.Add(self.sizer_param_y, 1, wx.EXPAND, 0)
462
489
 
463
490
  sizer_main.Add(sizer_param_optype, 0, wx.EXPAND, 0)
464
491
  sizer_main.Add(sizer_param_xy, 0, wx.EXPAND, 0)
@@ -568,6 +595,8 @@ class TemplatePanel(wx.Panel):
568
595
  self.combo_images.Bind(wx.EVT_COMBOBOX, self.on_combo_image)
569
596
  self.spin_count_1.Bind(wx.EVT_SPINCTRL, self.validate_input)
570
597
  self.spin_count_2.Bind(wx.EVT_SPINCTRL, self.validate_input)
598
+ self.Bind(wx.EVT_CHECKLISTBOX, self.validate_input, self.list_options_1)
599
+ self.Bind(wx.EVT_CHECKLISTBOX, self.validate_input, self.list_options_2)
571
600
 
572
601
  self.SetSizer(sizer_main)
573
602
  self.Layout()
@@ -602,6 +631,9 @@ class TemplatePanel(wx.Panel):
602
631
  self.text_dim_1.SetValue(f"{wd.mm:.1f}")
603
632
  self.text_dim_2.SetValue(f"{ht.mm:.1f}")
604
633
 
634
+ def on_selection_list(self, event):
635
+ return
636
+
605
637
  def set_callback(self, routine):
606
638
  self.callback = routine
607
639
  idx = self.combo_ops.GetSelection()
@@ -611,21 +643,7 @@ class TemplatePanel(wx.Panel):
611
643
  opnode = self.default_op[idx]
612
644
  secondary_node = self.secondary_default_op[idx]
613
645
  if self.callback is not None and idx >= 0:
614
- self.callback(opnode)
615
- if self.secondary_callback is not None:
616
- self.secondary_callback(secondary_node)
617
-
618
- def set_secondary_callback(self, routine):
619
- self.secondary_callback = routine
620
- idx = self.combo_ops.GetSelection()
621
- # opnode = None
622
- secondary_node = None
623
- if idx >= 0:
624
- # opnode = self.default_op[idx]
625
- secondary_node = self.secondary_default_op[idx]
626
-
627
- if self.secondary_callback is not None:
628
- self.secondary_callback(secondary_node)
646
+ self.callback(opnode, secondary_node)
629
647
 
630
648
  def use_percent(self):
631
649
  self.context.device.setting(bool, "use_percent_for_power_display", False)
@@ -700,15 +718,13 @@ class TemplatePanel(wx.Panel):
700
718
 
701
719
  self.sizer_param_op.Layout()
702
720
  if self.callback is not None:
703
- self.callback(opnode)
704
- if self.secondary_callback is not None:
705
- self.secondary_callback(secondary_node)
721
+ self.callback(opnode, secondary_node)
706
722
  self.combo_color_1.Enable(self._freecolor)
707
723
  self.combo_color_2.Enable(self._freecolor)
708
724
  self.check_color_direction_1.Enable(self._freecolor)
709
725
  self.check_color_direction_2.Enable(self._freecolor)
710
726
 
711
- # (internal_attribute, secondary_attribute, Label, unit, keep_unit, needs_to_be_positive)
727
+ # (internal_attribute, secondary_attribute, Label, unit, keep_unit, needs_to_be_positive, choices)
712
728
  if self.use_percent():
713
729
  ppi = "%"
714
730
  else:
@@ -718,57 +734,119 @@ class TemplatePanel(wx.Panel):
718
734
  else:
719
735
  speed_unit = "mm/s"
720
736
  self.parameters = [
721
- ("speed", None, _("Speed"), speed_unit, False, True),
722
- ("power", None, _("Power"), ppi, False, True),
723
- ("passes", preset_passes, _("Passes"), "x", False, True),
737
+ ("speed", None, _("Speed"), speed_unit, False, True, None),
738
+ ("power", None, _("Power"), ppi, False, True, None),
739
+ ("passes", preset_passes, _("Passes"), "x", False, True, None),
724
740
  ]
725
741
 
726
742
  if opidx == 0:
727
743
  # Cut
728
744
  # (internal_attribute, secondary_attribute, Label, unit, keep_unit, needs_to_be_positive, type)
729
745
  self.parameters = [
730
- ("speed", None, _("Speed"), speed_unit, False, True, None),
731
- ("power", None, _("Power"), ppi, False, True, None),
732
- ("passes", preset_passes, _("Passes"), "x", False, True, int),
746
+ ("speed", None, _("Speed"), speed_unit, False, True, None, None),
747
+ ("power", None, _("Power"), ppi, False, True, None, None),
748
+ ("passes", preset_passes, _("Passes"), "x", False, True, int, None),
733
749
  ]
734
750
  elif opidx == 1:
735
751
  # Engrave
736
752
  self.parameters = [
737
- ("speed", None, _("Speed"), speed_unit, False, True, None),
738
- ("power", None, _("Power"), ppi, False, True, None),
739
- ("passes", preset_passes, _("Passes"), "x", False, True, int),
753
+ ("speed", None, _("Speed"), speed_unit, False, True, None, None),
754
+ ("power", None, _("Power"), ppi, False, True, None, None),
755
+ ("passes", preset_passes, _("Passes"), "x", False, True, int, None),
740
756
  ]
741
757
  elif opidx == 2:
742
758
  # Raster
743
759
  self.parameters = [
744
- ("speed", None, _("Speed"), speed_unit, False, True, None),
745
- ("power", None, _("Power"), ppi, False, True, None),
746
- ("passes", preset_passes, _("Passes"), "x", False, True, int),
747
- ("dpi", None, _("DPI"), "dpi", False, True, int),
748
- ("overscan", None, _("Overscan"), "mm", False, True, None),
760
+ ("speed", None, _("Speed"), speed_unit, False, True, None, None),
761
+ ("power", None, _("Power"), ppi, False, True, None, None),
762
+ ("passes", preset_passes, _("Passes"), "x", False, True, int, None),
763
+ ("dpi", None, _("DPI"), "dpi", False, True, int, None),
764
+ ("overscan", None, _("Overscan"), "mm", False, True, None, None),
749
765
  ]
750
766
  elif opidx == 3:
751
767
  # Image
752
768
  self.parameters = [
753
- ("speed", None, _("Speed"), speed_unit, False, True, None),
754
- ("power", None, _("Power"), ppi, False, True, None),
755
- ("passes", preset_passes, _("Passes"), "x", False, True, int),
756
- ("dpi", preset_image_dpi, _("DPI"), "dpi", False, True, int),
757
- ("overscan", None, _("Overscan"), "mm", False, True, None),
769
+ ("speed", None, _("Speed"), speed_unit, False, True, None, None),
770
+ ("power", None, _("Power"), ppi, False, True, None, None),
771
+ ("passes", preset_passes, _("Passes"), "x", False, True, int, None),
772
+ ("dpi", preset_image_dpi, _("DPI"), "dpi", False, True, int, None),
773
+ ("overscan", None, _("Overscan"), "mm", False, True, None, None),
758
774
  ]
759
775
  elif opidx == 4:
760
776
  # Hatch
761
777
  self.parameters = [
762
- ("speed", None, _("Speed"), speed_unit, False, True, None),
763
- ("power", None, _("Power"), ppi, False, True, None),
764
- ("passes", preset_passes, _("Passes"), "x", False, True, int),
765
- ("hatch_distance", None, _("Hatch Distance"), "mm", False, True, None),
766
- ("hatch_angle", None, _("Hatch Angle"), "deg", False, True, None),
778
+ ("speed", None, _("Speed"), speed_unit, False, True, None, None),
779
+ ("power", None, _("Power"), ppi, False, True, None, None),
780
+ ("passes", preset_passes, _("Passes"), "x", False, True, int, None),
781
+ (
782
+ "hatch_distance",
783
+ None,
784
+ _("Hatch Distance"),
785
+ "mm",
786
+ False,
787
+ True,
788
+ None,
789
+ None,
790
+ ),
791
+ ("hatch_angle", None, _("Hatch Angle"), "deg", False, True, None, None),
767
792
  ]
793
+ elif opidx == 5:
794
+ # Wobble
795
+ # (internal_attribute, secondary_attribute, Label, unit, keep_unit, needs_to_be_positive, type)
796
+ wobble_choices = list(self.context.match("wobble", suffix=True))
797
+ self.parameters = [
798
+ ("speed", None, _("Speed"), speed_unit, False, True, None, None),
799
+ ("power", None, _("Power"), ppi, False, True, None, None),
800
+ ("passes", preset_passes, _("Passes"), "x", False, True, int, None),
801
+ # wobble_radius
802
+ (
803
+ "wobble_radius",
804
+ preset_balor_wobble,
805
+ _("Wobble Radius"),
806
+ "mm",
807
+ True,
808
+ True,
809
+ None,
810
+ None,
811
+ ),
812
+ (
813
+ "wobble_interval",
814
+ preset_balor_wobble,
815
+ _("Wobble Interval"),
816
+ "mm",
817
+ True,
818
+ True,
819
+ None,
820
+ None,
821
+ ),
822
+ (
823
+ "wobble_speed",
824
+ preset_balor_wobble,
825
+ _("Wobble Speed Multiplier"),
826
+ "x",
827
+ False,
828
+ True,
829
+ None,
830
+ None,
831
+ ),
832
+ ]
833
+ if wobble_choices:
834
+ self.parameters.append(
835
+ (
836
+ "wobble_type",
837
+ preset_balor_wobble,
838
+ _("Wobble Type"),
839
+ "",
840
+ True,
841
+ True,
842
+ None,
843
+ wobble_choices,
844
+ ),
845
+ )
768
846
 
769
847
  if "balor" in self.context.device.path:
770
848
  balor_choices = [
771
- ("frequency", None, _("Frequency"), "kHz", False, True, None),
849
+ ("frequency", None, _("Frequency"), "kHz", False, True, None, None),
772
850
  (
773
851
  "rapid_speed",
774
852
  preset_balor_rapid,
@@ -777,6 +855,7 @@ class TemplatePanel(wx.Panel):
777
855
  False,
778
856
  True,
779
857
  None,
858
+ None,
780
859
  ),
781
860
  (
782
861
  "delay_laser_on",
@@ -786,6 +865,7 @@ class TemplatePanel(wx.Panel):
786
865
  False,
787
866
  False,
788
867
  None,
868
+ None,
789
869
  ),
790
870
  (
791
871
  "delay_laser_off",
@@ -795,6 +875,7 @@ class TemplatePanel(wx.Panel):
795
875
  False,
796
876
  False,
797
877
  None,
878
+ None,
798
879
  ),
799
880
  (
800
881
  "delay_polygon",
@@ -804,32 +885,6 @@ class TemplatePanel(wx.Panel):
804
885
  False,
805
886
  False,
806
887
  None,
807
- ),
808
- (
809
- "wobble_radius",
810
- preset_balor_wobble,
811
- _("Wobble Radius"),
812
- "mm",
813
- True,
814
- True,
815
- None,
816
- ),
817
- (
818
- "wobble_interval",
819
- preset_balor_wobble,
820
- _("Wobble Interval"),
821
- "mm",
822
- True,
823
- True,
824
- None,
825
- ),
826
- (
827
- "wobble_speed",
828
- preset_balor_wobble,
829
- _("Wobble Speed Multiplier"),
830
- "x",
831
- False,
832
- True,
833
888
  None,
834
889
  ),
835
890
  ]
@@ -843,11 +898,11 @@ class TemplatePanel(wx.Panel):
843
898
  False,
844
899
  True,
845
900
  None,
901
+ None,
846
902
  )
847
903
  )
848
904
 
849
- for entry in balor_choices:
850
- self.parameters.append(entry)
905
+ self.parameters.extend(balor_choices)
851
906
  # for p in self.parameters:
852
907
  # if len(p) != 7:
853
908
  # print (f"No good: {p}")
@@ -880,11 +935,32 @@ class TemplatePanel(wx.Panel):
880
935
  # 0 = internal_attribute, 1 = secondary_attribute,
881
936
  # 2 = Label, 3 = unit,
882
937
  # 4 = keep_unit, 5 = needs_to_be_positive)
938
+ standard_items = True
939
+ choices = []
883
940
  if 0 <= idx < len(self.parameters):
884
941
  s_unit = self.parameters[idx][3]
885
942
  b_positive = self.parameters[idx][5]
943
+ if self.parameters[idx][7] is not None:
944
+ self.context.template_list1 = "|".join(
945
+ self.list_options_1.GetCheckedStrings()
946
+ )
947
+ standard_items = False
948
+ choices = self.parameters[idx][7]
949
+ self.list_options_1.Set(choices)
950
+ checked_strings = [
951
+ s for s in self.context.template_list1.split("|") if s
952
+ ]
953
+ if not checked_strings:
954
+ checked_strings = choices
955
+ self.list_options_1.SetCheckedStrings(checked_strings)
956
+
886
957
  self.unit_param_1a.SetLabel(s_unit)
887
958
  self.unit_param_1b.SetLabel(s_unit)
959
+ self.min_max_container_1.ShowItems(standard_items)
960
+ self.list_options_1.Show(not standard_items)
961
+ self.sizer_param_x.Layout()
962
+ self.Layout()
963
+
888
964
  # And now enter validation...
889
965
  self.validate_input(None)
890
966
 
@@ -894,10 +970,29 @@ class TemplatePanel(wx.Panel):
894
970
  # 0 = internal_attribute, 1 = secondary_attribute,
895
971
  # 2 = Label, 3 = unit,
896
972
  # 4 = keep_unit, 5 = needs_to_be_positive)
973
+ standard_items = True
974
+ choices = []
897
975
  if 0 <= idx < len(self.parameters):
898
976
  s_unit = self.parameters[idx][3]
977
+ if self.parameters[idx][7] is not None:
978
+ self.context.template_list2 = "|".join(
979
+ self.list_options_2.GetCheckedStrings()
980
+ )
981
+ standard_items = False
982
+ choices = self.parameters[idx][7]
983
+ self.list_options_2.Set(choices)
984
+ checked_strings = [
985
+ s for s in self.context.template_list2.split("|") if s
986
+ ]
987
+ if not checked_strings:
988
+ checked_strings = choices
989
+ self.list_options_2.SetCheckedStrings(checked_strings)
899
990
  self.unit_param_2a.SetLabel(s_unit)
900
991
  self.unit_param_2b.SetLabel(s_unit)
992
+ self.min_max_container_2.ShowItems(standard_items)
993
+ self.list_options_2.Show(not standard_items)
994
+ self.sizer_param_y.Layout()
995
+ self.Layout()
901
996
  # And now enter validation...
902
997
  self.validate_input(None)
903
998
 
@@ -913,83 +1008,97 @@ class TemplatePanel(wx.Panel):
913
1008
  result = False
914
1009
  return result
915
1010
 
916
- active = True
917
- valid_interval_1 = True
918
- valid_interval_2 = True
919
- optype = self.combo_ops.GetSelection()
920
- if optype < 0:
921
- active = False
922
- if (
923
- optype == 3 and self.combo_images.GetSelection() < 1
924
- ): # image and no valid image chosen
925
- active = False
926
- idx1 = self.combo_param_1.GetSelection()
927
- if idx1 < 0:
928
- active = False
929
- idx2 = self.combo_param_2.GetSelection()
930
- if idx2 < 0:
931
- active = False
932
- if idx1 == idx2:
933
- active = False
934
- if not valid_float(self.text_min_1):
935
- active = False
936
- valid_interval_1 = False
937
- if not valid_float(self.text_max_1):
938
- active = False
939
- valid_interval_1 = False
940
- if not valid_float(self.text_min_2):
941
- active = False
942
- valid_interval_2 = False
943
- if not valid_float(self.text_max_2):
944
- active = False
945
- valid_interval_2 = False
946
- if not valid_float(self.text_dim_1):
947
- active = False
948
- if not valid_float(self.text_delta_1):
949
- active = False
950
- if not valid_float(self.text_dim_2):
951
- active = False
952
- if not valid_float(self.text_delta_2):
953
- active = False
954
- if valid_interval_1:
955
- minv = float(self.text_min_1.GetValue())
956
- maxv = float(self.text_max_1.GetValue())
957
- count = self.spin_count_1.GetValue()
958
- delta = maxv - minv
959
- if count > 1:
960
- delta /= count - 1
961
- s_unit = ""
962
- idx = self.combo_param_1.GetSelection()
963
- # 0 = internal_attribute, 1 = secondary_attribute,
964
- # 2 = Label, 3 = unit,
965
- # 4 = keep_unit, 5 = needs_to_be_positive)
966
- if 0 <= idx < len(self.parameters):
967
- s_unit = self.parameters[idx][3]
968
- self.info_delta_1.SetLabel(
969
- _("Every {dist}").format(dist=self.shortened(delta, 3) + s_unit)
970
- )
971
- else:
972
- self.info_delta_1.SetLabel("---")
973
- if valid_interval_2:
974
- minv = float(self.text_min_2.GetValue())
975
- maxv = float(self.text_max_2.GetValue())
976
- count = self.spin_count_2.GetValue()
977
- delta = maxv - minv
978
- if count > 1:
979
- delta /= count - 1
980
- s_unit = ""
981
- idx = self.combo_param_2.GetSelection()
982
- # 0 = internal_attribute, 1 = secondary_attribute,
983
- # 2 = Label, 3 = unit,
984
- # 4 = keep_unit, 5 = needs_to_be_positive)
985
- if 0 <= idx < len(self.parameters):
986
- s_unit = self.parameters[idx][3]
987
- self.info_delta_2.SetLabel(
988
- _("Every {dist}").format(dist=self.shortened(delta, 3) + s_unit)
989
- )
990
- else:
991
- self.info_delta_2.SetLabel("---")
1011
+ def check_for_active():
1012
+ active = True
1013
+ valid_interval_1 = True
1014
+ valid_interval_2 = True
1015
+ optype = self.combo_ops.GetSelection()
1016
+ if optype < 0:
1017
+ return False
1018
+ if (
1019
+ optype == 3 and self.combo_images.GetSelection() < 1
1020
+ ): # image and no valid image chosen
1021
+ return False
1022
+ idx1 = self.combo_param_1.GetSelection()
1023
+ if idx1 < 0:
1024
+ return False
1025
+ idx2 = self.combo_param_2.GetSelection()
1026
+ if idx2 < 0:
1027
+ return False
1028
+ if idx1 == idx2:
1029
+ return False
1030
+ # Proper check for standard / non-standard parameters
1031
+ if self.parameters[idx1][7] is not None:
1032
+ if not self.list_options_1.GetCheckedStrings():
1033
+ active = False
1034
+ valid_interval_1 = False
1035
+ else:
1036
+ if not valid_float(self.text_min_1):
1037
+ active = False
1038
+ valid_interval_1 = False
1039
+ if not valid_float(self.text_max_1):
1040
+ active = False
1041
+ valid_interval_1 = False
1042
+ if self.parameters[idx2][7] is not None:
1043
+ if not self.list_options_2.GetCheckedStrings():
1044
+ active = False
1045
+ valid_interval_2 = False
1046
+ else:
1047
+ if not valid_float(self.text_min_2):
1048
+ active = False
1049
+ valid_interval_2 = False
1050
+ if not valid_float(self.text_max_2):
1051
+ active = False
1052
+ valid_interval_2 = False
1053
+ if not valid_float(self.text_dim_1):
1054
+ active = False
1055
+ if not valid_float(self.text_delta_1):
1056
+ active = False
1057
+ if not valid_float(self.text_dim_2):
1058
+ active = False
1059
+ if not valid_float(self.text_delta_2):
1060
+ active = False
1061
+ if valid_interval_1:
1062
+ minv = float(self.text_min_1.GetValue())
1063
+ maxv = float(self.text_max_1.GetValue())
1064
+ count = self.spin_count_1.GetValue()
1065
+ delta = maxv - minv
1066
+ if count > 1:
1067
+ delta /= count - 1
1068
+ s_unit = ""
1069
+ idx = self.combo_param_1.GetSelection()
1070
+ # 0 = internal_attribute, 1 = secondary_attribute,
1071
+ # 2 = Label, 3 = unit,
1072
+ # 4 = keep_unit, 5 = needs_to_be_positive)
1073
+ if 0 <= idx < len(self.parameters):
1074
+ s_unit = self.parameters[idx][3]
1075
+ self.info_delta_1.SetLabel(
1076
+ _("Every {dist}").format(dist=self.shortened(delta, 3) + s_unit)
1077
+ )
1078
+ else:
1079
+ self.info_delta_1.SetLabel("---")
1080
+ if valid_interval_2:
1081
+ minv = float(self.text_min_2.GetValue())
1082
+ maxv = float(self.text_max_2.GetValue())
1083
+ count = self.spin_count_2.GetValue()
1084
+ delta = maxv - minv
1085
+ if count > 1:
1086
+ delta /= count - 1
1087
+ s_unit = ""
1088
+ idx = self.combo_param_2.GetSelection()
1089
+ # 0 = internal_attribute, 1 = secondary_attribute,
1090
+ # 2 = Label, 3 = unit,
1091
+ # 4 = keep_unit, 5 = needs_to_be_positive)
1092
+ if 0 <= idx < len(self.parameters):
1093
+ s_unit = self.parameters[idx][3]
1094
+ self.info_delta_2.SetLabel(
1095
+ _("Every {dist}").format(dist=self.shortened(delta, 3) + s_unit)
1096
+ )
1097
+ else:
1098
+ self.info_delta_2.SetLabel("---")
1099
+ return active
992
1100
 
1101
+ active = check_for_active()
993
1102
  self.button_create.Enable(active)
994
1103
 
995
1104
  def on_device_update(self):
@@ -1043,8 +1152,38 @@ class TemplatePanel(wx.Panel):
1043
1152
  self.context.elements.clear_operations(fast=True)
1044
1153
  self.context.elements.clear_elements(fast=True)
1045
1154
 
1046
- def create_operations():
1155
+ def create_operations(range1, range2):
1047
1156
  # opchoices = [_("Cut"), _("Engrave"), _("Raster"), _("Image"), _("Hatch")]
1157
+ count_1 = len(range1)
1158
+ count_2 = len(range2)
1159
+ try:
1160
+ dimension_1 = float(self.text_dim_1.GetValue())
1161
+ except ValueError:
1162
+ dimension_1 = -1
1163
+ try:
1164
+ dimension_2 = float(self.text_dim_2.GetValue())
1165
+ except ValueError:
1166
+ dimension_2 = -1
1167
+ if dimension_1 <= 0:
1168
+ dimension_1 = 5
1169
+ if dimension_2 <= 0:
1170
+ dimension_2 = 5
1171
+
1172
+ try:
1173
+ gap_1 = float(self.text_delta_1.GetValue())
1174
+ except ValueError:
1175
+ gap_1 = -1
1176
+ try:
1177
+ gap_2 = float(self.text_delta_2.GetValue())
1178
+ except ValueError:
1179
+ gap_2 = -1
1180
+
1181
+ if gap_1 < 0:
1182
+ gap_1 = 0
1183
+ if gap_2 < 0:
1184
+ gap_2 = 5
1185
+
1186
+ # print (f"Creating operations for {len(range1)} x {len(range2)}")
1048
1187
  display_labels = self.check_labels.GetValue()
1049
1188
  display_values = self.check_values.GetValue()
1050
1189
  color_aspect_1 = max(0, self.combo_color_1.GetSelection())
@@ -1052,8 +1191,6 @@ class TemplatePanel(wx.Panel):
1052
1191
  color_growing_1 = self.check_color_direction_1.GetValue()
1053
1192
  color_growing_2 = self.check_color_direction_2.GetValue()
1054
1193
 
1055
- if optype < 0 or optype > 4:
1056
- return
1057
1194
  if optype == 3:
1058
1195
  shapetype = "image"
1059
1196
  else:
@@ -1090,8 +1227,9 @@ class TemplatePanel(wx.Panel):
1090
1227
  if display_labels:
1091
1228
  text_x = start_x + expected_width / 2
1092
1229
  text_y = start_y - min(float(Length("10mm")), 3 * gap_y)
1093
- node = self.context.elements.elem_branch.add(
1094
- text=f"{param_name_1} [{param_unit_1}]",
1230
+ unit_str = f" [{param_unit_1}]" if param_unit_1 else ""
1231
+ node = element_branch.add(
1232
+ text=f"{param_name_1}{unit_str}",
1095
1233
  matrix=Matrix(
1096
1234
  f"translate({text_x}, {text_y}) scale({2 * max(text_scale_x, text_scale_y) * UNITS_PER_PIXEL})"
1097
1235
  ),
@@ -1103,8 +1241,9 @@ class TemplatePanel(wx.Panel):
1103
1241
 
1104
1242
  text_x = start_x - min(float(Length("10mm")), 3 * gap_x)
1105
1243
  text_y = start_y + expected_height / 2
1106
- node = self.context.elements.elem_branch.add(
1107
- text=f"{param_name_2} [{param_unit_2}]",
1244
+ unit_str = f" [{param_unit_2}]" if param_unit_2 else ""
1245
+ node = element_branch.add(
1246
+ text=f"{param_name_2}{unit_str}",
1108
1247
  matrix=Matrix(
1109
1248
  f"translate({text_x}, {text_y}) scale({2 * max(text_scale_x, text_scale_y) * UNITS_PER_PIXEL})"
1110
1249
  ),
@@ -1116,10 +1255,9 @@ class TemplatePanel(wx.Panel):
1116
1255
  node.modified()
1117
1256
  text_op_y.add_reference(node, 0)
1118
1257
 
1119
- _p_value_1 = min_value_1
1120
-
1121
1258
  xx = start_x
1122
- for idx1 in range(count_1):
1259
+ for idx1, _p_value_1 in enumerate(range1):
1260
+ # print (f"Creating row {idx1} of {len(range1)} with value {_p_value_1}")
1123
1261
  p_value_1 = _p_value_1
1124
1262
  if param_value_type_1 is not None:
1125
1263
  try:
@@ -1127,16 +1265,18 @@ class TemplatePanel(wx.Panel):
1127
1265
  p_value_1 = _pp
1128
1266
  except ValueError:
1129
1267
  pass
1130
- pval1 = self.shortened(p_value_1, 3)
1268
+ if isinstance(p_value_1, str):
1269
+ pval1 = p_value_1
1270
+ else:
1271
+ pval1 = self.shortened(p_value_1, 3)
1131
1272
 
1132
- _p_value_2 = min_value_2
1133
1273
  yy = start_y
1134
1274
 
1135
1275
  if display_values:
1136
1276
  # Add a text above for each column
1137
1277
  text_x = xx + 0.5 * size_x
1138
1278
  text_y = yy - min(float(Length("5mm")), 1.5 * gap_y)
1139
- node = self.context.elements.elem_branch.add(
1279
+ node = element_branch.add(
1140
1280
  text=f"{pval1}",
1141
1281
  matrix=Matrix(
1142
1282
  f"translate({text_x}, {text_y}) scale({text_scale_x * UNITS_PER_PIXEL})"
@@ -1149,7 +1289,8 @@ class TemplatePanel(wx.Panel):
1149
1289
  node.modified()
1150
1290
  text_op_x.add_reference(node, 0)
1151
1291
 
1152
- for idx2 in range(count_2):
1292
+ for idx2, _p_value_2 in enumerate(range2):
1293
+ # print (f"Creating column {idx2} of {len(range2)} with value {_p_value_2}")
1153
1294
  p_value_2 = _p_value_2
1154
1295
  if param_value_type_2 is not None:
1155
1296
  try:
@@ -1157,14 +1298,16 @@ class TemplatePanel(wx.Panel):
1157
1298
  p_value_2 = _pp
1158
1299
  except ValueError:
1159
1300
  pass
1160
-
1161
- pval2 = self.shortened(p_value_2, 3)
1301
+ if isinstance(p_value_2, str):
1302
+ pval2 = p_value_2
1303
+ else:
1304
+ pval2 = self.shortened(p_value_2, 3)
1162
1305
  s_lbl = f"{param_type_1}={pval1}{param_unit_1}"
1163
1306
  s_lbl += f"- {param_type_2}={pval2}{param_unit_2}"
1164
1307
  if display_values and idx1 == 0: # first row, so add a text above
1165
1308
  text_x = xx - min(float(Length("5mm")), 1.5 * gap_x)
1166
1309
  text_y = yy + 0.5 * size_y
1167
- node = self.context.elements.elem_branch.add(
1310
+ node = element_branch.add(
1168
1311
  text=f"{pval2}",
1169
1312
  matrix=Matrix(
1170
1313
  f"translate({text_x}, {text_y}) scale({text_scale_y * UNITS_PER_PIXEL})"
@@ -1198,6 +1341,13 @@ class TemplatePanel(wx.Panel):
1198
1341
 
1199
1342
  # We need to add a hatch node and make this the target for parameter application
1200
1343
  usefill = False
1344
+ elif optype == 5: # Wobble
1345
+ # Wobble is a special case, we need to create a master op and a secondary op
1346
+ # We need to add a wobble node and make this the target for parameter application
1347
+ master_op = copy(self.default_op[optype])
1348
+ this_op = copy(self.secondary_default_op[optype])
1349
+ master_op.add_node(this_op)
1350
+ usefill = False
1201
1351
  else:
1202
1352
  return
1203
1353
  this_op.label = s_lbl
@@ -1279,9 +1429,9 @@ class TemplatePanel(wx.Panel):
1279
1429
 
1280
1430
  set_color = make_color(
1281
1431
  idx1,
1282
- count_1,
1432
+ len(range1),
1283
1433
  idx2,
1284
- count_2,
1434
+ len(range2),
1285
1435
  color_aspect_1,
1286
1436
  color_growing_1,
1287
1437
  color_aspect_2,
@@ -1299,9 +1449,9 @@ class TemplatePanel(wx.Panel):
1299
1449
  elemnode = copy(self.images[idx])
1300
1450
  elemnode.matrix.post_translate(xx, yy)
1301
1451
  elemnode.modified()
1302
- self.context.elements.elem_branch.add_node(elemnode)
1452
+ element_branch.add_node(elemnode)
1303
1453
  elif shapetype == "rect":
1304
- elemnode = self.context.elements.elem_branch.add(
1454
+ elemnode = element_branch.add(
1305
1455
  x=xx,
1306
1456
  y=yy,
1307
1457
  width=size_x,
@@ -1311,7 +1461,7 @@ class TemplatePanel(wx.Panel):
1311
1461
  type="elem rect",
1312
1462
  )
1313
1463
  elif shapetype == "circle":
1314
- elemnode = self.context.elements.elem_branch.add(
1464
+ elemnode = element_branch.add(
1315
1465
  cx=xx + size_x / 2,
1316
1466
  cy=yy + size_y / 2,
1317
1467
  rx=size_x / 2,
@@ -1323,136 +1473,103 @@ class TemplatePanel(wx.Panel):
1323
1473
  if elemnode is not None:
1324
1474
  elemnode.label = s_lbl
1325
1475
  this_op.add_reference(elemnode, 0)
1326
- _p_value_2 += delta_2
1327
1476
  yy = yy + gap_y + size_y
1328
- _p_value_1 += delta_1
1329
1477
  xx = xx + gap_x + size_x
1330
1478
 
1331
1479
  # Read the parameters and user input
1332
1480
  optype = self.combo_ops.GetSelection()
1333
1481
  if optype < 0:
1334
1482
  return
1335
- idx = self.combo_param_1.GetSelection()
1336
- if idx < 0:
1483
+ idx1 = self.combo_param_1.GetSelection()
1484
+ if idx1 < 0:
1337
1485
  return
1338
1486
  # 0 = internal_attribute, 1 = secondary_attribute,
1339
1487
  # 2 = Label, 3 = unit,
1340
1488
  # 4 = keep_unit, 5 = needs_to_be_positive)
1341
- param_name_1 = self.parameters[idx][2]
1342
- param_type_1 = self.parameters[idx][0]
1343
- param_value_type_1 = self.parameters[idx][6]
1344
- param_prepper_1 = self.parameters[idx][1]
1489
+ param_name_1 = self.parameters[idx1][2]
1490
+ param_type_1 = self.parameters[idx1][0]
1491
+ param_value_type_1 = self.parameters[idx1][6]
1492
+ param_prepper_1 = self.parameters[idx1][1]
1345
1493
  if param_prepper_1 == "":
1346
1494
  param_prepper_1 = None
1347
- param_unit_1 = self.parameters[idx][3]
1348
- param_keep_unit_1 = self.parameters[idx][4]
1349
- param_positive_1 = self.parameters[idx][5]
1495
+ param_unit_1 = self.parameters[idx1][3]
1496
+ param_keep_unit_1 = self.parameters[idx1][4]
1350
1497
 
1351
- idx = self.combo_param_2.GetSelection()
1352
- if idx < 0:
1498
+ idx2 = self.combo_param_2.GetSelection()
1499
+ if idx2 < 0:
1353
1500
  return
1354
- param_name_2 = self.parameters[idx][2]
1355
- param_type_2 = self.parameters[idx][0]
1356
- param_value_type_2 = self.parameters[idx][6]
1357
- param_prepper_2 = self.parameters[idx][1]
1501
+ param_name_2 = self.parameters[idx2][2]
1502
+ param_type_2 = self.parameters[idx2][0]
1503
+ param_value_type_2 = self.parameters[idx2][6]
1504
+ param_prepper_2 = self.parameters[idx2][1]
1358
1505
  if param_prepper_2 == "":
1359
1506
  param_prepper_2 = None
1360
- param_unit_2 = self.parameters[idx][3]
1361
- param_keep_unit_2 = self.parameters[idx][4]
1362
- param_positive_2 = self.parameters[idx][5]
1507
+ param_unit_2 = self.parameters[idx2][3]
1508
+ param_keep_unit_2 = self.parameters[idx2][4]
1363
1509
  if param_type_1 == param_type_2:
1364
1510
  return
1365
- if self.text_min_1.GetValue() == "":
1366
- return
1367
- try:
1368
- min_value_1 = float(self.text_min_1.GetValue())
1369
- except ValueError:
1370
- return
1371
- if self.text_min_2.GetValue() == "":
1372
- return
1373
- try:
1374
- min_value_2 = float(self.text_min_2.GetValue())
1375
- except ValueError:
1376
- return
1377
- if self.text_max_1.GetValue() == "":
1378
- return
1379
- try:
1380
- max_value_1 = float(self.text_max_1.GetValue())
1381
- except ValueError:
1382
- return
1383
- if self.text_max_2.GetValue() == "":
1384
- return
1385
- try:
1386
- max_value_2 = float(self.text_max_2.GetValue())
1387
- except ValueError:
1388
- return
1389
1511
 
1390
- if param_unit_1 == "deg":
1391
- min_value_1 = float(self.text_min_1.GetValue())
1392
- max_value_1 = float(self.text_max_1.GetValue())
1393
- elif param_unit_1 == "ppi":
1394
- min_value_1 = max(min_value_1, 0)
1395
- max_value_1 = min(max_value_1, 1000)
1396
- elif param_unit_1 == "%":
1397
- min_value_1 = max(min_value_1, 0)
1398
- max_value_1 = min(max_value_1, 100)
1399
- else:
1400
- # > 0
1401
- if param_positive_1:
1402
- min_value_1 = max(min_value_1, 0)
1403
- max_value_1 = max(max_value_1, 0)
1404
-
1405
- if param_unit_2 == "deg":
1406
- min_value_2 = float(self.text_min_2.GetValue())
1407
- max_value_2 = float(self.text_max_2.GetValue())
1408
- elif param_unit_2 == "ppi":
1409
- min_value_2 = max(min_value_2, 0)
1410
- max_value_2 = min(max_value_2, 1000)
1411
- elif param_unit_2 == "%":
1412
- min_value_2 = max(min_value_2, 0)
1413
- max_value_2 = min(max_value_2, 100)
1414
- else:
1415
- # > 0
1416
- if param_positive_2:
1417
- min_value_2 = max(min_value_2, 0)
1418
- max_value_2 = max(max_value_2, 0)
1419
-
1420
- count_1 = int(self.spin_count_1.GetValue())
1421
- count_2 = int(self.spin_count_2.GetValue())
1422
- if count_1 > 1:
1423
- delta_1 = (max_value_1 - min_value_1) / (count_1 - 1)
1424
- else:
1425
- delta_1 = 0
1426
- if count_2 > 1:
1427
- delta_2 = (max_value_2 - min_value_2) / (count_2 - 1)
1428
- else:
1429
- delta_2 = 0
1430
- try:
1431
- dimension_1 = float(self.text_dim_1.GetValue())
1432
- except ValueError:
1433
- dimension_1 = -1
1434
- try:
1435
- dimension_2 = float(self.text_dim_2.GetValue())
1436
- except ValueError:
1437
- dimension_2 = -1
1438
- if dimension_1 <= 0:
1439
- dimension_1 = 5
1440
- if dimension_2 <= 0:
1441
- dimension_2 = 5
1512
+ def get_range(isx: bool, idx: int) -> list:
1513
+ value_range = []
1514
+ if idx < 0 or idx >= len(self.parameters):
1515
+ return value_range
1516
+ if self.parameters[idx][7] is not None:
1517
+ # Non-standard parameter, so we need to get the checked strings
1518
+ value_range = (
1519
+ self.list_options_1.GetCheckedStrings()
1520
+ if isx
1521
+ else self.list_options_2.GetCheckedStrings()
1522
+ )
1523
+ if not value_range:
1524
+ return []
1525
+ else:
1526
+ param_unit = self.parameters[idx][3]
1527
+ param_positive = self.parameters[idx][5]
1528
+ if isx:
1529
+ text_min = self.text_min_1.GetValue()
1530
+ text_max = self.text_max_1.GetValue()
1531
+ text_count = self.spin_count_1.GetValue()
1532
+ else:
1533
+ text_min = self.text_min_2.GetValue()
1534
+ text_max = self.text_max_2.GetValue()
1535
+ text_count = self.spin_count_2.GetValue()
1536
+ if text_min == "" or text_max == "" or text_count <= 0:
1537
+ return value_range
1538
+ try:
1539
+ min_value = float(text_min)
1540
+ max_value = float(text_max)
1541
+ count = int(text_count)
1542
+ except ValueError:
1543
+ return value_range
1544
+ if param_unit == "deg":
1545
+ min_value = float(text_min)
1546
+ max_value = float(text_max)
1547
+ elif param_unit == "ppi":
1548
+ min_value = max(min_value, 0)
1549
+ max_value = min(max_value, 1000)
1550
+ elif param_unit == "%":
1551
+ min_value = max(min_value, 0)
1552
+ max_value = min(max_value, 100)
1553
+ else:
1554
+ # > 0
1555
+ if param_positive:
1556
+ min_value = max(min_value, 0)
1557
+ max_value = max(max_value, 0)
1558
+ delta = (max_value - min_value) / (count - 1) if count > 1 else 0
1559
+ if delta == 0:
1560
+ value_range = [min_value]
1561
+ else:
1562
+ value_range = [min_value + i * delta for i in range(count)]
1442
1563
 
1443
- try:
1444
- gap_1 = float(self.text_delta_1.GetValue())
1445
- except ValueError:
1446
- gap_1 = -1
1447
- try:
1448
- gap_2 = float(self.text_delta_2.GetValue())
1449
- except ValueError:
1450
- gap_2 = -1
1564
+ return value_range
1565
+
1566
+ valid_range_1 = get_range(True, idx1)
1567
+ valid_range_2 = get_range(False, idx2)
1568
+ # print (valid_range_1)
1569
+ # print (valid_range_2)
1451
1570
 
1452
- if gap_1 < 0:
1453
- gap_1 = 0
1454
- if gap_2 < 0:
1455
- gap_2 = 5
1571
+ if len(valid_range_1) == 0 or len(valid_range_2) == 0:
1572
+ return
1456
1573
 
1457
1574
  message = _("This will delete all existing operations and elements") + "\n"
1458
1575
  message += (
@@ -1473,7 +1590,7 @@ class TemplatePanel(wx.Panel):
1473
1590
  elif result == wx.ID_CANCEL:
1474
1591
  return
1475
1592
 
1476
- create_operations()
1593
+ create_operations(range1=valid_range_1, range2=valid_range_2)
1477
1594
 
1478
1595
  self.context.signal("rebuild_tree")
1479
1596
  self.context.signal("refresh_scene", "Scene")
@@ -1499,6 +1616,8 @@ class TemplatePanel(wx.Panel):
1499
1616
  self.context.setting(int, "template_color2", 2)
1500
1617
  self.context.setting(bool, "template_coldir1", False)
1501
1618
  self.context.setting(bool, "template_coldir2", False)
1619
+ self.context.setting(str, "template_list1", "")
1620
+ self.context.setting(str, "template_list2", "")
1502
1621
 
1503
1622
  def _set_settings(self, templatename):
1504
1623
  info_field = (
@@ -1521,6 +1640,8 @@ class TemplatePanel(wx.Panel):
1521
1640
  self.context.template_color2,
1522
1641
  self.context.template_coldir1,
1523
1642
  self.context.template_coldir2,
1643
+ self.context.template_list1,
1644
+ self.context.template_list2,
1524
1645
  )
1525
1646
  # print (f"Save data to {templatename}, infofield-len={len(info_field)}")
1526
1647
  key = f"{templatename}"
@@ -1533,20 +1654,27 @@ class TemplatePanel(wx.Panel):
1533
1654
  if (
1534
1655
  info_field is not None
1535
1656
  and isinstance(info_field, (tuple, list))
1536
- and len(info_field) == 19
1657
+ and len(info_field) >= 19
1537
1658
  ):
1659
+
1660
+ def get_setting(idx, default):
1661
+ try:
1662
+ return info_field[idx]
1663
+ except IndexError:
1664
+ return default
1665
+
1538
1666
  # print (f"Load data from {templatename}")
1539
- self.context.template_show_values = info_field[0]
1540
- self.context.template_show_labels = info_field[1]
1667
+ self.context.template_show_values = get_setting(0, True)
1668
+ self.context.template_show_labels = get_setting(1, True)
1541
1669
  self.context.template_optype = info_field[2]
1542
1670
  self.context.template_param1 = info_field[3]
1543
1671
  self.context.template_param2 = info_field[4]
1544
- self.context.template_min1 = info_field[5]
1545
- self.context.template_max1 = info_field[6]
1546
- self.context.template_min2 = info_field[7]
1547
- self.context.template_max2 = info_field[8]
1548
- self.context.template_count1 = info_field[9]
1549
- self.context.template_count2 = info_field[10]
1672
+ self.context.template_min1 = get_setting(5, 0)
1673
+ self.context.template_max1 = get_setting(6, 100)
1674
+ self.context.template_min2 = get_setting(7, 0)
1675
+ self.context.template_max2 = get_setting(8, 100)
1676
+ self.context.template_count1 = get_setting(9, 5)
1677
+ self.context.template_count2 = get_setting(10, 5)
1550
1678
  self.context.template_dim_1 = info_field[11]
1551
1679
  self.context.template_dim_2 = info_field[12]
1552
1680
  self.context.template_gap_1 = info_field[13]
@@ -1555,6 +1683,8 @@ class TemplatePanel(wx.Panel):
1555
1683
  self.context.template_color2 = info_field[16]
1556
1684
  self.context.template_coldir1 = info_field[17]
1557
1685
  self.context.template_coldir2 = info_field[18]
1686
+ self.context.template_list1 = get_setting(19, "")
1687
+ self.context.template_list2 = get_setting(20, "")
1558
1688
 
1559
1689
  def save_settings(self, templatename=None):
1560
1690
  self.context.template_show_values = self.check_values.GetValue()
@@ -1576,6 +1706,8 @@ class TemplatePanel(wx.Panel):
1576
1706
  self.context.template_color2 = self.combo_color_2.GetSelection()
1577
1707
  self.context.template_coldir1 = self.check_color_direction_1.GetValue()
1578
1708
  self.context.template_coldir2 = self.check_color_direction_2.GetValue()
1709
+ self.context.template_list1 = "|".join(self.list_options_1.GetCheckedStrings())
1710
+ self.context.template_list2 = "|".join(self.list_options_2.GetCheckedStrings())
1579
1711
  if templatename:
1580
1712
  # let's try to restore the settings
1581
1713
  self._set_settings(templatename)
@@ -1614,6 +1746,12 @@ class TemplatePanel(wx.Panel):
1614
1746
  self.text_dim_2.SetValue(self.context.template_dim_2)
1615
1747
  self.text_delta_1.SetValue(self.context.template_gap_1)
1616
1748
  self.text_delta_2.SetValue(self.context.template_gap_2)
1749
+ self.list_options_1.SetCheckedStrings(
1750
+ self.context.template_list1.split("|")
1751
+ )
1752
+ self.list_options_2.SetCheckedStrings(
1753
+ self.context.template_list2.split("|")
1754
+ )
1617
1755
  except (AttributeError, ValueError):
1618
1756
  pass
1619
1757
 
@@ -1649,7 +1787,6 @@ class TemplateTool(MWindow):
1649
1787
  self.storage.read_configuration()
1650
1788
  self.panel_instances = []
1651
1789
  self.primary_prop_panels = []
1652
- self.secondary_prop_panels = []
1653
1790
  self.panel_template = TemplatePanel(
1654
1791
  self,
1655
1792
  wx.ID_ANY,
@@ -1683,7 +1820,6 @@ class TemplateTool(MWindow):
1683
1820
  self.notebook_main.AddPage(self.panel_template, _("Generator"))
1684
1821
 
1685
1822
  self.panel_template.set_callback(self.set_node)
1686
- self.panel_template.set_secondary_callback(self.set_secondary_node)
1687
1823
  self.add_module_delegate(self.panel_template)
1688
1824
 
1689
1825
  self.notebook_main.AddPage(self.panel_saveload, _("Templates"))
@@ -1721,7 +1857,7 @@ class TemplateTool(MWindow):
1721
1857
 
1722
1858
  return None
1723
1859
 
1724
- def set_node(self, node):
1860
+ def set_node(self, primary_node, secondary_node=None):
1725
1861
  def sort_priority(prop):
1726
1862
  prop_sheet, node = prop
1727
1863
  return (
@@ -1730,25 +1866,26 @@ class TemplateTool(MWindow):
1730
1866
  else 0
1731
1867
  )
1732
1868
 
1733
- if node is None:
1869
+ if primary_node is None:
1734
1870
  return
1735
1871
  busy = wx.BusyCursor()
1736
1872
  self.Freeze()
1737
- pages_to_instance = []
1738
- self.primary_prop_panels = []
1739
- found = False
1873
+ primary_panels = []
1874
+ secondary_panels = []
1740
1875
  for property_sheet in self.context.lookup_all(
1741
- f"property/{node.__class__.__name__}/.*"
1876
+ f"property/{primary_node.__class__.__name__}/.*"
1742
1877
  ):
1743
- if not hasattr(property_sheet, "accepts") or property_sheet.accepts(node):
1744
- self.primary_prop_panels.append((property_sheet, node))
1745
- found = True
1878
+ if not hasattr(property_sheet, "accepts") or property_sheet.accepts(
1879
+ primary_node
1880
+ ):
1881
+ primary_panels.append((property_sheet, primary_node))
1882
+ found = len(primary_panels) > 0
1746
1883
  # If we did not have any hits and the node is a reference
1747
1884
  # then we fall back to the master. So if in the future we
1748
1885
  # would have a property panel dealing with reference-nodes
1749
1886
  # then this would no longer apply.
1750
- if node.type == "reference" and not found:
1751
- snode = node.node
1887
+ if primary_node.type == "reference" and not found:
1888
+ snode = primary_node.node
1752
1889
  found = False
1753
1890
  for property_sheet in self.context.lookup_all(
1754
1891
  f"property/{snode.__class__.__name__}/.*"
@@ -1756,94 +1893,19 @@ class TemplateTool(MWindow):
1756
1893
  if not hasattr(property_sheet, "accepts") or property_sheet.accepts(
1757
1894
  snode
1758
1895
  ):
1759
- self.primary_prop_panels.append((property_sheet, snode))
1760
- found = True
1761
-
1762
- self.primary_prop_panels.sort(key=sort_priority, reverse=True)
1763
- pages_to_instance.extend(self.primary_prop_panels)
1764
- pages_to_instance.extend(self.secondary_prop_panels)
1765
-
1766
- for p in self.panel_instances:
1767
- try:
1768
- p.pane_hide()
1769
- except AttributeError:
1770
- pass
1771
- self.remove_module_delegate(p)
1772
-
1773
- # Delete all but the first and last page...
1774
- while self.notebook_main.GetPageCount() > 2:
1775
- self.notebook_main.DeletePage(1)
1776
- for prop_sheet, instance in pages_to_instance:
1777
- page_panel = prop_sheet(
1778
- self.notebook_main, wx.ID_ANY, context=self.context, node=instance
1779
- )
1780
- try:
1781
- name = prop_sheet.name
1782
- except AttributeError:
1783
- name = instance.__class__.__name__
1784
-
1785
- self.notebook_main.InsertPage(1, page_panel, _(name))
1786
- try:
1787
- page_panel.set_widgets(instance)
1788
- except AttributeError:
1789
- pass
1790
- self.add_module_delegate(page_panel)
1791
- self.panel_instances.append(page_panel)
1792
- try:
1793
- page_panel.pane_show()
1794
- except AttributeError:
1795
- pass
1796
- page_panel.Layout()
1797
- try:
1798
- page_panel.SetupScrolling()
1799
- except AttributeError:
1800
- pass
1801
-
1802
- self.Layout()
1803
- self.Thaw()
1804
- del busy
1805
-
1806
- def set_secondary_node(self, node):
1807
- def sort_priority(prop):
1808
- prop_sheet, node = prop
1809
- return (
1810
- getattr(prop_sheet, "priority")
1811
- if hasattr(prop_sheet, "priority")
1812
- else 0
1813
- )
1814
-
1815
- if node is None:
1816
- return
1817
- busy = wx.BusyCursor()
1818
- self.Freeze()
1819
- pages_to_instance = []
1820
- self.secondary_prop_panels = []
1821
- found = False
1822
- for property_sheet in self.context.lookup_all(
1823
- f"property/{node.__class__.__name__}/.*"
1824
- ):
1825
- if not hasattr(property_sheet, "accepts") or property_sheet.accepts(node):
1826
- self.secondary_prop_panels.append((property_sheet, node))
1827
- found = True
1828
- # If we did not have any hits and the node is a reference
1829
- # then we fall back to the master. So if in the future we
1830
- # would have a property panel dealing with reference-nodes
1831
- # then this would no longer apply.
1832
- if node.type == "reference" and not found:
1833
- snode = node.node
1834
- found = False
1896
+ primary_panels.append((property_sheet, snode))
1897
+ if secondary_node is not None:
1835
1898
  for property_sheet in self.context.lookup_all(
1836
- f"property/{snode.__class__.__name__}/.*"
1899
+ f"property/{secondary_node.__class__.__name__}/.*"
1837
1900
  ):
1838
1901
  if not hasattr(property_sheet, "accepts") or property_sheet.accepts(
1839
- snode
1902
+ secondary_node
1840
1903
  ):
1841
- self.secondary_prop_panels.append((property_sheet, snode))
1842
- found = True
1904
+ secondary_panels.append((property_sheet, secondary_node))
1843
1905
 
1844
- self.secondary_prop_panels.sort(key=sort_priority, reverse=True)
1845
- pages_to_instance.extend(self.primary_prop_panels)
1846
- pages_to_instance.extend(self.secondary_prop_panels)
1906
+ primary_panels.sort(key=sort_priority, reverse=True)
1907
+ secondary_panels.sort(key=sort_priority, reverse=True)
1908
+ pages_to_instance = primary_panels + secondary_panels
1847
1909
 
1848
1910
  for p in self.panel_instances:
1849
1911
  try:
@@ -1851,10 +1913,15 @@ class TemplateTool(MWindow):
1851
1913
  except AttributeError:
1852
1914
  pass
1853
1915
  self.remove_module_delegate(p)
1916
+ self.panel_instances.clear()
1854
1917
 
1855
1918
  # Delete all but the first and last page...
1856
1919
  while self.notebook_main.GetPageCount() > 2:
1857
1920
  self.notebook_main.DeletePage(1)
1921
+ # print(
1922
+ # f"Adding {len(pages_to_instance)} pages to the notebook, remaining {self.notebook_main.GetPageCount()} pages: content={self.notebook_main.GetPageText(0)} and {self.notebook_main.GetPageText(1)}"
1923
+ # )
1924
+ # Add the primary property panels
1858
1925
  for prop_sheet, instance in pages_to_instance:
1859
1926
  page_panel = prop_sheet(
1860
1927
  self.notebook_main, wx.ID_ANY, context=self.context, node=instance
@@ -1883,6 +1950,8 @@ class TemplateTool(MWindow):
1883
1950
 
1884
1951
  self.Layout()
1885
1952
  self.Thaw()
1953
+ self.notebook_main.SetSelection(1)
1954
+ self.notebook_main.SetSelection(0)
1886
1955
  del busy
1887
1956
 
1888
1957
  def window_open(self):