mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
VirtualKeyboard: Revamp visibility handling (#10852)
Move as much of the state tracking as possible inside VirtualKeyboard itself. InputDialog unfortunately needs an internal tracking of this state because it needs to know about it *before* the VK is shown, so we have to keep a bit of duplication in there, although we do try much harder to keep everything in sync (at least at function call edges), and to keep the damage contained to, essentially, the toggle button's handler. (Followup to #10803 & #10850)
This commit is contained in:
@@ -920,10 +920,10 @@ function ReaderStyleTweak:editBookTweak(touchmenu_instance)
|
||||
end
|
||||
end
|
||||
end,
|
||||
-- Set/save view and cursor position callback
|
||||
-- Store/retrieve view and cursor position callback
|
||||
view_pos_callback = function(top_line_num, charpos)
|
||||
-- This same callback is called with no argument to get initial position,
|
||||
-- and with arguments to give back final position when closed.
|
||||
-- This same callback is called with no arguments on init to retrieve the stored initial position,
|
||||
-- and with arguments to store the final position on close.
|
||||
if top_line_num and charpos then
|
||||
self.book_style_tweak_last_edit_pos = {top_line_num, charpos}
|
||||
else
|
||||
|
||||
@@ -141,7 +141,7 @@ local InputDialog = FocusManager:extend{
|
||||
add_scroll_buttons = false, -- add scroll Up/Down buttons to first row of buttons
|
||||
add_nav_bar = false, -- append a row of page navigation buttons
|
||||
-- note that the text widget can be scrolled with Swipe North/South even when no button
|
||||
keyboard_hidden = false, -- start with keyboard hidden in full fullscreen mode
|
||||
keyboard_visible = true, -- whether we start with the keyboard visible or not (i.e., our caller skipped onShowKeyboard)
|
||||
-- needs add_nav_bar to have a Show keyboard button to get it back
|
||||
scroll_by_pan = false, -- allow scrolling by lines with Pan (= Swipe, but wait a bit at end
|
||||
-- of gesture before releasing) (may conflict with movable)
|
||||
@@ -162,8 +162,8 @@ local InputDialog = FocusManager:extend{
|
||||
edited_callback = nil, -- Called on each text modification
|
||||
|
||||
-- For use by TextEditor plugin:
|
||||
view_pos_callback = nil, -- Called with no arg to get initial top_line_num/charpos,
|
||||
-- called with (top_line_num, charpos) to give back position on close.
|
||||
view_pos_callback = nil, -- Called with no args on init to retrieve top_line_num/charpos (however the caller chooses to do so, e.g., some will store it in a LuaSettings),
|
||||
-- called with (top_line_num, charpos) on close to let the callback do its thing so that the no args branch spits back useful data..
|
||||
|
||||
-- Set to false if movable gestures conflicts with subwidgets gestures
|
||||
is_movable = true,
|
||||
@@ -189,6 +189,7 @@ local InputDialog = FocusManager:extend{
|
||||
alignment_strict = false,
|
||||
|
||||
-- for internal use
|
||||
_keyboard_was_visible = nil, -- previous kb visibility state
|
||||
_text_modified = false, -- previous known modified status
|
||||
_top_line_num = nil,
|
||||
_charpos = nil,
|
||||
@@ -216,7 +217,7 @@ function InputDialog:init()
|
||||
self.text_width = self.text_width or math.floor(self.width * 0.9)
|
||||
end
|
||||
if self.readonly then -- hide keyboard if we can't edit
|
||||
self.keyboard_hidden = true
|
||||
self.keyboard_visible = false
|
||||
end
|
||||
if self.fullscreen or self.add_nav_bar then
|
||||
self.deny_keyboard_hiding = true
|
||||
@@ -299,10 +300,7 @@ function InputDialog:init()
|
||||
local text_height = input_widget:getTextHeight()
|
||||
local line_height = input_widget:getLineHeight()
|
||||
local input_pad_height = input_widget:getSize().h - text_height
|
||||
local keyboard_height = 0
|
||||
if not self.keyboard_hidden then
|
||||
keyboard_height = input_widget:getKeyboardDimen().h
|
||||
end
|
||||
local keyboard_height = self.keyboard_visible and input_widget:getKeyboardDimen().h or 0
|
||||
input_widget:onCloseWidget() -- free() textboxwidget and keyboard
|
||||
-- Find out available height
|
||||
local available_height = self.screen_height
|
||||
@@ -331,9 +329,14 @@ function InputDialog:init()
|
||||
end
|
||||
end
|
||||
if self.view_pos_callback then
|
||||
-- Get initial cursor and top line num from callback
|
||||
-- (will work in case of re-init as these are saved by onClose()
|
||||
self._top_line_num, self._charpos = self.view_pos_callback()
|
||||
-- Retrieve cursor position and top line num from our callback.
|
||||
-- Mainly used for runtime re-inits.
|
||||
-- c.f., our onClose handler for the other end of this.
|
||||
-- *May* return nils, in which case, we do *not* want to override our caller's values!
|
||||
local top_line_num, charpos = self.view_pos_callback()
|
||||
if top_line_num and charpos then
|
||||
self._top_line_num, self._charpos = top_line_num, charpos
|
||||
end
|
||||
end
|
||||
self._input_widget = self.inputtext_class:new{
|
||||
text = self.input,
|
||||
@@ -368,7 +371,6 @@ function InputDialog:init()
|
||||
scroll_by_pan = self.scroll_by_pan,
|
||||
cursor_at_end = self.cursor_at_end,
|
||||
readonly = self.readonly,
|
||||
manage_keyboard_state = not self.add_nav_bar, -- we handle keyboard toggle ourselve if nav_bar
|
||||
parent = self,
|
||||
is_text_edited = self._text_modified,
|
||||
top_line_num = self._top_line_num,
|
||||
@@ -423,8 +425,7 @@ function InputDialog:init()
|
||||
}
|
||||
frame = self.movable
|
||||
end
|
||||
local keyboard_height = self.keyboard_hidden and 0
|
||||
or self._input_widget:getKeyboardDimen().h
|
||||
local keyboard_height = self.keyboard_visible and self._input_widget:getKeyboardDimen().h or 0
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = self.screen_width,
|
||||
@@ -449,6 +450,11 @@ function InputDialog:init()
|
||||
self:addWidget(widget, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- If we're fullscreen without a keyboard, make sure only the toggle button can show the keyboard...
|
||||
if self.fullscreen and not self.keyboard_visible then
|
||||
self:lockKeyboard(true)
|
||||
end
|
||||
end
|
||||
|
||||
function InputDialog:addWidget(widget, re_init)
|
||||
@@ -474,13 +480,13 @@ function InputDialog:getAddedWidgetAvailableWidth()
|
||||
return self._input_widget.width
|
||||
end
|
||||
|
||||
-- Close the keyboard if we tap anywhere outside of the keyboard (that isn't an input field, where it would be caught via InputText:onTapTextBox)
|
||||
function InputDialog:onTap()
|
||||
-- This is slightly more fine-grained than VK's own visibility lock, hence the duplication...
|
||||
if self.deny_keyboard_hiding then
|
||||
return
|
||||
end
|
||||
if self._input_widget.onCloseKeyboard then
|
||||
self._input_widget:onCloseKeyboard()
|
||||
end
|
||||
self:onCloseKeyboard()
|
||||
end
|
||||
|
||||
function InputDialog:getInputText()
|
||||
@@ -525,24 +531,79 @@ function InputDialog:onCloseWidget()
|
||||
end
|
||||
|
||||
function InputDialog:onShowKeyboard(ignore_first_hold_release)
|
||||
if not self.readonly and not self.keyboard_hidden then
|
||||
self._input_widget:onShowKeyboard(ignore_first_hold_release)
|
||||
end
|
||||
-- NOTE: There's no VirtualKeyboard widget instantiated at all when readonly,
|
||||
-- and our input widget handles that itself, so we don't need any guards here.
|
||||
-- (In which case, isKeyboardVisible will return `nil`, same as if we had a VK instantiated but *never* shown).
|
||||
self._input_widget:onShowKeyboard(ignore_first_hold_release)
|
||||
-- There's a bit of a chicken or egg issue in init where we would like to check the actual keyboard's visibility state,
|
||||
-- but the widget might not exist or be shown yet, so we'll just have to keep this in sync...
|
||||
self.keyboard_visible = self._input_widget:isKeyboardVisible()
|
||||
end
|
||||
|
||||
function InputDialog:toggleKeyboard(force_hide)
|
||||
if force_hide and self.keyboard_hidden then return end
|
||||
self.keyboard_hidden = not self.keyboard_hidden
|
||||
function InputDialog:onCloseKeyboard()
|
||||
self._input_widget:onCloseKeyboard()
|
||||
self.keyboard_visible = self._input_widget:isKeyboardVisible()
|
||||
end
|
||||
|
||||
function InputDialog:isKeyboardVisible()
|
||||
return self._input_widget:isKeyboardVisible()
|
||||
end
|
||||
|
||||
function InputDialog:lockKeyboard(toggle)
|
||||
return self._input_widget:lockKeyboard(toggle)
|
||||
end
|
||||
|
||||
-- NOTE: Only called by fullscreen and/or add_nav_bar codepaths
|
||||
-- We do not currently have !fullscreen add_nav_bar callers...
|
||||
function InputDialog:toggleKeyboard(force_toggle)
|
||||
-- Remember the *current* visibility, as the following close will reset it
|
||||
local visible = self:isKeyboardVisible()
|
||||
|
||||
-- When we forcibly close the keyboard, remember its current visiblity state, so that we can properly restore it later.
|
||||
-- (This is used by some buttons in fullscreen mode, where we might want to keep the original keyboard hidden when popping up a new one for another InputDialog).
|
||||
if force_toggle == false then
|
||||
-- NOTE: visible will be nil between our own init and a show of the keyboard, which is precisely what happens when we *hide* the keyboard.
|
||||
self._keyboard_was_visible = visible == true
|
||||
end
|
||||
|
||||
self.input = self:getInputText() -- re-init with up-to-date text
|
||||
self:onClose() -- will close keyboard and save view position
|
||||
self:free()
|
||||
self:init()
|
||||
if not self.keyboard_hidden then
|
||||
self:onShowKeyboard()
|
||||
|
||||
if force_toggle == false and not visible then
|
||||
-- Already hidden, bye!
|
||||
return
|
||||
end
|
||||
|
||||
-- Init needs to know the keyboard's visibility state *before* the widget is actually shown...
|
||||
if force_toggle == true then
|
||||
self.keyboard_visible = true
|
||||
elseif force_toggle == false then
|
||||
self.keyboard_visible = false
|
||||
elseif self._keyboard_was_visible ~= nil then
|
||||
self.keyboard_visible = self._keyboard_was_visible
|
||||
self._keyboard_was_visible = nil
|
||||
else
|
||||
self.keyboard_visible = not visible
|
||||
end
|
||||
self:init()
|
||||
|
||||
-- NOTE: If we ever have non-fullscreen add_nav_bar callers, it might make sense *not* to lock the keyboard there?
|
||||
if self.keyboard_visible then
|
||||
self:lockKeyboard(false)
|
||||
self:onShowKeyboard()
|
||||
else
|
||||
self:onCloseKeyboard()
|
||||
-- Prevent InputText:onTapTextBox from opening the keyboard back up on top of our buttons
|
||||
self:lockKeyboard(true)
|
||||
end
|
||||
|
||||
-- Make sure we refresh the nav bar, as it will have moved, and it belongs to us, not to VK or our input widget...
|
||||
self:refreshButtons()
|
||||
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
|
||||
@@ -555,8 +616,11 @@ function InputDialog:onKeyboardHeightChanged()
|
||||
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 not self.keyboard_hidden then
|
||||
if self.keyboard_visible then
|
||||
self:onShowKeyboard()
|
||||
end
|
||||
-- Our position on screen has probably changed, so have the full screen refreshed
|
||||
@@ -573,14 +637,16 @@ function InputDialog:onCloseDialog()
|
||||
end
|
||||
|
||||
function InputDialog:onClose()
|
||||
-- Tell our input widget to poke its text widget so that we'll pickup up to date values
|
||||
self._input_widget:resyncPos()
|
||||
-- Remember current view & position in case of re-init
|
||||
self._top_line_num = self._input_widget.top_line_num
|
||||
self._charpos = self._input_widget.charpos
|
||||
if self.view_pos_callback then
|
||||
-- Give back top line num and cursor position
|
||||
-- This lets the caller store/process the current top line num and cursor position via this callback
|
||||
self.view_pos_callback(self._top_line_num, self._charpos)
|
||||
end
|
||||
self._input_widget:onCloseKeyboard()
|
||||
self:onCloseKeyboard()
|
||||
end
|
||||
|
||||
function InputDialog:refreshButtons()
|
||||
@@ -764,7 +830,7 @@ function InputDialog:_addScrollButtons(nav_bar)
|
||||
-- Also add Keyboard hide/show button if we can
|
||||
if self.fullscreen and not self.readonly then
|
||||
table.insert(row, {
|
||||
text = self.keyboard_hidden and "↑⌨" or "↓⌨",
|
||||
text = self.keyboard_visible and "↓⌨" or "↑⌨",
|
||||
id = "keyboard",
|
||||
callback = function()
|
||||
self:toggleKeyboard()
|
||||
@@ -776,8 +842,7 @@ function InputDialog:_addScrollButtons(nav_bar)
|
||||
table.insert(row, {
|
||||
text = _("Find"),
|
||||
callback = function()
|
||||
local keyboard_hidden_state = not self.keyboard_hidden
|
||||
self:toggleKeyboard(true) -- hide text editor keyboard
|
||||
self:toggleKeyboard(false) -- hide text editor keyboard
|
||||
local input_dialog
|
||||
input_dialog = InputDialog:new{
|
||||
title = _("Enter text to search for"),
|
||||
@@ -790,21 +855,20 @@ function InputDialog:_addScrollButtons(nav_bar)
|
||||
id = "close",
|
||||
callback = function()
|
||||
UIManager:close(input_dialog)
|
||||
self.keyboard_hidden = keyboard_hidden_state
|
||||
self:toggleKeyboard()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Find first"),
|
||||
callback = function()
|
||||
self:findCallback(keyboard_hidden_state, input_dialog, true)
|
||||
self:findCallback(input_dialog, true)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Find next"),
|
||||
is_enter_default = true,
|
||||
callback = function()
|
||||
self:findCallback(keyboard_hidden_state, input_dialog)
|
||||
self:findCallback(input_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
@@ -829,8 +893,7 @@ function InputDialog:_addScrollButtons(nav_bar)
|
||||
table.insert(row, {
|
||||
text = _("Go"),
|
||||
callback = function()
|
||||
local keyboard_hidden_state = not self.keyboard_hidden
|
||||
self:toggleKeyboard(true) -- hide text editor keyboard
|
||||
self:toggleKeyboard(false) -- hide text editor keyboard
|
||||
local cur_line_num, last_line_num = self._input_widget:getLineNums()
|
||||
local input_dialog
|
||||
input_dialog = InputDialog:new{
|
||||
@@ -846,7 +909,6 @@ function InputDialog:_addScrollButtons(nav_bar)
|
||||
id = "close",
|
||||
callback = function()
|
||||
UIManager:close(input_dialog)
|
||||
self.keyboard_hidden = keyboard_hidden_state
|
||||
self:toggleKeyboard()
|
||||
end,
|
||||
},
|
||||
@@ -857,7 +919,6 @@ function InputDialog:_addScrollButtons(nav_bar)
|
||||
local new_line_num = tonumber(input_dialog:getInputText())
|
||||
if new_line_num and new_line_num >= 1 and new_line_num <= last_line_num then
|
||||
UIManager:close(input_dialog)
|
||||
self.keyboard_hidden = keyboard_hidden_state
|
||||
self:toggleKeyboard()
|
||||
self._input_widget:moveCursorToCharPos(self._input_widget:getLineCharPos(new_line_num))
|
||||
end
|
||||
@@ -939,11 +1000,10 @@ function InputDialog:_addScrollButtons(nav_bar)
|
||||
end
|
||||
end
|
||||
|
||||
function InputDialog:findCallback(keyboard_hidden_state, input_dialog, find_first)
|
||||
function InputDialog:findCallback(input_dialog, find_first)
|
||||
self.search_value = input_dialog:getInputText()
|
||||
if self.search_value == "" then return end
|
||||
UIManager:close(input_dialog)
|
||||
self.keyboard_hidden = keyboard_hidden_state
|
||||
self:toggleKeyboard()
|
||||
local start_pos = find_first and 1 or self._charpos + 1
|
||||
local char_pos = util.stringSearch(self.input, self.search_value, self.case_sensitive, start_pos)
|
||||
|
||||
@@ -32,9 +32,8 @@ local InputText = InputContainer:extend{
|
||||
focused = true,
|
||||
parent = nil, -- parent dialog that will be set dirty
|
||||
edit_callback = nil, -- called with true when text modified, false on init or text re-set
|
||||
scroll_callback = nil, -- called with (low, high) when view is scrolled (cf ScrollTextWidget)
|
||||
scroll_callback = nil, -- called with (low, high) when view is scrolled (c.f., ScrollTextWidget)
|
||||
scroll_by_pan = false, -- allow scrolling by lines with Pan (needs scroll=true)
|
||||
manage_keyboard_state = true, -- manage keyboard hidden/shown state
|
||||
|
||||
width = nil,
|
||||
height = nil, -- when nil, will be set to original text height (possibly
|
||||
@@ -54,7 +53,10 @@ local InputText = InputContainer:extend{
|
||||
auto_para_direction = false,
|
||||
alignment_strict = false,
|
||||
|
||||
readonly = nil, -- will not support a Keyboard widget if true
|
||||
|
||||
-- for internal use
|
||||
keyboard = nil, -- Keyboard widget (either VirtualKeyboard or PhysicalKeyboard)
|
||||
text_widget = nil, -- Text Widget for cursor movement, possibly a ScrollTextWidget
|
||||
charlist = nil, -- table of individual chars from input string
|
||||
charpos = nil, -- position of the cursor, where a new char would be inserted
|
||||
@@ -65,7 +67,6 @@ local InputText = InputContainer:extend{
|
||||
for_measurement_only = nil, -- When the widget is a one-off used to compute text height
|
||||
do_select = false, -- to start text selection
|
||||
selection_start_pos = nil, -- selection start position
|
||||
is_keyboard_hidden = true, -- to be able to show the keyboard again when it was hidden. (On init, it's the caller's responsibility to call onShowKeyboard, as far as we're concerned, it's hidden)
|
||||
}
|
||||
|
||||
-- These may be (internally) overloaded as needed, depending on Device capabilities.
|
||||
@@ -73,6 +74,11 @@ function InputText:initEventListener() end
|
||||
function InputText:onFocus() end
|
||||
function InputText:onUnfocus() end
|
||||
|
||||
-- Resync our position state with our text widget's actual state
|
||||
function InputText:resyncPos()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
end
|
||||
|
||||
local function initTouchEvents()
|
||||
if Device:isTouchDevice() then
|
||||
function InputText:initEventListener()
|
||||
@@ -133,8 +139,8 @@ local function initTouchEvents()
|
||||
if self.parent.onSwitchFocus then
|
||||
self.parent:onSwitchFocus(self)
|
||||
else
|
||||
if self.is_keyboard_hidden and self.manage_keyboard_state then
|
||||
self:onShowKeyboard()
|
||||
if self.keyboard then
|
||||
self.keyboard:showKeyboard()
|
||||
end
|
||||
end
|
||||
-- zh keyboard with candidates shown here has _frame_textwidget.dimen = nil.
|
||||
@@ -144,7 +150,7 @@ local function initTouchEvents()
|
||||
local x = ges.pos.x - self._frame_textwidget.dimen.x - textwidget_offset
|
||||
local y = ges.pos.y - self._frame_textwidget.dimen.y - textwidget_offset
|
||||
self.text_widget:moveCursorToXY(x, y, true) -- restrict_to_view=true
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -512,7 +518,7 @@ function InputText:initTextBox(text, char_added)
|
||||
}
|
||||
end
|
||||
-- Get back possibly modified charpos and virtual_line_num
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
|
||||
self._frame_textwidget = FrameContainer:new{
|
||||
bordersize = self.bordersize,
|
||||
@@ -676,22 +682,27 @@ dbg:guard(InputText, "onTextInput",
|
||||
end)
|
||||
|
||||
function InputText:onShowKeyboard(ignore_first_hold_release)
|
||||
Device:startTextInput()
|
||||
|
||||
if self.is_keyboard_hidden or not self.manage_keyboard_state then
|
||||
self.keyboard.ignore_first_hold_release = ignore_first_hold_release
|
||||
UIManager:show(self.keyboard)
|
||||
self.is_keyboard_hidden = false
|
||||
if self.keyboard then
|
||||
self.keyboard:showKeyboard(ignore_first_hold_release)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function InputText:onCloseKeyboard()
|
||||
Device:stopTextInput()
|
||||
if self.keyboard then
|
||||
self.keyboard:hideKeyboard()
|
||||
end
|
||||
end
|
||||
|
||||
if not self.is_keyboard_hidden or not self.manage_keyboard_state then
|
||||
UIManager:close(self.keyboard)
|
||||
self.is_keyboard_hidden = true
|
||||
function InputText:isKeyboardVisible()
|
||||
if self.keyboard then
|
||||
return self.keyboard:isVisible()
|
||||
end
|
||||
end
|
||||
|
||||
function InputText:lockKeyboard(toggle)
|
||||
if self.keyboard then
|
||||
return self.keyboard:lockVisibility(toggle)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -873,71 +884,71 @@ end
|
||||
function InputText:leftChar()
|
||||
if self.charpos == 1 then return end
|
||||
self.text_widget:moveCursorLeft()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:rightChar()
|
||||
if self.charpos > #self.charlist then return end
|
||||
self.text_widget:moveCursorRight()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:goToStartOfLine()
|
||||
local new_pos = select(1, self:getStringPos({"\n", "\r"}, {"\n", "\r"}))
|
||||
self.text_widget:moveCursorToCharPos(new_pos)
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:goToEndOfLine()
|
||||
local new_pos = select(2, self:getStringPos({"\n", "\r"}, {"\n", "\r"})) + 1
|
||||
self.text_widget:moveCursorToCharPos(new_pos)
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:goToHome()
|
||||
self.text_widget:moveCursorHome()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:goToEnd()
|
||||
self.text_widget:moveCursorEnd()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:moveCursorToCharPos(char_pos)
|
||||
self.text_widget:moveCursorToCharPos(char_pos)
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:upLine()
|
||||
self.text_widget:moveCursorUp()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:downLine()
|
||||
if #self.charlist == 0 then return end -- Avoid cursor moving within a hint.
|
||||
self.text_widget:moveCursorDown()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:scrollDown()
|
||||
self.text_widget:scrollDown()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:scrollUp()
|
||||
self.text_widget:scrollUp()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:scrollToTop()
|
||||
self.text_widget:scrollToTop()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:scrollToBottom()
|
||||
self.text_widget:scrollToBottom()
|
||||
self.charpos, self.top_line_num = self.text_widget:getCharPos()
|
||||
self:resyncPos()
|
||||
end
|
||||
|
||||
function InputText:clear()
|
||||
|
||||
@@ -218,7 +218,9 @@ end
|
||||
function MultiInputDialog:onSwitchFocus(inputbox)
|
||||
-- unfocus current inputbox
|
||||
self._input_widget:unfocus()
|
||||
self._input_widget:onCloseKeyboard()
|
||||
-- and close its existing keyboard (via InputDialog's thin wrapper around _input_widget's own method)
|
||||
self:onCloseKeyboard()
|
||||
|
||||
UIManager:setDirty(nil, function()
|
||||
return "ui", self.dialog_frame.dimen
|
||||
end)
|
||||
@@ -226,7 +228,9 @@ function MultiInputDialog:onSwitchFocus(inputbox)
|
||||
-- focus new inputbox
|
||||
self._input_widget = inputbox
|
||||
self._input_widget:focus()
|
||||
self._input_widget:onShowKeyboard()
|
||||
|
||||
-- Make sure we have a (new) visible keyboard
|
||||
self:onShowKeyboard()
|
||||
end
|
||||
|
||||
return MultiInputDialog
|
||||
|
||||
@@ -169,4 +169,11 @@ function PhysicalKeyboard:setupNumericMappingUI()
|
||||
self.dimen = keyboard_frame:getSize()
|
||||
end
|
||||
|
||||
-- Match VirtualKeyboard's API to ease caller's life
|
||||
function PhysicalKeyboard:lockVisibility() end
|
||||
function PhysicalKeyboard:setVisibility() end
|
||||
function PhysicalKeyboard:isVisible() return true end
|
||||
function PhysicalKeyboard:showKeyboard() end
|
||||
function PhysicalKeyboard:hideKeyboard() end
|
||||
|
||||
return PhysicalKeyboard
|
||||
|
||||
@@ -755,6 +755,8 @@ end
|
||||
|
||||
local VirtualKeyboard = FocusManager:extend{
|
||||
name = "VirtualKeyboard",
|
||||
visible = nil,
|
||||
lock_visibility = false,
|
||||
covers_footer = true,
|
||||
modal = true,
|
||||
disable_double_tap = true,
|
||||
@@ -929,11 +931,53 @@ end
|
||||
|
||||
function VirtualKeyboard:onShow()
|
||||
self:_refresh(true)
|
||||
self.visible = true
|
||||
Device:startTextInput()
|
||||
return true
|
||||
end
|
||||
|
||||
function VirtualKeyboard:onCloseWidget()
|
||||
self:_refresh(true)
|
||||
self.visible = false
|
||||
-- NOTE: This effectively stops SDL text input when a keyboard is hidden (... but navigational stuff still works).
|
||||
-- If you instead wanted it to be enabled as long as an input dialog is displayed, regardless of VK's state,
|
||||
-- this could be moved to InputDialog's onShow/onCloseWidget handlers (but, it would allow input on unfocused fields).
|
||||
-- NOTE: But something more complex, possibly based on an in-class ref count would have to be implemented in order to be able to deal
|
||||
-- with multiple InputDialogs being shown and closed in asymmetric fashion... Ugh.
|
||||
Device:stopTextInput()
|
||||
end
|
||||
|
||||
function VirtualKeyboard:lockVisibility(toggle)
|
||||
self.lock_visibility = toggle
|
||||
end
|
||||
|
||||
function VirtualKeyboard:setVisibility(toggle)
|
||||
if self.lock_visibility then
|
||||
return
|
||||
end
|
||||
|
||||
if toggle then
|
||||
UIManager:show(self)
|
||||
else
|
||||
self:onClose()
|
||||
end
|
||||
end
|
||||
|
||||
function VirtualKeyboard:isVisible()
|
||||
return self.visible
|
||||
end
|
||||
|
||||
function VirtualKeyboard:showKeyboard(ignore_first_hold_release)
|
||||
if not self:isVisible() then
|
||||
self.ignore_first_hold_release = ignore_first_hold_release
|
||||
self:setVisibility(true)
|
||||
end
|
||||
end
|
||||
|
||||
function VirtualKeyboard:hideKeyboard()
|
||||
if self:isVisible() then
|
||||
self:setVisibility(false)
|
||||
end
|
||||
end
|
||||
|
||||
function VirtualKeyboard:initLayer(layer)
|
||||
|
||||
@@ -545,13 +545,13 @@ function TextEditor:editFile(file_path, readonly)
|
||||
cursor_at_end = false,
|
||||
readonly = readonly,
|
||||
add_nav_bar = true,
|
||||
keyboard_hidden = not self.show_keyboard_on_start,
|
||||
keyboard_visible = self.show_keyboard_on_start, -- InputDialog will enforce false if readonly
|
||||
scroll_by_pan = true,
|
||||
buttons = {buttons_first_row},
|
||||
-- Set/save view and cursor position callback
|
||||
-- Store/retrieve view and cursor position callback
|
||||
view_pos_callback = function(top_line_num, charpos)
|
||||
-- This same callback is called with no argument to get initial position,
|
||||
-- and with arguments to give back final position when closed.
|
||||
-- This same callback is called with no arguments on init to retrieve the stored initial position,
|
||||
-- and with arguments to store the final position on close.
|
||||
if top_line_num and charpos then
|
||||
self.last_view_pos[file_path] = {top_line_num, charpos}
|
||||
else
|
||||
@@ -572,7 +572,7 @@ function TextEditor:editFile(file_path, readonly)
|
||||
end,
|
||||
-- File saving callback
|
||||
save_callback = function(content, closing) -- Will add Save/Close buttons
|
||||
if self.readonly then
|
||||
if readonly then
|
||||
-- We shouldn't be called if read-only, but just in case
|
||||
return false, _("File is read only")
|
||||
end
|
||||
@@ -641,8 +641,10 @@ Do you want to keep this file as empty, or do you prefer to delete it?
|
||||
|
||||
}
|
||||
UIManager:show(input)
|
||||
input:onShowKeyboard()
|
||||
-- Note about self.readonly:
|
||||
if self.show_keyboard_on_start and not readonly then
|
||||
input:onShowKeyboard()
|
||||
end
|
||||
-- Note about readonly:
|
||||
-- We might have liked to still show keyboard even if readonly, just
|
||||
-- to use the arrow keys for line by line scrolling with cursor.
|
||||
-- But it's easier to just let InputDialog and InputText do their
|
||||
|
||||
Reference in New Issue
Block a user