diff options
| author | ruki <[email protected]> | 2017-12-22 00:51:41 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2017-12-21 23:10:09 +0800 |
| commit | fe6f634879645e86609dfb014bab5546bfe0e7fc (patch) | |
| tree | 5c0c436390c8bc7aa3f209558b1f155d3f0a71a8 | |
| parent | bf0ea773b29ca4a85430dcb5ab024ed27a8eeb0c (diff) | |
rewrite refresh view
| -rw-r--r-- | xmake/core/ui/desktop.lua | 18 | ||||
| -rw-r--r-- | xmake/core/ui/group.lua | 154 | ||||
| -rw-r--r-- | xmake/core/ui/menubar.lua | 5 | ||||
| -rw-r--r-- | xmake/core/ui/program.lua | 58 | ||||
| -rw-r--r-- | xmake/core/ui/statusbar.lua | 3 | ||||
| -rw-r--r-- | xmake/core/ui/view.lua | 100 |
6 files changed, 168 insertions, 170 deletions
diff --git a/xmake/core/ui/desktop.lua b/xmake/core/ui/desktop.lua index 899053d48..9bf1e98ea 100644 --- a/xmake/core/ui/desktop.lua +++ b/xmake/core/ui/desktop.lua @@ -28,6 +28,7 @@ $Id: desktop.lua 18 2007-06-21 20:43:52Z tngd $ --------------------------------------------------------------------------]] -- load modules +local log = require("ui/log") local group = require("ui/group") -- define module @@ -35,7 +36,12 @@ local desktop = desktop or group() -- init desktop function desktop:init(name, bounds) + + -- init group group.init(self, name, bounds) + + -- init color + self:attr_set("color", curses.color_pair("white", "blue")) end -- exit desktop @@ -43,5 +49,17 @@ function desktop:exit() group.exit(self) end +-- draw view +function desktop:draw() + + -- trace + log:print("%s: draw ..", self) + + -- draw it + local c = self:canvas() + c:attr(self:attr("color")):move(0, 0):write(string.rep(' ', self:width() * self:height())) +end + + -- return module return desktop diff --git a/xmake/core/ui/group.lua b/xmake/core/ui/group.lua index 06f2a1864..80f7c22b7 100644 --- a/xmake/core/ui/group.lua +++ b/xmake/core/ui/group.lua @@ -100,9 +100,6 @@ function group:insert(v) -- check assert(not v:parent() or v:parent() == self) - -- lock - self:lock() - -- this view has been inserted into this group? remove it first if v:parent() == self then self:remove(v) @@ -133,12 +130,6 @@ function group:insert(v) if v:option("selectable") then self:select(v) end - - -- show this view - v:show(true) - - -- unlock - self:unlock() end -- remove view @@ -257,130 +248,63 @@ function group:event_on(e) end end --- execute group -function group:execute() - - -- show this group - self:show(true) - - -- refresh first - self:refresh() - - -- do message loop - local e = nil - local sleep = true - local app = self:application() - while true do +-- draw group +function group:draw() - -- get the current event - e = self:event() + -- draw it + if self:state("redraw") then - -- do event - if e then - self:event_on(e) - sleep = false - else - -- do idle event - app:event_on(event.idle()) - end + -- draw group background first + view.draw(self) - -- wait some time, 50ms - if sleep then - curses.napms(50) + -- draw all child views + for v in self:views() do + if v:state("visible") then + v:draw() + v:state_set("redraw", false) + end end - end - - -- hide this group - self:show(false) -end --- draw group -function group:draw() + -- clear mark + self:state_set("redraw", false) + else - -- draw sub views - for v in self:views() do - if v:state("visible") then - v:draw() + -- only draw child views + for v in self:views() do + if v:state("visible") and v:state("redraw") then + v:draw() + v:state_set("redraw", false) + end end end end --- redraw group -function group:redraw(on_parent) +-- refresh group +function group:refresh() - -- lock - self:lock() + -- need not refresh? do not refresh it + if not self:state("refresh") then + return + end - -- redraw all child views + -- refresh all child views for v in self:views() do - if v:state("visible") then - - -- cause groups to redraw - v:redraw(false) - - -- draw this child view - self:_draw_child(v) + if v:state("refresh") then + v:refresh() + v:state_set("refresh", false) end end - -- redraw view - view.redraw(self, on_parent) - - -- unlock - self:unlock() -end - --- refresh group in parent window -function group:refresh() - self:lock() - self:draw() - self:redraw(true) - self:unlock() -end - --- draw this child view -function group:_draw_child(v) + -- refresh it + view.refresh(self) - -- draw it if this child view is in a vaild bounds - local bounds = v:bounds() - local r = bounds():intersect(rect{0, 0, self:width(), self:height()}) - if r.ex > r.sx and r.ey > r.sy then - - -- TODO - -- copy this child view to group window - local sx = bounds.sx; sx = sx > 0 and 0 or -sx - local sy = bounds.sy; sy = sy > 0 and 0 or -sy - v:window():copy(self:window(), sy, sx, r.sy, r.sx, r.ey - 1, r.ex - 1) - end + -- clear mark + self:state_set("refresh", false) end --- draw overlapping views about this child view -function group:_draw_overlap(v) - - -- lock - self:lock() - - -- draw all overlapping areas - local bounds = v:bounds() - while v do - - -- check for overlapping areas - if v:state("visible") and v:bounds():is_intersect(bounds) then - - -- draw this child view - self:_draw_child(v) - - -- if they overlap, join them. - -- use the resulting rectangle to check for overlapping areas on the following windows - bounds:union(v:bounds()) - end - - -- get the next view - v = self:next(v) - end - - -- unlock - self:unlock() +-- dump all views +function group:dump() + log:print("%s", self:_tostring(1)) end -- tostring(group, level) @@ -405,7 +329,7 @@ end -- tostring(group) function group:__tostring() - return self:_tostring(1) + return string.format("<group(%s) %s>", self:name(), tostring(self:bounds())) end diff --git a/xmake/core/ui/menubar.lua b/xmake/core/ui/menubar.lua index af0e2b593..fa9fc910c 100644 --- a/xmake/core/ui/menubar.lua +++ b/xmake/core/ui/menubar.lua @@ -55,6 +55,11 @@ end -- draw view function menubar:draw() + + -- trace + log:print("%s: draw ..", self) + + -- draw it local c = self:canvas() c:attr(self:attr("color")):move(0, 0):write(string.rep(' ', self:width() * self:height())) c:move(1, 0):write(self:title()) diff --git a/xmake/core/ui/program.lua b/xmake/core/ui/program.lua index af3cb09bf..8d30903c0 100644 --- a/xmake/core/ui/program.lua +++ b/xmake/core/ui/program.lua @@ -28,6 +28,7 @@ $Id: program.lua 18 2007-06-21 20:43:52Z tngd $ --------------------------------------------------------------------------]] -- load modules +local log = require("ui/log") local rect = require("ui/rect") local group = require("ui/group") local event = require("ui/event") @@ -147,8 +148,61 @@ function program:loop(argv) -- save the current arguments self._ARGV = argv - -- execute group - self:execute() + -- do message loop + local e = nil + local sleep = true + while true do + + -- get the current event + e = self:event() + + -- do event + if e then + self:event_on(e) + sleep = false + else + -- do idle event + self:event_on(event.idle()) + end + + -- draw views + self:draw() + + -- refresh views + self:refresh() + + -- wait some time, 50ms + if sleep then + curses.napms(50) + end + end +end + +-- refresh program +function program:refresh() + + -- need not refresh? do not refresh it + if not self:state("refresh") then + return + end + + -- refresh views + group.refresh(self) + + -- trace + log:print("%s: refresh ..", self) + + -- get main window + local main_window = curses.main_window() + + -- refresh main window + self:window():copy(main_window, 0, 0, 0, 0, self:height() - 1, self:width() - 1) + + -- mark as refresh + main_window:noutrefresh() + + -- do update + curses.doupdate() end -- get key map diff --git a/xmake/core/ui/statusbar.lua b/xmake/core/ui/statusbar.lua index 0c00c730c..97c05f916 100644 --- a/xmake/core/ui/statusbar.lua +++ b/xmake/core/ui/statusbar.lua @@ -54,6 +54,9 @@ end -- draw view function statusbar:draw() + -- trace + log:print("%s: draw ..", self) + -- get canvas local c = self:canvas() c:move(0, 0) diff --git a/xmake/core/ui/view.lua b/xmake/core/ui/view.lua index 5c32f59e2..fc63ec181 100644 --- a/xmake/core/ui/view.lua +++ b/xmake/core/ui/view.lua @@ -29,6 +29,7 @@ $Id: view.lua 18 2007-06-21 20:43:52Z tngd $ -- load modules local log = require("ui/log") +local rect = require("ui/rect") local object = require("ui/object") local canvas = require("ui/canvas") local curses = require("ui/curses") @@ -36,9 +37,6 @@ local curses = require("ui/curses") -- define module local view = view or object() --- the screen lock/update counter -local screen_lock = 0 - -- new view instance function view:new(name, bounds, ...) @@ -60,9 +58,11 @@ function view:init(name, bounds) -- init state local state = object() - state.visible = false -- view visibility + state.visible = true -- view visibility state.selected = false -- current selected window inside group state.focused = false -- true if parent is also focused + state.redraw = true -- need redraw + state.refresh = true -- need refresh self._STATE = state -- init options @@ -179,42 +179,32 @@ end -- draw view function view:draw() -log:print("view draw: %s", self:name()) + + -- trace + log:print("%s: draw ..", self) + + -- clear view self:canvas():clear() end --- refresh view in parent window +-- refresh view function view:refresh() - self:draw() - self:redraw(true) -end --- redraw view -function view:redraw(on_parent) + -- refresh to the parent view + local parent = self:parent() + if parent then - -- redraw this child view on parent view (group) - if on_parent and self:parent() then - self:lock() - local v = self - while v:parent() do - v:parent():_draw_overlap(v) - v = v:parent() - end - self:unlock() - end -end + -- clip bounds with the parent view + local bounds = self:bounds() + local r = bounds():intersect(rect{0, 0, parent:width(), parent:height()}) + if not r:empty() then --- lock view -function view:lock() - screen_lock = screen_lock + 1 -end + -- trace + log:print("%s: refresh to %s(%d, %d, %d, %d) ..", self, parent:name(), r.sx, r.sy, r.ex, r.ey) --- unlock view -function view:unlock() - assert(screen_lock > 0) - screen_lock = screen_lock - 1 - if screen_lock == 0 then - self:_update_screen() + -- copy this view to parent view + self:window():copy(parent:window(), 0, 0, r.sy, r.sx, r.ey - 1, r.ex - 1) + end end end @@ -225,6 +215,14 @@ function view:show(visible) end end +-- invalidate view to redraw it +function view:invalidate() + + -- need redraw and refresh it + self:_mark_redraw() + self:_mark_refresh() +end + -- on event (abstract) function view:event_on(e) end @@ -295,37 +293,33 @@ function view:attr_set(name, value) self._ATTRS[name] = value end --- update screen -function view:_update_screen() +-- need redraw view +function view:_mark_redraw() - -- get application - local app = self:application() - assert(app, "cannot get application from view(" .. self:name() .. ")") + -- need redraw it + self:state_set("redraw", true) - -- is visible? disable to update screen before finishing application initialization - if not app:state("visible") then - return + -- need redraw it's parent view if this view is invisible + if not self:state("visible") and self:parent() then + self:parent():_mark_redraw() end +end - -- trace - log:print("view(%s): update screen ..", self:name()) - - -- get main window - local main_window = curses.main_window() - - -- update screen - app:window():copy(main_window, 0, 0, 0, 0, app:height() - 1, app:width() - 1) +-- need refresh view +function view:_mark_refresh() - -- mark as refresh - main_window:noutrefresh() + -- need refresh it + self:state_set("refresh", true) - -- do update - curses.doupdate() + -- need refresh it's parent view + if self:parent() then + self:parent():_mark_refresh() + end end -- tostring(view) function view:__tostring() - return string.format("<%s %s>", self:name(), tostring(self:bounds())) + return string.format("<view(%s) %s>", self:name(), tostring(self:bounds())) end -- return module |
