312 lines
6.2 KiB
C++
312 lines
6.2 KiB
C++
|
|
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||
|
|
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||
|
|
// SPDX-License-Identifier: MIT
|
||
|
|
|
||
|
|
#include <TestFramework.h>
|
||
|
|
|
||
|
|
#include <Renderer/Renderer.h>
|
||
|
|
#include <UI/UIElement.h>
|
||
|
|
#include <UI/UIAnimation.h>
|
||
|
|
|
||
|
|
JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(UIElement)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
UIElement::UIElement() :
|
||
|
|
mID(-1),
|
||
|
|
mParent(nullptr),
|
||
|
|
mIsVisible(true),
|
||
|
|
mAnimatedIsVisible(true),
|
||
|
|
mIsHighlighted(false),
|
||
|
|
mIsSelected(false),
|
||
|
|
mIsDisabled(false),
|
||
|
|
mHasActivateAnimation(true),
|
||
|
|
mHasDeactivateAnimation(true),
|
||
|
|
mManager(nullptr)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
UIElement::~UIElement()
|
||
|
|
{
|
||
|
|
Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::Add(UIElement *inElement)
|
||
|
|
{
|
||
|
|
inElement->mParent = this;
|
||
|
|
inElement->mManager = mManager;
|
||
|
|
mChildren.push_back(inElement);
|
||
|
|
inElement->OnAdded();
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::Clear()
|
||
|
|
{
|
||
|
|
for (UIAnimation *a : mAnimations)
|
||
|
|
delete a;
|
||
|
|
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
delete e;
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::StartAnimation(UIAnimation *inAnimation)
|
||
|
|
{
|
||
|
|
mAnimations.push_back(inAnimation);
|
||
|
|
|
||
|
|
inAnimation->Init(this);
|
||
|
|
inAnimation->Update(this, 0.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::StopAnimation(const RTTI *inAnimationType)
|
||
|
|
{
|
||
|
|
for (int i = (int)mAnimations.size() - 1; i >= 0; --i)
|
||
|
|
if (mAnimations[i]->GetRTTI()->IsKindOf(inAnimationType))
|
||
|
|
{
|
||
|
|
mAnimations[i]->Exit(this);
|
||
|
|
delete mAnimations[i];
|
||
|
|
mAnimations.erase(mAnimations.begin() + i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UIElement *UIElement::Clone() const
|
||
|
|
{
|
||
|
|
UIElement *element = reinterpret_cast<UIElement *>(GetRTTI()->CreateObject());
|
||
|
|
CopyTo(element);
|
||
|
|
return element;
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::SetHighlighted(bool inHighlighted)
|
||
|
|
{
|
||
|
|
mIsHighlighted = inHighlighted;
|
||
|
|
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
e->SetHighlighted(inHighlighted);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::SetSelected(bool inSelected)
|
||
|
|
{
|
||
|
|
mIsSelected = inSelected;
|
||
|
|
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
e->SetSelected(inSelected);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::SetDisabled(bool inDisabled)
|
||
|
|
{
|
||
|
|
mIsDisabled = inDisabled;
|
||
|
|
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
e->SetDisabled(inDisabled);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::CopyTo(UIElement *ioElement) const
|
||
|
|
{
|
||
|
|
// Clone properties
|
||
|
|
ioElement->mID = mID;
|
||
|
|
ioElement->mRelativeX = mRelativeX;
|
||
|
|
ioElement->mRelativeY = mRelativeY;
|
||
|
|
ioElement->mWidth = mWidth;
|
||
|
|
ioElement->mHeight = mHeight;
|
||
|
|
ioElement->mIsVisible = mIsVisible;
|
||
|
|
ioElement->mAnimatedIsVisible = mAnimatedIsVisible;
|
||
|
|
ioElement->mHasActivateAnimation = mHasActivateAnimation;
|
||
|
|
ioElement->mHasDeactivateAnimation = mHasDeactivateAnimation;
|
||
|
|
ioElement->mManager = mManager;
|
||
|
|
|
||
|
|
// Clone children
|
||
|
|
for (const UIElement *e : mChildren)
|
||
|
|
ioElement->Add(e->Clone());
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UIElement::Contains(int inX, int inY) const
|
||
|
|
{
|
||
|
|
int x = GetX(), y = GetY();
|
||
|
|
return inX >= x && inX < x + GetWidth() && inY >= y && inY < y + GetHeight();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UIElement::ContainsWidened(int inX, int inY, int inBorder) const
|
||
|
|
{
|
||
|
|
int x = GetX(), y = GetY();
|
||
|
|
return inX >= x - inBorder && inX < x + GetWidth() + inBorder && inY >= y - inBorder && inY < y + GetHeight() + inBorder;
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::Update(float inDeltaTime)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < (int)mAnimations.size(); ++i)
|
||
|
|
{
|
||
|
|
UIAnimation *animation = mAnimations[i];
|
||
|
|
if (!animation->Update(this, inDeltaTime))
|
||
|
|
{
|
||
|
|
animation->Exit(this);
|
||
|
|
delete animation;
|
||
|
|
mAnimations.erase(mAnimations.begin() + i, mAnimations.begin() + i + 1);
|
||
|
|
--i;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
if (e->IsVisible())
|
||
|
|
e->Update(inDeltaTime);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::Draw() const
|
||
|
|
{
|
||
|
|
for (const UIElement *e : mChildren)
|
||
|
|
if (e->IsVisible())
|
||
|
|
e->Draw();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UIElement::MouseDown(int inX, int inY)
|
||
|
|
{
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
if (e->IsVisible() && !e->mIsDisabled)
|
||
|
|
if (e->MouseDown(inX, inY))
|
||
|
|
return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UIElement::MouseUp(int inX, int inY)
|
||
|
|
{
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
if (e->IsVisible() && !e->mIsDisabled)
|
||
|
|
if (e->MouseUp(inX, inY))
|
||
|
|
return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UIElement::MouseMove(int inX, int inY)
|
||
|
|
{
|
||
|
|
if (Contains(inX, inY))
|
||
|
|
mIsHighlighted = true;
|
||
|
|
else
|
||
|
|
mIsHighlighted = false;
|
||
|
|
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
if (e->IsVisible() && !e->mIsDisabled)
|
||
|
|
if (e->MouseMove(inX, inY))
|
||
|
|
return true;
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::MouseCancel()
|
||
|
|
{
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
if (e->IsVisible() && !e->mIsDisabled)
|
||
|
|
e->MouseCancel();
|
||
|
|
}
|
||
|
|
|
||
|
|
UIElement *UIElement::FindByID(int inID)
|
||
|
|
{
|
||
|
|
if (inID == mID)
|
||
|
|
return this;
|
||
|
|
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
{
|
||
|
|
UIElement *element = e->FindByID(inID);
|
||
|
|
if (element != nullptr)
|
||
|
|
return element;
|
||
|
|
}
|
||
|
|
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::AutoLayout()
|
||
|
|
{
|
||
|
|
for (UIElement *e : mChildren)
|
||
|
|
{
|
||
|
|
// Recurse
|
||
|
|
e->AutoLayout();
|
||
|
|
|
||
|
|
// Encapsulate height and width of children
|
||
|
|
if (e->IsVisible())
|
||
|
|
{
|
||
|
|
mWidth.Set(max(GetWidth(), e->GetX() + e->GetWidth() - GetX() + e->GetPaddingRight()), PIXELS);
|
||
|
|
mHeight.Set(max(GetHeight(), e->GetY() + e->GetHeight() - GetY() + e->GetPaddingBottom()), PIXELS);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UIElement::HandleUIEvent(EUIEvent inEvent, UIElement *inSender)
|
||
|
|
{
|
||
|
|
if (mParent != nullptr)
|
||
|
|
return mParent->HandleUIEvent(inEvent, inSender);
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::Size::Set(int inValue, EUnits inUnits)
|
||
|
|
{
|
||
|
|
mUnit = inUnits;
|
||
|
|
mSize = inValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
int UIElement::Size::GetSize(const UIElement *inElement, fGetSize inGetSize) const
|
||
|
|
{
|
||
|
|
switch (mUnit)
|
||
|
|
{
|
||
|
|
case PIXELS:
|
||
|
|
return mSize;
|
||
|
|
|
||
|
|
case PERCENTAGE:
|
||
|
|
{
|
||
|
|
const UIElement *parent = inElement->GetParent();
|
||
|
|
if (parent != nullptr)
|
||
|
|
return (mSize * (parent->*inGetSize)()) / 100;
|
||
|
|
else
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
JPH_ASSERT(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void UIElement::Position::Set(int inValue, EUnits inUnits, EAlignment inAlignment)
|
||
|
|
{
|
||
|
|
mAlignment = inAlignment;
|
||
|
|
mSize.Set(inValue, inUnits);
|
||
|
|
}
|
||
|
|
|
||
|
|
int UIElement::Position::GetPosition(const UIElement *inElement, fGetSize inGetSize) const
|
||
|
|
{
|
||
|
|
int pos = mSize.GetSize(inElement, inGetSize);
|
||
|
|
|
||
|
|
switch (mAlignment)
|
||
|
|
{
|
||
|
|
case LEFT:
|
||
|
|
return pos;
|
||
|
|
|
||
|
|
case ONE_THIRD:
|
||
|
|
{
|
||
|
|
const UIElement *parent = inElement->GetParent();
|
||
|
|
if (parent != nullptr)
|
||
|
|
return ((parent->*inGetSize)() - (inElement->*inGetSize)()) / 3 + pos;
|
||
|
|
else
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
case CENTER:
|
||
|
|
{
|
||
|
|
const UIElement *parent = inElement->GetParent();
|
||
|
|
if (parent != nullptr)
|
||
|
|
return ((parent->*inGetSize)() - (inElement->*inGetSize)()) / 2 + pos;
|
||
|
|
else
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
case RIGHT:
|
||
|
|
{
|
||
|
|
const UIElement *parent = inElement->GetParent();
|
||
|
|
if (parent != nullptr)
|
||
|
|
return (parent->*inGetSize)() - (inElement->*inGetSize)() + pos;
|
||
|
|
else
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
JPH_ASSERT(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|