summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2020-05-07 22:45:25 +0800
committerruki <[email protected]>2020-05-07 10:32:31 +0800
commitca238c29d3e14b0c72787b47588b979356dd9410 (patch)
treeaccec9b30f7b057b9bfbf9cf9e5985d5060232db
parent5d22635894f2b19f49441e0671ac0eb1b1da9c17 (diff)
update ui
-rw-r--r--core/src/lcurses/lcurses.c12
-rw-r--r--tests/ui/desktop.lua16
-rw-r--r--tests/ui/dialog.lua109
-rw-r--r--tests/ui/inputdialog.lua28
-rw-r--r--tests/ui/mconfdialog.lua35
-rw-r--r--tests/ui/window.lua20
-rw-r--r--xmake/core/ui/action.lua1
-rw-r--r--xmake/core/ui/application.lua12
-rw-r--r--xmake/core/ui/border.lua8
-rw-r--r--xmake/core/ui/boxdialog.lua29
-rw-r--r--xmake/core/ui/button.lua6
-rw-r--r--xmake/core/ui/choicebox.lua2
-rw-r--r--xmake/core/ui/choicedialog.lua8
-rw-r--r--xmake/core/ui/dialog.lua41
-rw-r--r--xmake/core/ui/inputdialog.lua5
-rw-r--r--xmake/core/ui/label.lua4
-rw-r--r--xmake/core/ui/mconfdialog.lua45
-rw-r--r--xmake/core/ui/menuconf.lua2
-rw-r--r--xmake/core/ui/panel.lua62
-rw-r--r--xmake/core/ui/program.lua54
-rw-r--r--xmake/core/ui/textarea.lua6
-rw-r--r--xmake/core/ui/textdialog.lua12
-rw-r--r--xmake/core/ui/textedit.lua8
-rw-r--r--xmake/core/ui/view.lua76
-rw-r--r--xmake/core/ui/window.lua22
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