Skip to content

Commit 85b4b2f

Browse files
committed
implemented vertical zoom (via Codex CLI)
1 parent 6756ab7 commit 85b4b2f

File tree

5 files changed

+72
-7
lines changed

5 files changed

+72
-7
lines changed

src/Autoload/Global.gd

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,28 @@ var integer_zoom := false:
214214
zoom_slider.step = 1
215215
zoom_slider.value = zoom_slider.value # to trigger signal emission
216216

217+
## Vertical display zoom factor for the canvas (Y axis only).
218+
## 1.0 means no vertical stretch; 2.0 doubles visible height of pixels.
219+
var vertical_zoom := 1.0:
220+
set(value):
221+
if is_equal_approx(value, vertical_zoom):
222+
return
223+
vertical_zoom = value
224+
if is_instance_valid(top_menu_container):
225+
var vzs: ValueSlider = top_menu_container.get_node("%VerticalZoomSlider")
226+
if is_instance_valid(vzs) and !is_equal_approx(vzs.value, vertical_zoom * 100.0):
227+
vzs.value = vertical_zoom * 100.0
228+
# Persist with the current project like normal zoom (session-only)
229+
if is_instance_valid(current_project):
230+
current_project.vertical_zoom = vertical_zoom
231+
# Update all canvas cameras to apply new transform and checkerboard scale
232+
for cam in get_tree().get_nodes_in_group("CanvasCameras"):
233+
if cam is CanvasCamera:
234+
cam._update_viewport_transform()
235+
cam.update_transparent_checker_offset()
236+
# Ensure rulers refresh to reflect new pixel size
237+
get_tree().call_group("CanvasRulers", "queue_redraw")
238+
217239
## Found in Preferences. The scale of the interface.
218240
var shrink := 1.0
219241
var theme_font := loaded_fonts[theme_font_index]:

src/Classes/Project.gd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ var fps := 6.0:
6767
fps_changed.emit()
6868
var user_data := "" ## User defined data, set in the project properties.
6969

70+
# Session-only view state
71+
var vertical_zoom := 1.0
72+
7073
var x_symmetry_point: float
7174
var y_symmetry_point: float
7275
var xy_symmetry_point: Vector2

src/UI/Canvas/CanvasCamera.gd

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var mouse_pos := Vector2.ZERO
4040
var drag := false
4141
var rotation_slider: ValueSlider
4242
var zoom_slider: ValueSlider
43+
var vertical_zoom_slider: ValueSlider
4344
var should_tween := true
4445

4546
@onready var viewport := get_viewport()
@@ -55,6 +56,8 @@ func _ready() -> void:
5556
rotation_slider.value_changed.connect(_rotation_slider_value_changed)
5657
zoom_slider = Global.top_menu_container.get_node("%ZoomSlider")
5758
zoom_slider.value_changed.connect(_zoom_slider_value_changed)
59+
vertical_zoom_slider = Global.top_menu_container.get_node("%VerticalZoomSlider")
60+
vertical_zoom_slider.value_changed.connect(_vertical_zoom_slider_value_changed)
5861
zoom_changed.connect(_zoom_changed)
5962
rotation_changed.connect(_rotation_changed)
6063
viewport_container = get_viewport().get_parent()
@@ -182,7 +185,10 @@ func update_transparent_checker_offset() -> void:
182185
func _update_viewport_transform() -> void:
183186
if not is_instance_valid(viewport):
184187
return
185-
var zoom_scale := Vector2.ONE / zoom
188+
var zoom_scale := Vector2(
189+
1.0 / zoom.x,
190+
1.0 / (zoom.y * maxf(Global.vertical_zoom, 0.01))
191+
)
186192
var viewport_size := get_viewport_rect().size
187193
var screen_offset := viewport_size * 0.5 * zoom_scale
188194
screen_offset = screen_offset.rotated(camera_angle)
@@ -198,6 +204,7 @@ func _zoom_changed() -> void:
198204
if index == Cameras.MAIN:
199205
should_tween = false
200206
zoom_slider.value = zoom.x * 100.0
207+
vertical_zoom_slider.value = Global.vertical_zoom * 100.0
201208
should_tween = true
202209
for guide in Global.current_project.guides:
203210
guide.width = 1.0 / zoom.x * 2
@@ -231,6 +238,14 @@ func _rotation_slider_value_changed(value: float) -> void:
231238
camera_angle = angle
232239

233240

241+
func _vertical_zoom_slider_value_changed(value: float) -> void:
242+
# Convert percentage to factor
243+
var factor := value / 100.0
244+
if is_equal_approx(Global.vertical_zoom, factor):
245+
return
246+
Global.vertical_zoom = factor
247+
248+
234249
func _has_selection_tool() -> bool:
235250
for slot in Tools._slots.values():
236251
if slot.tool_node is BaseSelectionTool:
@@ -242,6 +257,9 @@ func _project_switched() -> void:
242257
offset = Global.current_project.cameras_offset[index]
243258
camera_angle = Global.current_project.cameras_rotation[index]
244259
zoom = Global.current_project.cameras_zoom[index]
260+
# Restore session vertical zoom per project
261+
if index == Cameras.MAIN:
262+
Global.vertical_zoom = Global.current_project.vertical_zoom
245263

246264

247265
func _rotate_camera_around_point(degrees: float, point: Vector2) -> void:

src/UI/Canvas/Rulers/VerticalRuler.gd

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@ func _draw() -> void:
3535
var ruler_transform := Transform2D()
3636
var major_subdivide := Transform2D()
3737
var minor_subdivide := Transform2D()
38-
var zoom := Global.camera.zoom.x
39-
transform.y = Vector2(zoom, zoom)
38+
# Use effective Y scale: base zoom times vertical display zoom
39+
var y_zoom := Global.camera.zoom.x * maxf(Global.vertical_zoom, 0.01)
40+
transform.y = Vector2(y_zoom, y_zoom)
4041

4142
# This tracks the "true" top left corner of the drawing:
4243
transform.origin = (
4344
Global.main_viewport.size / 2
44-
+ Global.camera.offset.rotated(-Global.camera.rotation) * -zoom
45+
+ Global.camera.offset.rotated(-Global.camera.rotation) * -y_zoom
4546
)
4647

4748
var proj_size := Global.current_project.size
@@ -51,15 +52,15 @@ func _draw() -> void:
5152
var b := Vector2(proj_size.x, 0).rotated(-Global.camera.rotation) # Top right
5253
var c := Vector2(0, proj_size.y).rotated(-Global.camera.rotation) # Bottom left
5354
var d := Vector2(proj_size.x, proj_size.y).rotated(-Global.camera.rotation) # Bottom right
54-
transform.origin.y += minf(minf(a.y, b.y), minf(c.y, d.y)) * zoom
55+
transform.origin.y += minf(minf(a.y, b.y), minf(c.y, d.y)) * y_zoom
5556

5657
var basic_rule := 100.0
5758
var i := 0
58-
while basic_rule * zoom > 100:
59+
while basic_rule * y_zoom > 100:
5960
basic_rule /= 5.0 if i % 2 else 2.0
6061
i += 1
6162
i = 0
62-
while basic_rule * zoom < 100:
63+
while basic_rule * y_zoom < 100:
6364
basic_rule *= 2.0 if i % 2 else 5.0
6465
i += 1
6566

src/UI/TopMenuContainer/TopMenuContainer.tscn

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,27 @@ script = ExtResource("1")
9191
suffix = "%"
9292
snap_step = 100.0
9393

94+
[node name="VerticalZoomSlider" type="TextureProgressBar" parent="MarginContainer/HBoxContainer/TopLabels"]
95+
unique_name_in_owner = true
96+
custom_minimum_size = Vector2(90, 20)
97+
layout_mode = 2
98+
size_flags_vertical = 4
99+
focus_mode = 2
100+
mouse_default_cursor_shape = 2
101+
theme_type_variation = &"ValueSlider"
102+
min_value = 25.0
103+
max_value = 400.0
104+
value = 100.0
105+
allow_greater = true
106+
nine_patch_stretch = true
107+
stretch_margin_left = 3
108+
stretch_margin_top = 3
109+
stretch_margin_right = 3
110+
stretch_margin_bottom = 3
111+
script = ExtResource("1")
112+
suffix = "V%"
113+
snap_step = 25.0
114+
94115
[node name="CursorPosition" type="Label" parent="MarginContainer/HBoxContainer/TopLabels"]
95116
layout_mode = 2
96117
text = "[64×64]"

0 commit comments

Comments
 (0)