From 6c9e222d332f039972d4e7aabc2b11d9247a6f7b Mon Sep 17 00:00:00 2001 From: zwim <36999612+zwim@users.noreply.github.com> Date: Sun, 2 Jan 2022 23:13:19 +0100 Subject: [PATCH] Screensaver: allow limiting stretch of covers and images (#8570) ImageWidget: adds stretch_limit_percentage parameter. Add support for screensaver on the emulator, for easier testing. --- frontend/device/sdl/device.lua | 19 ++++----- frontend/ui/elements/screensaver_menu.lua | 20 ++++++--- frontend/ui/screensaver.lua | 31 ++++++++++++++ frontend/ui/widget/imagewidget.lua | 28 ++++++++++--- frontend/ui/widget/spinwidget.lua | 51 ++++++++++++++++------- 5 files changed, 109 insertions(+), 40 deletions(-) diff --git a/frontend/device/sdl/device.lua b/frontend/device/sdl/device.lua index e98dcef0f..4f387135d 100644 --- a/frontend/device/sdl/device.lua +++ b/frontend/device/sdl/device.lua @@ -318,22 +318,17 @@ function Device:setDateTime(year, month, day, hour, min, sec) end end +function Emulator:supportsScreensaver() return true end + function Emulator:simulateSuspend() - local InfoMessage = require("ui/widget/infomessage") - local UIManager = require("ui/uimanager") - local _ = require("gettext") - UIManager:show(InfoMessage:new{ - text = _("Suspend") - }) + local Screensaver = require("ui/screensaver") + Screensaver:setup() + Screensaver:show() end function Emulator:simulateResume() - local InfoMessage = require("ui/widget/infomessage") - local UIManager = require("ui/uimanager") - local _ = require("gettext") - UIManager:show(InfoMessage:new{ - text = _("Resume") - }) + local Screensaver = require("ui/screensaver") + Screensaver:close() end -- fake network manager for the emulator diff --git a/frontend/ui/elements/screensaver_menu.lua b/frontend/ui/elements/screensaver_menu.lua index e08ef4dbf..2ff2a50ec 100644 --- a/frontend/ui/elements/screensaver_menu.lua +++ b/frontend/ui/elements/screensaver_menu.lua @@ -126,7 +126,7 @@ return { text = _("Covers and images settings"), sub_item_table = { { - text = _("Black background behind covers and images"), + text = _("Black background"), checked_func = function() return G_reader_settings:readSetting("screensaver_img_background") == "black" end, @@ -135,7 +135,7 @@ return { end, }, { - text = _("White background behind covers and images"), + text = _("White background"), checked_func = function() return G_reader_settings:readSetting("screensaver_img_background") == "white" end, @@ -144,7 +144,7 @@ return { end, }, { - text = _("Leave background as-is behind covers and images"), + text = _("Leave background as-is"), checked_func = function() return G_reader_settings:readSetting("screensaver_img_background") == "none" end, @@ -153,12 +153,20 @@ return { end, }, { - text = _("Stretch covers and images to fit screen"), + text_func = function() + if G_reader_settings:nilOrFalse("screensaver_stretch_images") then + return _("Stretch to fit screen") + elseif G_reader_settings:readSetting("screensaver_stretch_limit_percentage") then + return _("Stretch to fit screen (with limit)") + else + return _("Stretch to fit screen") + end + end, checked_func = function() return G_reader_settings:isTrue("screensaver_stretch_images") end, - callback = function() - G_reader_settings:toggle("screensaver_stretch_images") + callback = function(touchmenu_instance) + Screensaver:setStretchLimit(touchmenu_instance) end, separator = true, }, diff --git a/frontend/ui/screensaver.lua b/frontend/ui/screensaver.lua index 31e3c56ec..cc133f22b 100644 --- a/frontend/ui/screensaver.lua +++ b/frontend/ui/screensaver.lua @@ -14,6 +14,7 @@ local ImageWidget = require("ui/widget/imagewidget") local Math = require("optmath") local OverlapGroup = require("ui/widget/overlapgroup") local ScreenSaverWidget = require("ui/widget/screensaverwidget") +local SpinWidget = require("ui/widget/spinwidget") local TextBoxWidget = require("ui/widget/textboxwidget") local TopContainer = require("ui/widget/container/topcontainer") local UIManager = require("ui/uimanager") @@ -383,6 +384,34 @@ function Screensaver:setMessage() self.input_dialog:onShowKeyboard() end +function Screensaver:setStretchLimit(touchmenu_instance) + UIManager:show(SpinWidget:new{ + value = G_reader_settings:readSetting("screensaver_stretch_limit_percentage", 8), + value_min = 0, + value_max = 25, + default_value = 8, -- percent + title_text = _("Set maximum stretch limit"), + ok_text = _("Set"), + ok_always_enabled = true, + callback = function(spin) + G_reader_settings:saveSetting("screensaver_stretch_limit_percentage", spin.value) + G_reader_settings:makeTrue("screensaver_stretch_images") + if touchmenu_instance then touchmenu_instance:updateItems() end + end, + extra_text = _("Disable stretch"), + extra_callback = function() + G_reader_settings:makeFalse("screensaver_stretch_images") + if touchmenu_instance then touchmenu_instance:updateItems() end + end, + option_text = _("Full stretch"), + option_callback = function() + G_reader_settings:makeTrue("screensaver_stretch_images") + G_reader_settings:delSetting("screensaver_stretch_limit_percentage") + if touchmenu_instance then touchmenu_instance:updateItems() end + end, + }) +end + -- When called after setup(), may not match the saved settings, because it accounts for fallbacks that might have kicked in. function Screensaver:getMode() return self.screensaver_type @@ -543,6 +572,7 @@ function Screensaver:show() width = Screen:getWidth(), height = Screen:getHeight(), scale_factor = G_reader_settings:isFalse("screensaver_stretch_images") and 0 or nil, + stretch_limit_percentage = G_reader_settings:readSetting("screensaver_stretch_limit_percentage"), } elseif self.screensaver_type == "bookstatus" then local ReaderUI = require("apps/reader/readerui") @@ -565,6 +595,7 @@ function Screensaver:show() width = Screen:getWidth(), height = Screen:getHeight(), scale_factor = G_reader_settings:isFalse("screensaver_stretch_images") and 0 or nil, + stretch_limit_percentage = G_reader_settings:readSetting("screensaver_stretch_limit_percentage"), } elseif self.screensaver_type == "readingprogress" then widget = Screensaver.getReaderProgress() diff --git a/frontend/ui/widget/imagewidget.lua b/frontend/ui/widget/imagewidget.lua index 167fd8baf..f9cae9f90 100644 --- a/frontend/ui/widget/imagewidget.lua +++ b/frontend/ui/widget/imagewidget.lua @@ -81,12 +81,18 @@ local ImageWidget = Widget:new{ -- If scale_for_dpi is true image will be rescaled according to screen dpi scale_for_dpi = false, - -- When scale_factor is not nil, native image is scaled by this factor - -- (if scale_factor == 1, native image size is kept) - -- Special case : scale_factor == 0 : image will be scaled to best fit provided - -- width and height, keeping aspect ratio (scale_factor will be updated - -- from 0 to the factor used at _render() time) + -- When scale_factor is not nil, native image is scaled by this factor, + -- (if scale_factor == 1, native image size is kept) + -- Special case: scale_factor == 0 : image will be scaled to best fit provided + -- width and height, keeping aspect ratio (scale_factor will be updated + -- from 0 to the factor used at _render() time) + -- If scale_factor is nil and stretch_limit_percantage is provided: + -- If the aspect ratios of the image and the width/height provided don't differ by more than + -- stretch_limit_percentage, then stretch the image (as scale_factor=nil); + -- otherwise, scale to best fit (as scale_factor=0) + -- In all other cases the image will be stretched to best fit the container. scale_factor = nil, + stretch_limit_percentage = nil, -- Whether to use former blitbuffer:scale() (default to using MuPDF) use_legacy_image_scaling = G_reader_settings:isTrue("legacy_image_scaling"), @@ -281,8 +287,18 @@ function ImageWidget:_render() self.scale_factor = self.scale_factor * DPI_SCALE end - -- scale to best fit container : compute scale_factor for that + if self.stretch_limit_percentage and not self.scale_factor then + -- stretch or scale to fit container, depending on self.stretch_limit_percentage + local screen_ratio = self.width / self.height + local image_ratio = bb_w / bb_h + local ratio_divergence_percent = math.abs(100 - image_ratio / screen_ratio * 100) + if ratio_divergence_percent > self.stretch_limit_percentage then + self.scale_factor = 0 + end + end + if self.scale_factor == 0 then + -- scale to best fit container: compute scale_factor for that if self.width and self.height then self.scale_factor = math.min(self.width / bb_w, self.height / bb_h) logger.dbg("ImageWidget: scale to fit, setting scale_factor to", self.scale_factor) diff --git a/frontend/ui/widget/spinwidget.lua b/frontend/ui/widget/spinwidget.lua index 9aa971893..cb1a779b7 100644 --- a/frontend/ui/widget/spinwidget.lua +++ b/frontend/ui/widget/spinwidget.lua @@ -47,9 +47,12 @@ local SpinWidget = InputContainer:new{ -- Set this to add upper default button that restores number to its default value default_value = nil, default_text = nil, - -- Optional extra button above ok/cancel buttons row + -- Optional extra button extra_text = nil, extra_callback = nil, + -- Optional extra button above ok/cancel buttons row + option_text = nil, + option_callback = nil, } function SpinWidget:init() @@ -138,21 +141,37 @@ function SpinWidget:update(numberpicker_value, numberpicker_value_index) }, }) end - if self.extra_text then - table.insert(buttons, { - { - text = self.extra_text, - callback = function() - if self.extra_callback then - self.value, self.value_index = value_widget:getValue() - self.extra_callback(self) - end - if not self.keep_shown_on_apply then -- assume extra wants it same as ok - self:onClose() - end - end, - }, - }) + + local extra_button = { + text = self.extra_text, + callback = function() + if self.extra_callback then + self.value, self.value_index = value_widget:getValue() + self.extra_callback(self) + end + if not self.keep_shown_on_apply then -- assume extra wants it same as ok + self:onClose() + end + end, + } + local option_button = { + text = self.option_text, + callback = function() + if self.option_callback then + self.value, self.value_index = value_widget:getValue() + self.option_callback(self) + end + if not self.keep_shown_on_apply then -- assume option wants it same as ok + self:onClose() + end + end, + } + if self.extra_text and not self.option_text then + table.insert(buttons, {extra_button}) + elseif self.option_text and not self.extra_text then + table.insert(buttons, {option_button}) + elseif self.extra_text and self.option_text then + table.insert(buttons, {extra_button, option_button}) end table.insert(buttons, { {