add vertically scrollable text widget

pull/187/head
chrox 11 years ago
parent 668e84290e
commit 872ffa5767

@ -1,6 +1,6 @@
require "ui/widget/base"
require "ui/rendertext"
require "ui/widget/base"
require "ui/widget/scrollbar"
--[[
A TextWidget puts a string on a single line
@ -65,12 +65,25 @@ TextBoxWidget = Widget:new{
bgcolor = 0.0, -- [0.0, 1.0]
fgcolor = 1.0, -- [0.0, 1.0]
width = 400, -- in pixels
height = nil,
first_line = 1,
virtual_line = 1, -- used by scroll bar
line_height = 0.3, -- in em
v_list = nil,
_bb = nil,
_length = 0,
}
function TextBoxWidget:init()
local v_list = nil
if self.height then
v_list = self:_getCurrentVerticalList()
else
v_list = self:_getVerticalList()
end
self:_render(v_list)
end
function TextBoxWidget:_wrapGreedyAlg(h_list)
local cur_line_width = 0
local space_w = sizeUtf8Text(0, Screen:getWidth(), self.face, " ", true).x
@ -98,10 +111,13 @@ function TextBoxWidget:_wrapGreedyAlg(h_list)
end
function TextBoxWidget:_getVerticalList(alg)
if self.vertical_list then
return self.vertical_list
end
-- build horizontal list
h_list = {}
local h_list = {}
for w in self.text:gmatch("[\33-\127\192-\255]+[\128-\191]*") do
word_box = {}
local word_box = {}
word_box.word = w
word_box.width = sizeUtf8Text(0, Screen:getWidth(), self.face, w, true).x
table.insert(h_list, word_box)
@ -109,12 +125,84 @@ function TextBoxWidget:_getVerticalList(alg)
-- @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)
self.vertical_list = self:_wrapGreedyAlg(h_list)
return self.vertical_list
end
function TextBoxWidget:_getCurrentVerticalList()
local line_height = (1 + self.line_height) * self.face.size
local v_list = self:_getVerticalList()
local current_v_list = {}
local height = 0
for i = self.first_line, #v_list do
if height < self.height - line_height then
table.insert(current_v_list, v_list[i])
height = height + line_height
else
break
end
end
return current_v_list
end
function TextBoxWidget:_getPreviousVerticalList()
local line_height = (1 + self.line_height) * self.face.size
local v_list = self:_getVerticalList()
local previous_v_list = {}
local height = 0
if self.first_line == 1 then
return self:_getCurrentVerticalList()
end
self.virtual_line = self.first_line
for i = self.first_line - 1, 1, -1 do
if height < self.height - line_height then
table.insert(previous_v_list, 1, v_list[i])
height = height + line_height
self.virtual_line = self.virtual_line - 1
else
break
end
end
for i = self.first_line, #v_list do
if height < self.height - line_height then
table.insert(previous_v_list, v_list[i])
height = height + line_height
else
break
end
end
if self.first_line > #previous_v_list then
self.first_line = self.first_line - #previous_v_list
else
self.first_line = 1
end
return previous_v_list
end
function TextBoxWidget:_getNextVerticalList()
local line_height = (1 + self.line_height) * self.face.size
local v_list = self:_getVerticalList()
local current_v_list = self:_getCurrentVerticalList()
local next_v_list = {}
local height = 0
if self.first_line + #current_v_list > #v_list then
return current_v_list
end
self.virtual_line = self.first_line
for i = self.first_line + #current_v_list, #v_list do
if height < self.height - line_height then
table.insert(next_v_list, v_list[i])
height = height + line_height
self.virtual_line = self.virtual_line + 1
else
break
end
end
self.first_line = self.first_line + #current_v_list
return next_v_list
end
function TextBoxWidget:_render()
self.v_list = self:_getVerticalList()
local v_list = self.v_list
function TextBoxWidget:_render(v_list)
local font_height = self.face.size
local line_height_px = self.line_height * font_height
local space_w = sizeUtf8Text(0, Screen:getWidth(), self.face, " ", true).x
@ -134,23 +222,47 @@ function TextBoxWidget:_render()
end
y = y + line_height_px + font_height
end
-- if text is shorter than one line, shrink to text's width
if #v_list == 1 then
self.width = pen_x
end
-- -- if text is shorter than one line, shrink to text's width
-- if #v_list == 1 then
-- self.width = pen_x
-- end
end
function TextBoxWidget:getVirtualLineNum()
return self.virtual_line
end
function TextBoxWidget:getAllLineCount()
local v_list = self:_getVerticalList()
return #v_list
end
function TextBoxWidget:getVisLineCount()
local line_height = (1 + self.line_height) * self.face.size
return math.floor(self.height / line_height)
end
function TextBoxWidget:scrollDown()
local next_v_list = self:_getNextVerticalList()
self:free()
self:_render(next_v_list)
end
function TextBoxWidget:scrollUp()
local previous_v_list = self:_getPreviousVerticalList()
self:free()
self:_render(previous_v_list)
end
function TextBoxWidget:getSize()
if not self._bb then
self:_render()
if self.width and self.height then
return Geom:new{ w = self.width, h = self.height}
else
return Geom:new{ w = self.width, h = self._bb:getHeight()}
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
@ -161,7 +273,6 @@ function TextBoxWidget:free()
end
end
--[[
FixedTextWidget
--]]
@ -183,3 +294,72 @@ function FixedTextWidget:paintTo(bb, x, y)
renderUtf8Text(bb, x, y+self._height, self.face, self.text,
true, self.bgcolor, self.fgcolor)
end
--[[
Text widget with vertical scroll bar
--]]
ScrollTextWidget = InputContainer:new{
text = nil,
font_face = nil,
width = 400,
height = 300,
scroll_bar_width = scaleByDPI(6),
text_scroll_span = scaleByDPI(6),
dialog = nil,
}
function ScrollTextWidget:init()
self.text_widget = TextBoxWidget:new{
text = self.text,
face = self.font_face,
width = self.width - self.scroll_bar_width - self.text_scroll_span,
height = self.height
}
local visible_line_count = self.text_widget:getVisLineCount()
local total_line_count = self.text_widget:getAllLineCount()
self.v_scroll_bar = VerticalScrollBar:new{
enable = visible_line_count < total_line_count,
low = 0,
high = visible_line_count/total_line_count,
width = scaleByDPI(6),
height = self.height,
}
local horizontal_group = HorizontalGroup:new{}
table.insert(horizontal_group, self.text_widget)
table.insert(horizontal_group, HorizontalSpan:new{width = scaleByDPI(6)})
table.insert(horizontal_group, self.v_scroll_bar)
self[1] = horizontal_group
self.dimen = Geom:new(self[1]:getSize())
if Device:isTouchDevice() then
self.ges_events = {
Swipe = {
GestureRange:new{
ges = "swipe",
range = self.dimen,
},
},
}
end
end
function ScrollTextWidget:updateScrollBar(text)
local virtual_line_num = text:getVirtualLineNum()
local visible_line_count = text:getVisLineCount()
local all_line_count = text:getAllLineCount()
self.v_scroll_bar:set(
(virtual_line_num - 1) / all_line_count,
(virtual_line_num - 1 + visible_line_count) / all_line_count
)
end
function ScrollTextWidget:onSwipe(arg, ges)
if ges.direction == "north" then
self.text_widget:scrollDown()
self:updateScrollBar(self.text_widget)
elseif ges.direction == "south" then
self.text_widget:scrollUp()
self:updateScrollBar(self.text_widget)
end
UIManager:setDirty(self.dialog, "partial")
return true
end

Loading…
Cancel
Save