mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-10-30 07:46:03 +03:00
411 lines
11 KiB
C++
411 lines
11 KiB
C++
#include "ui/CSimpleScrollFrame.hpp"
|
|
#include "gx/Camera.hpp"
|
|
#include "gx/Coordinate.hpp"
|
|
#include "gx/Transform.hpp"
|
|
#include "ui/CRenderBatch.hpp"
|
|
#include "ui/CSimpleScrollFrameScript.hpp"
|
|
#include "ui/FrameXML.hpp"
|
|
#include "util/CStatus.hpp"
|
|
#include "util/Lua.hpp"
|
|
#include <cmath>
|
|
#include <limits>
|
|
#include <common/XML.hpp>
|
|
#include <tempest/Matrix.hpp>
|
|
|
|
int32_t CSimpleScrollFrame::s_metatable;
|
|
int32_t CSimpleScrollFrame::s_objectType;
|
|
|
|
void CSimpleScrollFrame::CreateScriptMetaTable() {
|
|
lua_State* L = FrameScript_GetContext();
|
|
int32_t ref = FrameScript_Object::CreateScriptMetaTable(L, &CSimpleScrollFrame::RegisterScriptMethods);
|
|
CSimpleScrollFrame::s_metatable = ref;
|
|
}
|
|
|
|
int32_t CSimpleScrollFrame::GetObjectType() {
|
|
if (!CSimpleScrollFrame::s_objectType) {
|
|
CSimpleScrollFrame::s_objectType = ++FrameScript_Object::s_objectTypes;
|
|
}
|
|
|
|
return CSimpleScrollFrame::s_objectType;
|
|
}
|
|
|
|
void CSimpleScrollFrame::RegisterScriptMethods(lua_State* L) {
|
|
CSimpleFrame::RegisterScriptMethods(L);
|
|
FrameScript_Object::FillScriptMethodTable(L, SimpleScrollFrameMethods, NUM_SIMPLE_SCROLL_FRAME_SCRIPT_METHODS);
|
|
}
|
|
|
|
void CSimpleScrollFrame::RenderScrollChild(void* param) {
|
|
auto frame = static_cast<CSimpleScrollFrame*>(param);
|
|
|
|
CRect viewRect;
|
|
if (!frame->GetHitRect(viewRect)) {
|
|
return;
|
|
}
|
|
|
|
auto scrollChild = frame->m_scrollChild;
|
|
if (!scrollChild) {
|
|
return;
|
|
}
|
|
|
|
if (!scrollChild->m_visible) {
|
|
return;
|
|
}
|
|
|
|
C44Matrix savedProj;
|
|
GxXformProjection(savedProj);
|
|
|
|
C44Matrix savedView;
|
|
GxXformView(savedView);
|
|
|
|
float minX, maxX, minY, maxY, minZ, maxZ;
|
|
GxXformViewport(minX, maxX, minY, maxY, minZ, maxZ);
|
|
|
|
// TODO clean up
|
|
float v34 = 0.0f;
|
|
float v35 = 0.0f;
|
|
float v36 = 0.0f;
|
|
float v37 = 0.0f;
|
|
NDCToDDC(minX, minY, &v35, &v34);
|
|
NDCToDDC(maxX, maxY, &v37, &v36);
|
|
|
|
auto v4 = viewRect.minX;
|
|
if (v35 > viewRect.minX) {
|
|
v4 = v35;
|
|
viewRect.minX = v35;
|
|
}
|
|
auto v5 = viewRect.maxX;
|
|
if (v37 < viewRect.maxX) {
|
|
v5 = v37;
|
|
viewRect.maxX = v37;
|
|
}
|
|
auto v6 = viewRect.minY;
|
|
if (v34 > viewRect.minY) {
|
|
v6 = v34;
|
|
viewRect.minY = v34;
|
|
}
|
|
auto v7 = viewRect.maxY;
|
|
if (v36 < viewRect.maxY) {
|
|
v7 = v36;
|
|
viewRect.maxY = v36;
|
|
}
|
|
|
|
if (v4 != v5 && v6 != v7) {
|
|
C2Vector screenPoint = { 0.0f, 0.0f };
|
|
CameraSetupScreenProjection(viewRect, screenPoint, 0.0f, 0);
|
|
|
|
DDCToNDC(viewRect.minX, viewRect.minY, &viewRect.minX, &viewRect.minY);
|
|
DDCToNDC(viewRect.maxX, viewRect.maxY, &viewRect.maxX, &viewRect.maxY);
|
|
|
|
float v11, v12, v13, v14;
|
|
|
|
if (viewRect.minX >= 0.0f) {
|
|
v12 = viewRect.minX;
|
|
v11 = viewRect.maxX;
|
|
} else {
|
|
v11 = viewRect.maxX - viewRect.minX;
|
|
viewRect.maxX = v11;
|
|
v12 = 0.0f;
|
|
viewRect.minX = 0.0f;
|
|
}
|
|
|
|
if (v11 > 1.0f) {
|
|
v12 = v12 - (v11 - 1.0f);
|
|
viewRect.minX = v12;
|
|
viewRect.maxX = 1.0f;
|
|
v11 = 1.0f;
|
|
}
|
|
|
|
if (viewRect.minY >= 0.0f) {
|
|
v14 = viewRect.minY;
|
|
v13 = viewRect.maxY;
|
|
} else {
|
|
v13 = viewRect.maxY - viewRect.minY;
|
|
viewRect.maxY = v13;
|
|
v14 = 0.0f;
|
|
viewRect.minY = 0.0f;
|
|
}
|
|
|
|
float v15 = v14;
|
|
float v16 = v13;
|
|
float v17 = v15;
|
|
|
|
if (v16 > 1.0f) {
|
|
v17 = v17 - (v16 - 1.0f);
|
|
viewRect.minY = v17;
|
|
v16 = 1.0f;
|
|
viewRect.maxY = 1.0f;
|
|
}
|
|
|
|
float v18 = v16;
|
|
float v19 = v12;
|
|
float v20 = v18;
|
|
|
|
if (v19 < v11) {
|
|
float v21 = v19;
|
|
float v22 = v17;
|
|
float v23 = v21;
|
|
|
|
if (v22 < v20) {
|
|
float v27 = v20;
|
|
float v26 = v22;
|
|
float v25 = v11;
|
|
float v24 = v23;
|
|
|
|
GxXformSetViewport(v24, v25, v26, v27, 0.0f, 1.0f);
|
|
scrollChild->OnFrameRender();
|
|
}
|
|
}
|
|
|
|
GxXformSetProjection(savedProj);
|
|
GxXformSetView(savedView);
|
|
GxXformSetViewport(minX, maxX, minY, maxY, minZ, maxZ);
|
|
}
|
|
}
|
|
|
|
CSimpleScrollFrame::CSimpleScrollFrame(CSimpleFrame* parent) : CSimpleFrame(parent) {
|
|
// TODO
|
|
}
|
|
|
|
int32_t CSimpleScrollFrame::GetBoundsRect(CRect& bounds) {
|
|
if (this->IsResizePending()) {
|
|
this->Resize(1);
|
|
}
|
|
|
|
CRect rect = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
if (this->GetRect(&rect)) {
|
|
bounds.minX = rect.minX >= bounds.minX ? bounds.minX : rect.minX;
|
|
bounds.maxX = rect.maxX <= bounds.maxX ? bounds.maxX : rect.maxX;
|
|
bounds.minY = rect.minY >= bounds.minY ? bounds.minY : rect.minY;
|
|
bounds.maxY = rect.maxY <= bounds.maxY ? bounds.maxY : rect.maxY;
|
|
}
|
|
|
|
for (auto region = this->m_regions.Head(); region; region = this->m_regions.Next(region)) {
|
|
if (region->IsShown()) {
|
|
if (region->IsResizePending()) {
|
|
region->Resize(1);
|
|
}
|
|
|
|
if (region->GetRect(&rect)) {
|
|
bounds.minX = rect.minX >= bounds.minX ? bounds.minX : rect.minX;
|
|
bounds.maxX = rect.maxX <= bounds.maxX ? bounds.maxX : rect.maxX;
|
|
bounds.minY = rect.minY >= bounds.minY ? bounds.minY : rect.minY;
|
|
bounds.maxY = rect.maxY <= bounds.maxY ? bounds.maxY : rect.maxY;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto child = this->m_children.Head(); child; child = this->m_children.Next(child)) {
|
|
if (child->frame != this->m_scrollChild && child->frame->m_shown) {
|
|
child->frame->GetBoundsRect(bounds);
|
|
}
|
|
}
|
|
|
|
return bounds.maxY > bounds.minY && bounds.maxX > bounds.minX;
|
|
}
|
|
|
|
FrameScript_Object::ScriptIx* CSimpleScrollFrame::GetScriptByName(const char* name, ScriptData& data) {
|
|
auto parentScript = CSimpleFrame::GetScriptByName(name, data);
|
|
|
|
if (parentScript) {
|
|
return parentScript;
|
|
}
|
|
|
|
if (!SStrCmpI(name, "OnHorizontalScroll", STORM_MAX_STR)) {
|
|
data.wrapper = "return function(self,offset) %s end";
|
|
return &this->m_onHorizontalScroll;
|
|
}
|
|
|
|
if (!SStrCmpI(name, "OnVerticalScroll", STORM_MAX_STR)) {
|
|
data.wrapper = "return function(self,offset) %s end";
|
|
return &this->m_onVerticalScroll;
|
|
}
|
|
|
|
if (!SStrCmpI(name, "OnScrollRangeChanged", STORM_MAX_STR)) {
|
|
data.wrapper = "return function(self,xrange,yrange) %s end";
|
|
return &this->m_onScrollRangeChanged;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
int32_t CSimpleScrollFrame::GetScriptMetaTable() {
|
|
return CSimpleScrollFrame::s_metatable;
|
|
}
|
|
|
|
bool CSimpleScrollFrame::IsA(int32_t type) {
|
|
return type == CSimpleScrollFrame::s_objectType
|
|
|| type == CSimpleFrame::s_objectType
|
|
|| type == CScriptRegion::s_objectType
|
|
|| type == CScriptObject::s_objectType;
|
|
}
|
|
|
|
void CSimpleScrollFrame::LoadXML(XMLNode* node, CStatus* status) {
|
|
CSimpleFrame::LoadXML(node, status);
|
|
|
|
XMLNode* scrollChildNode = node->GetChildByName("ScrollChild");
|
|
|
|
if (scrollChildNode) {
|
|
XMLNode* childNode = scrollChildNode->m_child;
|
|
|
|
if (childNode) {
|
|
CSimpleFrame* childFrame = FrameXML_CreateFrame(childNode, this, status);
|
|
|
|
if (childFrame) {
|
|
this->SetScrollChild(childFrame);
|
|
}
|
|
} else {
|
|
const char* frameName = this->GetName();
|
|
|
|
if (!frameName) {
|
|
frameName = "<unnamed>";
|
|
}
|
|
|
|
status->Add(
|
|
STATUS_WARNING,
|
|
"Frame %s: Scroll frame created without scroll child",
|
|
frameName
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSimpleScrollFrame::OnFrameRender(CRenderBatch* batch, uint32_t layer) {
|
|
CSimpleFrame::OnFrameRender(batch, layer);
|
|
|
|
if (layer == DRAWLAYER_HIGHLIGHT) {
|
|
batch->QueueCallback(CSimpleScrollFrame::RenderScrollChild, this);
|
|
}
|
|
}
|
|
|
|
void CSimpleScrollFrame::OnFrameSizeChanged(float w, float h) {
|
|
CSimpleFrame::OnFrameSizeChanged(w, h);
|
|
this->m_updateScrollChild = 1;
|
|
}
|
|
|
|
void CSimpleScrollFrame::OnLayerUpdate(float elapsedSec) {
|
|
CSimpleFrame::OnLayerUpdate(elapsedSec);
|
|
|
|
if (this->m_updateScrollChild) {
|
|
CRect rect = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
if (this->GetRect(&rect)) {
|
|
float w = rect.maxX - rect.minX;
|
|
float h = rect.maxY - rect.minY;
|
|
this->UpdateScrollChildRect(w, h);
|
|
}
|
|
|
|
this->m_updateScrollChild = 0;
|
|
}
|
|
}
|
|
|
|
void CSimpleScrollFrame::RunOnScrollRangeChangedScript() {
|
|
if (!this->m_onScrollRangeChanged.luaRef) {
|
|
return;
|
|
}
|
|
|
|
auto L = FrameScript_GetContext();
|
|
|
|
auto rangeX = this->m_scrollRange.x;
|
|
auto ddcRangeX = CoordinateGetAspectCompensation() * 1024.0f * rangeX;
|
|
auto ndcRangeX = DDCToNDCWidth(ddcRangeX);
|
|
lua_pushnumber(L, ndcRangeX);
|
|
|
|
auto rangeY = this->m_scrollRange.y;
|
|
auto ddcRangeY = CoordinateGetAspectCompensation() * 1024.0f * rangeY;
|
|
auto ndcRangeY = DDCToNDCWidth(ddcRangeY);
|
|
lua_pushnumber(L, ndcRangeY);
|
|
|
|
this->RunScript(this->m_onScrollRangeChanged, 2, nullptr);
|
|
}
|
|
|
|
void CSimpleScrollFrame::RunOnVerticalScrollScript() {
|
|
if (!this->m_onVerticalScroll.luaRef) {
|
|
return;
|
|
}
|
|
|
|
auto L = FrameScript_GetContext();
|
|
|
|
auto offsetY = this->m_scrollOffset.y;
|
|
auto ddcOffsetY = CoordinateGetAspectCompensation() * 1024.0f * offsetY;
|
|
auto ndcOffsetY = DDCToNDCWidth(ddcOffsetY);
|
|
lua_pushnumber(L, ndcOffsetY);
|
|
|
|
this->RunScript(this->m_onVerticalScroll, 1, nullptr);
|
|
}
|
|
|
|
void CSimpleScrollFrame::SetScrollChild(CSimpleFrame* frame) {
|
|
if (this->m_scrollChild) {
|
|
this->m_scrollChild->SetBeingScrolled(0, 0);
|
|
this->m_scrollChild->SetParent(nullptr);
|
|
}
|
|
|
|
this->m_scrollChild = frame;
|
|
|
|
if (this->m_scrollChild) {
|
|
this->m_scrollChild->SetParent(this);
|
|
this->m_scrollChild->SetBeingScrolled(1, 1);
|
|
}
|
|
|
|
this->UpdateScrollChild();
|
|
|
|
this->m_updateScrollChild = 1;
|
|
}
|
|
|
|
void CSimpleScrollFrame::SetVerticalScroll(float offset) {
|
|
if (fabs(offset - this->m_scrollOffset.y) >= 0.00000095367432) {
|
|
this->m_scrollOffset.y = offset;
|
|
this->UpdateScrollChild();
|
|
this->RunOnVerticalScrollScript();
|
|
}
|
|
}
|
|
|
|
void CSimpleScrollFrame::UpdateScrollChild() {
|
|
if (!this->m_scrollChild) {
|
|
return;
|
|
}
|
|
|
|
this->m_scrollChild->ClearAllPoints();
|
|
this->m_scrollChild->SetPoint(
|
|
FRAMEPOINT_TOPLEFT,
|
|
this,
|
|
FRAMEPOINT_TOPLEFT,
|
|
-this->m_scrollOffset.x,
|
|
this->m_scrollOffset.y,
|
|
1
|
|
);
|
|
}
|
|
|
|
void CSimpleScrollFrame::UpdateScrollChildRect(float w, float h) {
|
|
if (!this->m_scrollChild) {
|
|
return;
|
|
}
|
|
|
|
float rangeX = this->m_scrollRange.x;
|
|
float rangeY = this->m_scrollRange.y;
|
|
|
|
CRect childBounds = {
|
|
std::numeric_limits<float>::max(),
|
|
std::numeric_limits<float>::max(),
|
|
0.0f,
|
|
0.0f
|
|
};
|
|
|
|
this->m_scrollChild->GetBoundsRect(childBounds);
|
|
|
|
auto ooScale = 1.0f / this->m_layoutScale;
|
|
|
|
auto v7 = std::max(childBounds.maxX - childBounds.minX - w, 0.0f);
|
|
this->m_scrollRange.x = v7 * ooScale;
|
|
|
|
auto v12 = std::max(childBounds.maxY - childBounds.minY - h, 0.0f);
|
|
this->m_scrollRange.y = v12 * ooScale;
|
|
|
|
if (
|
|
fabs(this->m_scrollRange.x - rangeX) >= 0.00000095367432
|
|
|| fabs(this->m_scrollRange.y - rangeY) >= 0.00000095367432
|
|
) {
|
|
this->RunOnScrollRangeChangedScript();
|
|
}
|
|
}
|