diff --git a/Translations/Translations.pot b/Translations/Translations.pot index ec6d3351b..cb3407593 100644 --- a/Translations/Translations.pot +++ b/Translations/Translations.pot @@ -1517,6 +1517,22 @@ msgstr "" msgid "100% Zoom" msgstr "" +#. One of the modes of a selection tool. Found in the tool options, when a selection tool is active. +msgid "Replace selection" +msgstr "" + +#. One of the modes of a selection tool. Found in the tool options, when a selection tool is active. +msgid "Add to selection" +msgstr "" + +#. One of the modes of a selection tool. Found in the tool options, when a selection tool is active. +msgid "Subtract from selection" +msgstr "" + +#. One of the modes of a selection tool. Found in the tool options, when a selection tool is active. +msgid "Intersection of selections" +msgstr "" + msgid "Mirroring" msgstr "" diff --git a/project.godot b/project.godot index e796bf041..b416e9791 100644 --- a/project.godot +++ b/project.godot @@ -233,6 +233,11 @@ _global_script_classes=[ { "class": "ValueSlider", "language": "GDScript", "path": "res://src/UI/Nodes/ValueSlider.gd" +}, { +"base": "HBoxContainer", +"class": "ValueSliderV2", +"language": "GDScript", +"path": "res://src/UI/Nodes/ValueSliderV2.gd" } ] _global_script_class_icons={ "AImgIOAPNGExporter": "", @@ -279,7 +284,8 @@ _global_script_class_icons={ "ShortcutProfile": "", "SymmetryGuide": "", "Tiles": "", -"ValueSlider": "" +"ValueSlider": "", +"ValueSliderV2": "" } [application] diff --git a/src/Tools/SelectionTools/SelectionTool.gd b/src/Tools/SelectionTools/SelectionTool.gd index b6962c610..2a97b1744 100644 --- a/src/Tools/SelectionTools/SelectionTool.gd +++ b/src/Tools/SelectionTools/SelectionTool.gd @@ -22,11 +22,9 @@ var _intersect := false # Shift + Ctrl + Mouse Click var _content_transformation_check := false onready var selection_node: Node2D = Global.canvas.selection -onready var xspinbox: ValueSlider = $XSpinBox -onready var yspinbox: ValueSlider = $YSpinBox -onready var wspinbox: ValueSlider = $WSpinBox -onready var hspinbox: ValueSlider = $HSpinBox -onready var timer: Timer = $Timer +onready var position_sliders := $Position as ValueSliderV2 +onready var size_sliders := $Size as ValueSliderV2 +onready var timer := $Timer as Timer func _ready() -> void: @@ -34,14 +32,14 @@ func _ready() -> void: refresh_options() -func refresh_options(): +func refresh_options() -> void: # The existence of this function is to ensure all items - # are added when we are selecting an option (Bad things will happen if i dont do this...) + # are added when we are selecting an option (bad things will happen otherwise) $Modes.clear() - $Modes.add_item("Default (New Selection)") - $Modes.add_item("Add to Selection") - $Modes.add_item("Subtract from Selection") - $Modes.add_item("Intersection of Selections") + $Modes.add_item("Replace selection") + $Modes.add_item("Add to selection") + $Modes.add_item("Subtract from selection") + $Modes.add_item("Intersection of selections") $Modes.select(_mode_selected) @@ -61,15 +59,10 @@ func update_config() -> void: func set_spinbox_values() -> void: var select_rect: Rect2 = selection_node.big_bounding_rectangle - xspinbox.editable = !select_rect.has_no_area() - yspinbox.editable = xspinbox.editable - wspinbox.editable = xspinbox.editable - hspinbox.editable = xspinbox.editable - - xspinbox.value = select_rect.position.x - yspinbox.value = select_rect.position.y - wspinbox.value = select_rect.size.x - hspinbox.value = select_rect.size.y + position_sliders.editable = !select_rect.has_no_area() + position_sliders.value = select_rect.position + size_sliders.editable = position_sliders.editable + size_sliders.value = select_rect.size func draw_start(position: Vector2) -> void: @@ -228,13 +221,7 @@ func _set_cursor_text(rect: Rect2) -> void: cursor_text += " (%s, %s)" % [rect.size.x, rect.size.y] -func _on_position_value_changed(value: float, horizontal: bool) -> void: - if horizontal: - if selection_node.big_bounding_rectangle.position.x == value: - return - else: - if selection_node.big_bounding_rectangle.position.y == value: - return +func _on_Position_value_changed(value: Vector2) -> void: var project: Project = Global.current_project if !project.has_selection: return @@ -242,10 +229,7 @@ func _on_position_value_changed(value: float, horizontal: bool) -> void: if timer.is_stopped(): undo_data = selection_node.get_undo_data(false) timer.start() - if horizontal: - selection_node.big_bounding_rectangle.position.x = value - else: - selection_node.big_bounding_rectangle.position.y = value + selection_node.big_bounding_rectangle.position = value var selection_map_copy := SelectionMap.new() selection_map_copy.copy_from(project.selection_map) @@ -254,29 +238,14 @@ func _on_position_value_changed(value: float, horizontal: bool) -> void: project.selection_map_changed() -func _on_size_value_changed(value: float, horizontal: bool) -> void: - if horizontal: - if ( - selection_node.big_bounding_rectangle.size.x == value - or selection_node.big_bounding_rectangle.size.x <= 0 - ): - return - else: - if ( - selection_node.big_bounding_rectangle.size.y == value - or selection_node.big_bounding_rectangle.size.y <= 0 - ): - return +func _on_Size_value_changed(value: Vector2) -> void: if !Global.current_project.has_selection: return if timer.is_stopped(): undo_data = selection_node.get_undo_data(false) timer.start() - if horizontal: - selection_node.big_bounding_rectangle.size.x = value - else: - selection_node.big_bounding_rectangle.size.y = value + selection_node.big_bounding_rectangle.size = value selection_node.resize_selection() diff --git a/src/Tools/SelectionTools/SelectionTool.tscn b/src/Tools/SelectionTools/SelectionTool.tscn index 341ca4728..455ca2484 100644 --- a/src/Tools/SelectionTools/SelectionTool.tscn +++ b/src/Tools/SelectionTools/SelectionTool.tscn @@ -2,7 +2,7 @@ [ext_resource path="res://src/Tools/BaseTool.tscn" type="PackedScene" id=1] [ext_resource path="res://src/Tools/SelectionTools/SelectionTool.gd" type="Script" id=2] -[ext_resource path="res://src/UI/Nodes/ValueSlider.tscn" type="PackedScene" id=3] +[ext_resource path="res://src/UI/Nodes/ValueSliderV2.tscn" type="PackedScene" id=4] [node name="ToolOptions" instance=ExtResource( 1 )] script = ExtResource( 2 ) @@ -17,6 +17,7 @@ text = "Mode:" margin_top = 44.0 margin_right = 116.0 margin_bottom = 64.0 +mouse_default_cursor_shape = 2 align = 1 [node name="PositionLabel" type="Label" parent="." index="4"] @@ -25,57 +26,35 @@ margin_right = 116.0 margin_bottom = 82.0 text = "Position:" -[node name="XSpinBox" parent="." index="5" instance=ExtResource( 3 )] +[node name="Position" parent="." index="5" instance=ExtResource( 4 )] margin_top = 86.0 margin_right = 116.0 -margin_bottom = 110.0 -hint_tooltip = "X coordinate of the top left corner" -allow_greater = true -allow_lesser = true -prefix = "X:" - -[node name="YSpinBox" parent="." index="6" instance=ExtResource( 3 )] -margin_top = 114.0 -margin_right = 116.0 margin_bottom = 138.0 -hint_tooltip = "Y coordinate of the top left corner" allow_greater = true allow_lesser = true -prefix = "Y:" -[node name="SizeLabel" type="Label" parent="." index="7"] +[node name="SizeLabel" type="Label" parent="." index="6"] margin_top = 142.0 margin_right = 116.0 margin_bottom = 156.0 text = "Size:" -[node name="WSpinBox" parent="." index="8" instance=ExtResource( 3 )] +[node name="Size" parent="." index="7" instance=ExtResource( 4 )] margin_top = 160.0 margin_right = 116.0 -margin_bottom = 184.0 -hint_tooltip = "Width of selection" -min_value = 1.0 -value = 1.0 -allow_greater = true -prefix = "W:" - -[node name="HSpinBox" parent="." index="9" instance=ExtResource( 3 )] -margin_top = 188.0 -margin_right = 116.0 margin_bottom = 212.0 -hint_tooltip = "Height of selection" +value = Vector2( 1, 1 ) min_value = 1.0 -value = 1.0 allow_greater = true -prefix = "H:" +show_ratio = true +prefix_x = "Width:" +prefix_y = "Height:" -[node name="Timer" type="Timer" parent="." index="10"] +[node name="Timer" type="Timer" parent="." index="8"] wait_time = 0.2 one_shot = true [connection signal="item_selected" from="Modes" to="." method="_on_Modes_item_selected"] -[connection signal="value_changed" from="XSpinBox" to="." method="_on_position_value_changed" binds= [ true ]] -[connection signal="value_changed" from="YSpinBox" to="." method="_on_position_value_changed" binds= [ false ]] -[connection signal="value_changed" from="WSpinBox" to="." method="_on_size_value_changed" binds= [ true ]] -[connection signal="value_changed" from="HSpinBox" to="." method="_on_size_value_changed" binds= [ false ]] +[connection signal="value_changed" from="Position" to="." method="_on_Position_value_changed"] +[connection signal="value_changed" from="Size" to="." method="_on_Size_value_changed"] [connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"] diff --git a/src/UI/Nodes/ValueSliderV2.gd b/src/UI/Nodes/ValueSliderV2.gd new file mode 100644 index 000000000..fd479da4d --- /dev/null +++ b/src/UI/Nodes/ValueSliderV2.gd @@ -0,0 +1,157 @@ +tool +class_name ValueSliderV2 +extends HBoxContainer + +signal value_changed(value) + +export var editable := true setget _set_editable +export var value := Vector2.ZERO setget _set_value +export var min_value := 0.0 setget _set_min_value +export var max_value := 100.0 setget _set_max_value +export var step := 1.0 setget _set_step +export var allow_greater := false setget _set_allow_greater +export var allow_lesser := false setget _set_allow_lesser +export var show_ratio := false setget _set_show_ratio +export(int, 1, 2) var grid_columns := 1 setget _set_grid_columns +export var slider_min_size := Vector2(32, 24) setget _set_slider_min_size +export var snap_step := 1.0 setget _set_snap_step +export var snap_by_default := false setget _set_snap_by_default +export var prefix_x := "X:" setget _set_prefix_x +export var prefix_y := "Y:" setget _set_prefix_y +export var suffix_x := "" setget _set_suffix_x +export var suffix_y := "" setget _set_suffix_y + +var ratio := Vector2.ONE +var _locked_ratio := false +var _can_emit_signal := true + + +func _ready() -> void: + if not Engine.editor_hint: # Pixelorama specific code + $Ratio.modulate = Global.modulate_icon_color + + +func get_sliders() -> Array: + return [$GridContainer/X, $GridContainer/Y] + + +# Greatest common divisor +func _gcd(a: int, b: int) -> int: + return a if b == 0 else _gcd(b, a % b) + + +func _on_X_value_changed(val: float) -> void: + value.x = val + if _locked_ratio: + value.y = max(min_value, (value.x / ratio.x) * ratio.y) + if _can_emit_signal: + emit_signal("value_changed", value) + + +func _on_Y_value_changed(val: float) -> void: + value.y = val + if _locked_ratio: + value.x = max(min_value, (value.y / ratio.y) * ratio.x) + if _can_emit_signal: + emit_signal("value_changed", value) + + +func _on_RatioButton_toggled(button_pressed: bool) -> void: + _locked_ratio = button_pressed + var divisor := _gcd(value.x, value.y) + ratio = value / divisor + + +# Setters + + +func _set_editable(val: bool) -> void: + editable = val + for slider in get_sliders(): + slider.editable = val + + +func _set_value(val: Vector2) -> void: + value = val + _can_emit_signal = false + $GridContainer/X.value = value.x + $GridContainer/Y.value = value.y + _can_emit_signal = true + + +func _set_min_value(val: float) -> void: + min_value = val + for slider in get_sliders(): + slider.min_value = val + + +func _set_max_value(val: float) -> void: + max_value = val + for slider in get_sliders(): + slider.max_value = val + + +func _set_step(val: float) -> void: + step = val + for slider in get_sliders(): + slider.step = val + + +func _set_allow_greater(val: bool) -> void: + allow_greater = val + for slider in get_sliders(): + slider.allow_greater = val + + +func _set_allow_lesser(val: bool) -> void: + allow_lesser = val + for slider in get_sliders(): + slider.allow_lesser = val + + +func _set_show_ratio(val: bool) -> void: + show_ratio = val + $Ratio.visible = val + + +func _set_grid_columns(val: int) -> void: + grid_columns = val + $GridContainer.columns = val + + +func _set_slider_min_size(val: Vector2) -> void: + slider_min_size = val + for slider in get_sliders(): + slider.rect_min_size = val + + +func _set_snap_step(val: float) -> void: + snap_step = val + for slider in get_sliders(): + slider.snap_step = val + + +func _set_snap_by_default(val: bool) -> void: + snap_by_default = val + for slider in get_sliders(): + slider.snap_by_default = val + + +func _set_prefix_x(val: String) -> void: + prefix_x = val + $GridContainer/X.prefix = val + + +func _set_prefix_y(val: String) -> void: + prefix_y = val + $GridContainer/Y.prefix = val + + +func _set_suffix_x(val: String) -> void: + suffix_x = val + $GridContainer/X.suffix = val + + +func _set_suffix_y(val: String) -> void: + suffix_y = val + $GridContainer/Y.suffix = val diff --git a/src/UI/Nodes/ValueSliderV2.tscn b/src/UI/Nodes/ValueSliderV2.tscn new file mode 100644 index 000000000..fd0223819 --- /dev/null +++ b/src/UI/Nodes/ValueSliderV2.tscn @@ -0,0 +1,75 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://src/UI/Nodes/ValueSlider.gd" type="Script" id=1] +[ext_resource path="res://src/UI/Nodes/ValueSliderV2.gd" type="Script" id=2] +[ext_resource path="res://assets/graphics/misc/lock_aspect_2.png" type="Texture" id=3] +[ext_resource path="res://assets/graphics/misc/lock_aspect_guides.png" type="Texture" id=4] +[ext_resource path="res://assets/graphics/misc/lock_aspect.png" type="Texture" id=5] + +[node name="ValueSliderV2" type="HBoxContainer"] +margin_right = 40.0 +margin_bottom = 40.0 +script = ExtResource( 2 ) + +[node name="GridContainer" type="GridContainer" parent="."] +margin_right = 40.0 +margin_bottom = 52.0 +size_flags_horizontal = 3 + +[node name="X" type="TextureProgress" parent="GridContainer"] +margin_right = 40.0 +margin_bottom = 24.0 +rect_min_size = Vector2( 32, 24 ) +mouse_default_cursor_shape = 2 +size_flags_horizontal = 3 +theme_type_variation = "ValueSlider" +nine_patch_stretch = true +stretch_margin_left = 3 +stretch_margin_top = 3 +stretch_margin_right = 3 +stretch_margin_bottom = 3 +script = ExtResource( 1 ) +prefix = "X:" + +[node name="Y" type="TextureProgress" parent="GridContainer"] +margin_top = 28.0 +margin_right = 40.0 +margin_bottom = 52.0 +rect_min_size = Vector2( 32, 24 ) +mouse_default_cursor_shape = 2 +size_flags_horizontal = 3 +theme_type_variation = "ValueSlider" +nine_patch_stretch = true +stretch_margin_left = 3 +stretch_margin_top = 3 +stretch_margin_right = 3 +stretch_margin_bottom = 3 +script = ExtResource( 1 ) +prefix = "Y:" + +[node name="Ratio" type="TextureRect" parent="." groups=["UIButtons"]] +visible = false +margin_left = 36.0 +margin_right = 52.0 +margin_bottom = 52.0 +rect_min_size = Vector2( 16, 0 ) +texture = ExtResource( 4 ) + +[node name="RatioButton" type="TextureButton" parent="Ratio" groups=["UIButtons"]] +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +margin_left = -8.0 +margin_top = -10.0 +margin_right = 8.0 +margin_bottom = 6.0 +hint_tooltip = "Lock aspect ratio" +mouse_default_cursor_shape = 2 +toggle_mode = true +texture_normal = ExtResource( 3 ) +texture_pressed = ExtResource( 5 ) + +[connection signal="value_changed" from="GridContainer/X" to="." method="_on_X_value_changed"] +[connection signal="value_changed" from="GridContainer/Y" to="." method="_on_Y_value_changed"] +[connection signal="toggled" from="Ratio/RatioButton" to="." method="_on_RatioButton_toggled"]