TextWidget: small refactoring, better handle max_width (#5503)

Lots of code was doing some renderText calls to get the size
of some text string, and truncate it to some width if needed,
with or without an added ellipsis, before instantiating
a TextWidget with that tweaked text string.

This PR fixes/adds some properties and methods to TextWidget
so all that can be done by it. It makes the calling code
simpler, as they don't need to use RenderText directly.
(Additionally, when we go at using Harfbuzz for text rendering,
we'll just have to update or replace textwidget.lua without
the need to update any higher level code.)

Also:
- RenderText: removed the space added by truncateTextByWidth
  after the ellipsis, as it doesn't feel needed, and break
  right alignment of the ellipsis with other texts.
- KeyValuePage: fix some subtle size and alignment issues.
- NumberPickerWidget: fix font size (provided font size was
  not used)
pull/5525/head
poire-z 5 years ago committed by GitHub
parent ef22e85469
commit f05e62c1fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -50,10 +50,6 @@ local function restoreScreenMode()
end
end
local function truncatePath(text)
return FileChooser:truncatePath(text)
end
local FileManager = InputContainer:extend{
title = _("KOReader"),
root_path = lfs.currentdir(),
@ -110,7 +106,9 @@ function FileManager:init()
self.path_text = TextWidget:new{
face = Font:getFace("xx_smallinfofont"),
text = truncatePath(filemanagerutil.abbreviate(self.root_path)),
text = filemanagerutil.abbreviate(self.root_path),
max_width = Screen:getWidth() - 2*Size.padding.small,
truncate_left = true,
}
self.banner = FrameContainer:new{
@ -177,7 +175,7 @@ function FileManager:init()
self.focused_file = nil -- use it only once
function file_chooser:onPathChanged(path) -- luacheck: ignore
FileManager.instance.path_text:setText(truncatePath(filemanagerutil.abbreviate(path)))
FileManager.instance.path_text:setText(filemanagerutil.abbreviate(path))
UIManager:setDirty(FileManager.instance, function()
return "ui", FileManager.instance.path_text.dimen, FileManager.instance.dithered
end)

@ -263,8 +263,7 @@ function RenderText:renderUtf8Text(dest_bb, x, baseline, face, text, kerning, bo
return pen_x
end
local ellipsis, space = "", " "
local ellipsis_width, space_width
local ellipsis = ""
--- Returns a substring of a given text that meets the maximum width (in pixels)
-- restriction with ellipses (…) at the end if required.
--
@ -273,23 +272,13 @@ local ellipsis_width, space_width
-- @int width maximum width in pixels
-- @bool[opt=false] kerning whether the text should be measured with kerning
-- @bool[opt=false] bold whether the text should be measured as bold
-- @bool[opt=false] prepend_space whether a space should be prepended to the text
-- @treturn string
-- @see getSubTextByWidth
function RenderText:truncateTextByWidth(text, face, max_width, kerning, bold, prepend_space)
if not ellipsis_width then
ellipsis_width = self:sizeUtf8Text(0, max_width, face, ellipsis).x
end
if not space_width then
space_width = self:sizeUtf8Text(0, max_width, face, space).x
end
local new_txt_width = max_width - ellipsis_width - space_width
function RenderText:truncateTextByWidth(text, face, max_width, kerning, bold)
local ellipsis_width = self:sizeUtf8Text(0, max_width, face, ellipsis, false, bold).x
local new_txt_width = max_width - ellipsis_width
local sub_txt = self:getSubTextByWidth(text, face, new_txt_width, kerning, bold)
if prepend_space then
return space.. sub_txt .. ellipsis
else
return sub_txt .. ellipsis .. space
end
return sub_txt .. ellipsis
end
return RenderText

@ -459,7 +459,6 @@ function Screensaver:addOverlayMessage(widget, text)
local Font = require("ui/font")
local FrameContainer = require("ui/widget/container/framecontainer")
local OverlapGroup = require("ui/widget/overlapgroup")
local RenderText = require("ui/rendertext")
local RightContainer = require("ui/widget/container/rightcontainer")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
@ -468,15 +467,13 @@ function Screensaver:addOverlayMessage(widget, text)
local face = Font:getFace("infofont")
local screen_w, screen_h = Screen:getWidth(), Screen:getHeight()
local textw
local textw = TextWidget:new{
text = text,
face = face,
}
-- Don't make our message reach full screen width
local tsize = RenderText:sizeUtf8Text(0, screen_w, face, text)
if tsize.x < screen_w * 0.9 then
textw = TextWidget:new{
text = text,
face = face,
}
else -- if text too wide, use TextBoxWidget for multi lines display
if textw:getWidth() > screen_w * 0.9 then
-- Text too wide: use TextBoxWidget for multi lines display
textw = TextBoxWidget:new{
text = text,
face = face,

@ -18,7 +18,6 @@ local IconButton = require("ui/widget/iconbutton")
local ImageWidget = require("ui/widget/imagewidget")
local InputContainer = require("ui/widget/container/inputcontainer")
local LineWidget = require("ui/widget/linewidget")
local RenderText = require("ui/rendertext")
local RightContainer = require("ui/widget/container/rightcontainer")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
@ -208,7 +207,11 @@ function ConfigOption:init()
local face = Font:getFace(name_font_face, name_font_size)
local txt_width = 0
if text ~= nil then
txt_width = RenderText:sizeUtf8Text(0, Screen:getWidth(), face, text).x
local tmp = TextWidget:new{
text = text,
face = face,
}
txt_width = tmp:getWidth()
end
max_option_name_width = math.max(max_option_name_width, txt_width)
end
@ -265,16 +268,12 @@ function ConfigOption:init()
local name_text_max_width = name_widget_width - default_option_hpadding - 2*padding_small
local text = self.options[c].name_text
local face = Font:getFace(name_font_face, name_font_size)
local width_name_text = RenderText:sizeUtf8Text(0, Screen:getWidth(), face, text).x
if width_name_text > name_text_max_width then
text = RenderText:truncateTextByWidth(text, face, name_text_max_width)
end
local option_name_container = RightContainer:new{
dimen = Geom:new{ w = name_widget_width, h = option_height},
}
local option_name = Button:new{
text = text,
max_width = name_text_max_width,
bordersize = 0,
face = face,
enabled = enabled,
@ -436,13 +435,10 @@ function ConfigOption:init()
else
local text = self.options[c].item_text[d]
local face = Font:getFace(item_font_face, item_font_size)
local width_item_text = RenderText:sizeUtf8Text(0, Screen:getWidth(), face, text).x
if max_item_text_width < width_item_text then
text = RenderText:truncateTextByWidth(text, face, max_item_text_width)
end
option_item = OptionTextItem:new{
TextWidget:new{
text = text,
max_width = max_item_text_width,
face = face,
fgcolor = enabled and Blitbuffer.COLOR_BLACK or Blitbuffer.COLOR_DARK_GRAY,
},

@ -1,29 +1,25 @@
local TextWidget = require("ui/widget/textwidget")
local RenderText = require("ui/rendertext")
local Geom = require("ui/geometry")
local Screen = require("device").screen
--[[
FixedTextWidget
--]]
local FixedTextWidget = TextWidget:new{}
function FixedTextWidget:getSize()
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold)
if tsize.x == 0 then
return Geom:new{}
end
self._length = tsize.x
function FixedTextWidget:updateSize()
TextWidget.updateSize(self)
-- Only difference from TextWidget:
-- no vertical padding, baseline is height
self._height = self.face.size
return Geom:new{
w = self._length,
h = self._height,
}
self._baseline_h = self.face.size
end
function FixedTextWidget:paintTo(bb, x, y)
RenderText:renderUtf8Text(bb, x, y+self._height, self.face, self.text, true, self.bold,
self.fgcolor)
function FixedTextWidget:getSize()
self:updateSize()
if self._length == 0 then
return Geom:new{}
end
return TextWidget.getSize(self)
end
return FixedTextWidget

@ -108,7 +108,6 @@ local LineWidget = require("ui/widget/linewidget")
local MovableContainer = require("ui/widget/container/movablecontainer")
local MultiConfirmBox = require("ui/widget/multiconfirmbox")
local Notification = require("ui/widget/notification")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TextWidget = require("ui/widget/textwidget")
@ -211,15 +210,6 @@ function InputDialog:init()
end
-- Title & description
local title_width = RenderText:sizeUtf8Text(0, self.width,
self.title_face, self.title, true).x
if title_width > self.width then
local indicator = " >> "
local indicator_w = RenderText:sizeUtf8Text(0, self.width,
self.title_face, indicator, true).x
self.title = RenderText:getSubTextByWidth(self.title, self.title_face,
self.width - indicator_w, true) .. indicator
end
self.title_widget = FrameContainer:new{
padding = self.title_padding,
margin = self.title_margin,
@ -227,7 +217,7 @@ function InputDialog:init()
TextWidget:new{
text = self.title,
face = self.title_face,
width = self.width,
max_width = self.width,
}
}
self.title_bar = LineWidget:new{

@ -34,7 +34,6 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local LineWidget = require("ui/widget/linewidget")
local OverlapGroup = require("ui/widget/overlapgroup")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local TextViewer = require("ui/widget/textviewer")
local TextWidget = require("ui/widget/textwidget")
@ -57,20 +56,12 @@ local KeyValueTitle = VerticalGroup:new{
function KeyValueTitle:init()
self.close_button = CloseButton:new{ window = self }
local btn_width = self.close_button:getSize().w
local title_txt_width = RenderText:sizeUtf8Text(
0, self.width, self.tface, self.title).x
local show_title_txt
if self.width < (title_txt_width + btn_width) then
show_title_txt = RenderText:truncateTextByWidth(
self.title, self.tface, self.width-btn_width)
else
show_title_txt = self.title
end
-- title and close button
table.insert(self, OverlapGroup:new{
dimen = { w = self.width },
TextWidget:new{
text = show_title_txt,
text = self.title,
max_width = self.width - btn_width,
face = self.tface,
},
self.close_button,
@ -154,25 +145,54 @@ function KeyValueItem:init()
local frame_padding = Size.padding.default
local frame_internal_width = self.width - frame_padding * 2
-- Default widths (and position of value widget) if each text fits in 1/2 screen width
local key_w = frame_internal_width / 2
local value_w = frame_internal_width / 2
local key_w_rendered = RenderText:sizeUtf8Text(0, frame_internal_width, self.tface, self.key).x
local value_w_rendered = RenderText:sizeUtf8Text(0, frame_internal_width, self.cface, tvalue).x
local space_w_rendered = RenderText:sizeUtf8Text(0, frame_internal_width, self.cface, " ").x
local key_widget = TextWidget:new{
text = self.key,
max_width = frame_internal_width,
face = self.tface,
}
local value_widget = TextWidget:new{
text = tvalue,
max_width = frame_internal_width,
face = self.cface,
}
local key_w_rendered = key_widget:getWidth()
local value_w_rendered = value_widget:getWidth()
-- As both key_widget and value_width will be in a HorizontalGroup,
-- and key is always left aligned, we can just tweak the key width
-- to position the value_widget
local value_prepend_space = false
local value_align_right = false
local fit_right_align = true -- by default, really right align
if key_w_rendered > key_w or value_w_rendered > value_w then
-- truncate key or value so they fit in one row
-- One (or both) does not fit in 1/2 width
if key_w_rendered + value_w_rendered > frame_internal_width then
-- Both do not fit: one has to be truncated so they fit
if key_w_rendered >= value_w_rendered then
-- Rare case: key larger than value.
-- We should have kept our keys small, smaller than 1/2 width.
-- If it is larger than value, it's that value is kinda small,
-- so keep the whole value, and truncate the key
key_w = frame_internal_width - value_w_rendered
self.show_key = RenderText:truncateTextByWidth(self.key, self.tface, frame_internal_width - value_w_rendered)
self.show_value = tvalue
else
key_w = key_w_rendered + space_w_rendered
self.show_value = RenderText:truncateTextByWidth(tvalue, self.cface, frame_internal_width - key_w_rendered,
false, false, true)
self.show_key = self.key
-- Usual case: value larger than key.
-- Keep our small key, fit the value in the remaining width,
-- prepend some space to separate them
key_w = key_w_rendered
value_prepend_space = true
end
-- allow for displaying the non-truncated texts with Hold
value_align_right = true -- so the ellipsis touches the screen right border
if self.value_overflow_align ~= "right" and self.value_align ~= "right" then
-- Don't adjust the ellipsis to the screen right border,
-- so the left of text is aligned with other truncated texts
fit_right_align = false
end
-- Allow for displaying the non-truncated texts with Hold
if Device:isTouchDevice() then
self.ges_events.Hold = {
GestureRange:new{
@ -181,24 +201,43 @@ function KeyValueItem:init()
}
}
end
-- misalign to fit all info
else
-- Both can fit: break the 1/2 widths
if self.value_overflow_align == "right" or self.value_align == "right" then
key_w = frame_internal_width - value_w_rendered
value_align_right = true
else
key_w = key_w_rendered + space_w_rendered
key_w = key_w_rendered
value_prepend_space = true
end
self.show_key = self.key
self.show_value = tvalue
end
-- In all the above case, we set the right key_w to include any
-- needed in-between padding: value_w is what's left.
value_w = frame_internal_width - key_w
else
if self.value_align == "right" then
key_w = frame_internal_width - value_w_rendered
value_w = value_w_rendered
value_align_right = true
end
self.show_key = self.key
self.show_value = tvalue
end
-- Adjust widgets' max widths and text as needed
if value_prepend_space then
value_widget:setText(" "..tvalue)
end
value_widget:setMaxWidth(value_w)
if fit_right_align and value_align_right and value_widget:getWidth() < value_w then
-- Because of truncation at glyph boundaries, value_widget
-- may be a tad smaller than the specified value_w:
-- add some padding to key_w so value is pushed to the screen right border
key_w = key_w + ( value_w - value_widget:getWidth() )
end
key_widget:setMaxWidth(key_w)
-- For debugging positioning:
-- value_widget = FrameContainer:new{ padding=0, margin=0, bordersize=1, value_widget }
self[1] = FrameContainer:new{
padding = frame_padding,
bordersize = 0,
@ -209,20 +248,14 @@ function KeyValueItem:init()
w = key_w,
h = self.height
},
TextWidget:new{
text = self.show_key,
face = self.tface,
}
key_widget,
},
LeftContainer:new{
dimen = {
w = value_w,
h = self.height
},
TextWidget:new{
text = self.show_value,
face = self.cface,
}
value_widget,
}
}
}

@ -129,8 +129,6 @@ local MenuItem = InputContainer:new{
text = nil,
show_parent = nil,
detail = nil,
face = Font:getFace("cfont", 30),
info_face = Font:getFace("infont", 15),
font = "cfont",
font_size = 24,
infont = "infont",
@ -176,6 +174,25 @@ function MenuItem:init()
}
end
-- State button and indentation for tree expand/collapse (for TOC)
local state_button_width = self.state_size.w or 0
local state_button = self.state or HorizontalSpan:new{
width = state_button_width,
}
local state_indent = self.state and self.state.indent or ""
local state_container = LeftContainer:new{
dimen = Geom:new{w = self.content_width/2, h = self.dimen.h},
HorizontalGroup:new{
TextWidget:new{
text = state_indent,
face = Font:getFace(self.font, self.font_size),
},
state_button,
}
}
-- "mandatory" is the text on the right: file size, page number...
-- Padding before mandatory
local text_mandatory_padding = 0
local text_ellipsis_mandatory_padding = 0
if self.mandatory then
@ -185,44 +202,39 @@ function MenuItem:init()
end
local mandatory = self.mandatory and ""..self.mandatory or ""
local state_button_width = self.state_size.w or 0
local state_button = self.state or HorizontalSpan:new{
width = state_button_width,
}
local state_indent = self.state and self.state.indent or ""
-- Font for main text (may have its size decreased to make text fit)
self.face = Font:getFace(self.font, self.font_size)
-- Font for "mandatory" on the right
self.info_face = Font:getFace(self.infont, self.infont_size)
local item_name
local mandatory_widget
if self.single_line then -- items only in single line
self.info_face = Font:getFace(self.infont, self.infont_size)
self.face = Font:getFace(self.font, self.font_size)
local mandatory_w = RenderText:sizeUtf8Text(0, self.dimen.w, self.info_face, ""..mandatory, true, self.bold).x
local my_text = self.text and ""..self.text or ""
local w = RenderText:sizeUtf8Text(0, self.dimen.w, self.face, my_text, true, self.bold).x
if w + mandatory_w + state_button_width + text_mandatory_padding >= self.content_width then
local indicator = "\226\128\166 " -- an ellipsis
local indicator_w = RenderText:sizeUtf8Text(0, self.dimen.w, self.face,
indicator, true, self.bold).x
self.text = RenderText:getSubTextByWidth(my_text, self.face,
self.content_width - indicator_w - mandatory_w - state_button_width - text_ellipsis_mandatory_padding,
true, self.bold) .. indicator
end
item_name = TextWidget:new{
text = self.text,
face = self.face,
bold = self.bold,
fgcolor = self.dim and Blitbuffer.COLOR_DARK_GRAY or nil,
}
mandatory_widget = TextWidget:new{
text = mandatory,
face = self.info_face,
bold = self.bold,
fgcolor = self.dim and Blitbuffer.COLOR_DARK_GRAY or nil,
}
if self.align_baselines then
local mandatory_w = mandatory_widget:getWidth()
-- No font size change: text will be truncated if it overflows
-- (we give it a little more room if truncated for better visual
-- feeling - which might make it no more truncated, but well...)
local text_max_width_base = self.content_width - state_button_width - mandatory_w
local text_max_width = text_max_width_base - text_mandatory_padding
local text_max_width_if_ellipsis = text_max_width_base - text_ellipsis_mandatory_padding
item_name = TextWidget:new{
text = self.text,
face = self.face,
bold = self.bold,
fgcolor = self.dim and Blitbuffer.COLOR_DARK_GRAY or nil,
}
local w = item_name:getWidth()
if w > text_max_width then
item_name:setMaxWidth(text_max_width_if_ellipsis)
end
if self.align_baselines then -- Align baselines of text and mandatory
local name_baseline = item_name:getBaseline()
local mandatory_baseline = mandatory_widget:getBaseline()
local baselines_diff = Math.round(name_baseline - mandatory_baseline)
@ -313,16 +325,6 @@ function MenuItem:init()
self.face = Font:getFace(self.font, self.font_size)
end
local state_container = LeftContainer:new{
dimen = Geom:new{w = self.content_width/2, h = self.dimen.h},
HorizontalGroup:new{
HorizontalSpan:new{
width = RenderText:sizeUtf8Text(0, self.dimen.w, self.face,
state_indent, true, self.bold).x,
},
state_button,
}
}
local text_container = LeftContainer:new{
dimen = Geom:new{w = self.content_width, h = self.dimen.h},
HorizontalGroup:new{
@ -579,7 +581,9 @@ function Menu:init()
if self.show_path then
self.path_text = TextWidget:new{
face = Font:getFace("xx_smallinfofont"),
text = self:truncatePath(self.path),
text = self.path,
max_width = self.dimen.w - 2*Size.padding.small,
truncate_left = true,
}
path_text_container = CenterContainer:new{
dimen = Geom:new{
@ -865,19 +869,6 @@ function Menu:init()
end
end
function Menu:truncatePath(text)
local screen_width = Screen:getWidth()
local face = Font:getFace("xx_smallinfofont")
-- we want to truncate text on the left, so work with the reverse of text (which is fine as we don't use kerning)
local reversed_text = require("util").utf8Reverse(text)
local txt_width = RenderText:sizeUtf8Text(0, screen_width, face, reversed_text, false, false).x
if screen_width - 2 * Size.padding.small < txt_width then
reversed_text = RenderText:truncateTextByWidth(reversed_text, face, screen_width - 2 * Size.padding.small, false, false)
text = require("util").utf8Reverse(reversed_text)
end
return text
end
function Menu:onCloseWidget()
--- @fixme
-- we cannot refresh regionally using the dimen field
@ -984,7 +975,7 @@ function Menu:updateItems(select_number)
self:updatePageInfo(select_number)
if self.show_path then
self.path_text.text = self:truncatePath(self.path)
self.path_text:setText(self.path)
end
UIManager:setDirty(self.show_parent, function()
@ -1011,7 +1002,7 @@ end
--]]
function Menu:switchItemTable(new_title, new_item_table, itemnumber, itemmatch)
if self.menu_title and new_title then
self.menu_title.text = new_title
self.menu_title:setText(new_title)
end
if itemnumber == nil then

@ -25,7 +25,6 @@ local Font = require("ui/font")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
@ -120,12 +119,7 @@ function NumberPickerWidget:paintWidget()
width = self.screen_height * 0.01
}
local value = self.value
if self.value_table then
local text_width = RenderText:sizeUtf8Text(0, self.width, self.spinner_face, self.value, true, true).x
if self.width < text_width then
value = RenderText:truncateTextByWidth(self.value, self.spinner_face, self.width,true, true)
end
else
if not self.value_table then
value = string.format(self.precision, value)
end
@ -185,9 +179,10 @@ function NumberPickerWidget:paintWidget()
text = value,
bordersize = 0,
padding = 0,
text_font_face = self.spinner_face_font,
text_font_size = self.spinner_face_size,
text_font_face = self.spinner_face.font,
text_font_size = self.spinner_face.orig_size,
width = self.width,
max_width = self.width,
callback = callback_input,
}
return VerticalGroup:new{

@ -12,7 +12,6 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local LineWidget = require("ui/widget/linewidget")
local OverlapGroup = require("ui/widget/overlapgroup")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
@ -33,20 +32,12 @@ local SortTitleWidget = VerticalGroup:new{
function SortTitleWidget:init()
self.close_button = CloseButton:new{ window = self }
local btn_width = self.close_button:getSize().w
local title_txt_width = RenderText:sizeUtf8Text(
0, self.width, self.tface, self.title).x
local show_title_txt
if self.width < (title_txt_width + btn_width) then
show_title_txt = RenderText:truncateTextByWidth(
self.title, self.tface, self.width-btn_width)
else
show_title_txt = self.title
end
-- title and close button
table.insert(self, OverlapGroup:new{
dimen = { w = self.width },
TextWidget:new{
text = show_title_txt,
text = self.title,
max_width = self.width - btn_width,
face = self.tface,
},
self.close_button,
@ -124,10 +115,6 @@ function SortItemWidget:init()
local frame_padding = Size.padding.default
local frame_internal_width = self.width - frame_padding * 2
local text_rendered = RenderText:sizeUtf8Text(0, self.width, self.tface, self.text).x
if text_rendered > frame_internal_width then
self.text = RenderText:truncateTextByWidth(self.text, self.tface, frame_internal_width)
end
self[1] = FrameContainer:new{
padding = 0,
@ -139,6 +126,7 @@ function SortItemWidget:init()
},
TextWidget:new{
text = self.text,
max_width = frame_internal_width,
face = self.tface,
}
},

@ -12,7 +12,6 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local LineWidget = require("ui/widget/linewidget")
local NumberPickerWidget = require("ui/widget/numberpickerwidget")
local OverlapGroup = require("ui/widget/overlapgroup")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TextWidget = require("ui/widget/textwidget")
@ -90,24 +89,16 @@ function SpinWidget:update()
local close_button = CloseButton:new{ window = self, padding_top = Size.margin.title, }
local btn_width = close_button:getSize().w + Size.padding.default * 2
local title_txt_width = RenderText:sizeUtf8Text(
0, self.width, self.title_face, self.title_text).x
local show_title_txt
if self.width < (title_txt_width + btn_width) then
show_title_txt = RenderText:truncateTextByWidth(
self.title_text, self.title_face, self.width - btn_width)
else
show_title_txt = self.title_text
end
local value_title = FrameContainer:new{
padding = Size.padding.default,
margin = Size.margin.title,
bordersize = 0,
TextWidget:new{
text = show_title_txt,
text = self.title_text,
max_width = self.width - btn_width,
face = self.title_face,
bold = true,
width = self.width,
},
}
local value_line = LineWidget:new{

@ -19,39 +19,76 @@ local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local Widget = require("ui/widget/widget")
local Screen = require("device").screen
local util = require("util")
local TextWidget = Widget:new{
text = nil,
face = nil,
bold = nil,
bold = false, -- synthetized/fake bold (use a bold face for nicer bold)
fgcolor = Blitbuffer.COLOR_BLACK,
padding = Size.padding.small, -- should padding be function of face.size ?
padding = Size.padding.small, -- vertical padding (should it be function of face.size ?)
-- (no horizontal padding is added)
max_width = nil,
_bb = nil,
truncate_with_ellipsis = true, -- when truncation at max_width needed, add "…"
truncate_left = false, -- truncate on the right by default
_updated = nil,
_text_to_draw = nil,
_length = 0,
_height = 0,
_baseline_h = 0,
_maxlength = 1200,
}
--function TextWidget:_render()
--local h = self.face.size * 1.3
--self._bb = Blitbuffer.new(self._maxlength, h)
--self._bb:fill(Blitbuffer.COLOR_WHITE)
--self._length = RenderText:renderUtf8Text(self._bb, 0, h*0.8, self.face, self.text, true, self.bold)
--end
function TextWidget:updateSize()
local tsize = RenderText:sizeUtf8Text(0, self.max_width and self.max_width or Screen:getWidth(), self.face, self.text, true, self.bold)
if tsize.x == 0 then
self._length = 0
else
-- As text length includes last glyph pen "advance" (for positionning
-- next char), it's best to use math.floor() instead of math.ceil()
-- to get rid of a fraction of it in case this text is to be
-- horizontally centered
if self._updated then
return
end
self._updated = true
-- In case we draw truncated text, keep original self.text
-- so caller can fetch it again
self._text_to_draw = self.text
-- Note: we use kerning=true in all RenderText calls
--- @todo Don't use kerning for monospaced fonts. (houqp)
-- Compute width:
-- We never need to draw/size more than one screen width, so limit computation
-- to that width in case we are given some huge string
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self._text_to_draw, true, self.bold)
-- As text length includes last glyph pen "advance" (for positionning
-- next char), it's best to use math.floor() instead of math.ceil()
-- to get rid of a fraction of it in case this text is to be
-- horizontally centered
self._length = math.floor(tsize.x)
-- Ensure max_width, and truncate text if needed
if self.max_width and self._length > self.max_width then
if self.truncate_left then
-- We want to truncate text on the left, so work with the reverse of text.
-- We don't use kerning in this measurement as it might be different
-- on the reversed text. The final text will use kerning, and might get
-- a smaller width than the one found out here.
-- Also, not sure if this is correct when diacritics/clustered glyphs
-- happen at truncation point. But it will do for now.
local reversed_text = util.utf8Reverse(self._text_to_draw)
if self.truncate_with_ellipsis then
reversed_text = RenderText:truncateTextByWidth(reversed_text, self.face, self.max_width, false, self.bold)
else
reversed_text = RenderText:getSubTextByWidth(reversed_text, self.face, self.max_width, false, self.bold)
end
self._text_to_draw = util.utf8Reverse(reversed_text)
elseif self.truncate_with_ellipsis then
self._text_to_draw = RenderText:truncateTextByWidth(self._text_to_draw, self.face, self.max_width, true, self.bold)
end
-- Get the adjusted width when limiting to max_width (it might be
-- smaller than max_width when dropping the truncated glyph).
tsize = RenderText:sizeUtf8Text(0, self.max_width, self.face, self._text_to_draw, true, self.bold)
self._length = math.floor(tsize.x)
end
-- Compute height:
-- Used to be:
-- self._height = math.ceil(self.face.size * 1.5)
-- self._baseline_h = self._height*0.7
@ -68,10 +105,6 @@ function TextWidget:updateSize()
end
function TextWidget:getSize()
--if not self._bb then
--self:_render()
--end
--return { w = self._length, h = self._bb:getHeight() }
self:updateSize()
return Geom:new{
w = self._length,
@ -79,6 +112,11 @@ function TextWidget:getSize()
}
end
function TextWidget:getWidth()
self:updateSize()
return self._length
end
function TextWidget:getBaseline()
self:updateSize()
return self._baseline_h
@ -86,27 +124,18 @@ end
function TextWidget:setText(text)
self.text = text
self:updateSize()
self._updated = false
end
function TextWidget:paintTo(bb, x, y)
--if not self._bb then
--self:_render()
--end
--bb:blitFrom(self._bb, x, y, 0, 0, self._length, self._bb:getHeight())
--- @todo Don't use kerning for monospaced fonts. (houqp)
if self.max_width and RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold).x > self.max_width then
self.text = RenderText:truncateTextByWidth(self.text, self.face, self.max_width, true)
end
RenderText:renderUtf8Text(bb, x, y+self._baseline_h, self.face, self.text, true, self.bold,
self.fgcolor, self.max_width and self.max_width or self.width)
function TextWidget:setMaxWidth(max_width)
self.max_width = max_width
self._updated = false
end
function TextWidget:free()
if self._bb then
self._bb:free()
self._bb = nil
end
function TextWidget:paintTo(bb, x, y)
self:updateSize()
RenderText:renderUtf8Text(bb, x, y+self._baseline_h, self.face, self._text_to_draw, true, self.bold,
self.fgcolor, self._length)
end
return TextWidget

@ -14,7 +14,6 @@ local GestureRange = require("ui/gesturerange")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local InputContainer = require("ui/widget/container/inputcontainer")
local FrameContainer = require("ui/widget/container/framecontainer")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
@ -28,10 +27,6 @@ local ToggleLabel = TextWidget:new{
fgcolor = Blitbuffer.COLOR_BLACK,
}
function ToggleLabel:paintTo(bb, x, y)
RenderText:renderUtf8Text(bb, x, y+self._baseline_h, self.face, self.text, true, self.bold, self.fgcolor)
end
local ToggleSwitch = InputContainer:new{
width = Screen:scaleBySize(216),
height = Size.item.height_default,
@ -84,13 +79,10 @@ function ToggleSwitch:init()
end
local text = self.toggle[i]
local face = Font:getFace(self.font_face, self.font_size)
local txt_width = RenderText:sizeUtf8Text(0, Screen:getWidth(), face, text, true, true).x
if txt_width > real_item_width - item_padding then
text = RenderText:truncateTextByWidth(text, face, real_item_width - item_padding, true, true)
end
local label = ToggleLabel:new{
text = text,
face = face,
max_width = real_item_width - item_padding,
}
local content = CenterContainer:new{
dimen = Geom:new{

@ -19,7 +19,6 @@ local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local LineWidget = require("ui/widget/linewidget")
local RenderText = require("ui/rendertext")
local RightContainer = require("ui/widget/container/rightcontainer")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
@ -87,9 +86,6 @@ function TouchMenuItem:init()
-- 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)
if RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, text, true).x > text_max_width then
text = RenderText:truncateTextByWidth(text, self.face, text_max_width, true)
end
self.item_frame = FrameContainer:new{
width = self.dimen.w,
bordersize = 0,
@ -102,6 +98,7 @@ function TouchMenuItem:init()
},
TextWidget:new{
text = text,
max_width = text_max_width,
fgcolor = item_enabled ~= false and Blitbuffer.COLOR_BLACK or Blitbuffer.COLOR_DARK_GRAY,
face = self.face,
},

@ -18,7 +18,6 @@ local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TextWidget = require("ui/widget/textwidget")
@ -59,16 +58,14 @@ function TrapWidget:init()
}
end
if self.text then
local textw
local textw = TextWidget:new{
text = self.text,
face = self.face,
}
-- Don't make our message reach full screen width, so
-- it looks like popping from bottom left corner
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text)
if tsize.x < Screen:getWidth() * 0.9 then
textw = TextWidget:new{
text = self.text,
face = self.face,
}
else -- if text too wide, use TextBoxWidget for multi lines display
if textw:getWidth() > Screen:getWidth() * 0.9 then
-- Text too wide: use TextBoxWidget for multi lines display
textw = TextBoxWidget:new{
text = self.text,
face = self.face,

@ -95,7 +95,7 @@ function CoverMenu:updateItems(select_number)
self:updatePageInfo(select_number)
if self.show_path then
self.path_text.text = self:truncatePath(self.path)
self.path_text:setText(self.path)
end
self.show_parent.dithered = self._has_cover_images
UIManager:setDirty(self.show_parent, function()

@ -17,7 +17,6 @@ local LeftContainer = require("ui/widget/container/topcontainer")
local LineWidget = require("ui/widget/linewidget")
local LuaSettings = require("luasettings")
local OverlapGroup = require("ui/widget/overlapgroup")
local RenderText = require("ui/rendertext")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
@ -39,20 +38,12 @@ local DoubleKeyValueTitle = VerticalGroup:new{
function DoubleKeyValueTitle:init()
self.close_button = CloseButton:new{ window = self }
local btn_width = self.close_button:getSize().w
local title_txt_width = RenderText:sizeUtf8Text(
0, self.width, self.tface, self.title).x
local show_title_txt
if self.width < (title_txt_width + btn_width) then
show_title_txt = RenderText:truncateTextByWidth(
self.title, self.tface, self.width - btn_width)
else
show_title_txt = self.title
end
-- title and close button
table.insert(self, OverlapGroup:new{
dimen = { w = self.width },
TextWidget:new{
text = show_title_txt,
text = self.title,
max_width = self.width - btn_width,
face = self.tface,
},
self.close_button,
@ -114,7 +105,6 @@ local DoubleKeyValueItem = InputContainer:new{
function DoubleKeyValueItem:init()
self.dimen = Geom:new{align = "left", w = self.width, h = self.height}
local padding = Screen:scaleBySize(20)
if self.callback and Device:isTouchDevice() then
self.ges_events.Tap = {
GestureRange:new{
@ -123,18 +113,8 @@ function DoubleKeyValueItem:init()
}
}
end
local key_w = RenderText:sizeUtf8Text(0, self.width, self.cface_down, self.key).x
local value_w = RenderText:sizeUtf8Text(0, self.width, self.cface_up, self.value).x
if key_w > self.width - 2*padding then
self.show_key = RenderText:truncateTextByWidth(self.key, self.cface_down, self.width - 2*padding)
else
self.show_key = self.key
end
if value_w > self.width - 2*padding then
self.show_value = RenderText:truncateTextByWidth(self.value, self.cface_up, self.width - 2*padding)
else
self.show_value = self.value
end
local padding = Screen:scaleBySize(20)
local max_width = self.width - 2*padding
local h = self.dimen.h / 2
local w = self.dimen.w
self[1] = FrameContainer:new{
@ -147,7 +127,8 @@ function DoubleKeyValueItem:init()
padding = 0,
dimen = Geom:new{ h = h, w = w },
TextWidget:new{
text = self.show_value,
text = self.value,
max_width = max_width,
face = self.cface_up,
}
},
@ -155,7 +136,8 @@ function DoubleKeyValueItem:init()
padding = 0,
dimen = Geom:new{ h = h, w = w },
TextWidget:new{
text = self.show_key,
text = self.key,
max_width = max_width,
face = self.cface_down,
}
}

Loading…
Cancel
Save