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},