Merge pull request #187 from chrox/scroll_text

fix long definition not shown properly in dictionary window
This commit is contained in:
{Qingping,Dave} Hou
2013-07-28 12:17:01 -07:00
4 changed files with 245 additions and 42 deletions

View File

@@ -39,6 +39,7 @@ function ReaderDictionary:showDict(results)
results = results,
dictionary = self.default_dictionary,
width = Screen:getWidth() - scaleByDPI(120),
height = Screen:getHeight()*0.43,
})
end
end

View File

@@ -131,7 +131,7 @@ function Screen:getDPI()
end
function Screen:scaleByDPI(px)
return (px * self:getDPI()/167)
return math.floor(px * self:getDPI()/167)
end
-- make a shortcut to Screen:scaleByDPI

View File

@@ -14,35 +14,43 @@ DictQuickLookup = InputContainer:new{
word_face = Font:getFace("tfont", 20),
content_face = Font:getFace("cfont", 20),
width = nil,
height = nil,
title_padding = scaleByDPI(5),
title_margin = scaleByDPI(2),
word_padding = scaleByDPI(5),
word_padding = scaleByDPI(2),
word_margin = scaleByDPI(2),
definition_padding = scaleByDPI(5),
definition_padding = scaleByDPI(2),
definition_margin = scaleByDPI(2),
button_padding = scaleByDPI(14),
}
function DictQuickLookup:init()
if Device:hasKeyboard() then
key_events = {
AnyKeyPressed = { { Input.group.Any },
seqtext = "any key", doc = _("close dialog") }
}
else
self.ges_events.TapCloseDict = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
}
self:changeToDefaultDict()
if Device:isTouchDevice() then
self.ges_events = {
TapCloseDict = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
},
},
Swipe = {
GestureRange:new{
ges = "swipe",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
},
},
}
end
self:changeToDefaultDict()
end
function DictQuickLookup:update()
@@ -73,10 +81,12 @@ function DictQuickLookup:update()
padding = self.definition_padding,
margin = self.definition_margin,
bordersize = 0,
TextBoxWidget:new{
ScrollTextWidget:new{
text = self.definition,
face = self.content_face,
font_face = self.content_face,
width = self.width,
height = self.height*0.8,
dialog = self,
},
}
local button_table = ButtonTable:new{
@@ -138,9 +148,21 @@ function DictQuickLookup:update()
self.dict_title,
title_bar,
-- word
lookup_word,
CenterContainer:new{
dimen = Geom:new{
w = title_bar:getSize().w,
h = lookup_word:getSize().h,
},
lookup_word,
},
-- definition
definition,
CenterContainer:new{
dimen = Geom:new{
w = title_bar:getSize().w,
h = definition:getSize().h,
},
definition,
},
-- buttons
CenterContainer:new{
dimen = Geom:new{

View File

@@ -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:_render()
self.v_list = self:_getVerticalList()
local v_list = self.v_list
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(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