diff options
| author | ruki <[email protected]> | 2020-05-07 22:45:25 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2020-05-07 10:32:31 +0800 |
| commit | ca238c29d3e14b0c72787b47588b979356dd9410 (patch) | |
| tree | accec9b30f7b057b9bfbf9cf9e5985d5060232db | |
| parent | 5d22635894f2b19f49441e0671ac0eb1b1da9c17 (diff) | |
update ui
| -rw-r--r-- | core/src/lcurses/lcurses.c | 12 | ||||
| -rw-r--r-- | tests/ui/desktop.lua | 16 | ||||
| -rw-r--r-- | tests/ui/dialog.lua | 109 | ||||
| -rw-r--r-- | tests/ui/inputdialog.lua | 28 | ||||
| -rw-r--r-- | tests/ui/mconfdialog.lua | 35 | ||||
| -rw-r--r-- | tests/ui/window.lua | 20 | ||||
| -rw-r--r-- | xmake/core/ui/action.lua | 1 | ||||
| -rw-r--r-- | xmake/core/ui/application.lua | 12 | ||||
| -rw-r--r-- | xmake/core/ui/border.lua | 8 | ||||
| -rw-r--r-- | xmake/core/ui/boxdialog.lua | 29 | ||||
| -rw-r--r-- | xmake/core/ui/button.lua | 6 | ||||
| -rw-r--r-- | xmake/core/ui/choicebox.lua | 2 | ||||
| -rw-r--r-- | xmake/core/ui/choicedialog.lua | 8 | ||||
| -rw-r--r-- | xmake/core/ui/dialog.lua | 41 | ||||
| -rw-r--r-- | xmake/core/ui/inputdialog.lua | 5 | ||||
| -rw-r--r-- | xmake/core/ui/label.lua | 4 | ||||
| -rw-r--r-- | xmake/core/ui/mconfdialog.lua | 45 | ||||
| -rw-r--r-- | xmake/core/ui/menuconf.lua | 2 | ||||
| -rw-r--r-- | xmake/core/ui/panel.lua | 62 | ||||
| -rw-r--r-- | xmake/core/ui/program.lua | 54 | ||||
| -rw-r--r-- | xmake/core/ui/textarea.lua | 6 | ||||
| -rw-r--r-- | xmake/core/ui/textdialog.lua | 12 | ||||
| -rw-r--r-- | xmake/core/ui/textedit.lua | 8 | ||||
| -rw-r--r-- | xmake/core/ui/view.lua | 76 | ||||
| -rw-r--r-- | xmake/core/ui/window.lua | 22 |
25 files changed, 425 insertions, 198 deletions
diff --git a/core/src/lcurses/lcurses.c b/core/src/lcurses/lcurses.c index 822bd3cf8..4844dd000 100644 --- a/core/src/lcurses/lcurses.c +++ b/core/src/lcurses/lcurses.c @@ -72,6 +72,10 @@ Notes: #include <curses.h> #include <signal.h> +#if defined(NCURSES_VERSION) +#include <locale.h> +#endif + #if defined(PDCURSES) && (PDC_BUILD < 3100) # error Please upgrade to PDCurses 3.1 or later #endif @@ -2345,6 +2349,14 @@ int xm_curses_register (lua_State *L) lua_pushcclosure(L, lc_initscr, 1); lua_settable(L, -3); + /* Since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function. + * That means that you have to call setlocale() in the application and encode Unicode strings using one of the system’s available encodings. + * + * And we need link libncursesw.so for drawing vline, hline characters + */ +#if defined(NCURSES_VERSION) + setlocale(LC_ALL, ""); +#endif return 1; } diff --git a/tests/ui/desktop.lua b/tests/ui/desktop.lua index 6f4cda6aa..cc5881abf 100644 --- a/tests/ui/desktop.lua +++ b/tests/ui/desktop.lua @@ -16,7 +16,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- Copyright (C) 2015 - 2019, TBOOX Open Source Group. +-- Copyright (C) 2015-2020, TBOOX Open Source Group. -- -- @author ruki -- @file desktop.lua @@ -49,7 +49,7 @@ function demo:init() self:menubar():title():text_set("Menu Bar (Hello)") -- add title label - self:desktop():insert(label:new("title", rect {0, 0, 12, 1}, "hello xmake!"):textattr_set("white"), {centerx = true}) + self:desktop():insert(label:new("title", rect {0, 0, 12, 1}, "hello ltui!"):textattr_set("white"), {centerx = true}) -- add yes button self:desktop():insert(button:new("yes", rect {0, 1, 7, 2}, "< Yes >"):textattr_set("white"), {centerx = true}) @@ -59,8 +59,8 @@ function demo:init() end -- on event -function demo:event_on(e) - if application.event_on(self, e) then +function demo:on_event(e) + if application.on_event(self, e) then return true end if e.type == event.ev_keyboard then @@ -75,6 +75,14 @@ function demo:event_on(e) end end +-- on resize +function demo:on_resize() + for v in self:desktop():views() do + self:center(v, {centerx = true}) + end + application.on_resize(self) +end + -- main entry function main(...) demo:run(...) diff --git a/tests/ui/dialog.lua b/tests/ui/dialog.lua index 7a052cbf5..fa9bcf7d6 100644 --- a/tests/ui/dialog.lua +++ b/tests/ui/dialog.lua @@ -16,7 +16,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- Copyright (C) 2015 - 2019, TBOOX Open Source Group. +-- Copyright (C) 2015-2020, TBOOX Open Source Group. -- -- @author ruki -- @file dialog.lua @@ -45,39 +45,90 @@ function demo:init() -- init background self:background_set("blue") - -- init help dialog - local dialog_help = textdialog:new("dialog.help", rect {1, 1, self:width() - 1, self:height() - 1}, "README") - dialog_help:text():text_set(io.readfile(path.join(os.scriptdir(), "dialog.lua"))) - dialog_help:button_add("exit", "< Exit >", function (v) self:remove(dialog_help) end) - -- init main dialog - local dialog_main = boxdialog:new("dialog.main", rect {1, 1, self:width() - 1, self:height() - 1}, "main dialog") - dialog_main:text():text_set("The project focuses on making development and building easier and provides many features (e.g. package, install, plugin, macro, action, option, task ...), so that any developer can quickly pick it up and enjoy the productivity boost when developing and building project.") - dialog_main:button_add("tips", "< Tips >", function (v) self:view("dialog.tips"):show(true, {focused = true}) end) - dialog_main:button_add("input", "< Input >", function (v) self:view("dialog.input"):show(true, {focused = true}) end) - dialog_main:button_add("help", "< Help >", function (v) self:insert(dialog_help) end) - dialog_main:button_add("quit", "< Quit >", "cm_quit") - self:insert(dialog_main) + self:insert(self:dialog_main()) -- init input dialog - local dialog_input = inputdialog:new("dialog.input", rect {0, 0, 50, 8}):background_set(dialog_main:frame():background()) - dialog_input:frame():background_set("cyan") - dialog_input:text():text_set("please input text:"):textattr_set("red") - dialog_input:button_add("no", "< No >", function (v) dialog_input:show(false) end) - dialog_input:button_add("yes", "< Yes >", function (v) - dialog_main:text():text_set(dialog_input:textedit():text()) - dialog_input:show(false) - end) - self:insert(dialog_input, {centerx = true, centery = true}) - dialog_input:show(false) + self:insert(self:dialog_input(), {centerx = true, centery = true}) -- init tips dialog - local dialog_tips = textdialog:new("dialog.tips", rect {0, 0, 50, 8}):background_set(dialog_main:frame():background()) - dialog_tips:frame():background_set("cyan") - dialog_tips:text():text_set("hello xmake! (http://xmake.io)\nA cross-platform build utility based on Lua"):textattr_set("red") - dialog_tips:button_add("yes", "< Yes >", function (v) dialog_tips:show(false) end) - dialog_tips:button_add("no", "< No >", function (v) dialog_tips:show(false) end) - self:insert(dialog_tips, {centerx = true, centery = true}) + self:insert(self:dialog_tips(), {centerx = true, centery = true}) +end + +-- main dialog +function demo:dialog_main() + local dialog_main = self._DIALOG_MAIN + if not dialog_main then + dialog_main = boxdialog:new("dialog.main", rect {1, 1, self:width() - 1, self:height() - 1}, "main dialog") + dialog_main:text():text_set("The project focuses on making development and building easier and provides many features (.e.g package, install, plugin, macro, action, option, task ...), so that any developer can quickly pick it up and enjoy the productivity boost when developing and building project.") + dialog_main:button_add("tips", "< Tips >", function (v) self:view("dialog.tips"):show(true, {focused = true}) end) + dialog_main:button_add("input", "< Input >", function (v) self:view("dialog.input"):show(true, {focused = true}) end) + dialog_main:button_add("help", "< Help >", function (v) self:insert(self:dialog_help()) end) + dialog_main:button_add("quit", "< Quit >", "cm_quit") + self._DIALOG_MAIN = dialog_main + end + return dialog_main +end + +-- help dialog +function demo:dialog_help() + local dialog_help = self._DIALOG_HELP + if not dialog_help then + dialog_help = textdialog:new("dialog.help", rect {1, 1, self:width() - 1, self:height() - 1}, "README") + local helptext = nil + local file = io.open("./LICENSE.md", 'r') + if file then + helptext = file:read("*a") + file:close() + end + if helptext then + dialog_help:text():text_set(helptext) + end + dialog_help:button_add("exit", "< Exit >", function (v) self:remove(dialog_help) end) + self._DIALOG_HELP = dialog_help + end + return dialog_help +end + +-- input dialog +function demo:dialog_input() + local dialog_input = self._DIALOG_INPUT + if not dialog_input then + dialog_input = inputdialog:new("dialog.input", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background()) + dialog_input:frame():background_set("cyan") + dialog_input:text():text_set("please input text:"):textattr_set("red") + dialog_input:button_add("no", "< No >", function (v) dialog_input:show(false) end) + dialog_input:button_add("yes", "< Yes >", function (v) + self:dialog_main():text():text_set(dialog_input:textedit():text()) + dialog_input:show(false) + end) + dialog_input:show(false) + self._DIALOG_INPUT = dialog_input + end + return dialog_input +end + +-- tips dialog +function demo:dialog_tips() + local dialog_tips = self._DIALOG_TIPS + if not dialog_tips then + dialog_tips = textdialog:new("dialog.tips", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background()) + dialog_tips:frame():background_set("cyan") + dialog_tips:text():text_set("hello ltui! (https://tboox.org)\nA cross-platform terminal ui library based on Lua"):textattr_set("red") + dialog_tips:button_add("yes", "< Yes >", function (v) dialog_tips:show(false) end) + dialog_tips:button_add("no", "< No >", function (v) dialog_tips:show(false) end) + self._DIALOG_TIPS = dialog_tips + end + return dialog_tips +end + +-- on resize +function demo:on_resize() + self:dialog_main():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) + self:dialog_help():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) + self:center(self:dialog_input(), {centerx = true, centery = true}) + self:center(self:dialog_tips(), {centerx = true, centery = true}) + application.on_resize(self) end -- main entry diff --git a/tests/ui/inputdialog.lua b/tests/ui/inputdialog.lua index 85cdc8229..56ef2880b 100644 --- a/tests/ui/inputdialog.lua +++ b/tests/ui/inputdialog.lua @@ -16,7 +16,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- Copyright (C) 2015 - 2019, TBOOX Open Source Group. +-- Copyright (C) 2015-2020, TBOOX Open Source Group. -- -- @author ruki -- @file inputdialog.lua @@ -44,11 +44,27 @@ function demo:init() self:background_set("blue") -- init input dialog - local dialog_input = inputdialog:new("dialog.input", rect {0, 0, 50, 8}) - dialog_input:text():text_set("please input text:") - dialog_input:button_add("no", "< No >", function (v) dialog_input:quit() end) - dialog_input:button_add("yes", "< Yes >", function (v) dialog_input:quit() end) - self:insert(dialog_input, {centerx = true, centery = true}) + self:insert(self:dialog_input(), {centerx = true, centery = true}) +end + +-- input dialog +function demo:dialog_input() + local dialog_input = self._DIALOG_INPUT + if not dialog_input then + dialog_input = inputdialog:new("dialog.input", rect{0, 0, math.floor(self:width() / 2), math.floor(self:height() / 3)}) + dialog_input:text():text_set("please input text:") + dialog_input:button_add("no", "< No >", function (v) dialog_input:quit() end) + dialog_input:button_add("yes", "< Yes >", function (v) dialog_input:quit() end) + self._DIALOG_INPUT = dialog_input + end + return dialog_input +end + +-- on resize +function demo:on_resize() + self:dialog_input():bounds_set(rect{0, 0, math.floor(self:width() / 2), math.floor(self:height() / 3)}) + self:center(self:dialog_input(), {centerx = true, centery = true}) + application.on_resize(self) end -- main entry diff --git a/tests/ui/mconfdialog.lua b/tests/ui/mconfdialog.lua index 6394fa91e..15c6f1707 100644 --- a/tests/ui/mconfdialog.lua +++ b/tests/ui/mconfdialog.lua @@ -16,7 +16,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- Copyright (C) 2015 - 2019, TBOOX Open Source Group. +-- Copyright (C) 2015-2020, TBOOX Open Source Group. -- -- @author ruki -- @file mconfdialog.lua @@ -71,16 +71,29 @@ function demo:init() table.insert(configs, menuconf.choice {value = 3, values = {1, 5, 6, 7}, description = "choice config item"}) -- init menu config dialog - local mconfdialog = mconfdialog:new("mconfdialog.main", rect {1, 1, self:width() - 1, self:height() - 1}, "menu config") - mconfdialog:load(configs) - mconfdialog:action_set(action.ac_on_exit, function (v) self:quit() end) - mconfdialog:action_set(action.ac_on_save, function (v) - for _, config in ipairs(configs) do - log:print("%s", config) - end - mconfdialog:quit() - end) - self:insert(mconfdialog) + self:dialog_mconf():load(configs) + self:insert(self:dialog_mconf()) +end + +-- get mconfdialog +function demo:dialog_mconf() + local dialog_mconf = self._DIALOG_MCONF + if not dialog_mconf then + dialog_mconf = mconfdialog:new("mconfdialog.main", rect{1, 1, self:width() - 1, self:height() - 1}, "menu config") + dialog_mconf:action_set(action.ac_on_exit, function (v) self:quit() end) + dialog_mconf:action_set(action.ac_on_save, function (v) + -- TODO save configs + dialog_mconf:quit() + end) + self._DIALOG_MCONF = dialog_mconf + end + return dialog_mconf +end + +-- on resize +function demo:on_resize() + self:dialog_mconf():bounds_set(rect{1, 1, self:width() - 1, self:height() - 1}) + application.on_resize(self) end -- main entry diff --git a/tests/ui/window.lua b/tests/ui/window.lua index f726e6715..ca1f7e2bd 100644 --- a/tests/ui/window.lua +++ b/tests/ui/window.lua @@ -16,7 +16,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- Copyright (C) 2015 - 2019, TBOOX Open Source Group. +-- Copyright (C) 2015-2020, TBOOX Open Source Group. -- -- @author ruki -- @file window.lua @@ -43,8 +43,22 @@ function demo:init() -- init background self:background_set("blue") - -- init main window - self:insert(window:new("window.main", rect {1, 1, self:width() - 1, self:height() - 1}, "main window", true)) + -- init body window + self:insert(self:body_window()) +end + +-- get body window +function demo:body_window() + if not self._BODY_WINDOW then + self._BODY_WINDOW = window:new("window.body", rect {1, 1, self:width() - 1, self:height() - 1}, "main window", true) + end + return self._BODY_WINDOW +end + +-- on resize +function demo:on_resize() + self:body_window():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1}) + application.on_resize(self) end -- main entry diff --git a/xmake/core/ui/action.lua b/xmake/core/ui/action.lua index e50f4388e..6df11a559 100644 --- a/xmake/core/ui/action.lua +++ b/xmake/core/ui/action.lua @@ -40,6 +40,7 @@ end action:register("ac_max", "ac_on_text_changed", "ac_on_selected", + "ac_on_resized", "ac_on_enter", "ac_on_load", "ac_on_save", diff --git a/xmake/core/ui/application.lua b/xmake/core/ui/application.lua index e4f17167b..169b08fdd 100644 --- a/xmake/core/ui/application.lua +++ b/xmake/core/ui/application.lua @@ -85,8 +85,16 @@ function application:statusbar() end -- on event -function application:event_on(e) - program.event_on(self, e) +function application:on_event(e) + program.on_event(self, e) +end + +-- on resize +function application:on_resize() + self:menubar():bounds_set(rect{0, 0, self:width(), 1}) + self:desktop():bounds_set(rect{0, 1, self:width(), self:height() - 1}) + self:statusbar():bounds_set(rect{0, self:height() - 1, self:width(), self:height()}) + program.on_resize(self) end -- run application diff --git a/xmake/core/ui/border.lua b/xmake/core/ui/border.lua index de4bbcb64..2f70d0a6b 100644 --- a/xmake/core/ui/border.lua +++ b/xmake/core/ui/border.lua @@ -39,10 +39,10 @@ function border:init(name, bounds) end -- draw border -function border:draw(transparent) +function border:on_draw(transparent) -- draw background (transparent) - view.draw(self, true) + view.on_draw(self, true) -- get corner attribute local cornerattr = self:cornerattr() @@ -50,13 +50,13 @@ function border:draw(transparent) -- the left-upper attribute local attr_ul = curses.color_pair(cornerattr[1], self:background()) if self:background() == cornerattr[1] then - attr_ul = {attr_ul, "standout"} + attr_ul = {attr_ul, "bold"} end -- the right-lower attribute local attr_rl = curses.color_pair(cornerattr[2], self:background()) if self:background() == cornerattr[2] then - attr_rl = {attr_rl, "standout"} + attr_rl = {attr_rl, "bold"} end -- the border characters diff --git a/xmake/core/ui/boxdialog.lua b/xmake/core/ui/boxdialog.lua index 60971995f..ec92a0d2f 100644 --- a/xmake/core/ui/boxdialog.lua +++ b/xmake/core/ui/boxdialog.lua @@ -35,40 +35,51 @@ function boxdialog:init(name, bounds, title) -- init window textdialog.init(self, name, bounds, title) - -- insert box - self:panel():insert(self:box()) - -- resize text - self:text():bounds().ey = 3 + self._TEXT_EY = 3 + self:text():bounds().ey = self._TEXT_EY self:text():invalidate(true) self:text():option_set("selectable", false) self:text():option_set("progress", false) + -- insert box + self:panel():insert(self:box()) + -- text changed self:text():action_set(action.ac_on_text_changed, function (v) if v:text() then local lines = #self:text():splitext(v:text()) if lines > 0 and lines < self:height() then - self:box():bounds().sy = lines - self:text():bounds().ey = lines - self:box():invalidate(true) - self:text():invalidate(true) + self._TEXT_EY = lines + self:panel():invalidate(true) end end end) -- select buttons by default self:panel():select(self:buttons()) + + -- on resize for panel + self:panel():action_add(action.ac_on_resized, function (v) + self:text():bounds().ey = self._TEXT_EY + self:box():bounds_set(rect{0, self._TEXT_EY, v:width(), v:height() - 1}) + end) end -- get box function boxdialog:box() if not self._BOX then - self._BOX = window:new("boxdialog.box", rect{0, 3, self:panel():width(), self:panel():height() - 1}) + self._BOX = window:new("boxdialog.box", rect{0, self._TEXT_EY, self:panel():width(), self:panel():height() - 1}) self._BOX:border():cornerattr_set("black", "white") end return self._BOX end +-- on resize +function boxdialog:on_resize() + self:text():text_set(self:text():text()) + textdialog.on_resize(self) +end + -- return module return boxdialog diff --git a/xmake/core/ui/button.lua b/xmake/core/ui/button.lua index 5079efdf7..484b5cc89 100644 --- a/xmake/core/ui/button.lua +++ b/xmake/core/ui/button.lua @@ -46,10 +46,10 @@ function button:init(name, bounds, text, on_action) end -- draw button -function button:draw(transparent) +function button:on_draw(transparent) -- draw background - view.draw(self, transparent) + view.on_draw(self, transparent) -- strip text string local str = self:text() @@ -73,7 +73,7 @@ function button:draw(transparent) end -- on event -function button:event_on(e) +function button:on_event(e) -- selected? if not self:state("selected") then diff --git a/xmake/core/ui/choicebox.lua b/xmake/core/ui/choicebox.lua index c7e8f8bc8..89b0cddae 100644 --- a/xmake/core/ui/choicebox.lua +++ b/xmake/core/ui/choicebox.lua @@ -43,7 +43,7 @@ function choicebox:init(name, bounds) end -- on event -function choicebox:event_on(e) +function choicebox:on_event(e) -- select config if e.type == event.ev_keyboard then diff --git a/xmake/core/ui/choicedialog.lua b/xmake/core/ui/choicedialog.lua index c9b527785..da959e458 100644 --- a/xmake/core/ui/choicedialog.lua +++ b/xmake/core/ui/choicedialog.lua @@ -42,7 +42,7 @@ function choicedialog:init(name, bounds, title) -- init buttons self:button_add("select", "< Select >", function (v, e) - self:choicebox():event_on(event.command {"cm_enter"}) + self:choicebox():on_event(event.command {"cm_enter"}) self:quit() end) self:button_add("cancel", "< Cancel >", function (v, e) @@ -68,7 +68,7 @@ function choicedialog:choicebox() end -- on event -function choicedialog:event_on(e) +function choicedialog:on_event(e) -- load values first if e.type == event.ev_idle then @@ -79,10 +79,10 @@ function choicedialog:event_on(e) -- select value elseif e.type == event.ev_keyboard then if e.key_name == "Down" or e.key_name == "Up" or e.key_name == " " then - return self:choicebox():event_on(e) + return self:choicebox():on_event(e) end end - return boxdialog.event_on(self, e) + return boxdialog.on_event(self, e) end -- return module diff --git a/xmake/core/ui/dialog.lua b/xmake/core/ui/dialog.lua index cab9ff067..499c6ad1f 100644 --- a/xmake/core/ui/dialog.lua +++ b/xmake/core/ui/dialog.lua @@ -32,6 +32,25 @@ local curses = require("ui/curses") -- define module local dialog = dialog or window() +-- update the position of all buttons +function dialog:_update_buttons_layout() + + -- update the position of all buttons + local index = 1 + local width = self:buttons():width() + local count = self:buttons():count() + local padding = math.floor(width / 8) + for v in self:buttons():views() do + local x = padding + index * math.floor((width - padding * 2) / (count + 1)) - math.floor(v:width() / 2) + if x + v:width() > width then + x = math.max(0, width - v:width()) + end + v:bounds():move2(x, 0) + v:invalidate(true) + index = index + 1 + end +end + -- init dialog function dialog:init(name, bounds, title) @@ -40,6 +59,10 @@ function dialog:init(name, bounds, title) -- insert buttons self:panel():insert(self:buttons()) + self:panel():action_add(action.ac_on_resized, function (v) + self:buttons():bounds_set(rect:new(0, v:height() - 1, v:width(), 1)) + self:_update_buttons_layout() + end) end -- get buttons @@ -65,19 +88,7 @@ function dialog:button_add(name, text, command) self:buttons():insert(btn) -- update the position of all buttons - local index = 1 - local width = self:buttons():width() - local count = self:buttons():count() - local padding = math.floor(width / 8) - for v in self:buttons():views() do - local x = padding + index * math.floor((width - padding * 2) / (count + 1)) - math.floor(v:width() / 2) - if x + v:width() > width then - x = math.max(0, width - v:width()) - end - v:bounds():move2(x, 0) - v:invalidate(true) - index = index + 1 - end + self:_update_buttons_layout() -- invalidate self:invalidate() @@ -102,12 +113,12 @@ function dialog:quit() end -- on event -function dialog:event_on(e) +function dialog:on_event(e) if e.type == event.ev_keyboard and e.key_name == "Esc" then self:quit() return true end - return window.event_on(self, e) + return window.on_event(self, e) end -- return module diff --git a/xmake/core/ui/inputdialog.lua b/xmake/core/ui/inputdialog.lua index 64bd533a3..8da3e7c6a 100644 --- a/xmake/core/ui/inputdialog.lua +++ b/xmake/core/ui/inputdialog.lua @@ -59,6 +59,11 @@ function inputdialog:init(name, bounds, title) end end end) + + -- on resize for panel + self:panel():action_add(action.ac_on_resized, function (v) + self:textedit():bounds_set(rect{0, 1, v:width(), v:height() - 1}) + end) end -- get textedit diff --git a/xmake/core/ui/label.lua b/xmake/core/ui/label.lua index 4cb72802d..47c2db0eb 100644 --- a/xmake/core/ui/label.lua +++ b/xmake/core/ui/label.lua @@ -42,10 +42,10 @@ function label:init(name, bounds, text) end -- draw view -function label:draw(transparent) +function label:on_draw(transparent) -- draw background - view.draw(self, transparent) + view.on_draw(self, transparent) -- get the text attribute value local textattr = self:textattr_val() diff --git a/xmake/core/ui/mconfdialog.lua b/xmake/core/ui/mconfdialog.lua index cfdf9ef9c..6dbe0fd5c 100644 --- a/xmake/core/ui/mconfdialog.lua +++ b/xmake/core/ui/mconfdialog.lua @@ -19,6 +19,7 @@ -- -- load modules +local table = require("base/table") local log = require("ui/log") local rect = require("ui/rect") local event = require("ui/event") @@ -46,8 +47,8 @@ Pressing <Y> includes, <N> excludes. Enter <Esc> or <Back> to go back, <?> for H ]]) -- init buttons - self:button_add("select", "< Select >", function (v, e) self:menuconf():event_on(event.command {"cm_enter"}) end) - self:button_add("back", "< Back >", function (v, e) self:menuconf():event_on(event.command {"cm_back"}) end) + self:button_add("select", "< Select >", function (v, e) self:menuconf():on_event(event.command {"cm_enter"}) end) + self:button_add("back", "< Back >", function (v, e) self:menuconf():on_event(event.command {"cm_back"}) end) self:button_add("exit", "< Exit >", function (v, e) self:quit() end) self:button_add("help", "< Help >", function (v, e) self:show_help() end) self:button_add("save", "< Save >", function (v, e) self:action_on(action.ac_on_save) end) @@ -55,6 +56,10 @@ Pressing <Y> includes, <N> excludes. Enter <Esc> or <Back> to go back, <?> for H -- insert menu config self:box():panel():insert(self:menuconf()) + self:box():panel():action_add(action.ac_on_resized, function (v) + local bounds = self:box():panel():bounds() + self:menuconf():bounds_set(rect:new(0, 0, bounds:width(), bounds:height())) + end) -- disable to select to box (disable Tab switch and only response to buttons) self:box():option_set("selectable", false) @@ -135,7 +140,7 @@ end -- get input dialog function mconfdialog:inputdialog() if not self._INPUTDIALOG then - local dialog_input = inputdialog:new("mconfdialog.input", rect {0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}, "input dialog") + local dialog_input = inputdialog:new("mconfdialog.input", rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}, "input dialog") dialog_input:background_set(self:frame():background()) dialog_input:frame():background_set("cyan") dialog_input:textedit():option_set("multiline", false) @@ -163,7 +168,7 @@ end -- get choice dialog function mconfdialog:choicedialog() if not self._CHOICEDIALOG then - local dialog_choice = choicedialog:new("mconfdialog.choice", rect {0, 0, math.min(80, self:width() - 8), math.min(20, self:height())}, "input dialog") + local dialog_choice = choicedialog:new("mconfdialog.choice", rect{0, 0, math.min(80, self:width() - 8), math.min(20, self:height())}, "input dialog") dialog_choice:background_set(self:frame():background()) dialog_choice:frame():background_set("cyan") dialog_choice:box():frame():background_set("cyan") @@ -175,7 +180,7 @@ end -- get search dialog function mconfdialog:searchdialog() if not self._SEARCHDIALOG then - local dialog_search = inputdialog:new("mconfdialog.input", rect {0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}, "Search Configuration Parameter") + local dialog_search = inputdialog:new("mconfdialog.input", rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}, "Search Configuration Parameter") dialog_search:background_set(self:frame():background()) dialog_search:frame():background_set("cyan") dialog_search:textedit():option_set("multiline", false) @@ -288,12 +293,12 @@ function mconfdialog:show_result(text) end -- on event -function mconfdialog:event_on(e) +function mconfdialog:on_event(e) -- select config if e.type == event.ev_keyboard then if e.key_name == "Down" or e.key_name == "Up" or e.key_name == " " or e.key_name == "Esc" or e.key_name:lower() == "y" or e.key_name:lower() == "n" then - return self:menuconf():event_on(e) + return self:menuconf():on_event(e) elseif e.key_name == "?" then self:show_help() return true @@ -302,7 +307,31 @@ function mconfdialog:event_on(e) return true end end - return boxdialog.event_on(self, e) + return boxdialog.on_event(self, e) +end + +-- on resize +function mconfdialog:on_resize() + if self._HELPDIALOG then + self:helpdialog():bounds_set(self:bounds()) + end + if self._RESULTDIALOG then + self:resultdialog():bounds_set(self:bounds()) + self:center(self:resultdialog(), {centerx = true, centery = true}) + end + if self._INPUTDIALOG then + self:inputdialog():bounds_set(rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}) + self:center(self:inputdialog(), {centerx = true, centery = true}) + end + if self._CHOICEDIALOG then + self:choicedialog():bounds_set(rect{0, 0, math.min(80, self:width() - 8), math.min(20, self:height())}) + self:center(self:choicedialog(), {centerx = true, centery = true}) + end + if self._SEARCHDIALOG then + self:searchdialog():bounds_set(rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}) + self:center(self:searchdialog(), {centerx = true, centery = true}) + end + boxdialog.on_resize(self) end -- return module diff --git a/xmake/core/ui/menuconf.lua b/xmake/core/ui/menuconf.lua index c0f025585..40901ed83 100644 --- a/xmake/core/ui/menuconf.lua +++ b/xmake/core/ui/menuconf.lua @@ -43,7 +43,7 @@ function menuconf:init(name, bounds) end -- on event -function menuconf:event_on(e) +function menuconf:on_event(e) -- select config local back = false diff --git a/xmake/core/ui/panel.lua b/xmake/core/ui/panel.lua index 7d5d2b504..84ffdf115 100644 --- a/xmake/core/ui/panel.lua +++ b/xmake/core/ui/panel.lua @@ -89,17 +89,8 @@ function panel:view(name) return self._VIEWS_CACHE[name] end --- insert view -function panel:insert(v, opt) - - -- check - assert(not v:parent() or v:parent() == self) - assert(not self:view(v:name()), v:name() .. " has been in this panel!") - - -- this view has been inserted into this panel? remove it first - if v:parent() == self then - self:remove(v) - end +-- center view +function panel:center(v, opt) -- center this view if centerx or centery are set local bounds = v:bounds() @@ -117,6 +108,22 @@ function panel:insert(v, opt) bounds:move(org.x - bounds.sx, org.y - bounds.sy) v:invalidate(true) end +end + +-- insert view +function panel:insert(v, opt) + + -- check + assert(not v:parent() or v:parent() == self) + assert(not self:view(v:name()), v:name() .. " has been in this panel!") + + -- this view has been inserted into this panel? remove it first + if v:parent() == self then + self:remove(v) + end + + -- center this view if centerx or centery are set + self:center(v, opt) -- insert this view self._VIEWS:push(v) @@ -269,11 +276,11 @@ function panel:select_prev(start) end -- on event -function panel:event_on(e) +function panel:on_event(e) -- select view? if e.type == event.ev_keyboard then - if e.key_name == "Right" then + if e.key_name == "Right" or e.key_name == "Tab" then return self:select_next() elseif e.key_name == "Left" then return self:select_prev() @@ -291,14 +298,14 @@ function panel:state_set(name, enable) end -- draw panel -function panel:draw(transparent) +function panel:on_draw(transparent) -- redraw panel? local redraw = self:state("redraw") -- draw panel background first if redraw then - view.draw(self, transparent) + view.on_draw(self, transparent) end -- draw all child views @@ -307,33 +314,28 @@ function panel:draw(transparent) v:state_set("redraw", true) end if v:state("visible") and (v:state("redraw") or v:type() == "panel") then - v:draw(transparent) + v:on_draw(transparent) end end end -- resize panel -function panel:resize() +function panel:on_resize() - -- resize panel? - local resize = self:state("resize") - if resize then - view.resize(self) - end + -- resize panel + view.on_resize(self) -- resize all child views for v in self:views() do - if resize then - v:state_set("resize", true) - end - if v:state("visible") and (v:state("resize") or v:type() == "panel") then - v:resize() + v:state_set("resize", true) + if v:state("visible") then + v:on_resize() end end end -- refresh panel -function panel:refresh() +function panel:on_refresh() -- need not refresh? do not refresh it if not self:state("refresh") or not self:state("visible") then @@ -343,13 +345,13 @@ function panel:refresh() -- refresh all child views for v in self:views() do if v:state("refresh") then - v:refresh() + v:on_refresh() v:state_set("refresh", false) end end -- refresh it - view.refresh(self) + view.on_refresh(self) -- clear mark self:state_set("refresh", false) diff --git a/xmake/core/ui/program.lua b/xmake/core/ui/program.lua index 728281158..7f80451d9 100644 --- a/xmake/core/ui/program.lua +++ b/xmake/core/ui/program.lua @@ -18,11 +18,6 @@ -- @file program.lua -- ---[[ Console User Interface (cui) ]----------------------------------------- -Author: Tiago Dionizio (tiago.dionizio AT gmail.com) -$Id: program.lua 18 2007-06-21 20:43:52Z tngd $ ---------------------------------------------------------------------------]] - -- load modules local log = require("ui/log") local rect = require("ui/rect") @@ -145,7 +140,7 @@ function program:event() end -- on event -function program:event_on(e) +function program:on_event(e) -- get the top focused view local focused_view = self @@ -156,16 +151,28 @@ function program:event_on(e) -- do event for focused views while focused_view and focused_view ~= self do local parent = focused_view:parent() - if focused_view:event_on(e) then + if focused_view:on_event(e) then return true end focused_view = parent end + -- do event + if e.type == event.ev_keyboard then + -- resize? + if e.key_name == "Resize" then + self:bounds_set(rect {0, 0, curses.columns(), curses.lines()}) + return true + -- refresh? + elseif e.key_name == "Refresh" then + self:invalidate() + return true + -- ctrl+c? quit program + elseif e.key_name == "CtrlC" then + self:send("cm_exit") + return true + end -- quit program? - if e.type == event.ev_keyboard and e.key_name == "CtrlC" then - self:send("cm_exit") - return true elseif event.is_command(e, "cm_exit") then self:quit() return true @@ -173,7 +180,7 @@ function program:event_on(e) end -- put an event to view -function program:event_put(e) +function program:put_event(e) -- init event queue self._EVENT_QUEUE = self._EVENT_QUEUE or {} @@ -184,7 +191,7 @@ end -- send command function program:send(command, extra) - self:event_put(event.command {command, extra}) + self:put_event(event.command {command, extra}) end -- quit program @@ -206,11 +213,11 @@ function program:loop(argv) -- do event if e then event.dump(e) - self:event_on(e) + self:on_event(e) sleep = false else -- do idle event - self:event_on(event.idle()) + self:on_event(event.idle()) sleep = true end @@ -220,13 +227,17 @@ function program:loop(argv) end -- resize views - self:resize() + if self:state("resize") then + self:on_resize() + end -- draw views - self:draw() + self:on_draw() -- refresh views - self:refresh() + if self:state("refresh") then + self:on_refresh() + end -- wait some time, 50ms if sleep then @@ -236,15 +247,10 @@ function program:loop(argv) end -- refresh program -function program:refresh() - - -- need not refresh? do not refresh it - if not self:state("refresh") then - return - end +function program:on_refresh() -- refresh views - panel.refresh(self) + panel.on_refresh(self) -- trace log:print("%s: refresh ..", self) diff --git a/xmake/core/ui/textarea.lua b/xmake/core/ui/textarea.lua index 0201a2754..56c3b1f53 100644 --- a/xmake/core/ui/textarea.lua +++ b/xmake/core/ui/textarea.lua @@ -46,10 +46,10 @@ function textarea:init(name, bounds, text) end -- draw textarea -function textarea:draw(transparent) +function textarea:on_draw(transparent) -- draw background - view.draw(self, transparent) + view.on_draw(self, transparent) -- get the text attribute value local textattr = self:textattr_val() @@ -100,7 +100,7 @@ function textarea:scroll_to_end() end -- on event -function textarea:event_on(e) +function textarea:on_event(e) if e.type == event.ev_keyboard then if e.key_name == "Up" then self:scroll(-5) diff --git a/xmake/core/ui/textdialog.lua b/xmake/core/ui/textdialog.lua index 06dd63ecd..153c68a51 100644 --- a/xmake/core/ui/textdialog.lua +++ b/xmake/core/ui/textdialog.lua @@ -25,6 +25,7 @@ local event = require("ui/event") local dialog = require("ui/dialog") local curses = require("ui/curses") local textarea = require("ui/textarea") +local action = require("ui/action") -- define module local textdialog = textdialog or dialog() @@ -40,6 +41,11 @@ function textdialog:init(name, bounds, title) -- select buttons by default self:panel():select(self:buttons()) + + -- on resize for panel + self:panel():action_add(action.ac_on_resized, function (v) + self:text():bounds_set(rect:new(0, 0, v:width(), v:height() - 1)) + end) end -- get text @@ -51,16 +57,16 @@ function textdialog:text() end -- on event -function textdialog:event_on(e) +function textdialog:on_event(e) -- pass event to dialog - if dialog.event_on(self, e) then + if dialog.on_event(self, e) then return true end -- pass keyboard event to text area to scroll if e.type == event.ev_keyboard then - return self:text():event_on(e) + return self:text():on_event(e) end end diff --git a/xmake/core/ui/textedit.lua b/xmake/core/ui/textedit.lua index 85ed007fc..c36df5e3d 100644 --- a/xmake/core/ui/textedit.lua +++ b/xmake/core/ui/textedit.lua @@ -50,10 +50,10 @@ function textedit:init(name, bounds, text) end -- draw textedit -function textedit:draw(transparent) +function textedit:on_draw(transparent) -- draw label - textarea.draw(self, transparent) + textarea.on_draw(self, transparent) -- move cursor if not self:text() or #self:text() == 0 then @@ -71,7 +71,7 @@ function textedit:text_set(text) end -- on event -function textedit:event_on(e) +function textedit:on_event(e) -- update text if e.type == event.ev_keyboard then @@ -97,7 +97,7 @@ function textedit:event_on(e) end -- do textarea event - return textarea.event_on(self, e) + return textarea.on_event(self, e) end -- return module diff --git a/xmake/core/ui/view.lua b/xmake/core/ui/view.lua index 2501918e7..fbe149e3b 100644 --- a/xmake/core/ui/view.lua +++ b/xmake/core/ui/view.lua @@ -19,12 +19,14 @@ -- -- load modules +local table = require("base/table") local log = require("ui/log") local rect = require("ui/rect") local point = require("ui/point") local object = require("ui/object") local canvas = require("ui/canvas") local curses = require("ui/curses") +local action = require("ui/action") -- define module local view = view or object() @@ -59,8 +61,8 @@ function view:init(name, bounds) state.selected = false -- is selected? state.focused = false -- is focused? state.redraw = true -- need redraw - state.refresh = true -- need refresh - state.resize = true -- need resize + state.on_refresh = true -- need refresh + state.on_resize = true -- need resize self._STATE = state -- init options @@ -91,8 +93,8 @@ end function view:exit() -- close window - if self:window() then - self:window():close() + if self._WINDOW then + self._WINDOW:close() self._WINDOW = nil end end @@ -154,6 +156,15 @@ end -- get the view window function view:window() + if not self._WINDOW then + + -- create window + self._WINDOW = curses.new_pad(self:height() > 0 and self:height() or 1, self:width() > 0 and self:width() or 1) + assert(self._WINDOW, "cannot create window!") + + -- disable cursor + self._WINDOW:leaveok(true) + end return self._WINDOW end @@ -166,10 +177,10 @@ function view:canvas() end -- draw view -function view:draw(transparent) +function view:on_draw(transparent) -- trace - log:print("%s: draw ..", self) + log:print("%s: draw (transparent: %s) ..", self, tostring(transparent)) -- draw background if not transparent then @@ -188,7 +199,7 @@ function view:draw(transparent) end -- refresh view -function view:refresh() +function view:on_refresh() -- refresh to the parent view local parent = self:parent() @@ -209,34 +220,30 @@ function view:refresh() end -- resize bounds of inner child views (abstract) -function view:resize() +function view:on_resize() -- trace log:print("%s: resize ..", self) -- close the previous windows first - if self:window() then - self:window():close() + if self._WINDOW then + self._WINDOW:close() self._WINDOW = nil end -- need renew canvas self._CANVAS = nil - -- create a new window - self._WINDOW = curses.new_pad(self:height() > 0 and self:height() or 1, self:width() > 0 and self:width() or 1) - assert(self._WINDOW, "cannot create window!") - - -- disable cursor - self:window():leaveok(true) - -- clear mark self:state_set("resize", false) + + -- do action + self:action_on(action.ac_on_resized) end -- show view? -- --- e.g. +-- .e.g -- v:show(false) -- v:show(true, {focused = true}) -- @@ -265,7 +272,7 @@ end -- -- @return true: done and break dispatching, false/nil: continous to dispatch to other views -- -function view:event_on(e) +function view:on_event(e) end -- get the current event @@ -274,8 +281,8 @@ function view:event() end -- put an event to view -function view:event_put(e) - return self:parent() and self:parent():event_put(e) +function view:put_event(e) + return self:parent() and self:parent():put_event(e) end -- get type @@ -349,20 +356,21 @@ function view:extra_set(name, value) return self end --- get action -function view:action(name) - return self._ACTIONS[name] -end - -- set action function view:action_set(name, on_action) self._ACTIONS[name] = on_action return self end +-- add action +function view:action_add(name, on_action) + self._ACTIONS[name] = table.join(table.wrap(self._ACTIONS[name]), on_action) + return self +end + -- do action function view:action_on(name, ...) - local on_action = self:action(name) + local on_action = self._ACTIONS[name] if on_action then if type(on_action) == "string" then -- send command @@ -372,6 +380,13 @@ function view:action_on(name, ...) elseif type(on_action) == "function" then -- do action script return on_action(self, ...) + elseif type(on_action) == "table" then + for _, on_action_val in ipairs(on_action) do + -- we cannot uses the return value of action for multi-actions + if type(on_action_val) == "function" then + on_action_val(self, ...) + end + end end end end @@ -404,7 +419,7 @@ function view:background() return background end --- set background, e.g. background_set("blue") +-- set background, .e.g background_set("blue") function view:background_set(color) return self:attr_set("background", color) end @@ -427,6 +442,11 @@ function view:_mark_resize() -- need resize it self:state_set("resize", true) + + -- @note we need trigger on_resize() of the root view and pass it to this subview + if self:parent() then + self:parent():invalidate(true) + end end -- need redraw view diff --git a/xmake/core/ui/window.lua b/xmake/core/ui/window.lua index 7b30a15d2..81aac83c0 100644 --- a/xmake/core/ui/window.lua +++ b/xmake/core/ui/window.lua @@ -43,6 +43,7 @@ function window:init(name, bounds, title, shadow) -- insert shadow if shadow then + self._SHADOW = view:new("window.shadow", rect{2, 1, self:width(), self:height()}):background_set("black") self:insert(self:shadow()) self:frame():bounds():movee(-2, -1) self:frame():invalidate(true) @@ -98,9 +99,6 @@ end -- get shadow function window:shadow() - if not self._SHADOW then - self._SHADOW = view:new("window.shadow", rect{2, 1, self:width(), self:height()}):background_set("black") - end return self._SHADOW end @@ -113,7 +111,7 @@ function window:border() end -- on event -function window:event_on(e) +function window:on_event(e) -- select panel? if e.type == event.ev_keyboard then @@ -123,5 +121,21 @@ function window:event_on(e) end end +-- on resize +function window:on_resize() + self:frame():bounds_set(rect{0, 0, self:width(), self:height()}) + if self:shadow() then + self:shadow():bounds_set(rect{2, 1, self:width(), self:height()}) + self:frame():bounds():movee(-2, -1) + end + self:border():bounds_set(self:frame():bounds()) + if self:title() then + self:frame():center(self:title(), {centerx = true}) + end + self:panel():bounds_set(self:frame():bounds()) + self:panel():bounds():grow(-1, -1) + panel.on_resize(self) +end + -- return module return window |
