GUITable: Scale images with display density / row height (#14709)

This commit is contained in:
grorp 2024-07-02 20:57:43 +02:00 committed by GitHub
parent 8ed55b3aff
commit fcb4f258f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 80 additions and 15 deletions

@ -3248,7 +3248,7 @@ Elements
* Types: `text`, `image`, `color`, `indent`, `tree` * Types: `text`, `image`, `color`, `indent`, `tree`
* `text`: show cell contents as text * `text`: show cell contents as text
* `image`: cell contents are an image index, use column options to define * `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 * `color`: cell contents are a ColorString and define color of following
cell. cell.
* `indent`: cell contents are a number and define indentation of following * `indent`: cell contents are a number and define indentation of following
@ -3269,7 +3269,7 @@ Elements
* `0=<value>` sets image for image index 0 * `0=<value>` sets image for image index 0
* `1=<value>` sets image for image index 1 * `1=<value>` sets image for image index 1
* `2=<value>` sets image for image index 2 * `2=<value>` 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`. non-numeric cells are treated as `0`.
* `color` column options: * `color` column options:
* `span=<value>`: number of following columns to affect * `span=<value>`: number of following columns to affect

@ -64,6 +64,41 @@ local inv_style_fs = [[
list[current_player;main;.5,7;8,4] 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 local hypertext_basic = [[A hypertext element
<bigger>Normal test</bigger> <bigger>Normal test</bigger>
This is a normal text. This is a normal text.
@ -350,6 +385,10 @@ local pages = {
"label[11,0.5;Noclip]" .. "label[11,0.5;Noclip]" ..
"container[11.5,1]" .. clip_fs:gsub("%%c", "true") .. "container_end[]", "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 -- Hypertext
"size[12,13]real_coordinates[true]" .. "size[12,13]real_coordinates[true]" ..
"container[0.5,0.5]" .. hypertext_fs .. "container_end[]", "container[0.5,0.5]" .. hypertext_fs .. "container_end[]",
@ -477,7 +516,7 @@ local function show_test_formspec(pname)
page = page() page = page()
end 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) minetest.show_formspec(pname, "testformspec:formspec", fs)
end end

@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IGUIFont.h> #include <IGUIFont.h>
#include "client/renderingengine.h" #include "client/renderingengine.h"
#include "debug.h" #include "debug.h"
#include "irrlicht_changes/CGUITTFont.h"
#include "log.h" #include "log.h"
#include "client/texturesource.h" #include "client/texturesource.h"
#include "gettime.h" #include "gettime.h"
@ -227,6 +228,8 @@ void GUITable::setTable(const TableOptions &options,
s32 content_index; s32 content_index;
// Next cell: Width in pixels // Next cell: Width in pixels
s32 content_width; s32 content_width;
// Next cell: Image scale (only for "image" column type)
f32 image_scale;
// Vector of completed cells in this row // Vector of completed cells in this row
std::vector<Cell> cells; std::vector<Cell> cells;
// Stores colors and how long they last (maximum column index) // 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]; TempRow *rows = new TempRow[rowcount];
CGUITTFont *ttfont = dynamic_cast<CGUITTFont *>(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 // Get em width. Pedantically speaking, the width of "M" is not
// necessarily the same as the em width, but whatever, close enough. // necessarily the same as the em width, but whatever, close enough.
s32 em = 6; s32 em = 6;
@ -373,8 +387,18 @@ void GUITable::setTable(const TableOptions &options,
if (row->content_index >= 0) if (row->content_index >= 0)
image = m_images[row->content_index]; 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 // Get content width and update xmax
row->content_width = image ? image->getOriginalSize().Width : 0;
row->content_width = MYMAX(row->content_width, width); row->content_width = MYMAX(row->content_width, width);
s32 row_xmax = row->x + padding + row->content_width; s32 row_xmax = row->x + padding + row->content_width;
xmax = MYMAX(xmax, row_xmax); xmax = MYMAX(xmax, row_xmax);
@ -384,6 +408,7 @@ void GUITable::setTable(const TableOptions &options,
newcell.xmin = rows[i].x + padding; newcell.xmin = rows[i].x + padding;
alignContent(&newcell, xmax, rows[i].content_width, align); alignContent(&newcell, xmax, rows[i].content_width, align);
newcell.content_index = rows[i].content_index; newcell.content_index = rows[i].content_index;
newcell.image_scale = rows[i].image_scale;
rows[i].cells.push_back(newcell); rows[i].cells.push_back(newcell);
rows[i].x = newcell.xmax; 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]; video::ITexture *image = m_images[cell->content_index];
if (image) { if (image) {
core::position2d<s32> dest_pos =
row_rect.UpperLeftCorner;
dest_pos.X += cell->xpos;
core::rect<s32> source_rect( core::rect<s32> source_rect(
core::position2d<s32>(0, 0), core::position2d<s32>(0, 0),
image->getOriginalSize()); image->getOriginalSize());
s32 imgh = source_rect.LowerRightCorner.Y; core::rect<s32> 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(); s32 rowh = row_rect.getHeight();
// Center vertically if needed
if (imgh < rowh) if (imgh < rowh)
dest_pos.Y += (rowh - imgh) / 2; dest_rect += v2s32(0, (rowh - imgh) / 2);
else
source_rect.LowerRightCorner.Y = rowh;
video::SColor color(255, 255, 255, 255); driver->draw2DImage(image, dest_rect, source_rect,
&client_clip, nullptr, true);
driver->draw2DImage(image, dest_pos, source_rect,
&client_clip, color, true);
} }
} }
} }

@ -166,6 +166,7 @@ protected:
video::SColor color; video::SColor color;
bool color_defined; bool color_defined;
s32 reported_column; s32 reported_column;
f32 image_scale; // only for "image" type columns
}; };
struct Row { struct Row {