Keyvaluepage: better alignment (#9672)

reviewable/pr9702/r1
weijiuqiao 2 years ago committed by GitHub
parent 1d9c81de6e
commit ad89742e9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -52,6 +52,8 @@ local KeyValueItem = InputContainer:extend{
value = nil,
value_lang = nil,
font_size = 20, -- will be adjusted depending on keyvalues_per_page
frame_padding = Size.padding.default,
middle_padding = Size.padding.default, -- min enforced padding between key and value
key_font_name = "smallinfofontbold",
value_font_name = "smallinfofont",
width = nil,
@ -75,14 +77,15 @@ function KeyValueItem:init()
local tvalue = tostring(self.value)
tvalue = tvalue:gsub("[\n\t]", "|")
local frame_padding = Size.padding.default
local frame_padding = self.frame_padding
local frame_internal_width = self.width - frame_padding * 2
local middle_padding = Size.padding.default -- min enforced padding between key and value
local middle_padding = self.middle_padding
local available_width = frame_internal_width - middle_padding
-- Default widths (and position of value widget) if each text fits in 1/2 screen width
local key_w = math.floor(frame_internal_width / 2 - middle_padding)
local value_w = math.floor(frame_internal_width / 2)
local ratio = self.width_ratio or 0.5
local key_w = math.floor(frame_internal_width * ratio - middle_padding)
local value_w = math.floor(frame_internal_width * (1-ratio))
local key_widget = TextWidget:new{
text = self.key,
@ -131,7 +134,8 @@ function KeyValueItem:init()
else
-- Both can fit: break the 1/2 widths
if self.value_align == "right" or self.value_overflow_align == "right_always"
or (self.value_overflow_align == "right" and value_w_rendered > value_w) then
or (self.value_overflow_align == "right" and value_w_rendered > value_w)
or key_w_rendered < key_w then -- it's the value that can't fit (longer), this way it stays closest to border
key_w = available_width - value_w_rendered
value_align_right = true
else
@ -468,7 +472,7 @@ function KeyValuePage:init()
local TextBoxWidget = require("ui/widget/textboxwidget")
local line_extra_height = 1.0 -- ~ 2em -- unscaled_size_check: ignore
-- (gives a font size similar to the fixed one from former implementation at 14 items per page)
self.items_font_size = TextBoxWidget:getFontSizeToFitHeight(self.item_height, 1, line_extra_height)
self.items_font_size = math.min(TextBoxWidget:getFontSizeToFitHeight(self.item_height, 1, line_extra_height), 22)
self.pages = math.ceil(#self.kv_pairs / self.items_per_page)
self.main_content = VerticalGroup:new{}
@ -543,6 +547,100 @@ function KeyValuePage:_populateItems()
self.return_button:resetLayout()
self.main_content:clear()
local idx_offset = (self.show_page - 1) * self.items_per_page
-- for flexible middle ratio calculation
-- in sync with KeyValueItem actual computation
local frame_padding = KeyValueItem.frame_padding
local frame_internal_width = self.item_width - frame_padding * 2
local middle_padding = KeyValueItem.middle_padding
local available_width = frame_internal_width - middle_padding
-- Default widths (and position of value widget) if each text fits in 1/2 screen width
local key_w = math.floor(frame_internal_width / 2 - middle_padding)
local value_w = math.floor(frame_internal_width / 2)
local key_widget = TextWidget:new{
text = " ",
max_width = available_width,
face = Font:getFace("smallinfofontbold", self.items_font_size),
}
local value_widget = TextWidget:new{
text = " ",
max_width = available_width,
face = Font:getFace("smallinfofont", self.items_font_size),
lang = self.values_lang,
}
local key_widths = {}
local value_widths = {}
local tvalue
for idx=1, self.items_per_page do
local kv_pairs_idx = idx_offset + idx
local entry = self.kv_pairs[kv_pairs_idx]
if entry == nil then break end
if type(entry) == "table" then
tvalue = tostring(entry[2])
tvalue = tvalue:gsub("[\n\t]", "|")
key_widget:setText(entry[1])
value_widget:setText(tvalue)
table.insert(key_widths, key_widget:getWidth())
table.insert(value_widths, value_widget:getWidth())
end
end
key_widget:free()
value_widget:free()
table.sort(key_widths)
table.sort(value_widths)
local unfit_items_count -- count item that needs to move or truncate key/value, not fit 1/2 ratio
-- first we check if no unfit item at all
local width_ratio
if key_widths[#key_widths] <= key_w and value_widths[#value_widths] <= value_w then
width_ratio = 1/2
end
if not width_ratio then
-- has to adjust, not fitting 1/2 ratio
local last_iter_key_index = #key_widths
for vi = #value_widths, 1, -1 do
-- from longest to shortest
local key_width_limit = available_width - value_widths[vi]
-- if we were to draw a vertical line at the start of the value item,
-- i.e. the border between keys and values, we want the less items cross it the better,
-- as the keys/values that cross the line (being cut) make clean alignment impossible
-- we track their number and find the line that cuts the least key/value items
local key_cut_count = 0
for ki = #key_widths, 1, -1 do
-- from longest to shortest for keys too
if key_widths[ki] > key_width_limit then
key_cut_count = key_cut_count + 1 -- got cut
else
last_iter_key_index = ki
break -- others are all shorter so no more cut
end
end
local total_cut_count = key_cut_count + (#value_widths - vi) -- latter is value_cut_count, as with each increased index, the previous one got cut
if unfit_items_count then -- not the first round of iteration
if total_cut_count >= unfit_items_count then
-- previous iteration has the least moved ones
width_ratio = (key_widths[last_iter_key_index] + middle_padding) / frame_internal_width
break
else
-- still could be less total cut ones
unfit_items_count = total_cut_count
end
elseif total_cut_count == 0 then
-- no cross-over, we take the longest key to compute ratio
width_ratio = (key_widths[#key_widths] + middle_padding) / frame_internal_width
break
else
unfit_items_count = total_cut_count
end
end
end
width_ratio = width_ratio or 0.5
for idx = 1, self.items_per_page do
local kv_pairs_idx = idx_offset + idx
local entry = self.kv_pairs[kv_pairs_idx]
@ -552,6 +650,7 @@ function KeyValuePage:_populateItems()
local kv_item = KeyValueItem:new{
height = self.item_height,
width = self.item_width,
width_ratio = width_ratio,
font_size = self.items_font_size,
key = entry[1],
value = entry[2],

Loading…
Cancel
Save