From fcb4f258f57cbc0bf3d0e724c7fb3748d220ec5b Mon Sep 17 00:00:00 2001 From: grorp Date: Tue, 2 Jul 2024 20:57:43 +0200 Subject: [PATCH] GUITable: Scale images with display density / row height (#14709) --- doc/lua_api.md | 4 +- games/devtest/mods/testformspec/formspec.lua | 41 +++++++++++++++- src/gui/guiTable.cpp | 49 +++++++++++++++----- src/gui/guiTable.h | 1 + 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index f18f90921..5709109ab 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -3248,7 +3248,7 @@ Elements * Types: `text`, `image`, `color`, `indent`, `tree` * `text`: show cell contents as text * `image`: cell contents are an image index, use column options to define - images. + images. images are scaled down to fit the row height if necessary. * `color`: cell contents are a ColorString and define color of following cell. * `indent`: cell contents are a number and define indentation of following @@ -3269,7 +3269,7 @@ Elements * `0=` sets image for image index 0 * `1=` sets image for image index 1 * `2=` sets image for image index 2 - * and so on; defined indices need not be contiguous empty or + * and so on; defined indices need not be contiguous. empty or non-numeric cells are treated as `0`. * `color` column options: * `span=`: number of following columns to affect diff --git a/games/devtest/mods/testformspec/formspec.lua b/games/devtest/mods/testformspec/formspec.lua index c2074e6e0..99ee691f1 100644 --- a/games/devtest/mods/testformspec/formspec.lua +++ b/games/devtest/mods/testformspec/formspec.lua @@ -64,6 +64,41 @@ local inv_style_fs = [[ list[current_player;main;.5,7;8,4] ]] +-- Some textures from textures/base/pack and Devtest, with many different sizes +-- and aspect ratios. +local image_column = "image,0=logo.png,1=rare_controls.png,2=checkbox_16.png," .. + "3=checkbox_32.png,4=checkbox_64.png,5=default_lava.png," .. + "6=progress_bar.png,7=progress_bar_bg.png" +local words = { + "esciunt", "repudiandae", "repellat", "voluptatem", "autem", "vitae", "et", + "minima", "quasi", "facere", "nihil", "ea", "nemo", "rem", "non", "eos", + "laudantium", "eveniet", "veritatis", +} + +local reseed = math.random(2^31-1) +math.randomseed(1337) + +local table_content = {} +for i = 1, 100 do + table.insert(table_content, words[math.random(#words)]) + table.insert(table_content, words[math.random(#words)]) + table.insert(table_content, words[math.random(#words)]) + table.insert(table_content, math.random(0, 7)) + table.insert(table_content, math.random(0, 7)) + table.insert(table_content, math.random(0, 7)) + table.insert(table_content, words[math.random(#words)]) +end + +math.randomseed(reseed) + +local table_fs = table.concat({ + "tablecolumns[text,align=left;text,align=right;text,align=center;", + image_column, ",align=left;", + image_column, ",align=right;", + image_column, ",align=center;text,align=right]", + "table[0,0;17,12;the_table;", table.concat(table_content, ","), ";1]" +}) + local hypertext_basic = [[A hypertext element Normal test This is a normal text. @@ -350,6 +385,10 @@ local pages = { "label[11,0.5;Noclip]" .. "container[11.5,1]" .. clip_fs:gsub("%%c", "true") .. "container_end[]", + -- Table + "size[18,13]real_coordinates[true]" .. + "container[0.5,0.5]" .. table_fs.. "container_end[]", + -- Hypertext "size[12,13]real_coordinates[true]" .. "container[0.5,0.5]" .. hypertext_fs .. "container_end[]", @@ -477,7 +516,7 @@ local function show_test_formspec(pname) page = page() end - local fs = page .. "tabheader[0,0;11,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Invs,Window,Anim,Model,ScrollC,Sound,Background,Unsized;" .. page_id .. ";false;false]" + local fs = page .. "tabheader[0,0;11,0.65;maintabs;Real Coord,Styles,Noclip,Table,Hypertext,Tabs,Invs,Window,Anim,Model,ScrollC,Sound,Background,Unsized;" .. page_id .. ";false;false]" minetest.show_formspec(pname, "testformspec:formspec", fs) end diff --git a/src/gui/guiTable.cpp b/src/gui/guiTable.cpp index 93a56ed3c..a58020300 100644 --- a/src/gui/guiTable.cpp +++ b/src/gui/guiTable.cpp @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "client/renderingengine.h" #include "debug.h" +#include "irrlicht_changes/CGUITTFont.h" #include "log.h" #include "client/texturesource.h" #include "gettime.h" @@ -227,6 +228,8 @@ void GUITable::setTable(const TableOptions &options, s32 content_index; // Next cell: Width in pixels s32 content_width; + // Next cell: Image scale (only for "image" column type) + f32 image_scale; // Vector of completed cells in this row std::vector cells; // Stores colors and how long they last (maximum column index) @@ -236,6 +239,17 @@ void GUITable::setTable(const TableOptions &options, }; TempRow *rows = new TempRow[rowcount]; + CGUITTFont *ttfont = dynamic_cast(m_font); + f32 desired_image_scale = 1.0f; + if (ttfont) { + // This gives us the effective font size, which is chosen taking display + // density and gui_scaling into account. + // Since row height scales with font size, this gives better results than + // just using display density and gui_scaling when a non-standard font + // size is used (e.g. Android default of 14). + desired_image_scale = std::max(1.0f, ttfont->getFontSize() / 16.0f); + } + // Get em width. Pedantically speaking, the width of "M" is not // necessarily the same as the em width, but whatever, close enough. s32 em = 6; @@ -373,8 +387,18 @@ void GUITable::setTable(const TableOptions &options, if (row->content_index >= 0) image = m_images[row->content_index]; + row->image_scale = 1.0f; + row->content_width = 0; + if (image) { + f32 max_image_scale = (f32)m_rowheight / (f32)image->getOriginalSize().Height; + // Scale with display density and make sure it fits into the row + row->image_scale = std::min(desired_image_scale, max_image_scale); + // When upscaling, fractional factors would cause artifacts + if (row->image_scale > 1.0f) + row->image_scale = std::floor(row->image_scale); + row->content_width = image->getOriginalSize().Width * row->image_scale; + } // Get content width and update xmax - row->content_width = image ? image->getOriginalSize().Width : 0; row->content_width = MYMAX(row->content_width, width); s32 row_xmax = row->x + padding + row->content_width; xmax = MYMAX(xmax, row_xmax); @@ -384,6 +408,7 @@ void GUITable::setTable(const TableOptions &options, newcell.xmin = rows[i].x + padding; alignContent(&newcell, xmax, rows[i].content_width, align); newcell.content_index = rows[i].content_index; + newcell.image_scale = rows[i].image_scale; rows[i].cells.push_back(newcell); rows[i].x = newcell.xmax; } @@ -740,23 +765,23 @@ void GUITable::drawCell(const Cell *cell, video::SColor color, video::ITexture *image = m_images[cell->content_index]; if (image) { - core::position2d dest_pos = - row_rect.UpperLeftCorner; - dest_pos.X += cell->xpos; core::rect source_rect( core::position2d(0, 0), image->getOriginalSize()); - s32 imgh = source_rect.LowerRightCorner.Y; + core::rect dest_rect( + 0, 0, + image->getOriginalSize().Width * cell->image_scale, + image->getOriginalSize().Height * cell->image_scale); + dest_rect += row_rect.UpperLeftCorner + v2s32(cell->xpos, 0); + + s32 imgh = dest_rect.getHeight(); s32 rowh = row_rect.getHeight(); + // Center vertically if needed if (imgh < rowh) - dest_pos.Y += (rowh - imgh) / 2; - else - source_rect.LowerRightCorner.Y = rowh; + dest_rect += v2s32(0, (rowh - imgh) / 2); - video::SColor color(255, 255, 255, 255); - - driver->draw2DImage(image, dest_pos, source_rect, - &client_clip, color, true); + driver->draw2DImage(image, dest_rect, source_rect, + &client_clip, nullptr, true); } } } diff --git a/src/gui/guiTable.h b/src/gui/guiTable.h index 76a0e94d0..271649ff2 100644 --- a/src/gui/guiTable.h +++ b/src/gui/guiTable.h @@ -166,6 +166,7 @@ protected: video::SColor color; bool color_defined; s32 reported_column; + f32 image_scale; // only for "image" type columns }; struct Row {