diff options
Diffstat (limited to 'src/syslua')
-rw-r--r-- | src/syslua/lx/tk.lua | 157 |
1 files changed, 124 insertions, 33 deletions
diff --git a/src/syslua/lx/tk.lua b/src/syslua/lx/tk.lua index 374e260..0862e5b 100644 --- a/src/syslua/lx/tk.lua +++ b/src/syslua/lx/tk.lua @@ -3,6 +3,70 @@ local sys = require 'lx.sys' local tk = {} +-- UTIL + +function region_operation(reg1, reg2, sel_fun) + local xs = {reg1.x, reg1.x + reg1.w, reg2.x, reg2.x + reg2.w} + local ys = {reg1.y, reg1.y + reg1.h, reg2.y, reg2.y + reg2.h} + table.sort(xs) + table.sort(ys) + local pieces = {} + local function add_region(x, y, w, h) + for i, r in pairs(pieces) do + if r.y == y and r.h == h and r.x + r.w == x then + table.remove(pieces, i) + add_region(r.x, r.y, r.w + w, r.h) + return + elseif r.x == x and r.w == w and r.y + r.h == y then + table.remove(pieces, i) + add_region(r.x, r.y, r.w, r.h + h) + return + end + end + table.insert(pieces, {x = x, y = y, w = w, h = h}) + end + for i = 1, 3 do + for j = 1, 3 do + local x0, x1, y0, y1 = xs[i], xs[i+1], ys[j], ys[j+1] + if x1 > x0 and y1 > y0 then + if sel_fun(x0, x1, y0, y1) then + add_region(x0, y0, x1 - x0, y1 - y0) + end + end + end + end + return pieces +end + +function region_diff(reg1, reg2) + return region_operation(reg1, reg2, + function(x0, x1, y0, y1) + return (x0 >= reg1.x and x0 < reg1.x + reg1.w and y0 >= reg1.y and y0 < reg1.y + reg1.h) + and not (x0 >= reg2.x and x0 < reg2.x + reg2.w and y0 >= reg2.y and y0 < reg2.y + reg2.h) + end + ) +end + +function region_inter(reg1, reg2) + return region_operation(reg1, reg2, + function(x0, x1, y0, y1) + return (x0 >= reg1.x and x0 < reg1.x + reg1.w and y0 >= reg1.y and y0 < reg1.y + reg1.h) + and (x0 >= reg2.x and x0 < reg2.x + reg2.w and y0 >= reg2.y and y0 < reg2.y + reg2.h) + end + ) +end + +function region_union(reg1, reg2) + return region_operation(reg1, reg2, + function(x0, x1, y0, y1) + return (x0 >= reg1.x and x0 < reg1.x + reg1.w and y0 >= reg1.y and y0 < reg1.y + reg1.h) + or (x0 >= reg2.x and x0 < reg2.x + reg2.w and y0 >= reg2.y and y0 < reg2.y + reg2.h) + end + ) +end + + + function tk.widget(width, height) local w = { width = width, @@ -23,6 +87,15 @@ function tk.widget(width, height) -- Replaced by widget code by a function that does the actual drawing end + function w:redraw_sub(x0, y0, buf, subwidget) + local region = {x = x0, y = y0, w = buf:width(), h = buf:height()} + local subregion = {x = subwidget.x, y = subwidget.y, w = subwidget.width, h = subwidget.height} + local inter = region_inter(region, subregion) + for _, z in pairs(inter) do + subwidget:redraw(z.x - subwidget.x, z.y - subwidget.y, buf:sub(z.x - x0, z.y - y0, z.w, z.h)) + end + end + function w:on_mouse_down(x, y, lb, rb, mb) -- Handler for mouse down event end @@ -127,14 +200,7 @@ function tk.wm_widget() end function win:redraw(x0, y0, buf) - local xx0 = math.max(x0, 1) - local yy0 = math.max(y0, 21) - - local ww, hh = buf:width() - (xx0-x0), buf:height() - (yy0-y0) - if xx0-1 + ww > content.width then ww = content.width - xx0+1 end - if yy0-21 + ww > content.height then hh = content.height - yy0+21 end - - self.content:redraw(xx0-1, yy0-21, buf:sub(xx0-x0, yy0-y0, ww, hh)) + self:redraw_sub(x0, y0, buf, self.content) buf:rect(-x0, -y0, self.width, self.height, buf:rgb(255, 128, 0)) buf:fillrect(-x0+1, -y0+1, win.width-2, 20, buf:rgb(200, 200, 200)) @@ -161,12 +227,15 @@ function tk.wm_widget() function win:on_mouse_move(px, py, nx, ny) if self.moving then - self.visible = false - wm:redraw_win(self) + local reg1 = {x = self.x, y = self.y, w = self.width, h = self.height} self.x = self.x + nx - px self.y = self.y + ny - py - self.visible = true - wm:redraw_win(self) + local reg2 = {x = self.x, y = self.y, w = self.width, h = self.height} + local pieces = region_diff(reg1, reg2) + table.insert(pieces, reg2) + for _, p in pairs(pieces) do + wm:redraw_region(p.x, p.y, p.w, p.h) + end else self.content:on_mouse_move(px-1, py-21, px-1, py-21) end @@ -191,39 +260,61 @@ function tk.wm_widget() end end + function wm:redraw_region(x, y, w, h) + local ok = region_inter({x = 0, y = 0, w = self.width, h = self.height}, + {x = x, y = y, w = w, h = h}) + for _, r in pairs(ok) do + self:redraw(r.x, r.y, self:get_draw_buffer(r.x, r.y, r.w, r.h)) + end + end + function wm:redraw_win(win) - local x0, y0 = math.max(0, win.x), math.max(0, win.y) - local width = win.x + win.width - x0 - local height = win.y + win.height - y0 - self:redraw(x0, y0, self:get_draw_buffer(x0, y0, width, height)) + self:redraw_region(win.x, win.y, win.width, win.height) end function wm:redraw(x0, y0, buf) - -- Draw background - - local step = 32 - local halfstep = 16 - for x = x0 - (x0 % step), x0 + buf:width(), step do - for y = y0 - (y0 % step), y0 + buf:height(), step do - buf:fillrect(x - x0, y - y0, halfstep, halfstep, buf:rgb(110, 110, 140)) - buf:fillrect(x - x0 + halfstep, y - y0 + halfstep, halfstep, halfstep, buf:rgb(110, 110, 140)) - buf:fillrect(x - x0 + halfstep, y - y0, halfstep, halfstep, buf:rgb(110, 140, 110)) - buf:fillrect(x - x0, y - y0 + halfstep, halfstep, halfstep, buf:rgb(110, 140, 110)) - end - end + local remaining = { {x = x0, y = y0, w = buf:width(), h = buf:height()} } -- TODO do this in inverse order and clip regions of hidden windows -- so that less redrawing is done - for i = 1, #self.windows do + for i = #self.windows, 1, -1 do win = self.windows[i] if win.visible then - local wx0, wy0 = math.max(x0, win.x), math.max(y0, win.y) - local ww, wh = win.x + win.width - wx0, win.y + win.height - wy0 - if ww > 0 and wh > 0 then - win:redraw(wx0 - win.x, wy0 - win.y, buf:sub(wx0 - x0, wy0 - y0, ww, wh)) + local remaining2 = {} + local win_reg = {x = win.x, y = win.y, w = win.width, h = win.height} + + for _, reg in pairs(remaining) do + local draw_to = region_inter(reg, win_reg) + for _, reg2 in pairs(draw_to) do + win:redraw(reg2.x - win.x, reg2.y - win.y, buf:sub(reg2.x - x0, reg2.y - y0, reg2.w, reg2.h)) + end + + local remain_to = region_diff(reg, win_reg) + for _, reg2 in pairs(remain_to) do + table.insert(remaining2, reg2) + end + end + + remaining = remaining2 + end + end + + -- Draw background + function draw_background(x0, y0, buf) + local step = 32 + local halfstep = 16 + for x = x0 - (x0 % step), x0 + buf:width(), step do + for y = y0 - (y0 % step), y0 + buf:height(), step do + buf:fillrect(x - x0, y - y0, halfstep, halfstep, buf:rgb(110, 110, 140)) + buf:fillrect(x - x0 + halfstep, y - y0 + halfstep, halfstep, halfstep, buf:rgb(110, 110, 140)) + buf:fillrect(x - x0 + halfstep, y - y0, halfstep, halfstep, buf:rgb(110, 140, 110)) + buf:fillrect(x - x0, y - y0 + halfstep, halfstep, halfstep, buf:rgb(110, 140, 110)) end end end + for _, reg in pairs(remaining) do + draw_background(reg.x, reg.y, buf:sub(reg.x - x0, reg.y - y0, reg.w, reg.h)) + end end function wm:find_win(x, y) |