diff --git a/frontend/ui/widget/keyvaluepage.lua b/frontend/ui/widget/keyvaluepage.lua index b76d00b4e..0de3df5f8 100644 --- a/frontend/ui/widget/keyvaluepage.lua +++ b/frontend/ui/widget/keyvaluepage.lua @@ -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],