Text editor: rotate (#12658)

This commit is contained in:
hius07
2024-10-29 20:49:43 +02:00
committed by GitHub
parent b42b9a8799
commit 97a7ebefb9
9 changed files with 127 additions and 153 deletions

View File

@@ -60,28 +60,21 @@ local function isFile(file)
return lfs.attributes(file, "mode") == "file"
end
function FileManager:onSetRotationMode(rotation)
if rotation ~= nil and rotation ~= Screen:getRotationMode() then
Screen:setRotationMode(rotation)
if FileManager.instance then
self:reinit(self.path, self.focused_file)
end
end
return true
end
function FileManager:onPhysicalKeyboardConnected()
-- So that the key navigation shortcuts apply right away.
-- This will also naturally call registerKeyEvents
self:reinit(self.path, self.focused_file)
end
FileManager.onPhysicalKeyboardDisconnected = FileManager.onPhysicalKeyboardConnected
function FileManager:setRotationMode()
local locked = G_reader_settings:isTrue("lock_rotation")
if not locked then
local rotation_mode = G_reader_settings:readSetting("fm_rotation_mode") or Screen.DEVICE_ROTATED_UPRIGHT
self:onSetRotationMode(rotation_mode)
local mode = G_reader_settings:readSetting("fm_rotation_mode") or Screen.DEVICE_ROTATED_UPRIGHT
self:onSetRotationMode(mode)
end
end
function FileManager:onSetRotationMode(mode)
local old_mode = Screen:getRotationMode()
if mode ~= nil and mode ~= old_mode then
Screen:setRotationMode(mode)
if FileManager.instance then
self:rotate()
end
end
end
@@ -728,6 +721,8 @@ function FileManager:tapPlus()
end
function FileManager:reinit(path, focused_file)
path = path or self.path
focused_file = focused_file or self.focused_file
UIManager:flushSettings()
self.dimen = Screen:getSize()
-- backup the root path and path items
@@ -748,6 +743,13 @@ function FileManager:reinit(path, focused_file)
-- self:onRefresh()
end
FileManager.rotate = FileManager.reinit
-- So that the key navigation shortcuts apply right away.
-- This will also naturally call registerKeyEvents
FileManager.onPhysicalKeyboardConnected = FileManager.reinit
FileManager.onPhysicalKeyboardDisconnected = FileManager.reinit
function FileManager:getCurrentDir()
return FileManager.instance and FileManager.instance.file_chooser.path
end

View File

@@ -2454,11 +2454,11 @@ function ReaderFooter:onSwapPageTurnButtons()
end
ReaderFooter.onToggleReadingOrder = ReaderFooter.onSwapPageTurnButtons
function ReaderFooter:onSetRotationMode()
function ReaderFooter:onSetDimensions()
self:updateFooterContainer()
self:resetLayout(true)
end
ReaderFooter.onScreenResize = ReaderFooter.onSetRotationMode
ReaderFooter.onScreenResize = ReaderFooter.onSetDimensions
function ReaderFooter:onSetPageHorizMargins(h_margins)
if self.settings.progress_margin then

View File

@@ -1,47 +0,0 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("device")
local Event = require("ui/event")
local _ = require("gettext")
local ReaderRotation = InputContainer:extend{
current_rotation = 0,
}
function ReaderRotation:init()
self:registerKeyEvents()
-- NOP our own gesture handling
self.ges_events = nil
end
function ReaderRotation:onGesture() end
function ReaderRotation:registerKeyEvents()
if Device:hasKeyboard() then
self.key_events = {
-- these will all generate the same event, just with different arguments
RotateLeft = {
{ "J" },
event = "Rotate",
args = -90
},
RotateRight = {
{ "K" },
event = "Rotate",
args = 90
},
}
end
end
ReaderRotation.onPhysicalKeyboardConnected = ReaderRotation.registerKeyEvents
--- @todo Reset rotation on new document, maybe on new page?
--- @fixme: More importantly, this breaks rendering, c.f., `Document:renderPage`
-- A modern implementation of this feature is available in Dispatcher via the `IterateRotation` Event.
function ReaderRotation:onRotate(rotate_by)
self.current_rotation = (self.current_rotation + rotate_by) % 360
self.ui:handleEvent(Event:new("RotationUpdate", self.current_rotation))
return true
end
return ReaderRotation

View File

@@ -836,13 +836,15 @@ function ReaderView:restoreViewContext(ctx)
return false
end
function ReaderView:onSetRotationMode(rotation)
if rotation ~= nil then
local old_rotation = Screen:getRotationMode()
if rotation == old_rotation then
return
function ReaderView:onSetRotationMode(mode)
local old_mode = Screen:getRotationMode()
if mode ~= nil and mode ~= old_mode then
Screen:setRotationMode(mode)
self:rotate(mode, old_mode)
end
end
function ReaderView:rotate(mode, old_mode)
-- NOTE: We cannot rely on getScreenMode, as it actually checks the screen dimensions, instead of the rotation mode.
-- (i.e., it returns how the screen *looks* like, not how it's oriented relative to its native layout).
-- This would horribly break if you started in Portrait (both rotation and visually),
@@ -850,26 +852,18 @@ function ReaderView:onSetRotationMode(rotation)
-- If you then attempted to switch to a Landscape *rotation*, it would mistakenly think the layout hadn't changed!
-- So, instead, as we're concerned with *rotation* layouts, just compare the two.
-- We use LinuxFB-style constants, so, Portraits are even, Landscapes are odds, making this trivial.
local matching_orientation = bit.band(rotation, 1) == bit.band(old_rotation, 1)
if rotation ~= old_rotation and matching_orientation then
local matching_orientation = bit.band(mode, 1) == bit.band(old_mode, 1)
if matching_orientation then
-- No layout change, just rotate & repaint with a flash
Screen:setRotationMode(rotation)
UIManager:setDirty(self.dialog, "full")
Notification:notify(T(_("Rotation mode set to: %1"), optionsutil:getOptionText("SetRotationMode", rotation)))
return
end
Screen:setRotationMode(rotation)
end
else
UIManager:setDirty(nil, "full") -- SetDimensions will only request a partial, we want a flash
local new_screen_size = Screen:getSize()
self.ui:handleEvent(Event:new("SetDimensions", new_screen_size))
self.ui:onScreenResize(new_screen_size)
self.ui:handleEvent(Event:new("InitScrollPageStates"))
Notification:notify(T(_("Rotation mode set to: %1"), optionsutil:getOptionText("SetRotationMode", rotation)))
return
end
Notification:notify(T(_("Rotation mode set to: %1"), optionsutil:getOptionText("SetRotationMode", mode)))
end
function ReaderView:onSetDimensions(dimensions)
@@ -975,7 +969,7 @@ function ReaderView:onBBoxUpdate(bbox)
self.use_bbox = bbox and true or false
end
--- @note: From ReaderRotation, which is broken and disabled.
--- @note: From ReaderRotation, which was broken, and has been removed in #12658
function ReaderView:onRotationUpdate(rotation)
self.state.rotation = rotation
self:recalculate()

View File

@@ -322,7 +322,7 @@ function ReaderZooming:onRestoreDimensions(dimensions)
self:setZoom()
end
--- @note: From ReaderRotation, which is broken and disabled.
--- @note: From ReaderRotation, which was broken, and has been removed in #12658
function ReaderZooming:onRotationUpdate(rotation)
self.rotation = rotation
self:setZoom()

View File

@@ -43,7 +43,6 @@ local ReaderLink = require("apps/reader/modules/readerlink")
local ReaderMenu = require("apps/reader/modules/readermenu")
local ReaderPageMap = require("apps/reader/modules/readerpagemap")
local ReaderPanning = require("apps/reader/modules/readerpanning")
--local ReaderRotation = require("apps/reader/modules/readerrotation")
local ReaderPaging = require("apps/reader/modules/readerpaging")
local ReaderRolling = require("apps/reader/modules/readerrolling")
local ReaderSearch = require("apps/reader/modules/readersearch")
@@ -159,15 +158,6 @@ function ReaderUI:init()
view = self.view,
ui = self
})
-- (legacy, and defunct) rotation controller
--- @fixme: Tripping this would break rendering, c.f., `Document:renderPage`
--[[
self:registerModule("rotation", ReaderRotation:new{
dialog = self.dialog,
view = self.view,
ui = self
})
--]]
-- Handmade/custom ToC and hidden flows
self:registerModule("handmade", ReaderHandMade:new{
dialog = self.dialog,

View File

@@ -501,9 +501,9 @@ function Document:renderPage(pageno, rect, zoom, rotation, gamma, hinting)
-- Make the context match the rotation,
-- by pointing at the rotated origin via coordinates offsets.
-- NOTE: We rotate our *Screen* bb on rotation (SetRotationMode), not the document,
-- so we hardly ever exercise this codepath...
-- AFAICT, the only thing that will *ever* (attempt to) rotate the document is ReaderRotation's key bindings (RotationUpdate).
--- @fixme: And whaddayano, it's broken ;). The aptly named key binds in question are J/K, I shit you not.
-- so we hardly ever exercize this codepath...
-- AFAICT, the only thing that *ever* (attempted to) rotate the document was ReaderRotation's key bindings (RotationUpdate).
--- @note: It was broken as all hell (it had likely never worked outside of its original implementation in KPV), and has been removed in #12658
if rotation == 90 then
dc:setOffset(page_size.w, 0)
elseif rotation == 180 then

View File

@@ -237,6 +237,8 @@ function InputDialog:init()
title_multilines = true,
bottom_v_padding = self.bottom_v_padding,
info_text = self.description,
left_icon = self.title_bar_left_icon,
left_icon_tap_callback = self.title_bar_left_icon_tap_callback,
show_parent = self,
}
@@ -475,6 +477,31 @@ function InputDialog:init()
end
end
function InputDialog:reinit()
local visible = self:isKeyboardVisible()
self.input = self:getInputText() -- re-init with up-to-date text
self:onClose() -- will close keyboard and save view position
self._input_widget:onCloseWidget() -- proper cleanup of InputText and its keyboard
if self._added_widgets then
-- prevent these externally added widgets from being freed as :init() will re-add them
for i = 1, #self._added_widgets do
table.remove(self.vgroup, #self.vgroup-2)
end
end
self:free()
-- Restore original text_height (or reset it if none to force recomputing it)
self.text_height = self.orig_text_height or nil
-- Same deal as in toggleKeyboard...
self.keyboard_visible = visible and true or false
self:init()
if self.keyboard_visible then
self:onShowKeyboard()
end
-- Our position on screen has probably changed, so have the full screen refreshed
UIManager:setDirty("all", "flashui")
end
function InputDialog:addWidget(widget, re_init)
table.insert(self.layout, #self.layout, {widget})
if not re_init then -- backup widget for re-init
@@ -677,30 +704,7 @@ function InputDialog:onKeyboardClosed()
end
end
function InputDialog:onKeyboardHeightChanged()
local visible = self:isKeyboardVisible()
self.input = self:getInputText() -- re-init with up-to-date text
self:onClose() -- will close keyboard and save view position
self._input_widget:onCloseWidget() -- proper cleanup of InputText and its keyboard
if self._added_widgets then
-- prevent these externally added widgets from being freed as :init() will re-add them
for i = 1, #self._added_widgets do
table.remove(self.vgroup, #self.vgroup-2)
end
end
self:free()
-- Restore original text_height (or reset it if none to force recomputing it)
self.text_height = self.orig_text_height or nil
-- Same deal as in toggleKeyboard...
self.keyboard_visible = visible
self:init()
if self.keyboard_visible then
self:onShowKeyboard()
end
-- Our position on screen has probably changed, so have the full screen refreshed
UIManager:setDirty("all", "flashui")
end
InputDialog.onKeyboardHeightChanged = InputDialog.reinit
function InputDialog:onCloseDialog()
local close_button = self.button_table:getButtonById("close")
@@ -724,6 +728,15 @@ function InputDialog:onClose()
self:onCloseKeyboard()
end
function InputDialog:onSetRotationMode(mode)
if self.rotation_enabled and mode ~= nil then -- Text editor only
self.rotation_mode_backup = self.rotation_mode_backup or Screen:getRotationMode() -- backup only initial mode
Screen:setRotationMode(mode)
self:reinit()
return true -- we are the upper widget, stop event propagation
end
end
function InputDialog:refreshButtons()
-- Using what ought to be enough:
-- return "ui", self.button_table.dimen

View File

@@ -1,4 +1,5 @@
local BD = require("ui/bidi")
local ButtonDialog = require("ui/widget/buttondialog")
local ConfirmBox = require("ui/widget/confirmbox")
local DataStorage = require("datastorage")
local Dispatcher = require("dispatcher")
@@ -438,7 +439,7 @@ function TextEditor:checkEditFile(file_path, from_history, possibly_new_file)
-- No need to warn if readonly, the user will know it when we open
-- without keyboard and the Save button says "Read only".
local readonly = true
local file = io.open(file_path, 'r+b')
local file = io.open(file_path, "r+b")
if file then
file:close()
readonly = false
@@ -474,18 +475,6 @@ function TextEditor:checkEditFile(file_path, from_history, possibly_new_file)
end
end
function TextEditor:readFileContent(file_path)
local file = io.open(file_path, "rb")
if not file then
-- We checked file existence before, so assume it's
-- because it's a new file
return ""
end
local file_content = file:read("*all")
file:close()
return file_content
end
function TextEditor:saveFileContent(file_path, content)
local ok, err = util.writeToFile(content, file_path)
if ok then
@@ -514,7 +503,6 @@ function TextEditor:editFile(file_path, readonly)
local directory, filename = util.splitFilePathName(file_path) -- luacheck: no unused
local filename_without_suffix, filetype = util.splitFileNameSuffix(filename) -- luacheck: no unused
local is_lua = filetype:lower() == "lua"
local input
local para_direction_rtl = nil -- use UI language direction
if self.force_ltr_para_direction then
para_direction_rtl = false -- force LTR
@@ -524,7 +512,7 @@ function TextEditor:editFile(file_path, readonly)
table.insert(buttons_first_row, {
text = _("Lua check"),
callback = function()
local parse_error = util.checkLuaSyntax(input:getInputText())
local parse_error = util.checkLuaSyntax(self.input:getInputText())
if parse_error then
UIManager:show(InfoMessage:new{
text = T(_("Lua syntax check failed:\n\n%1"), parse_error)
@@ -542,16 +530,16 @@ function TextEditor:editFile(file_path, readonly)
text = _("QR"),
callback = function()
UIManager:show(QRMessage:new{
text = input:getInputText(),
text = self.input:getInputText(),
height = Screen:getHeight(),
width = Screen:getWidth()
})
end,
})
end
input = InputDialog:new{
self.input = InputDialog:new{
title = filename,
input = self:readFileContent(file_path),
input = util.readFromFile(file_path, "rb"),
input_face = Font:getFace(self.font_face, self.font_size),
para_direction_rtl = para_direction_rtl,
auto_para_direction = self.auto_para_direction,
@@ -561,6 +549,9 @@ function TextEditor:editFile(file_path, readonly)
cursor_at_end = false,
readonly = readonly,
add_nav_bar = true,
title_bar_left_icon = "appbar.menu",
title_bar_left_icon_tap_callback = function() self:showMenu() end,
rotation_enabled = true,
keyboard_visible = self.show_keyboard_on_start, -- InputDialog will enforce false if readonly
scroll_by_pan = true,
buttons = {buttons_first_row},
@@ -580,10 +571,13 @@ function TextEditor:editFile(file_path, readonly)
end,
-- File restoring callback
reset_callback = function(content) -- Will add a Reset button
return self:readFileContent(file_path), _("Text reset to last saved content")
return util.readFromFile(file_path, "rb") or "", _("Text reset to last saved content")
end,
-- Close callback
close_callback = function()
if self.input.rotation_mode_backup and self.input.rotation_mode_backup ~= Screen:getRotationMode() then
Screen:setRotationMode(self.input.rotation_mode_backup)
end
self:execWhenDoneFunc()
end,
-- File saving callback
@@ -656,9 +650,9 @@ Do you want to keep this file as empty, or do you prefer to delete it?
end,
}
UIManager:show(input)
UIManager:show(self.input)
if self.show_keyboard_on_start and not readonly then
input:onShowKeyboard()
self.input:onShowKeyboard()
end
-- Note about readonly:
-- We might have liked to still show keyboard even if readonly, just
@@ -688,4 +682,32 @@ function TextEditor:quickEditFile(file_path, done_callback, possible_new_file)
self:checkEditFile(file_path, possible_new_file or false)
end
-- TitleBar left button tap
function TextEditor:showMenu()
local dialog
local buttons = {}
local optionsutil = require("ui/data/optionsutil")
for i, mode in ipairs(optionsutil.rotation_modes) do
buttons[i] = {{
text = optionsutil.rotation_labels[i],
enabled_func = function()
return optionsutil.rotation_modes[i] ~= Screen:getRotationMode()
end,
callback = function()
UIManager:close(dialog)
self.input:onSetRotationMode(optionsutil.rotation_modes[i])
end,
}}
end
dialog = ButtonDialog:new{
shrink_unneeded_width = true,
buttons = buttons,
anchor = function()
return self.input.title_bar.left_button.image.dimen
end,
modal = true,
}
UIManager:show(dialog)
end
return TextEditor