diff --git a/frontend/ui/rendertext.lua b/frontend/ui/rendertext.lua index 30d1e517a..14f5cc47d 100644 --- a/frontend/ui/rendertext.lua +++ b/frontend/ui/rendertext.lua @@ -9,7 +9,7 @@ local BlitBuffer = require("ffi/blitbuffer") local DEBUG = require("dbg") --[[ -TODO: all these functions should probably be methods on Face objects +@TODO: all these functions should probably be methods on Face objects ]]-- local RenderText = {} @@ -99,9 +99,18 @@ function RenderText:getGlyph(face, charcode, bold) return rendered_glyph end +--- Return a substring of a given text that meets the maximum width (in pixels) +-- restriction. +-- +-- @string text text to truncate +-- @tparam ui.font.FontFaceObj face font face for the text +-- @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 +-- @treturn string function RenderText:getSubTextByWidth(text, face, width, kerning, bold) local pen_x = 0 - local prevcharcode = 0 + local prevcharcode local char_list = {} for _, charcode, uchar in utf8Chars(text) do if pen_x < width then @@ -127,13 +136,13 @@ end -- Note this function does not render the text into a bitmap. Use it if you -- only care about the size for the rendered result. -- ----- @int x start position for a given text (within maxium width) ----- @int width maxium rendering width (think of it as size of the bitmap) ----- @tparam ui.font.FontFaceObj face font face that will be used for rendering ----- @string text text to measure ----- @bool[opt=false] kerning whether the text should be measured with kerning ----- @bool[opt=false] bold whether the text should be measured as bold ----- @treturn RenderTextSize +-- @int x start position for a given text (within maximum width) +-- @int width maximum rendering width in pixels (think of it as size of the bitmap) +-- @tparam ui.font.FontFaceObj face font face that will be used for rendering +-- @string text text to measure +-- @bool[opt=false] kerning whether the text should be measured with kerning +-- @bool[opt=false] bold whether the text should be measured as bold +-- @treturn RenderTextSize function RenderText:sizeUtf8Text(x, width, face, text, kerning, bold) if not text then DEBUG("sizeUtf8Text called without text"); diff --git a/frontend/ui/widget/keyvaluepage.lua b/frontend/ui/widget/keyvaluepage.lua index 9ad9a9d2b..e2c394f18 100644 --- a/frontend/ui/widget/keyvaluepage.lua +++ b/frontend/ui/widget/keyvaluepage.lua @@ -32,25 +32,56 @@ local CloseButton = require("ui/widget/closebutton") local UIManager = require("ui/uimanager") local TextWidget = require("ui/widget/textwidget") local GestureRange = require("ui/gesturerange") +local RenderText = require("ui/rendertext") local Geom = require("ui/geometry") local Font = require("ui/font") local Device = require("device") local Screen = Device.screen +local ellipsis, space = "...", " " +local ellipsis_width, space_width +function truncateTextByWidth(text, face, max_width, prepend_space) + if not ellipsis_width then + ellipsis_width = RenderText:sizeUtf8Text(0, max_width, face, ellipsis).x + end + if not space_width then + space_width = RenderText:sizeUtf8Text(0, max_width, face, space).x + end + local new_txt_width = max_width - ellipsis_width - space_width + local sub_txt = RenderText:getSubTextByWidth(text, face, new_txt_width) + if prepend_space then + return space.. sub_txt .. ellipsis + else + return sub_txt .. ellipsis .. space + end +end + + local KeyValueTitle = VerticalGroup:new{ kv_page = nil, title = "", + tface = Font:getFace("tfont"), align = "left", } 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 = truncateTextByWidth( + self.title, self.tface, self.width-btn_width) + else + show_title_txt = self.title + end table.insert(self, OverlapGroup:new{ dimen = { w = self.width }, TextWidget:new{ - text = self.title, - face = Font:getFace("tfont", 26), + text = show_title_txt, + face = self.tface, }, self.close_button, }) @@ -100,7 +131,7 @@ end local KeyValueItem = InputContainer:new{ key = nil, value = nil, - cface = Font:getFace("cfont", 24), + cface = Font:getFace("cfont"), width = nil, height = nil, } @@ -117,20 +148,40 @@ function KeyValueItem:init() } end - self[1] = OverlapGroup:new{ - dimen = self.dimen:copy(), - LeftContainer:new{ + local key_w = RenderText:sizeUtf8Text(0, self.width, self.cface, self.key).x + local value_w = RenderText:sizeUtf8Text(0, self.width, self.cface, self.value).x + if key_w + value_w > self.width then + -- truncate key or value so they fits in one row + if key_w >= value_w then + self.show_key = truncateTextByWidth(self.key, self.cface, self.width-value_w) + self.show_value = self.value + else + self.show_value = truncateTextByWidth(self.value, self.cface, self.width-key_w, true) + self.show_key = self.key + end + else + self.show_key = self.key + self.show_value = self.value + end + + self[1] = FrameContainer:new{ + padding = 0, + bordersize = 0, + OverlapGroup:new{ dimen = self.dimen:copy(), - TextWidget:new{ - text = self.key, - face = self.cface, - } - }, - RightContainer:new{ - dimen = self.dimen:copy(), - TextWidget:new{ - text = self.value, - face = self.cface, + LeftContainer:new{ + dimen = self.dimen:copy(), + TextWidget:new{ + text = self.show_key, + face = self.cface, + } + }, + RightContainer:new{ + dimen = self.dimen:copy(), + TextWidget:new{ + text = self.show_value, + face = self.cface, + } } } } @@ -176,8 +227,8 @@ function KeyValuePage:init() kv_page = self, } -- setup main content - self.item_padding = self.item_height / 4 - local line_height = self.item_height + 2 * self.item_padding + self.item_margin = self.item_height / 4 + local line_height = self.item_height + 2 * self.item_margin local content_height = self.dimen.h - self.title_bar:getSize().h self.items_per_page = math.floor(content_height / line_height) self.pages = math.ceil(#self.kv_pairs / self.items_per_page) @@ -212,7 +263,7 @@ function KeyValuePage:prevPage() end end --- make sure self.item_padding and self.item_height are set before calling this +-- make sure self.item_margin and self.item_height are set before calling this function KeyValuePage:_populateItems() self.main_content:clear() local idx_offset = (self.show_page - 1) * self.items_per_page @@ -221,7 +272,7 @@ function KeyValuePage:_populateItems() if entry == nil then break end table.insert(self.main_content, - VerticalSpan:new{ width = self.item_padding }) + VerticalSpan:new{ width = self.item_margin }) if type(entry) == "table" then table.insert( self.main_content, @@ -247,7 +298,7 @@ function KeyValuePage:_populateItems() end end table.insert(self.main_content, - VerticalSpan:new{ width = self.item_padding }) + VerticalSpan:new{ width = self.item_margin }) end self.title_bar:setPageCount(self.show_page, self.pages) UIManager:setDirty(self, function()