diff --git a/base b/base index bef742eb7..afd0c6c5a 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit bef742eb7e04d8e1dc5948f8827bf4760158dc45 +Subproject commit afd0c6c5a6d50e15ecfede981f5c8bcb768ad43a diff --git a/frontend/apps/filemanager/filemanager.lua b/frontend/apps/filemanager/filemanager.lua index 051621a1d..cf04ce733 100644 --- a/frontend/apps/filemanager/filemanager.lua +++ b/frontend/apps/filemanager/filemanager.lua @@ -159,7 +159,7 @@ function FileManager:init() function file_chooser:onPathChanged(path) -- luacheck: ignore FileManager.instance.path_text:setText(truncatePath(filemanagerutil.abbreviate(path))) UIManager:setDirty(FileManager.instance, function() - return "partial", FileManager.instance.path_text.dimen + return "partial", FileManager.instance.path_text.dimen, FileManager.instance.dithered end) return true end diff --git a/frontend/apps/reader/modules/readerfooter.lua b/frontend/apps/reader/modules/readerfooter.lua index 72de85796..a94e7e2f5 100644 --- a/frontend/apps/reader/modules/readerfooter.lua +++ b/frontend/apps/reader/modules/readerfooter.lua @@ -417,7 +417,7 @@ function ReaderFooter:addToMainMenu(menu_items) end if should_update then self:updateFooter() - UIManager:setDirty("all", "partial") + UIManager:setDirty(nil, "ui") end end, } @@ -436,7 +436,7 @@ function ReaderFooter:addToMainMenu(menu_items) callback = function() self.settings.disable_progress_bar = not self.settings.disable_progress_bar self:updateFooter() - UIManager:setDirty("all", "partial") + UIManager:setDirty(nil, "ui") end, }, getMinibarOption("toc_markers", self.setTocMarkers), @@ -579,6 +579,8 @@ function ReaderFooter:_updateFooterText() end self.text_container.dimen.w = self.text_width self.horizontal_group:resetLayout() + -- NOTE: This is essentially preventing us from truly using "fast" for panning, + -- since it'll get coalesced in the "fast" panning update, upgrading it to "ui". UIManager:setDirty(self.view.dialog, function() return "ui", self.footer_content.dimen end) diff --git a/frontend/apps/reader/modules/readerstatus.lua b/frontend/apps/reader/modules/readerstatus.lua index 0e69dbcfc..e7c3ce168 100644 --- a/frontend/apps/reader/modules/readerstatus.lua +++ b/frontend/apps/reader/modules/readerstatus.lua @@ -152,7 +152,8 @@ function ReaderStatus:showStatus(before_show_callback) if before_show_callback then before_show_callback() end - UIManager:show(status_page) + status_page.dithered = true + UIManager:show(status_page, "full") end function ReaderStatus:onReadSettings(config) diff --git a/frontend/apps/reader/modules/readertoc.lua b/frontend/apps/reader/modules/readertoc.lua index 5f5385057..d0984c347 100644 --- a/frontend/apps/reader/modules/readertoc.lua +++ b/frontend/apps/reader/modules/readertoc.lua @@ -76,7 +76,7 @@ function ReaderToc:onPageUpdate(pageno) if self:isChapterEnd(pageno, 0) then self.chapter_refresh = true elseif self:isChapterBegin(pageno, 0) and self.chapter_refresh then - UIManager:setDirty("all", "full") + UIManager:setDirty(nil, "full") self.chapter_refresh = false else self.chapter_refresh = false diff --git a/frontend/apps/reader/modules/readerview.lua b/frontend/apps/reader/modules/readerview.lua index c0f6d9843..fa1f559f2 100644 --- a/frontend/apps/reader/modules/readerview.lua +++ b/frontend/apps/reader/modules/readerview.lua @@ -213,6 +213,23 @@ function ReaderView:paintTo(bb, x, y) end -- stop activity indicator self.ui:handleEvent(Event:new("StopActivityIndicator")) + + -- Most pages should not require dithering + self.dialog.dithered = nil + -- For KOpt, let the user choose. + if self.ui.document.info.has_pages then + if self.document.configurable.hw_dithering == 1 then + self.dialog.dithered = true + end + else + -- Whereas for CRe, + -- If we're attempting to show a large enough amount of image data, request dithering (without triggering another repaint ;)). + local img_count, img_coverage = self.ui.document:getDrawnImagesStatistics() + -- With some nil guards because this may not be implemented in every engine ;). + if img_count and img_count > 0 and img_coverage and img_coverage >= 0.075 then + self.dialog.dithered = true + end + end end --[[ @@ -545,6 +562,9 @@ end This method is supposed to be only used by ReaderPaging --]] function ReaderView:recalculate() + -- Start by resetting the dithering flag early, so it doesn't carry over from the previous page. + self.dialog.dithered = nil + if self.ui.document.info.has_pages and self.state.page then self.page_area = self:getPageArea( self.state.page, @@ -579,6 +599,7 @@ function ReaderView:recalculate() self.state.offset.x = (self.dimen.w - self.visible_area.w) / 2 end -- flag a repaint so self:paintTo will be called + -- NOTE: This is also unfortunately called during panning, essentially making sure we'll never be using "fast" for pans ;). UIManager:setDirty(self.dialog, "partial") end @@ -588,7 +609,7 @@ function ReaderView:PanningUpdate(dx, dy) self.visible_area:offsetWithin(self.page_area, dx, dy) if self.visible_area ~= old then -- flag a repaint - UIManager:setDirty(self.dialog, "partial") + UIManager:setDirty(self.dialog, "fast") logger.dbg("on pan: page_area", self.page_area) logger.dbg("on pan: visible_area", self.visible_area) self.ui:handleEvent( @@ -605,7 +626,7 @@ function ReaderView:PanningStart(x, y) self.visible_area = self.panning_visible_area:copy() self.visible_area:offsetWithin(self.page_area, x, y) self.ui:handleEvent(Event:new("ViewRecalculate", self.visible_area, self.page_area)) - UIManager:setDirty(self.dialog, "partial") + UIManager:setDirty(self.dialog, "fast") end function ReaderView:PanningStop() diff --git a/frontend/device/generic/device.lua b/frontend/device/generic/device.lua index c9bf84996..6a2aadc99 100644 --- a/frontend/device/generic/device.lua +++ b/frontend/device/generic/device.lua @@ -26,6 +26,7 @@ local Device = { needsTouchScreenProbe = no, hasClipboard = yes, -- generic internal clipboard on all devices hasEinkScreen = yes, + canHWDither = no, hasColorScreen = no, hasBGRFrameBuffer = no, canToggleGSensor = no, @@ -190,7 +191,9 @@ function Device:onPowerEvent(ev) self.orig_rotation_mode = nil end require("ui/screensaver"):show() - self.screen:refreshFull() + if self:needsScreenRefreshAfterResume() then + self.screen:refreshFull() + end self.screen_saver_mode = true UIManager:scheduleIn(0.1, function() local network_manager = require("ui/network/manager") diff --git a/frontend/device/kobo/device.lua b/frontend/device/kobo/device.lua index c860f780a..70223593a 100644 --- a/frontend/device/kobo/device.lua +++ b/frontend/device/kobo/device.lua @@ -32,6 +32,8 @@ local Kobo = Generic:new{ touch_mirrored_x = true, -- enforce portrait mode on Kobos isAlwaysPortrait = yes, + -- we don't need an extra refreshFull on resume, thank you very much. + needsScreenRefreshAfterResume = no, -- the internal storage mount point users can write to internal_storage_mount_point = "/mnt/onboard/", -- currently only the Aura One and Forma have coloured frontlights diff --git a/frontend/device/sysfs_light.lua b/frontend/device/sysfs_light.lua index c1ddd2c54..f5c5d8d9f 100644 --- a/frontend/device/sysfs_light.lua +++ b/frontend/device/sysfs_light.lua @@ -103,9 +103,9 @@ end dbg:guard(SysfsLight, 'setNaturalBrightness', function(self, brightness, warmth) - assert(brightness >= 0 and brightness <= 100, + assert(brightness == nil or (brightness >= 0 and brightness <= 100), "Wrong brightness value given!") - assert(warmth >= 0 and warmth <= 100, + assert(warmth == nil or (warmth >= 0 and warmth <= 100), "Wrong warmth value given!") end) diff --git a/frontend/ui/data/koptoptions.lua b/frontend/ui/data/koptoptions.lua index 4ce4f67d1..7b88ac202 100644 --- a/frontend/ui/data/koptoptions.lua +++ b/frontend/ui/data/koptoptions.lua @@ -251,6 +251,16 @@ This can also be used to remove some gray background or to convert a grayscale o end, name_text_hold_callback = optionsutil.showValues, }, + { + name = "hw_dithering", + name_text = S.HW_DITHERING, + toggle = {S.ON, S.OFF}, + values = {1, 0}, + default_value = 0, + advanced = true, + show = Device:hasEinkScreen() and Device:canHWDither(), + name_text_hold_callback = optionsutil.showValues, + }, { name = "forced_ocr", name_text = S.FORCED_OCR, diff --git a/frontend/ui/data/strings.lua b/frontend/ui/data/strings.lua index 902a854d6..65021d801 100644 --- a/frontend/ui/data/strings.lua +++ b/frontend/ui/data/strings.lua @@ -32,6 +32,7 @@ S.EMBEDDED_FONTS = _("Embedded Fonts") S.WRITING_DIR = _("Writing Direction") S.PROGRESS_BAR = _("Progress Bar") S.FORCED_OCR = _("Forced OCR") +S.HW_DITHERING = _("Dithering") S.INVERSE_READING_ORDER = _("Inverse Order") S.ON = _("on") diff --git a/frontend/ui/screensaver.lua b/frontend/ui/screensaver.lua index 8e3a13857..dd2870745 100644 --- a/frontend/ui/screensaver.lua +++ b/frontend/ui/screensaver.lua @@ -387,7 +387,8 @@ function Screensaver:show(event, fallback_message) covers_fullscreen = covers_fullscreen, } self.left_msg.modal = true - -- refresh whole screen for other types + -- Refresh whole screen for other types + self.left_msg.dithered = true UIManager:show(self.left_msg, "full") end end @@ -400,8 +401,7 @@ function Screensaver:close() UIManager:scheduleIn(screensaver_delay_number, function() logger.dbg("close screensaver") if self.left_msg then - UIManager:close(self.left_msg) - UIManager:setDirty("all", "full") + UIManager:close(self.left_msg, "full") self.left_msg = nil end end) diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index 657bc85cc..04aba90f8 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -56,7 +56,9 @@ function UIManager:init() self._entered_poweroff_stage = true; Screen:setRotationMode(0) require("ui/screensaver"):show("poweroff", _("Powered off")) - Screen:refreshFull() + if Device:needsScreenRefreshAfterResume() then + Screen:refreshFull() + end UIManager:nextTick(function() Device:saveSettings() self:broadcastEvent(Event:new("Close")) @@ -67,7 +69,9 @@ function UIManager:init() self._entered_poweroff_stage = true; Screen:setRotationMode(0) require("ui/screensaver"):show("reboot", _("Rebooting...")) - Screen:refreshFull() + if Device:needsScreenRefreshAfterResume() then + Screen:refreshFull() + end UIManager:nextTick(function() Device:saveSettings() self:broadcastEvent(Event:new("Close")) @@ -261,13 +265,14 @@ For refreshtype & refreshregion see description of setDirty(). ---- @param refreshregion a Geom object ---- @int x ---- @int y +---- @param refreshdither an optional bool ---- @see setDirty -function UIManager:show(widget, refreshtype, refreshregion, x, y) +function UIManager:show(widget, refreshtype, refreshregion, x, y, refreshdither) if not widget then logger.dbg("widget not exist to be shown") return end - logger.dbg("show widget", widget.id or widget.name or "unknown") + logger.dbg("show widget:", widget.id or widget.name or tostring(widget)) self._running = true local window = {x = x or 0, y = y or 0, widget = widget} @@ -281,7 +286,7 @@ function UIManager:show(widget, refreshtype, refreshregion, x, y) end end -- and schedule it to be painted - self:setDirty(widget, refreshtype, refreshregion) + self:setDirty(widget, refreshtype, refreshregion, refreshdither) -- tell the widget that it is shown now widget:handleEvent(Event:new("Show")) -- check if this widget disables double tap gesture @@ -300,13 +305,14 @@ For refreshtype & refreshregion see description of setDirty(). ---- @param widget a widget object ---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast" ---- @param refreshregion a Geom object +---- @param refreshdither an optional bool ---- @see setDirty -function UIManager:close(widget, refreshtype, refreshregion) +function UIManager:close(widget, refreshtype, refreshregion, refreshdither) if not widget then logger.dbg("widget to be closed does not exist") return end - logger.dbg("close widget", widget.id or widget.name) + logger.dbg("close widget:", widget.name or widget.id or tostring(widget)) local dirty = false -- Ensure all the widgets can get onFlushSettings event. widget:handleEvent(Event:new("FlushSettings")) @@ -317,10 +323,19 @@ function UIManager:close(widget, refreshtype, refreshregion) -- then remove all references to that widget on stack and refresh for i = #self._window_stack, 1, -1 do if self._window_stack[i].widget == widget then + self._dirty[self._window_stack[i].widget] = nil table.remove(self._window_stack, i) dirty = true - elseif self._window_stack[i].widget.disable_double_tap == false then - Input.disable_double_tap = false + else + -- If anything else on the stack was dithered, honor the hint + if self._window_stack[i].widget.dithered then + refreshdither = true + logger.dbg("Lower widget", self._window_stack[i].widget.name or self._window_stack[i].widget.id or tostring(self._window_stack[i].widget), "was dithered, honoring the dithering hint") + end + + if self._window_stack[i].widget.disable_double_tap == false then + Input.disable_double_tap = false + end end end if dirty and not widget.invisible then @@ -328,7 +343,7 @@ function UIManager:close(widget, refreshtype, refreshregion) for i = 1, #self._window_stack do self:setDirty(self._window_stack[i].widget) end - self:_refresh(refreshtype, refreshregion) + self:_refresh(refreshtype, refreshregion, refreshdither) end end @@ -464,6 +479,8 @@ NOTE: You'll notice a trend on UI elements that are usually shown *over* some ki That said, depending on your use case, using "ui" onClose can be a perfectly valid decision, and will ensure never seeing a flash because of that widget. +The final parameter (refreshdither) is an optional hint for devices with hardware dithering support that this repaint +could benefit from dithering (i.e., it contains an image). @usage @@ -475,15 +492,32 @@ UIManager:setDirty(self.widget, function() return "ui", self.someelement.dimen e ---- @param widget a widget object ---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast" ---- @param refreshregion a Geom object -function UIManager:setDirty(widget, refreshtype, refreshregion) +---- @param refreshdither an optional bool +function UIManager:setDirty(widget, refreshtype, refreshregion, refreshdither) if widget then if widget == "all" then -- special case: set all top-level widgets as being "dirty". for i = 1, #self._window_stack do self._dirty[self._window_stack[i].widget] = true + -- If any of 'em were dithered, honor their dithering hint + if self._window_stack[i].widget.dithered then + -- NOTE: That works when refreshtype is NOT a function, + -- which is why _repaint does another pass of this check ;). + refreshdither = true + end end elseif not widget.invisible then - self._dirty[widget] = true + -- We only ever check the dirty flag on top-level widgets, so only set it there! + -- NOTE: Enable verbose debug to catch misbehaving widgets via our post-guard. + for i = 1, #self._window_stack do + if self._window_stack[i].widget == widget then + self._dirty[widget] = true + end + end + -- Again, if it's flagged as dithered, honor that + if widget.dithered then + refreshdither = true + end end end -- handle refresh information @@ -493,23 +527,23 @@ function UIManager:setDirty(widget, refreshtype, refreshregion) if dbg.is_on then -- FIXME: We can't consume the return values of refreshtype by running it, because for a reason that is beyond me (scoping? gc?), that renders it useless later, meaning we then enqueue refreshes with bogus arguments... -- Thankfully, we can track them in _refresh()'s logging very soon after that... - logger.dbg("setDirty via a func from widget", widget and (widget.name or widget.id or tostring(widget))) + logger.dbg("setDirty via a func from widget", widget and (widget.name or widget.id or tostring(widget)) or "nil") end else -- otherwise, enqueue refresh - self:_refresh(refreshtype, refreshregion) + self:_refresh(refreshtype, refreshregion, refreshdither) if dbg.is_on then if refreshregion then - logger.dbg("setDirty", refreshtype and refreshtype or "nil", "from widget", widget and (widget.name or widget.id or tostring(widget)) or "nil", "w/ region", refreshregion.x, refreshregion.y, refreshregion.w, refreshregion.h) + logger.dbg("setDirty", refreshtype and refreshtype or "nil", "from widget", widget and (widget.name or widget.id or tostring(widget)) or "nil", "w/ region", refreshregion.x, refreshregion.y, refreshregion.w, refreshregion.h, refreshdither and "AND w/ HW dithering" or "") else - logger.dbg("setDirty", refreshtype and refreshtype or "nil", "from widget", widget and (widget.name or widget.id or tostring(widget)) or "nil", "w/ NO region") + logger.dbg("setDirty", refreshtype and refreshtype or "nil", "from widget", widget and (widget.name or widget.id or tostring(widget)) or "nil", "w/ NO region", refreshdither and "AND w/ HW dithering" or "") end end end end dbg:guard(UIManager, 'setDirty', nil, - function(self, widget, refreshtype, refreshregion) + function(self, widget, refreshtype, refreshregion, refreshdither) if not widget or widget == "all" then return end -- when debugging, we check if we get handed a valid widget, -- which would be a dialog that was previously passed via show() @@ -680,6 +714,8 @@ end -- precedence of refresh modes: local refresh_modes = { fast = 1, ui = 2, partial = 3, flashui = 4, flashpartial = 5, full = 6 } +-- NOTE: We might want to introduce a "force_fast" that points to fast, but has the highest priority, +-- for the few cases where we might *really* want to enforce fast (for stuff like panning or skimming?). -- refresh methods in framebuffer implementation local refresh_methods = { fast = "refreshFast", @@ -704,6 +740,20 @@ local function update_mode(mode1, mode2) end end +--[[ +Compares dither hints. + +Dither always wins. +--]] +local function update_dither(dither1, dither2) + if dither1 and not dither2 then + logger.dbg("update_dither: Update dither hint", dither2, "to", dither1) + return dither1 + else + return dither2 + end +end + --[[-- Enqueues a refresh. @@ -716,9 +766,20 @@ UIManager that a certain part of the screen is to be refreshed. Rect() that specifies the region to be updated optional, update will affect whole screen if not specified. Note that this should be the exception. +@param dither + Bool, a hint to request hardware dithering (if supported) + optional, no dithering requested if not specified or not supported. --]] -function UIManager:_refresh(mode, region) - if not mode then return end +function UIManager:_refresh(mode, region, dither) + if not mode then + -- If we're trying to float a dither hint up from a lower widget after a close, mode might be nil... + -- So use the lowest priority refresh mode (short of fast, because that'd do half-toning). + if dither then + mode = "ui" + else + return + end + end if not region and mode == "full" then self.refresh_count = 0 -- reset counter on explicit full refresh end @@ -763,6 +824,9 @@ function UIManager:_refresh(mode, region) -- if no region is specified, define default region region = region or Geom:new{w=Screen:getWidth(), h=Screen:getHeight()} + -- if no dithering hint was specified, don't request dithering + dither = dither or false + -- NOTE: While, ideally, we shouldn't merge refreshes w/ different waveform modes, -- this allows us to optimize away a number of quirks of our rendering stack -- (f.g., multiple setDirty calls queued when showing/closing a widget because of update mechanisms), @@ -775,16 +839,18 @@ function UIManager:_refresh(mode, region) local combined = region:combine(self._refresh_stack[i].region) -- update the mode, if needed mode = update_mode(mode, self._refresh_stack[i].mode) + -- dithering hints are viral, one is enough to infect the whole queue + dither = update_dither(dither, self._refresh_stack[i].dither) -- remove colliding refresh table.remove(self._refresh_stack, i) -- and try again with combined data - return self:_refresh(mode, combined) + return self:_refresh(mode, combined, dither) end end -- if we've stopped hitting collisions, enqueue the refresh - logger.dbg("_refresh: Enqueued", mode, "update for region", region.x, region.y, region.w, region.h) - table.insert(self._refresh_stack, {mode = mode, region = region}) + logger.dbg("_refresh: Enqueued", mode, "update for region", region.x, region.y, region.w, region.h, dither and "w/ HW dithering" or "") + table.insert(self._refresh_stack, {mode = mode, region = region, dither = dither}) end --- Repaints dirty widgets. @@ -792,6 +858,8 @@ function UIManager:_repaint() -- flag in which we will record if we did any repaints at all -- will trigger a refresh if set. local dirty = false + -- remember if any of our repaints were dithered + local dithered = false -- We don't need to call paintTo() on widgets that are under -- a widget that covers the full screen @@ -820,13 +888,21 @@ function UIManager:_repaint() -- trigger repaint dirty = true + + -- if any of 'em were dithered, we'll want to dither the final refresh + if widget.widget.dithered then + logger.dbg("_repaint: it was dithered, infecting the refresh queue") + dithered = true + end end end -- execute pending refresh functions for _, refreshfunc in ipairs(self._refresh_func_stack) do - local refreshtype, region = refreshfunc() - if refreshtype then self:_refresh(refreshtype, region) end + local refreshtype, region, dither = refreshfunc() + -- honor dithering hints from *anywhere* in the dirty stack + dither = update_dither(dither, dithered) + if refreshtype then self:_refresh(refreshtype, region, dither) end end self._refresh_func_stack = {} @@ -845,7 +921,8 @@ function UIManager:_repaint() -- but checkBounds & getPhysicalRect will sanitize that in mxc_update @ ffi/framebuffer_mxcfb ;). Screen[refresh_methods[refresh.mode]](Screen, refresh.region.x - 1, refresh.region.y - 1, - refresh.region.w + 2, refresh.region.h + 2) + refresh.region.w + 2, refresh.region.h + 2, + refresh.dither) end self._refresh_stack = {} self.refresh_counted = false @@ -855,6 +932,16 @@ function UIManager:forceRePaint() self:_repaint() end +-- Used to repaint a specific sub-widget that isn't on the _window_stack itself +-- Useful to avoid repainting a complex widget when we just want to invert an icon, for instance. +-- No safety checks on x & y *by design*. I want this to blow up if used wrong. +function UIManager:widgetRepaint(widget, x, y) + if not widget then return end + + logger.dbg("Explicit widgetRepaint:", widget.name or widget.id or tostring(widget), "@ (", x, ",", y, ")") + widget:paintTo(Screen.bb, x, y) +end + function UIManager:setInputTimeout(timeout) self.INPUT_TIMEOUT = timeout or 200*1000 end diff --git a/frontend/ui/widget/bookstatuswidget.lua b/frontend/ui/widget/bookstatuswidget.lua index 162fe9b67..624f429dc 100644 --- a/frontend/ui/widget/bookstatuswidget.lua +++ b/frontend/ui/widget/bookstatuswidget.lua @@ -111,6 +111,8 @@ function BookStatusWidget:init() padding = 0, self:getStatusContent(screen_size.w), } + + self.dithered = true end function BookStatusWidget:getStats() @@ -254,7 +256,9 @@ function BookStatusWidget:setStar(num) table.insert(self.stars_container, stars_group) - UIManager:setDirty(nil, "ui") + -- Individual stars are Button, w/ flash_ui, they'll have their own flash. + -- And we need to redraw the full widget, because we don't know the coordinates of stars_container :/. + UIManager:setDirty(self, "ui", nil, true) return true end @@ -540,7 +544,7 @@ function BookStatusWidget:onConfigChoose(values, name, event, args, events, posi if values then self:onChangeBookStatus(args, position) end - UIManager:setDirty("all", "ui") + UIManager:setDirty(nil, "ui", nil, true) end) end @@ -558,7 +562,7 @@ function BookStatusWidget:onSwipe(arg, ges_ev) do end -- luacheck: ignore 541 else -- diagonal swipe -- trigger full refresh - UIManager:setDirty(nil, "full") + UIManager:setDirty(nil, "full", nil, true) -- a long diagonal swipe may also be used for taking a screenshot, -- so let it propagate return false @@ -568,8 +572,7 @@ end function BookStatusWidget:onClose() self:saveSummary() -- NOTE: Flash on close to avoid ghosting, since we show an image. - UIManager:setDirty("all", "flashpartial") - UIManager:close(self) + UIManager:close(self, "flashpartial") return true end diff --git a/frontend/ui/widget/button.lua b/frontend/ui/widget/button.lua index d53f2014d..f0211d6a2 100644 --- a/frontend/ui/widget/button.lua +++ b/frontend/ui/widget/button.lua @@ -193,16 +193,18 @@ function Button:onTapSelectButton() if G_reader_settings:isFalse("flash_ui") then self.callback() else - -- NOTE: Flag all widgets as dirty to force a repaint, so we actually get to see the highlight. - -- (For some reason (wrong widget passed to setDirty?), we never saw the effects on the FM chevrons without this hack). self[1].invert = true - UIManager:setDirty("all", function() + -- For most of our buttons, we can't avoid that initial repaint... + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self[1].dimen end) + -- And we also often have to delay the callback to both see the flash and/or avoid tearing artefacts w/ fast refreshes... UIManager:tickAfterNext(function() self.callback() self[1].invert = false - UIManager:setDirty("all", function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self[1].dimen end) end) diff --git a/frontend/ui/widget/checkbutton.lua b/frontend/ui/widget/checkbutton.lua index 68073739f..207841f26 100644 --- a/frontend/ui/widget/checkbutton.lua +++ b/frontend/ui/widget/checkbutton.lua @@ -96,14 +96,16 @@ function CheckButton:onTapCheckButton() if G_reader_settings:isFalse("flash_ui") then self.callback() else - self.invert = true - UIManager:setDirty(self.show_parent, function() + self[1].invert = true + UIManager:widgetRepaint(self[1], self.dimen.x, self.dimen.y) + UIManager:setDirty(nil, function() return "fast", self.dimen end) UIManager:tickAfterNext(function() self.callback() - self.invert = false - UIManager:setDirty(self.show_parent, function() + self[1].invert = false + UIManager:widgetRepaint(self[1], self.dimen.x, self.dimen.y) + UIManager:setDirty(nil, function() return "fast", self.dimen end) end) diff --git a/frontend/ui/widget/configdialog.lua b/frontend/ui/widget/configdialog.lua index 0a469373a..2320d1057 100644 --- a/frontend/ui/widget/configdialog.lua +++ b/frontend/ui/widget/configdialog.lua @@ -711,6 +711,7 @@ Widget that displays config menubar and config panel local ConfigDialog = FocusManager:new{ --is_borderless = false, panel_index = 1, + is_fresh = true, } function ConfigDialog:init() @@ -783,7 +784,7 @@ end function ConfigDialog:onCloseWidget() -- NOTE: As much as we would like to flash here, don't, because of adverse interactions with touchmenu that might lead to a double flash... - UIManager:setDirty("all", function() + UIManager:setDirty(nil, function() return "partial", self.dialog_frame.dimen end) end @@ -794,10 +795,11 @@ function ConfigDialog:onShowConfigPanel(index) self:update() -- NOTE: Keep that one as UI to avoid delay when both this and the topmenu are shown. -- Plus, this is also called for each tab anyway, so that wouldn't have been great. - UIManager:setDirty("all", function() + UIManager:setDirty(self.is_fresh and self or "all", function() local refresh_dimen = old_dimen and old_dimen:combine(self.dialog_frame.dimen) or self.dialog_frame.dimen + self.is_fresh = false return "ui", refresh_dimen end) return true diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index de41f51f7..5b09a1950 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -551,7 +551,7 @@ function DictQuickLookup:update() dimen = self.region, self.movable, } - UIManager:setDirty("all", function() + UIManager:setDirty(self, function() local update_region = self.dict_frame and self.dict_frame.dimen and self.dict_frame.dimen:combine(orig_dimen) or orig_dimen logger.dbg("update dict region", update_region) return "partial", update_region diff --git a/frontend/ui/widget/frontlightwidget.lua b/frontend/ui/widget/frontlightwidget.lua index 2a2722dea..dd7ae6e8f 100644 --- a/frontend/ui/widget/frontlightwidget.lua +++ b/frontend/ui/widget/frontlightwidget.lua @@ -276,7 +276,7 @@ function FrontLightWidget:setProgress(num, step, num_warmth) -- Reset container height to what it actually contains self.fl_container.dimen.h = vertical_group:getSize().h - UIManager:setDirty("all", "ui") + UIManager:setDirty(self, "ui") return true end @@ -596,7 +596,7 @@ function FrontLightWidget:naturalLightConfigOpen() self.nl_configure_open = true -- Move to the bottom to make place for the new widget self[1].align="bottom" - UIManager:setDirty("all", "ui") + UIManager:setDirty(self, "ui") end function FrontLightWidget:naturalLightConfigClose() @@ -606,7 +606,7 @@ function FrontLightWidget:naturalLightConfigClose() self.configure_button:enable() self.nl_configure_open = false self[1].align="center" - UIManager:setDirty("all", "ui") + UIManager:setDirty(self, "ui") end return FrontLightWidget diff --git a/frontend/ui/widget/iconbutton.lua b/frontend/ui/widget/iconbutton.lua index 8b3f32f72..17bf8c742 100644 --- a/frontend/ui/widget/iconbutton.lua +++ b/frontend/ui/widget/iconbutton.lua @@ -96,14 +96,17 @@ function IconButton:onTapIconButton() self.callback() else self.image.invert = true - UIManager:setDirty(self.show_parent, function() + -- For ConfigDialog icons, we can't avoid that initial repaint... + UIManager:widgetRepaint(self.image, self.dimen.x + self.padding_left, self.dimen.y + self.padding_top) + UIManager:setDirty(nil, function() return "fast", self.dimen end) - -- Make sure button reacts before doing callback + -- And, we usually need to delay the callback for the same reasons as Button... UIManager:tickAfterNext(function() self.callback() self.image.invert = false - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self.image, self.dimen.x + self.padding_left, self.dimen.y + self.padding_top) + UIManager:setDirty(nil, function() return "fast", self.dimen end) end) diff --git a/frontend/ui/widget/imageviewer.lua b/frontend/ui/widget/imageviewer.lua index 7e0405112..ddbb23bd0 100644 --- a/frontend/ui/widget/imageviewer.lua +++ b/frontend/ui/widget/imageviewer.lua @@ -392,16 +392,22 @@ function ImageViewer:update() self.main_frame, } } - UIManager:setDirty("all", function() + -- NOTE: We use UI instead of partial, because we do NOT want to end up using a REAGL waveform... + -- NOTE: Disabling dithering here makes for a perfect test-case of how well it works: + -- page turns will show color quantization artefacts (i.e., banding) like crazy, + -- while a long touch will trigger a dithered, flashing full-refresh that'll make everything shiny :). + self.dithered = true + UIManager:setDirty(self, function() local update_region = self.main_frame.dimen:combine(orig_dimen) logger.dbg("update image region", update_region) - return "partial", update_region + return "ui", update_region, true end) end function ImageViewer:onShow() + self.dithered = true UIManager:setDirty(self, function() - return "full", self.main_frame.dimen + return "full", self.main_frame.dimen, true end) return true end @@ -508,7 +514,8 @@ function ImageViewer:onHoldRelease(_, ges) self._pan_relative_y = ges.pos.y - self._pan_relative_y if math.abs(self._pan_relative_x) < self.pan_threshold and math.abs(self._pan_relative_y) < self.pan_threshold then -- Hold with no move (or less than pan_threshold): use this to trigger full refresh - UIManager:setDirty(nil, "full") + self.dithered = true + UIManager:setDirty(nil, "full", nil, true) else self:panBy(-self._pan_relative_x, -self._pan_relative_y) end @@ -601,6 +608,7 @@ function ImageViewer:onCloseWidget() if self._images_list and self._images_list_disposable and self._images_list.free then self._images_list.free() end + -- NOTE: Assume there's no image beneath us, so, no dithering request UIManager:setDirty(nil, function() return "flashui", self.main_frame.dimen end) diff --git a/frontend/ui/widget/imagewidget.lua b/frontend/ui/widget/imagewidget.lua index fda61e1a8..b29b1b792 100644 --- a/frontend/ui/widget/imagewidget.lua +++ b/frontend/ui/widget/imagewidget.lua @@ -334,8 +334,9 @@ function ImageWidget:panBy(x, y) if new_offset_x ~= self._offset_x or new_offset_y ~= self._offset_y then self._offset_x = new_offset_x self._offset_y = new_offset_y + self.dithered = true UIManager:setDirty("all", function() - return "partial", self.dimen + return "ui", self.dimen, true end) end -- return new center ratio, so caller can use them later to create a new diff --git a/frontend/ui/widget/keyvaluepage.lua b/frontend/ui/widget/keyvaluepage.lua index ccf3841c5..a4f4f84e1 100644 --- a/frontend/ui/widget/keyvaluepage.lua +++ b/frontend/ui/widget/keyvaluepage.lua @@ -234,13 +234,15 @@ function KeyValueItem:onTap() self.callback() else self[1].invert = true - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self[1].dimen end) UIManager:tickAfterNext(function() self.callback() self[1].invert = false - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "ui", self[1].dimen end) end) @@ -553,7 +555,7 @@ function KeyValuePage:onReturn() if self.callback_return then self:callback_return() UIManager:close(self) - UIManager:setDirty("all", "ui") + UIManager:setDirty(nil, "ui") end end diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index 512df105d..2d154de26 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -403,19 +403,21 @@ function MenuItem:onTapSelect(arg, ges) coroutine.resume(co) else self[1].invert = true - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self[1].dimen end) UIManager:tickAfterNext(function() - self[1].invert = false - UIManager:setDirty(self.show_parent, function() - return "ui", self[1].dimen - end) logger.dbg("creating coroutine for menu select") local co = coroutine.create(function() self.menu:onMenuSelect(self.table, pos) end) coroutine.resume(co) + self[1].invert = false + --UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(self.show_parent, function() + return "ui", self[1].dimen + end) end) end return true @@ -427,15 +429,17 @@ function MenuItem:onHoldSelect(arg, ges) self.menu:onMenuHold(self.table, pos) else self[1].invert = true - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self[1].dimen end) UIManager:tickAfterNext(function() + self.menu:onMenuHold(self.table, pos) self[1].invert = false + --UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) UIManager:setDirty(self.show_parent, function() return "ui", self[1].dimen end) - self.menu:onMenuHold(self.table, pos) end) end return true @@ -587,25 +591,25 @@ function Menu:init() icon = "resources/icons/appbar.chevron.left.png", callback = function() self:onPrevPage() end, bordersize = 0, - show_parent = self, + show_parent = self.show_parent, } self.page_info_right_chev = Button:new{ icon = "resources/icons/appbar.chevron.right.png", callback = function() self:onNextPage() end, bordersize = 0, - show_parent = self, + show_parent = self.show_parent, } self.page_info_first_chev = Button:new{ icon = "resources/icons/appbar.chevron.first.png", callback = function() self:onFirstPage() end, bordersize = 0, - show_parent = self, + show_parent = self.show_parent, } self.page_info_last_chev = Button:new{ icon = "resources/icons/appbar.chevron.last.png", callback = function() self:onLastPage() end, bordersize = 0, - show_parent = self, + show_parent = self.show_parent, } self.page_info_spacer = HorizontalSpan:new{ width = Screen:scaleBySize(32), @@ -699,7 +703,7 @@ function Menu:init() if self.onReturn then self:onReturn() end end, bordersize = 0, - show_parent = self, + show_parent = self.show_parent, readonly = self.return_arrow_propagation, } self.page_return_arrow:hide() @@ -953,7 +957,7 @@ function Menu:updateItems(select_number) self.path_text.text = self:truncatePath(self.path) end - UIManager:setDirty("all", function() + UIManager:setDirty(self.show_parent, function() local refresh_dimen = old_dimen and old_dimen:combine(self.dimen) or self.dimen diff --git a/frontend/ui/widget/multiinputdialog.lua b/frontend/ui/widget/multiinputdialog.lua index e3ce73782..37fdfa487 100644 --- a/frontend/ui/widget/multiinputdialog.lua +++ b/frontend/ui/widget/multiinputdialog.lua @@ -122,7 +122,7 @@ function MultiInputDialog:init() }, self.dialog_frame, } - UIManager:setDirty("all", "full") + UIManager:setDirty(self, "ui") end function MultiInputDialog:getFields() diff --git a/frontend/ui/widget/naturallightwidget.lua b/frontend/ui/widget/naturallightwidget.lua index 466e8d316..92b20a270 100644 --- a/frontend/ui/widget/naturallightwidget.lua +++ b/frontend/ui/widget/naturallightwidget.lua @@ -353,7 +353,7 @@ function NaturalLightWidget:createMainContent(width, height) table.insert(self.fl_container, vertical_group) -- Reset container height to what it actually contains self.fl_container.dimen.h = vertical_group:getSize().h - UIManager:setDirty("all", "ui") + UIManager:setDirty(self, "ui") return self.fl_container end diff --git a/frontend/ui/widget/radiobutton.lua b/frontend/ui/widget/radiobutton.lua index a938a3072..1d4e12fed 100644 --- a/frontend/ui/widget/radiobutton.lua +++ b/frontend/ui/widget/radiobutton.lua @@ -116,14 +116,17 @@ function RadioButton:onTapCheckButton() if G_reader_settings:isFalse("flash_ui") then self.callback() else - self.invert = true - UIManager:setDirty(self.show_parent, function() + -- While I'd like to only flash the button itself, we have to make do with flashing the full width of the TextWidget... + self.frame.invert = true + UIManager:widgetRepaint(self.frame, self.dimen.x, self.dimen.y) + UIManager:setDirty(nil, function() return "fast", self.dimen end) UIManager:tickAfterNext(function() self.callback() - self.invert = false - UIManager:setDirty(self.show_parent, function() + self.frame.invert = false + UIManager:widgetRepaint(self.frame, self.dimen.x, self.dimen.y) + UIManager:setDirty(nil, function() return "fast", self.dimen end) end) diff --git a/frontend/ui/widget/screensaverwidget.lua b/frontend/ui/widget/screensaverwidget.lua index f9b599625..fa2c096db 100644 --- a/frontend/ui/widget/screensaverwidget.lua +++ b/frontend/ui/widget/screensaverwidget.lua @@ -49,8 +49,9 @@ function ScreenSaverWidget:update() height = self.height, self.widget, } + self.dithered = true self[1] = self.main_frame - UIManager:setDirty("all", function() + UIManager:setDirty(self, function() local update_region = self.main_frame.dimen return "partial", update_region end) @@ -66,14 +67,12 @@ end function ScreenSaverWidget:onTap(_, ges) if ges.pos:intersectWith(self.main_frame.dimen) then self:onClose() - UIManager:setDirty("all", "full") end return true end function ScreenSaverWidget:onClose() - UIManager:close(self) - UIManager:setDirty("all", "full") + UIManager:close(self, "full") return true end diff --git a/frontend/ui/widget/textviewer.lua b/frontend/ui/widget/textviewer.lua index 8db7ffe27..ab5462810 100644 --- a/frontend/ui/widget/textviewer.lua +++ b/frontend/ui/widget/textviewer.lua @@ -200,7 +200,7 @@ function TextViewer:init() dimen = self.region, self.movable, } - UIManager:setDirty("all", function() + UIManager:setDirty(self, function() local update_region = self.frame.dimen:combine(orig_dimen) logger.dbg("update region", update_region) return "partial", update_region diff --git a/frontend/ui/widget/touchmenu.lua b/frontend/ui/widget/touchmenu.lua index 868fc8aaf..45ebd6592 100644 --- a/frontend/ui/widget/touchmenu.lua +++ b/frontend/ui/widget/touchmenu.lua @@ -141,7 +141,8 @@ function TouchMenuItem:onTapSelect(arg, ges) self.menu:onMenuSelect(self.item) else self.item_frame.invert = true - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self.dimen end) -- yield to main UI loop to invert item @@ -153,6 +154,7 @@ function TouchMenuItem:onTapSelect(arg, ges) -- Since it's an *un*highlight containing text, we make it "ui" and not "fast", both so it won't mangle text, -- and because "fast" can have some weird side-effects on some devices in this specific instance... if self.item.hold_keep_menu_open or self.item.keep_menu_open then + --UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) UIManager:setDirty(self.show_parent, function() return "ui", self.dimen end) @@ -173,7 +175,8 @@ function TouchMenuItem:onHoldSelect(arg, ges) self.menu:onMenuHold(self.item) else self.item_frame.invert = true - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self.dimen end) UIManager:tickAfterNext(function() @@ -181,6 +184,8 @@ function TouchMenuItem:onHoldSelect(arg, ges) end) UIManager:scheduleIn(0.5, function() self.item_frame.invert = false + -- NOTE: For some reason, this is finicky (I end up with a solid black bar, i.e., text gets inverted, but not the bg?!) + --UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) UIManager:setDirty(self.show_parent, function() return "ui", self.dimen end) @@ -431,13 +436,13 @@ function TouchMenu:init() icon = "resources/icons/appbar.chevron.left.png", callback = function() self:onPrevPage() end, bordersize = 0, - show_parent = self, + show_parent = self.show_parent, } self.page_info_right_chev = Button:new{ icon = "resources/icons/appbar.chevron.right.png", callback = function() self:onNextPage() end, bordersize = 0, - show_parent = self, + show_parent = self.show_parent, } self.page_info_left_chev:hide() self.page_info_right_chev:hide() @@ -518,8 +523,8 @@ function TouchMenu:init() end function TouchMenu:onCloseWidget() - -- NOTE: We pass a nil region to ensure a full-screen flash to avoid ghosting - UIManager:setDirty(nil, "flashui", nil) + -- NOTE: We don't pass a region in order to ensure a full-screen flash to avoid ghosting + UIManager:setDirty(nil, "flashui") end function TouchMenu:_recalculatePageLayout() @@ -605,7 +610,8 @@ function TouchMenu:updateItems() -- NOTE: We use a slightly ugly hack to detect a brand new menu vs. a tab switch, -- in order to optionally flash on initial menu popup... - UIManager:setDirty("all", function() + -- NOTE: Also avoid repainting what's underneath us on initial popup. + UIManager:setDirty(self.is_fresh and self.show_parent or "all", function() local refresh_dimen = old_dimen and old_dimen:combine(self.dimen) or self.dimen diff --git a/frontend/ui/widget/virtualkeyboard.lua b/frontend/ui/widget/virtualkeyboard.lua index 961064f92..86521b8f0 100644 --- a/frontend/ui/widget/virtualkeyboard.lua +++ b/frontend/ui/widget/virtualkeyboard.lua @@ -133,7 +133,9 @@ function VirtualKey:update_keyboard(want_flash, want_fast) if want_fast then refresh_type = "fast" end - UIManager:setDirty(self.keyboard, function() + -- Only repaint the key itself, not the full board... + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() logger.dbg("update key region", self[1].dimen) return refresh_type, self[1].dimen end) diff --git a/plugins/coverbrowser.koplugin/bookinfomanager.lua b/plugins/coverbrowser.koplugin/bookinfomanager.lua index 1507c3e32..d4171eb09 100644 --- a/plugins/coverbrowser.koplugin/bookinfomanager.lua +++ b/plugins/coverbrowser.koplugin/bookinfomanager.lua @@ -146,7 +146,7 @@ function BookInfoManager:createDB() -- Check version (not updated by previous exec if already there) local res = db_conn:exec("SELECT value FROM config where key='version';") if res[1][1] ~= BOOKINFO_DB_VERSION then - logger.warn("BookInfo cache DB schema updated from version ", res[1][1], "to version", BOOKINFO_DB_VERSION) + logger.warn("BookInfo cache DB schema updated from version", res[1][1], "to version", BOOKINFO_DB_VERSION) logger.warn("Deleting existing", self.db_location, "to recreate it") db_conn:close() os.remove(self.db_location) @@ -451,7 +451,7 @@ function BookInfoManager:extractBookInfo(filepath, cover_specs) -- release memory used by uncompressed data: cover_data = nil -- luacheck: no unused dbrow.cover_dataz = SQ3.blob(cover_dataz) -- cast to blob for sqlite - logger.dbg("cover for", filename, "scaled by", scale_factor, "=>", cbb_w, "x", cbb_h, "(compressed from ", dbrow.cover_datalen, " to ", cover_dataz:len()) + logger.dbg("cover for", filename, "scaled by", scale_factor, "=>", cbb_w, "x", cbb_h, ", compressed from", dbrow.cover_datalen, "to", cover_dataz:len()) end end end @@ -554,7 +554,7 @@ function BookInfoManager:collectSubprocesses() -- have caused a terminateBackgroundJobs() - if we're here, it's -- that user has left reader in FileBrower and went away) if util.gettime() > self.subprocesses_last_added_ts + self.subprocesses_killall_timeout_seconds then - logger.warn("Some subprocess were running for too long, killing them") + logger.warn("Some subprocesses were running for too long, killing them") self:terminateBackgroundJobs() -- we'll collect them next time we're run end diff --git a/plugins/coverbrowser.koplugin/covermenu.lua b/plugins/coverbrowser.koplugin/covermenu.lua index 2022fb4e0..d65b70bba 100644 --- a/plugins/coverbrowser.koplugin/covermenu.lua +++ b/plugins/coverbrowser.koplugin/covermenu.lua @@ -77,6 +77,7 @@ function CoverMenu:updateItems(select_number) collectgarbage() -- Specific UI building implementation (defined in some other module) + self._has_cover_images = false self:_updateItemsBuildUI() -- Set the local variables with the things we know @@ -89,11 +90,12 @@ function CoverMenu:updateItems(select_number) if self.show_path then self.path_text.text = self:truncatePath(self.path) end - UIManager:setDirty("all", function() + self.show_parent.dithered = self._has_cover_images + UIManager:setDirty(self.show_parent, function() local refresh_dimen = old_dimen and old_dimen:combine(self.dimen) or self.dimen - return "partial", refresh_dimen + return "partial", refresh_dimen, self.show_parent.dithered end) -- As additionally done in FileChooser:updateItems() @@ -137,13 +139,14 @@ function CoverMenu:updateItems(select_number) item:update() if item.bookinfo_found then logger.dbg(" found", item.text) + self.show_parent.dithered = item._has_cover_image local refreshfunc = function() if item.refresh_dimen then -- MosaicMenuItem may exceed its own dimen in its paintTo -- with its "description" hint - return "ui", item.refresh_dimen + return "ui", item.refresh_dimen, self.show_parent.dithered else - return "ui", item[1].dimen + return "ui", item[1].dimen, self.show_parent.dithered end end UIManager:setDirty(self.show_parent, refreshfunc) diff --git a/plugins/coverbrowser.koplugin/listmenu.lua b/plugins/coverbrowser.koplugin/listmenu.lua index 5c981e146..62a73509e 100644 --- a/plugins/coverbrowser.koplugin/listmenu.lua +++ b/plugins/coverbrowser.koplugin/listmenu.lua @@ -288,6 +288,9 @@ function ListMenuItem:update() wimage, } } + -- Let menu know it has some item with images + self.menu._has_cover_images = true + self._has_cover_image = true else -- empty element the size of an image wleft = CenterContainer:new{ diff --git a/plugins/coverbrowser.koplugin/mosaicmenu.lua b/plugins/coverbrowser.koplugin/mosaicmenu.lua index f18aa97b2..af48b5592 100644 --- a/plugins/coverbrowser.koplugin/mosaicmenu.lua +++ b/plugins/coverbrowser.koplugin/mosaicmenu.lua @@ -498,6 +498,9 @@ function MosaicMenuItem:update() image, } } + -- Let menu know it has some item with images + self.menu._has_cover_images = true + self._has_cover_image = true else -- add Series metadata if requested if bookinfo.series then diff --git a/plugins/goodreads.koplugin/doublekeyvaluepage.lua b/plugins/goodreads.koplugin/doublekeyvaluepage.lua index f36bfed7c..acd148ad4 100644 --- a/plugins/goodreads.koplugin/doublekeyvaluepage.lua +++ b/plugins/goodreads.koplugin/doublekeyvaluepage.lua @@ -173,14 +173,16 @@ function DoubleKeyValueItem:onTap() UIManager:close(info) else self[1].invert = true - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "fast", self[1].dimen end) UIManager:tickAfterNext(function() self.callback() UIManager:close(info) self[1].invert = false - UIManager:setDirty(self.show_parent, function() + UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y) + UIManager:setDirty(nil, function() return "ui", self[1].dimen end) end) diff --git a/plugins/goodreads.koplugin/goodreadsbook.lua b/plugins/goodreads.koplugin/goodreadsbook.lua index 73a624f1c..f359df4a9 100644 --- a/plugins/goodreads.koplugin/goodreadsbook.lua +++ b/plugins/goodreads.koplugin/goodreadsbook.lua @@ -260,8 +260,7 @@ function GoodreadsBook:onAnyKeyPressed() end function GoodreadsBook:onClose() - UIManager:setDirty("all") - UIManager:close(self) + UIManager:close(self, "flashui") return true end diff --git a/plugins/kobolight.koplugin/main.lua b/plugins/kobolight.koplugin/main.lua index 641e3b72f..ddb579592 100644 --- a/plugins/kobolight.koplugin/main.lua +++ b/plugins/kobolight.koplugin/main.lua @@ -235,8 +235,7 @@ function KoboLight:addToMainMenu(menu_items) (self:disabled() and _("Do you want to enable the frontlight gesture controller?") or _("Do you want to disable the frontlight gesture controller?")), ok_text = self:disabled() and _("Enable") or _("Disable"), ok_callback = function() - UIManager:close(image) - UIManager:setDirty("all", "full") + UIManager:close(image, "full") UIManager:show(InfoMessage:new{ text = T(_("You have %1 the frontlight gesture controller. It will take effect on next restart."), self:disabled() and _("enabled") or _("disabled")) @@ -245,8 +244,7 @@ function KoboLight:addToMainMenu(menu_items) end, cancel_text = _("Close"), cancel_callback = function() - UIManager:close(image) - UIManager:setDirty("all", "full") + UIManager:close(image, "full") end, }) UIManager:setDirty("all", "full")