Files
koreader/frontend/ui/widget/textviewer.lua
hius07 20e9f3e80a textviewer: fix refresh (#8576)
When TextViewer is showing up, it causes screen refresh of the rectangle from the upper left corner of the screen (0,0) till the lower right corner of the TextViewer window (the result of `combine`).
So when the TextViewer is not full-screen, left and upper parts of the screen are refreshed.
This unpleasent screen flashing can be seen, for exampe, when showing book description from the Book information page, or when calling the clipboard (long-press on the text input box).
Let's show the TextViewer in a usual way, as (almost) all other widgets do.
2021-12-25 22:56:24 +01:00

279 lines
8.4 KiB
Lua

--[[--
Displays some text in a scrollable view.
@usage
local textviewer = TextViewer:new{
title = _("I can scroll!"),
text = _("I'll need to be longer than this example to scroll."),
}
UIManager:show(textviewer)
]]
local BD = require("ui/bidi")
local Blitbuffer = require("ffi/blitbuffer")
local ButtonTable = require("ui/widget/buttontable")
local CenterContainer = require("ui/widget/container/centercontainer")
local CloseButton = require("ui/widget/closebutton")
local Device = require("device")
local Geom = require("ui/geometry")
local Font = require("ui/font")
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")
local TextBoxWidget = require("ui/widget/textboxwidget")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local _ = require("gettext")
local Screen = Device.screen
local TextViewer = InputContainer:new{
modal = true,
title = nil,
text = nil,
width = nil,
height = nil,
buttons_table = nil,
-- See TextBoxWidget for details about these options
-- We default to justified and auto_para_direction to adapt
-- to any kind of text we are given (book descriptions,
-- bookmarks' text, translation results...).
-- When used to display more technical text (HTML, CSS,
-- application logs...), it's best to reset them to false.
alignment = "left",
justified = true,
lang = nil,
para_direction_rtl = nil,
auto_para_direction = true,
alignment_strict = false,
title_face = Font:getFace("x_smalltfont"),
text_face = Font:getFace("x_smallinfofont"),
fgcolor = Blitbuffer.COLOR_BLACK,
title_padding = Size.padding.default,
title_margin = Size.margin.title,
text_padding = Size.padding.large,
text_margin = Size.margin.small,
button_padding = Size.padding.default,
}
function TextViewer:init()
-- calculate window dimension
self.align = "center"
self.region = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
self.width = self.width or Screen:getWidth() - Screen:scaleBySize(30)
self.height = self.height or Screen:getHeight() - Screen:scaleBySize(30)
if Device:hasKeys() then
self.key_events = {
Close = { {"Back"}, doc = "close text viewer" }
}
end
if Device:isTouchDevice() then
self.ges_events = {
TapClose = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
},
},
Swipe = {
GestureRange:new{
ges = "swipe",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
},
},
}
end
local closeb = CloseButton:new{ window = self, padding_top = Size.padding.tiny, }
local title_text = TextBoxWidget:new{
text = self.title,
face = self.title_face,
bold = true,
width = self.width - 2*self.title_padding - 2*self.title_margin - closeb:getSize().w,
}
local titlew = FrameContainer:new{
padding = self.title_padding,
-- TextBoxWidget has less text top & bottom padding than TextWidget
-- (for a reasonable line height with multi lines), but we
-- can get the same as TextWidget by simply adding Size.padding.small
padding_top = self.title_padding + Size.padding.small,
padding_bottom = self.title_padding + Size.padding.small,
margin = self.title_margin,
bordersize = 0,
title_text
}
titlew = OverlapGroup:new{
dimen = {
w = self.width,
h = titlew:getSize().h
},
titlew,
closeb,
}
local separator = LineWidget:new{
dimen = Geom:new{
w = self.width,
h = Size.line.thick,
}
}
local buttons
if self.buttons_table == nil then
buttons = {
{
{
text = _("Close"),
callback = function()
UIManager:close(self)
end,
},
},
}
else
buttons = self.buttons_table
end
local button_table = ButtonTable:new{
width = self.width - 2*self.button_padding,
button_font_face = "cfont",
button_font_size = 20,
buttons = buttons,
zero_sep = true,
show_parent = self,
}
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,
fgcolor = self.fgcolor,
width = self.width - 2*self.text_padding - 2*self.text_margin,
height = textw_height - 2*self.text_padding -2*self.text_margin,
dialog = self,
alignment = self.alignment,
justified = self.justified,
lang = self.lang,
para_direction_rtl = self.para_direction_rtl,
auto_para_direction = self.auto_para_direction,
alignment_strict = self.alignment_strict,
}
self.textw = FrameContainer:new{
padding = self.text_padding,
margin = self.text_margin,
bordersize = 0,
self.scroll_text_w
}
self.frame = FrameContainer:new{
radius = Size.radius.window,
padding = 0,
margin = 0,
background = Blitbuffer.COLOR_WHITE,
VerticalGroup:new{
align = "left",
titlew,
separator,
CenterContainer:new{
dimen = Geom:new{
w = self.width,
h = self.textw:getSize().h,
},
self.textw,
},
CenterContainer:new{
dimen = Geom:new{
w = self.width,
h = button_table:getSize().h,
},
button_table,
}
}
}
self.movable = MovableContainer:new{
ignore_events = {"swipe"},
self.frame,
}
self[1] = WidgetContainer:new{
align = self.align,
dimen = self.region,
self.movable,
}
UIManager:setDirty(self, function()
return "partial", self.frame.dimen
end)
end
function TextViewer:onCloseWidget()
UIManager:setDirty(nil, function()
return "partial", self.frame.dimen
end)
end
function TextViewer:onShow()
UIManager:setDirty(self, function()
return "ui", self.frame.dimen
end)
return true
end
function TextViewer:onAnyKeyPressed()
UIManager:close(self)
return true
end
function TextViewer:onTapClose(arg, ges_ev)
if ges_ev.pos:notIntersectWith(self.frame.dimen) then
self:onClose()
end
return true
end
function TextViewer:onClose()
UIManager:close(self)
return true
end
function TextViewer:onSwipe(arg, ges)
if ges.pos:intersectWith(self.textw.dimen) then
local direction = BD.flipDirectionIfMirroredUILayout(ges.direction)
if direction == "west" then
self.scroll_text_w:scrollText(1)
return true
elseif direction == "east" then
self.scroll_text_w:scrollText(-1)
return true
else
-- trigger a full-screen HQ flashing 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