mirror of
https://github.com/minetest/minetest.git
synced 2024-12-22 06:02:23 +01:00
Improve formspec scaling (#14840)
This commit is contained in:
parent
1527cdf6a4
commit
041d67ceca
@ -28,10 +28,8 @@ local function buttonbar_formspec(self)
|
||||
end
|
||||
|
||||
local formspec = {
|
||||
"style_type[box;noclip=true]",
|
||||
string.format("box[%f,%f;%f,%f;%s]", self.pos.x, self.pos.y, self.size.x,
|
||||
self.size.y, self.bgcolor),
|
||||
"style_type[box;noclip=false]",
|
||||
}
|
||||
|
||||
local btn_size = self.size.y - 2*BASE_SPACING
|
||||
@ -71,7 +69,7 @@ local function buttonbar_formspec(self)
|
||||
y = self.pos.y + BASE_SPACING,
|
||||
}
|
||||
|
||||
table.insert(formspec, string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;false]tooltip[%s;%s]",
|
||||
table.insert(formspec, string.format("image_button[%f,%f;%f,%f;%s;%s;%s;false;false]tooltip[%s;%s]",
|
||||
btn_pos.x, btn_pos.y, btn_size, btn_size, btn.image, btn.name,
|
||||
btn.caption, btn.name, btn.tooltip))
|
||||
end
|
||||
@ -86,9 +84,6 @@ local function buttonbar_formspec(self)
|
||||
y = self.pos.y + BASE_SPACING,
|
||||
}
|
||||
|
||||
table.insert(formspec, string.format("style[%s,%s;noclip=true]",
|
||||
self.btn_prev_name, self.btn_next_name))
|
||||
|
||||
table.insert(formspec, string.format("button[%f,%f;%f,%f;%s;<]",
|
||||
btn_prev_pos.x, btn_prev_pos.y, get_scroll_btn_width(), btn_size,
|
||||
self.btn_prev_name))
|
||||
|
@ -66,11 +66,22 @@ local function get_formspec(self)
|
||||
|
||||
local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize)
|
||||
|
||||
local tsize = tab.tabsize or { width = self.width, height = self.height }
|
||||
local ENABLE_TOUCH = core.settings:get_bool("enable_touch")
|
||||
|
||||
local orig_tsize = tab.tabsize or { width = self.width, height = self.height }
|
||||
local tsize = { width = orig_tsize.width, height = orig_tsize.height }
|
||||
tsize.height = tsize.height
|
||||
+ TABHEADER_H -- tabheader included in formspec size
|
||||
+ (ENABLE_TOUCH and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP)
|
||||
+ GAMEBAR_H -- gamebar included in formspec size
|
||||
|
||||
if self.parent == nil and not prepend then
|
||||
prepend = string.format("size[%f,%f,%s]", tsize.width, tsize.height,
|
||||
dump(self.fixed_size))
|
||||
|
||||
local anchor_pos = TABHEADER_H + orig_tsize.height / 2
|
||||
prepend = prepend .. ("anchor[0.5,%f]"):format(anchor_pos / tsize.height)
|
||||
|
||||
if tab.formspec_version then
|
||||
prepend = ("formspec_version[%d]"):format(tab.formspec_version) .. prepend
|
||||
end
|
||||
@ -78,12 +89,15 @@ local function get_formspec(self)
|
||||
|
||||
local end_button_size = 0.75
|
||||
|
||||
local tab_header_size = { width = tsize.width, height = 0.85 }
|
||||
local tab_header_size = { width = tsize.width, height = TABHEADER_H }
|
||||
if self.end_button then
|
||||
tab_header_size.width = tab_header_size.width - end_button_size - 0.1
|
||||
end
|
||||
|
||||
local formspec = (prepend or "") .. self:tab_header(tab_header_size) .. content
|
||||
local formspec = (prepend or "")
|
||||
formspec = formspec .. ("bgcolor[;neither]container[0,%f]box[0,0;%f,%f;#0000008C]"):format(
|
||||
TABHEADER_H, orig_tsize.width, orig_tsize.height)
|
||||
formspec = formspec .. self:tab_header(tab_header_size) .. content
|
||||
|
||||
if self.end_button then
|
||||
formspec = formspec ..
|
||||
@ -98,6 +112,8 @@ local function get_formspec(self)
|
||||
self.end_button.name)
|
||||
end
|
||||
|
||||
formspec = formspec .. "container_end[]"
|
||||
|
||||
return formspec
|
||||
end
|
||||
|
||||
|
@ -23,6 +23,13 @@ mt_color_dark_green = "#25C191"
|
||||
mt_color_orange = "#FF8800"
|
||||
mt_color_red = "#FF3300"
|
||||
|
||||
MAIN_TAB_W = 15.5
|
||||
MAIN_TAB_H = 7.1
|
||||
TABHEADER_H = 0.85
|
||||
GAMEBAR_H = 1.25
|
||||
GAMEBAR_OFFSET_DESKTOP = 0.375
|
||||
GAMEBAR_OFFSET_TOUCH = 0.15
|
||||
|
||||
local menupath = core.get_mainmenu_path()
|
||||
local basepath = core.get_builtin_path()
|
||||
defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
|
||||
@ -89,7 +96,7 @@ local function init_globals()
|
||||
mm_game_theme.set_engine() -- This is just a fallback.
|
||||
|
||||
-- Create main tabview
|
||||
local tv_main = tabview_create("maintab", {x = 15.5, y = 7.1}, {x = 0, y = 0})
|
||||
local tv_main = tabview_create("maintab", {x = MAIN_TAB_W, y = MAIN_TAB_H}, {x = 0, y = 0})
|
||||
|
||||
tv_main:set_autosave_tab(true)
|
||||
tv_main:add(tabs.local_game)
|
||||
|
@ -92,10 +92,16 @@ function singleplayer_refresh_gamebar()
|
||||
end
|
||||
end
|
||||
|
||||
local ENABLE_TOUCH = core.settings:get_bool("enable_touch")
|
||||
|
||||
local gamebar_pos_y = MAIN_TAB_H
|
||||
+ TABHEADER_H -- tabheader included in formspec size
|
||||
+ (ENABLE_TOUCH and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP)
|
||||
|
||||
local btnbar = buttonbar_create(
|
||||
"game_button_bar",
|
||||
core.settings:get_bool("touch_gui") and {x = 0, y = 7.25} or {x = 0, y = 7.475},
|
||||
{x = 15.5, y = 1.25},
|
||||
{x = 0, y = gamebar_pos_y},
|
||||
{x = MAIN_TAB_W, y = GAMEBAR_H},
|
||||
"#000000",
|
||||
game_buttonbar_button_handler)
|
||||
|
||||
|
@ -5580,8 +5580,8 @@ Utilities
|
||||
},
|
||||
|
||||
-- Estimated maximum formspec size before Minetest will start shrinking the
|
||||
-- formspec to fit. For a fullscreen formspec, use a size 10-20% larger than
|
||||
-- this and `padding[-0.01,-0.01]`.
|
||||
-- formspec to fit. For a fullscreen formspec, use this formspec size and
|
||||
-- `padding[0,0]`. `bgcolor[;true]` is also recommended.
|
||||
max_formspec_size = {
|
||||
x = 20,
|
||||
y = 11.25
|
||||
|
@ -253,8 +253,8 @@ GUI
|
||||
},
|
||||
|
||||
-- Estimated maximum formspec size before Minetest will start shrinking the
|
||||
-- formspec to fit. For a fullscreen formspec, use a size 10-20% larger than
|
||||
-- this and `padding[-0.01,-0.01]`.
|
||||
-- formspec to fit. For a fullscreen formspec, use this formspec size and
|
||||
-- `padding[0,0]`. `bgcolor[;true]` is also recommended.
|
||||
max_formspec_size = {
|
||||
x = 20,
|
||||
y = 11.25
|
||||
|
@ -1,18 +1,30 @@
|
||||
local function show_fullscreen_fs(name)
|
||||
local window = minetest.get_player_window_information(name)
|
||||
if not window then
|
||||
return false, "Unable to get window info"
|
||||
end
|
||||
local function window_info_equal(a, b)
|
||||
return
|
||||
-- size
|
||||
a.size.x == b.size.x and a.size.y == b.size.y and
|
||||
-- real_gui_scaling, real_hud_scaling
|
||||
a.real_gui_scaling == b.real_gui_scaling and
|
||||
a.real_hud_scaling == b.real_hud_scaling and
|
||||
-- max_formspec_size
|
||||
a.max_formspec_size.x == b.max_formspec_size.x and
|
||||
a.max_formspec_size.y == b.max_formspec_size.y and
|
||||
-- touch_controls
|
||||
a.touch_controls == b.touch_controls
|
||||
end
|
||||
|
||||
local last_window_info = {}
|
||||
|
||||
local function show_fullscreen_fs(name, window)
|
||||
print(dump(window))
|
||||
|
||||
local size = { x = window.max_formspec_size.x * 1.1, y = window.max_formspec_size.y * 1.1 }
|
||||
local size = window.max_formspec_size
|
||||
local touch_text = window.touch_controls and "Touch controls enabled" or
|
||||
"Touch controls disabled"
|
||||
local fs = {
|
||||
"formspec_version[4]",
|
||||
("size[%f,%f]"):format(size.x, size.y),
|
||||
"padding[-0.01,-0.01]",
|
||||
"padding[0,0]",
|
||||
"bgcolor[;true]",
|
||||
("button[%f,%f;1,1;%s;%s]"):format(0, 0, "tl", "TL"),
|
||||
("button[%f,%f;1,1;%s;%s]"):format(size.x - 1, 0, "tr", "TR"),
|
||||
("button[%f,%f;1,1;%s;%s]"):format(size.x - 1, size.y - 1, "br", "BR"),
|
||||
@ -23,10 +35,37 @@ local function show_fullscreen_fs(name)
|
||||
}
|
||||
|
||||
minetest.show_formspec(name, "testfullscreenfs:fs", table.concat(fs))
|
||||
return true, ("Calculated size of %f, %f"):format(size.x, size.y)
|
||||
minetest.chat_send_player(name, ("Calculated size of %f, %f"):format(size.x, size.y))
|
||||
last_window_info[name] = window
|
||||
end
|
||||
|
||||
|
||||
minetest.register_chatcommand("testfullscreenfs", {
|
||||
func = show_fullscreen_fs,
|
||||
func = function(name)
|
||||
local window = minetest.get_player_window_information(name)
|
||||
if not window then
|
||||
return false, "Unable to get window info"
|
||||
end
|
||||
|
||||
show_fullscreen_fs(name, window)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
for name, last_window in pairs(last_window_info) do
|
||||
local window = minetest.get_player_window_information(name)
|
||||
if window and not window_info_equal(last_window, window) then
|
||||
show_fullscreen_fs(name, window)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname == "testfullscreenfs:fs" and fields.quit then
|
||||
last_window_info[player:get_player_name()] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
last_window_info[player:get_player_name()] = nil
|
||||
end)
|
||||
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "settings.h"
|
||||
#include "client/renderingengine.h"
|
||||
#include "gui/guiFormSpecMenu.h"
|
||||
#include "gui/touchcontrols.h"
|
||||
|
||||
ClientDynamicInfo ClientDynamicInfo::getCurrent()
|
||||
@ -37,19 +38,22 @@ ClientDynamicInfo ClientDynamicInfo::getCurrent()
|
||||
|
||||
return {
|
||||
screen_size, real_gui_scaling, real_hud_scaling,
|
||||
ClientDynamicInfo::calculateMaxFSSize(screen_size, gui_scaling),
|
||||
ClientDynamicInfo::calculateMaxFSSize(screen_size, density, gui_scaling),
|
||||
touch_controls
|
||||
};
|
||||
}
|
||||
|
||||
v2f32 ClientDynamicInfo::calculateMaxFSSize(v2u32 render_target_size, f32 gui_scaling)
|
||||
v2f32 ClientDynamicInfo::calculateMaxFSSize(v2u32 render_target_size, f32 density, f32 gui_scaling)
|
||||
{
|
||||
f32 factor = (g_settings->getBool("touch_gui") ? 10 : 15) / gui_scaling;
|
||||
f32 ratio = (f32)render_target_size.X / (f32)render_target_size.Y;
|
||||
if (ratio < 1)
|
||||
return { factor, factor / ratio };
|
||||
else
|
||||
return { factor * ratio, factor };
|
||||
// must stay in sync with GUIFormSpecMenu::calculateImgsize
|
||||
|
||||
const double screen_dpi = density * 96;
|
||||
|
||||
// assume padding[0,0] since max_formspec_size is used for fullscreen formspecs
|
||||
double prefer_imgsize = GUIFormSpecMenu::getImgsize(render_target_size,
|
||||
screen_dpi, gui_scaling);
|
||||
return v2f32(render_target_size.X / prefer_imgsize,
|
||||
render_target_size.Y / prefer_imgsize);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -42,6 +42,6 @@ public:
|
||||
static ClientDynamicInfo getCurrent();
|
||||
|
||||
private:
|
||||
static v2f32 calculateMaxFSSize(v2u32 render_target_size, f32 gui_scaling);
|
||||
static v2f32 calculateMaxFSSize(v2u32 render_target_size, f32 density, f32 gui_scaling);
|
||||
#endif
|
||||
};
|
||||
|
@ -3133,58 +3133,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
offset = v2s32(0,0);
|
||||
}
|
||||
|
||||
const double gui_scaling = g_settings->getFloat("gui_scaling", 0.5f, 42.0f);
|
||||
const double screen_dpi = RenderingEngine::getDisplayDensity() * 96;
|
||||
|
||||
double use_imgsize;
|
||||
if (m_lock) {
|
||||
// In fixed-size mode, inventory image size
|
||||
// is 0.53 inch multiplied by the gui_scaling
|
||||
// config parameter. This magic size is chosen
|
||||
// to make the main menu (15.5 inventory images
|
||||
// wide, including border) just fit into the
|
||||
// default window (800 pixels wide) at 96 DPI
|
||||
// and default scaling (1.00).
|
||||
use_imgsize = 0.5555 * screen_dpi * gui_scaling;
|
||||
} else {
|
||||
// Variables for the maximum imgsize that can fit in the screen.
|
||||
double fitx_imgsize;
|
||||
double fity_imgsize;
|
||||
|
||||
v2f padded_screensize(
|
||||
mydata.screensize.X * (1.0f - mydata.padding.X * 2.0f),
|
||||
mydata.screensize.Y * (1.0f - mydata.padding.Y * 2.0f)
|
||||
);
|
||||
|
||||
if (mydata.real_coordinates) {
|
||||
fitx_imgsize = padded_screensize.X / mydata.invsize.X;
|
||||
fity_imgsize = padded_screensize.Y / mydata.invsize.Y;
|
||||
} else {
|
||||
// The maximum imgsize in the old coordinate system also needs to
|
||||
// factor in padding and spacing along with 0.1 inventory slot spare
|
||||
// and help text space, hence the magic numbers.
|
||||
fitx_imgsize = padded_screensize.X /
|
||||
((5.0 / 4.0) * (0.5 + mydata.invsize.X));
|
||||
fity_imgsize = padded_screensize.Y /
|
||||
((15.0 / 13.0) * (0.85 + mydata.invsize.Y));
|
||||
}
|
||||
|
||||
s32 min_screen_dim = std::min(padded_screensize.X, padded_screensize.Y);
|
||||
|
||||
double prefer_imgsize;
|
||||
if (g_settings->getBool("touch_gui")) {
|
||||
// The preferred imgsize should be larger to accommodate the
|
||||
// smaller screensize.
|
||||
prefer_imgsize = min_screen_dim / 10 * gui_scaling;
|
||||
} else {
|
||||
// Desktop computers have more space, so try to fit 15 coordinates.
|
||||
prefer_imgsize = min_screen_dim / 15 * gui_scaling;
|
||||
}
|
||||
// Try to use the preferred imgsize, but if that's bigger than the maximum
|
||||
// size, use the maximum size.
|
||||
use_imgsize = std::min(prefer_imgsize,
|
||||
std::min(fitx_imgsize, fity_imgsize));
|
||||
}
|
||||
double use_imgsize = calculateImgsize(mydata);
|
||||
|
||||
// Everything else is scaled in proportion to the
|
||||
// inventory image size. The inventory slot spacing
|
||||
@ -5072,3 +5021,68 @@ std::array<StyleSpec, StyleSpec::NUM_STATES> GUIFormSpecMenu::getStyleForElement
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
double GUIFormSpecMenu::getFixedImgsize(double screen_dpi, double gui_scaling)
|
||||
{
|
||||
// In fixed-size mode, inventory image size
|
||||
// is 0.53 inch multiplied by the gui_scaling
|
||||
// config parameter. This magic size is chosen
|
||||
// to make the main menu (15.5 inventory images
|
||||
// wide, including border) just fit into the
|
||||
// default window (800 pixels wide) at 96 DPI
|
||||
// and default scaling (1.00).
|
||||
return 0.5555 * screen_dpi * gui_scaling;
|
||||
}
|
||||
|
||||
double GUIFormSpecMenu::getImgsize(v2u32 avail_screensize, double screen_dpi, double gui_scaling)
|
||||
{
|
||||
double fixed_imgsize = getFixedImgsize(screen_dpi, gui_scaling);
|
||||
|
||||
s32 min_screen_dim = std::min(avail_screensize.X, avail_screensize.Y);
|
||||
double prefer_imgsize = min_screen_dim / 15 * gui_scaling;
|
||||
// Use the available space more effectively on small windows/screens.
|
||||
// This is especially important for mobile platforms.
|
||||
prefer_imgsize = std::max(prefer_imgsize, fixed_imgsize);
|
||||
return prefer_imgsize;
|
||||
}
|
||||
|
||||
double GUIFormSpecMenu::calculateImgsize(const parserData &data)
|
||||
{
|
||||
// must stay in sync with ClientDynamicInfo::calculateMaxFSSize
|
||||
|
||||
const double screen_dpi = RenderingEngine::getDisplayDensity() * 96;
|
||||
const double gui_scaling = g_settings->getFloat("gui_scaling", 0.5f, 42.0f);
|
||||
|
||||
// Fixed-size mode
|
||||
if (m_lock)
|
||||
return getFixedImgsize(screen_dpi, gui_scaling);
|
||||
|
||||
// Variables for the maximum imgsize that can fit in the screen.
|
||||
double fitx_imgsize;
|
||||
double fity_imgsize;
|
||||
|
||||
v2f padded_screensize(
|
||||
data.screensize.X * (1.0f - data.padding.X * 2.0f),
|
||||
data.screensize.Y * (1.0f - data.padding.Y * 2.0f)
|
||||
);
|
||||
|
||||
if (data.real_coordinates) {
|
||||
fitx_imgsize = padded_screensize.X / data.invsize.X;
|
||||
fity_imgsize = padded_screensize.Y / data.invsize.Y;
|
||||
} else {
|
||||
// The maximum imgsize in the old coordinate system also needs to
|
||||
// factor in padding and spacing along with 0.1 inventory slot spare
|
||||
// and help text space, hence the magic numbers.
|
||||
fitx_imgsize = padded_screensize.X /
|
||||
((5.0 / 4.0) * (0.5 + data.invsize.X));
|
||||
fity_imgsize = padded_screensize.Y /
|
||||
((15.0 / 13.0) * (0.85 + data.invsize.Y));
|
||||
}
|
||||
|
||||
double prefer_imgsize = getImgsize(v2u32(padded_screensize.X, padded_screensize.Y),
|
||||
screen_dpi, gui_scaling);
|
||||
|
||||
// Try to use the preferred imgsize, but if that's bigger than the maximum
|
||||
// size, use the maximum size.
|
||||
return std::min(prefer_imgsize, std::min(fitx_imgsize, fity_imgsize));
|
||||
}
|
||||
|
@ -296,6 +296,11 @@ public:
|
||||
void getAndroidUIInput();
|
||||
#endif
|
||||
|
||||
// Returns the fixed formspec coordinate size for the given parameters.
|
||||
static double getFixedImgsize(double screen_dpi, double gui_scaling);
|
||||
// Returns the preferred non-fixed formspec coordinate size for the given parameters.
|
||||
static double getImgsize(v2u32 avail_screensize, double screen_dpi, double gui_scaling);
|
||||
|
||||
protected:
|
||||
v2s32 getBasePos() const
|
||||
{
|
||||
@ -514,6 +519,9 @@ private:
|
||||
|
||||
// used by getAbsoluteRect
|
||||
s32 m_tabheader_upper_edge = 0;
|
||||
|
||||
// Determines the size (in pixels) of formspec coordinate units.
|
||||
double calculateImgsize(const parserData &data);
|
||||
};
|
||||
|
||||
class FormspecFormSource: public IFormSource
|
||||
|
Loading…
Reference in New Issue
Block a user