thunderbrew/src/ui/CSimpleTop.cpp

597 lines
16 KiB
C++

#include "ui/CSimpleTop.hpp"
#include "gx/Camera.hpp"
#include "gx/Coordinate.hpp"
#include "gx/Device.hpp"
#include "gx/Font.hpp"
#include "gx/Screen.hpp"
#include "ui/CSimpleFrame.hpp"
#include "ui/CSimpleRender.hpp"
#include "ui/CSimpleTexture.hpp"
#include "ui/CSimpleTitleRegion.hpp"
#include "cursor/Cursor.hpp"
#include <cstring>
#include <tempest/Math.hpp>
CSimpleTop* CSimpleTop::s_instance;
uint32_t CSimpleTop::m_eventTime;
void PaintScreen(void* param, const RECTF* rect, const RECTF* visible, float elapsedSec) {
CSimpleTop::s_instance->OnLayerUpdate(elapsedSec);
CSimpleTop::s_instance->OnLayerRender();
}
int32_t CSimpleTop::OnChar(const EVENT_DATA_CHAR* pCharData, void* param) {
CSimpleTop* top = static_cast<CSimpleTop*>(param);
int32_t eaten = 0;
CCharEvent charEvent;
charEvent = *pCharData;
charEvent.id = 0x40060067;
for (int32_t strata = FRAME_STRATA_TOOLTIP; strata >= FRAME_STRATA_WORLD; strata--) {
if (eaten) {
break;
}
auto priorities = &top->m_eventqueue[strata][SIMPLE_EVENT_CHAR];
for (uint32_t i = 0; i < priorities->Count(); i++) {
auto priority = priorities->operator[](i);
if (!priority || eaten) {
break;
}
auto frame = priority->frame;
eaten = frame->OnLayerChar(charEvent);
}
}
return eaten == 0;
}
int32_t CSimpleTop::OnDisplaySizeChanged(const EVENT_DATA_SIZE* pSizeData, void* param) {
CSimpleTop* top = static_cast<CSimpleTop*>(param);
GxuFontWindowSizeChanged();
for (auto frame = top->m_frames.Head(); frame; frame = top->m_frames.Link(frame)->Next()) {
frame->OnScreenSizeChanged();
}
if (top->m_displaySizeCallback) {
CSizeEvent sizeEvent;
sizeEvent = *pSizeData;
sizeEvent.id = 0x40040064;
top->m_displaySizeCallback(sizeEvent);
}
return 1;
}
int32_t CSimpleTop::OnFocusChanged(const void* a1, void* a2) {
// TODO
return 0;
}
int32_t CSimpleTop::OnIme(const void* a1, void* a2) {
// TODO
return 0;
}
int32_t CSimpleTop::OnKeyDown(const EVENT_DATA_KEY* pKeyData, void* param) {
CSimpleTop* top = static_cast<CSimpleTop*>(param);
CSimpleTop::m_eventTime = pKeyData->time;
CKeyEvent keyEvent;
keyEvent = *pKeyData;
keyEvent.id = 0x40060064;
// TODO
// if (top->unk1239) {
// top->unk1239(keyEvent);
// }
int32_t eaten = 0;
for (int32_t strata = FRAME_STRATA_TOOLTIP; strata >= FRAME_STRATA_WORLD; strata--) {
if (eaten) {
break;
}
auto priorities = &top->m_eventqueue[strata][SIMPLE_EVENT_KEY];
for (uint32_t i = 0; i < priorities->Count(); i++) {
auto priority = priorities->operator[](i);
if (!priority || eaten) {
break;
}
auto frame = priority->frame;
eaten = frame->OnLayerKeyDown(keyEvent);
if (eaten) {
top->m_keydownCapture[keyEvent.key] = frame;
}
}
}
return eaten == 0;
}
int32_t CSimpleTop::OnKeyDownRepeat(const void* a1, void* a2) {
// TODO
return 0;
}
int32_t CSimpleTop::OnKeyUp(const EVENT_DATA_KEY* pKeyData, void* param) {
CSimpleTop* top = static_cast<CSimpleTop*>(param);
CSimpleTop::m_eventTime = pKeyData->time;
int32_t eaten = 0;
CSimpleFrame* frame = top->m_keydownCapture[pKeyData->key];
if (frame) {
CKeyEvent keyEvent;
keyEvent = *pKeyData;
keyEvent.id = 0x40060066;
frame->OnLayerKeyUp(keyEvent);
eaten = 1;
} else if (pKeyData->key == KEY_PRINTSCREEN) {
eaten = CSimpleTop::OnKeyDown(pKeyData, param);
}
top->m_keydownCapture[pKeyData->key] = nullptr;
return eaten == 0;
}
int32_t CSimpleTop::OnMouseDown(const EVENT_DATA_MOUSE* pMouseData, void* param) {
CSimpleTop* top = static_cast<CSimpleTop*>(param);
CMouseEvent mouseEvent;
mouseEvent = *pMouseData;
mouseEvent.id = 0x400500C8;
CSimpleTop::m_eventTime = pMouseData->time;
// TODO
// bool v4 = top->m_layout.enabled;
bool enabled = false;
memcpy(&top->m_mousePosition, pMouseData, sizeof(top->m_mousePosition));
if (enabled && (EventIsKeyDown(KEY_LCONTROL) || EventIsKeyDown(KEY_LALT))) {
int32_t v5 = EventIsKeyDown(KEY_LCONTROL);
top->StartMoveOrResizeFrame(mouseEvent, MOVERESIZE_REASON1, v5);
return 0;
}
auto mouseButtonCallback = top->m_mouseButtonCallback;
if (!top->m_mouseCapture && mouseButtonCallback && mouseButtonCallback(&mouseEvent)) {
return 0;
}
CSimpleFrame* target = top->m_mouseCapture;
if (!target) {
target = top->m_mouseFocus;
}
if (!target) {
return 1;
}
target->Raise();
CSimpleTitleRegion* titleRegion = target->m_titleRegion;
C2Vector pt = { mouseEvent.x, mouseEvent.y };
if (titleRegion && titleRegion->PtInFrameRect(pt)) {
top->StartMoveOrResizeFrame(target, MOVERESIZE_REASON2, mouseEvent.x, mouseEvent.y, 4);
} else {
top->m_mouseCapture = target;
target->OnLayerMouseDown(mouseEvent, nullptr);
}
return 0;
}
int32_t CSimpleTop::OnMouseMove(const EVENT_DATA_MOUSE* pMouseData, void* param) {
CSimpleTop* top = static_cast<CSimpleTop*>(param);
CMouseEvent mouseEvent;
mouseEvent = *pMouseData;
mouseEvent.id = 0x400500CA;
int32_t v18 = pMouseData != &top->m_mousePosition;
if (v18) {
if (pMouseData->x == top->m_mousePosition.x && pMouseData->y == top->m_mousePosition.y) {
return 0;
}
CSimpleTop::m_eventTime = pMouseData->time;
}
memcpy(&top->m_mousePosition, pMouseData, sizeof(top->m_mousePosition));
CSimpleFrame* lastFocus = top->m_mouseFocus;
CSimpleFrame* nextFocus = nullptr;
if (top->m_layout.frame) {
CMouseEvent evt;
evt = *pMouseData;
top->MoveOrResizeFrame(evt);
return 0;
}
auto mousePositionCallback = top->m_mousePositionCallback;
if (mousePositionCallback && mousePositionCallback(&mouseEvent)) {
return 0;
}
CSimpleFrame* mouseCapture = top->m_mouseCapture;
if (mouseCapture) {
mouseCapture->OnLayerTrackUpdate(mouseEvent);
}
for (int32_t strata = FRAME_STRATA_DIALOG; strata >= FRAME_STRATA_WORLD; strata--) {
auto priorities = &top->m_eventqueue[strata][SIMPLE_EVENT_MOUSE];
for (int32_t i = 0; i < priorities->Count(); i++) {
auto priority = priorities->operator[](i);
auto frame = priority->frame;
if (frame->OnLayerTrackUpdate(mouseEvent)) {
nextFocus = frame;
break;
}
}
if (nextFocus) {
break;
}
}
if (nextFocus != lastFocus) {
top->m_mouseFocus = nextFocus;
if (lastFocus) {
lastFocus->OnLayerCursorExit(v18, 0);
}
if (nextFocus) {
nextFocus->OnLayerCursorEnter(v18);
}
}
return nextFocus == nullptr;
}
int32_t CSimpleTop::OnMouseMoveRelative(const EVENT_DATA_MOUSE* pMouseData, void* param) {
// TODO
return 0;
}
int32_t CSimpleTop::OnMouseUp(const EVENT_DATA_MOUSE* pMouseData, void* param) {
CSimpleTop* top = static_cast<CSimpleTop*>(param);
CMouseEvent mouseEvent;
mouseEvent = *pMouseData;
mouseEvent.id = 0x400500C9;
CSimpleTop::m_eventTime = pMouseData->time;
if (top->m_layout.anchor == 1 || top->m_layout.anchor == 2) {
if (top->m_layout.frame) {
top->m_layout.frame->UnflattenFrame(top);
}
top->m_layout.frame = nullptr;
top->m_layout.anchor = FRAMEPOINT_TOPLEFT;
return 0;
}
// TODO
// if (v11 && !top->m_mouseCapture && v11(mouseEvent)) {
// return 0;
// }
if (!top->m_mouseCapture) {
return 1;
}
top->m_mouseCapture->OnLayerMouseUp(mouseEvent, nullptr);
if (!mouseEvent.buttonState) {
top->m_mouseCapture = nullptr;
}
return 0;
}
int32_t CSimpleTop::OnMouseWheel(const EVENT_DATA_MOUSE* pMouseData, void* param) {
// TODO
return 0;
}
float CSimpleTop::RoundToPixelHeight(float ddcHeight) {
if (abs(ddcHeight) < 0.00000023841858) {
return ddcHeight;
}
CRect windowRect = { 0.0f, 0.0f, 0.0f, 0.0f };
g_theGxDevicePtr->CapsWindowSizeInScreenCoords(windowRect);
float windowHeight = windowRect.maxY - windowRect.minY;
if (abs(windowHeight) < 0.00000023841858) {
return ddcHeight;
}
auto ndcHeight = DDCToNDCHeight(ddcHeight);
auto pixelHeight = ndcHeight * windowHeight;
auto roundedPixelHeight = CMath::fuint_pi(pixelHeight);
auto roundedNdcHeight = static_cast<float>(roundedPixelHeight) / windowHeight;
auto roundedDdcHeight = NDCToDDCHeight(roundedNdcHeight);
return roundedDdcHeight;
}
CSimpleTop::CSimpleTop() : CLayoutFrame() {
// TODO
CSimpleTop::s_instance = this;
ScrnLayerCreate(nullptr, 1.0, 0x4, nullptr, &PaintScreen, &this->m_screenLayer);
this->EnableEvents();
// TODO
// memset(this->m_keydownCapture, 0, sizeof(this->m_keydownCapture));
NDCToDDC(1.0f, 1.0f, &this->m_rect.maxX, &this->m_rect.maxY);
this->m_flags |= 0x1;
// TODO
for (int32_t s = 0; s < NUM_FRAME_STRATA; s++) {
auto m = SMemAlloc(sizeof(CFrameStrata), __FILE__, __LINE__, 0x0);
this->m_strata[s] = new (m) CFrameStrata();
}
// TODO
CSimpleRender::Init();
CSimpleTexture::Init();
}
void CSimpleTop::CompressStrata(int32_t strata) {
// TODO
}
void CSimpleTop::EnableEvents() {
EventRegisterEx(EVENT_ID_CHAR, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnChar), this, 1.0);
EventRegisterEx(EVENT_ID_IME, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnIme), this, 1.0);
EventRegisterEx(EVENT_ID_KEYDOWN, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnKeyDown), this, 1.0);
EventRegisterEx(EVENT_ID_KEYUP, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnKeyUp), this, 1.0);
EventRegisterEx(EVENT_ID_KEYDOWN_REPEATING, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnKeyDownRepeat), this, 1.0);
EventRegisterEx(EVENT_ID_MOUSEMOVE, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnMouseMove), this, 1.0);
EventRegisterEx(EVENT_ID_MOUSEMOVE_RELATIVE, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnMouseMoveRelative), this, 1.0);
EventRegisterEx(EVENT_ID_MOUSEDOWN, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnMouseDown), this, 1.0);
EventRegisterEx(EVENT_ID_MOUSEUP, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnMouseUp), this, 1.0);
EventRegisterEx(EVENT_ID_MOUSEWHEEL, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnMouseWheel), this, 1.0);
EventRegisterEx(EVENT_ID_SIZE, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnDisplaySizeChanged), this, 1.0);
EventRegisterEx(EVENT_ID_FOCUS, reinterpret_cast<EVENTHANDLERFUNC>(CSimpleTop::OnFocusChanged), this, 1.0);
}
void CSimpleTop::HideFrame(CSimpleFrame* frame, int32_t a4) {
if (this->m_layout.frame == frame && !a4) {
if (this->m_layout.frame) {
this->m_layout.frame->UnflattenFrame(this);
}
this->m_layout.frame = nullptr;
this->m_layout.anchor = FRAMEPOINT_TOPLEFT;
}
frame->UnregisterForEvents(a4);
this->m_strata[frame->m_strata]->RemoveFrame(frame);
}
void CSimpleTop::OnLayerUpdate(float elapsedSec) {
// TODO
// - walk m_destroyed and perform some cleanup
CLayoutFrame::ResizePending();
for (int32_t s = 0; s < NUM_FRAME_STRATA; s++) {
auto strata = this->m_strata[s];
strata->OnLayerUpdate(elapsedSec);
}
CLayoutFrame::ResizePending();
if (this->m_checkFocus) {
this->m_checkFocus = 0;
CSimpleTop::OnMouseMove(&this->m_mousePosition, this);
}
}
void CSimpleTop::OnLayerRender() {
C2Vector v13 = { 0.0f, 0.0f };
CameraSetupScreenProjection(this->m_rect, v13, 0.0f, 0);
for (int32_t s = 0; s < NUM_FRAME_STRATA; s++) {
auto strata = this->m_strata[s];
strata->BuildBatches(this->m_mouseCapture == nullptr);
strata->RenderBatches();
}
}
void CSimpleTop::MoveOrResizeFrame(const CMouseEvent& evt) {
// TODO
}
void CSimpleTop::NotifyFrameLayerChanged(CSimpleFrame* frame, uint32_t layer) {
auto strata = this->m_strata[frame->m_strata];
auto level = strata->levels[frame->m_level];
level->batchDirty |= 1 << layer;
strata->batchDirty = 1;
}
void CSimpleTop::NotifyFrameMovedOrResized(CSimpleFrame* frame) {
auto strata = this->m_strata[frame->m_strata];
strata->levelsDirty = 1;
if (this->m_layout.frame) {
this->RaiseFrame(this->m_layout.frame, 0);
}
this->m_checkFocus = 1;
}
int32_t CSimpleTop::RaiseFrame(CSimpleFrame* frame, int32_t checkOcclusion) {
while (frame && frame->m_flags & 0x01) {
frame = frame->m_parent;
}
if (!frame) {
return 0;
}
if (checkOcclusion) {
if (!(static_cast<CLayoutFrame*>(frame)->m_flags & 0x01) || this->IsResizePending()) {
frame->Resize(1);
}
int32_t occluded = this->m_strata[frame->m_strata]->FrameOccluded(frame);
frame->SetFrameFlag(0x10, occluded);
}
if (frame->m_flags & 0x10) {
this->CompressStrata(frame->m_strata);
auto strata = this->m_strata[frame->m_strata];
frame->SetFrameLevel(strata->topLevel, 1);
this->m_checkFocus = 1;
}
return 1;
}
void CSimpleTop::RegisterForEvent(CSimpleFrame* frame, CSimpleEventType event, int32_t a4, uint32_t priority) {
auto& queue = this->m_eventqueue[frame->m_strata][event];
auto m = SMemAlloc(sizeof(FRAMEPRIORITY), __FILE__, __LINE__, 0x0);
auto framePriority = new (m) FRAMEPRIORITY();
framePriority->frame = frame;
framePriority->priority = priority == -1 ? frame->m_level : priority;
queue.Insert(framePriority);
if (!a4 || event == SIMPLE_EVENT_MOUSE) {
this->m_checkFocus = 1;
}
}
void CSimpleTop::RegisterFrame(CSimpleFrame* frame) {
this->m_frames.LinkToTail(frame);
}
void CSimpleTop::SetCursor(MipBits* image) {
if (image) {
auto cursor = g_theGxDevicePtr->CursorLock();
memcpy(cursor, image->mip[0], CURSOR_IMAGE_BYTES);
g_theGxDevicePtr->CursorUnlock(0, 0);
g_theGxDevicePtr->CursorSetVisible(1);
}
}
void CSimpleTop::ShowFrame(CSimpleFrame* frame, int32_t a3) {
this->m_strata[frame->m_strata]->AddFrame(frame);
frame->RegisterForEvents(a3);
}
int32_t CSimpleTop::StartMoveOrResizeFrame(const CMouseEvent& start, MOVERESIZE_REASON reason, int32_t resize) {
// TODO
return 0;
}
int32_t CSimpleTop::StartMoveOrResizeFrame(CSimpleFrame* frame, MOVERESIZE_REASON reason, float startx, float starty, int32_t a6) {
// TODO
return 0;
}
int32_t CSimpleTop::StartMoveOrResizeFrame(CSimpleFrame* frame, MOVERESIZE_REASON reason, float startx, float starty, FRAMEPOINT a6) {
// TODO
return 0;
}
void CSimpleTop::UnregisterForEvent(CSimpleFrame* frame, CSimpleEventType event, int32_t a4) {
auto& queue = this->m_eventqueue[frame->m_strata][event];
int32_t found = 0;
for (int32_t i = 0; i < queue.Count(); i++) {
if (queue[i]->frame == frame) {
queue.Remove(i);
found = 1;
break;
}
}
if (!found) {
return;
}
if (!a4) {
if (event == SIMPLE_EVENT_KEY) {
for (int32_t i = 0; i < 787; i++) {
if (frame == this->m_keydownCapture[i]) {
this->m_keydownCapture[i] = nullptr;
}
}
} else if (event == SIMPLE_EVENT_MOUSE) {
if (frame == this->m_mouseCapture) {
this->m_mouseCapture = nullptr;
}
if (frame == this->m_mouseFocus) {
this->m_mouseFocus = nullptr;
this->m_checkFocus = 1;
if (frame->m_intAC != 3) {
frame->OnLayerCursorExit(0, 1);
}
}
}
}
}
void CSimpleTop::UnregisterFrame(CSimpleFrame* frame) {
this->HideFrame(frame, 0);
auto framesLink = this->m_frames.Link(frame);
if (framesLink) {
framesLink->Unlink();
}
}