2017-09-13 14:56:20 +00:00
--[[--
TouchMenu widget for hierarchical menus .
] ]
2019-12-06 21:55:39 +00:00
local BD = require ( " ui/bidi " )
2017-04-29 08:38:09 +00:00
local Blitbuffer = require ( " ffi/blitbuffer " )
local Button = require ( " ui/widget/button " )
2013-10-18 20:38:07 +00:00
local CenterContainer = require ( " ui/widget/container/centercontainer " )
2017-08-15 07:28:27 +00:00
local CheckMark = require ( " ui/widget/checkmark " )
2017-04-29 08:38:09 +00:00
local Device = require ( " device " )
2018-03-14 21:16:38 +00:00
local Event = require ( " ui/event " )
local FocusManager = require ( " ui/widget/focusmanager " )
2017-04-29 08:38:09 +00:00
local Font = require ( " ui/font " )
local FrameContainer = require ( " ui/widget/container/framecontainer " )
local Geom = require ( " ui/geometry " )
local GestureRange = require ( " ui/gesturerange " )
2013-10-18 20:38:07 +00:00
local HorizontalGroup = require ( " ui/widget/horizontalgroup " )
local HorizontalSpan = require ( " ui/widget/horizontalspan " )
local IconButton = require ( " ui/widget/iconbutton " )
2018-05-25 18:56:37 +00:00
local InfoMessage = require ( " ui/widget/infomessage " )
2017-04-29 08:38:09 +00:00
local InputContainer = require ( " ui/widget/container/inputcontainer " )
local LeftContainer = require ( " ui/widget/container/leftcontainer " )
local LineWidget = require ( " ui/widget/linewidget " )
local RightContainer = require ( " ui/widget/container/rightcontainer " )
2017-09-13 14:56:20 +00:00
local Size = require ( " ui/size " )
2017-04-29 08:38:09 +00:00
local TextWidget = require ( " ui/widget/textwidget " )
2013-10-18 20:38:07 +00:00
local UIManager = require ( " ui/uimanager " )
2018-03-14 21:16:38 +00:00
local UnderlineContainer = require ( " ui/widget/container/underlinecontainer " )
2017-04-29 08:38:09 +00:00
local VerticalGroup = require ( " ui/widget/verticalgroup " )
local VerticalSpan = require ( " ui/widget/verticalspan " )
2019-12-06 21:55:39 +00:00
local getMenuText = require ( " ui/widget/menu " ) . getMenuText
2017-04-23 04:32:58 +00:00
local _ = require ( " gettext " )
2019-12-06 21:55:39 +00:00
local T = require ( " ffi/util " ) . template
2018-03-14 21:16:38 +00:00
local Input = Device.input
local Screen = Device.screen
2013-03-14 05:06:42 +00:00
--[[
TouchMenuItem widget
--]]
2013-10-18 20:38:07 +00:00
local TouchMenuItem = InputContainer : new {
2014-03-13 13:52:43 +00:00
menu = nil ,
vertical_align = " center " ,
item = nil ,
dimen = nil ,
2017-04-29 08:38:09 +00:00
face = Font : getFace ( " smallinfofont " ) ,
2014-03-13 13:52:43 +00:00
show_parent = nil ,
2013-03-14 05:06:42 +00:00
}
function TouchMenuItem : init ( )
2014-03-13 13:52:43 +00:00
self.ges_events = {
TapSelect = {
GestureRange : new {
ges = " tap " ,
range = self.dimen ,
} ,
2014-06-05 06:58:53 +00:00
doc = " Select Menu Item " ,
2014-03-13 13:52:43 +00:00
} ,
2014-07-02 14:51:27 +00:00
HoldSelect = {
GestureRange : new {
ges = " hold " ,
range = self.dimen ,
} ,
doc = " Hold Menu Item " ,
} ,
2014-03-13 13:52:43 +00:00
}
2014-05-01 10:37:12 +00:00
local item_enabled = self.item . enabled
if self.item . enabled_func then
item_enabled = self.item . enabled_func ( )
end
2017-08-15 07:28:27 +00:00
local item_checkable = false
2014-06-05 11:06:35 +00:00
local item_checked = self.item . checked
if self.item . checked_func then
2017-08-15 07:28:27 +00:00
item_checkable = true
2014-06-05 11:06:35 +00:00
item_checked = self.item . checked_func ( )
end
2019-01-15 17:37:36 +00:00
local checkmark_widget = CheckMark : new {
checkable = item_checkable ,
checked = item_checked ,
enabled = item_enabled ,
2017-08-15 07:28:27 +00:00
}
2019-01-15 17:37:36 +00:00
local checked_widget = CheckMark : new { -- for layout, to :getSize()
checked = true ,
2014-06-05 11:06:35 +00:00
}
2018-07-05 05:20:15 +00:00
-- text_max_width should be the TouchMenuItem width minus the below
-- FrameContainer default paddings minus the checked widget width
local text_max_width = self.dimen . w - 2 * Size.padding . default - checked_widget : getSize ( ) . w
local text = getMenuText ( self.item )
2014-03-13 13:52:43 +00:00
self.item_frame = FrameContainer : new {
width = self.dimen . w ,
bordersize = 0 ,
2014-10-22 13:34:11 +00:00
color = Blitbuffer.COLOR_BLACK ,
2014-03-13 13:52:43 +00:00
HorizontalGroup : new {
align = " center " ,
2014-06-05 11:06:35 +00:00
CenterContainer : new {
dimen = Geom : new { w = checked_widget : getSize ( ) . w } ,
2019-01-15 17:37:36 +00:00
checkmark_widget ,
2014-06-05 11:06:35 +00:00
} ,
2014-03-13 13:52:43 +00:00
TextWidget : new {
2018-07-05 05:20:15 +00:00
text = text ,
2019-10-21 13:20:40 +00:00
max_width = text_max_width ,
2019-03-14 19:58:45 +00:00
fgcolor = item_enabled ~= false and Blitbuffer.COLOR_BLACK or Blitbuffer.COLOR_DARK_GRAY ,
2014-03-13 13:52:43 +00:00
face = self.face ,
} ,
} ,
}
2018-03-14 21:16:38 +00:00
self._underline_container = UnderlineContainer : new {
vertical_align = " center " ,
2018-06-02 16:10:55 +00:00
dimen = self.dimen ,
2018-03-14 21:16:38 +00:00
self.item_frame
}
self [ 1 ] = self._underline_container
function self : isEnabled ( )
return item_enabled ~= false and true
end
end
function TouchMenuItem : onFocus ( )
self._underline_container . color = Blitbuffer.COLOR_BLACK
return true
end
function TouchMenuItem : onUnfocus ( )
self._underline_container . color = Blitbuffer.COLOR_WHITE
return true
2013-03-14 05:06:42 +00:00
end
function TouchMenuItem : onTapSelect ( arg , ges )
2014-05-01 10:37:12 +00:00
local enabled = self.item . enabled
if self.item . enabled_func then
enabled = self.item . enabled_func ( )
end
if enabled == false then return end
2017-10-10 21:50:45 +00:00
if G_reader_settings : isFalse ( " flash_ui " ) then
2014-11-12 07:39:04 +00:00
self.menu : onMenuSelect ( self.item )
2017-10-10 21:50:45 +00:00
else
self.item_frame . invert = true
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
UIManager : widgetRepaint ( self [ 1 ] , self [ 1 ] . dimen.x , self [ 1 ] . dimen.y )
UIManager : setDirty ( nil , function ( )
2018-06-02 16:10:55 +00:00
return " fast " , self.dimen
2014-11-30 00:12:00 +00:00
end )
2017-10-10 21:50:45 +00:00
-- yield to main UI loop to invert item
2018-06-02 16:10:55 +00:00
UIManager : tickAfterNext ( function ( )
2017-10-10 21:50:45 +00:00
self.menu : onMenuSelect ( self.item )
self.item_frame . invert = false
2018-09-19 04:38:53 +00:00
-- NOTE: We can *usually* optimize that repaint away, as most entries in the menu will at least trigger a menu repaint ;).
-- But when stuff doesn't repaint the menu and keeps it open, we need to do it.
-- 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
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
--UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y)
2018-09-19 04:38:53 +00:00
UIManager : setDirty ( self.show_parent , function ( )
return " ui " , self.dimen
end )
end
2017-10-10 21:50:45 +00:00
end )
end
2014-10-30 07:51:31 +00:00
return true
2013-03-14 05:06:42 +00:00
end
2014-07-02 14:51:27 +00:00
function TouchMenuItem : onHoldSelect ( arg , ges )
local enabled = self.item . enabled
if self.item . enabled_func then
enabled = self.item . enabled_func ( )
end
if enabled == false then return end
2017-10-10 21:50:45 +00:00
if G_reader_settings : isFalse ( " flash_ui " ) then
2014-11-12 07:39:04 +00:00
self.menu : onMenuHold ( self.item )
2017-10-10 21:50:45 +00:00
else
2018-06-02 16:10:55 +00:00
self.item_frame . invert = true
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
UIManager : widgetRepaint ( self [ 1 ] , self [ 1 ] . dimen.x , self [ 1 ] . dimen.y )
UIManager : setDirty ( nil , function ( )
2018-06-02 16:10:55 +00:00
return " fast " , self.dimen
2014-11-30 00:12:00 +00:00
end )
2018-06-02 16:10:55 +00:00
UIManager : tickAfterNext ( function ( )
2017-10-10 21:50:45 +00:00
self.menu : onMenuHold ( self.item )
end )
UIManager : scheduleIn ( 0.5 , function ( )
self.item_frame . invert = false
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
-- 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)
2017-10-10 21:50:45 +00:00
UIManager : setDirty ( self.show_parent , function ( )
return " ui " , self.dimen
end )
end )
end
2014-10-30 07:51:31 +00:00
return true
2014-07-02 14:51:27 +00:00
end
2013-03-14 05:06:42 +00:00
--[[
TouchMenuBar widget
--]]
2013-10-18 20:38:07 +00:00
local TouchMenuBar = InputContainer : new {
2014-03-13 13:52:43 +00:00
width = Screen : getWidth ( ) ,
icons = { } ,
-- touch menu that holds the bar, used for trigger repaint on icons
show_parent = nil ,
menu = nil ,
2013-03-14 05:06:42 +00:00
}
function TouchMenuBar : init ( )
2017-09-13 14:56:20 +00:00
local icon_sep_width = Size.span . vertical_default
2014-05-28 12:05:38 +00:00
local icons_sep_width = icon_sep_width * ( # self.icons + 1 )
2014-06-05 04:58:57 +00:00
-- we assume all icons are of the same width
2017-09-23 20:01:30 +00:00
local icon_width = Screen : scaleBySize ( 40 )
local icon_height = icon_width
2017-09-13 08:12:29 +00:00
-- content_width is the width of all the icon images
2017-09-23 20:01:30 +00:00
local content_width = icon_width * # self.icons + icons_sep_width
2014-06-05 04:58:57 +00:00
local spacing_width = ( self.width - content_width ) / ( # self.icons * 2 )
2017-09-23 20:01:30 +00:00
local icon_padding = math.min ( spacing_width , Screen : scaleBySize ( 16 ) )
self.height = icon_height + Size.span . vertical_large
2014-06-05 04:58:57 +00:00
self.show_parent = self.show_parent or self
self.bar_icon_group = HorizontalGroup : new { }
2014-03-13 13:52:43 +00:00
-- build up image widget for menu icon bar
self.icon_widgets = { }
2014-05-28 12:05:38 +00:00
-- hold icon seperators
self.icon_seps = { }
2014-03-13 13:52:43 +00:00
-- the start_seg for first icon_widget should be 0
-- we asign negative here to offset it in the loop
2014-05-28 12:05:38 +00:00
local start_seg = - icon_sep_width
local end_seg = start_seg
2017-03-26 10:53:55 +00:00
-- self.width is the screen width
2017-09-13 08:12:29 +00:00
-- content_width is the width of all the icon images
-- (2 * icon_padding * #self.icons) is the combined width of icons paddings
local stretch_width = self.width - content_width - ( 2 * icon_padding * # self.icons ) + icon_sep_width
2017-03-26 10:53:55 +00:00
2014-03-13 13:52:43 +00:00
for k , v in ipairs ( self.icons ) do
local ib = IconButton : new {
show_parent = self.show_parent ,
icon_file = v ,
2017-09-23 20:01:30 +00:00
width = icon_width ,
height = icon_height ,
scale_for_dpi = false ,
2014-03-13 13:52:43 +00:00
callback = nil ,
2017-09-27 16:15:11 +00:00
padding_left = icon_padding ,
padding_right = icon_padding ,
2018-03-14 21:16:38 +00:00
menu = self.menu ,
2014-03-13 13:52:43 +00:00
}
2017-09-13 08:12:29 +00:00
table.insert ( self.icon_widgets , ib )
2018-03-14 21:16:38 +00:00
table.insert ( self.menu . layout , ib ) -- for the focusmanager
2014-11-11 02:06:17 +00:00
2014-03-13 13:52:43 +00:00
-- we have to use local variable here for closure callback
2014-05-28 12:05:38 +00:00
local _start_seg = end_seg + icon_sep_width
2014-03-13 13:52:43 +00:00
local _end_seg = _start_seg + self.icon_widgets [ k ] : getSize ( ) . w
2019-12-06 21:55:39 +00:00
end_seg = _end_seg -- for next loop _start_seg
if BD.mirroredUILayout ( ) then
_start_seg , _end_seg = self.width - _end_seg , self.width - _start_seg
end
2014-03-13 13:52:43 +00:00
if k == 1 then
self.bar_sep = LineWidget : new {
dimen = Geom : new {
w = self.width ,
2017-09-13 14:56:20 +00:00
h = Size.line . thick ,
2014-03-13 13:52:43 +00:00
} ,
empty_segments = {
{
s = _start_seg , e = _end_seg
}
} ,
}
end
2014-05-28 12:05:38 +00:00
local icon_sep = LineWidget : new {
style = k == 1 and " solid " or " none " ,
dimen = Geom : new {
2017-02-28 21:46:32 +00:00
w = icon_sep_width ,
2014-05-28 12:05:38 +00:00
h = self.height ,
}
}
2017-03-26 10:53:55 +00:00
-- no separator on the right
if k < # self.icons then
table.insert ( self.icon_seps , icon_sep )
end
2014-05-28 12:05:38 +00:00
-- callback to set visual style
2014-03-13 13:52:43 +00:00
ib.callback = function ( )
self.bar_sep . empty_segments = {
{
s = _start_seg , e = _end_seg
}
}
2014-05-28 12:05:38 +00:00
for i , sep in ipairs ( self.icon_seps ) do
2017-03-26 10:53:55 +00:00
local current_icon , last_icon
if k == # self.icons then
current_icon = false
last_icon = i == k
else
current_icon = i == k - 1 or i == k
last_icon = false
end
-- if the active icon is the last icon then the empty bar segment has
-- to move over to the right by the width of a separator and the stretch width
if last_icon then
2019-12-06 21:55:39 +00:00
local _start_last_seg = icon_sep_width + stretch_width + _start_seg
local _end_last_seg = icon_sep_width + stretch_width + _end_seg
if BD.mirroredUILayout ( ) then
_start_last_seg = _start_seg - icon_sep_width - stretch_width
_end_last_seg = _end_seg - icon_sep_width - stretch_width
end
2017-03-26 10:53:55 +00:00
self.bar_sep . empty_segments = {
{
2019-12-06 21:55:39 +00:00
s = _start_last_seg , e = _end_last_seg
2017-03-26 10:53:55 +00:00
}
}
sep.style = " solid "
-- regular behavior
else
sep.style = current_icon and " solid " or " none "
end
2014-05-28 12:05:38 +00:00
end
2014-03-13 13:52:43 +00:00
self.menu : switchMenuTab ( k )
end
table.insert ( self.bar_icon_group , self.icon_widgets [ k ] )
table.insert ( self.bar_icon_group , icon_sep )
2017-03-26 10:53:55 +00:00
-- if we're at the before-last icon, add an extra span and the final separator
if k == # self.icons - 1 then
table.insert ( self.bar_icon_group , HorizontalSpan : new {
width = stretch_width
} )
-- need to create a new LineWidget otherwise it's just a reference to the same instance
local icon_sep_duplicate = LineWidget : new {
style = " none " ,
dimen = Geom : new {
w = icon_sep_width ,
h = self.height ,
}
}
table.insert ( self.icon_seps , icon_sep_duplicate )
table.insert ( self.bar_icon_group , icon_sep_duplicate )
end
2014-03-13 13:52:43 +00:00
end
self [ 1 ] = FrameContainer : new {
bordersize = 0 ,
padding = 0 ,
VerticalGroup : new {
align = " left " ,
-- bar icons
self.bar_icon_group ,
2014-05-28 12:05:38 +00:00
-- horizontal separate line
2014-03-13 13:52:43 +00:00
self.bar_sep
} ,
}
2014-06-05 04:58:57 +00:00
self.dimen = Geom : new { w = self.width , h = self.height }
2013-03-14 05:06:42 +00:00
end
2014-11-11 02:06:17 +00:00
function TouchMenuBar : switchToTab ( index )
2017-02-25 10:58:39 +00:00
-- a little safety check
-- don't auto-activate a non-existent index
2017-09-13 08:12:29 +00:00
if index > # self.icon_widgets then
2018-04-06 09:32:54 +00:00
index = # self.icon_widgets
2017-02-25 10:58:39 +00:00
end
2017-09-13 08:12:29 +00:00
self.icon_widgets [ index ] . callback ( )
2014-11-11 02:06:17 +00:00
end
2013-03-14 05:06:42 +00:00
--[[
2014-06-05 12:12:47 +00:00
TouchMenu widget for hierarchical menus
2013-03-14 05:06:42 +00:00
--]]
2018-03-14 21:16:38 +00:00
local TouchMenu = FocusManager : new {
2014-03-13 13:52:43 +00:00
tab_item_table = { } ,
2018-06-02 16:10:55 +00:00
-- for returning in multi-level menus
2014-03-13 13:52:43 +00:00
item_table_stack = nil ,
item_table = nil ,
2017-09-13 14:56:20 +00:00
item_height = Size.item . height_large ,
2017-10-14 20:00:58 +00:00
bordersize = Size.border . window ,
2017-09-13 14:56:20 +00:00
padding = Size.padding . default ,
2017-04-29 08:38:09 +00:00
fface = Font : getFace ( " ffont " ) ,
2014-03-13 13:52:43 +00:00
width = nil ,
height = nil ,
page = 1 ,
2020-02-14 07:22:25 +00:00
max_per_page_default = 10 ,
2014-03-13 13:52:43 +00:00
-- for UIManager:setDirty
show_parent = nil ,
cur_tab = - 1 ,
close_callback = nil ,
2018-06-02 16:10:55 +00:00
is_fresh = true ,
2013-03-14 05:06:42 +00:00
}
function TouchMenu : init ( )
2017-10-14 20:00:58 +00:00
-- We won't include self.bordersize in our width calculations, so that
-- borders are pushed off-(screen-)width and so not visible.
-- We'll then be similar to bottom menu ConfigDialog (where this
-- nice effect is caused by some width calculations bug).
2015-09-13 08:06:22 +00:00
if not self.dimen then self.dimen = Geom : new { } end
2014-03-13 13:52:43 +00:00
self.show_parent = self.show_parent or self
if not self.close_callback then
self.close_callback = function ( )
UIManager : close ( self.show_parent )
end
end
2018-03-14 21:16:38 +00:00
self.layout = { }
2014-03-13 13:52:43 +00:00
self.ges_events . TapCloseAllMenus = {
GestureRange : new {
ges = " tap " ,
range = Geom : new {
x = 0 , y = 0 ,
w = Screen : getWidth ( ) ,
h = Screen : getHeight ( ) ,
}
}
}
self.ges_events . Swipe = {
GestureRange : new {
ges = " swipe " ,
range = self.dimen ,
}
}
2018-03-14 21:16:38 +00:00
self.key_events . Back = { { " Back " } , doc = " back to upper menu or close touchmenu " }
2020-06-04 11:26:18 +00:00
if Device : hasFewKeys ( ) then
self.key_events . Back = { { " Left " } , doc = " back to upper menu or close touchmenu " }
end
2018-03-14 21:16:38 +00:00
self.key_events . NextPage = { { Input.group . PgFwd } , doc = " next page " }
self.key_events . PrevPage = { { Input.group . PgBack } , doc = " previous page " }
self.key_events . Press = { { " Press " } , doc = " chose selected item " }
2014-06-10 07:57:10 +00:00
2014-03-13 13:52:43 +00:00
local icons = { }
for _ , v in ipairs ( self.tab_item_table ) do
table.insert ( icons , v.icon )
end
self.bar = TouchMenuBar : new {
2017-10-14 20:00:58 +00:00
width = self.width , -- will impose width and push left and right borders offscreen
2014-03-13 13:52:43 +00:00
icons = icons ,
show_parent = self.show_parent ,
menu = self ,
}
self.item_group = VerticalGroup : new {
2017-10-14 20:00:58 +00:00
align = " center " ,
2014-03-13 13:52:43 +00:00
}
2014-06-05 12:12:47 +00:00
-- group for page info
2019-12-06 21:55:39 +00:00
local chevron_left = " resources/icons/appbar.chevron.left.png "
local chevron_right = " resources/icons/appbar.chevron.right.png "
if BD.mirroredUILayout ( ) then
chevron_left , chevron_right = chevron_right , chevron_left
end
2014-06-05 12:12:47 +00:00
self.page_info_left_chev = Button : new {
2019-12-06 21:55:39 +00:00
icon = chevron_left ,
2014-06-05 12:12:47 +00:00
callback = function ( ) self : onPrevPage ( ) end ,
bordersize = 0 ,
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
show_parent = self.show_parent ,
2014-06-05 12:12:47 +00:00
}
self.page_info_right_chev = Button : new {
2019-12-06 21:55:39 +00:00
icon = chevron_right ,
2014-06-05 12:12:47 +00:00
callback = function ( ) self : onNextPage ( ) end ,
bordersize = 0 ,
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
show_parent = self.show_parent ,
2014-06-05 12:12:47 +00:00
}
self.page_info_left_chev : hide ( )
self.page_info_right_chev : hide ( )
self.page_info_text = TextWidget : new {
2014-03-13 13:52:43 +00:00
text = " " ,
2014-06-05 12:12:47 +00:00
face = self.fface ,
}
self.page_info = HorizontalGroup : new {
self.page_info_left_chev ,
self.page_info_text ,
self.page_info_right_chev
2014-03-13 13:52:43 +00:00
}
2018-06-02 16:10:55 +00:00
-- group for device info
2014-03-13 13:52:43 +00:00
self.time_info = TextWidget : new {
text = " " ,
2014-06-05 12:12:47 +00:00
face = self.fface ,
2014-03-13 13:52:43 +00:00
}
2014-11-11 04:12:34 +00:00
self.device_info = HorizontalGroup : new {
self.time_info ,
2017-10-14 20:00:58 +00:00
-- Add some span to balance up_button image included padding
HorizontalSpan : new { width = Size.span . horizontal_default } ,
2014-11-11 04:12:34 +00:00
}
2019-08-03 16:02:45 +00:00
local footer_width = self.width - self.padding * 2
2014-11-20 10:02:28 +00:00
local up_button = IconButton : new {
icon_file = " resources/icons/appbar.chevron.up.png " ,
show_parent = self.show_parent ,
2019-08-03 16:02:45 +00:00
padding_left = footer_width * 0.33 * 0.1 ,
padding_right = footer_width * 0.33 * 0.1 ,
2014-11-20 10:02:28 +00:00
callback = function ( )
self : backToUpperMenu ( )
end ,
}
2017-09-13 14:56:20 +00:00
local footer_height = up_button : getSize ( ) . h + Size.line . thick
2014-03-13 13:52:43 +00:00
self.footer = HorizontalGroup : new {
LeftContainer : new {
2014-11-20 10:02:28 +00:00
dimen = Geom : new { w = footer_width * 0.33 , h = footer_height } ,
up_button ,
2014-03-13 13:52:43 +00:00
} ,
CenterContainer : new {
2014-11-20 10:02:28 +00:00
dimen = Geom : new { w = footer_width * 0.33 , h = footer_height } ,
2014-06-05 12:12:47 +00:00
self.page_info ,
2014-03-13 13:52:43 +00:00
} ,
RightContainer : new {
2014-11-20 10:02:28 +00:00
dimen = Geom : new { w = footer_width * 0.33 , h = footer_height } ,
2014-09-14 14:05:28 +00:00
self.device_info ,
2014-03-13 13:52:43 +00:00
}
}
2017-10-14 20:00:58 +00:00
self.menu_frame = FrameContainer : new {
2014-03-13 13:52:43 +00:00
padding = self.padding ,
bordersize = self.bordersize ,
2014-10-22 13:34:11 +00:00
background = Blitbuffer.COLOR_WHITE ,
2014-03-13 13:52:43 +00:00
-- menubar and footer will be inserted in
-- item_group in updateItems
self.item_group ,
}
2017-10-14 20:00:58 +00:00
-- This CenterContainer will make the left and right borders drawn
-- off-screen
self [ 1 ] = CenterContainer : new {
dimen = Screen : getSize ( ) ,
ignore = " height " ,
self.menu_frame
}
2014-03-13 13:52:43 +00:00
2017-10-14 20:00:58 +00:00
self.item_width = self.width - self.padding * 2
2016-02-28 21:32:25 +00:00
self.split_line = HorizontalGroup : new {
-- pad with 10 pixel to align with the up arrow in footer
2017-09-13 14:56:20 +00:00
HorizontalSpan : new { width = Size.span . horizontal_default } ,
2016-02-28 21:32:25 +00:00
LineWidget : new {
2019-03-14 19:58:45 +00:00
background = Blitbuffer.COLOR_GRAY ,
2016-02-28 21:32:25 +00:00
dimen = Geom : new {
2017-10-14 20:00:58 +00:00
w = self.item_width - 2 * Size.span . horizontal_default ,
2017-09-13 14:56:20 +00:00
h = Size.line . medium ,
2016-02-28 21:32:25 +00:00
}
2017-10-14 20:00:58 +00:00
} ,
HorizontalSpan : new { width = Size.span . horizontal_default } ,
2016-02-28 21:32:25 +00:00
}
2017-09-13 14:56:20 +00:00
self.footer_top_margin = VerticalSpan : new { width = Size.span . vertical_default }
2016-02-28 21:32:25 +00:00
self.bar : switchToTab ( self.last_index or 1 )
2013-03-14 05:06:42 +00:00
end
2014-12-01 16:21:42 +00:00
function TouchMenu : onCloseWidget ( )
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
-- NOTE: We don't pass a region in order to ensure a full-screen flash to avoid ghosting
UIManager : setDirty ( nil , " flashui " )
2014-12-01 16:21:42 +00:00
end
2016-02-28 21:32:25 +00:00
function TouchMenu : _recalculatePageLayout ( )
local content_height -- content == item_list + footer
2014-03-13 13:52:43 +00:00
2016-02-28 21:32:25 +00:00
local bar_height = self.bar : getSize ( ) . h
local footer_height = self.footer : getSize ( ) . h
if self.height then
content_height = self.height - bar_height
2014-03-13 13:52:43 +00:00
else
2016-02-28 21:32:25 +00:00
content_height = # self.item_table * self.item_height + footer_height
-- split line height
content_height = content_height + ( # self.item_table - 1 )
content_height = content_height + self.footer_top_margin : getSize ( ) . h
2014-03-13 13:52:43 +00:00
end
2016-02-28 21:32:25 +00:00
if content_height + bar_height > Screen : getHeight ( ) then
content_height = Screen : getHeight ( ) - bar_height
2014-03-13 13:52:43 +00:00
end
2016-02-28 21:32:25 +00:00
local item_list_content_height = content_height - footer_height
self.perpage = math.floor ( item_list_content_height / self.item_height )
2020-02-14 07:22:25 +00:00
local max_per_page = self.item_table . max_per_page or self.max_per_page_default
if self.perpage > max_per_page then
self.perpage = max_per_page
2014-03-13 13:52:43 +00:00
end
self.page_num = math.ceil ( # self.item_table / self.perpage )
2013-03-14 05:06:42 +00:00
end
function TouchMenu : updateItems ( )
2014-11-30 12:04:33 +00:00
local old_dimen = self.dimen and self.dimen : copy ( )
2016-02-28 21:32:25 +00:00
self : _recalculatePageLayout ( )
2014-03-13 13:52:43 +00:00
self.item_group : clear ( )
2018-03-14 21:16:38 +00:00
self.layout = { }
2014-03-13 13:52:43 +00:00
table.insert ( self.item_group , self.bar )
2018-06-02 16:10:55 +00:00
table.insert ( self.layout , self.bar . icon_widgets ) -- for the focusmanager
2014-03-13 13:52:43 +00:00
for c = 1 , self.perpage do
-- calculate index in item_table
local i = ( self.page - 1 ) * self.perpage + c
if i <= # self.item_table then
2017-02-28 21:46:32 +00:00
local item = self.item_table [ i ]
2017-03-05 11:57:39 +00:00
local item_tmp = TouchMenuItem : new {
item = item ,
menu = self ,
dimen = Geom : new {
w = self.item_width ,
h = self.item_height ,
} ,
show_parent = self.show_parent ,
}
table.insert ( self.item_group , item_tmp )
2018-03-14 21:16:38 +00:00
if item_tmp : isEnabled ( ) then
2018-06-02 16:10:55 +00:00
table.insert ( self.layout , { [ self.cur_tab ] = item_tmp } ) -- for the focusmanager
2018-03-14 21:16:38 +00:00
end
2017-03-05 11:57:39 +00:00
if item.separator and c ~= self.perpage then
-- insert split line
table.insert ( self.item_group , self.split_line )
2014-03-13 13:52:43 +00:00
end
else
-- item not enough to fill the whole page, break out of loop
2016-02-16 06:34:28 +00:00
break
2014-03-13 13:52:43 +00:00
end -- if i <= self.items
end -- for c=1, self.perpage
2016-02-28 21:32:25 +00:00
table.insert ( self.item_group , self.footer_top_margin )
2014-03-13 13:52:43 +00:00
table.insert ( self.item_group , self.footer )
2019-10-21 12:24:29 +00:00
if self.page_num > 1 then
-- @translators %1 is the current page. %2 is the total number of pages. In some languages a good translation might need to reverse this order, for instance: "Total %2, page %1".
2019-12-06 21:55:39 +00:00
self.page_info_text : setText ( T ( _ ( " Page %1 of %2 " ) , self.page , self.page_num ) )
2019-10-21 12:24:29 +00:00
else
self.page_info_text : setText ( " " )
end
2014-06-05 12:12:47 +00:00
self.page_info_left_chev : showHide ( self.page_num > 1 )
self.page_info_right_chev : showHide ( self.page_num > 1 )
self.page_info_left_chev : enableDisable ( self.page > 1 )
self.page_info_right_chev : enableDisable ( self.page < self.page_num )
2019-10-21 12:24:29 +00:00
local time_info_txt
if G_reader_settings : nilOrTrue ( " twelve_hour_clock " ) then
2020-02-26 07:34:42 +00:00
if os.date ( " %p " ) == " AM " then
-- @translators This is the time in the morning in the 12-hour clock (%I is the hour, %M the minute).
time_info_txt = os.date ( _ ( " %I:%M AM " ) )
else
-- @translators This is the time in the afternoon in the 12-hour clock (%I is the hour, %M the minute).
time_info_txt = os.date ( _ ( " %I:%M PM " ) )
end
2019-10-21 12:24:29 +00:00
else
2020-02-26 07:34:42 +00:00
-- @translators This is the time in the 24-hour clock (%H is the hour, %M the minute).
time_info_txt = os.date ( _ ( " %H:%M " ) )
2019-10-21 12:24:29 +00:00
end
2019-10-27 04:22:17 +00:00
local powerd = Device : getPowerDevice ( )
local batt_lvl = powerd : getCapacity ( )
2019-12-06 21:55:39 +00:00
local batt_symbol
2019-10-27 04:22:17 +00:00
if powerd : isCharging ( ) then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
else
if batt_lvl >= 100 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 90 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 80 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 70 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 60 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 50 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 40 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 30 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 20 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
elseif batt_lvl >= 10 then
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
else
2019-12-06 21:55:39 +00:00
batt_symbol = " "
2019-10-27 04:22:17 +00:00
end
2016-02-28 21:32:25 +00:00
end
2020-04-11 15:45:37 +00:00
if not Device : isDesktop ( ) then
time_info_txt = BD.wrap ( time_info_txt ) .. " " .. BD.wrap ( " ⌁ " ) .. BD.wrap ( batt_symbol ) .. BD.wrap ( batt_lvl .. " % " )
end
2016-02-28 21:32:25 +00:00
self.time_info : setText ( time_info_txt )
-- recalculate dimen based on new layout
self.dimen . w = self.width
self.dimen . h = self.item_group : getSize ( ) . h + self.bordersize * 2 + self.padding * 2
2018-06-02 16:10:55 +00:00
self.selected = { x = self.cur_tab , y = 1 } -- reset the position of the focusmanager
2014-11-30 12:04:33 +00:00
2018-06-02 16:10:55 +00:00
-- 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...
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
-- NOTE: Also avoid repainting what's underneath us on initial popup.
2019-10-15 19:57:51 +00:00
-- NOTE: And we also only need to repaint what's behind us when switching to a smaller menu...
local keep_bg = old_dimen and self.dimen . h >= old_dimen.h
UIManager : setDirty ( ( self.is_fresh or keep_bg ) and self.show_parent or " all " , function ( )
2014-11-30 12:04:33 +00:00
local refresh_dimen =
old_dimen and old_dimen : combine ( self.dimen )
or self.dimen
2018-06-02 16:10:55 +00:00
local refresh_type = " ui "
if self.is_fresh then
refresh_type = " flashui "
-- Drop the region, too, to make it full-screen? May help when starting from a "small" menu.
--refresh_dimen = nil
self.is_fresh = false
end
return refresh_type , refresh_dimen
2014-11-30 12:04:33 +00:00
end )
2013-03-14 05:06:42 +00:00
end
2014-09-14 14:05:28 +00:00
2013-03-14 05:06:42 +00:00
function TouchMenu : switchMenuTab ( tab_num )
2014-11-11 02:06:17 +00:00
if self.tab_item_table [ tab_num ] . remember ~= false then
self.last_index = tab_num
end
2014-11-05 04:15:07 +00:00
if self.touch_menu_callback then
self.touch_menu_callback ( )
end
2014-03-13 13:52:43 +00:00
if self.tab_item_table [ tab_num ] . callback then
self.tab_item_table [ tab_num ] . callback ( )
end
if self.cur_tab ~= tab_num then
-- it's like getting a new menu everytime we switch tab!
self.page = 1
-- clear item table stack
self.item_table_stack = { }
self.cur_tab = tab_num
self.item_table = self.tab_item_table [ tab_num ]
self : updateItems ( )
end
2013-03-15 09:18:34 +00:00
end
function TouchMenu : backToUpperMenu ( )
2014-03-13 13:52:43 +00:00
if # self.item_table_stack ~= 0 then
self.item_table = table.remove ( self.item_table_stack )
self.page = 1
self : updateItems ( )
2014-11-30 12:04:33 +00:00
else
self : closeMenu ( )
2014-03-13 13:52:43 +00:00
end
2013-03-14 05:06:42 +00:00
end
function TouchMenu : closeMenu ( )
2014-03-13 13:52:43 +00:00
self.close_callback ( )
2013-03-14 05:06:42 +00:00
end
2013-03-16 00:30:42 +00:00
function TouchMenu : onNextPage ( )
2014-03-13 13:52:43 +00:00
if self.page < self.page_num then
self.page = self.page + 1
2015-08-01 09:44:40 +00:00
elseif self.page == self.page_num then
self.page = 1
2014-03-13 13:52:43 +00:00
end
2015-08-01 09:44:40 +00:00
self : updateItems ( )
2014-03-13 13:52:43 +00:00
return true
2013-03-16 00:30:42 +00:00
end
function TouchMenu : onPrevPage ( )
2014-03-13 13:52:43 +00:00
if self.page > 1 then
self.page = self.page - 1
2015-08-01 09:44:40 +00:00
elseif self.page == 1 then
self.page = self.page_num
2014-03-13 13:52:43 +00:00
end
2015-08-01 09:44:40 +00:00
self : updateItems ( )
2014-03-13 13:52:43 +00:00
return true
2013-03-16 00:30:42 +00:00
end
function TouchMenu : onSwipe ( arg , ges_ev )
2019-12-06 21:55:39 +00:00
local direction = BD.flipDirectionIfMirroredUILayout ( ges_ev.direction )
if direction == " west " then
2014-03-13 13:52:43 +00:00
self : onNextPage ( )
2019-12-06 21:55:39 +00:00
elseif direction == " east " then
2014-03-13 13:52:43 +00:00
self : onPrevPage ( )
2019-12-06 21:55:39 +00:00
elseif direction == " north " then
2017-04-15 12:45:56 +00:00
self : closeMenu ( )
2014-03-13 13:52:43 +00:00
end
2013-03-16 00:30:42 +00:00
end
2013-03-14 05:06:42 +00:00
function TouchMenu : onMenuSelect ( item )
2014-11-05 04:15:07 +00:00
if self.touch_menu_callback then
self.touch_menu_callback ( )
end
2017-03-28 22:47:18 +00:00
if item.tap_input or type ( item.tap_input_func ) == " function " then
2018-09-04 21:55:58 +00:00
if not item.keep_menu_open then
self : closeMenu ( )
end
2017-03-28 22:47:18 +00:00
if item.tap_input then
self : onInput ( item.tap_input )
else
self : onInput ( item.tap_input_func ( ) )
end
2014-08-05 02:22:57 +00:00
else
local sub_item_table = item.sub_item_table
if item.sub_item_table_func then
sub_item_table = item.sub_item_table_func ( )
end
if sub_item_table == nil then
2015-03-12 06:19:10 +00:00
-- keep menu opened if this item is a check option
local callback , refresh = item.callback , item.checked or item.checked_func
2014-08-05 02:22:57 +00:00
if item.callback_func then
callback = item.callback_func ( )
end
if callback then
2014-11-14 14:07:14 +00:00
-- put stuff in scheduler so we can see
2014-08-05 02:22:57 +00:00
-- the effect of inverted menu item
2018-06-02 16:10:55 +00:00
UIManager : tickAfterNext ( function ( )
2018-09-04 21:55:58 +00:00
-- Provide callback with us, so it can call our
-- closemenu() or updateItems() when it sees fit
-- (if not providing checked or checked_fund, caller
-- must set keep_menu_open=true if that is wished)
2016-06-26 00:53:08 +00:00
callback ( self )
2015-03-12 06:19:10 +00:00
if refresh then
self : updateItems ( )
2018-09-04 21:55:58 +00:00
elseif not item.keep_menu_open then
2015-03-12 06:19:10 +00:00
self : closeMenu ( )
end
2014-08-05 02:22:57 +00:00
end )
end
else
table.insert ( self.item_table_stack , self.item_table )
self.item_table = sub_item_table
2016-08-01 01:22:35 +00:00
self.page = 1
2014-08-05 02:22:57 +00:00
self : updateItems ( )
end
2014-05-01 10:37:12 +00:00
end
2014-08-05 02:22:57 +00:00
return true
end
function TouchMenu : onMenuHold ( item )
2014-11-05 04:15:07 +00:00
if self.touch_menu_callback then
self.touch_menu_callback ( )
end
2017-03-28 22:47:18 +00:00
if item.hold_input or type ( item.hold_input_func ) == " function " then
2018-09-04 21:55:58 +00:00
if item.hold_keep_menu_open == false then
self : closeMenu ( )
end
2017-03-28 22:47:18 +00:00
if item.hold_input then
self : onInput ( item.hold_input )
else
self : onInput ( item.hold_input_func ( ) )
end
2018-05-25 18:56:37 +00:00
elseif item.hold_callback or type ( item.hold_callback_func ) == " function " then
2014-08-05 02:22:57 +00:00
local callback = item.hold_callback
if item.hold_callback_func then
callback = item.hold_callback_func ( )
2014-05-01 10:37:12 +00:00
end
if callback then
2018-06-02 16:10:55 +00:00
UIManager : tickAfterNext ( function ( )
2018-09-04 21:55:58 +00:00
-- With hold, the default is to keep menu open, as we're
-- most often showing a ConfirmBox that can be cancelled
-- (provide hold_keep_menu_open=false to override)
if item.hold_keep_menu_open == false then
2018-05-11 15:48:26 +00:00
self : closeMenu ( )
end
2018-09-04 21:55:58 +00:00
-- Provide callback with us, so it can call our
-- closemenu() or updateItems() when it sees fit
callback ( self )
2014-03-13 13:52:43 +00:00
end )
end
2018-05-25 18:56:37 +00:00
elseif item.help_text or type ( item.help_text_func ) == " function " then
local help_text = item.help_text
if item.help_text_func then
help_text = item.help_text_func ( )
end
if help_text then
UIManager : show ( InfoMessage : new { text = help_text , } )
end
2014-03-13 13:52:43 +00:00
end
return true
2013-03-14 05:06:42 +00:00
end
function TouchMenu : onTapCloseAllMenus ( arg , ges_ev )
2014-03-13 13:52:43 +00:00
if ges_ev.pos : notIntersectWith ( self.dimen ) then
self : closeMenu ( )
end
2013-03-14 05:06:42 +00:00
end
2014-06-10 07:57:10 +00:00
function TouchMenu : onClose ( )
self : closeMenu ( )
end
2018-03-14 21:16:38 +00:00
function TouchMenu : onBack ( )
self : backToUpperMenu ( )
end
function TouchMenu : onPress ( )
self : getFocusItem ( ) : handleEvent ( Event : new ( " TapSelect " ) )
end
2013-10-18 20:38:07 +00:00
return TouchMenu