mirror of
https://github.com/whoahq/whoa.git
synced 2026-02-01 00:02:45 +03:00
354 lines
10 KiB
C++
354 lines
10 KiB
C++
#include "ui/simple/CSimpleSlider.hpp"
|
|
#include "math/Utils.hpp"
|
|
#include "ui/LoadXML.hpp"
|
|
#include "ui/simple/CSimpleSliderScript.hpp"
|
|
#include "ui/simple/CSimpleTexture.hpp"
|
|
#include "util/Lua.hpp"
|
|
#include "util/StringTo.hpp"
|
|
#include <common/XML.hpp>
|
|
#include <tempest/Math.hpp>
|
|
|
|
int32_t CSimpleSlider::s_metatable;
|
|
int32_t CSimpleSlider::s_objectType;
|
|
|
|
void CSimpleSlider::CreateScriptMetaTable() {
|
|
lua_State* L = FrameScript_GetContext();
|
|
int32_t ref = FrameScript_Object::CreateScriptMetaTable(L, &CSimpleSlider::RegisterScriptMethods);
|
|
CSimpleSlider::s_metatable = ref;
|
|
}
|
|
|
|
int32_t CSimpleSlider::GetObjectType() {
|
|
if (!CSimpleSlider::s_objectType) {
|
|
CSimpleSlider::s_objectType = ++FrameScript_Object::s_objectTypes;
|
|
}
|
|
|
|
return CSimpleSlider::s_objectType;
|
|
}
|
|
|
|
void CSimpleSlider::RegisterScriptMethods(lua_State* L) {
|
|
CSimpleFrame::RegisterScriptMethods(L);
|
|
FrameScript_Object::FillScriptMethodTable(L, SimpleSliderMethods, NUM_SIMPLE_SLIDER_SCRIPT_METHODS);
|
|
}
|
|
|
|
FrameScript_Object::ScriptIx* CSimpleSlider::GetScriptByName(const char* name, ScriptData& data) {
|
|
auto parentScript = CSimpleFrame::GetScriptByName(name, data);
|
|
|
|
if (parentScript) {
|
|
return parentScript;
|
|
}
|
|
|
|
if (!SStrCmpI(name, "OnValueChanged", STORM_MAX_STR)) {
|
|
data.wrapper = "return function(self,value) %s end";
|
|
return &this->m_onValueChanged;
|
|
}
|
|
|
|
if (!SStrCmpI(name, "OnMinMaxChanged", STORM_MAX_STR)) {
|
|
data.wrapper = "return function(self,min,max) %s end";
|
|
return &this->m_onMinMaxChanged;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
int32_t CSimpleSlider::GetScriptMetaTable() {
|
|
return CSimpleSlider::s_metatable;
|
|
}
|
|
|
|
bool CSimpleSlider::IsA(int32_t type) {
|
|
return type == CSimpleSlider::s_objectType
|
|
|| type == CSimpleFrame::s_objectType
|
|
|| type == CScriptRegion::s_objectType
|
|
|| type == CScriptObject::s_objectType;
|
|
}
|
|
|
|
void CSimpleSlider::LoadXML(const XMLNode* node, CStatus* status) {
|
|
this->CSimpleFrame::LoadXML(node, status);
|
|
|
|
// Thumb
|
|
|
|
int32_t drawLayer = DRAWLAYER_ARTWORK_OVERLAY;
|
|
|
|
auto drawLayerStr = node->GetAttributeByName("drawLayer");
|
|
if (drawLayerStr && *drawLayerStr) {
|
|
StringToDrawLayer(drawLayerStr, drawLayer);
|
|
}
|
|
|
|
for (auto child = node->m_child; child; child = child->m_next) {
|
|
if (!SStrCmpI(child->GetName(), "ThumbTexture")) {
|
|
auto thumbTexture = LoadXML_Texture(child, this, status);
|
|
this->SetThumbTexture(thumbTexture, drawLayer);
|
|
}
|
|
}
|
|
|
|
// Value step
|
|
|
|
auto valueStepStr = node->GetAttributeByName("valueStep");
|
|
auto valueStep = valueStepStr && *valueStepStr ? SStrToFloat(valueStepStr) : 0.001f;
|
|
this->SetValueStep(valueStep);
|
|
|
|
// Min, max, and default values
|
|
|
|
auto minValueStr = node->GetAttributeByName("minValue");
|
|
if (minValueStr && *minValueStr) {
|
|
auto minValue = SStrToFloat(minValueStr);
|
|
|
|
auto maxValueStr = node->GetAttributeByName("maxValue");
|
|
if (maxValueStr && *maxValueStr) {
|
|
auto maxValue = SStrToFloat(maxValueStr);
|
|
|
|
this->SetMinMaxValues(minValue, maxValue);
|
|
|
|
auto defaultValueStr = node->GetAttributeByName("defaultValue");
|
|
if (defaultValueStr && *defaultValueStr) {
|
|
auto defaultValue = SStrToFloat(defaultValueStr);
|
|
|
|
this->SetValue(defaultValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Orientation
|
|
|
|
auto orientationStr = node->GetAttributeByName("orientation");
|
|
if (orientationStr && *orientationStr) {
|
|
ORIENTATION orientation;
|
|
|
|
if (StringToOrientation(orientationStr, orientation)) {
|
|
this->SetOrientation(orientation);
|
|
} else {
|
|
status->Add(
|
|
STATUS_WARNING,
|
|
"Frame %s: Unknown orientation %s in element %s",
|
|
this->GetDisplayName(),
|
|
orientationStr,
|
|
node->GetName()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSimpleSlider::OnFrameSizeChanged(const CRect& rect) {
|
|
this->CSimpleFrame::OnFrameSizeChanged(rect);
|
|
|
|
this->m_changed = 1;
|
|
}
|
|
|
|
|
|
void CSimpleSlider::OnLayerHide() {
|
|
this->m_buttonDown = 0;
|
|
|
|
this->CSimpleFrame::OnLayerHide();
|
|
}
|
|
|
|
int32_t CSimpleSlider::OnLayerMouseDown(const CMouseEvent& evt, const char* btn) {
|
|
// TODO something like CSimpleFrame::IsEnabled or CSimpleFrame::GetFrameFlag
|
|
if (!(this->m_flags & 0x400)) {
|
|
this->m_buttonDown = 1;
|
|
this->OnLayerTrackUpdate(evt);
|
|
}
|
|
|
|
return this->CSimpleFrame::OnLayerMouseDown(evt, btn);
|
|
}
|
|
|
|
int32_t CSimpleSlider::OnLayerMouseUp(const CMouseEvent& evt, const char* btn) {
|
|
this->m_buttonDown = 0;
|
|
|
|
return this->CSimpleFrame::OnLayerMouseUp(evt, btn);
|
|
}
|
|
|
|
int32_t CSimpleSlider::OnLayerTrackUpdate(const CMouseEvent& evt) {
|
|
if (this->m_buttonDown && this->m_thumbTexture) {
|
|
auto thumbTexture = this->m_thumbTexture;
|
|
|
|
float area;
|
|
float offset;
|
|
|
|
if (this->m_orientation == ORIENTATION_VERTICAL) {
|
|
area = this->m_rect.maxY - this->m_rect.minY - thumbTexture->GetHeight();
|
|
offset = this->m_rect.maxY - (thumbTexture->GetHeight() / 2.0f) - evt.y;
|
|
} else {
|
|
area = this->m_rect.maxX - this->m_rect.minX - thumbTexture->GetWidth();
|
|
offset = evt.x - ((thumbTexture->GetWidth() / 2.0f) + this->m_rect.minX);
|
|
}
|
|
|
|
float value = (this->m_range + this->m_baseValue - this->m_baseValue) * (offset / area) + this->m_baseValue;
|
|
|
|
this->SetValue(value);
|
|
}
|
|
|
|
return this->CSimpleFrame::OnLayerTrackUpdate(evt);
|
|
}
|
|
|
|
void CSimpleSlider::OnLayerUpdate(float elapsedSec) {
|
|
this->CSimpleFrame::OnLayerUpdate(elapsedSec);
|
|
|
|
if (this->m_changed && this->m_thumbTexture && this->m_rangeSet && this->m_valueSet) {
|
|
auto valueRange = this->m_range + this->m_baseValue - this->m_baseValue;
|
|
auto valueOffset = CMath::fequal(valueRange, 0.0f)
|
|
? 0.0f
|
|
: (this->m_value - this->m_baseValue) / valueRange;
|
|
|
|
if (this->m_orientation == ORIENTATION_VERTICAL) {
|
|
auto rangeY = (this->m_rect.maxY - this->m_rect.minY) / this->m_layoutScale;
|
|
auto offsetY = -((rangeY - this->m_thumbTexture->GetHeight()) * valueOffset);
|
|
|
|
this->m_thumbTexture->SetPoint(FRAMEPOINT_TOP, this, FRAMEPOINT_TOP, 0.0f, offsetY, 1);
|
|
} else {
|
|
auto rangeX = (this->m_rect.maxX - this->m_rect.minX) / this->m_layoutScale;
|
|
auto offsetX = (rangeX - this->m_thumbTexture->GetWidth()) * valueOffset;
|
|
|
|
this->m_thumbTexture->SetPoint(FRAMEPOINT_LEFT, this, FRAMEPOINT_LEFT, offsetX, 0.0f, 1);
|
|
}
|
|
|
|
this->m_changed = 0;
|
|
}
|
|
}
|
|
|
|
void CSimpleSlider::RunOnMinMaxChangedScript() {
|
|
if (!this->m_onMinMaxChanged.luaRef) {
|
|
return;
|
|
}
|
|
|
|
auto L = FrameScript_GetContext();
|
|
|
|
lua_pushnumber(L, this->m_baseValue);
|
|
lua_pushnumber(L, this->m_range + this->m_baseValue);
|
|
|
|
this->RunScript(this->m_onMinMaxChanged, 2, nullptr);
|
|
}
|
|
|
|
void CSimpleSlider::RunOnValueChangedScript() {
|
|
if (!this->m_onValueChanged.luaRef) {
|
|
return;
|
|
}
|
|
|
|
auto L = FrameScript_GetContext();
|
|
|
|
lua_pushnumber(L, this->m_value);
|
|
|
|
this->RunScript(this->m_onValueChanged, 1, nullptr);
|
|
}
|
|
|
|
void CSimpleSlider::SetMinMaxValues(float min, float max) {
|
|
float range = max - min;
|
|
|
|
if (this->m_rangeSet && AreEqual(this->m_range, range, WHOA_EPSILON_1) && AreEqual(this->m_baseValue, min, WHOA_EPSILON_1)) {
|
|
return;
|
|
}
|
|
|
|
this->m_baseValue = min;
|
|
this->m_range = range;
|
|
this->m_changed = 1;
|
|
this->m_rangeSet = 1;
|
|
|
|
this->RunOnMinMaxChangedScript();
|
|
|
|
if (this->m_valueSet) {
|
|
// Fit current value within range
|
|
this->SetValue(this->m_value);
|
|
}
|
|
}
|
|
|
|
void CSimpleSlider::SetOrientation(ORIENTATION orientation) {
|
|
this->m_orientation = orientation;
|
|
|
|
if (this->m_thumbTexture) {
|
|
this->m_thumbTexture->ClearAllPoints();
|
|
}
|
|
|
|
this->m_changed = 1;
|
|
}
|
|
|
|
void CSimpleSlider::SetThumbTexture(CSimpleTexture* texture, int32_t drawLayer) {
|
|
if (this->m_thumbTexture == texture) {
|
|
return;
|
|
}
|
|
|
|
if (this->m_thumbTexture) {
|
|
delete this->m_thumbTexture;
|
|
}
|
|
|
|
if (texture) {
|
|
texture->SetFrame(this, drawLayer, 1);
|
|
texture->ClearAllPoints();
|
|
}
|
|
|
|
this->m_changed = 1;
|
|
this->m_thumbTexture = texture;
|
|
}
|
|
|
|
void CSimpleSlider::SetValue(float value) {
|
|
if (!this->m_rangeSet) {
|
|
return;
|
|
}
|
|
|
|
auto v4 = value;
|
|
auto v5 = std::max(value, this->m_baseValue);
|
|
auto maxValue = this->m_range + this->m_baseValue;
|
|
|
|
if (maxValue >= v5) {
|
|
if (v4 < this->m_baseValue) {
|
|
v4 = this->m_baseValue;
|
|
}
|
|
} else {
|
|
v4 = maxValue;
|
|
}
|
|
|
|
auto newValue = this->StepValue(v4);
|
|
|
|
// Clamp to max value
|
|
if (newValue + this->m_valueStep > maxValue) {
|
|
newValue = maxValue;
|
|
}
|
|
|
|
// Clamp to base value
|
|
if (newValue - this->m_valueStep < this->m_baseValue) {
|
|
newValue = this->m_baseValue;
|
|
}
|
|
|
|
if (!this->m_valueSet || fabs(newValue - this->m_value) >= 0.00000023841858) {
|
|
this->m_value = newValue;
|
|
this->m_changed = 1;
|
|
this->m_valueSet = 1;
|
|
|
|
this->RunOnValueChangedScript();
|
|
}
|
|
}
|
|
|
|
void CSimpleSlider::SetValueStep(float valueStep) {
|
|
valueStep = std::max(valueStep, 0.00000011920929f);
|
|
|
|
if (CMath::fequal(this->m_valueStep, valueStep)) {
|
|
return;
|
|
}
|
|
|
|
this->m_valueStep = valueStep;
|
|
|
|
if (this->m_valueSet) {
|
|
this->SetValue(this->m_value);
|
|
}
|
|
}
|
|
|
|
float CSimpleSlider::StepValue(float value) {
|
|
if (this->m_valueStep == 0.0f) {
|
|
return value;
|
|
}
|
|
|
|
auto valueOffset = value - this->m_baseValue;
|
|
auto halfStep = this->m_valueStep / 2.0f;
|
|
|
|
if (valueOffset <= 0.0f) {
|
|
return CMath::fint((valueOffset - halfStep) / this->m_valueStep) * this->m_valueStep + this->m_baseValue;
|
|
}
|
|
|
|
return CMath::fint((valueOffset + halfStep) / this->m_valueStep) * this->m_valueStep + this->m_baseValue;
|
|
}
|
|
|
|
void CSimpleSlider::UnregisterRegion(CSimpleRegion* region) {
|
|
if (this->m_thumbTexture == region) {
|
|
this->m_thumbTexture = nullptr;
|
|
}
|
|
|
|
this->CSimpleFrame::UnregisterRegion(region);
|
|
}
|