2
0
mirror of https://github.com/koreader/koreader synced 2024-11-16 06:12:56 +00:00
koreader/frontend/ui/widget/numberpickerwidget.lua
onde2rock e502bf04d3 [feat, UX] Support the virtualKeyboard on non touch-device (#3796)
* [VirtualKeyboard] Add support for keynaviguation

Also rename the variable "layout" to "keyboard_layout" because conflict
with the layout from the focusmanager

* Make the goto dialog compatible with key naviguation

My solution is to change the order of the widget. The last one will the
virtualkeybard so it catch all the keybinding, and below it, make the
dialog "is_always_active = true" so it can receive touch event.

* Correctly show the virtual keyboard on dpad devices

* change the order to call the virtualKeyboard so it end up on top

* Handle the multi input dialog

* Support reopening the virtualKeyboard by the Press key

* add check focusmanager

* Fix https://github.com/koreader/koreader/issues/3797

* MultiInputDialog : Now work on non touch-device

* Set the virtualkeyboard to be a modal widget

* Fix the layout in multiinputwidget

* Fix for the various combination of
hasKeys,hasDpad,isTouchDevice

* [Focusmanager] Better handling of malformed layout
2018-03-30 12:46:36 +02:00

231 lines
7.4 KiB
Lua

local Button = require("ui/widget/button")
local CenterContainer = require("ui/widget/container/centercontainer")
local Device = require("device")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local Font = require("ui/font")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local _ = require("gettext")
local Screen = Device.screen
local NumberPickerWidget = InputContainer:new{
spinner_face = Font:getFace("smalltfont"),
precision = "%02d",
width = nil,
height = nil,
value = 0,
value_min = 0,
value_max = 23,
value_step = 1,
value_hold_step = 4,
value_table = nil,
-- in case we need calculate number of days in a given month and year
date_month = nil,
date_year = nil,
}
function NumberPickerWidget:init()
self.screen_width = Screen:getWidth()
self.screen_height = Screen:getHeight()
if self.width == nil then
self.width = self.screen_width * 0.2
end
if self.value_table then
self.value_index = 1
self.value = self.value_table[self.value_index]
self.step = 1
self.value_hold_step = 1
end
self:update()
end
function NumberPickerWidget:paintWidget()
local bordersize = Size.border.default
local margin = Size.margin.default
local button_up = Button:new{
text = "",
bordersize = bordersize,
margin = margin,
radius = 0,
text_font_size = 24,
width = self.width,
show_parent = self.show_parent,
callback = function()
if self.date_month and self.date_year then
self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue())
end
self.value = self:changeValue(self.value, self.value_step, self.value_max, self.value_min)
self:update()
end,
hold_callback = function()
if self.date_month and self.date_year then
self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue())
end
self.value = self:changeValue(self.value, self.value_hold_step, self.value_max, self.value_min)
self:update()
end
}
local button_down = Button:new{
text = "",
bordersize = bordersize,
margin = margin,
radius = 0,
text_font_size = 24,
width = self.width,
show_parent = self.show_parent,
callback = function()
if self.date_month and self.date_year then
self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue())
end
self.value = self:changeValue(self.value, self.value_step * -1, self.value_max, self.value_min)
self:update()
end,
hold_callback = function()
if self.date_month and self.date_year then
self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue())
end
self.value = self:changeValue(self.value, self.value_hold_step * -1, self.value_max, self.value_min)
self:update()
end
}
local empty_space = VerticalSpan:new{
width = self.screen_height * 0.01
}
local value = self.value
if self.value_table then
local text_width = RenderText:sizeUtf8Text(0, self.width, self.spinner_face, self.value, true, true).x
if self.width < text_width then
value = RenderText:truncateTextByWidth(self.value, self.spinner_face, self.width,true, true)
end
else
value = string.format(self.precision, value)
end
local input
local callback_input = nil
if self.value_table == nil then
callback_input = function()
input = InputDialog:new{
title = _("Enter number"),
input_type = "number",
buttons = {
{
{
text = _("Cancel"),
callback = function()
UIManager:close(input)
end,
},
{
text = _("OK"),
is_enter_default = true,
callback = function()
input:closeInputDialog()
local input_value = tonumber(input:getInputText())
if input_value and input_value >= self.value_min and input_value <= self.value_max then
self.value = input_value
self:update()
end
UIManager:close(input)
end,
},
},
},
}
UIManager:show(input)
input:onShowKeyboard()
end
end
local text_value = Button:new{
text = value,
bordersize = 0,
padding = 0,
text_font_face = self.spinner_face_font,
text_font_size = self.spinner_face_size,
width = self.width,
callback = callback_input,
}
return VerticalGroup:new{
align = "center",
button_up,
empty_space,
text_value,
empty_space,
button_down,
}
end
function NumberPickerWidget:update()
local widget_spinner = self:paintWidget()
self.frame = FrameContainer:new{
bordersize = 0,
padding = Size.padding.default,
CenterContainer:new{
align = "center",
dimen = Geom:new{
w = widget_spinner:getSize().w,
h = widget_spinner:getSize().h
},
widget_spinner
}
}
self.dimen = self.frame:getSize()
self[1] = self.frame
UIManager:setDirty(self.show_parent, function()
return "ui", self.dimen
end)
end
function NumberPickerWidget:changeValue(value, step, max, min)
if self.value_index then
self.value_index = self.value_index + step
if self.value_index > #self.value_table then
self.value_index = 1
elseif
self.value_index < 1 then
self.value_index = #self.value_table
end
value = self.value_table[self.value_index]
else
value = value + step
if value > max then
value = min
elseif value < min then
value = max
end
end
return value
end
function NumberPickerWidget:getDaysInMonth(month, year)
local days_in_month = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
local days = days_in_month[month]
-- check for leap year
if (month == 2) then
if year % 4 == 0 then
if year % 100 == 0 then
if year % 400 == 0 then
days = 29
end
else
days = 29
end
end
end
return days
end
function NumberPickerWidget:getValue()
return self.value
end
return NumberPickerWidget