mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
MovableContainer: add support for anchoring initial position
When passing as 'anchor' a Geom object (ie. a widget dimen or a ges.pos), or a function returning such an object, a MovableContainer will be initially positionned near this point/widget, instead of being centered on the screen. Allow that for ButtonDialog and ButtonDialogTitle, so we can make them behave as context menus (ie. for a titlebar top left/right icons).
This commit is contained in:
@@ -88,6 +88,7 @@ function ButtonDialog:init()
|
||||
end
|
||||
self.movable = MovableContainer:new{
|
||||
alpha = self.alpha,
|
||||
anchor = self.anchor,
|
||||
FrameContainer:new{
|
||||
ButtonTable:new{
|
||||
buttons = self.buttons,
|
||||
|
||||
@@ -88,6 +88,7 @@ function ButtonDialogTitle:init()
|
||||
dimen = Screen:getSize(),
|
||||
ignore_if_over = "height",
|
||||
MovableContainer:new{
|
||||
anchor = self.anchor,
|
||||
FrameContainer:new{
|
||||
VerticalGroup:new{
|
||||
align = "center",
|
||||
|
||||
@@ -13,6 +13,7 @@ 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 BD = require("ui/bidi")
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
local Device = require("device")
|
||||
local Geom = require("ui/geometry")
|
||||
@@ -35,6 +36,12 @@ local MovableContainer = InputContainer:extend{
|
||||
-- Events to ignore (ie: ignore_events={"hold", "hold_release"})
|
||||
ignore_events = nil,
|
||||
|
||||
-- Initial position can be set related to an existing widget
|
||||
-- 'anchor' should be a Geom object (a widget's 'dimen', or a point), and
|
||||
-- can be a function returning that object
|
||||
anchor = nil,
|
||||
_anchor_ensured = nil,
|
||||
|
||||
-- Current move offset (use getMovedOffset()/setMovedOffset() to access them)
|
||||
_moved_offset_x = 0,
|
||||
_moved_offset_y = 0,
|
||||
@@ -100,6 +107,59 @@ function MovableContainer:setMovedOffset(offset_point)
|
||||
end
|
||||
end
|
||||
|
||||
function MovableContainer:ensureAnchor(x, y)
|
||||
local anchor_dimen = self.anchor
|
||||
local prefers_pop_down
|
||||
if type(self.anchor) == "function" then
|
||||
anchor_dimen, prefers_pop_down = self.anchor()
|
||||
end
|
||||
if not anchor_dimen then
|
||||
return
|
||||
end
|
||||
-- We try to find the best way to draw our content, depending on
|
||||
-- the size of the content and the space available on the screen.
|
||||
local content_w, content_h = self.dimen.w, self.dimen.h
|
||||
local screen_w, screen_h = Screen:getWidth(), Screen:getHeight()
|
||||
local left, top
|
||||
if BD.mirroredUILayout() then
|
||||
left = anchor_dimen.x + anchor_dimen.w - content_w
|
||||
else
|
||||
left = anchor_dimen.x
|
||||
end
|
||||
if left < 0 then
|
||||
left = 0
|
||||
elseif left + content_w > screen_w then
|
||||
left = screen_w - content_w
|
||||
end
|
||||
-- We prefer displaying above the anchor if there is room (so it looks like popping up)
|
||||
-- except if anchor() returned prefers_pop_down
|
||||
local h_remaining_if_above = anchor_dimen.y - content_h
|
||||
local h_remaining_if_below = screen_h - (anchor_dimen.y + anchor_dimen.h + content_h)
|
||||
if h_remaining_if_above >= 0 and not prefers_pop_down then
|
||||
-- Enough room above the anchor
|
||||
top = anchor_dimen.y - content_h
|
||||
elseif h_remaining_if_below >= 0 then
|
||||
-- Enough room below the anchor
|
||||
top = anchor_dimen.y + anchor_dimen.h
|
||||
elseif h_remaining_if_above >= 0 then
|
||||
-- Enough room above the anchor
|
||||
top = anchor_dimen.y - content_h
|
||||
else -- both negative
|
||||
if h_remaining_if_above >= h_remaining_if_below then
|
||||
top = 0
|
||||
else
|
||||
top = screen_h - content_h
|
||||
end
|
||||
end
|
||||
-- Ensure we show the top if we would overflow
|
||||
if top < 0 then
|
||||
top = 0
|
||||
end
|
||||
-- Make the initial offsets so that we display at left/top
|
||||
self._moved_offset_x = left - x
|
||||
self._moved_offset_y = top - y
|
||||
end
|
||||
|
||||
function MovableContainer:paintTo(bb, x, y)
|
||||
if self[1] == nil then
|
||||
return
|
||||
@@ -112,6 +172,12 @@ function MovableContainer:paintTo(bb, x, y)
|
||||
|
||||
self._orig_x = x
|
||||
self._orig_y = y
|
||||
-- If there is a widget passed as anchor, we need to set our initial position
|
||||
-- related to it. After that, we allow it to be moved like any other movable.
|
||||
if self.anchor and not self._anchor_ensured then
|
||||
self:ensureAnchor(x, y)
|
||||
self._anchor_ensured = true
|
||||
end
|
||||
-- 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
|
||||
|
||||
Reference in New Issue
Block a user