listbox improvements, tabbing while staying in frame (autoscroll)

This commit is contained in:
Mikayla Fischler 2023-10-15 17:02:48 -04:00
parent 43e545b6ae
commit 01caca48dc
3 changed files with 53 additions and 10 deletions

View File

@ -7,7 +7,7 @@ local flasher = require("graphics.flasher")
local core = {}
core.version = "2.0.3"
core.version = "2.0.4"
core.flasher = flasher
core.events = events

View File

@ -105,6 +105,7 @@ function element.new(args, child_offset_x, child_offset_y)
value = nil, ---@type any
window = nil, ---@type table
content_window = nil, ---@type table|nil
mouse_window_shift = { x = 0, y = 0 },
fg_bg = core.cpair(colors.white, colors.black),
frame = core.gframe(1, 1, 1, 1),
children = {},
@ -344,6 +345,10 @@ function element.new(args, child_offset_x, child_offset_y)
-- handle this element having been unfocused
function protected.on_unfocused() end
-- handle this element having had a child focused
---@param child graphics_element
function protected.on_child_focused(child) end
-- handle this element having been shown
function protected.on_shown() end
@ -520,6 +525,13 @@ function element.new(args, child_offset_x, child_offset_y)
else args.parent.__focus_child(child) end
end
-- a child was focused, used to make sure it is actually visible to the user in the content frame
---@param child graphics_element
function public.__child_focused(child)
protected.on_child_focused(child)
if not self.is_root then args.parent.__child_focused(public) end
end
-- get a child element
---@nodiscard
---@param id element_id
@ -652,6 +664,7 @@ function element.new(args, child_offset_x, child_offset_y)
if args.can_focus and protected.enabled and not self.focused then
self.focused = true
protected.on_focused()
if not self.is_root then args.parent.__child_focused(public) end
end
end
@ -704,10 +717,11 @@ function element.new(args, child_offset_x, child_offset_y)
end
local event_T = events.mouse_transposed(event, self.position.x, self.position.y)
-- handle the mouse event then pass to children
protected.handle_mouse(event_T)
for _, child in pairs(protected.children) do child.get().handle_mouse(event_T) end
-- shift child event if the content window has moved then pass to children
local c_event_T = events.mouse_transposed(event_T, protected.mouse_window_shift.x + 1, protected.mouse_window_shift.y + 1)
for _, child in pairs(protected.children) do child.get().handle_mouse(c_event_T) end
elseif event.type == events.MOUSE_CLICK.DOWN or event.type == events.MOUSE_CLICK.TAP then
-- clicked out, unfocus this element and children
public.unfocus_all()

View File

@ -158,6 +158,9 @@ local function listbox(args)
scroll_frame.reposition(1, 1 + scroll_offset)
scroll_frame.setVisible(true)
-- shift mouse events
e.mouse_window_shift.y = scroll_offset
draw_bar()
end
@ -219,6 +222,28 @@ local function listbox(args)
end
end
-- handle a child in the list being focused, make sure it is visible
function e.on_child_focused(child)
for i = 1, #list do
local item = list[i] ---@type listbox_item
if item.e == child then
if (item.y + scroll_offset) <= 0 then
scroll_offset = 1 - item.y
update_positions()
draw_bar()
elseif (item.y + scroll_offset) == 1 then
-- do nothing, it's right at the top (if the bottom doesn't fit we can't easily fix that)
elseif ((item.h + item.y - 1) + scroll_offset) > e.frame.h then
scroll_offset = 1 - ((item.h + item.y) - e.frame.h)
update_positions()
draw_bar()
end
return
end
end
end
-- handle mouse interaction
---@param event mouse_interaction mouse event
function e.handle_mouse(event)
@ -226,23 +251,27 @@ local function listbox(args)
if event.type == MOUSE_CLICK.TAP then
if event.current.x == e.frame.w then
if event.current.y == 1 or event.current.y < bar_bounds[1] then
draw_arrows(1)
scroll_up()
if args.nav_active ~= nil then tcd.dispatch(0.25, function () draw_arrows(0) end) end
if event.current.y == 1 then
draw_arrows(1)
if args.nav_active ~= nil then tcd.dispatch(0.25, function () draw_arrows(0) end) end
end
elseif event.current.y == e.frame.h or event.current.y > bar_bounds[2] then
draw_arrows(-1)
scroll_down()
if args.nav_active ~= nil then tcd.dispatch(0.25, function () draw_arrows(0) end) end
if event.current.y == e.frame.h then
draw_arrows(-1)
if args.nav_active ~= nil then tcd.dispatch(0.25, function () draw_arrows(0) end) end
end
end
end
elseif event.type == MOUSE_CLICK.DOWN then
if event.current.x == e.frame.w then
if event.current.y == 1 or event.current.y < bar_bounds[1] then
draw_arrows(1)
scroll_up()
if event.current.y == 1 then draw_arrows(1) end
elseif event.current.y == e.frame.h or event.current.y > bar_bounds[2] then
draw_arrows(-1)
scroll_down()
if event.current.y == e.frame.h then draw_arrows(-1) end
else
-- clicked on bar
holding_bar = true