Skip to content
Browse files

Added widget abstraction framework

An example for using it:

--snip
require "widget"
require "font"

fb = einkfb.open("/dev/fb0")
G_width, G_height = fb:getSize()

dialog = CenterContainer:new({
        dimen = { w = G_width, h = G_height },
        VerticalGroup:new({
                align = "center",
                FrameContainer:new({
                        CenterContainer:new({
                                dimen = { w = 400, h = 200 },
                                TextWidget:new({
                                        text = "Hi there! jgVJV",
                                        face = Font:getFace("cfont", 30)
                                })
                        })
                }),
                ImageWidget:new({
                        file = "test.png"
                }),
                FrameContainer:new({
                        CenterContainer:new({
                                dimen = { w = 300, h = 200 },
                                TextWidget:new({
                                        text = "another box",
                                        face = Font:getFace("cfont", 30)
                                })
                        })
                })
        })
})

dialog:paintTo(fb.bb, 0, 0)

fb:refresh(0)

input.waitForEvent()
--snip
  • Loading branch information...
1 parent 38afb59 commit b6d75b84ecb315b9df15312e0f876bc0d571c56d @hwhw hwhw committed Apr 15, 2012
Showing with 264 additions and 1 deletion.
  1. +1 −1 font.lua
  2. +263 −0 widget.lua
View
2 font.lua
@@ -55,7 +55,7 @@ function Font:getFace(font, size)
end
self.faces[font..size] = face
end
- return { ftface = face, hash = font..size }
+ return { size = size, ftface = face, hash = font..size }
end
function Font:_readList(target, dir, effective_dir)
View
263 widget.lua
@@ -0,0 +1,263 @@
+require "rendertext"
+require "graphics"
+require "image"
+
+--[[
+This is a (useless) generic Widget interface
+
+widgets can be queried about their size and can be paint.
+that's it for now. Probably we need something more elaborate
+later.
+]]
+Widget = {
+ dimen = { w = 0, h = 0},
+}
+
+function Widget:new(o)
+ o = o or {}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+function Widget:getSize()
+ return self.dimen
+end
+
+function Widget:paintTo(bb, x, y)
+end
+
+function Widget:free()
+end
+
+--[[
+WidgetContainer is a container for another Widget
+]]
+WidgetContainer = Widget:new()
+
+function WidgetContainer:free()
+ for _, widget in ipairs(self) do
+ widget:free()
+ end
+end
+
+--[[
+CenterContainer centers its content (1 widget) within its own dimensions
+]]
+CenterContainer = WidgetContainer:new()
+
+function CenterContainer:paintTo(bb, x, y)
+ local contentSize = self[1]:getSize()
+ if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
+ -- throw error?
+ return
+ end
+ self[1]:paintTo(bb,
+ x + (self.dimen.w - contentSize.w)/2,
+ y + (self.dimen.h - contentSize.h)/2)
+end
+
+--[[
+A FrameContainer is some graphics content (1 widget) that is surrounded by a frame
+]]
+FrameContainer = WidgetContainer:new({
+ background = nil,
+ color = 15,
+ margin = 0,
+ bordersize = 2,
+ padding = 5,
+})
+
+function FrameContainer:getSize()
+ local content_size = self[1]:getSize()
+ return {
+ w = content_size.w + ( self.margin + self.bordersize + self.padding ) * 2,
+ h = content_size.h + ( self.margin + self.bordersize + self.padding ) * 2
+ }
+end
+
+function FrameContainer:paintTo(bb, x, y)
+ local my_size = self:getSize()
+
+ if self.background then
+ bb:paintRect(x, y, my_size.w, my_size.h, self.background)
+ end
+ if self.bordersize > 0 then
+ bb:paintBorder(x + self.margin, y + self.margin,
+ my_size.w - self.margin * 2, my_size.h - self.margin * 2,
+ self.bordersize, self.color)
+ end
+ self[1]:paintTo(bb,
+ x + self.margin + self.bordersize + self.padding,
+ y + self.margin + self.bordersize + self.padding)
+end
+
+--[[
+A TextWidget puts a string on a single line
+]]
+TextWidget = Widget:new({
+ text = nil,
+ face = nil,
+ color = 15,
+ _bb = nil,
+ _length = 0,
+ _maxlength = 1200,
+})
+
+function TextWidget:_render()
+ local h = self.face.size * 1.5
+ self._bb = Blitbuffer.new(self._maxlength, h)
+ self._length = renderUtf8Text(self._bb, 0, h*.7, self.face, self.text, self.color)
+end
+
+function TextWidget:getSize()
+ if not self._bb then
+ self:_render()
+ end
+ return { w = self._length, h = self._bb:getHeight() }
+end
+
+function TextWidget:paintTo(bb, x, y)
+ if not self._bb then
+ self:_render()
+ end
+ bb:blitFrom(self._bb, x, y, 0, 0, self._length, self._bb:getHeight())
+end
+
+function TextWidget:free()
+ if self._bb then
+ self._bb:free()
+ self._bb = nil
+ end
+end
+
+--[[
+ImageWidget shows an image from a file
+]]
+ImageWidget = Widget:new({
+ file = nil,
+ _bb = nil
+})
+
+function ImageWidget:_render()
+ local itype = string.lower(string.match(self.file, ".+%.([^.]+)") or "")
+ if itype == "jpeg" or itype == "jpg" then
+ self._bb = Image.fromJPEG(self.file)
+ elseif itype == "png" then
+ self._bb = Image.fromPNG(self.file)
+ end
+end
+
+function ImageWidget:getSize()
+ if not self._bb then
+ self:_render()
+ end
+ return { w = self._bb:getWidth(), h = self._bb:getHeight() }
+end
+
+function ImageWidget:paintTo(bb, x, y)
+ local size = self:getSize()
+ bb:blitFrom(self._bb, x, y, 0, 0, size.w, size.h)
+end
+
+function ImageWidget:free()
+ if self._bb then
+ self._bb:free()
+ self._bb = nil
+ end
+end
+
+--[[
+A Layout widget that puts objects besides each others
+]]
+HorizontalGroup = WidgetContainer:new({
+ align = "center",
+ _size = nil,
+})
+
+function HorizontalGroup:getSize()
+ if not self._size then
+ self._size = { w = 0, h = 0 }
+ self._offsets = { }
+ for i, widget in ipairs(self) do
+ local w_size = widget:getSize()
+ self._offsets[i] = {
+ x = self._size.w,
+ y = w_size.h
+ }
+ self._size.w = self._size.w + w_size.w
+ if w_size.h > self._size.h then
+ self._size.h = w_size.h
+ end
+ end
+ end
+ return self._size
+end
+
+function HorizontalGroup:paintTo(bb, x, y)
+ local size = self:getSize()
+
+ for i, widget in ipairs(self) do
+ if self.align == "center" then
+ widget:paintTo(bb, x + self._offsets[i].x, y + (size.h - self._offsets[i].y) / 2)
+ elseif self.align == "top" then
+ widget:paintTo(bb, x + self._offsets[i].x, y)
+ elseif self.align == "bottom" then
+ widget:paintTo(bb, x + self._offsets[i].x, y + size.h - self._offsets[i].y)
+ end
+ end
+end
+
+function HorizontalGroup:free()
+ self._size = nil
+ self._offsets = {}
+ WidgetContainer.free(self)
+end
+
+--[[
+A Layout widget that puts objects under each other
+]]
+VerticalGroup = WidgetContainer:new({
+ align = "center",
+ _size = nil,
+ _offsets = {}
+})
+
+function VerticalGroup:getSize()
+ if not self._size then
+ self._size = { w = 0, h = 0 }
+ self._offsets = { }
+ for i, widget in ipairs(self) do
+ local w_size = widget:getSize()
+ self._offsets[i] = {
+ x = w_size.w,
+ y = self._size.h,
+ }
+ self._size.h = self._size.h + w_size.h
+ if w_size.w > self._size.w then
+ self._size.w = w_size.w
+ end
+ end
+ end
+ return self._size
+end
+
+function VerticalGroup:paintTo(bb, x, y)
+ local size = self:getSize()
+
+ for i, widget in ipairs(self) do
+ if self.align == "center" then
+ widget:paintTo(bb, x + (size.w - self._offsets[i].x) / 2, y + self._offsets[i].y)
+ elseif self.align == "left" then
+ widget:paintTo(bb, x, y + self._offsets[i].y)
+ elseif self.align == "right" then
+ widget:paintTo(bb, x + size.w - self._offsets[i].x, y + self._offsets[i].y)
+ end
+ end
+end
+
+function VerticalGroup:free()
+ self._size = nil
+ self._offsets = {}
+ WidgetContainer.free(self)
+end

0 comments on commit b6d75b8

Please sign in to comment.
Something went wrong with that request. Please try again.