local Blitbuffer = require("ffi/blitbuffer") local Button = require("ui/widget/button") local CenterContainer = require("ui/widget/container/centercontainer") local CloseButton = require("ui/widget/closebutton") local Device = require("device") local Event = require("ui/event") local Font = require("ui/font") 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 InputContainer = require("ui/widget/container/inputcontainer") local LineWidget = require("ui/widget/linewidget") local Math = require("optmath") local MovableContainer = require("ui/widget/container/movablecontainer") local OverlapGroup = require("ui/widget/overlapgroup") local ProgressWidget = require("ui/widget/progresswidget") local Size = require("ui/size") local TextWidget = require("ui/widget/textwidget") 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 = InputContainer:new{ title_face = Font:getFace("x_smalltfont"), width = nil, height = nil, } function SkimToWidget:init() self.medium_font_face = Font:getFace("ffont") self.screen_width = Screen:getWidth() self.screen_height = Screen:getHeight() self.span = math.ceil(self.screen_height * 0.01) self.width = self.screen_width * 0.95 self.button_bordersize = Size.border.button -- the buttons need some kind of separation but maybe I should just implement -- margin_left and margin_right… self.button_margin = self.button_bordersize self.button_width = self.screen_width * 0.16 - (2*self.button_margin) if Device:hasKeys() then self.key_events = { Close = { {"Back"}, doc = "close skimto page" } } end if Device:isTouchDevice() then self.ges_events = { TapProgress = { GestureRange:new{ ges = "tap", range = Geom:new{ x = 0, y = 0, w = self.screen_width, h = self.screen_height, } }, }, } end local dialog_title if self.document.info.has_pages then dialog_title = _("Go to Page") self.curr_page = self.ui.paging.current_page else dialog_title = _("Go to Location") self.curr_page = self.document:getCurrentPage() end self.page_count = self.document:getPageCount() local ticks_candidates = {} if self.ui.toc then local max_level = self.ui.toc:getMaxDepth() for i = 0, -max_level, -1 do local ticks = self.ui.toc:getTocTicks(i) table.insert(ticks_candidates, ticks) end -- find the finest toc ticks by sorting out the largest one table.sort(ticks_candidates, function(a, b) return #a > #b end) end if #ticks_candidates > 0 then self.ticks_candidates = ticks_candidates[1] end local skimto_title = FrameContainer:new{ padding = Size.padding.default, margin = Size.margin.title, bordersize = 0, TextWidget:new{ text = dialog_title, face = self.title_face, bold = true, width = self.screen_width * 0.95, }, } self.progress_bar = ProgressWidget:new{ width = self.screen_width * 0.9, height = Screen:scaleBySize(30), percentage = self.curr_page / self.page_count, ticks = self.ticks_candidates, tick_width = Size.line.medium, last = self.page_count, } self.skimto_progress = FrameContainer:new{ padding = Size.padding.button, margin = Size.margin.small, bordersize = 0, self.progress_bar, } local skimto_line = LineWidget:new{ dimen = Geom:new{ w = self.width, h = Size.line.thick, } } local skimto_bar = OverlapGroup:new{ dimen = { w = self.width, h = skimto_title:getSize().h }, skimto_title, CloseButton:new{ window = self, padding_top = Size.margin.title, }, } local button_minus = Button:new{ text = "-1", bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() self.curr_page = self.curr_page - 1 self:update() self.ui:handleEvent(Event:new("GotoPage", self.curr_page)) end, } local button_minus_ten = Button:new{ text = "-10", bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() self.curr_page = self.curr_page - 10 self:update() self.ui:handleEvent(Event:new("GotoPage", self.curr_page)) end, } local button_plus = Button:new{ text = "+1", bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() self.curr_page = self.curr_page + 1 self:update() self.ui:handleEvent(Event:new("GotoPage", self.curr_page)) end, } local button_plus_ten = Button:new{ text = "+10", bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() self.curr_page = self.curr_page + 10 self:update() self.ui:handleEvent(Event:new("GotoPage", self.curr_page)) end, } self.current_page_text = Button:new{ text = self.curr_page, bordersize = 0, margin = self.button_margin, radius = 0, padding = 0, enabled = true, width = self.screen_width * 0.2 - (2*self.button_margin), show_parent = self, callback = function() self.callback_switch_to_goto() end, } local button_chapter_next = Button:new{ text = '▷│', bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() local page = self:getNextChapter(self.curr_page) if page and page >=1 and page <= self.page_count then self.curr_page = page self.ui:handleEvent(Event:new("GotoPage", self.curr_page)) self:update() end end, } local button_chapter_prev = Button:new{ text = "│◁", bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() local page = self:getPrevChapter(self.curr_page) if page and page >=1 and page <= self.page_count then self.curr_page = page self.ui:handleEvent(Event:new("GotoPage", self.curr_page)) self:update() end end, } local button_bookmark_next = Button:new{ text = "☆▷", bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() local page if self.document.info.has_pages then page = self.ui.bookmark:getNextBookmarkedPageFromPage(self.ui.paging.current_page) else page = self.ui.bookmark:getNextBookmarkedPageFromPage(self.curr_page) end if page then self.ui.bookmark:gotoBookmark(page) if self.document.info.has_pages then self.curr_page = self.ui.paging.current_page else self.curr_page = self.document:getCurrentPage() end self:update() end end, } local button_bookmark_prev = Button:new{ text = "◁☆", bordersize = self.button_bordersize, margin = self.button_margin, radius = 0, enabled = true, width = self.button_width, show_parent = self, callback = function() local page if self.document.info.has_pages then page = self.ui.bookmark:getPreviousBookmarkedPageFromPage(self.ui.paging.current_page) else page = self.ui.bookmark:getPreviousBookmarkedPageFromPage(self.curr_page) end if page then self.ui.bookmark:gotoBookmark(page) if self.document.info.has_pages then self.curr_page = self.ui.paging.current_page else self.curr_page = self.document:getCurrentPage() end self:update() end end, } local horizontal_span_up = HorizontalSpan:new{ width = self.screen_width * 0.2 } local button_table_up = HorizontalGroup:new{ align = "center", button_chapter_prev, button_bookmark_prev, horizontal_span_up, button_bookmark_next, button_chapter_next, } local vertical_group_up = VerticalGroup:new{ align = "center" } local padding_span_up = VerticalSpan:new{ width = math.ceil(self.screen_height * 0.015) } table.insert(vertical_group_up, padding_span_up) table.insert(vertical_group_up, button_table_up) table.insert(vertical_group_up, padding_span_up) local button_table_down = HorizontalGroup:new{ align = "center", button_minus, button_minus_ten, self.current_page_text, button_plus_ten, button_plus, } local vertical_group_down = VerticalGroup:new{ align = "center" } local padding_span = VerticalSpan:new{ width = math.ceil(self.screen_height * 0.015) } table.insert(vertical_group_down, padding_span) table.insert(vertical_group_down, button_table_down) table.insert(vertical_group_down, padding_span) self.skimto_frame = FrameContainer:new{ radius = Size.radius.window, bordersize = Size.border.window, padding = 0, margin = 0, background = Blitbuffer.COLOR_WHITE, VerticalGroup:new{ align = "center", skimto_bar, skimto_line, vertical_group_up, CenterContainer:new{ dimen = Geom:new{ w = skimto_line:getSize().w, h = self.skimto_progress:getSize().h, }, self.skimto_progress, }, vertical_group_down, } } self[1] = WidgetContainer:new{ align = "center", dimen =Geom:new{ x = 0, y = 0, w = self.screen_width, h = self.screen_height, }, MovableContainer:new{ -- alpha = 0.8, self.skimto_frame, } } 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.curr_page, self.current_page_text.width) end function SkimToWidget:getNextChapter(cur_pageno) local next_chapter = nil for i = 1, #self.ticks_candidates do if self.ticks_candidates[i] > cur_pageno then next_chapter = self.ticks_candidates[i] break end end return next_chapter end function SkimToWidget:getPrevChapter(cur_pageno) local previous_chapter = nil for i = 1, #self.ticks_candidates do if self.ticks_candidates[i] >= cur_pageno then break end previous_chapter = self.ticks_candidates[i] end return previous_chapter end function SkimToWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.skimto_frame.dimen end) return true end function SkimToWidget:onShow() UIManager:setDirty(self, function() return "ui", self.skimto_frame.dimen end) return true end function SkimToWidget:onAnyKeyPressed() UIManager:close(self) return true end function SkimToWidget:onTapProgress(arg, ges_ev) if ges_ev.pos:intersectWith(self.progress_bar.dimen) then local width = self.progress_bar.dimen.w local pos = ges_ev.pos.x - self.progress_bar.dimen.x local perc = pos / width local page = Math.round(perc * self.page_count) self.ui:handleEvent(Event:new("GotoPage", page )) self.curr_page = page self:update() elseif not ges_ev.pos:intersectWith(self.skimto_frame.dimen) then -- close if tap outside self:onClose() end -- otherwise, do nothing (it's easy missing taping a button) return true end function SkimToWidget:onClose() UIManager:close(self) return true end return SkimToWidget