From 83031f9516fd5004e1433c9d10edd1d06f3f8ba0 Mon Sep 17 00:00:00 2001 From: laelnasan Date: Thu, 19 Nov 2020 13:44:04 -0300 Subject: [PATCH] mouseable views --- src/ltui/action.lua | 1 + src/ltui/application.lua | 10 +++++++++- src/ltui/boxdialog.lua | 30 ++++++++++++++++++++++++++++++ src/ltui/button.lua | 17 +++++++++++++++++ src/ltui/panel.lua | 36 ++++++++++++++++++++++++++++++++++++ src/ltui/program.lua | 1 + 6 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/ltui/action.lua b/src/ltui/action.lua index 20618a7..82a90b6 100644 --- a/src/ltui/action.lua +++ b/src/ltui/action.lua @@ -40,6 +40,7 @@ end action:register("ac_max", "ac_on_text_changed", "ac_on_selected", + "ac_on_clicked", "ac_on_resized", "ac_on_enter", "ac_on_load", diff --git a/src/ltui/application.lua b/src/ltui/application.lua index 54085af..04c7f92 100644 --- a/src/ltui/application.lua +++ b/src/ltui/application.lua @@ -85,7 +85,15 @@ end -- on event function application:on_event(e) - program.on_event(self, e) + if (not program.on_event(self, e)) and curses.KEY_MOUSE then + + -- mouse events + if e.type == ltui.event.ev_mouse and ( + e.btn_name == "BUTTON1_CLICKED" or + e.btn_name == "BUTTON1_DOUBLE_CLICKED") then + self:action_on(ltui.action.ac_on_clicked, e.x, e.y) + end + end end -- on resize diff --git a/src/ltui/boxdialog.lua b/src/ltui/boxdialog.lua index 1b1be6c..d9ab03f 100644 --- a/src/ltui/boxdialog.lua +++ b/src/ltui/boxdialog.lua @@ -64,6 +64,36 @@ function boxdialog:init(name, bounds, title) self:text():bounds().ey = self._TEXT_EY self:box():bounds_set(rect{0, self._TEXT_EY, v:width(), v:height() - 1}) end) + + if curses.KEY_MOUSE then + + -- set click action + self:frame():action_set(ltui.action.ac_on_clicked, function (v, x, y) + + -- return if not mouseable + if not v:option("mouseable") then + return + end + + -- get relative coordinates + x, y = x - v:bounds().sx, y - v:bounds().sy + + local panel, box = v:parent():panel(), v:parent():box() + local px, py = x - panel:bounds().sx, y - panel:bounds().sy + + -- if coordinates don't match any view try box + if panel:action_on(ltui.action.ac_on_clicked, x, y) and + (not box:option("selectable")) and + box:bounds():contains(px, py) then + + -- bypass panel + return box:action_on(ltui.action.ac_on_clicked, px, py) + end + + -- return true if it doesn't match any selectable view + return true + end) + end end -- get box diff --git a/src/ltui/button.lua b/src/ltui/button.lua index 56ae916..ca688d9 100644 --- a/src/ltui/button.lua +++ b/src/ltui/button.lua @@ -38,6 +38,23 @@ function button:init(name, bounds, text, on_action) -- mark as selectable self:option_set("selectable", true) + -- mark as mouseable + self:option_set("mouseable", true) + + -- set click action + self:action_set(ltui.action.ac_on_clicked, function (v) + + -- return if not mouseable + if not v:option("mouseable") then + return + end + + if v:parent()._do_select then + return v:parent():_do_select() + end + return v:action_on(ltui.action.ac_on_enter) + end) + -- show cursor self:cursor_show(true) diff --git a/src/ltui/panel.lua b/src/ltui/panel.lua index e830702..d105287 100644 --- a/src/ltui/panel.lua +++ b/src/ltui/panel.lua @@ -26,6 +26,7 @@ local event = require("ltui/event") local point = require("ltui/point") local curses = require("ltui/curses") local dlist = require("ltui/base/dlist") +local action = require("ltui/action") -- define module local panel = panel or view() @@ -47,6 +48,41 @@ function panel:init(name, bounds) -- init views cache self._VIEWS_CACHE = {} + + if curses.KEY_MOUSE then + + -- mark as mouseable + self:option_set("mouseable", true) + + -- set click action + self:action_set(action.ac_on_clicked, function (v, x, y) + + -- return if not clickable + if not v:option("mouseable") then + return + end + + -- get relative coordinates + x, y = x - v:bounds().sx, y - v:bounds().sy + + -- try focused first + if v:current() and v:current():bounds():contains(x, y) then + return v:current():action_on(ltui.action.ac_on_clicked, x, y) + end + + local p = v:last() + while p do + if p:option('selectable') and p:bounds():contains(x, y) then + v:select(p) + return p:action_on(action.ac_on_clicked, x, y) + end + p = v:prev(p) + end + + -- return true if does not match any selectable view + return true + end) + end end -- get all child views diff --git a/src/ltui/program.lua b/src/ltui/program.lua index 7046274..61e90c2 100644 --- a/src/ltui/program.lua +++ b/src/ltui/program.lua @@ -46,6 +46,7 @@ function program:init(name, argv) -- init mouse support if curses.KEY_MOUSE then + -- curses.ALL_MOUSE_EVENTS may be set to mask unused events curses.mousemask(curses.ALL_MOUSE_EVENTS) end