mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-30 23:19:49 +00:00
Add a new custom node, ValueSliderV2
ValueSliderV2 is a container for two ValueSliders and an optional lock ratio button, that helps with handling Vector2 values in the UI.
This commit is contained in:
parent
5ed91c6d8a
commit
e174f6e942
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
|
157
src/UI/Nodes/ValueSliderV2.gd
Normal file
157
src/UI/Nodes/ValueSliderV2.gd
Normal file
|
@ -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
|
75
src/UI/Nodes/ValueSliderV2.tscn
Normal file
75
src/UI/Nodes/ValueSliderV2.tscn
Normal file
|
@ -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"]
|
Loading…
Reference in a new issue