preset-related fixes (#3931)

* fix manually clicking pencil icon
* update choices when loading presets
* ignore hidden and disabled params when applying and creating presets
* mark selection param changed when a dependent param is changed
* don't immediately apply when clicking 'Use Last Settings'
* define on_change_hook in __init__
* make adding, updating, and deleting presets clearer
* only skip satin param for strokes thinner than 0.3mm when they have only one subpath
pull/3944/head dev-build-kaalleen-stroke-to-satin-start
Lex Neva 2025-08-30 02:33:24 -04:00 zatwierdzone przez GitHub
rodzic 28eaecabf2
commit d22f9d86f4
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
2 zmienionych plików z 83 dodań i 43 usunięć

Wyświetl plik

@ -16,6 +16,7 @@ import wx
from wx.lib.scrolledpanel import ScrolledPanel
from ..commands import is_command, is_command_symbol
from ..debug.debug import debug
from ..elements import (Clone, EmbroideryElement, FillStitch, SatinColumn,
Stroke)
from ..elements.clone import is_clone
@ -52,11 +53,14 @@ class ParamsTab(ScrolledPanel):
self.changed_inputs = set()
self.dependent_tabs = []
self.parent_tab = None
self.param_inputs = {}
self.param_name_to_input = {}
self.input_to_param_name = {}
self.param_name_to_param = {param.name: param for param in self.params}
self.choice_widgets = defaultdict(list)
self.dict_of_choices = {}
self.paired_tab = None
self.disable_notify_pair = False
self.on_change_hook = None
toggles = [param for param in self.params if param.type == 'toggle']
@ -75,7 +79,7 @@ class ParamsTab(ScrolledPanel):
wx.EVT_CHECKBOX, self.update_toggle_state)
self.toggle_checkbox.Bind(wx.EVT_CHECKBOX, self.changed)
self.param_inputs[self.toggle.name] = self.toggle_checkbox
self.param_name_to_input[self.toggle.name] = self.toggle_checkbox
else:
self.toggle = None
@ -105,8 +109,7 @@ class ParamsTab(ScrolledPanel):
# So let's add the satin column param to the list of changed_inputs right away - even when they didn't actively
# change it
if self.toggle and self.toggle.name == 'satin_column':
self.enable_change_indicator(self.toggle.name)
self.changed_inputs.add(self.toggle_checkbox)
self.param_changed(self.toggle.name)
self.update_enable_widgets()
@ -153,9 +156,9 @@ class ParamsTab(ScrolledPanel):
else:
selection = input.GetSelection()
param = self.inputs_to_params[input]
param_name = self.input_to_param_name[input]
self.update_choice_widgets((param, selection))
self.update_choice_widgets((param_name, selection))
self.settings_grid.Layout()
self.Fit()
self.Layout()
@ -196,7 +199,7 @@ class ParamsTab(ScrolledPanel):
def set_toggle_state(self, value):
if self.toggle_checkbox:
self.toggle_checkbox.SetValue(value)
self.changed_inputs.add(self.toggle_checkbox)
self.param_changed(self.toggle.name)
def get_values(self):
values = {}
@ -214,24 +217,25 @@ class ParamsTab(ScrolledPanel):
# because they're grayed out anyway.
return values
for name, input in self.param_inputs.items():
for name, input in self.param_name_to_input.items():
if input in self.changed_inputs and input != self.toggle_checkbox:
# there are two types of combo boxes:
# 1. multiple values for the same param on selected elements - 2. param type
# multiple values will be handled with the GetValue() method
if name in self.dict_of_choices and self.dict_of_choices[name]['param'].type == 'combo':
values[name] = input.GetClientData(input.GetSelection()).id
elif isinstance(input, wx.Choice):
values[name] = input.GetSelection()
else:
values[name] = input.GetValue()
if input.IsEnabled() and input.IsShown():
# there are two types of combo boxes:
# 1. multiple values for the same param on selected elements - 2. param type
# multiple values will be handled with the GetValue() method
if name in self.dict_of_choices and self.dict_of_choices[name]['param'].type == 'combo':
values[name] = input.GetClientData(input.GetSelection()).id
elif isinstance(input, wx.Choice):
values[name] = input.GetSelection()
else:
values[name] = input.GetValue()
return values
def on_reroll(self, event):
if len(self.nodes) == 1:
new_seed = str(randbelow(int(1e8)))
input = self.param_inputs['random_seed']
input = self.param_name_to_input['random_seed']
input.SetValue(new_seed)
self.changed_inputs.add(input)
else:
@ -247,7 +251,8 @@ class ParamsTab(ScrolledPanel):
def apply(self):
values = self.get_values()
for node in self.nodes:
if "satin_column" in values.keys() and values["satin_column"] is True and node.stroke_width < 0.3 * PIXELS_PER_MM:
if ("satin_column" in values.keys() and values["satin_column"] is True and
len(node.paths) == 1 and node.stroke_width < 0.3 * PIXELS_PER_MM):
# when we apply satin columns, strokes (running stitches) are not rendered in the simulator
# and we also don't want to set any of the chosen values to these elements as this may lead to unexpected rendering results
continue
@ -259,35 +264,61 @@ class ParamsTab(ScrolledPanel):
def changed(self, event):
input = event.GetEventObject()
self.changed_inputs.add(input)
param = self.inputs_to_params[input]
self.enable_change_indicator(param)
param_name = self.input_to_param_name[input]
self.param_changed(param_name)
event.Skip()
def param_changed(self, param_name):
param = self.param_name_to_param[param_name]
input = self.param_name_to_input[param_name]
self.changed_inputs.add(input)
self.enable_change_indicator(param_name)
# If they change a param enabled by a parent param, then we should
# consider the parent param changed too. This ensures that all
# selected embroidery elements get the effect of this param applied.
# For example, if they change the meander pattern, we should ensure
# that we're setting the fill type to meander on all selected elements.
debug.log(f"param_changed(): checking for parent params of {param.name} with selecT_items {param.select_items}")
for p in self.params:
if p.enables is not None:
if param.name in p.enables:
self.param_changed(p.name)
if param.select_items:
for choice_name, choice_value in param.select_items:
debug.log(f"forcing changed on parent select item: {choice_name}")
self.param_changed(choice_name)
if self.on_change_hook:
self.on_change_hook(self)
def load_preset(self, preset):
preset_data = preset.get(self.name, {})
# print(self.param_inputs, '\n\n', preset_data.items(), file=sys.stderr)
for name, value in preset_data.items():
if name in self.param_inputs:
if name in self.param_name_to_input:
if name in self.dict_of_choices and self.dict_of_choices[name]['param'].type == 'combo':
param = self.dict_of_choices[name]["param"]
self.param_inputs[name].SetSelection(self.get_combo_value_index(value, param.options, param.default))
elif isinstance(self.param_inputs[name], wx.Choice):
self.param_inputs[name].SetSelection(int(value))
self.param_name_to_input[name].SetSelection(self.get_combo_value_index(value, param.options, param.default))
elif isinstance(self.param_name_to_input[name], wx.Choice):
self.param_name_to_input[name].SetSelection(int(value))
else:
input = self.param_inputs[name]
input = self.param_name_to_input[name]
if name == "satin_column" and input.Label == _('Running stitch along paths'):
value = not value
input.SetValue(value)
self.changed_inputs.add(self.param_inputs[name])
self.changed_inputs.add(self.param_name_to_input[name])
self.enable_change_indicator(name)
self.update_toggle_state()
self.update_enable_widgets()
self.update_choice_widgets()
self.settings_grid.Layout()
self.Fit()
self.Layout()
def save_preset(self, storage):
storage[self.name] = self.get_values()
@ -371,9 +402,9 @@ class ParamsTab(ScrolledPanel):
if event is None:
for param in self.params:
if param.enables is not None:
value = self.param_inputs[param.name].GetValue()
value = self.param_name_to_input[param.name].GetValue()
for item in param.enables:
enable_input = self.param_inputs[item]
enable_input = self.param_name_to_input[item]
enable_input.Enable(value)
enable_input.GetPrevSibling().Enable(value)
else:
@ -385,7 +416,7 @@ class ParamsTab(ScrolledPanel):
if param.enables is not None:
value = input.GetValue()
for item in param.enables:
enable_input = self.param_inputs[item]
enable_input = self.param_name_to_input[item]
enable_input.Enable(value)
enable_input.GetPrevSibling().Enable(value)
@ -472,7 +503,7 @@ class ParamsTab(ScrolledPanel):
input = wx.TextCtrl(self, wx.ID_ANY, value=str(value))
input.Bind(wx.EVT_TEXT, self.changed)
self.param_inputs[param.name] = input
self.param_name_to_input[param.name] = input
if param.type == 'random_seed':
col4 = wx.Button(self, wx.ID_ANY, _("Re-roll"))
@ -490,7 +521,7 @@ class ParamsTab(ScrolledPanel):
self.settings_grid.Add(input, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.EXPAND, border=10)
self.settings_grid.Add(col4, flag=wx.ALIGN_CENTER_VERTICAL)
self.inputs_to_params = {v: k for k, v in self.param_inputs.items()}
self.input_to_param_name.update({v: k for k, v in self.param_name_to_input.items()})
box.Add(self.settings_grid, proportion=1, flag=wx.ALL | wx.EXPAND, border=10)
@ -500,20 +531,20 @@ class ParamsTab(ScrolledPanel):
self.Layout()
def create_change_indicator(self, param):
def create_change_indicator(self, param_name):
indicator = wx.Button(self, style=wx.BORDER_NONE |
wx.BU_NOTEXT, size=(28, 28))
indicator.SetToolTip(
_('Click to force this parameter to be saved when you click "Apply and Quit"'))
indicator.Bind(
wx.EVT_BUTTON, lambda event: self.enable_change_indicator(param))
wx.EVT_BUTTON, lambda event: self.param_changed(param_name))
self.param_change_indicators[param] = indicator
self.param_change_indicators[param_name] = indicator
return indicator
def enable_change_indicator(self, param):
self.param_change_indicators[param].SetBitmapLabel(self.pencil_icon)
self.param_change_indicators[param].SetToolTip(
def enable_change_indicator(self, param_name):
self.param_change_indicators[param_name].SetBitmapLabel(self.pencil_icon)
self.param_change_indicators[param_name].SetToolTip(
_('This parameter will be saved when you click "Apply and Quit"'))
# end of class SatinPane
@ -672,7 +703,6 @@ class SettingsPanel(wx.Panel):
def use_last(self, event):
self.presets_panel.load_preset("__LAST__")
self.apply(event)
def close(self):
self.simulator.stop()

Wyświetl plik

@ -102,9 +102,12 @@ class PresetsPanel(wx.Panel):
json.dump(presets, presets_file)
def update_preset_list(self):
current_preset = self.preset_chooser.GetValue().strip()
preset_names = list(self._load_presets().keys())
preset_names = [preset for preset in preset_names if not self.is_hidden(preset)]
self.preset_chooser.SetItems(sorted(preset_names))
if current_preset in preset_names:
self.preset_chooser.SetValue(current_preset)
def is_hidden(self, preset_name):
return self.HIDDEN_PRESET_RE.match(preset_name)
@ -141,6 +144,11 @@ class PresetsPanel(wx.Panel):
self.store_preset(preset_name, self.parent.get_preset_data())
if overwrite:
info_dialog(self, _('Preset "%s" updated.') % preset_name)
else:
info_dialog(self, _('Preset "%s" added.') % preset_name)
event.Skip()
def overwrite_preset(self, event):
@ -178,4 +186,6 @@ class PresetsPanel(wx.Panel):
self.update_preset_list()
self.preset_chooser.SetValue("")
info_dialog(self, _('Preset "%s" deleted.') % preset_name)
event.Skip()