From fa55a29a930cc8010981fbf6ebe06ec04b33c695 Mon Sep 17 00:00:00 2001 From: VDm Date: Tue, 12 Aug 2025 22:23:22 +0400 Subject: [PATCH] feat(ui): update CSimpleStatusBar to support texture --- src/ui/CSimpleStatusBar.cpp | 86 +++++++++++++++++++++++++++++++ src/ui/CSimpleStatusBar.hpp | 6 +++ src/ui/CSimpleStatusBarScript.cpp | 81 +++++++++++++++++++++++++++-- 3 files changed, 169 insertions(+), 4 deletions(-) diff --git a/src/ui/CSimpleStatusBar.cpp b/src/ui/CSimpleStatusBar.cpp index 0e9107b..f81c921 100644 --- a/src/ui/CSimpleStatusBar.cpp +++ b/src/ui/CSimpleStatusBar.cpp @@ -1,5 +1,7 @@ #include "ui/CSimpleStatusBar.hpp" #include "ui/CSimpleStatusBarScript.hpp" +#include "ui/CSimpleTexture.hpp" +#include "util/Lua.hpp" int32_t CSimpleStatusBar::s_metatable = 0; int32_t CSimpleStatusBar::s_objectType = 0; @@ -32,6 +34,90 @@ void CSimpleStatusBar::SetOrientation(uint32_t orientation) { this->m_orientation = orientation; } +void CSimpleStatusBar::SetMinMaxValues(float minValue, float maxValue) { + if ((this->m_flags & 2) != 0 && this->m_minValue == minValue && this->m_maxValue == maxValue) { + return; + } + + this->m_flags |= 3; + this->m_minValue = minValue; + this->m_maxValue = maxValue; + this->RunOnMinMaxChanged(); + + if (this->m_flags & 4) { + this->SetValue(this->m_value); + } +} + +void CSimpleStatusBar::SetBarTexture(const char* texFile, int32_t layer) { + if (this->m_barTexture) { + this->m_barTexture->SetTexture(texFile, false, false, GxTex_Linear, ImageMode_UI); + return; + } + + // TODO: CDataAllocator__GetData(CSimpleTexture::s_allocator, 0, ".?AVCSimpleTexture@@", -2); + auto texture = NEW(CSimpleTexture, nullptr, DRAWLAYER_ARTWORK, 0); + if (texture->SetTexture(texFile, false, false, GxTex_Linear, ImageMode_UI)) { + texture->SetAllPoints(this, 1); + texture->SetBlendMode(GxBlend_Add); + this->SetBarTexture(texture, layer); + } else if (texture) { + // TODO: FrameScript_Object::LookupScriptMethod(texture, 1); + } +} + +void CSimpleStatusBar::SetBarTexture(CSimpleTexture* texture, int32_t layer) { + if (texture == this->m_barTexture) { + return; + } + + if (this->m_barTexture) { + // TODO: FrameScript_Object::LookupScriptMethod(this->m_checkedTexture, 1); + } + + if (texture) { + texture->SetFrame(this, layer, 1); + texture->SetPoint(FRAMEPOINT_BOTTOMLEFT, this, FRAMEPOINT_BOTTOMLEFT, 0.0f, 0.0f, 1); + texture->SetPoint(FRAMEPOINT_BOTTOMRIGHT, this, FRAMEPOINT_BOTTOMRIGHT, 0.0f, 0.0f, 1); + texture->SetPoint(FRAMEPOINT_TOPLEFT, this, FRAMEPOINT_TOPLEFT, 0.0f, 0.0f, 1); + texture->SetPoint(FRAMEPOINT_TOPRIGHT, this, FRAMEPOINT_TOPRIGHT, 0.0f, 0.0f, 1); + } + + this->m_flags |= 1; + this->m_barTexture = texture; +} + +void CSimpleStatusBar::RunOnMinMaxChanged() { + if (this->m_onMinMaxChanged.luaRef) { + auto L = FrameScript_GetContext(); + lua_pushnumber(L, this->m_minValue); + lua_pushnumber(L, this->m_maxValue); + this->RunScript(this->m_onMinMaxChanged, 2, 0); + } +} + +void CSimpleStatusBar::RunOnValueChanged() { + if (this->m_onValueChanged.luaRef) { + auto L = FrameScript_GetContext(); + lua_pushnumber(L, this->m_value); + this->RunScript(this->m_onMinMaxChanged, 1, 0); + } +} + +void CSimpleStatusBar::SetValue(float value) { + if ((this->m_flags & 2) == 0) { + return; + } + + value = std::min(value, this->m_maxValue); + value = std::max(value, this->m_minValue); + + if ((this->m_flags & 4) == 0 || this->m_value != value) { + this->m_value = value; + this->RunOnValueChanged(); + } +} + bool CSimpleStatusBar::IsA(int32_t type) { return type == CSimpleStatusBar::s_objectType || type == CSimpleFrame::s_objectType diff --git a/src/ui/CSimpleStatusBar.hpp b/src/ui/CSimpleStatusBar.hpp index 180d831..5aea0c6 100644 --- a/src/ui/CSimpleStatusBar.hpp +++ b/src/ui/CSimpleStatusBar.hpp @@ -17,8 +17,14 @@ class CSimpleStatusBar : public CSimpleFrame { // Member functions CSimpleStatusBar(CSimpleFrame* parent); void SetOrientation(uint32_t orientation); + void SetMinMaxValues(float minValue, float maxValue); + void SetBarTexture(const char* texFile, int32_t layer); + void SetBarTexture(CSimpleTexture* texture, int32_t layer); + void RunOnMinMaxChanged(); + void RunOnValueChanged(); // Virtual member functions + virtual void SetValue(float value); virtual bool IsA(int32_t type); virtual int32_t GetScriptMetaTable(); virtual ScriptIx* GetScriptByName(const char* name, ScriptData& data); diff --git a/src/ui/CSimpleStatusBarScript.cpp b/src/ui/CSimpleStatusBarScript.cpp index aacd6a2..9aa2905 100644 --- a/src/ui/CSimpleStatusBarScript.cpp +++ b/src/ui/CSimpleStatusBarScript.cpp @@ -1,5 +1,6 @@ #include "ui/CSimpleStatusBarScript.hpp" #include "ui/CSimpleStatusBar.hpp" +#include "ui/CSimpleTexture.hpp" #include "ui/Util.hpp" #include "util/Lua.hpp" #include "util/Unimplemented.hpp" @@ -38,7 +39,22 @@ static int32_t Script_GetMinMaxValues(lua_State* L) { } static int32_t Script_SetMinMaxValues(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleStatusBar::GetObjectType(); + auto statusBar = static_cast(FrameScript_GetObjectThis(L, type)); + if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) { + return luaL_error(L, "Usage: %s:SetMinMaxValues(min, max)", statusBar->GetDisplayName()); + } + + auto minval = lua_tonumber(L, 2); + auto maxval = lua_tonumber(L, 3); + if (minval < -1.0e12 || minval > 1.0e12 || maxval < -1.0e12 || maxval > 1.0e12) { + return luaL_error(L, "Min or Max out of range"); + } + if (maxval - minval > 1.0e12) { + return luaL_error(L, "Min and Max too far apart"); + } + statusBar->SetMinMaxValues(minval, maxval); + return 0; } static int32_t Script_GetValue(lua_State* L) { @@ -49,15 +65,72 @@ static int32_t Script_GetValue(lua_State* L) { } static int32_t Script_SetValue(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleStatusBar::GetObjectType(); + auto statusBar = static_cast(FrameScript_GetObjectThis(L, type)); + if (!lua_isnumber(L, 2)) { + return luaL_error(L, "Usage: %s:SetValue(value)", statusBar->GetDisplayName()); + } + + auto value = lua_tonumber(L, 2); + statusBar->SetValue(value); + return 0; } static int32_t Script_GetStatusBarTexture(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleStatusBar::GetObjectType(); + auto statusBar = static_cast(FrameScript_GetObjectThis(L, type)); + auto texture = statusBar->m_barTexture; + if (texture) { + if (!texture->lua_registered) { + texture->RegisterScriptObject(nullptr); + } + lua_rawgeti(L, LUA_REGISTRYINDEX, texture->lua_objectRef); + } else { + lua_pushnil(L); + } + return 1; } static int32_t Script_SetStatusBarTexture(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleStatusBar::GetObjectType(); + auto statusBar = static_cast(FrameScript_GetObjectThis(L, type)); + + int32_t layer = 2; + + if (lua_isstring(L, 3)) { + StringToDrawLayer(lua_tolstring(L, 3, nullptr), layer); + } + + if (lua_type(L, 2) == LUA_TTABLE) { + lua_rawgeti(L, 2, 0); + auto texture = static_cast(lua_touserdata(L, -1)); + lua_settop(L, -2); + + if (!texture) { + return luaL_error(L, "%s:SetStatusBarTexture(): Couldn't find 'this' in texture", statusBar->GetDisplayName()); + } else { + auto textureType = CSimpleTexture::GetObjectType(); + if (!texture->IsA(textureType)) { + return luaL_error(L, "%s:SetStatusBarTexture(): Wrong object type, expected texture", statusBar->GetDisplayName()); + } + } + + statusBar->SetBarTexture(texture, layer); + return 0; + } + + if (lua_isstring(L, 2)) { + auto texFile = lua_tostring(L, 2); + statusBar->SetBarTexture(texFile, layer); + return 0; + } + + if (lua_type(L, 2) != LUA_TNIL) { + luaL_error(L, "Usage: %s:SetStatusBarTexture(texture or \"texture\" or nil [, \"layer\"])", statusBar->GetDisplayName()); + } + + statusBar->SetBarTexture(static_cast(nullptr), 2); + return 0; } static int32_t Script_GetStatusBarColor(lua_State* L) {