Index: binaries/data/mods/mod/gui/common/functions_msgbox.js
===================================================================
--- binaries/data/mods/mod/gui/common/functions_msgbox.js
+++ binaries/data/mods/mod/gui/common/functions_msgbox.js
@@ -15,6 +15,24 @@
});
}
+function timedConfirmation(mbWidth, mbHeight, mbMessage, mbTimeout, mbTitle, mbButtonCaptions, mbBtnCode, mbCallbackArgs)
+{
+ Engine.PushGuiPage(
+ "page_timedconfirmation.xml",
+ {
+ "width": mbWidth,
+ "height": mbHeight,
+ "message": mbMessage,
+ "timeout": mbTimeout,
+ "title": mbTitle,
+ "buttonCaptions": mbButtonCaptions
+ },
+ btnCode => {
+ if (mbBtnCode !== undefined && mbBtnCode[btnCode])
+ mbBtnCode[btnCode](mbCallbackArgs ? mbCallbackArgs[btnCode] : undefined);
+ });
+}
+
function openURL(url)
{
Engine.OpenURL(url);
Index: binaries/data/mods/mod/gui/msgbox/msgbox.js
===================================================================
--- binaries/data/mods/mod/gui/msgbox/msgbox.js
+++ binaries/data/mods/mod/gui/msgbox/msgbox.js
@@ -24,37 +24,7 @@
let captions = data.buttonCaptions || [translate("OK")];
- // Set button captions and visibility
let mbButton = [];
- captions.forEach((caption, i) => {
- mbButton[i] = Engine.GetGUIObjectByName("mbButton" + (i + 1));
- mbButton[i].caption = caption;
- mbButton[i].hidden = false;
- mbButton[i].onPress = () => {
- Engine.PopGuiPage(i);
- };
-
- // Convention: Cancel is the first button
- if (i == 0)
- mbCancelHotkey.onPress = mbButton[i].onPress;
- });
-
- // Distribute buttons horizontally
- let y1 = "100%-46";
- let y2 = "100%-18";
- switch (captions.length)
- {
- case 1:
- mbButton[0].size = "18 " + y1 + " 100%-18 " + y2;
- break;
- case 2:
- mbButton[0].size = "18 " + y1 + " 50%-5 " + y2;
- mbButton[1].size = "50%+5 " + y1 + " 100%-18 " + y2;
- break;
- case 3:
- mbButton[0].size = "18 " + y1 + " 33%-5 " + y2;
- mbButton[1].size = "33%+5 " + y1 + " 66%-5 " + y2;
- mbButton[2].size = "66%+5 " + y1 + " 100%-18 " + y2;
- break;
- }
+ setButtonCaptionsAndVisibitily(mbButton, captions, mbCancelHotkey, "mbButton");
+ distributeButtonsHorizontally(mbButton, captions);
}
Index: binaries/data/mods/mod/gui/timedconfirmation/timedconfirmation.js
===================================================================
--- /dev/null
+++ binaries/data/mods/mod/gui/timedconfirmation/timedconfirmation.js
@@ -0,0 +1,46 @@
+/**
+ * Currently limited to at most 3 buttons per message box.
+ * The convention is to have "cancel" appear first.
+ */
+function init(data)
+{
+ Engine.GetGUIObjectByName("tmcTitleBar").caption = data.title;
+
+ const textObj = Engine.GetGUIObjectByName("tmcText");
+ textObj.caption = data.message;
+
+ updateDisplayedTimer(data.timeout);
+
+ Engine.GetGUIObjectByName("tmcTimer").caption = data.timeout;
+ if (data.font)
+ textObj.font = data.font;
+
+ const cancelHotkey = Engine.GetGUIObjectByName("tmcCancelHotkey");
+ cancelHotkey.onPress = Engine.PopGuiPage;
+
+ const lRDiff = data.width / 2;
+ const uDDiff = data.height / 2;
+ Engine.GetGUIObjectByName("tmcMain").size = "50%-" + lRDiff + " 50%-" + uDDiff + " 50%+" + lRDiff + " 50%+" + uDDiff;
+
+ const captions = data.buttonCaptions || [translate("OK")];
+
+ // Set button captions and visibility
+ let button = [];
+ setButtonCaptionsAndVisibitily(button, captions, cancelHotkey, "tmcButton");
+ distributeButtonsHorizontally(button, captions);
+}
+
+function onTick() {
+ const timerObj = Engine.GetGUIObjectByName("tmcTimer");
+ let time = +timerObj.caption;
+ --time;
+ if (time < 1)
+ Engine.GetGUIObjectByName("tmcButton1").onPress();
+
+ timerObj.caption = time;
+ updateDisplayedTimer(time);
+}
+
+function updateDisplayedTimer(time) {
+ Engine.GetGUIObjectByName("tmcTimerDisplay").caption = Math.ceil(time / 100);
+}
Index: binaries/data/mods/mod/gui/timedconfirmation/timedconfirmation.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/mod/gui/timedconfirmation/timedconfirmation.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
Index: binaries/data/mods/public/gui/options/options.js
===================================================================
--- binaries/data/mods/public/gui/options/options.js
+++ binaries/data/mods/public/gui/options/options.js
@@ -146,6 +146,35 @@
};
}
},
+ "dropdownNumber":
+ {
+ "configToValue": value => +value,
+ "valueToGui": (value, control) => {
+ control.selected = control.list_data.indexOf(""+value);
+ },
+ "guiToValue": control => +control.list_data[control.selected],
+ "guiSetter": "onSelectionChange",
+ "initGUI": (option, control) => {
+ control.list = option.list.map(e => e.label);
+ control.list_data = option.list.map(e => e.value);
+ control.onHoverChange = () => {
+ let item = option.list[control.hovered];
+ control.tooltip = item && item.tooltip || option.tooltip;
+ };
+ },
+ "timeout": (option, oldValue, hasChanges, newValue) => {
+ if (!option.timeout)
+ return;
+ timedConfirmation(
+ 500, 200,
+ translate("Do you want to keep changes?"),
+ 500,
+ translate("Warning"),
+ [translate("No"), translate("Yes")],
+ [() => {this.revertChange(option, +oldValue, hasChanges);}, null]
+ );
+ }
+ },
"slider":
{
"configToValue": value => +value,
@@ -242,14 +271,20 @@
if (optionType.sanitizeValue)
optionType.sanitizeValue(value, control, option);
+ let oldValue = optionType.configToValue(Engine.ConfigDB_GetValue("user", option.config));
+
control.tooltip = option.tooltip + (optionType.tooltip ? "\n" + optionType.tooltip(value, option) : "");
+ let hasChanges = Engine.ConfigDB_HasChanges("user");
Engine.ConfigDB_CreateValue("user", option.config, String(value));
Engine.ConfigDB_SetChanges("user", true);
g_ChangedKeys.add(option.config);
fireConfigChangeHandlers(new Set([option.config]));
+ if (option.timeout)
+ optionType.timeout(option, oldValue, hasChanges, value);
+
if (option.function)
Engine[option.function](value);
@@ -315,6 +350,18 @@
revertChanges();
}
+function revertChange(option, oldValue, hadChanges)
+{
+ if (!hadChanges)
+ Engine.ConfigDB_SetChanges("user", false);
+
+ Engine.ConfigDB_CreateValue("user", option.config, String(oldValue));
+ if (option.function)
+ Engine[option.function](oldValue);
+
+ displayOptions();
+}
+
function revertChanges()
{
Engine.ConfigDB_Reload("user");
Index: binaries/data/mods/public/gui/options/options.json
===================================================================
--- binaries/data/mods/public/gui/options/options.json
+++ binaries/data/mods/public/gui/options/options.json
@@ -149,6 +149,24 @@
"config": "adaptivefps.session",
"min": 20,
"max": 100
+ },
+ {
+ "type": "dropdownNumber",
+ "label": "GUI scale",
+ "timeout": 500,
+ "tooltip": "GUI scale",
+ "config": "gui.scale",
+ "function": "SetGUIScale",
+ "list": [
+ { "value": 0.75, "label": "75%" },
+ { "value": 1.00, "label": "100%" },
+ { "value": 1.25, "label": "125%" },
+ { "value": 1.50, "label": "150%" },
+ { "value": 1.75, "label": "175%" },
+ { "value": 2.00, "label": "200%" },
+ { "value": 2.25, "label": "225%" },
+ { "value": 2.50, "label": "250%" }
+ ]
}
]
},
Index: binaries/data/mods/public/gui/options/options.xml
===================================================================
--- binaries/data/mods/public/gui/options/options.xml
+++ binaries/data/mods/public/gui/options/options.xml
@@ -33,6 +33,7 @@
+
Index: source/gui/CGUI.cpp
===================================================================
--- source/gui/CGUI.cpp
+++ source/gui/CGUI.cpp
@@ -42,6 +42,7 @@
#include "ps/Hotkey.h"
#include "ps/Profile.h"
#include "ps/Pyrogenesis.h"
+#include "ps/VideoMode.h"
#include "ps/XML/Xeromyces.h"
#include "scriptinterface/ScriptContext.h"
#include "scriptinterface/ScriptInterface.h"
@@ -154,7 +155,7 @@
// Yes the mouse position is stored as float to avoid
// constant conversions when operating in a
// float-based environment.
- m_MousePos = CVector2D((float)ev->ev.motion.x / g_GuiScale, (float)ev->ev.motion.y / g_GuiScale);
+ m_MousePos = CVector2D((float)ev->ev.motion.x / g_VideoMode.GetScale(), (float)ev->ev.motion.y / g_VideoMode.GetScale());
SGUIMessage msg(GUIM_MOUSE_MOTION);
m_BaseObject->RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::HandleMessage, msg);
@@ -179,7 +180,7 @@
CVector2D oldMousePos = m_MousePos;
if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP)
{
- m_MousePos = CVector2D((float)ev->ev.button.x / g_GuiScale, (float)ev->ev.button.y / g_GuiScale);
+ m_MousePos = CVector2D((float)ev->ev.button.x / g_VideoMode.GetScale(), (float)ev->ev.button.y / g_VideoMode.GetScale());
}
// Allow the focused object to pre-empt regular GUI events.
@@ -420,7 +421,7 @@
CSize2D CGUI::GetWindowSize() const
{
- return CSize2D{static_cast(g_xres) / g_GuiScale, static_cast(g_yres) / g_GuiScale};
+ return CSize2D{static_cast(g_xres) / g_VideoMode.GetScale(), static_cast(g_yres) / g_VideoMode.GetScale() };
}
void CGUI::SetFocusedObject(IGUIObject* pObject)
Index: source/gui/CGUIText.cpp
===================================================================
--- source/gui/CGUIText.cpp
+++ source/gui/CGUIText.cpp
@@ -26,12 +26,12 @@
#include "gui/ObjectBases/IGUIObject.h"
#include "gui/SettingTypes/CGUIString.h"
#include "ps/CStrInternStatic.h"
+#include "ps/VideoMode.h"
#include "renderer/Renderer.h"
#include
extern int g_xres, g_yres;
-extern float g_GuiScale;
// TODO Gee: CRect => CPoint ?
void SGenerateTextImage::SetupSpriteCall(
@@ -439,12 +439,13 @@
clipping.left = std::ceil(clipping.left);
clipping.right = std::floor(clipping.right);
+ float scale = g_VideoMode.GetScale();
glEnable(GL_SCISSOR_TEST);
glScissor(
- std::ceil(clipping.left * g_GuiScale),
- std::ceil(g_yres - clipping.bottom * g_GuiScale),
- std::floor(clipping.GetWidth() * g_GuiScale),
- std::floor(clipping.GetHeight() * g_GuiScale));
+ std::ceil(clipping.left * scale),
+ std::ceil(g_yres - clipping.bottom * scale),
+ std::floor(clipping.GetWidth() * scale),
+ std::floor(clipping.GetHeight() * scale));
}
CTextRenderer textRenderer;
Index: source/gui/GUIMatrix.cpp
===================================================================
--- source/gui/GUIMatrix.cpp
+++ source/gui/GUIMatrix.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019 Wildfire Games.
+/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -18,16 +18,15 @@
#include "precompiled.h"
#include "GUIMatrix.h"
-
+#include "ps/VideoMode.h"
#include "maths/Matrix3D.h"
extern int g_xres, g_yres;
-extern float g_GuiScale;
CMatrix3D GetDefaultGuiMatrix()
{
- float xres = g_xres / g_GuiScale;
- float yres = g_yres / g_GuiScale;
+ float xres = g_xres / g_VideoMode.GetScale();
+ float yres = g_yres / g_VideoMode.GetScale();
CMatrix3D m;
m.SetIdentity();
Index: source/gui/ObjectTypes/CInput.cpp
===================================================================
--- source/gui/ObjectTypes/CInput.cpp
+++ source/gui/ObjectTypes/CInput.cpp
@@ -31,6 +31,7 @@
#include "ps/GameSetup/Config.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
+#include "ps/VideoMode.h"
#include "renderer/Renderer.h"
#include
@@ -1238,12 +1239,13 @@
if (cliparea != CRect())
{
+ float scale = g_VideoMode.GetScale();
glEnable(GL_SCISSOR_TEST);
glScissor(
- cliparea.left * g_GuiScale,
- g_yres - cliparea.bottom * g_GuiScale,
- cliparea.GetWidth() * g_GuiScale,
- cliparea.GetHeight() * g_GuiScale);
+ cliparea.left * scale,
+ g_yres - cliparea.bottom * scale,
+ cliparea.GetWidth() * scale,
+ cliparea.GetHeight() * scale);
}
// These are useful later.
Index: source/ps/CConsole.cpp
===================================================================
--- source/ps/CConsole.cpp
+++ source/ps/CConsole.cpp
@@ -45,6 +45,7 @@
#include "ps/Hotkey.h"
#include "ps/Profile.h"
#include "ps/Pyrogenesis.h"
+#include "ps/VideoMode.h"
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/JSON.h"
@@ -116,8 +117,8 @@
m_fX = 0;
m_fY = 0;
float height = h * 0.6f;
- m_fWidth = w / g_GuiScale;
- m_fHeight = height / g_GuiScale;
+ m_fWidth = w / g_VideoMode.GetScale();
+ m_fHeight = height / g_VideoMode.GetScale();
}
void CConsole::ToggleVisible()
Index: source/ps/GameSetup/Config.h
===================================================================
--- source/ps/GameSetup/Config.h
+++ source/ps/GameSetup/Config.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020 Wildfire Games.
+/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -24,7 +24,6 @@
extern bool g_PauseOnFocusLoss;
extern int g_xres, g_yres;
-extern float g_GuiScale;
extern bool g_Quickstart;
extern bool g_DisableAudio;
Index: source/ps/GameSetup/Config.cpp
===================================================================
--- source/ps/GameSetup/Config.cpp
+++ source/ps/GameSetup/Config.cpp
@@ -34,7 +34,6 @@
bool g_PauseOnFocusLoss = false;
int g_xres, g_yres;
-float g_GuiScale = 1.0f;
bool g_Quickstart = false;
bool g_DisableAudio = false;
@@ -47,11 +46,8 @@
static void LoadGlobals()
{
CFG_GET_VAL("pauseonfocusloss", g_PauseOnFocusLoss);
-
- CFG_GET_VAL("gui.scale", g_GuiScale);
}
-
static void ProcessCommandLineArgs(const CmdLineArgs& args)
{
// TODO: all these options (and the ones processed elsewhere) should
Index: source/ps/GameSetup/GameSetup.cpp
===================================================================
--- source/ps/GameSetup/GameSetup.cpp
+++ source/ps/GameSetup/GameSetup.cpp
@@ -291,7 +291,7 @@
CStrW cursorName = g_CursorName;
if (cursorName.empty())
{
- cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y, g_GuiScale, false);
+ cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y, g_VideoMode.GetScale(), false);
}
else
{
@@ -316,7 +316,7 @@
#if OS_ANDROID
#warning TODO: cursors for Android
#else
- if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y, g_GuiScale, forceGL) < 0)
+ if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y, g_VideoMode.GetScale(), forceGL) < 0)
LOGWARNING("Failed to draw cursor '%s'", utf8_from_wstring(cursorName));
#endif
Index: source/ps/VideoMode.h
===================================================================
--- source/ps/VideoMode.h
+++ source/ps/VideoMode.h
@@ -47,6 +47,11 @@
bool ResizeWindow(int w, int h);
/**
+ * Tell dependent compoenent to recompute sizes because scaling have changed.
+ */
+ void Rescale(float scale);
+
+ /**
* Switch to fullscreen or windowed mode.
*/
bool SetFullscreen(bool fullscreen);
@@ -84,6 +89,8 @@
int GetDesktopBPP() const;
int GetDesktopFreq() const;
+ float GetScale() const;
+
SDL_Window* GetWindow();
void SetWindowIcon();
@@ -109,6 +116,8 @@
int m_PreferredBPP = 0;
int m_PreferredFreq = 0;
+ float m_Scale = 1.0f;
+
// Config file settings (0 if unspecified)
int m_ConfigW = 0;
int m_ConfigH = 0;
Index: source/ps/VideoMode.cpp
===================================================================
--- source/ps/VideoMode.cpp
+++ source/ps/VideoMode.cpp
@@ -70,6 +70,8 @@
CFG_GET_VAL("windowed", windowed);
m_ConfigFullscreen = !windowed;
+ CFG_GET_VAL("gui.scale", m_Scale);
+
CFG_GET_VAL("xres", m_ConfigW);
CFG_GET_VAL("yres", m_ConfigH);
CFG_GET_VAL("bpp", m_ConfigBPP);
@@ -359,6 +361,18 @@
return true;
}
+void CVideoMode::Rescale(float scale)
+{
+ ENSURE(m_IsInitialised);
+ m_Scale = scale;
+ UpdateRenderer(m_CurrentW, m_CurrentH);
+}
+
+float CVideoMode::GetScale() const
+{
+ return m_Scale;
+}
+
bool CVideoMode::SetFullscreen(bool fullscreen)
{
// This might get called before initialisation by psDisplayError;
Index: source/ps/scripting/JSInterface_ConfigDB.cpp
===================================================================
--- source/ps/scripting/JSInterface_ConfigDB.cpp
+++ source/ps/scripting/JSInterface_ConfigDB.cpp
@@ -21,6 +21,7 @@
#include "ps/ConfigDB.h"
#include "ps/CLogger.h"
+#include "ps/VideoMode.h"
#include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptRequest.h"
@@ -188,6 +189,11 @@
return true;
}
+void SetGUIScale(float scale)
+{
+ g_VideoMode.Rescale(scale);
+}
+
void RegisterScriptFunctions(const ScriptRequest& rq)
{
ScriptFunction::Register<&HasChanges>(rq, "ConfigDB_HasChanges");
@@ -201,5 +207,6 @@
ScriptFunction::Register<&CreateAndWriteValueToFile>(rq, "ConfigDB_CreateAndWriteValueToFile");
ScriptFunction::Register<&SetFile>(rq, "ConfigDB_SetFile");
ScriptFunction::Register<&Reload>(rq, "ConfigDB_Reload");
+ ScriptFunction::Register<&SetGUIScale>(rq, "SetGUIScale");
}
}