Last active
December 20, 2025 19:39
-
-
Save sebdelsol/16ab741b44b75a46cbceb133163bbab5 to your computer and use it in GitHub Desktop.
KOReader user patch: Thin status bar with chapter markers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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, need extra space for the taller markers | |
| 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 a 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) | |
| -- color depend on the tick placment: white if it's read, black if after | |
| 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 save_thin_setting = self.settings.progress_style_thin | |
| local save_getTocTicksFlattened = self.ui.toc.getTocTicksFlattened | |
| self.settings.progress_style_thin = false -- prevent premature exit | |
| self.ui.toc.getTocTicksFlattened = function(self, for_chapter_navigation) return self.ui.toc.getTocTicks(self, 1) end -- TOC only at level 1 | |
| orig_ReaderFooter_setTocMarkers(self, reset) | |
| self.settings.progress_style_thin = save_thin_setting | |
| self.ui.toc.getTocTicksFlattened = save_getTocTicksFlattened | |
| self.progress_bar.special_tick = self.settings.progress_style_thin and self.settings.toc_markers -- check ProgressWidget.paintTo | |
| end | |
| local orig_ReaderFooter_addToMainMenu = ReaderFooter.addToMainMenu | |
| local replace_item = function(attrib_name, replacement, menu, ...) | |
| local logger = require("logger") | |
| local find_sub_item = function(sub_items, text_to_find) | |
| local is_text | |
| if type(text_to_find) == "table" then | |
| local set = {} for _, text in ipairs(text_to_find) do set[text] = true end | |
| is_text = function(text) return set[text] end | |
| else | |
| is_text = function(text) return text == text_to_find end | |
| end | |
| for _, item in ipairs(sub_items) do | |
| local item_text = item.text or (item.text_func and item.text_func()) | |
| if item_text and is_text(item_text) then | |
| -- logger.info("Found item", item_text) | |
| return item | |
| end | |
| end | |
| end | |
| local find_item_from_path = function(menu, path) | |
| local sub_items, item | |
| for _, text in ipairs(path) do | |
| sub_items = (item or menu).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_item_from_path(menu, {...}) | |
| if item then | |
| item[attrib_name] = replacement | |
| local path = {...} for i, t in ipairs(path) do if type(t)=="table" then path[i] = table.concat(t, " | ") end end | |
| logger.info("Patch", attrib_name, "in '", table.concat(path," > "),"'") | |
| 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 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
MOVED to https://github.com/sebdelsol/KOReader.patches