From 3863cbaee7303d13f8ed5300c78b60b4fca42352 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Wed, 16 Oct 2024 18:00:20 +0500 Subject: [PATCH] Add a preference to share options between tools (#1120) * Add share config button * fill parameter now saves with curve tool * rename _fill to _fill_inside for sync consistency (fill in pencil and shape tools basically represent the same thing) * add icon * Move the option to the preferences * Add string to Translations.pot * Re-introduce `is_syncing` --------- Co-authored-by: Emmanouil Papadeas <35376950+OverloadedOrama@users.noreply.github.com> --- Translations/Translations.pot | 4 ++ src/Autoload/Global.gd | 4 ++ src/Autoload/Tools.gd | 40 ++++++++++++ src/Preferences/PreferencesDialog.gd | 10 ++- src/Preferences/PreferencesDialog.tscn | 63 +++++++++++++------ src/Tools/BaseDraw.gd | 30 ++++++--- src/Tools/BaseShapeDrawer.gd | 12 ++-- src/Tools/BaseTool.gd | 3 + src/Tools/DesignTools/CurveTool.gd | 9 ++- src/Tools/DesignTools/Pencil.gd | 5 +- .../GlobalToolOptions/GlobalToolOptions.tscn | 2 + 11 files changed, 141 insertions(+), 41 deletions(-) diff --git a/Translations/Translations.pot b/Translations/Translations.pot index bc63b953c..561aae0a7 100644 --- a/Translations/Translations.pot +++ b/Translations/Translations.pot @@ -898,6 +898,10 @@ msgstr "" msgid "Background color:" msgstr "" +#. Found in the preferences, under the Tools category. +msgid "Share options between the left and the right tools" +msgstr "" + msgid "Left tool color:" msgstr "" diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index 46f430172..5d89cdb28 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -276,6 +276,10 @@ var tool_button_size := ButtonSize.SMALL: return tool_button_size = value Tools.set_button_size(tool_button_size) +var share_options_between_tools := false: + set(value): + share_options_between_tools = value + Tools.attempt_config_share(MOUSE_BUTTON_LEFT) ## Found in Preferences. The left tool color. var left_tool_color := Color("0086cf"): set(value): diff --git a/src/Autoload/Tools.gd b/src/Autoload/Tools.gd index 3615c2cad..b236f3d7a 100644 --- a/src/Autoload/Tools.gd +++ b/src/Autoload/Tools.gd @@ -2,6 +2,8 @@ extends Node signal color_changed(color: Color, button: int) +signal config_changed(slot_idx: int, config: Dictionary) +@warning_ignore("unused_signal") signal flip_rotated(flip_x, flip_y, rotate_90, rotate_180, rotate_270) signal options_reset @@ -373,6 +375,34 @@ func _ready() -> void: _show_relevant_tools(layer_type) +## Syncs the other tool using the config of tool located at [param from_idx].[br] +## NOTE: For optimization, if there is already a ready made config available, then we will use that +## instead of re-calculating the config, else we have no choice but to re-generate it +func attempt_config_share(from_idx: int, config: Dictionary = {}) -> void: + if not Global.share_options_between_tools: + return + if _slots.is_empty(): + return + if config.is_empty() and _slots[from_idx]: + var from_slot: Slot = _slots.get(from_idx, null) + if from_slot: + var from_tool = from_slot.tool_node + if from_tool.has_method("get_config"): + config = from_tool.get_config() + var target_slot: Slot = _slots.get(MOUSE_BUTTON_LEFT, null) + if from_idx == MOUSE_BUTTON_LEFT: + target_slot = _slots.get(MOUSE_BUTTON_RIGHT, null) + if is_instance_valid(target_slot): + if ( + target_slot.tool_node.has_method("set_config") + and target_slot.tool_node.has_method("update_config") + ): + target_slot.tool_node.set("is_syncing", true) + target_slot.tool_node.set_config(config) + target_slot.tool_node.update_config() + target_slot.tool_node.set("is_syncing", false) + + func reset_options() -> void: default_color() assign_tool(get_tool(MOUSE_BUTTON_LEFT).tool_node.name, MOUSE_BUTTON_LEFT, true) @@ -401,9 +431,13 @@ func remove_tool(t: Tool) -> void: func set_tool(tool_name: String, button: int) -> void: + # To prevent any unintentional syncing, we will temporarily disconnect the signal + if config_changed.is_connected(attempt_config_share): + config_changed.disconnect(attempt_config_share) var slot: Slot = _slots[button] var panel: Node = _panels[button] var node: Node = tools[tool_name].instantiate_scene() + var config_slot := MOUSE_BUTTON_LEFT if button == MOUSE_BUTTON_RIGHT else MOUSE_BUTTON_RIGHT if button == MOUSE_BUTTON_LEFT: # As guides are only moved with left mouse if tool_name == "Pan": # tool you want to give more access at guides Global.move_guides_on_canvas = true @@ -422,6 +456,12 @@ func set_tool(tool_name: String, button: int) -> void: elif button == MOUSE_BUTTON_RIGHT: _right_tools_per_layer_type[_curr_layer_type] = tool_name + # Wait for config to get loaded, then re-connect and sync + await get_tree().process_frame + if not config_changed.is_connected(attempt_config_share): + config_changed.connect(attempt_config_share) + attempt_config_share(config_slot) # Sync it with the other tool + func get_tool(button: int) -> Slot: return _slots[button] diff --git a/src/Preferences/PreferencesDialog.gd b/src/Preferences/PreferencesDialog.gd index 1d96dcdee..074cdc7b6 100644 --- a/src/Preferences/PreferencesDialog.gd +++ b/src/Preferences/PreferencesDialog.gd @@ -36,10 +36,16 @@ var preferences: Array[Preference] = [ "custom_icon_color", "Interface/ButtonOptions/IconColorButton", "color", Color.GRAY ), Preference.new( - "left_tool_color", "Interface/ButtonOptions/LeftToolColorButton", "color", Color("0086cf") + "share_options_between_tools", + "Tools/ToolOptions/ShareOptionsCheckBox", + "button_pressed", + false ), Preference.new( - "right_tool_color", "Interface/ButtonOptions/RightToolColorButton", "color", Color("fd6d14") + "left_tool_color", "Tools/ToolOptions/LeftToolColorButton", "color", Color("0086cf") + ), + Preference.new( + "right_tool_color", "Tools/ToolOptions/RightToolColorButton", "color", Color("fd6d14") ), Preference.new( "tool_button_size", diff --git a/src/Preferences/PreferencesDialog.tscn b/src/Preferences/PreferencesDialog.tscn index d7092aae4..f252a4533 100644 --- a/src/Preferences/PreferencesDialog.tscn +++ b/src/Preferences/PreferencesDialog.tscn @@ -324,26 +324,6 @@ layout_mode = 2 mouse_default_cursor_shape = 2 color = Color(0.75, 0.75, 0.75, 1) -[node name="Label4" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/ButtonOptions"] -layout_mode = 2 -text = "Left tool color:" - -[node name="LeftToolColorButton" type="ColorPickerButton" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/ButtonOptions"] -custom_minimum_size = Vector2(64, 20) -layout_mode = 2 -mouse_default_cursor_shape = 2 -color = Color(0, 0.52549, 0.811765, 1) - -[node name="Label5" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/ButtonOptions"] -layout_mode = 2 -text = "Right tool color:" - -[node name="RightToolColorButton" type="ColorPickerButton" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/ButtonOptions"] -custom_minimum_size = Vector2(64, 20) -layout_mode = 2 -mouse_default_cursor_shape = 2 -color = Color(0.992157, 0.427451, 0.0784314, 1) - [node name="Canvas" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide"] visible = false layout_mode = 2 @@ -875,6 +855,49 @@ layout_mode = 2 mouse_default_cursor_shape = 2 color = Color(0, 0, 1, 1) +[node name="Tools" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide"] +visible = false +layout_mode = 2 + +[node name="ToolOptions" type="GridContainer" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Tools"] +layout_mode = 2 +columns = 3 + +[node name="ShareOptionsLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Tools/ToolOptions"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Share options between the left and the right tools" + +[node name="ShareOptionsCheckBox" type="CheckBox" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Tools/ToolOptions"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_default_cursor_shape = 2 +text = "On" + +[node name="LeftToolColorLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Tools/ToolOptions"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Left tool color:" + +[node name="LeftToolColorButton" type="ColorPickerButton" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Tools/ToolOptions"] +custom_minimum_size = Vector2(64, 20) +layout_mode = 2 +size_flags_horizontal = 3 +mouse_default_cursor_shape = 2 +color = Color(0, 0.52549, 0.811765, 1) + +[node name="RightToolColorLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Tools/ToolOptions"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Right tool color:" + +[node name="RightToolColorButton" type="ColorPickerButton" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Tools/ToolOptions"] +custom_minimum_size = Vector2(64, 20) +layout_mode = 2 +size_flags_horizontal = 3 +mouse_default_cursor_shape = 2 +color = Color(0.992157, 0.427451, 0.0784314, 1) + [node name="Selection" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide"] visible = false layout_mode = 2 diff --git a/src/Tools/BaseDraw.gd b/src/Tools/BaseDraw.gd index bfcadbe3c..be429d31a 100644 --- a/src/Tools/BaseDraw.gd +++ b/src/Tools/BaseDraw.gd @@ -71,14 +71,13 @@ func _on_Brush_selected(brush: Brushes.Brush) -> void: func _on_BrushSize_value_changed(value: float) -> void: - if _brush_size != int(value): - _brush_size = int(value) - _brush_size_dynamics = _brush_size - if Tools.dynamics_size != Tools.Dynamics.NONE: - _brush_size_dynamics = Tools.brush_size_min - _cache_limit = (_brush_size * _brush_size) * 3 # This equation seems the best match - update_config() - save_config() + _brush_size = int(value) + _brush_size_dynamics = _brush_size + if Tools.dynamics_size != Tools.Dynamics.NONE: + _brush_size_dynamics = Tools.brush_size_min + _cache_limit = (_brush_size * _brush_size) * 3 # This equation seems the best match + update_config() + save_config() func _reset_dynamics() -> void: @@ -113,6 +112,11 @@ func get_config() -> Dictionary: "brush_index": _brush.index, "brush_size": _brush_size, "brush_interpolate": _brush_interpolate, + "brush_flip_x": _brush_flip_x, + "brush_flip_y": _brush_flip_y, + "brush_rotate_90": _brush_rotate_90, + "brush_rotate_180": _brush_rotate_180, + "brush_rotate_270": _brush_rotate_270, } @@ -125,6 +129,11 @@ func set_config(config: Dictionary) -> void: if Tools.dynamics_size != Tools.Dynamics.NONE: _brush_size_dynamics = Tools.brush_size_min _brush_interpolate = config.get("brush_interpolate", _brush_interpolate) + _brush_flip_x = config.get("brush_flip_x", _brush_flip_x) + _brush_flip_y = config.get("brush_flip_y", _brush_flip_y) + _brush_rotate_90 = config.get("brush_rotate_90", _brush_rotate_90) + _brush_rotate_180 = config.get("brush_rotate_180", _brush_rotate_180) + _brush_rotate_270 = config.get("brush_rotate_270", _brush_rotate_270) func update_config() -> void: @@ -743,23 +752,28 @@ func _pick_color(pos: Vector2i) -> void: func _on_flip_x_toggled(button_pressed: bool) -> void: _brush_flip_x = button_pressed update_brush() + save_config() func _on_flip_y_toggled(button_pressed: bool) -> void: _brush_flip_y = button_pressed update_brush() + save_config() func _on_rotate_90_toggled(button_pressed: bool) -> void: _brush_rotate_90 = button_pressed update_brush() + save_config() func _on_rotate_180_toggled(button_pressed: bool) -> void: _brush_rotate_180 = button_pressed update_brush() + save_config() func _on_rotate_270_toggled(button_pressed: bool) -> void: _brush_rotate_270 = button_pressed update_brush() + save_config() diff --git a/src/Tools/BaseShapeDrawer.gd b/src/Tools/BaseShapeDrawer.gd index 54369d670..9544c7438 100644 --- a/src/Tools/BaseShapeDrawer.gd +++ b/src/Tools/BaseShapeDrawer.gd @@ -3,7 +3,7 @@ extends "res://src/Tools/BaseDraw.gd" var _start := Vector2i.ZERO var _offset := Vector2i.ZERO var _dest := Vector2i.ZERO -var _fill := false +var _fill_inside := false var _drawing := false var _displace_origin := false var _thickness := 1 @@ -41,27 +41,27 @@ func update_indicator() -> void: func _on_FillCheckbox_toggled(button_pressed: bool) -> void: - _fill = button_pressed + _fill_inside = button_pressed update_config() save_config() func get_config() -> Dictionary: var config := super.get_config() - config["fill"] = _fill + config["fill_inside"] = _fill_inside config["thickness"] = _thickness return config func set_config(config: Dictionary) -> void: super.set_config(config) - _fill = config.get("fill", _fill) + _fill_inside = config.get("fill_inside", _fill_inside) _thickness = config.get("thickness", _thickness) func update_config() -> void: super.update_config() - $FillCheckbox.button_pressed = _fill + $FillCheckbox.button_pressed = _fill_inside $ThicknessSlider.value = _thickness @@ -237,7 +237,7 @@ func _get_result_rect(origin: Vector2i, dest: Vector2i) -> Rect2i: func _get_points(shape_size: Vector2i) -> Array[Vector2i]: - return _get_shape_points_filled(shape_size) if _fill else _get_shape_points(shape_size) + return _get_shape_points_filled(shape_size) if _fill_inside else _get_shape_points(shape_size) func _set_cursor_text(rect: Rect2i) -> void: diff --git a/src/Tools/BaseTool.gd b/src/Tools/BaseTool.gd index 519f5aa49..23326db37 100644 --- a/src/Tools/BaseTool.gd +++ b/src/Tools/BaseTool.gd @@ -2,6 +2,7 @@ class_name BaseTool extends VBoxContainer var is_moving := false +var is_syncing := false var kname: String var tool_slot: Tools.Slot = null var cursor_text := "" @@ -34,6 +35,8 @@ func _ready() -> void: func save_config() -> void: var config := get_config() Global.config_cache.set_value(tool_slot.kname, kname, config) + if not is_syncing: # If the tool isn't busy syncing with another tool. + Tools.config_changed.emit(tool_slot.button, config) func load_config() -> void: diff --git a/src/Tools/DesignTools/CurveTool.gd b/src/Tools/DesignTools/CurveTool.gd index 80a1d3b81..9219c2bbc 100644 --- a/src/Tools/DesignTools/CurveTool.gd +++ b/src/Tools/DesignTools/CurveTool.gd @@ -2,7 +2,7 @@ extends "res://src/Tools/BaseDraw.gd" var _curve := Curve2D.new() ## The [Curve2D] responsible for the shape of the curve being drawn. var _drawing := false ## Set to true when a curve is being drawn. -var _fill := false ## When true, the inside area of the curve gets filled. +var _fill_inside := false ## When true, the inside area of the curve gets filled. var _fill_inside_rect := Rect2i() ## The bounding box that surrounds the area that gets filled. var _editing_bezier := false ## Needed to determine when to show the control points preview line. var _editing_out_control_point := false ## True when controlling the out control point only. @@ -29,7 +29,7 @@ func _on_thickness_value_changed(value: int) -> void: func _on_fill_checkbox_toggled(toggled_on: bool) -> void: - _fill = toggled_on + _fill_inside = toggled_on update_config() save_config() @@ -44,17 +44,20 @@ func update_indicator() -> void: func get_config() -> Dictionary: var config := super.get_config() + config["fill_inside"] = _fill_inside config["thickness"] = _thickness return config func set_config(config: Dictionary) -> void: super.set_config(config) + _fill_inside = config.get("fill_inside", _fill_inside) _thickness = config.get("thickness", _thickness) func update_config() -> void: super.update_config() + $FillCheckbox.button_pressed = _fill_inside $ThicknessSlider.value = _thickness @@ -188,7 +191,7 @@ func _draw_shape() -> void: _fill_inside_rect = _fill_inside_rect.expand(point) # Draw each point offsetted based on the shape's thickness _draw_pixel(point, images) - if _fill: + if _fill_inside: var v := Vector2i() for x in _fill_inside_rect.size.x: v.x = x + _fill_inside_rect.position.x diff --git a/src/Tools/DesignTools/Pencil.gd b/src/Tools/DesignTools/Pencil.gd index 5e80f654a..d4b7f0d76 100644 --- a/src/Tools/DesignTools/Pencil.gd +++ b/src/Tools/DesignTools/Pencil.gd @@ -50,6 +50,7 @@ func _on_SpacingMode_toggled(button_pressed: bool) -> void: func _on_Spacing_value_changed(value: Vector2) -> void: _spacing = value + save_config() func _input(event: InputEvent) -> void: @@ -58,10 +59,10 @@ func _input(event: InputEvent) -> void: if event.is_action_pressed("change_tool_mode"): _prev_mode = overwrite_button.button_pressed if event.is_action("change_tool_mode"): - overwrite_button.button_pressed = !_prev_mode + overwrite_button.set_pressed_no_signal(!_prev_mode) _overwrite = overwrite_button.button_pressed if event.is_action_released("change_tool_mode"): - overwrite_button.button_pressed = _prev_mode + overwrite_button.set_pressed_no_signal(_prev_mode) _overwrite = overwrite_button.button_pressed diff --git a/src/UI/GlobalToolOptions/GlobalToolOptions.tscn b/src/UI/GlobalToolOptions/GlobalToolOptions.tscn index 9abe461b1..ba988ab9e 100644 --- a/src/UI/GlobalToolOptions/GlobalToolOptions.tscn +++ b/src/UI/GlobalToolOptions/GlobalToolOptions.tscn @@ -105,6 +105,8 @@ anchor_bottom = 0.5 offset_left = -22.0 offset_top = -10.0 offset_bottom = 10.0 +grow_horizontal = 0 +grow_vertical = 2 mouse_default_cursor_shape = 2 item_count = 2 popup/item_0/text = "Move to canvas center"