diff --git a/doc/en/scripting/builtins/libgui.md b/doc/en/scripting/builtins/libgui.md
index 3dc10612b..e3a97675d 100644
--- a/doc/en/scripting/builtins/libgui.md
+++ b/doc/en/scripting/builtins/libgui.md
@@ -16,6 +16,17 @@ gui.str(text: str, context: str) -> str
-- Returns size of the main container (window).
gui.get_viewport() -> {int, int}
+-- Returns current GUI scale: window pixels per one UI unit (1..4).
+-- Set by the display.gui-scale setting and limited by window size.
+gui.get_scale() -> int
+
+-- Returns maximal GUI scale that fits the current window size.
+gui.get_max_scale() -> int
+
+-- Returns cursor position in UI units (unlike input.get_mouse_pos,
+-- which returns window pixels). Use it to position UI elements.
+gui.get_cursor_pos() -> {number, number}
+
-- Returns environment (global variables table) of the specified document.
gui.get_env(document: str) -> table
```
diff --git a/doc/en/scripting/builtins/libinput.md b/doc/en/scripting/builtins/libinput.md
index 9cf754d33..c2f7c858d 100644
--- a/doc/en/scripting/builtins/libinput.md
+++ b/doc/en/scripting/builtins/libinput.md
@@ -55,7 +55,8 @@ end, document.root)
input.get_mouse_pos() --> {int, int}
```
-Returns cursor screen position.
+Returns cursor screen position in window pixels.
+To get position in UI units (affected by GUI scale) use `gui.get_cursor_pos()`.
```lua
input.get_mouse_delta() --> {int, int}
diff --git a/doc/ru/scripting/builtins/libgui.md b/doc/ru/scripting/builtins/libgui.md
index 51ac7307f..b536267fb 100644
--- a/doc/ru/scripting/builtins/libgui.md
+++ b/doc/ru/scripting/builtins/libgui.md
@@ -31,6 +31,17 @@ gui.str(text: string, context: string) -> string
-- Возвращает размер главного контейнера (окна).
gui.get_viewport() -> {number, number}
+-- Возвращает текущий масштаб интерфейса: пикселей окна в одной единице UI (1..4).
+-- Задаётся настройкой display.gui-scale и ограничивается размером окна.
+gui.get_scale() -> int
+
+-- Возвращает максимальный масштаб интерфейса, помещающийся в текущее окно.
+gui.get_max_scale() -> int
+
+-- Возвращает позицию курсора в единицах UI (в отличие от input.get_mouse_pos,
+-- возвращающей пиксели окна). Используйте для позиционирования элементов UI.
+gui.get_cursor_pos() -> {number, number}
+
-- Возвращает окружение (глобальные переменные) указанного документа.
gui.get_env(document: string) -> table
diff --git a/doc/ru/scripting/builtins/libinput.md b/doc/ru/scripting/builtins/libinput.md
index f3ac4b699..d1ef05af8 100644
--- a/doc/ru/scripting/builtins/libinput.md
+++ b/doc/ru/scripting/builtins/libinput.md
@@ -29,7 +29,8 @@ input.set_enabled(bindname: string, flag: boolean)
## Курсор мыши
```lua
--- Возвращает позицию курсора на экране.
+-- Возвращает позицию курсора на экране в пикселях окна.
+-- Для позиции в единицах UI (с учётом масштаба) используйте gui.get_cursor_pos().
input.get_mouse_pos() -> {number, number}
-- Возращает дельту позиции курсора.
diff --git a/res/layouts/pages/settings_audio.xml.lua b/res/layouts/pages/settings_audio.xml.lua
index 6720496df..b2f099eb6 100644
--- a/res/layouts/pages/settings_audio.xml.lua
+++ b/res/layouts/pages/settings_audio.xml.lua
@@ -1,30 +1,7 @@
-function create_trackbar_setting(id, name, step, postfix, tooltip)
- local info = app.get_setting_info(id)
- postfix = postfix or ""
- tooltip = tooltip or ""
- document.root:add(gui.template("track_setting", {
- id=id,
- name=gui.str(name, "settings"),
- value=app.get_setting(id),
- min=info.min,
- max=info.max,
- step=step,
- postfix=postfix,
- tooltip=gui.str(tooltip, "settings")
- }))
- update_trackbar_label(app.get_setting(id), id, name, postfix)
-end
-
-function update_trackbar_label(x, id, name, postfix)
- app.set_setting(id, x)
- -- updating label
- document[id..".L"].text = string.format(
- "%s: %s%s",
- gui.str(name, "settings"),
- app.str_setting(id),
- postfix
- )
-end
+local settings = require "core:settings_common".new(document, {})
+-- templates call these functions by name, so they must be global
+create_trackbar_setting = settings.create_trackbar_setting
+update_trackbar_label = settings.update_trackbar_label
function update_checkbox_setting(id, value)
app.set_setting(id, value)
@@ -43,12 +20,8 @@ function update_checkbox_setting(id, value)
end
end
-function create_checkbox(id, name, tooltip)
- tooltip = tooltip or ''
- document.root:add(string.format(
- "%s",
- id, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
- ))
+local function create_audio_checkbox(id, name, tooltip)
+ settings.create_checkbox(id, name, tooltip, "update_checkbox_setting")
update_checkbox_setting(id, app.get_setting(id))
end
@@ -103,6 +76,6 @@ function on_open()
selectbox.value = app.get_setting("audio.input-device")
end
- create_checkbox("audio.recording-enabled", "Microphone access", "audio.recording-enabled.tooltip")
- create_checkbox("audio.acoustic-effects", "Acoustic effects", "audio.acoustic-effects.tooltip")
+ create_audio_checkbox("audio.recording-enabled", "Microphone access", "audio.recording-enabled.tooltip")
+ create_audio_checkbox("audio.acoustic-effects", "Acoustic effects", "audio.acoustic-effects.tooltip")
end
diff --git a/res/layouts/pages/settings_display.xml.lua b/res/layouts/pages/settings_display.xml.lua
index cdb6fda9c..62202e3fa 100644
--- a/res/layouts/pages/settings_display.xml.lua
+++ b/res/layouts/pages/settings_display.xml.lua
@@ -10,57 +10,24 @@ tostring_overrides["display.framerate"] = function(x)
end
tostring_overrides["display.gui-scale"] = function(x)
+ -- scale is limited by the window size, show what is really applied
+ local effective = gui.get_max_scale()
+ if x > 0 then
+ effective = math.min(x, effective)
+ end
if x == 0 then
- return gui.str("Auto")
- else
- return tostring(x)
+ return string.format("%s (%d)", gui.str("Auto"), effective)
+ elseif effective < x then
+ return string.format("%d (%s %d)", x, gui.str("Effective"), effective)
end
+ return tostring(x)
end
-function create_trackbar_setting(id, name, step, postfix, tooltip, changeonrelease)
- local info = app.get_setting_info(id)
- postfix = postfix or ""
- tooltip = tooltip or ""
- changeonrelease = changeonrelease or ""
- document.root:add(gui.template("track_setting", {
- id=id,
- name=gui.str(name, "settings"),
- value=app.get_setting(id),
- min=info.min,
- max=info.max,
- step=step,
- postfix=postfix,
- tooltip=tooltip,
- changeonrelease=changeonrelease
- }))
- update_trackbar_label(app.get_setting(id), id, name, postfix)
-end
-
-function update_trackbar_label(x, id, name, postfix)
- local str
- local func = tostring_overrides[id]
- if func then
- str = func(x)
- else
- str = app.str_setting(id)
- end
- -- updating label
- document[id..".L"].text = string.format(
- "%s: %s%s",
- gui.str(name, "settings"),
- str,
- postfix
- )
-end
-
-function create_checkbox(id, name, tooltip)
- tooltip = tooltip or ''
- document.root:add(string.format(
- "%s",
- id, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
- ))
-end
-
+local settings = require "core:settings_common".new(document, {tostring_overrides=tostring_overrides})
+-- templates call these functions by name, so they must be global
+create_trackbar_setting = settings.create_trackbar_setting
+update_trackbar_label = settings.update_trackbar_label
+create_checkbox = settings.create_checkbox
function on_open()
create_trackbar_setting("camera.fov", "FOV", 1, "°")
diff --git a/res/layouts/pages/settings_graphics.xml.lua b/res/layouts/pages/settings_graphics.xml.lua
index ed249b0f3..6ab08312b 100644
--- a/res/layouts/pages/settings_graphics.xml.lua
+++ b/res/layouts/pages/settings_graphics.xml.lua
@@ -1,39 +1,8 @@
-function create_trackbar_setting(id, name, step, postfix, tooltip, changeonrelease)
- local info = app.get_setting_info(id)
- postfix = postfix or ""
- tooltip = tooltip or ""
- changeonrelease = changeonrelease or ""
- document.root:add(gui.template("track_setting", {
- id=id,
- name=gui.str(name, "settings"),
- value=app.get_setting(id),
- min=info.min,
- max=info.max,
- step=step,
- postfix=postfix,
- tooltip=tooltip,
- changeonrelease=changeonrelease
- }))
- update_trackbar_label(app.get_setting(id), id, name, postfix)
-end
-
-function update_trackbar_label(x, id, name, postfix)
- -- updating label
- document[id..".L"].text = string.format(
- "%s: %s%s",
- gui.str(name, "settings"),
- app.str_setting(id),
- postfix
- )
-end
-
-function create_checkbox(id, name, tooltip)
- tooltip = tooltip or ''
- document.root:add(string.format(
- "%s",
- id, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
- ))
-end
+local settings = require "core:settings_common".new(document, {})
+-- templates call these functions by name, so they must be global
+create_trackbar_setting = settings.create_trackbar_setting
+update_trackbar_label = settings.update_trackbar_label
+create_checkbox = settings.create_checkbox
function on_open()
create_trackbar_setting("chunks.load-distance", "Load Distance", 1)
diff --git a/res/modules/settings_common.lua b/res/modules/settings_common.lua
new file mode 100644
index 000000000..aa635d99a
--- /dev/null
+++ b/res/modules/settings_common.lua
@@ -0,0 +1,84 @@
+-- Common helpers for settings pages (res/layouts/pages/settings_*.xml.lua).
+--
+-- Usage in a page script:
+--
+-- local settings = require "core:settings_common".new(document, {
+-- tostring_overrides = {["display.framerate"] = function(x) ... end}
+-- })
+-- -- templates call these functions by name, so they must be global
+-- create_trackbar_setting = settings.create_trackbar_setting
+-- update_trackbar_label = settings.update_trackbar_label
+-- create_checkbox = settings.create_checkbox
+
+local settings_common = {}
+
+--- Create helpers bound to the page document.
+--- @param document the page document
+--- @param options table (optional) with fields:
+--- tostring_overrides: {[setting_id] = function(value) -> string}
+function settings_common.new(document, options)
+ options = options or {}
+ local tostring_overrides = options.tostring_overrides or {}
+ local this = {}
+
+ --- Update trackbar label (called by the track_setting template)
+ function this.update_trackbar_label(x, id, name, postfix)
+ local str
+ local func = tostring_overrides[id]
+ if func then
+ str = func(x)
+ else
+ str = app.str_setting(id)
+ end
+ document[id..".L"].text = string.format(
+ "%s: %s%s",
+ gui.str(name, "settings"),
+ str,
+ postfix
+ )
+ end
+
+ --- Add a trackbar bound to the setting
+ --- @param changeonrelease apply value only when mouse is released
+ function this.create_trackbar_setting(
+ id, name, step, postfix, tooltip, changeonrelease
+ )
+ local info = app.get_setting_info(id)
+ postfix = postfix or ""
+ tooltip = tooltip or ""
+ changeonrelease = changeonrelease or ""
+ document.root:add(gui.template("track_setting", {
+ id=id,
+ name=gui.str(name, "settings"),
+ value=app.get_setting(id),
+ min=info.min,
+ max=info.max,
+ step=step,
+ postfix=postfix,
+ tooltip=tooltip,
+ changeonrelease=changeonrelease
+ }))
+ this.update_trackbar_label(app.get_setting(id), id, name, postfix)
+ end
+
+ --- Add a checkbox bound to the setting
+ --- @param consumer name of a global page function(id, value) called on
+ --- change instead of just setting the value (optional)
+ function this.create_checkbox(id, name, tooltip, consumer)
+ tooltip = tooltip or ""
+ local action
+ if consumer then
+ action = string.format("%s(\"%s\", x)", consumer, id)
+ else
+ action = string.format("app.set_setting(\"%s\", x)", id)
+ end
+ document.root:add(string.format(
+ "%s",
+ action, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
+ ))
+ end
+
+ return this
+end
+
+return settings_common
diff --git a/res/texts/ru_RU.txt b/res/texts/ru_RU.txt
index 39060c1d7..dab7dd06b 100644
--- a/res/texts/ru_RU.txt
+++ b/res/texts/ru_RU.txt
@@ -13,6 +13,7 @@ Description=Описание
Converting world...=Выполняется конвертация мира...
Unlimited=Неограниченно
Auto=Авто
+Effective=действует
Chat=Чат
Console=Консоль
Log=Лог
diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp
index b4bb4a9aa..dbdf8ece4 100644
--- a/src/graphics/ui/GUI.cpp
+++ b/src/graphics/ui/GUI.cpp
@@ -93,13 +93,18 @@ void GUI::onAssetsLoad(Assets* assets) {
static constexpr glm::uvec2 MIN_UI_SIZE {640, 480};
static constexpr int MAX_SCALE = 4;
-int GUI::calcScale(const glm::uvec2& viewport) const {
+int GUI::calcMaxScale(const glm::uvec2& viewport) {
int maxFit = 1;
while (maxFit < MAX_SCALE &&
viewport.x / (maxFit + 1) >= MIN_UI_SIZE.x &&
viewport.y / (maxFit + 1) >= MIN_UI_SIZE.y) {
maxFit++;
}
+ return maxFit;
+}
+
+int GUI::calcScale(const glm::uvec2& viewport) const {
+ int maxFit = calcMaxScale(viewport);
int value = engine.getSettings().display.guiScale.get();
if (value <= 0) {
return maxFit; // auto
@@ -111,6 +116,10 @@ int GUI::getScale() const {
return scale;
}
+int GUI::getMaxScale() const {
+ return calcMaxScale(engine.getWindow().getSize());
+}
+
CursorState GUI::getCursor() const {
auto cursor = input.getCursor();
cursor.pos /= static_cast(scale);
diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp
index 9e3f31327..d40edb3e1 100644
--- a/src/graphics/ui/GUI.hpp
+++ b/src/graphics/ui/GUI.hpp
@@ -95,6 +95,7 @@ namespace gui {
bool doubleClicked = false;
bool debug = false;
+ static int calcMaxScale(const glm::uvec2& viewport);
int calcScale(const glm::uvec2& viewport) const;
CursorState getScaledCursor() const;
@@ -134,6 +135,9 @@ namespace gui {
/// @brief Get current GUI scale: window pixels per one UI unit
int getScale() const;
+ /// @brief Get maximal GUI scale that fits the current window size
+ int getMaxScale() const;
+
/// @brief Get cursor state in UI coordinates
CursorState getCursor() const;
diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp
index 614d4c913..cc385309f 100644
--- a/src/graphics/ui/elements/InventoryView.cpp
+++ b/src/graphics/ui/elements/InventoryView.cpp
@@ -78,7 +78,7 @@ void InventoryBuilder::addGrid(
if (addpanel) {
auto panel =
std::make_shared(gui, glm::vec2(width, height));
- view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f));
+ view->setColor(InventoryView::DEFAULT_COLOR);
view->add(panel, pos);
}
diff --git a/src/graphics/ui/elements/InventoryView.hpp b/src/graphics/ui/elements/InventoryView.hpp
index fbfe3eee9..c58fdf0ee 100644
--- a/src/graphics/ui/elements/InventoryView.hpp
+++ b/src/graphics/ui/elements/InventoryView.hpp
@@ -160,6 +160,8 @@ namespace gui {
static const int SLOT_INTERVAL = 4;
static const int SLOT_SIZE = ITEM_ICON_SIZE;
+ /// @brief Default background color (can be overridden by 'color' attribute)
+ static inline const glm::vec4 DEFAULT_COLOR {0.122f, 0.122f, 0.122f, 0.878f};
};
class InventoryBuilder {
diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp
index 41a603cea..8ad9f9c5a 100644
--- a/src/graphics/ui/gui_xml.cpp
+++ b/src/graphics/ui/gui_xml.cpp
@@ -860,7 +860,7 @@ static std::shared_ptr read_inventory(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto view = std::make_shared(reader.getGUI());
- view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // TODO: fixme
+ view->setColor(InventoryView::DEFAULT_COLOR);
reader.addIgnore("slot");
reader.addIgnore("slots-grid");
reader.readUINode(reader, element, *view);
diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp
index dc4806d00..5625c7456 100644
--- a/src/logic/scripting/lua/libs/libgui.cpp
+++ b/src/logic/scripting/lua/libs/libgui.cpp
@@ -1067,6 +1067,20 @@ static int l_gui_getviewport(lua::State* L) {
return lua::pushvec2(L, engine->getGUI().getContainer()->getSize());
}
+static int l_gui_get_scale(lua::State* L) {
+ return lua::pushinteger(L, engine->getGUI().getScale());
+}
+
+static int l_gui_get_max_scale(lua::State* L) {
+ return lua::pushinteger(L, engine->getGUI().getMaxScale());
+}
+
+static int l_gui_get_cursor_pos(lua::State* L) {
+ if (engine->isHeadless())
+ return 0;
+ return lua::pushvec2(L, engine->getGUI().getCursor().pos);
+}
+
static int l_gui_clear_markup(lua::State* L) {
auto lang = lua::require_string(L, 1);
std::string text = lua::require_string(L, 2);
@@ -1247,6 +1261,9 @@ static int l_screenshot(lua::State* L) {
const luaL_Reg guilib[] = {
{"screenshot", lua::wrap},
{"get_viewport", lua::wrap},
+ {"get_scale", lua::wrap},
+ {"get_max_scale", lua::wrap},
+ {"get_cursor_pos", lua::wrap},
{"getattr", lua::wrap},
{"setattr", lua::wrap},
{"get_env", lua::wrap},