mirror of
https://github.com/koreader/koreader
synced 2024-11-10 01:10:34 +00:00
470 lines
16 KiB
Lua
470 lines
16 KiB
Lua
local BD = require("ui/bidi")
|
|
local Blitbuffer = require("ffi/blitbuffer")
|
|
local Button = require("ui/widget/button")
|
|
local Device = require("device")
|
|
local Event = require("ui/event")
|
|
local FocusManager = require("ui/widget/focusmanager")
|
|
local FrameContainer = require("ui/widget/container/framecontainer")
|
|
local Geom = require("ui/geometry")
|
|
local GestureRange = require("ui/gesturerange")
|
|
local HorizontalGroup = require("ui/widget/horizontalgroup")
|
|
local HorizontalSpan = require("ui/widget/horizontalspan")
|
|
local Math = require("optmath")
|
|
local MovableContainer = require("ui/widget/container/movablecontainer")
|
|
local ProgressWidget = require("ui/widget/progresswidget")
|
|
local Size = require("ui/size")
|
|
local UIManager = require("ui/uimanager")
|
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
|
local VerticalSpan = require("ui/widget/verticalspan")
|
|
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
|
local _ = require("gettext")
|
|
local Screen = Device.screen
|
|
|
|
local SkimToWidget = FocusManager:extend{}
|
|
|
|
function SkimToWidget:init()
|
|
if self.ui.paging then -- "page" view
|
|
self.ui.paging:enterSkimMode()
|
|
end
|
|
|
|
local screen_width = Screen:getWidth()
|
|
local screen_height = Screen:getHeight()
|
|
|
|
if Device:hasKeys() then
|
|
self.key_events.Close = { { Device.input.group.Back } }
|
|
end
|
|
if Device:isTouchDevice() then
|
|
self.ges_events.TapProgress = {
|
|
GestureRange:new{
|
|
ges = "tap",
|
|
range = Geom:new{
|
|
x = 0, y = 0,
|
|
w = screen_width,
|
|
h = screen_height,
|
|
}
|
|
},
|
|
}
|
|
end
|
|
|
|
-- nil for default center full mode; "top" and "bottom" for compact mode
|
|
local skim_dialog_position = G_reader_settings:readSetting("skim_dialog_position")
|
|
local full_mode = not skim_dialog_position
|
|
|
|
local frame_border_size = Size.border.window
|
|
local button_span_unit_width = Size.span.horizontal_small
|
|
local button_font_size, frame_padding, frame_width, inner_width, nb_buttons, larger_span_units, progress_bar_height
|
|
if full_mode then
|
|
button_font_size = nil -- use default
|
|
frame_padding = Size.padding.fullscreen -- large padding for airy feeling
|
|
frame_width = math.floor(math.min(screen_width, screen_height) * 0.95)
|
|
inner_width = frame_width - 2 * (frame_border_size + frame_padding)
|
|
nb_buttons = 5 -- with the middle one separated a bit more from the others
|
|
larger_span_units = 3 -- 3 x small span width
|
|
progress_bar_height = Size.item.height_big
|
|
else
|
|
button_font_size = 14
|
|
frame_padding = Size.padding.default
|
|
frame_width = screen_width + 2 * frame_border_size -- hide side borders
|
|
inner_width = frame_width - 2 * frame_padding
|
|
nb_buttons = 11 -- in equal distances
|
|
larger_span_units = 1
|
|
progress_bar_height = Screen:scaleBySize(36)
|
|
end
|
|
local nb_span_units = (nb_buttons - 1) - 2 + 2 * larger_span_units
|
|
local button_width = math.floor((inner_width - nb_span_units * button_span_unit_width) * (1 / nb_buttons))
|
|
-- Update inner_width (possibly smaller because of math.floor())
|
|
inner_width = nb_buttons * button_width + nb_span_units * button_span_unit_width
|
|
|
|
self.curr_page = self.ui:getCurrentPage()
|
|
self.page_count = self.ui.document:getPageCount()
|
|
|
|
self.progress_bar = ProgressWidget:new{
|
|
width = inner_width,
|
|
height = progress_bar_height,
|
|
percentage = self.curr_page / self.page_count,
|
|
ticks = self.ui.toc:getTocTicksFlattened(),
|
|
tick_width = Size.line.medium,
|
|
last = self.page_count,
|
|
alt = self.ui.document.flows,
|
|
initial_pos_marker = true,
|
|
}
|
|
|
|
-- Bottom row buttons
|
|
local button_minus = Button:new{
|
|
text = "-1",
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
self:goToPage(self.curr_page - 1)
|
|
end,
|
|
}
|
|
local button_minus_ten = Button:new{
|
|
text = "-10",
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
self:goToPage(self.curr_page - 10)
|
|
end,
|
|
}
|
|
local button_plus = Button:new{
|
|
text = "+1",
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
self:goToPage(self.curr_page + 1)
|
|
end,
|
|
}
|
|
local button_plus_ten = Button:new{
|
|
text = "+10",
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
self:goToPage(self.curr_page + 10)
|
|
end,
|
|
}
|
|
self.current_page_text = Button:new{
|
|
text_func = function()
|
|
if self.ui.pagemap and self.ui.pagemap:wantsPageLabels() then
|
|
return self.ui.pagemap:getCurrentPageLabel(true)
|
|
end
|
|
return tostring(self.curr_page)
|
|
end,
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
padding = 0,
|
|
bordersize = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
callback = function()
|
|
self.callback_switch_to_goto()
|
|
end,
|
|
hold_callback = function()
|
|
self:goToOrigPage()
|
|
end,
|
|
}
|
|
local button_orig_page = Button:new{
|
|
text = "\u{21BA}", -- Anticlockwise Open Circle Arrow
|
|
-- text = "\u{21A9}", -- Leftwards Arrow with Hook
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
self:goToOrigPage()
|
|
end,
|
|
}
|
|
|
|
-- Top row buttons
|
|
local chapter_next_text = " ▷▏"
|
|
local chapter_prev_text = "▕◁ "
|
|
local bookmark_next_text = "\u{F097}\u{202F}▷"
|
|
local bookmark_prev_text = "◁\u{202F}\u{F097}"
|
|
local bookmark_enabled_text = "\u{F02E}"
|
|
local bookmark_disabled_text = "\u{F097}"
|
|
if BD.mirroredUILayout() then
|
|
chapter_next_text, chapter_prev_text = chapter_prev_text, chapter_next_text
|
|
bookmark_next_text, bookmark_prev_text = bookmark_prev_text, bookmark_next_text
|
|
end
|
|
local button_chapter_next = Button:new{
|
|
text = chapter_next_text,
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
local page = self.ui.toc:getNextChapter(self.curr_page)
|
|
if page and page >= 1 and page <= self.page_count then
|
|
self:goToPage(page)
|
|
end
|
|
end,
|
|
hold_callback = function()
|
|
self:goToPage(self.page_count)
|
|
end,
|
|
}
|
|
local button_chapter_prev = Button:new{
|
|
text = chapter_prev_text,
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
local page = self.ui.toc:getPreviousChapter(self.curr_page)
|
|
if page and page >= 1 and page <= self.page_count then
|
|
self:goToPage(page)
|
|
end
|
|
end,
|
|
hold_callback = function()
|
|
self:goToPage(1)
|
|
end,
|
|
}
|
|
local button_bookmark_next = Button:new{
|
|
text = bookmark_next_text,
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
self:goToByEvent("GotoNextBookmarkFromPage")
|
|
end,
|
|
hold_callback = function()
|
|
self:goToByEvent("GotoLastBookmark")
|
|
end,
|
|
}
|
|
local button_bookmark_prev = Button:new{
|
|
text = bookmark_prev_text,
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
vsync = true,
|
|
callback = function()
|
|
self:goToByEvent("GotoPreviousBookmarkFromPage")
|
|
end,
|
|
hold_callback = function()
|
|
self:goToByEvent("GotoFirstBookmark")
|
|
end,
|
|
}
|
|
self.button_bookmark_toggle = Button:new{
|
|
text_func = function()
|
|
return self.ui.view.dogear_visible and bookmark_enabled_text or bookmark_disabled_text
|
|
end,
|
|
text_font_size = button_font_size,
|
|
radius = 0,
|
|
width = button_width,
|
|
show_parent = self,
|
|
callback = function()
|
|
self.ui:handleEvent(Event:new("ToggleBookmark"))
|
|
self:update()
|
|
end,
|
|
hold_callback = function()
|
|
self.ui:handleEvent(Event:new("ShowBookmark"))
|
|
UIManager:close(self)
|
|
end,
|
|
}
|
|
|
|
local small_button_span = HorizontalSpan:new{ width = button_span_unit_width }
|
|
local large_button_span = HorizontalSpan:new{ width = button_span_unit_width * larger_span_units }
|
|
local top_row_span, bottom_row_span, top_buttons_row, bottom_buttons_row, radius
|
|
if full_mode then
|
|
top_row_span = VerticalSpan:new{ width = Size.padding.fullscreen }
|
|
bottom_row_span = top_row_span
|
|
top_buttons_row = HorizontalGroup:new{
|
|
align = "center",
|
|
button_chapter_prev,
|
|
small_button_span,
|
|
button_bookmark_prev,
|
|
large_button_span,
|
|
self.button_bookmark_toggle,
|
|
large_button_span,
|
|
button_bookmark_next,
|
|
small_button_span,
|
|
button_chapter_next,
|
|
}
|
|
bottom_buttons_row = HorizontalGroup:new{
|
|
align = "center",
|
|
button_minus_ten,
|
|
small_button_span,
|
|
button_minus,
|
|
large_button_span,
|
|
self.current_page_text,
|
|
large_button_span,
|
|
button_plus,
|
|
small_button_span,
|
|
button_plus_ten,
|
|
}
|
|
radius = Size.radius.window
|
|
else
|
|
top_row_span = VerticalSpan:new{ width = Size.padding.default }
|
|
top_buttons_row = HorizontalGroup:new{
|
|
align = "center",
|
|
button_chapter_prev,
|
|
small_button_span,
|
|
button_chapter_next,
|
|
small_button_span,
|
|
button_bookmark_prev,
|
|
small_button_span,
|
|
button_bookmark_next,
|
|
small_button_span,
|
|
self.button_bookmark_toggle,
|
|
small_button_span,
|
|
self.current_page_text,
|
|
small_button_span,
|
|
button_orig_page,
|
|
small_button_span,
|
|
button_minus_ten,
|
|
small_button_span,
|
|
button_plus_ten,
|
|
small_button_span,
|
|
button_minus,
|
|
small_button_span,
|
|
button_plus,
|
|
}
|
|
if skim_dialog_position == "top" then
|
|
bottom_row_span, bottom_buttons_row = top_row_span, top_buttons_row
|
|
top_buttons_row = VerticalSpan:new{ width = 0 }
|
|
top_row_span = top_buttons_row
|
|
end
|
|
end
|
|
|
|
self.skimto_frame = FrameContainer:new{
|
|
margin = 0,
|
|
bordersize = frame_border_size,
|
|
padding = frame_padding,
|
|
radius = radius,
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
VerticalGroup:new{
|
|
align = "center",
|
|
top_buttons_row,
|
|
top_row_span,
|
|
self.progress_bar,
|
|
bottom_row_span,
|
|
bottom_buttons_row,
|
|
}
|
|
}
|
|
if full_mode then
|
|
self.movable = MovableContainer:new{
|
|
self.skimto_frame,
|
|
}
|
|
end
|
|
self[1] = WidgetContainer:new{
|
|
align = skim_dialog_position or "center",
|
|
dimen = Geom:new{
|
|
x = 0, y = 0,
|
|
w = screen_width,
|
|
h = screen_height,
|
|
},
|
|
self.movable or self.skimto_frame,
|
|
}
|
|
|
|
if Device:hasDPad() then
|
|
if full_mode then
|
|
self.layout = {
|
|
{ button_chapter_prev, button_bookmark_prev, self.button_bookmark_toggle, button_bookmark_next, button_chapter_next },
|
|
{ button_minus_ten, button_minus, self.current_page_text, button_plus, button_plus_ten },
|
|
}
|
|
else
|
|
self.layout = {
|
|
{ button_chapter_prev, button_chapter_next, button_bookmark_prev, button_bookmark_next, self.button_bookmark_toggle,
|
|
self.current_page_text, button_orig_page, button_minus_ten, button_plus_ten, button_minus, button_plus },
|
|
}
|
|
end
|
|
self:moveFocusTo(1, 1)
|
|
end
|
|
if Device:hasKeyboard() then
|
|
self.key_events.QKey = { { "Q" }, event = "FirstRowKeyPress", args = 0 }
|
|
self.key_events.WKey = { { "W" }, event = "FirstRowKeyPress", args = 0.11 }
|
|
self.key_events.EKey = { { "E" }, event = "FirstRowKeyPress", args = 0.22 }
|
|
self.key_events.RKey = { { "R" }, event = "FirstRowKeyPress", args = 0.33 }
|
|
self.key_events.TKey = { { "T" }, event = "FirstRowKeyPress", args = 0.44 }
|
|
self.key_events.YKey = { { "Y" }, event = "FirstRowKeyPress", args = 0.55 }
|
|
self.key_events.UKey = { { "U" }, event = "FirstRowKeyPress", args = 0.66 }
|
|
self.key_events.IKey = { { "I" }, event = "FirstRowKeyPress", args = 0.77 }
|
|
self.key_events.OKey = { { "O" }, event = "FirstRowKeyPress", args = 0.88 }
|
|
self.key_events.PKey = { { "P" }, event = "FirstRowKeyPress", args = 1 }
|
|
end
|
|
end
|
|
|
|
function SkimToWidget:update()
|
|
if self.curr_page <= 0 then
|
|
self.curr_page = 1
|
|
end
|
|
if self.curr_page > self.page_count then
|
|
self.curr_page = self.page_count
|
|
end
|
|
self.progress_bar.percentage = self.curr_page / self.page_count
|
|
self.current_page_text:setText(self.current_page_text:text_func(), self.current_page_text.width)
|
|
self.button_bookmark_toggle:setText(self.button_bookmark_toggle:text_func(), self.button_bookmark_toggle.width)
|
|
self:refocusWidget(FocusManager.RENDER_IN_NEXT_TICK)
|
|
end
|
|
|
|
function SkimToWidget:addOriginToLocationStack()
|
|
-- Only add the page from which we launched the SkimToWidget to the location stack
|
|
if not self.orig_page_added_to_stack then
|
|
self.ui.link:addCurrentLocationToStack()
|
|
self.orig_page_added_to_stack = true
|
|
end
|
|
end
|
|
|
|
function SkimToWidget:onCloseWidget()
|
|
if self.ui.paging then
|
|
self.ui.paging:exitSkimMode()
|
|
end
|
|
UIManager:setDirty(nil, function()
|
|
return "ui", self.skimto_frame.dimen
|
|
end)
|
|
self:free()
|
|
end
|
|
|
|
function SkimToWidget:onShow()
|
|
UIManager:setDirty(self, function()
|
|
return "ui", self.skimto_frame.dimen
|
|
end)
|
|
return true
|
|
end
|
|
|
|
function SkimToWidget:goToOrigPage()
|
|
if self.orig_page_added_to_stack then
|
|
self.ui.link:onGoBackLink()
|
|
self.curr_page = self.ui:getCurrentPage()
|
|
self:update()
|
|
self.orig_page_added_to_stack = nil
|
|
end
|
|
end
|
|
|
|
function SkimToWidget:goToPage(page)
|
|
self.curr_page = page
|
|
self:addOriginToLocationStack()
|
|
self.ui:handleEvent(Event:new("GotoPage", self.curr_page))
|
|
self:update()
|
|
end
|
|
|
|
function SkimToWidget:goToByEvent(event_name)
|
|
self:addOriginToLocationStack()
|
|
self.ui:handleEvent(Event:new(event_name, false))
|
|
-- add_current_location_to_stack=false, as we handled it here
|
|
self.curr_page = self.ui:getCurrentPage()
|
|
self:update()
|
|
end
|
|
|
|
function SkimToWidget:onFirstRowKeyPress(percent)
|
|
local page = Math.round(percent * self.page_count)
|
|
self:goToPage(page)
|
|
end
|
|
|
|
function SkimToWidget:onTapProgress(arg, ges_ev)
|
|
if ges_ev.pos:intersectWith(self.progress_bar.dimen) then
|
|
local percent = self.progress_bar:getPercentageFromPosition(ges_ev.pos)
|
|
if percent then
|
|
local page = Math.round(percent * self.page_count)
|
|
self:goToPage(page)
|
|
end
|
|
elseif not ges_ev.pos:intersectWith(self.skimto_frame.dimen) then
|
|
-- close if tap outside
|
|
self:onClose()
|
|
end
|
|
return true
|
|
end
|
|
|
|
function SkimToWidget:onClose()
|
|
UIManager:close(self)
|
|
return true
|
|
end
|
|
|
|
return SkimToWidget
|