diff --git a/dialog.lua b/dialog.lua index c168f0852..222f9760c 100644 --- a/dialog.lua +++ b/dialog.lua @@ -124,17 +124,25 @@ Widget that shows a message and OK/Cancel buttons ]] ConfirmBox = FocusManager:new{ text = "no text", + width = nil, + ok_text = "OK", + cancel_text = "Cancel", } function ConfirmBox:init() + -- calculate box width on the fly if not given + if not self.width then + self.width = G_width - 200 + end + -- build bottons self.key_events.Close = { {{"Home","Back"}}, doc = "cancel" } self.key_events.Select = { {{"Enter","Press"}}, doc = "chose selected option" } local ok_button = Button:new{ - text = "OK" + text = self.ok_text, } local cancel_button = Button:new{ - text = "Cancel", + text = self.cancel_text, preselect = true } @@ -153,17 +161,18 @@ function ConfirmBox:init() HorizontalSpan:new{ width = 10 }, VerticalGroup:new{ align = "left", - TextWidget:new{ + TextBoxWidget:new{ text = self.text, - face = Font:getFace("cfont", 30) + face = Font:getFace("cfont", 30), + width = self.width, }, + VerticalSpan:new{ width = 10 }, HorizontalGroup:new{ ok_button, Widget:new{ dimen = { w = 10, h = 0 } }, cancel_button } } - } } } diff --git a/widget.lua b/widget.lua index 8d74abe8e..b7046ae7b 100644 --- a/widget.lua +++ b/widget.lua @@ -193,6 +193,101 @@ function TextWidget:free() end end +--[[ +A TextWidget that handles long text wrapping +]] +TextBoxWidget = Widget:new{ + text = nil, + face = nil, + color = 15, + width = 400, -- in pixels + line_height = 0.3, -- in em + v_list = nil, + _bb = nil, + _length = 0, +} + +function TextBoxWidget:_wrapGreedyAlg(h_list) + local cur_line_width = 0 + local space_w = sizeUtf8Text(0, G_width, self.face, " ", true).x + local cur_line = {} + local v_list = {} + + for k,w in ipairs(h_list) do + cur_line_width = cur_line_width + w.width + if cur_line_width <= self.width then + cur_line_width = cur_line_width + space_w + table.insert(cur_line, w) + else + -- wrap to next line + table.insert(v_list, cur_line) + cur_line = {} + cur_line_width = w.width + space_w + table.insert(cur_line, w) + end + end + -- handle last line + table.insert(v_list, cur_line) + + return v_list +end + +function TextBoxWidget:_getVerticalList(alg) + -- build horizontal list + h_list = {} + for w in self.text:gmatch("%S+") do + word_box = {} + word_box.word = w + word_box.width = sizeUtf8Text(0, G_width, self.face, w, true).x + table.insert(h_list, word_box) + end + + -- @TODO check alg here 25.04 2012 (houqp) + -- @TODO replace greedy algorithm with K&P algorithm 25.04 2012 (houqp) + return self:_wrapGreedyAlg(h_list) +end + +function TextBoxWidget:_render() + self.v_list = self:_getVerticalList() + local v_list = self.v_list + local font_height = self.face.size + local line_height_px = self.line_height * font_height + local space_w = sizeUtf8Text(0, G_width, self.face, " ", true).x + local h = (font_height + line_height_px) * #v_list - line_height_px + self._bb = Blitbuffer.new(self.width, h) + local y = font_height + + for _,l in ipairs(v_list) do + local pen_x = 0 + for _,w in ipairs(l) do + renderUtf8Text(self._bb, pen_x, y, self.face, w.word, true) + pen_x = pen_x + w.width + space_w + end + y = y + line_height_px + font_height + end +end + +function TextBoxWidget:getSize() + if not self._bb then + self:_render() + end + return { w = self.width, h = self._bb:getHeight() } +end + +function TextBoxWidget:paintTo(bb, x, y) + if not self._bb then + self:_render() + end + bb:blitFrom(self._bb, x, y, 0, 0, self.width, self._bb:getHeight()) +end + +function TextBoxWidget:free() + if self._bb then + self._bb:free() + self._bb = nil + end +end + --[[ ImageWidget shows an image from a file ]] diff --git a/wtest.lua b/wtest.lua index 824cb5df4..36ea9269c 100644 --- a/wtest.lua +++ b/wtest.lua @@ -52,7 +52,7 @@ function Clock:schedFunc() self[1] = self:getTextWidget() UIManager:setDirty(self) -- reschedule - -- TODO: wait until next real minute shift + -- TODO: wait until next real second shift UIManager:scheduleIn(1, function() self:schedFunc() end) end @@ -71,7 +71,15 @@ function Clock:getTextWidget() } end +quiz = ConfirmBox:new{ + text = "Tell me the truth, isn't it COOL?!", + width = 300, + ok_text = "Yes, of course.", + cancel_text = "No, it's ugly.", +} +quiz:init() UIManager:show(Background:new()) UIManager:show(Clock:new()) +UIManager:show(quiz) UIManager:run()