mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Keyvaluepage: better alignment (#9672)
This commit is contained in:
@@ -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],
|
||||
|
||||
Reference in New Issue
Block a user