From 72d4648ed19f13d99ea7b5d439e991d6db15d131 Mon Sep 17 00:00:00 2001 From: Face <69168154+face-hh@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:41:19 +0300 Subject: [PATCH] element.size, element.position, mouse pos in cb --- docs/docs/lua/elements.md | 69 +++++++++++++++++++++++++++++++- flumi/Scripts/B9/Lua.gd | 58 ++++++++++++++++++++++++++- flumi/Scripts/Utils/Lua/DOM.gd | 54 +++++++++++++++++++++++++ flumi/Scripts/Utils/Lua/Event.gd | 2 +- 4 files changed, 178 insertions(+), 5 deletions(-) diff --git a/docs/docs/lua/elements.md b/docs/docs/lua/elements.md index c03e35b..bcbf8a5 100644 --- a/docs/docs/lua/elements.md +++ b/docs/docs/lua/elements.md @@ -55,6 +55,39 @@ for i = 1, #children do end ``` +### element.size + +Gets the size of an element in pixels. + +```lua +local box = gurt.select('#my-box') +local size = box.size + +trace.log('Width: ' .. size.width .. 'px') +trace.log('Height: ' .. size.height .. 'px') + +if size.width == size.height then + trace.log('Element is square') +end +``` + +### element.position + +Gets the position of an element relative to its parent. + +```lua +local element = gurt.select('#positioned-element') +local pos = element.position + +trace.log('X position: ' .. pos.x .. 'px') +trace.log('Y position: ' .. pos.y .. 'px') + +-- Check if element is at origin +if pos.x == 0 and pos.y == 0 then + trace.log('Element is at origin') +end +``` + ## DOM Traversal ### element.parent @@ -96,11 +129,19 @@ Adds an event listener. Returns a subscription object. local button = gurt.select('#my-button') -- Click event -local subscription = button:on('click', function() - trace.log('Button clicked!') +local subscription = button:on('click', function(event) + trace.log('Button clicked at: ' .. event.x .. ', ' .. event.y) end) -- Mouse events +button:on('mousedown', function(event) + trace.log('Mouse down at: ' .. event.x .. ', ' .. event.y) +end) + +button:on('mouseup', function(event) + trace.log('Mouse up at: ' .. event.x .. ', ' .. event.y) +end) + button:on('mouseenter', function() button.classList:add('hover-effect') end) @@ -128,6 +169,30 @@ end) subscription:unsubscribe() ``` +#### Mouse Event Positioning + +Mouse events (`click`, `mousedown`, `mouseup`) provide position information relative to the element: + +```lua +local element = gurt.select('#interactive-element') + +element:on('click', function(event) + -- event.x and event.y are relative to the element's top-left corner + local elementX = event.x + local elementY = event.y + + trace.log('Clicked at (' .. elementX .. ', ' .. elementY .. ') within element') + + local size = element.size + local pos = element.position + + local xPercent = (elementX / size.width) * 100 + local yPercent = (elementY / size.height) * 100 + + trace.log('Clicked at ' .. xPercent .. '% horizontally, ' .. yPercent .. '% vertically') +end) +``` + ### element:append(childElement) Adds a child element. diff --git a/flumi/Scripts/B9/Lua.gd b/flumi/Scripts/B9/Lua.gd index 8ce5835..ac55130 100644 --- a/flumi/Scripts/B9/Lua.gd +++ b/flumi/Scripts/B9/Lua.gd @@ -359,7 +359,8 @@ func _on_gui_input_click(event: InputEvent, subscription: EventSubscription) -> if event is InputEventMouseButton: var mouse_event = event as InputEventMouseButton if mouse_event.button_index == MOUSE_BUTTON_LEFT and mouse_event.pressed: - _execute_lua_callback(subscription) + var mouse_info = _get_element_relative_mouse_position(mouse_event, subscription.element_id) + _execute_lua_callback(subscription, [mouse_info]) func _on_gui_input_mouse_universal(event: InputEvent, signal_node: Node) -> void: if event is InputEventMouseButton: @@ -376,7 +377,8 @@ func _on_gui_input_mouse_universal(event: InputEvent, signal_node: Node) -> void should_trigger = true if should_trigger: - _execute_lua_callback(subscription) + var mouse_info = _get_element_relative_mouse_position(mouse_event, subscription.element_id) + _execute_lua_callback(subscription, [mouse_info]) # Event callback handlers func _on_gui_input_mousemove(event: InputEvent, subscription: EventSubscription) -> void: @@ -449,6 +451,30 @@ func _input(event: InputEvent) -> void: if subscription.event_name == "mousemove": _handle_mousemove_event(mouse_event, subscription) +func _get_element_relative_mouse_position(mouse_event: InputEvent, element_id: String) -> Dictionary: + var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) + if not dom_node or not dom_node is Control: + return {"x": 0, "y": 0} + + var control = dom_node as Control + var global_pos: Vector2 + + if mouse_event is InputEventMouseButton: + global_pos = (mouse_event as InputEventMouseButton).global_position + elif mouse_event is InputEventMouseMotion: + global_pos = (mouse_event as InputEventMouseMotion).global_position + else: + return {"x": 0, "y": 0} + + var element_rect = control.get_global_rect() + var local_x = global_pos.x - element_rect.position.x + var local_y = global_pos.y - element_rect.position.y + + return { + "x": local_x, + "y": local_y + } + func _handle_mousemove_event(mouse_event: InputEventMouseMotion, subscription: EventSubscription) -> void: # TODO: pass reference instead of hardcoded path var body_container = Engine.get_main_loop().current_scene.website_container @@ -1003,3 +1029,31 @@ func _handle_download_request(operation: Dictionary): var main_node = Engine.get_main_loop().current_scene main_node.download_manager.handle_download_request(download_data) + +func _get_element_size_sync(result: Array, element_id: String): + var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) + if dom_node and dom_node is Control: + var control = dom_node as Control + result[0] = control.size.x + result[1] = control.size.y + result[2] = true # completion flag + return + + # Fallback + result[0] = 0.0 + result[1] = 0.0 + result[2] = true # completion flag + +func _get_element_position_sync(result: Array, element_id: String): + var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) + if dom_node and dom_node is Control: + var control = dom_node as Control + result[0] = control.position.x + result[1] = control.position.y + result[2] = true # completion flag + return + + # Fallback + result[0] = 0.0 + result[1] = 0.0 + result[2] = true # completion flag diff --git a/flumi/Scripts/Utils/Lua/DOM.gd b/flumi/Scripts/Utils/Lua/DOM.gd index 244763a..299162d 100644 --- a/flumi/Scripts/Utils/Lua/DOM.gd +++ b/flumi/Scripts/Utils/Lua/DOM.gd @@ -1054,6 +1054,60 @@ static func _element_index_wrapper(vm: LuauVM) -> int: # Fallback to true (visible by default) vm.lua_pushboolean(true) return 1 + "size": + if lua_api: + vm.lua_getfield(1, "_element_id") + var element_id: String = vm.lua_tostring(-1) + vm.lua_pop(1) + + var dom_node = lua_api.dom_parser.parse_result.dom_nodes.get(element_id, null) + if dom_node and dom_node is Control: + var result = [0.0, 0.0, false] + lua_api.call_deferred("_get_element_size_sync", result, element_id) + while not result[2]: # wait for completion flag + OS.delay_msec(1) + + vm.lua_newtable() + vm.lua_pushnumber(result[0]) + vm.lua_setfield(-2, "width") + vm.lua_pushnumber(result[1]) + vm.lua_setfield(-2, "height") + return 1 + + # Fallback to zero size + vm.lua_newtable() + vm.lua_pushnumber(0) + vm.lua_setfield(-2, "width") + vm.lua_pushnumber(0) + vm.lua_setfield(-2, "height") + return 1 + "position": + if lua_api: + vm.lua_getfield(1, "_element_id") + var element_id: String = vm.lua_tostring(-1) + vm.lua_pop(1) + + var dom_node = lua_api.dom_parser.parse_result.dom_nodes.get(element_id, null) + if dom_node and dom_node is Control: + var result = [0.0, 0.0, false] + lua_api.call_deferred("_get_element_position_sync", result, element_id) + while not result[2]: # wait for completion flag + OS.delay_msec(1) + + vm.lua_newtable() + vm.lua_pushnumber(result[0]) + vm.lua_setfield(-2, "x") + vm.lua_pushnumber(result[1]) + vm.lua_setfield(-2, "y") + return 1 + + # Fallback to zero position + vm.lua_newtable() + vm.lua_pushnumber(0) + vm.lua_setfield(-2, "x") + vm.lua_pushnumber(0) + vm.lua_setfield(-2, "y") + return 1 _: # Check for DOM traversal properties first if lua_api: diff --git a/flumi/Scripts/Utils/Lua/Event.gd b/flumi/Scripts/Utils/Lua/Event.gd index 260925b..2fbcc8e 100644 --- a/flumi/Scripts/Utils/Lua/Event.gd +++ b/flumi/Scripts/Utils/Lua/Event.gd @@ -17,7 +17,7 @@ static func connect_element_event(signal_node: Node, event_name: String, subscri var wrapper = func(): LuaAudioUtils.mark_user_event() LuaDownloadUtils.mark_user_event() - subscription.lua_api._on_event_triggered(subscription) + subscription.lua_api._execute_lua_callback(subscription, [{}]) signal_node.pressed.connect(wrapper) subscription.connected_signal = "pressed" subscription.connected_node = signal_node if signal_node != subscription.lua_api.get_dom_node(signal_node.get_parent(), "signal") else null