|
|
@ -53,11 +53,11 @@ function inset(rect,dx1,dy1,dx2,dy2)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function to_pen(pen, default)
|
|
|
|
local function to_pen(default, pen, bg, bold)
|
|
|
|
if pen == nil then
|
|
|
|
if pen == nil then
|
|
|
|
return default or {}
|
|
|
|
return default or {}
|
|
|
|
elseif type(pen) ~= 'table' then
|
|
|
|
elseif type(pen) ~= 'table' then
|
|
|
|
return {fg=pen}
|
|
|
|
return {fg=pen,bg=bg,bold=bold}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
return pen
|
|
|
|
return pen
|
|
|
|
end
|
|
|
|
end
|
|
|
@ -70,40 +70,48 @@ end
|
|
|
|
Painter = defclass(Painter, nil)
|
|
|
|
Painter = defclass(Painter, nil)
|
|
|
|
|
|
|
|
|
|
|
|
function Painter.new(rect, pen)
|
|
|
|
function Painter.new(rect, pen)
|
|
|
|
rect = rect or {}
|
|
|
|
rect = rect or mkdims_wh(0,0,dscreen.getWindowSize())
|
|
|
|
local sw, sh = dscreen.getWindowSize()
|
|
|
|
local self = {
|
|
|
|
local self = mkdims_xy(
|
|
|
|
x1 = rect.x1, clip_x1 = rect.x1,
|
|
|
|
math.max(rect.x1 or 0, 0),
|
|
|
|
y1 = rect.y1, clip_y1 = rect.y1,
|
|
|
|
math.max(rect.y1 or 0, 0),
|
|
|
|
x2 = rect.x2, clip_x2 = rect.x2,
|
|
|
|
math.min(rect.x2 or sw-1, sw-1),
|
|
|
|
y2 = rect.y2, clip_y2 = rect.y2,
|
|
|
|
math.min(rect.y2 or sh-1, sh-1)
|
|
|
|
width = rect.x2-rect.x1+1,
|
|
|
|
)
|
|
|
|
height = rect.y2-rect.y1+1,
|
|
|
|
self.cur_pen = to_pen(pen or COLOR_GREY)
|
|
|
|
cur_pen = to_pen(nil, pen or COLOR_GREY)
|
|
|
|
self.x = self.x1
|
|
|
|
}
|
|
|
|
self.y = self.y1
|
|
|
|
return mkinstance(Painter, self):seek(0,0)
|
|
|
|
return mkinstance(Painter, self)
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:setRect(x1,y1,x2,y2)
|
|
|
|
function Painter:isValidPos()
|
|
|
|
local rect = mkdims_xy(x1,y1,x2,y2)
|
|
|
|
return self.x >= self.clip_x1 and self.x <= self.clip_x2
|
|
|
|
self.x1 = rect.x1
|
|
|
|
and self.y >= self.clip_y1 and self.y <= self.clip_y2
|
|
|
|
self.y1 = rect.y1
|
|
|
|
|
|
|
|
self.x2 = rect.x2
|
|
|
|
|
|
|
|
self.y2 = rect.y2
|
|
|
|
|
|
|
|
self.width = rect.width
|
|
|
|
|
|
|
|
self.height = rect.height
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:isValidPos()
|
|
|
|
function Painter:viewport(x,y,w,h)
|
|
|
|
return self.x >= self.x1 and self.x <= self.x2 and self.y >= self.y1 and self.y <= self.y2
|
|
|
|
local x1,y1 = self.x1+x, self.y1+y
|
|
|
|
|
|
|
|
local x2,y2 = x1+w-1, y1+h-1
|
|
|
|
|
|
|
|
local vp = {
|
|
|
|
|
|
|
|
-- Logical viewport
|
|
|
|
|
|
|
|
x1 = x1, y1 = y1, x2 = x2, y2 = y2,
|
|
|
|
|
|
|
|
width = w, height = h,
|
|
|
|
|
|
|
|
-- Actual clipping rect
|
|
|
|
|
|
|
|
clip_x1 = math.max(self.clip_x1, x1),
|
|
|
|
|
|
|
|
clip_y1 = math.max(self.clip_y1, y1),
|
|
|
|
|
|
|
|
clip_x2 = math.min(self.clip_x2, x2),
|
|
|
|
|
|
|
|
clip_y2 = math.min(self.clip_y2, y2),
|
|
|
|
|
|
|
|
-- Pen
|
|
|
|
|
|
|
|
cur_pen = self.cur_pen
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return mkinstance(Painter, vp):seek(0,0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:inset(dx1,dy1,dx2,dy1)
|
|
|
|
function Painter:localX()
|
|
|
|
self:setRect(
|
|
|
|
return self.x - self.x1
|
|
|
|
self.x1+dx1, self.y1+dy1,
|
|
|
|
end
|
|
|
|
self.x2-(dx2 or dx1), self.y2-(dy2 or dy1)
|
|
|
|
|
|
|
|
)
|
|
|
|
function Painter:localY()
|
|
|
|
return self
|
|
|
|
return self.y - self.y1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:seek(x,y)
|
|
|
|
function Painter:seek(x,y)
|
|
|
@ -124,55 +132,63 @@ function Painter:newline(dx)
|
|
|
|
return self
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:pen(pen)
|
|
|
|
function Painter:pen(pen,...)
|
|
|
|
self.cur_pen = to_pen(pen, self.cur_pen)
|
|
|
|
self.cur_pen = to_pen(self.cur_pen, pen, ...)
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:color(fg,bold,bg)
|
|
|
|
|
|
|
|
self.cur_pen = copyall(self.cur_pen)
|
|
|
|
|
|
|
|
self.cur_pen.fg = fg
|
|
|
|
|
|
|
|
self.cur_pen.bold = bold
|
|
|
|
|
|
|
|
if bg then self.cur_pen.bg = bg end
|
|
|
|
return self
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:clear()
|
|
|
|
function Painter:clear()
|
|
|
|
dscreen.fillRect(CLEAR_PEN, self.x1, self.y1, self.x2, self.y2)
|
|
|
|
dscreen.fillRect(CLEAR_PEN, self.clip_x1, self.clip_y1, self.clip_x2, self.clip_y2)
|
|
|
|
return self
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:fill(x1,y1,x2,y2,pen)
|
|
|
|
function Painter:fill(x1,y1,x2,y2,pen,bg,bold)
|
|
|
|
if type(x1) == 'table' then
|
|
|
|
if type(x1) == 'table' then
|
|
|
|
x1, y1, x2, y2, pen = x1.x1, x1.y1, x1.x2, x1.y2, x2
|
|
|
|
x1, y1, x2, y2, pen, bg, bold = x1.x1, x1.y1, x1.x2, x1.y2, y1, x2, y2
|
|
|
|
end
|
|
|
|
end
|
|
|
|
x1 = math.max(x1,self.x1)
|
|
|
|
x1 = math.max(x1,self.clip_x1)
|
|
|
|
y1 = math.max(y1,self.y1)
|
|
|
|
y1 = math.max(y1,self.clip_y1)
|
|
|
|
x2 = math.min(x2,self.x2)
|
|
|
|
x2 = math.min(x2,self.clip_x2)
|
|
|
|
y2 = math.min(y2,self.y2)
|
|
|
|
y2 = math.min(y2,self.clip_y2)
|
|
|
|
dscreen.fillRect(to_pen(pen, self.cur_pen),x1,y1,x2,y2)
|
|
|
|
dscreen.fillRect(to_pen(self.cur_pen,pen,bg,bold),x1,y1,x2,y2)
|
|
|
|
return self
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:char(char,pen)
|
|
|
|
function Painter:char(char,pen,...)
|
|
|
|
if self:isValidPos() then
|
|
|
|
if self:isValidPos() then
|
|
|
|
dscreen.paintTile(to_pen(pen, self.cur_pen), self.x, self.y, char)
|
|
|
|
dscreen.paintTile(to_pen(self.cur_pen, pen, ...), self.x, self.y, char)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return self:advance(1, nil)
|
|
|
|
return self:advance(1, nil)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:tile(char,tile,pen)
|
|
|
|
function Painter:tile(char,tile,pen,...)
|
|
|
|
if self:isValidPos() then
|
|
|
|
if self:isValidPos() then
|
|
|
|
dscreen.paintTile(to_pen(pen, self.cur_pen), self.x, self.y, char, tile)
|
|
|
|
dscreen.paintTile(to_pen(self.cur_pen, pen, ...), self.x, self.y, char, tile)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return self:advance(1, nil)
|
|
|
|
return self:advance(1, nil)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Painter:string(text,pen)
|
|
|
|
function Painter:string(text,pen,...)
|
|
|
|
if self.y >= self.y1 and self.y <= self.y2 then
|
|
|
|
if self.y >= self.clip_y1 and self.y <= self.clip_y2 then
|
|
|
|
local dx = 0
|
|
|
|
local dx = 0
|
|
|
|
if self.x < self.x1 then
|
|
|
|
if self.x < self.clip_x1 then
|
|
|
|
dx = self.x1 - self.x
|
|
|
|
dx = self.clip_x1 - self.x
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local len = #text
|
|
|
|
local len = #text
|
|
|
|
if self.x + len - 1 > self.x2 then
|
|
|
|
if self.x + len - 1 > self.clip_x2 then
|
|
|
|
len = self.x2 - self.x + 1
|
|
|
|
len = self.clip_x2 - self.x + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if len > dx then
|
|
|
|
if len > dx then
|
|
|
|
dscreen.paintString(
|
|
|
|
dscreen.paintString(
|
|
|
|
to_pen(pen, self.cur_pen),
|
|
|
|
to_pen(self.cur_pen, pen, ...),
|
|
|
|
self.x+dx, self.y,
|
|
|
|
self.x+dx, self.y,
|
|
|
|
string.sub(text,dx+1,len)
|
|
|
|
string.sub(text,dx+1,len)
|
|
|
|
)
|
|
|
|
)
|
|
|
@ -209,12 +225,12 @@ function Screen:inputToParent(...)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Screen:show()
|
|
|
|
function Screen:show(below)
|
|
|
|
if self._native then
|
|
|
|
if self._native then
|
|
|
|
error("This screen is already on display")
|
|
|
|
error("This screen is already on display")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
self:onAboutToShow()
|
|
|
|
self:onAboutToShow(below)
|
|
|
|
if dscreen.show(self) then
|
|
|
|
if dscreen.show(self, below) then
|
|
|
|
self:onShown()
|
|
|
|
self:onShown()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
@ -225,20 +241,40 @@ end
|
|
|
|
function Screen:onShown()
|
|
|
|
function Screen:onShown()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function paint_border(x1,y1,x2,y2,color,title)
|
|
|
|
------------------------
|
|
|
|
local pen = { ch = ' ', fg = COLOR_BLACK, bg = color }
|
|
|
|
-- Framed screen object --
|
|
|
|
dscreen.fillRect(pen,x1,y1,x2,y1)
|
|
|
|
------------------------
|
|
|
|
dscreen.fillRect(pen,x1,y2,x2,y2)
|
|
|
|
|
|
|
|
dscreen.fillRect(pen,x1,y1+1,x1,y2-1)
|
|
|
|
GREY_FRAME = {
|
|
|
|
dscreen.fillRect(pen,x2,y1+1,x2,y2-1)
|
|
|
|
frame_pen = { ch = ' ', fg = COLOR_BLACK, bg = COLOR_GREY },
|
|
|
|
|
|
|
|
title_pen = { fg = COLOR_BLACK, bg = COLOR_WHITE },
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function paint_frame(x1,y1,x2,y2,style,title)
|
|
|
|
|
|
|
|
local pen = style.frame_pen
|
|
|
|
|
|
|
|
dscreen.paintTile(style.lt_frame_pen or pen, x1, y1)
|
|
|
|
|
|
|
|
dscreen.paintTile(style.rt_frame_pen or pen, x2, y1)
|
|
|
|
|
|
|
|
dscreen.paintTile(style.lb_frame_pen or pen, x1, y2)
|
|
|
|
|
|
|
|
dscreen.paintTile(style.rb_frame_pen or pen, x2, y2)
|
|
|
|
|
|
|
|
dscreen.fillRect(style.t_frame_pen or style.h_frame_pen or pen,x1+1,y1,x2-1,y1)
|
|
|
|
|
|
|
|
dscreen.fillRect(style.b_frame_pen or style.h_frame_pen or pen,x1+1,y2,x2-1,y2)
|
|
|
|
|
|
|
|
dscreen.fillRect(style.l_frame_pen or style.v_frame_pen or pen,x1,y1+1,x1,y2-1)
|
|
|
|
|
|
|
|
dscreen.fillRect(style.r_frame_pen or style.v_frame_pen or pen,x2,y1+1,x2,y2-1)
|
|
|
|
|
|
|
|
|
|
|
|
if title then
|
|
|
|
if title then
|
|
|
|
local x = math.floor((x2-x1-3-#title)/2 + x1)
|
|
|
|
local x = math.max(0,math.floor((x2-x1-3-#title)/2)) + x1
|
|
|
|
pen.bg = bit32.bxor(pen.bg, 8)
|
|
|
|
local tstr = ' '..title..' '
|
|
|
|
dscreen.paintString(pen, x, y1, ' '..title..' ')
|
|
|
|
if #tstr > x2-x1-1 then
|
|
|
|
|
|
|
|
tstr = string.sub(tstr,1,x2-x1-1)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
dscreen.paintString(style.title_pen or pen, x, y1, tstr)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FramedScreen = defclass(FramedScreen, Screen)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FramedScreen.frame_style = GREY_FRAME
|
|
|
|
|
|
|
|
|
|
|
|
local function hint_coord(gap,hint)
|
|
|
|
local function hint_coord(gap,hint)
|
|
|
|
if hint and hint > 0 then
|
|
|
|
if hint and hint > 0 then
|
|
|
|
return math.min(hint,gap)
|
|
|
|
return math.min(hint,gap)
|
|
|
@ -249,25 +285,33 @@ local function hint_coord(gap,hint)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Screen:renderFrame(color,title,width,height,xhint,yhint)
|
|
|
|
function FramedScreen:updateLayout()
|
|
|
|
local sw, sh = dscreen.getWindowSize()
|
|
|
|
local sw, sh = dscreen.getWindowSize()
|
|
|
|
local iw, ih = sw-2, sh-2
|
|
|
|
local iw, ih = sw-2, sh-2
|
|
|
|
width = math.min(width or iw, iw)
|
|
|
|
local width = math.min(self.frame_width or iw, iw)
|
|
|
|
height = math.min(height or ih, ih)
|
|
|
|
local height = math.min(self.frame_height or ih, ih)
|
|
|
|
local gw, gh = iw-width, ih-height
|
|
|
|
local gw, gh = iw-width, ih-height
|
|
|
|
local x1, y1 = hint_coord(gw,xhint), hint_coord(gh,yhint)
|
|
|
|
local x1, y1 = hint_coord(gw,self.frame_xhint), hint_coord(gh,self.frame_yhint)
|
|
|
|
local x2, y2 = x1+width+1, y1+height+1
|
|
|
|
self.frame_rect = mkdims_wh(x1+1,y1+1,width,height)
|
|
|
|
|
|
|
|
self.frame_opaque = (gw == 0 and gh == 0)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function FramedScreen:onRender()
|
|
|
|
|
|
|
|
self:updateLayout()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local rect = self.frame_rect
|
|
|
|
|
|
|
|
local x1,y1,x2,y2 = rect.x1-1, rect.y1-1, rect.x2+1, rect.y2+1
|
|
|
|
|
|
|
|
|
|
|
|
if gw == 0 and gh == 0 then
|
|
|
|
if self.frame_opaque then
|
|
|
|
dscreen.clear()
|
|
|
|
dscreen.clear()
|
|
|
|
else
|
|
|
|
else
|
|
|
|
self:renderParent()
|
|
|
|
self:renderParent()
|
|
|
|
dscreen.fillRect(CLEAR_PEN,x1,y1,x2,y2)
|
|
|
|
dscreen.fillRect(CLEAR_PEN,x1,y1,x2,y2)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
paint_border(x1,y1,x2,y2,color,title)
|
|
|
|
paint_frame(x1,y1,x2,y2,self.frame_style,self.frame_title)
|
|
|
|
|
|
|
|
|
|
|
|
return Painter.new(mkdims_wh(x1+1,y1+1,width,height))
|
|
|
|
self:onRenderBody(Painter.new(rect))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
return _ENV
|
|
|
|
return _ENV
|
|
|
|