mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Add MovableContainer: allow moving some widgets (#3636)
This commit is contained in:
@@ -42,7 +42,7 @@ function ReaderSearch:onShowSearchDialog(text)
|
||||
end
|
||||
end
|
||||
self.search_dialog = ButtonDialog:new{
|
||||
alpha = 0.5,
|
||||
-- alpha = 0.7,
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
|
||||
@@ -12,6 +12,8 @@ local HorizontalGroup = require("ui/widget/horizontalgroup")
|
||||
local HorizontalSpan = require("ui/widget/horizontalspan")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local LineWidget = require("ui/widget/linewidget")
|
||||
local Math = require("optmath")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local OverlapGroup = require("ui/widget/overlapgroup")
|
||||
local ProgressWidget = require("ui/widget/progresswidget")
|
||||
local Size = require("ui/size")
|
||||
@@ -342,9 +344,8 @@ function SkimToWidget:init()
|
||||
w = self.screen_width,
|
||||
h = self.screen_height,
|
||||
},
|
||||
FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = Size.padding.default,
|
||||
MovableContainer:new{
|
||||
-- alpha = 0.8,
|
||||
self.skimto_frame,
|
||||
}
|
||||
}
|
||||
@@ -403,17 +404,19 @@ function SkimToWidget:onAnyKeyPressed()
|
||||
end
|
||||
|
||||
function SkimToWidget:onTapProgress(arg, ges_ev)
|
||||
if ges_ev.pos:intersectWith(self.skimto_progress.dimen) then
|
||||
local width = self.screen_width * 0.89
|
||||
local pos = ges_ev.pos.x - width * 0.05 - 3
|
||||
if ges_ev.pos:intersectWith(self.progress_bar.dimen) then
|
||||
local width = self.progress_bar.dimen.w
|
||||
local pos = ges_ev.pos.x - self.progress_bar.dimen.x
|
||||
local perc = pos / width
|
||||
local page = math.floor(perc * self.page_count)
|
||||
local page = Math.round(perc * self.page_count)
|
||||
self.ui:handleEvent(Event:new("GotoPage", page ))
|
||||
self.curr_page = page
|
||||
self:update()
|
||||
else
|
||||
elseif not ges_ev.pos:intersectWith(self.skimto_frame.dimen) then
|
||||
-- close if tap outside
|
||||
self:onClose()
|
||||
end
|
||||
-- otherwise, do nothing (it's easy missing taping a button)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
@@ -190,9 +190,11 @@ function Trapper:info(text, fast_refresh)
|
||||
|
||||
-- If fast_refresh option, avoid UIManager refresh overhead
|
||||
if fast_refresh and self.current_widget and self.current_widget.is_infomessage then
|
||||
local orig_moved_offset = self.current_widget.movable:getMovedOffset()
|
||||
self.current_widget:free()
|
||||
self.current_widget.text = text
|
||||
self.current_widget:init()
|
||||
self.current_widget.movable:setMovedOffset(orig_moved_offset)
|
||||
local Screen = require("device").screen
|
||||
self.current_widget:paintTo(Screen.bb, 0,0)
|
||||
local d = self.current_widget[1][1].dimen
|
||||
|
||||
@@ -6,6 +6,7 @@ local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local Geom = require("ui/geometry")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local Size = require("ui/size")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local _ = require("gettext")
|
||||
@@ -14,6 +15,7 @@ local Screen = require("device").screen
|
||||
local ButtonDialog = InputContainer:new{
|
||||
buttons = nil,
|
||||
tap_close_callback = nil,
|
||||
alpha = nil, -- passed to MovableContainer
|
||||
}
|
||||
|
||||
function ButtonDialog:init()
|
||||
@@ -36,20 +38,23 @@ function ButtonDialog:init()
|
||||
end
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
ButtonTable:new{
|
||||
width = Screen:getWidth()*0.9,
|
||||
buttons = self.buttons,
|
||||
show_parent = self,
|
||||
},
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
bordersize = Size.border.window,
|
||||
radius = Size.radius.window,
|
||||
padding = Size.padding.button,
|
||||
-- No padding at top or bottom to make all buttons
|
||||
-- look the same size
|
||||
padding_top = 0,
|
||||
padding_bottom = 0,
|
||||
MovableContainer:new{
|
||||
alpha = self.alpha,
|
||||
FrameContainer:new{
|
||||
ButtonTable:new{
|
||||
width = Screen:getWidth()*0.9,
|
||||
buttons = self.buttons,
|
||||
show_parent = self,
|
||||
},
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
bordersize = Size.border.window,
|
||||
radius = Size.radius.window,
|
||||
padding = Size.padding.button,
|
||||
-- No padding at top or bottom to make all buttons
|
||||
-- look the same size
|
||||
padding_top = 0,
|
||||
padding_bottom = 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
@@ -7,6 +7,7 @@ local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local Geom = require("ui/geometry")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local Size = require("ui/size")
|
||||
local TextBoxWidget = require("ui/widget/textboxwidget")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
@@ -45,33 +46,35 @@ function ButtonDialogTitle:init()
|
||||
end
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
VerticalGroup:new{
|
||||
align = "center",
|
||||
FrameContainer:new{
|
||||
padding = self.title_padding,
|
||||
margin = self.title_margin,
|
||||
bordersize = 0,
|
||||
TextBoxWidget:new{
|
||||
text = self.title,
|
||||
width = Screen:getWidth() * 0.8 ,
|
||||
face = self.title_face,
|
||||
alignment = self.title_align or "left",
|
||||
MovableContainer:new{
|
||||
FrameContainer:new{
|
||||
VerticalGroup:new{
|
||||
align = "center",
|
||||
FrameContainer:new{
|
||||
padding = self.title_padding,
|
||||
margin = self.title_margin,
|
||||
bordersize = 0,
|
||||
TextBoxWidget:new{
|
||||
text = self.title,
|
||||
width = Screen:getWidth() * 0.8 ,
|
||||
face = self.title_face,
|
||||
alignment = self.title_align or "left",
|
||||
},
|
||||
},
|
||||
VerticalSpan:new{ width = Size.span.vertical_default },
|
||||
ButtonTable:new{
|
||||
width = Screen:getWidth() * 0.9,
|
||||
buttons = self.buttons,
|
||||
zero_sep = true,
|
||||
show_parent = self,
|
||||
},
|
||||
},
|
||||
VerticalSpan:new{ width = Size.span.vertical_default },
|
||||
ButtonTable:new{
|
||||
width = Screen:getWidth() * 0.9,
|
||||
buttons = self.buttons,
|
||||
zero_sep = true,
|
||||
show_parent = self,
|
||||
},
|
||||
},
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
bordersize = Size.border.window,
|
||||
radius = Size.radius.window,
|
||||
padding = Size.padding.button,
|
||||
padding_bottom = 0, -- no padding below buttontable
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
bordersize = Size.border.window,
|
||||
radius = Size.radius.window,
|
||||
padding = Size.padding.button,
|
||||
padding_bottom = 0, -- no padding below buttontable
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
@@ -29,6 +29,7 @@ local HorizontalGroup = require("ui/widget/horizontalgroup")
|
||||
local HorizontalSpan = require("ui/widget/horizontalspan")
|
||||
local ImageWidget = require("ui/widget/imagewidget")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local Size = require("ui/size")
|
||||
local TextBoxWidget = require("ui/widget/textboxwidget")
|
||||
local UIManager = require("ui/uimanager")
|
||||
@@ -127,17 +128,19 @@ function ConfirmBox:init()
|
||||
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
margin = self.margin,
|
||||
padding = self.padding,
|
||||
padding_bottom = 0, -- no padding below buttontable
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
content,
|
||||
-- Add same vertical space after than before content
|
||||
VerticalSpan:new{ width = self.margin + self.padding },
|
||||
button_table,
|
||||
MovableContainer:new{
|
||||
FrameContainer:new{
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
margin = self.margin,
|
||||
padding = self.padding,
|
||||
padding_bottom = 0, -- no padding below buttontable
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
content,
|
||||
-- Add same vertical space after than before content
|
||||
VerticalSpan:new{ width = self.margin + self.padding },
|
||||
button_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
295
frontend/ui/widget/container/movablecontainer.lua
Normal file
295
frontend/ui/widget/container/movablecontainer.lua
Normal file
@@ -0,0 +1,295 @@
|
||||
--[[--
|
||||
A MovableContainer can have its content moved on screen
|
||||
with Swipe/Hold/Pan.
|
||||
Can optionally apply alpha transparency to its content.
|
||||
|
||||
With Swipe: the widget will be constrained to screen borders.
|
||||
With Hold and pan, the widget can overflow the borders.
|
||||
|
||||
Hold with no move will reset the widget to its original position.
|
||||
If the widget has not been moved or is already at its original
|
||||
position, Hold will toggle between full opacity and 0.7 transparency.
|
||||
|
||||
This container's content is expected to not change its width and height.
|
||||
]]
|
||||
|
||||
local BlitBuffer = require("ffi/blitbuffer")
|
||||
local Device = require("device")
|
||||
local Geom = require("ui/geometry")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Math = require("optmath")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Screen = Device.screen
|
||||
local logger = require("logger")
|
||||
|
||||
local MovableContainer = InputContainer:new{
|
||||
-- Alpha value for subwidget transparency
|
||||
-- 0 = fully invisible, 1 = fully opaque (0.6 / 0.7 / 0.8 are some interesting values)
|
||||
alpha = nil,
|
||||
|
||||
-- Move threshold (if move distance less than that, considered as a Hold
|
||||
-- with no movement, used for reseting move to original position)
|
||||
move_threshold = Screen:scaleBySize(5),
|
||||
|
||||
-- Events to ignore (ie: ignore_events={"hold", "hold_release"})
|
||||
ignore_events = nil,
|
||||
|
||||
-- Current move offset (use getMovedOffset()/setMovedOffset() to access them)
|
||||
_moved_offset_x = 0,
|
||||
_moved_offset_y = 0,
|
||||
-- Internal state between events
|
||||
_touch_pre_pan_was_inside = false,
|
||||
_moving = true,
|
||||
_move_relative_x = nil,
|
||||
_move_relative_y = nil,
|
||||
-- Original painting position from outer widget
|
||||
_orig_x = nil,
|
||||
_orig_y = nil,
|
||||
}
|
||||
|
||||
function MovableContainer:init()
|
||||
if Device:isTouchDevice() then
|
||||
local range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
-- Unflatten self.ignore_events to table keys for cleaner code below
|
||||
local ignore = {}
|
||||
if self.ignore_events then
|
||||
for _, evname in pairs(self.ignore_events) do
|
||||
ignore[evname] = true
|
||||
end
|
||||
end
|
||||
-- The following gestures need to be supported, depending on the
|
||||
-- ways a user can move things:
|
||||
-- Hold happens if he holds at start
|
||||
-- Pan happens if he doesn't hold at start, but holds at end
|
||||
-- Swipe happens if he doesn't hold at any moment
|
||||
-- Note that Swipe is tied to 0/45/90/135 degree... directions,
|
||||
-- which is somehow nice and gives a kind of magnetic move that
|
||||
-- stick the widget to some invisible rulers.
|
||||
-- (Touch is needed for accurate pan)
|
||||
self.ges_events = {}
|
||||
self.ges_events.MovableTouch = not ignore.touch and { GestureRange:new{ ges = "touch", range = range } } or nil
|
||||
self.ges_events.MovableSwipe = not ignore.swipe and { GestureRange:new{ ges = "swipe", range = range } } or nil
|
||||
self.ges_events.MovableHold = not ignore.hold and { GestureRange:new{ ges = "hold", range = range } } or nil
|
||||
self.ges_events.MovableHoldPan = not ignore.hold_pan and { GestureRange:new{ ges = "hold_pan", range = range } } or nil
|
||||
self.ges_events.MovableHoldRelease = not ignore.hold_release and { GestureRange:new{ ges = "hold_release", range = range } } or nil
|
||||
self.ges_events.MovablePan = not ignore.pan and { GestureRange:new{ ges = "pan", range = range } } or nil
|
||||
self.ges_events.MovablePanRelease = not ignore.pan_release and { GestureRange:new{ ges = "pan_release", range = range } } or nil
|
||||
end
|
||||
end
|
||||
|
||||
function MovableContainer:getMovedOffset()
|
||||
return Geom:new{
|
||||
x = self._moved_offset_x,
|
||||
y = self._moved_offset_y,
|
||||
}
|
||||
end
|
||||
|
||||
function MovableContainer:setMovedOffset(offset_point)
|
||||
if offset_point and offset_point.x and offset_point.y then
|
||||
self._moved_offset_x = offset_point.x
|
||||
self._moved_offset_y = offset_point.y
|
||||
end
|
||||
end
|
||||
|
||||
function MovableContainer:paintTo(bb, x, y)
|
||||
if self[1] == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local content_size = self[1]:getSize()
|
||||
if not self.dimen then
|
||||
self.dimen = Geom:new{w = content_size.w, h = content_size.h}
|
||||
end
|
||||
|
||||
self._orig_x = x
|
||||
self._orig_y = y
|
||||
-- We just need to shift painting by our _moved_offset_x/y
|
||||
self.dimen.x = x + self._moved_offset_x
|
||||
self.dimen.y = y + self._moved_offset_y
|
||||
|
||||
if self.alpha then
|
||||
-- Create private blitbuffer for our child widget to paint to
|
||||
local private_bb = BlitBuffer.new(bb:getWidth(), bb:getHeight(), bb:getType())
|
||||
private_bb:fill(BlitBuffer.COLOR_WHITE) -- for round corners' outside to not stay black
|
||||
self[1]:paintTo(private_bb, self.dimen.x, self.dimen.y)
|
||||
-- And blend our private blitbuffer over the original bb
|
||||
bb:addblitFrom(private_bb, self.dimen.x, self.dimen.y, self.dimen.x, self.dimen.y,
|
||||
self.dimen.w, self.dimen.h, self.alpha)
|
||||
private_bb:free()
|
||||
else
|
||||
-- No alpha, just paint
|
||||
self[1]:paintTo(bb, self.dimen.x, self.dimen.y)
|
||||
end
|
||||
end
|
||||
|
||||
function MovableContainer:_moveBy(dx, dy, restrict_to_screen)
|
||||
logger.dbg("MovableContainer:_moveBy:", dx, dy)
|
||||
if dx and dy then
|
||||
self._moved_offset_x = self._moved_offset_x + Math.round(dx)
|
||||
self._moved_offset_y = self._moved_offset_y + Math.round(dy)
|
||||
if restrict_to_screen then
|
||||
local screen_w, screen_h = Screen:getWidth(), Screen:getHeight()
|
||||
if self._orig_x + self._moved_offset_x < 0 then
|
||||
self._moved_offset_x = - self._orig_x
|
||||
end
|
||||
if self._orig_y + self._moved_offset_y < 0 then
|
||||
self._moved_offset_y = - self._orig_y
|
||||
end
|
||||
if self._orig_x + self._moved_offset_x + self.dimen.w > screen_w then
|
||||
self._moved_offset_x = screen_w - self._orig_x - self.dimen.w
|
||||
end
|
||||
if self._orig_y + self._moved_offset_y + self.dimen.h > screen_h then
|
||||
self._moved_offset_y = screen_h - self._orig_y - self.dimen.h
|
||||
end
|
||||
end
|
||||
-- if not restrict_to_screen, we don't need to check anything:
|
||||
-- we trust gestures' position and distances: if we started with our
|
||||
-- finger on widget, and moved our finger to screen border, a part
|
||||
-- of the widget should always be on the screen.
|
||||
else
|
||||
-- Not-moving Hold can be used to revert to original position
|
||||
if self._moved_offset_x == 0 and self._moved_offset_y == 0 then
|
||||
-- If we hold while already in initial position, take that
|
||||
-- as a wish to toggle between alpha or no-alpha
|
||||
if self.alpha then
|
||||
self.orig_alpha = self.alpha
|
||||
self.alpha = nil
|
||||
else
|
||||
self.alpha = self.orig_alpha or 0.7
|
||||
-- For testing: to visually see how different alpha
|
||||
-- values look: loop thru decreasing alpha values
|
||||
-- self.alpha = self.orig_alpha or 1.0
|
||||
-- if self.alpha > 0.55 then -- below 0.5 are too transparent
|
||||
-- self.alpha = self.alpha - 0.1
|
||||
-- else
|
||||
-- self.alpha = 0.9
|
||||
-- end
|
||||
end
|
||||
end
|
||||
self._moved_offset_x = 0
|
||||
self._moved_offset_y = 0
|
||||
end
|
||||
-- We need to have all widgets in the area between orig and move position
|
||||
-- redraw themselves
|
||||
local orig_dimen = self.dimen:copy() -- dimen before move/paintTo
|
||||
UIManager:setDirty("all", function()
|
||||
local update_region = orig_dimen:combine(self.dimen)
|
||||
logger.dbg("MovableContainer refresh region", update_region)
|
||||
return "ui", update_region
|
||||
end)
|
||||
end
|
||||
|
||||
function MovableContainer:onMovableSwipe(_, ges)
|
||||
logger.dbg("MovableContainer:onMovableSwipe", ges)
|
||||
if not ges.pos:intersectWith(self.dimen) then
|
||||
-- with swipe, ges.pos is swipe's start position, which should
|
||||
-- be on us to consider it
|
||||
return false
|
||||
end
|
||||
self._moving = false -- could have been set by "pan" event received before "swipe"
|
||||
local direction = ges.direction
|
||||
local distance = ges.distance
|
||||
local sq_distance = math.floor(math.sqrt(distance*distance/2))
|
||||
-- Use restrict_to_screen for all move with Swipe for easy push to screen
|
||||
-- borders (user can Hold and pan if he wants them outside)
|
||||
if direction == "north" then self:_moveBy(0, -distance, true)
|
||||
elseif direction == "south" then self:_moveBy(0, distance, true)
|
||||
elseif direction == "east" then self:_moveBy(distance, 0, true)
|
||||
elseif direction == "west" then self:_moveBy(-distance, 0, true)
|
||||
elseif direction == "northeast" then self:_moveBy(sq_distance, -sq_distance, true)
|
||||
elseif direction == "northwest" then self:_moveBy(-sq_distance, -sq_distance, true)
|
||||
elseif direction == "southeast" then self:_moveBy(sq_distance, sq_distance, true)
|
||||
elseif direction == "southwest" then self:_moveBy(-sq_distance, sq_distance, true)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function MovableContainer:onMovableTouch(_, ges)
|
||||
-- First "pan" event may already be outsise us, we need to
|
||||
-- remember any "touch" event on us prior to "pan"
|
||||
logger.dbg("MovableContainer:onMovableTouch", ges)
|
||||
if ges.pos:intersectWith(self.dimen) then
|
||||
self._touch_pre_pan_was_inside = true
|
||||
self._move_relative_x = ges.pos.x
|
||||
self._move_relative_y = ges.pos.y
|
||||
else
|
||||
self._touch_pre_pan_was_inside = false
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function MovableContainer:onMovableHold(_, ges)
|
||||
logger.dbg("MovableContainer:onMovableHold", ges)
|
||||
if ges.pos:intersectWith(self.dimen) then
|
||||
self._moving = true -- start of pan
|
||||
self._move_relative_x = ges.pos.x
|
||||
self._move_relative_y = ges.pos.y
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function MovableContainer:onMovableHoldPan(_, ges)
|
||||
logger.dbg("MovableContainer:onMovableHoldPan", ges)
|
||||
-- we may sometimes not see the "hold" event
|
||||
if ges.pos:intersectWith(self.dimen) or self._moving or self._touch_pre_pan_was_inside then
|
||||
self._touch_pre_pan_was_inside = false -- reset it
|
||||
self._moving = true
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function MovableContainer:onMovableHoldRelease(_, ges)
|
||||
logger.dbg("MovableContainer:onMovableHoldRelease", ges)
|
||||
if self._moving or self._touch_pre_pan_was_inside then
|
||||
self._moving = false
|
||||
if not self._move_relative_x or not self._move_relative_y then
|
||||
-- no previous event gave us accurate move info, ignore it
|
||||
return false
|
||||
end
|
||||
self._move_relative_x = ges.pos.x - self._move_relative_x
|
||||
self._move_relative_y = ges.pos.y - self._move_relative_y
|
||||
if math.abs(self._move_relative_x) < self.move_threshold and math.abs(self._move_relative_y) < self.move_threshold then
|
||||
-- Hold with no move (or less than self.move_threshold): use this to reposition to original position
|
||||
self:_moveBy()
|
||||
else
|
||||
self:_moveBy(self._move_relative_x, self._move_relative_y)
|
||||
self._move_relative_x = nil
|
||||
self._move_relative_y = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function MovableContainer:onMovablePan(_, ges)
|
||||
logger.dbg("MovableContainer:onMovablePan", ges)
|
||||
if ges.pos:intersectWith(self.dimen) or self._moving or self._touch_pre_pan_was_inside then
|
||||
self._touch_pre_pan_was_inside = false -- reset it
|
||||
self._moving = true
|
||||
self._move_relative_x = ges.relative.x
|
||||
self._move_relative_y = ges.relative.y
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function MovableContainer:onMovablePanRelease(_, ges)
|
||||
logger.dbg("MovableContainer:onMovablePanRelease", ges)
|
||||
if self._moving then
|
||||
self:_moveBy(self._move_relative_x, self._move_relative_y)
|
||||
self._moving = false
|
||||
self._move_relative_x = nil
|
||||
self._move_relative_y = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
return MovableContainer
|
||||
@@ -13,6 +13,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local LeftContainer = require("ui/widget/container/leftcontainer")
|
||||
local LineWidget = require("ui/widget/linewidget")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local OverlapGroup = require("ui/widget/overlapgroup")
|
||||
local ScrollHtmlWidget = require("ui/widget/scrollhtmlwidget")
|
||||
local ScrollTextWidget = require("ui/widget/scrolltextwidget")
|
||||
@@ -187,6 +188,7 @@ end
|
||||
|
||||
function DictQuickLookup:update()
|
||||
local orig_dimen = self.dict_frame and self.dict_frame.dimen or Geom:new{}
|
||||
local orig_moved_offset = self.movable and self.movable:getMovedOffset()
|
||||
-- Free our previous widget and subwidgets' resources (especially
|
||||
-- definitions' TextBoxWidget bb, HtmlBoxWidget bb and MuPDF instance,
|
||||
-- and scheduled image_update_action)
|
||||
@@ -302,7 +304,7 @@ function DictQuickLookup:update()
|
||||
end
|
||||
|
||||
-- word definition
|
||||
local definition = FrameContainer:new{
|
||||
self.definition_widget = FrameContainer:new{
|
||||
padding = self.definition_padding,
|
||||
margin = self.definition_margin,
|
||||
bordersize = 0,
|
||||
@@ -456,7 +458,7 @@ function DictQuickLookup:update()
|
||||
end
|
||||
|
||||
local button_table = ButtonTable:new{
|
||||
width = math.max(self.width, definition:getSize().w),
|
||||
width = math.max(self.width, self.definition_widget:getSize().w),
|
||||
button_font_face = "cfont",
|
||||
button_font_size = 20,
|
||||
buttons = buttons,
|
||||
@@ -503,9 +505,9 @@ function DictQuickLookup:update()
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = definition:getSize().h,
|
||||
h = self.definition_widget:getSize().h,
|
||||
},
|
||||
definition,
|
||||
self.definition_widget,
|
||||
},
|
||||
-- buttons
|
||||
CenterContainer:new{
|
||||
@@ -517,14 +519,19 @@ function DictQuickLookup:update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.movable = MovableContainer:new{
|
||||
-- We'll handle these events ourselves, and call appropriate
|
||||
-- MovableContainer's methods when we didn't process the event
|
||||
ignore_events = {"swipe", "hold", "hold_release"},
|
||||
self.dict_frame,
|
||||
}
|
||||
self.movable:setMovedOffset(orig_moved_offset)
|
||||
|
||||
self[1] = WidgetContainer:new{
|
||||
align = self.align,
|
||||
dimen = self.region,
|
||||
FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = Size.padding.default,
|
||||
self.dict_frame,
|
||||
}
|
||||
self.movable,
|
||||
}
|
||||
UIManager:setDirty("all", function()
|
||||
local update_region = self.dict_frame.dimen:combine(orig_dimen)
|
||||
@@ -734,19 +741,37 @@ function DictQuickLookup:onHoldClose(no_clear)
|
||||
end
|
||||
|
||||
function DictQuickLookup:onSwipe(arg, ges)
|
||||
if ges.direction == "west" then
|
||||
self:changeToNextDict()
|
||||
elseif ges.direction == "east" then
|
||||
self:changeToPrevDict()
|
||||
else
|
||||
if self.refresh_callback then self.refresh_callback() end
|
||||
-- trigger full refresh
|
||||
UIManager:setDirty(nil, "full")
|
||||
-- a long diagonal swipe may also be used for taking a screenshot,
|
||||
-- so let it propagate
|
||||
return false
|
||||
if ges.pos:intersectWith(self.definition_widget.dimen) then
|
||||
-- if we want changeDict to still work with swipe outside window :
|
||||
-- or not ges.pos:intersectWith(self.dict_frame.dimen) then
|
||||
if ges.direction == "west" then
|
||||
self:changeToNextDict()
|
||||
elseif ges.direction == "east" then
|
||||
self:changeToPrevDict()
|
||||
else
|
||||
if self.refresh_callback then self.refresh_callback() end
|
||||
-- trigger full refresh
|
||||
UIManager:setDirty(nil, "full")
|
||||
-- a long diagonal swipe may also be used for taking a screenshot,
|
||||
-- so let it propagate
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
return true
|
||||
-- Let our MovableContainer handle swipe outside of definition
|
||||
return self.movable:onMovableSwipe(arg, ges)
|
||||
end
|
||||
|
||||
function DictQuickLookup:onHoldStartText(_, ges)
|
||||
-- Forward Hold events not processed by TextBoxWidget event handler
|
||||
-- to our MovableContainer
|
||||
return self.movable:onMovableHold(_, ges)
|
||||
end
|
||||
|
||||
function DictQuickLookup:onHoldReleaseText(_, ges)
|
||||
-- Forward Hold events not processed by TextBoxWidget event handler
|
||||
-- to our MovableContainer
|
||||
return self.movable:onMovableHoldRelease(_, ges)
|
||||
end
|
||||
|
||||
function DictQuickLookup:lookupInputWord(hint)
|
||||
|
||||
@@ -33,6 +33,7 @@ local HorizontalGroup = require("ui/widget/horizontalgroup")
|
||||
local HorizontalSpan = require("ui/widget/horizontalspan")
|
||||
local ImageWidget = require("ui/widget/imagewidget")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local ScrollTextWidget = require("ui/widget/scrolltextwidget")
|
||||
local Size = require("ui/size")
|
||||
local TextBoxWidget = require("ui/widget/textboxwidget")
|
||||
@@ -126,9 +127,7 @@ function InfoMessage:init()
|
||||
width = text_width,
|
||||
}
|
||||
end
|
||||
-- we construct the actual content here because self.text is only available now
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
self.movable = MovableContainer:new{
|
||||
FrameContainer:new{
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
HorizontalGroup:new{
|
||||
@@ -139,6 +138,10 @@ function InfoMessage:init()
|
||||
}
|
||||
}
|
||||
}
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
self.movable,
|
||||
}
|
||||
end
|
||||
|
||||
function InfoMessage:onCloseWidget()
|
||||
|
||||
@@ -56,6 +56,7 @@ local Geom = require("ui/geometry")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local InputText = require("ui/widget/inputtext")
|
||||
local LineWidget = require("ui/widget/linewidget")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local RenderText = require("ui/rendertext")
|
||||
local Size = require("ui/size")
|
||||
local TextBoxWidget = require("ui/widget/textboxwidget")
|
||||
@@ -200,7 +201,9 @@ function InputDialog:init()
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight() - self._input_widget:getKeyboardDimen().h,
|
||||
},
|
||||
self.dialog_frame,
|
||||
MovableContainer:new{
|
||||
self.dialog_frame,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -806,7 +806,7 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
local Trapper = require("ui/trapper")
|
||||
UIManager:scheduleIn(0.1, function() Trapper:wrap(load_and_show_image) end)
|
||||
-- And we return without calling the "Hold on text" callback
|
||||
return
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,7 @@ local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local LineWidget = require("ui/widget/linewidget")
|
||||
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||
local OverlapGroup = require("ui/widget/overlapgroup")
|
||||
local ScrollTextWidget = require("ui/widget/scrolltextwidget")
|
||||
local Size = require("ui/size")
|
||||
@@ -150,14 +151,14 @@ function TextViewer:init()
|
||||
local textw_height = self.height - titlew:getSize().h - separator:getSize().h - button_table:getSize().h
|
||||
|
||||
self.scroll_text_w = ScrollTextWidget:new{
|
||||
text = self.text,
|
||||
face = self.text_face,
|
||||
width = self.width - 2*self.text_padding - 2*self.text_margin,
|
||||
height = textw_height - 2*self.text_padding -2*self.text_margin,
|
||||
dialog = self,
|
||||
justified = true,
|
||||
text = self.text,
|
||||
face = self.text_face,
|
||||
width = self.width - 2*self.text_padding - 2*self.text_margin,
|
||||
height = textw_height - 2*self.text_padding -2*self.text_margin,
|
||||
dialog = self,
|
||||
justified = true,
|
||||
}
|
||||
local textw = FrameContainer:new{
|
||||
self.textw = FrameContainer:new{
|
||||
padding = self.text_padding,
|
||||
margin = self.text_margin,
|
||||
bordersize = 0,
|
||||
@@ -176,9 +177,9 @@ function TextViewer:init()
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = textw:getSize().h,
|
||||
h = self.textw:getSize().h,
|
||||
},
|
||||
textw,
|
||||
self.textw,
|
||||
},
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
@@ -189,10 +190,14 @@ function TextViewer:init()
|
||||
}
|
||||
}
|
||||
}
|
||||
self.movable = MovableContainer:new{
|
||||
ignore_events = {"swipe"},
|
||||
self.frame,
|
||||
}
|
||||
self[1] = WidgetContainer:new{
|
||||
align = self.align,
|
||||
dimen = self.region,
|
||||
self.frame,
|
||||
self.movable,
|
||||
}
|
||||
UIManager:setDirty("all", function()
|
||||
local update_region = self.frame.dimen:combine(orig_dimen)
|
||||
@@ -233,19 +238,23 @@ function TextViewer:onClose()
|
||||
end
|
||||
|
||||
function TextViewer:onSwipe(arg, ges)
|
||||
if ges.direction == "west" then
|
||||
self.scroll_text_w:scrollText(1)
|
||||
return true
|
||||
elseif ges.direction == "east" then
|
||||
self.scroll_text_w:scrollText(-1)
|
||||
return true
|
||||
else
|
||||
-- trigger full refresh
|
||||
UIManager:setDirty(nil, "full")
|
||||
-- a long diagonal swipe may also be used for taking a screenshot,
|
||||
-- so let it propagate
|
||||
return false
|
||||
if ges.pos:intersectWith(self.textw.dimen) then
|
||||
if ges.direction == "west" then
|
||||
self.scroll_text_w:scrollText(1)
|
||||
return true
|
||||
elseif ges.direction == "east" then
|
||||
self.scroll_text_w:scrollText(-1)
|
||||
return true
|
||||
else
|
||||
-- trigger full refresh
|
||||
UIManager:setDirty(nil, "full")
|
||||
-- a long diagonal swipe may also be used for taking a screenshot,
|
||||
-- so let it propagate
|
||||
return false
|
||||
end
|
||||
end
|
||||
-- Let our MovableContainer handle swipe outside of text
|
||||
return self.movable:onMovableSwipe(arg, ges)
|
||||
end
|
||||
|
||||
return TextViewer
|
||||
|
||||
Reference in New Issue
Block a user