Text/HTML widgets: allow scrolling with the scrollbar

By tapping on or panning the scrollbar.
reviewable/pr6579/r1
poire-z 4 years ago
parent 69d11ebfd9
commit 29d83b67d3

@ -12,7 +12,6 @@ local HorizontalSpan = require("ui/widget/horizontalspan")
local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local VerticalScrollBar = require("ui/widget/verticalscrollbar")
local Math = require("optmath")
local Input = Device.input
local Screen = Device.screen
@ -46,6 +45,9 @@ function ScrollHtmlWidget:init()
enable = self.htmlbox_widget.page_count > 1,
width = self.scroll_bar_width,
height = self.height,
scroll_callback = function(ratio)
self:scrollToRatio(ratio)
end
}
self.v_scroll_bar:set((self.htmlbox_widget.page_number-1) / self.htmlbox_widget.page_count, self.htmlbox_widget.page_number / self.htmlbox_widget.page_count)
@ -89,7 +91,10 @@ end
function ScrollHtmlWidget:scrollToRatio(ratio)
ratio = math.max(0, math.min(1, ratio)) -- ensure ratio is between 0 and 1 (100%)
local page_num = 1 + Math.round((self.htmlbox_widget.page_count - 1) * ratio)
local page_num = 1 + math.floor((self.htmlbox_widget.page_count) * ratio)
if page_num > self.htmlbox_widget.page_count then
page_num = self.htmlbox_widget.page_count
end
if page_num == self.htmlbox_widget.page_number then
return
end

@ -71,6 +71,9 @@ function ScrollTextWidget:init()
high = visible_line_count / total_line_count,
width = self.scroll_bar_width,
height = self.text_widget:getTextHeight(),
scroll_callback = function(ratio)
self:scrollToRatio(ratio, false)
end
}
self:updateScrollBar()
local horizontal_group = HorizontalGroup:new{ align = "top" }
@ -219,8 +222,14 @@ function ScrollTextWidget:scrollText(direction)
self:updateScrollBar(true)
end
function ScrollTextWidget:scrollToRatio(ratio)
self.text_widget:scrollToRatio(ratio)
function ScrollTextWidget:scrollToRatio(ratio, force_to_page)
if force_to_page == nil then
-- default to force to page, for consistency with
-- ScrollHtmlWidget that always forces to page (for
-- DictQuickLookup when going back to previous dict)
force_to_page = true
end
self.text_widget:scrollToRatio(ratio, force_to_page)
self:updateScrollBar(true)
end

@ -87,6 +87,7 @@ local TextBoxWidget = InputContainer:new{
image_padding_bottom = Screen:scaleBySize(3),
image_alt_face = Font:getFace("xx_smallinfofont"),
image_alt_fgcolor = Blitbuffer.COLOR_BLACK,
scroll_force_to_page = false, -- will be forced to true if images
-- Additional properties only used when using xtext
use_xtext = G_reader_settings:nilOrTrue("use_xtext"),
@ -249,6 +250,11 @@ function TextBoxWidget:_splitToLines()
local ln = 1
local offset, end_offset, cur_line_width
if self.images and #self.images > 0 then
-- Force scrolling to align to top of pages, as we
-- expect to draw images only at top of view
self.scroll_force_to_page = true
end
local image_num = 0
local targeted_width = self.width
local image_lines_remaining = 0
@ -1227,12 +1233,25 @@ function TextBoxWidget:scrollToBottom()
end
function TextBoxWidget:scrollToRatio(ratio)
function TextBoxWidget:scrollToRatio(ratio, force_to_page)
self.image_show_alt_text = nil
local line_num
ratio = math.max(0, math.min(1, ratio)) -- ensure ratio is between 0 and 1 (100%)
local page_count = 1 + math.floor((#self.vertical_string_list - 1) / self.lines_per_page)
local page_num = 1 + Math.round((page_count - 1) * ratio)
local line_num = 1 + (page_num - 1) * self.lines_per_page
if force_to_page or self.scroll_force_to_page then
-- We want scroll to align to original pages
local page_count = 1 + math.floor((#self.vertical_string_list - 1) / self.lines_per_page)
local page_num = 1 + Math.round((page_count - 1) * ratio)
line_num = 1 + (page_num - 1) * self.lines_per_page
else
-- We want the middle of page to show at ratio, so remove self.lines_per_page/2
line_num = 1 + math.floor(ratio * #self.vertical_string_list - self.lines_per_page/2)
if line_num + self.lines_per_page > #self.vertical_string_list then
line_num = #self.vertical_string_list - self.lines_per_page + 1
end
if line_num < 1 then
line_num = 1
end
end
if line_num ~= self.virtual_line_num then
self:free(false)
self.virtual_line_num = line_num

@ -1,9 +1,12 @@
local Blitbuffer = require("ffi/blitbuffer")
local Device = require("device")
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local InputContainer = require("ui/widget/container/inputcontainer")
local Size = require("ui/size")
local Widget = require("ui/widget/widget")
local Screen = require("device").screen
local VerticalScrollBar = Widget:new{
local VerticalScrollBar = InputContainer:new{
enable = true,
low = 0,
high = 1,
@ -16,8 +19,72 @@ local VerticalScrollBar = Widget:new{
-- minimal height of the thumb/knob/grip (usually showing the current
-- view size and position relative to the whole scrollable height):
min_thumb_size = Size.line.thick,
scroll_callback = nil,
-- extra touchable width (for scrolling with pan) can be larger than
-- the provided width (this is added on each side)
extra_touch_on_side_width_ratio = 1, -- make it 3 x width
}
function VerticalScrollBar:init()
self.extra_touch_on_side = math.ceil( self.extra_touch_on_side_width_ratio * self.width )
if Device:isTouchDevice() then
local pan_rate = Screen.low_pan_rate and 2.0 or 5.0
self.ges_events = {
TapScroll = {
GestureRange:new{
ges = "tap",
range = function() return self.touch_dimen end,
},
},
HoldScroll = {
GestureRange:new{
ges = "hold",
range = function() return self.touch_dimen end,
},
},
HoldPanScroll = {
GestureRange:new{
ges = "hold_pan",
rate = pan_rate,
range = function() return self.touch_dimen end,
},
},
HoldReleaseScroll = {
GestureRange:new{
ges = "hold_release",
range = function() return self.touch_dimen end,
},
},
PanScroll = {
GestureRange:new{
ges = "pan",
rate = pan_rate,
range = function() return self.touch_dimen end,
},
},
PanScrollRelease = {
GestureRange:new{
ges = "pan_release",
range = function() return self.touch_dimen end,
},
}
}
end
end
function VerticalScrollBar:onTapScroll(arg, ges)
if self.scroll_callback then
local ratio = (ges.pos.y - self.touch_dimen.y) / self.height
self.scroll_callback(ratio)
return true
end
end
VerticalScrollBar.onHoldScroll = VerticalScrollBar.onTapScroll
VerticalScrollBar.onHoldPanScroll = VerticalScrollBar.onTapScroll
VerticalScrollBar.onHoldReleaseScroll = VerticalScrollBar.onTapScroll
VerticalScrollBar.onPanScroll = VerticalScrollBar.onTapScroll
VerticalScrollBar.onPanScrollRelease = VerticalScrollBar.onTapScroll
function VerticalScrollBar:getSize()
return Geom:new{
w = self.width,
@ -32,6 +99,12 @@ end
function VerticalScrollBar:paintTo(bb, x, y)
if not self.enable then return end
self.touch_dimen = Geom:new{
x = x - self.extra_touch_on_side,
y = y,
w = self.width + 2 * self.extra_touch_on_side,
h = self.height,
}
bb:paintBorder(x, y, self.width, self.height,
self.bordersize, self.bordercolor, self.radius)
bb:paintRect(x + self.bordersize, y + self.bordersize + self.low * self.height,

Loading…
Cancel
Save