diff --git a/frontend/apps/reader/modules/readersearch.lua b/frontend/apps/reader/modules/readersearch.lua index e2f7f481a..d93052c55 100644 --- a/frontend/apps/reader/modules/readersearch.lua +++ b/frontend/apps/reader/modules/readersearch.lua @@ -42,7 +42,7 @@ function ReaderSearch:onShowSearchDialog(text) end end self.search_dialog = ButtonDialog:new{ - alpha = 0.5, + -- alpha = 0.7, buttons = { { { diff --git a/frontend/apps/reader/skimtowidget.lua b/frontend/apps/reader/skimtowidget.lua index 588a84983..24fc42737 100644 --- a/frontend/apps/reader/skimtowidget.lua +++ b/frontend/apps/reader/skimtowidget.lua @@ -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 diff --git a/frontend/ui/trapper.lua b/frontend/ui/trapper.lua index d374f9e02..e859b4d3f 100644 --- a/frontend/ui/trapper.lua +++ b/frontend/ui/trapper.lua @@ -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 diff --git a/frontend/ui/widget/buttondialog.lua b/frontend/ui/widget/buttondialog.lua index 01cb9dc53..c0913b6b2 100644 --- a/frontend/ui/widget/buttondialog.lua +++ b/frontend/ui/widget/buttondialog.lua @@ -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 diff --git a/frontend/ui/widget/buttondialogtitle.lua b/frontend/ui/widget/buttondialogtitle.lua index 1aa4bcd9e..e93b1488f 100644 --- a/frontend/ui/widget/buttondialogtitle.lua +++ b/frontend/ui/widget/buttondialogtitle.lua @@ -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 diff --git a/frontend/ui/widget/confirmbox.lua b/frontend/ui/widget/confirmbox.lua index da03b7925..c63249df9 100644 --- a/frontend/ui/widget/confirmbox.lua +++ b/frontend/ui/widget/confirmbox.lua @@ -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, + } } } } diff --git a/frontend/ui/widget/container/movablecontainer.lua b/frontend/ui/widget/container/movablecontainer.lua new file mode 100644 index 000000000..439fba779 --- /dev/null +++ b/frontend/ui/widget/container/movablecontainer.lua @@ -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 diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index 6b4ea6c71..01b3de6f2 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -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) diff --git a/frontend/ui/widget/infomessage.lua b/frontend/ui/widget/infomessage.lua index 116c63938..6523b19a0 100644 --- a/frontend/ui/widget/infomessage.lua +++ b/frontend/ui/widget/infomessage.lua @@ -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() diff --git a/frontend/ui/widget/inputdialog.lua b/frontend/ui/widget/inputdialog.lua index 9e0a607fb..720749e81 100644 --- a/frontend/ui/widget/inputdialog.lua +++ b/frontend/ui/widget/inputdialog.lua @@ -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 diff --git a/frontend/ui/widget/textboxwidget.lua b/frontend/ui/widget/textboxwidget.lua index 71a874e81..7907d9f65 100644 --- a/frontend/ui/widget/textboxwidget.lua +++ b/frontend/ui/widget/textboxwidget.lua @@ -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 diff --git a/frontend/ui/widget/textviewer.lua b/frontend/ui/widget/textviewer.lua index 7e1d94e1f..d01ce1e42 100644 --- a/frontend/ui/widget/textviewer.lua +++ b/frontend/ui/widget/textviewer.lua @@ -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