diff --git a/frontend/ui/widget/scrollhtmlwidget.lua b/frontend/ui/widget/scrollhtmlwidget.lua
index 1cd2869f6..1e25999fe 100644
--- a/frontend/ui/widget/scrollhtmlwidget.lua
+++ b/frontend/ui/widget/scrollhtmlwidget.lua
@@ -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
diff --git a/frontend/ui/widget/scrolltextwidget.lua b/frontend/ui/widget/scrolltextwidget.lua
index 2f49089ea..d1056f03b 100644
--- a/frontend/ui/widget/scrolltextwidget.lua
+++ b/frontend/ui/widget/scrolltextwidget.lua
@@ -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
diff --git a/frontend/ui/widget/textboxwidget.lua b/frontend/ui/widget/textboxwidget.lua
index c05fd5f73..db9a6bcfb 100644
--- a/frontend/ui/widget/textboxwidget.lua
+++ b/frontend/ui/widget/textboxwidget.lua
@@ -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
diff --git a/frontend/ui/widget/verticalscrollbar.lua b/frontend/ui/widget/verticalscrollbar.lua
index 120e3c0c7..5ac76eabb 100644
--- a/frontend/ui/widget/verticalscrollbar.lua
+++ b/frontend/ui/widget/verticalscrollbar.lua
@@ -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,