local BD = require("ui/bidi") local Blitbuffer = require("ffi/blitbuffer") local Device = require("device") local Font = require("ui/font") local Geom = require("ui/geometry") local ProgressWidget = require("ui/widget/progresswidget") local SpinWidget = require("ui/widget/spinwidget") local TextWidget = require("ui/widget/textwidget") local UIManager = require("ui/uimanager") local Math = require("optmath") local ReaderFooter = require("apps/reader/modules/readerfooter") local T = require("ffi/util").template local _ = require("gettext") local Screen = Device.screen -- Somewhat empirically chosen threshold to switch between the two designs ;o) local INITIAL_MARKER_HEIGHT_THRESHOLD = Screen:scaleBySize(12) ProgressWidget.paintTo = function(self, bb, x, y) -- TODO Overlay the initial position marker on top of that local my_size = self:getSize() -- same bar height if special local dy = self.special_tick and math.floor(Screen:scaleBySize(1) / 2) or 0 my_size.h = my_size.h + dy * 2 if not self.dimen then self.dimen = Geom:new{ x = x, y = y, w = my_size.w, h = my_size.h } else self.dimen.x = x self.dimen.y = y end if self.dimen.w == 0 or self.dimen.h == 0 then return end local _mirroredUI = BD.mirroredUILayout() -- We'll draw every bar element in order, bottom to top. local fill_width = my_size.w - 2*(self.margin_h + self.bordersize) local fill_y = y + self.margin_v + self.bordersize local fill_height = my_size.h - 2*(self.margin_v + self.bordersize) if not self.special_tick then -- special doesn't need border if self.radius == 0 then -- If we don't have rounded borders, we can start with a simple border colored rectangle. bb:paintRect(x, y, my_size.w, my_size.h, self.bordercolor) -- And a full background bar inside (i.e., on top) of that. bb:paintRect(x + self.margin_h + self.bordersize, fill_y, math.ceil(fill_width), math.ceil(fill_height), self.bgcolor) else -- Otherwise, we have to start with the background. bb:paintRoundedRect(x, y, my_size.w, my_size.h, self.bgcolor, self.radius) -- Then the border around that. bb:paintBorder(math.floor(x), math.floor(y), my_size.w, my_size.h, self.bordersize, self.bordercolor, self.radius) end end -- Then we can just paint the fill rectangle(s) and tick(s) on top of that. -- First the fill bar(s)... -- Fill bar for alternate pages (e.g. non-linear flows). if self.alt and self.alt[1] ~= nil then for i=1, #self.alt do local tick_x = fill_width * ((self.alt[i][1] - 1) / self.last) local width = fill_width * (self.alt[i][2] / self.last) if _mirroredUI then tick_x = fill_width - tick_x - width end tick_x = math.floor(tick_x) width = math.ceil(width) bb:paintRect(x + self.margin_h + self.bordersize + tick_x, fill_y + dy, width, math.ceil(fill_height) - dy * 2, self.altcolor) end elseif self.special_tick then -- paint in case missing bb:paintRect(x + self.margin_h + self.bordersize, fill_y + dy, fill_width, math.ceil(fill_height) - dy * 2, self.altcolor) end -- Main fill bar for the specified percentage. if self.percentage >= 0 and self.percentage <= 1 then local fill_x = x + self.margin_h + self.bordersize if self.fill_from_right or (_mirroredUI and not self.fill_from_right) then fill_x = fill_x + (fill_width * (1 - self.percentage)) fill_x = math.floor(fill_x) end bb:paintRect(fill_x, fill_y + dy, math.ceil(fill_width * self.percentage), math.ceil(fill_height) - dy * 2, self.fillcolor) -- Overlay the initial position marker on top of that if self.initial_pos_marker and self.initial_percentage >= 0 then if self.height <= INITIAL_MARKER_HEIGHT_THRESHOLD then self.initial_pos_icon:paintTo(bb, Math.round(fill_x + math.ceil(fill_width * self.initial_percentage) - self.height / 4), y - Math.round(self.height / 6)) else self.initial_pos_icon:paintTo(bb, Math.round(fill_x + math.ceil(fill_width * self.initial_percentage) - self.height / 2), y) end end end -- ...then the tick(s). if self.ticks and self.last and self.last > 0 then local filled = math.floor(fill_width * self.percentage) for i, tick in ipairs(self.ticks) do local tick_x = fill_width * (tick / self.last) if _mirroredUI then tick_x = fill_width - tick_x end tick_x = math.floor(tick_x) local color = (self.special_tick and (tick_x < filled)) and Blitbuffer.COLOR_WHITE or self.bordercolor bb:paintRect(x + self.margin_h + self.bordersize + tick_x, fill_y, self.tick_width, math.ceil(fill_height), color) end end end local orig_ReaderFooter_setTocMarkers = ReaderFooter.setTocMarkers ReaderFooter.setTocMarkers = function(self, reset) local thin_save = self.settings.progress_style_thin self.settings.progress_style_thin = false local getTocTicksFlattened_save = self.ui.toc.getTocTicksFlattened self.ui.toc.getTocTicksFlattened = function(self, reset) -- TOC only at level 1 return self.ui.toc.getTocTicks(self, 1) end orig_ReaderFooter_setTocMarkers(self, reset) self.settings.progress_style_thin = thin_save self.ui.toc.getTocTicksFlattened = getTocTicksFlattened_save self.progress_bar.special_tick = self.settings.progress_style_thin and self.settings.toc_markers end local orig_ReaderFooter_addToMainMenu = ReaderFooter.addToMainMenu local replace_item = function(attrib, replacement, menu, ...) -- local logger = require("logger") local find_sub_item = function(sub_items, text_to_find) local test if type(text_to_find) == "table" then local set = {} for _, text in ipairs(text_to_find) do set[text] = true end test = function(text) return set[text] end else test = function(text) return text == text_to_find end end for _, item in ipairs(sub_items) do local text = item.text or (item.text_func and item.text_func()) if test(text) then -- logger.info("Found item", text) return item end end end local find_deep_item = function(menu, ...) local sub_items local item = menu for _, text in ipairs({...}) do sub_items = item.sub_item_table if not sub_items then return end item = find_sub_item(sub_items, text) if not item then return end end return item end local item = find_deep_item(menu, ...) if item then item[attrib] = replacement -- local path = {...} for i, t in ipairs(path) do if type(t)=="table" then path[i] = table.concat(t, " or ") end end -- logger.info("Patch", attrib, "in '", table.concat(path," > "),"'") return true end end ReaderFooter.addToMainMenu = function(self, menu_items) orig_ReaderFooter_addToMainMenu(self, menu_items) replace_item( "callback", function() self.settings.progress_style_thin = true local bar_height = self.settings.progress_style_thin_height self.progress_bar:updateStyle(false, bar_height) self:setTocMarkers() self:refreshFooter(true, true) end, menu_items.status_bar, _("Progress bar"), {_("Thickness and height: thin"), _("Thickness and height: thick")}, _("Thin") ) replace_item( "enabled_func", function() return not self.settings.chapter_progress_bar and not self.settings.disable_progress_bar end, menu_items.status_bar, _("Progress bar"), _("Show chapter markers") ) replace_item( "enabled_func", function() return not self.settings.chapter_progress_bar and self.settings.toc_markers and not self.settings.disable_progress_bar end, menu_items.status_bar, _("Progress bar"), T(_("Chapter marker width: %1"), self:genProgressBarChapterMarkerWidthMenuItems()) ) end