Skip to content

Commit a0b96e0

Browse files
committed
Fix scroll_cursor_into_view to work correctly with keyboard arrows.
- Renamed `offset_x_state` and `offset_y_state` to `scroll_x` and `scroll_y`, improving naming clarity and alignment with functionality. - Updated all references across multiple modules (`view_state.v`, `xtra_window.v`, `view_scrollbar.v`, etc.) to use the new variable names. - Refined `scroll_cursor_into_view` logic in `view_text.v` for better readability and scroll offset calculations. - Adjusted stats output in `stats.v` to reflect renamed variables. - Miscellaneous improvements to comments and parameter consistency for scroll handling methods.
1 parent 1a17b03 commit a0b96e0

File tree

7 files changed

+51
-49
lines changed

7 files changed

+51
-49
lines changed

layout.v

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -568,12 +568,12 @@ fn layout_adjust_scroll_offsets(mut layout Layout, mut w Window) {
568568
id_scroll := layout.shape.id_scroll
569569
if id_scroll > 0 {
570570
max_offset_x := f32_min(0, layout.shape.width - layout.shape.padding.width() - content_width(layout))
571-
offset_x := w.view_state.offset_x_state[id_scroll]
572-
w.view_state.offset_x_state[id_scroll] = f32_clamp(offset_x, max_offset_x, 0)
571+
offset_x := w.view_state.scroll_x[id_scroll]
572+
w.view_state.scroll_x[id_scroll] = f32_clamp(offset_x, max_offset_x, 0)
573573

574574
max_offset_y := f32_min(0, layout.shape.height - layout.shape.padding.height() - content_height(layout))
575-
offset_y := w.view_state.offset_y_state[id_scroll]
576-
w.view_state.offset_y_state[id_scroll] = f32_clamp(offset_y, max_offset_y, 0)
575+
offset_y := w.view_state.scroll_y[id_scroll]
576+
w.view_state.scroll_y[id_scroll] = f32_clamp(offset_y, max_offset_y, 0)
577577
}
578578
for mut child in layout.children {
579579
layout_adjust_scroll_offsets(mut child, mut w)
@@ -599,8 +599,8 @@ fn layout_positions(mut layout Layout, offset_x f32, offset_y f32, w &Window) {
599599
mut y := layout.shape.y + padding.top
600600

601601
if layout.shape.id_scroll > 0 {
602-
x += w.view_state.offset_x_state[layout.shape.id_scroll]
603-
y += w.view_state.offset_y_state[layout.shape.id_scroll]
602+
x += w.view_state.scroll_x[layout.shape.id_scroll]
603+
y += w.view_state.scroll_y[layout.shape.id_scroll]
604604
}
605605

606606
// Eventually start/end will be culture dependent

stats.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ fn (vs ViewState) view_state_stats() string {
123123
tx << 'View State'
124124
tx << stat_sub_div
125125
tx << 'input_state length ${cm(usize(vs.input_state.len)):8}'
126-
tx << 'offset_x_state length ${cm(usize(vs.offset_x_state.len)):8}'
127-
tx << 'offset_y_state length ${cm(usize(vs.offset_y_state.len)):8}'
126+
tx << 'scroll_x length ${cm(usize(vs.scroll_x.len)):8}'
127+
tx << 'scroll_y length ${cm(usize(vs.scroll_y.len)):8}'
128128
tx << 'text_widths length ${cm(usize(vs.text_widths.len)):8}'
129129
tx << 'menu_state length ${cm(usize(vs.menu_state.len)):8}'
130130
tx << 'image_map length ${cm(usize(vs.image_map.len)):8}'

view_scrollbar.v

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,14 @@ fn (cfg &ScrollbarCfg) mouse_move(layout &Layout, mut e Event, mut w Window) {
181181
if e.mouse_x >= (ly.shape.x - extend)
182182
&& e.mouse_x <= (ly.shape.x + ly.shape.width + extend) {
183183
offset := offset_mouse_change_x(ly, e.mouse_dx, cfg.id_track, w)
184-
w.view_state.offset_x_state[cfg.id_track] = offset
184+
w.view_state.scroll_x[cfg.id_track] = offset
185185
}
186186
}
187187
else {
188188
if e.mouse_y >= (ly.shape.y - extend)
189189
&& e.mouse_y <= (ly.shape.y + ly.shape.height + extend) {
190190
offset := offset_mouse_change_y(ly, e.mouse_dy, cfg.id_track, w)
191-
w.view_state.offset_y_state[cfg.id_track] = offset
191+
w.view_state.scroll_y[cfg.id_track] = offset
192192
}
193193
}
194194
}
@@ -219,7 +219,7 @@ fn (cfg &ScrollbarCfg) amend_layout(mut layout Layout, mut w Window) {
219219
thumb_width := f32_clamp(t_width, min_thumb_size, layout.shape.width)
220220

221221
available_width := layout.shape.width - thumb_width
222-
scroll_offset := -w.view_state.offset_x_state[cfg.id_track]
222+
scroll_offset := -w.view_state.scroll_x[cfg.id_track]
223223
offset := if available_width == 0 {
224224
0
225225
} else {
@@ -247,7 +247,7 @@ fn (cfg &ScrollbarCfg) amend_layout(mut layout Layout, mut w Window) {
247247
thumb_height := f32_clamp(t_height, min_thumb_size, layout.shape.height)
248248

249249
available_height := layout.shape.height - thumb_height
250-
scroll_offset := -w.view_state.offset_y_state[cfg.id_track]
250+
scroll_offset := -w.view_state.scroll_y[cfg.id_track]
251251
offset := if available_height == 0 {
252252
0
253253
} else {
@@ -307,7 +307,7 @@ fn find_layout_by_id_scroll(layout &Layout, id_scroll u32) ?Layout {
307307
fn offset_mouse_change_x(layout &Layout, mouse_x f32, id_scroll u32, w &Window) f32 {
308308
total_width := content_width(layout)
309309
shape_width := layout.shape.width - layout.shape.padding.width()
310-
old_offset := w.view_state.offset_x_state[id_scroll]
310+
old_offset := w.view_state.scroll_x[id_scroll]
311311
new_offset := mouse_x * (total_width / shape_width)
312312
offset := old_offset - new_offset
313313
return f32_min(0, f32_max(offset, shape_width - total_width))
@@ -327,7 +327,7 @@ fn offset_mouse_change_x(layout &Layout, mouse_x f32, id_scroll u32, w &Window)
327327
fn offset_mouse_change_y(layout &Layout, mouse_y f32, id_scroll u32, w &Window) f32 {
328328
total_height := content_height(layout)
329329
shape_height := layout.shape.height - layout.shape.padding.height()
330-
old_offset := w.view_state.offset_y_state[id_scroll]
330+
old_offset := w.view_state.scroll_y[id_scroll]
331331
new_offset := mouse_y * (total_height / shape_height)
332332
offset := old_offset - new_offset
333333
return f32_min(0, f32_max(offset, shape_height - total_height))
@@ -352,7 +352,7 @@ fn offset_from_mouse_x(layout &Layout, mouse_x f32, id_scroll u32, mut w Window)
352352
if percent >= 0.97 {
353353
percent = 1
354354
}
355-
w.view_state.offset_x_state[id_scroll] = -percent * (total_width - sb.shape.width)
355+
w.view_state.scroll_x[id_scroll] = -percent * (total_width - sb.shape.width)
356356
}
357357
}
358358

@@ -375,7 +375,7 @@ fn offset_from_mouse_y(layout &Layout, mouse_y f32, id_scroll u32, mut w Window)
375375
if percent >= 0.97 {
376376
percent = 1
377377
}
378-
w.view_state.offset_y_state[id_scroll] = -percent * (total_height - sb.shape.height)
378+
w.view_state.scroll_y[id_scroll] = -percent * (total_height - sb.shape.height)
379379
}
380380
}
381381

@@ -393,8 +393,8 @@ fn scroll_horizontal(layout &Layout, delta f32, mut w Window) bool {
393393
if v_id > 0 {
394394
// scrollable region does not including padding
395395
max_offset := f32_min(0, layout.shape.width - layout.shape.padding.width() - content_width(layout))
396-
offset_x := w.view_state.offset_x_state[v_id] + delta * gui_theme.scroll_multiplier
397-
w.view_state.offset_x_state[v_id] = f32_clamp(offset_x, max_offset, 0)
396+
offset_x := w.view_state.scroll_x[v_id] + delta * gui_theme.scroll_multiplier
397+
w.view_state.scroll_x[v_id] = f32_clamp(offset_x, max_offset, 0)
398398
return true
399399
}
400400
return false
@@ -414,8 +414,8 @@ fn scroll_vertical(layout &Layout, delta f32, mut w Window) bool {
414414
if v_id > 0 {
415415
// scrollable region does not including padding
416416
max_offset := f32_min(0, layout.shape.height - layout.shape.padding.height() - content_height(layout))
417-
offset_y := w.view_state.offset_y_state[v_id] + delta * gui_theme.scroll_multiplier
418-
w.view_state.offset_y_state[v_id] = f32_clamp(offset_y, max_offset, 0)
417+
offset_y := w.view_state.scroll_y[v_id] + delta * gui_theme.scroll_multiplier
418+
w.view_state.scroll_y[v_id] = f32_clamp(offset_y, max_offset, 0)
419419
return true
420420
}
421421
return false

view_state.v

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ struct ViewState {
88
mut:
99
input_state map[u32]InputState // [id_focus] -> InputState
1010
input_date_state map[string]bool // [id] -> visible
11-
offset_x_state map[u32]f32 // [id_scroll] -> offset x
12-
offset_y_state map[u32]f32 // [id_scroll] -> offset y
11+
scroll_x map[u32]f32 // [id_scroll] -> scroll offset x
12+
scroll_y map[u32]f32 // [id_scroll] -> scroll offset y
1313
text_widths map[u32]f32 // [text + hash(text_style)] -> text width
1414
mouse_cursor sapp.MouseCursor // arrow, finger, ibeam, etc.
1515
menu_state map[u32]string // [id_menubar] -> id of menu
@@ -28,8 +28,8 @@ fn (mut vs ViewState) clear(mut w Window) {
2828
unsafe {
2929
vs.input_state.free()
3030
vs.input_date_state.free()
31-
vs.offset_x_state.free()
32-
vs.offset_y_state.free()
31+
vs.scroll_x.free()
32+
vs.scroll_y.free()
3333
vs.text_widths.free()
3434
vs.menu_state.free()
3535
vs.image_map.free()

view_text.v

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub:
9696
placeholder_active bool
9797
}
9898

99-
// text is a general purpose text renderer. Use it for labels or larger
99+
// text is a general purpose text view. Use it for labels or larger
100100
// blocks of multiline text. Giving it an id_focus allows mark and copy
101101
// operations. See [TextCfg](#TextCfg)
102102
pub fn text(cfg TextView) View {
@@ -202,7 +202,13 @@ fn (tv &TextView) mouse_move_locked(layout &Layout, mut e Event, mut w Window) {
202202
// scroll container. It calculates the line position of the cursor and
203203
// adjusts the scroll offset if the cursor is outside the current visible
204204
// area.
205-
fn scroll_cursor_into_view(cursor_pos int, layout &Layout, e &Event, mut w Window) {
205+
fn scroll_cursor_into_view(cursor_pos int, layout &Layout, _ &Event, mut w Window) {
206+
// Find the scroll container and calculate height. (need to start at the root layout)
207+
scroll_container := w.layout.find_layout(fn [layout] (ly Layout) bool {
208+
return ly.shape.id_scroll == layout.shape.id_scroll_container
209+
}) or { return }
210+
scroll_view_height := scroll_container.shape.height - scroll_container.shape.padding.height()
211+
206212
// Find the index of the line where the cursor is located.
207213
mut line_idx := 0
208214
mut total_len := 0
@@ -217,29 +223,22 @@ fn scroll_cursor_into_view(cursor_pos int, layout &Layout, e &Event, mut w Windo
217223
// Calculate the y offset of the cursor line.
218224
// Since scroll offsets are often negative (content moves up), use -lh.
219225
lh := line_height(layout.shape)
220-
cursor_offset_y := line_idx * -lh
221-
222-
// Find the scroll container. (need to start at the root layout)
223-
scroll_container := w.layout.find_layout(fn [layout] (ly Layout) bool {
224-
return ly.shape.id_scroll == layout.shape.id_scroll_container
225-
}) or { return }
226-
227-
// Calculate the visible height of the scroll container
228-
scroll_container_height := scroll_container.shape.height - scroll_container.shape.padding.height()
226+
cursor_y := line_idx * -lh
227+
cursor_h_y := cursor_y + scroll_view_height - lh
229228

230-
// Determine the bottom boundary relative to the cursor
231-
scroll_offset_yb := cursor_offset_y + scroll_container_height
229+
// Calculate scroll offsets for current visible region
230+
current_scroll_y := w.view_state.scroll_y[layout.shape.id_scroll_container]
231+
current_scroll_h_y := current_scroll_y - scroll_view_height
232232

233233
// Determine if we need to scroll:
234-
// 1. If cursor is above the current view and trying to go up (mouse_dy < 0)
235-
// 2. If cursor is below the current view and trying to go down (mouse_dy > 0)
236-
current_scroll_offset_y := w.view_state.offset_y_state[layout.shape.id_scroll_container]
237-
new_scroll_offset := match true {
238-
cursor_offset_y > current_scroll_offset_y && e.mouse_dy < 0 { cursor_offset_y }
239-
scroll_offset_yb < current_scroll_offset_y && e.mouse_dy > 0 { scroll_offset_yb }
240-
else { return }
234+
// 1. If cursor is above the current view
235+
// 2. If cursor is below the current view
236+
new_scroll_y := match true {
237+
cursor_y > current_scroll_y { cursor_y }
238+
cursor_y <= current_scroll_h_y { cursor_h_y }
239+
else { current_scroll_y }
241240
}
242-
w.scroll_vertical_to(layout.shape.id_scroll_container, new_scroll_offset)
241+
w.scroll_vertical_to(layout.shape.id_scroll_container, new_scroll_y)
243242
}
244243

245244
fn view_text_mouse_up(layout &Layout, mut e Event, mut w Window) {

window.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ fn event_fn(ev &gg.Event, mut w Window) {
169169
// An Event is processed until an event handler sets the event.is_handled`
170170
// member to true.
171171
w.lock()
172+
172173
// layout is not modified else where at this point in the life cycle.
173174
// Locks in V do not nest, which is why unlock() is called immediately after
174175
// acquiring the layout. This allows event handlers to lock the window to
@@ -260,6 +261,8 @@ pub fn (mut window Window) update_window() {
260261
gui_stats.update_max_renderers(usize(window.renderers.len))
261262
}
262263

264+
// Technically, clearing views and layouts should not be needed,
265+
// but it appears to help the GC in some instances.
263266
clear_views(mut view)
264267
clear_layouts(mut old_layout)
265268
window.ui.refresh_ui()

xtra_window.v

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,25 +182,25 @@ fn (mut window Window) update_window_size() {
182182
// scroll_horizontal_by scrolls the given scrollable by delta.
183183
// Use update_window() if not called from event handler
184184
pub fn (mut window Window) scroll_horizontal_by(id_scroll u32, delta f32) {
185-
window.view_state.offset_x_state[id_scroll] += delta
185+
window.view_state.scroll_x[id_scroll] += delta
186186
}
187187

188188
// scroll_horizontal_to scrolls the given scrollable to the offset. offset is negative.
189189
// Use update_window() if not called from event handler
190190
pub fn (mut window Window) scroll_horizontal_to(id_scroll u32, offset f32) {
191-
window.view_state.offset_x_state[id_scroll] = offset
191+
window.view_state.scroll_x[id_scroll] = offset
192192
}
193193

194194
// scroll_vertical_by scrolls the given scrollable by delta.
195195
// Use update_window() if not called from event handler
196196
pub fn (mut window Window) scroll_vertical_by(id_scroll u32, delta f32) {
197-
window.view_state.offset_y_state[id_scroll] += delta
197+
window.view_state.scroll_y[id_scroll] += delta
198198
}
199199

200200
// scroll_vertical_to scrolls the given scrollable to the offset. offset is negative.
201201
// Use update_window() if not called from event handler
202202
pub fn (mut window Window) scroll_vertical_to(id_scroll u32, offset f32) {
203-
window.view_state.offset_y_state[id_scroll] = offset
203+
window.view_state.scroll_y[id_scroll] = offset
204204
}
205205

206206
// set_id_focus sets the window's focus id.

0 commit comments

Comments
 (0)