1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-22 13:33:13 +00:00

Replace the Locked Aspect Ratio mode in the crop tool with a lock button next to the size sliders

This commit is contained in:
Emmanouil Papadeas 2023-03-24 01:17:30 +02:00
parent 2ad1391ca1
commit acb32844a1
3 changed files with 72 additions and 126 deletions

View file

@ -1,10 +1,11 @@
extends BaseTool extends BaseTool
# Crop Tool, allows you to resize the canvas interactively # Crop Tool, allows you to resize the canvas interactively
var _offset = Vector2.ZERO var _offset := Vector2.ZERO
var _crop: CropRect var _crop: CropRect
var _start_pos: Vector2 var _start_pos: Vector2
var _syncing := false var _syncing := false
var _locked_ratio := false
func _ready() -> void: func _ready() -> void:
@ -29,28 +30,24 @@ func draw_move(position: Vector2) -> void:
if _crop.locked_size: if _crop.locked_size:
_crop.rect.position = position - _offset _crop.rect.position = position - _offset
else: else:
match _crop.mode: if _crop.mode == CropRect.Mode.POSITION_SIZE and _locked_ratio:
CropRect.Mode.MARGINS, CropRect.Mode.POSITION_SIZE: var ratio: Vector2 = $"%Size".ratio
_crop.rect.position.x = min(_start_pos.x, position.x) var distance := abs(_start_pos.x - position.x) + abs(_start_pos.y - position.y)
_crop.rect.position.y = min(_start_pos.y, position.y) _crop.rect.size.x = round(distance * ratio.x / (ratio.x + ratio.y))
_crop.rect.end.x = max(_start_pos.x, position.x) _crop.rect.size.y = round(distance * ratio.y / (ratio.x + ratio.y))
_crop.rect.end.y = max(_start_pos.y, position.y) if _start_pos.x < position.x:
CropRect.Mode.LOCKED_ASPECT_RATIO: _crop.rect.position.x = _start_pos.x
var distance = abs(_start_pos.x - position.x) + abs(_start_pos.y - position.y) else:
_crop.rect.size.x = round( _crop.rect.position.x = _start_pos.x - _crop.rect.size.x
distance * _crop.ratio.x / (_crop.ratio.x + _crop.ratio.y) if _start_pos.y < position.y:
) _crop.rect.position.y = _start_pos.y
_crop.rect.size.y = round( else:
distance * _crop.ratio.y / (_crop.ratio.x + _crop.ratio.y) _crop.rect.position.y = _start_pos.y - _crop.rect.size.y
) else:
if _start_pos.x < position.x: _crop.rect.position.x = min(_start_pos.x, position.x)
_crop.rect.position.x = _start_pos.x _crop.rect.position.y = min(_start_pos.y, position.y)
else: _crop.rect.end.x = max(_start_pos.x, position.x)
_crop.rect.position.x = _start_pos.x - _crop.rect.size.x _crop.rect.end.y = max(_start_pos.y, position.y)
if _start_pos.y < position.y:
_crop.rect.position.y = _start_pos.y
else:
_crop.rect.position.y = _start_pos.y - _crop.rect.size.y
# Ensure that the size is at least 1: # Ensure that the size is at least 1:
_crop.rect.size.x = max(1, _crop.rect.size.x) _crop.rect.size.x = max(1, _crop.rect.size.x)
_crop.rect.size.y = max(1, _crop.rect.size.y) _crop.rect.size.y = max(1, _crop.rect.size.y)
@ -69,12 +66,6 @@ func _sync_ui() -> void:
$"%DimensionsLabel".show() $"%DimensionsLabel".show()
CropRect.Mode.POSITION_SIZE: CropRect.Mode.POSITION_SIZE:
$"%MarginsContainer".hide() $"%MarginsContainer".hide()
$"%RatioContainer".hide()
$"%PosSizeContainer".show()
$"%DimensionsLabel".hide()
CropRect.Mode.LOCKED_ASPECT_RATIO:
$"%MarginsContainer".hide()
$"%RatioContainer".show()
$"%PosSizeContainer".show() $"%PosSizeContainer".show()
$"%DimensionsLabel".hide() $"%DimensionsLabel".hide()
@ -87,17 +78,10 @@ func _sync_ui() -> void:
$"%Left".value = _crop.rect.position.x $"%Left".value = _crop.rect.position.x
$"%Right".value = _crop.rect.end.x $"%Right".value = _crop.rect.end.x
$"%RatioX".value = _crop.ratio.x $"%Position".max_value = Global.current_project.size - Vector2.ONE
$"%RatioY".value = _crop.ratio.y $"%Size".max_value = Global.current_project.size
$"%Position".value = _crop.rect.position
$"%PositionX".max_value = Global.current_project.size.x - 1 $"%Size".value = _crop.rect.size
$"%PositionY".max_value = Global.current_project.size.y - 1
$"%Width".max_value = Global.current_project.size.x
$"%Height".max_value = Global.current_project.size.y
$"%PositionX".value = _crop.rect.position.x
$"%PositionY".value = _crop.rect.position.y
$"%Width".value = _crop.rect.size.x
$"%Height".value = _crop.rect.size.y
$"%DimensionsLabel".text = str(_crop.rect.size.x, " x ", _crop.rect.size.y) $"%DimensionsLabel".text = str(_crop.rect.size.x, " x ", _crop.rect.size.y)
_syncing = false _syncing = false
@ -161,49 +145,40 @@ func _on_Right_value_changed(value: float) -> void:
func _on_RatioX_value_changed(value: float) -> void: func _on_RatioX_value_changed(value: float) -> void:
if _syncing: if _syncing:
return return
_crop.rect.size.x = round(max(1, _crop.rect.size.y / _crop.ratio.y * value)) var prev_ratio: Vector2 = $"%Size".ratio
_crop.ratio.x = value $"%Size".ratio.x = value
_crop.rect.size.x = round(max(1, _crop.rect.size.y / prev_ratio.y * value))
_crop.emit_signal("updated") _crop.emit_signal("updated")
func _on_RatioY_value_changed(value: float) -> void: func _on_RatioY_value_changed(value: float) -> void:
if _syncing: if _syncing:
return return
_crop.rect.size.y = round(max(1, _crop.rect.size.x / _crop.ratio.x * value)) var prev_ratio: Vector2 = $"%Size".ratio
_crop.ratio.y = value $"%Size".ratio.y = value
_crop.rect.size.y = round(max(1, _crop.rect.size.x / prev_ratio.x * value))
_crop.emit_signal("updated") _crop.emit_signal("updated")
func _on_PositionX_value_changed(value: float) -> void: func _on_Position_value_changed(value: Vector2) -> void:
if _syncing: if _syncing:
return return
_crop.rect.position.x = value _crop.rect.position = value
_crop.emit_signal("updated") _crop.emit_signal("updated")
func _on_PositionY_value_changed(value: float) -> void: func _on_Size_value_changed(value: Vector2) -> void:
if _syncing: if _syncing:
return return
_crop.rect.position.y = value _crop.rect.size = value
_crop.emit_signal("updated") _crop.emit_signal("updated")
func _on_Width_value_changed(value: float) -> void: func _on_Size_ratio_toggled(button_pressed: bool) -> void:
if _syncing: $"%RatioX".value = $"%Size".ratio.x
return $"%RatioY".value = $"%Size".ratio.y
if _crop.mode == CropRect.Mode.LOCKED_ASPECT_RATIO: $"%RatioContainer".visible = button_pressed
_crop.rect.size.y = round(max(1, (value / _crop.ratio.x) * _crop.ratio.y)) _locked_ratio = button_pressed
_crop.rect.size.x = value
_crop.emit_signal("updated")
func _on_Height_value_changed(value: float) -> void:
if _syncing:
return
if _crop.mode == CropRect.Mode.LOCKED_ASPECT_RATIO:
_crop.rect.size.x = round(max(1, (value / _crop.ratio.y) * _crop.ratio.x))
_crop.rect.size.y = value
_crop.emit_signal("updated")
func _on_Apply_pressed() -> void: func _on_Apply_pressed() -> void:

View file

@ -1,20 +1,21 @@
[gd_scene load_steps=5 format=2] [gd_scene load_steps=6 format=2]
[ext_resource path="res://src/Tools/BaseTool.tscn" type="PackedScene" id=1] [ext_resource path="res://src/Tools/BaseTool.tscn" type="PackedScene" id=1]
[ext_resource path="res://src/UI/Nodes/ValueSlider.tscn" type="PackedScene" id=2] [ext_resource path="res://src/UI/Nodes/ValueSlider.tscn" type="PackedScene" id=2]
[ext_resource path="res://src/Tools/CropTool.gd" type="Script" id=3] [ext_resource path="res://src/Tools/CropTool.gd" type="Script" id=3]
[ext_resource path="res://assets/graphics/misc/unlocked_size.png" type="Texture" id=4] [ext_resource path="res://assets/graphics/misc/unlocked_size.png" type="Texture" id=4]
[ext_resource path="res://src/UI/Nodes/ValueSliderV2.tscn" type="PackedScene" id=5]
[node name="ToolOptions" instance=ExtResource( 1 )] [node name="ToolOptions" instance=ExtResource( 1 )]
script = ExtResource( 3 ) script = ExtResource( 3 )
[node name="ModeLabel" type="Label" parent="." index="4"] [node name="ModeLabel" type="Label" parent="." index="2"]
margin_top = 26.0 margin_top = 26.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 40.0 margin_bottom = 40.0
text = "Mode:" text = "Mode:"
[node name="HBoxContainer" type="HBoxContainer" parent="." index="5"] [node name="HBoxContainer" type="HBoxContainer" parent="." index="3"]
margin_top = 44.0 margin_top = 44.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 66.0 margin_bottom = 66.0
@ -23,10 +24,11 @@ margin_bottom = 66.0
unique_name_in_owner = true unique_name_in_owner = true
margin_right = 84.0 margin_right = 84.0
margin_bottom = 22.0 margin_bottom = 22.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Margins" text = "Margins"
clip_text = true clip_text = true
items = [ "Margins", null, false, 0, null, "Position + Size", null, false, 1, null, "Locked Aspect Ratio", null, false, 3, null ] items = [ "Margins", null, false, 0, null, "Position + Size", null, false, 1, null ]
selected = 0 selected = 0
[node name="SizeLock" type="Button" parent="HBoxContainer" index="1"] [node name="SizeLock" type="Button" parent="HBoxContainer" index="1"]
@ -40,13 +42,14 @@ When enabled using the tool on the canvas will only move the cropping rectangle.
When disabled using the tool on the canvas will draw the rectangle." When disabled using the tool on the canvas will draw the rectangle."
focus_mode = 0 focus_mode = 0
mouse_default_cursor_shape = 2
toggle_mode = true toggle_mode = true
icon = ExtResource( 4 ) icon = ExtResource( 4 )
__meta__ = { __meta__ = {
"_editor_description_": "" "_editor_description_": ""
} }
[node name="MarginsContainer" type="VBoxContainer" parent="." index="6"] [node name="MarginsContainer" type="VBoxContainer" parent="." index="4"]
unique_name_in_owner = true unique_name_in_owner = true
margin_top = 70.0 margin_top = 70.0
margin_right = 116.0 margin_right = 116.0
@ -93,8 +96,9 @@ allow_greater = true
allow_lesser = true allow_lesser = true
prefix = "Right:" prefix = "Right:"
[node name="RatioContainer" type="VBoxContainer" parent="." index="7"] [node name="RatioContainer" type="VBoxContainer" parent="." index="5"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false
margin_top = 200.0 margin_top = 200.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 242.0 margin_bottom = 242.0
@ -131,72 +135,55 @@ min_value = 1.0
value = 1.0 value = 1.0
allow_greater = true allow_greater = true
[node name="PosSizeContainer" type="VBoxContainer" parent="." index="8"] [node name="PosSizeContainer" type="VBoxContainer" parent="." index="6"]
unique_name_in_owner = true unique_name_in_owner = true
margin_top = 246.0 margin_top = 200.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 390.0 margin_bottom = 344.0
[node name="PositionLabel" type="Label" parent="PosSizeContainer" index="0"] [node name="PositionLabel" type="Label" parent="PosSizeContainer" index="0"]
margin_right = 116.0 margin_right = 116.0
margin_bottom = 14.0 margin_bottom = 14.0
text = "Position:" text = "Position:"
[node name="PositionX" parent="PosSizeContainer" index="1" instance=ExtResource( 2 )] [node name="Position" parent="PosSizeContainer" index="1" instance=ExtResource( 5 )]
unique_name_in_owner = true unique_name_in_owner = true
margin_top = 18.0 margin_top = 18.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 42.0
allow_greater = true
allow_lesser = true
prefix = "X:"
[node name="PositionY" parent="PosSizeContainer" index="2" instance=ExtResource( 2 )]
unique_name_in_owner = true
margin_top = 46.0
margin_right = 116.0
margin_bottom = 70.0 margin_bottom = 70.0
allow_greater = true allow_greater = true
allow_lesser = true allow_lesser = true
prefix = "Y:"
[node name="SizeLabel" type="Label" parent="PosSizeContainer" index="3"] [node name="SizeLabel" type="Label" parent="PosSizeContainer" index="2"]
margin_top = 74.0 margin_top = 74.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 88.0 margin_bottom = 88.0
text = "Size:" text = "Size:"
[node name="Width" parent="PosSizeContainer" index="4" instance=ExtResource( 2 )] [node name="Size" parent="PosSizeContainer" index="3" instance=ExtResource( 5 )]
unique_name_in_owner = true unique_name_in_owner = true
margin_top = 92.0 margin_top = 92.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 116.0
min_value = 1.0
value = 1.0
allow_greater = true
prefix = "W:"
[node name="Height" parent="PosSizeContainer" index="5" instance=ExtResource( 2 )]
unique_name_in_owner = true
margin_top = 120.0
margin_right = 116.0
margin_bottom = 144.0 margin_bottom = 144.0
min_value = 1.0 value = Vector2( 1, 1 )
value = 1.0 min_value = Vector2( 1, 1 )
allow_greater = true allow_greater = true
prefix = "H:" show_ratio = true
prefix_x = "Width:"
prefix_y = "Height:"
[node name="Apply" type="Button" parent="." index="9"] [node name="Apply" type="Button" parent="." index="7"]
margin_top = 394.0 margin_top = 348.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 414.0 margin_bottom = 368.0
mouse_default_cursor_shape = 2
text = "Apply" text = "Apply"
[node name="DimensionsLabel" type="Label" parent="." index="10"] [node name="DimensionsLabel" type="Label" parent="." index="8"]
unique_name_in_owner = true unique_name_in_owner = true
margin_top = 418.0 margin_top = 372.0
margin_right = 116.0 margin_right = 116.0
margin_bottom = 432.0 margin_bottom = 386.0
align = 1 align = 1
[connection signal="item_selected" from="HBoxContainer/CropMode" to="." method="_on_CropMode_item_selected"] [connection signal="item_selected" from="HBoxContainer/CropMode" to="." method="_on_CropMode_item_selected"]
@ -207,8 +194,7 @@ align = 1
[connection signal="value_changed" from="MarginsContainer/Right" to="." method="_on_Right_value_changed"] [connection signal="value_changed" from="MarginsContainer/Right" to="." method="_on_Right_value_changed"]
[connection signal="value_changed" from="RatioContainer/HBoxContainer/RatioX" to="." method="_on_RatioX_value_changed"] [connection signal="value_changed" from="RatioContainer/HBoxContainer/RatioX" to="." method="_on_RatioX_value_changed"]
[connection signal="value_changed" from="RatioContainer/HBoxContainer/RatioY" to="." method="_on_RatioY_value_changed"] [connection signal="value_changed" from="RatioContainer/HBoxContainer/RatioY" to="." method="_on_RatioY_value_changed"]
[connection signal="value_changed" from="PosSizeContainer/PositionX" to="." method="_on_PositionX_value_changed"] [connection signal="value_changed" from="PosSizeContainer/Position" to="." method="_on_Position_value_changed"]
[connection signal="value_changed" from="PosSizeContainer/PositionY" to="." method="_on_PositionY_value_changed"] [connection signal="ratio_toggled" from="PosSizeContainer/Size" to="." method="_on_Size_ratio_toggled"]
[connection signal="value_changed" from="PosSizeContainer/Width" to="." method="_on_Width_value_changed"] [connection signal="value_changed" from="PosSizeContainer/Size" to="." method="_on_Size_value_changed"]
[connection signal="value_changed" from="PosSizeContainer/Height" to="." method="_on_Height_value_changed"]
[connection signal="pressed" from="Apply" to="." method="_on_Apply_pressed"] [connection signal="pressed" from="Apply" to="." method="_on_Apply_pressed"]

View file

@ -5,16 +5,15 @@ extends Node2D
signal updated signal updated
enum Mode { MARGINS, POSITION_SIZE, LOCKED_ASPECT_RATIO } enum Mode { MARGINS, POSITION_SIZE }
const BIG = 100000 # Size of big rectangles used to darken background. const BIG = 100000 # Size of big rectangles used to darken background.
const DARKEN_COLOR = Color(0, 0, 0, 0.5) const DARKEN_COLOR = Color(0, 0, 0, 0.5)
const LINE_COLOR = Color.white const LINE_COLOR = Color.white
var mode := 0 setget _set_mode var mode: int = Mode.MARGINS setget _set_mode
var locked_size := false var locked_size := false
var rect := Rect2(0, 0, 1, 1) var rect := Rect2(0, 0, 1, 1)
var ratio := Vector2.ONE
# How many crop tools are active (0-2), setter makes this visible if not 0 # How many crop tools are active (0-2), setter makes this visible if not 0
var tool_count := 0 setget _set_tool_count var tool_count := 0 setget _set_tool_count
@ -66,27 +65,13 @@ func apply() -> void:
func reset() -> void: func reset() -> void:
rect.position = Vector2.ZERO rect.position = Vector2.ZERO
rect.size = Global.current_project.size rect.size = Global.current_project.size
if mode == Mode.LOCKED_ASPECT_RATIO:
_auto_ratio_from_resolution()
emit_signal("updated") emit_signal("updated")
func _auto_ratio_from_resolution() -> void:
var divisor := _gcd(rect.size.x, rect.size.y)
ratio = rect.size / divisor
# Greatest common divisor
func _gcd(a: int, b: int) -> int:
return a if b == 0 else _gcd(b, a % b)
# Setters # Setters
func _set_mode(value: int) -> void: func _set_mode(value: int) -> void:
if value == Mode.LOCKED_ASPECT_RATIO and mode != Mode.LOCKED_ASPECT_RATIO:
_auto_ratio_from_resolution()
mode = value mode = value