Share settings page helpers, add GUI cursor/scale API

- move create_trackbar_setting/update_trackbar_label/create_checkbox from
  settings_audio/display/graphics pages to core:settings_common module
- GUI scale trackbar shows the really applied scale, e.g. '3 (effective 2)'
- add gui.get_scale(), gui.get_max_scale(), gui.get_cursor_pos() (UI units);
  document that input.get_mouse_pos() returns window pixels
- InventoryView default color is defined once (InventoryView::DEFAULT_COLOR)
  instead of duplicated literals; 'color' attribute still overrides it
This commit is contained in:
loki5512344 2026-10-03 13:12:30 +00:00
parent 851c1a0e27
commit 33e132a231
15 changed files with 173 additions and 123 deletions

View file

@ -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
```

View file

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

View file

@ -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

View file

@ -29,7 +29,8 @@ input.set_enabled(bindname: string, flag: boolean)
## Курсор мыши
```lua
-- Возвращает позицию курсора на экране.
-- Возвращает позицию курсора на экране в пикселях окна.
-- Для позиции в единицах UI (с учётом масштаба) используйте gui.get_cursor_pos().
input.get_mouse_pos() -> {number, number}
-- Возращает дельту позиции курсора.

View file

@ -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(
"<checkbox consumer='function(x) update_checkbox_setting(\"%s\", x) end' checked='%s' tooltip='%s'>%s</checkbox>",
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

View file

@ -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(
"<checkbox consumer='function(x) app.set_setting(\"%s\", x) end' checked='%s' tooltip='%s'>%s</checkbox>",
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, "°")

View file

@ -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(
"<checkbox consumer='function(x) app.set_setting(\"%s\", x) end' checked='%s' tooltip='%s'>%s</checkbox>",
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)

View file

@ -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(
"<checkbox consumer='function(x) %s end' checked='%s' tooltip='%s'>%s</checkbox>",
action, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
))
end
return this
end
return settings_common

View file

@ -13,6 +13,7 @@ Description=Описание
Converting world...=Выполняется конвертация мира...
Unlimited=Неограниченно
Auto=Авто
Effective=действует
Chat=Чат
Console=Консоль
Log=Лог

View file

@ -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<float>(scale);

View file

@ -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;

View file

@ -78,7 +78,7 @@ void InventoryBuilder::addGrid(
if (addpanel) {
auto panel =
std::make_shared<gui::Container>(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);
}

View file

@ -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 {

View file

@ -860,7 +860,7 @@ static std::shared_ptr<UINode> read_inventory(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto view = std::make_shared<InventoryView>(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);

View file

@ -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<l_screenshot>},
{"get_viewport", lua::wrap<l_gui_getviewport>},
{"get_scale", lua::wrap<l_gui_get_scale>},
{"get_max_scale", lua::wrap<l_gui_get_max_scale>},
{"get_cursor_pos", lua::wrap<l_gui_get_cursor_pos>},
{"getattr", lua::wrap<l_gui_getattr>},
{"setattr", lua::wrap<l_gui_setattr>},
{"get_env", lua::wrap<l_gui_get_env>},