Index: binaries/data/mods/mod/gui/gui.rnc
===================================================================
--- binaries/data/mods/mod/gui/gui.rnc
+++ binaries/data/mods/mod/gui/gui.rnc
@@ -99,6 +99,7 @@
attribute sprite2_pressed { text }?&
attribute sprite_selectarea { text }?&
attribute square_side { xsd:decimal }?&
+ attribute steps { xsd:positiveInteger }?&
attribute textcolor { ccolor }?&
attribute textcolor_disabled { ccolor }?&
attribute textcolor_over { ccolor }?&
Index: binaries/data/mods/mod/gui/gui.rng
===================================================================
--- binaries/data/mods/mod/gui/gui.rng
+++ binaries/data/mods/mod/gui/gui.rng
@@ -380,6 +380,11 @@
+
+
+
+
+
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
@@ -137,6 +137,7 @@
let callbackFunction;
let minvalue;
let maxvalue;
+ let steps;
for (let param in option.parameters)
{
@@ -155,6 +156,9 @@
case "max":
maxvalue = +option.parameters.max;
break;
+ case "steps":
+ steps = +option.parameters.steps;
+ break;
default:
warn("Unknown option source type '" + param + "'");
}
@@ -174,7 +178,8 @@
if (+Engine.ConfigDB_GetValue("user", key) === this.value)
return;
- Engine.ConfigDB_CreateValue("user", key, this.value);
+ // Avoid the floats precision error, this precision is enough for most cases
+ Engine.ConfigDB_CreateValue("user", key, this.value.toFixed(5));
Engine.ConfigDB_SetChanges("user", true);
if (callbackFunction)
Engine[callbackFunction](+this.value);
@@ -185,6 +190,7 @@
control.value = value;
control.max_value = maxvalue;
control.min_value = minvalue;
+ control.steps = steps;
control.onValueChange = onUpdate;
break;
case "number":
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
@@ -154,7 +154,7 @@
"type": "slider",
"label": "Graphics quality",
"tooltip": "Number of shader effects. REQUIRES GAME RESTART",
- "parameters": { "config": "materialmgr.quality", "min": 0, "max": 10 }
+ "parameters": { "config": "materialmgr.quality", "min": 0, "max": 10, "steps": 9 }
},
{
"type": "boolean",
@@ -240,13 +240,13 @@
"type": "slider",
"label": "FPS throttling in menus",
"tooltip": "To save CPU workload, throttle render frequency in all menus. Set to maximum to disable throttling.",
- "parameters": { "config": "adaptivefps.menu", "min": 20, "max": 100 }
+ "parameters": { "config": "adaptivefps.menu", "min": 20, "max": 100, "steps": 79 }
},
{
"type": "slider",
"label": "FPS throttling in games",
"tooltip": "To save CPU workload, throttle render frequency in running games. Set to maximum to disable throttling.",
- "parameters": { "config": "adaptivefps.session", "min": 20, "max": 100 }
+ "parameters": { "config": "adaptivefps.session", "min": 20, "max": 100, "steps": 79 }
}
],
"soundSetting":
@@ -255,31 +255,31 @@
"type": "slider",
"label": "Master Volume",
"tooltip": "Master audio gain",
- "parameters": { "config": "sound.mastergain", "function": "SetMasterGain", "min": 0, "max": 2 }
+ "parameters": { "config": "sound.mastergain", "function": "SetMasterGain", "min": 0, "max": 2, "steps": 19 }
},
{
"type": "slider",
"label": "Music Volume",
"tooltip": "In game music gain",
- "parameters": { "config": "sound.musicgain", "function": "SetMusicGain", "min": 0, "max": 2 }
+ "parameters": { "config": "sound.musicgain", "function": "SetMusicGain", "min": 0, "max": 2, "steps": 19 }
},
{
"type": "slider",
"label": "Ambient Volume",
"tooltip": "In game ambient sound gain",
- "parameters": { "config": "sound.ambientgain", "function": "SetAmbientGain", "min": 0, "max": 2 }
+ "parameters": { "config": "sound.ambientgain", "function": "SetAmbientGain", "min": 0, "max": 2, "steps": 19 }
},
{
"type": "slider",
"label": "Action Volume",
"tooltip": "In game unit action sound gain",
- "parameters": { "config": "sound.actiongain", "function": "SetActionGain", "min": 0, "max": 2 }
+ "parameters": { "config": "sound.actiongain", "function": "SetActionGain", "min": 0, "max": 2, "steps": 19 }
},
{
"type": "slider",
"label": "UI Volume",
"tooltip": "UI sound gain",
- "parameters": { "config": "sound.uigain", "function": "SetUIGain", "min": 0, "max": 2 }
+ "parameters": { "config": "sound.uigain", "function": "SetUIGain", "min": 0, "max": 2, "steps": 19 }
},
{
"type": "boolean",
Index: source/gui/CSlider.h
===================================================================
--- source/gui/CSlider.h
+++ source/gui/CSlider.h
@@ -46,6 +46,7 @@
CRect GetButtonRect();
float m_MinValue, m_MaxValue, m_Value;
+ int m_Steps, m_Step;
private:
bool m_IsPressed;
@@ -53,6 +54,8 @@
CPos m_Mouse;
float m_ButtonSide;
+ float m_OldValue;
+ int m_OldStep;
};
#endif // INCLUDED_CSLIDER
Index: source/gui/CSlider.cpp
===================================================================
--- source/gui/CSlider.cpp
+++ source/gui/CSlider.cpp
@@ -23,21 +23,32 @@
CSlider::CSlider()
- : m_IsPressed(false), m_ButtonSide(0)
+ : m_IsPressed(false), m_ButtonSide(0.f), m_Steps(0), m_Step(0)
{
- AddSetting(GUIST_float, "value");
+ AddSetting(GUIST_float, "button_width");
+ AddSetting(GUIST_int, "cell_id");
AddSetting(GUIST_float, "min_value");
AddSetting(GUIST_float, "max_value");
- AddSetting(GUIST_int, "cell_id");
AddSetting(GUIST_CGUISpriteInstance, "sprite");
AddSetting(GUIST_CGUISpriteInstance, "sprite_bar");
- AddSetting(GUIST_float, "button_width");
+ AddSetting(GUIST_int, "steps");
+ AddSetting(GUIST_float, "value");
- GUI::GetSetting(this, "value", m_Value);
+ GUI::GetSetting(this, "button_width", m_ButtonSide);
GUI::GetSetting(this, "min_value", m_MinValue);
GUI::GetSetting(this, "max_value", m_MaxValue);
- GUI::GetSetting(this, "button_width", m_ButtonSide);
+ GUI::GetSetting(this, "steps", m_Steps);
+ GUI::GetSetting(this, "value", m_Value);
+
m_Value = Clamp(m_Value, m_MinValue, m_MaxValue);
+ if (m_Steps < 0)
+ m_Steps = 0;
+ if (m_Steps > 0)
+ {
+ m_Step = round(m_Value * (m_Steps + 1) / (m_MaxValue - m_MinValue));
+ m_Step = Clamp(m_Step, 0, m_Steps + 1);
+ m_Value = m_MinValue + (m_MaxValue - m_MinValue) / (m_Steps + 1) * m_Step;
+ }
}
CSlider::~CSlider()
@@ -50,18 +61,35 @@
{
case GUIM_SETTINGS_UPDATED:
{
- GUI::GetSetting(this, "value", m_Value);
+ GUI::GetSetting(this, "button_width", m_ButtonSide);
GUI::GetSetting(this, "min_value", m_MinValue);
GUI::GetSetting(this, "max_value", m_MaxValue);
- GUI::GetSetting(this, "button_width", m_ButtonSide);
+ GUI::GetSetting(this, "steps", m_Steps);
+ GUI::GetSetting(this, "value", m_Value);
+
m_Value = Clamp(m_Value, m_MinValue, m_MaxValue);
+
+ if (m_Steps < 0)
+ m_Steps = 0;
+ if (m_Steps > 0)
+ {
+ m_Step = std::round((m_Value - m_MinValue) / (m_MaxValue - m_MinValue) * (m_Steps + 1));
+ m_Step = Clamp(m_Step, 0, m_Steps + 1);
+ m_Value = m_MinValue + (m_MaxValue - m_MinValue) / (m_Steps + 1) * m_Step;
+ }
break;
}
case GUIM_MOUSE_WHEEL_DOWN:
{
if (m_IsPressed)
break;
- m_Value = std::max(m_Value - 0.01f, m_MinValue);
+ if (m_Steps > 0)
+ {
+ m_Step = std::min(m_Step + 1, m_Steps + 1);
+ m_Value = m_MinValue + (m_MaxValue - m_MinValue) / (m_Steps + 1) * m_Step;
+ }
+ else
+ m_Value = std::max(m_Value + 0.1f, m_MinValue);
UpdateValue();
break;
}
@@ -69,7 +97,26 @@
{
if (m_IsPressed)
break;
- m_Value = std::min(m_Value + 0.01f, m_MaxValue);
+ if (m_Steps > 0)
+ {
+ m_Step = std::max(m_Step - 1, 0);
+ m_Value = m_MinValue + (m_MaxValue - m_MinValue) / (m_Steps + 1) * m_Step;
+ }
+ else
+ m_Value = std::min(m_Value - 0.1f, m_MaxValue);
+ UpdateValue();
+ break;
+ }
+ case GUIM_MOUSE_DBLCLICK_LEFT:
+ {
+ m_IsPressed = false;
+ if (m_Steps > 0)
+ {
+ m_Step = m_Steps / 2;
+ m_Value = m_MinValue + (m_MaxValue - m_MinValue) / (m_Steps + 1) * m_Step;
+ }
+ else
+ m_Value = (m_MaxValue + m_MinValue) / 2.f;
UpdateValue();
break;
}
@@ -78,6 +125,10 @@
if (GetButtonRect().PointInside(GetMousePos()))
{
m_Mouse = GetMousePos();
+ if (m_Steps > 0)
+ m_OldStep = m_Step;
+ else
+ m_OldValue = m_Value;
m_IsPressed = true;
}
break;
@@ -93,10 +144,18 @@
m_IsPressed = false;
if (m_IsPressed)
{
- float ratio = (m_MaxValue - m_MinValue) / (m_CachedActualSize.GetWidth() - m_ButtonSide);
- float difference = float(GetMousePos().x - m_Mouse.x) * ratio;
- m_Mouse = GetMousePos();
- m_Value = Clamp(m_Value + difference, m_MinValue, m_MaxValue);
+ const float difference = float(GetMousePos().x - m_Mouse.x);
+ if (m_Steps > 0)
+ {
+ const float step_length = (m_CachedActualSize.GetWidth() - m_ButtonSide) / (m_Steps + 1);
+ m_Step = Clamp(m_OldStep + int(std::round(difference / step_length)), 0, m_Steps + 1);
+ m_Value = m_MinValue + (m_MaxValue - m_MinValue) / (m_Steps + 1) * m_Step;
+ }
+ else
+ {
+ const float ratio = (m_MaxValue - m_MinValue) / (m_CachedActualSize.GetWidth() - m_ButtonSide);
+ m_Value = Clamp(m_OldValue + difference * ratio, m_MinValue, m_MaxValue);
+ }
UpdateValue();
}
break;
@@ -127,15 +186,15 @@
}
void CSlider::UpdateValue()
-{
+{
GUI::SetSetting(this, "value", m_Value);
ScriptEvent("valuechange");
}
CRect CSlider::GetButtonRect()
{
- float ratio = m_MaxValue > m_MinValue ? (m_Value - m_MinValue) / (m_MaxValue - m_MinValue) : 0.0f;
- float x = m_CachedActualSize.left + ratio * (m_CachedActualSize.GetWidth() - m_ButtonSide);
- float y = m_CachedActualSize.top + (m_CachedActualSize.GetHeight() - m_ButtonSide) / 2.0;
+ const float ratio = (m_Value - m_MinValue) / (m_MaxValue - m_MinValue);
+ const float x = m_CachedActualSize.left + ratio * (m_CachedActualSize.GetWidth() - m_ButtonSide);
+ const float y = m_CachedActualSize.top + (m_CachedActualSize.GetHeight() - m_ButtonSide) / 2.0;
return CRect(x, y, x + m_ButtonSide, y + m_ButtonSide);
}