Ajout de Jolt Physics + 1ere version des factory entitecomposants - camera, transform, rigidbody, collider, renderer
This commit is contained in:
11
lib/All/JoltPhysics/TestFramework/UI/UIAnimation.cpp
Normal file
11
lib/All/JoltPhysics/TestFramework/UI/UIAnimation.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UIAnimation.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(UIAnimation)
|
||||
{
|
||||
}
|
||||
26
lib/All/JoltPhysics/TestFramework/UI/UIAnimation.h
Normal file
26
lib/All/JoltPhysics/TestFramework/UI/UIAnimation.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Jolt/Core/RTTI.h>
|
||||
|
||||
class UIElement;
|
||||
|
||||
/// Base class for UI element animations
|
||||
class UIAnimation
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL_BASE(JPH_NO_EXPORT, UIAnimation)
|
||||
|
||||
/// Destructor
|
||||
virtual ~UIAnimation() = default;
|
||||
|
||||
///@name Interface
|
||||
virtual void Init(UIElement *inElement) { }
|
||||
virtual bool Update(UIElement *inElement, float inDeltaTime) { return true; } ///< Returns false when done
|
||||
virtual void Exit(UIElement *inElement) { }
|
||||
};
|
||||
|
||||
using UIAnimationVector = Array<UIAnimation *>;
|
||||
82
lib/All/JoltPhysics/TestFramework/UI/UIAnimationSlide.cpp
Normal file
82
lib/All/JoltPhysics/TestFramework/UI/UIAnimationSlide.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
// 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 <Window/ApplicationWindow.h>
|
||||
#include <UI/UIAnimationSlide.h>
|
||||
#include <UI/UIElement.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_ABSTRACT(UIAnimationSlide)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UIAnimationSlide, UIAnimation)
|
||||
}
|
||||
|
||||
UIAnimationSlide::UIAnimationSlide(EMode inMode, int inSlideDistanceH, int inSlideDistanceV, float inTimeBeforeSlide, float inSlideTime) :
|
||||
mSlideMode(inMode),
|
||||
mSlideDistanceH(inSlideDistanceH),
|
||||
mSlideDistanceV(inSlideDistanceV),
|
||||
mTimeBeforeSlide(inTimeBeforeSlide),
|
||||
mSlideTime(inSlideTime)
|
||||
{
|
||||
}
|
||||
|
||||
void UIAnimationSlide::Init(UIElement *inElement)
|
||||
{
|
||||
mTargetRelativeX = inElement->GetRelativeX();
|
||||
mTargetRelativeY = inElement->GetRelativeY();
|
||||
|
||||
ApplicationWindow *window = inElement->GetManager()->GetRenderer()->GetWindow();
|
||||
int dl = inElement->GetX();
|
||||
int dr = window->GetWindowWidth() - (inElement->GetX() + inElement->GetWidth());
|
||||
int dt = inElement->GetY();
|
||||
int db = window->GetWindowHeight() - (inElement->GetY() + inElement->GetHeight());
|
||||
|
||||
if (min(dl, dr) < min(dt, db))
|
||||
{
|
||||
mInitialRelativeX = mTargetRelativeX + (dl < dr? -mSlideDistanceH : mSlideDistanceH);
|
||||
mInitialRelativeY = mTargetRelativeY;
|
||||
}
|
||||
else
|
||||
{
|
||||
mInitialRelativeX = mTargetRelativeX;
|
||||
mInitialRelativeY = mTargetRelativeY + (dt < db? -mSlideDistanceV : mSlideDistanceV);
|
||||
}
|
||||
|
||||
if (mSlideMode == SLIDE_ON_SCREEN)
|
||||
inElement->SetAnimatedVisible(true);
|
||||
|
||||
mTime = 0.0f;
|
||||
}
|
||||
|
||||
bool UIAnimationSlide::Update(UIElement *inElement, float inDeltaTime)
|
||||
{
|
||||
mTime += inDeltaTime;
|
||||
|
||||
float factor = (mTime - mTimeBeforeSlide) / mSlideTime;
|
||||
if (factor >= 1.0f)
|
||||
return false;
|
||||
if (factor < 0.0f)
|
||||
factor = 0.0f;
|
||||
|
||||
if (mSlideMode == SLIDE_OFF_SCREEN)
|
||||
factor = 1.0f - factor;
|
||||
|
||||
float x = mInitialRelativeX * (1.0f - factor) + mTargetRelativeX * factor;
|
||||
float y = mInitialRelativeY * (1.0f - factor) + mTargetRelativeY * factor;
|
||||
|
||||
inElement->SetRelativeX((int)x);
|
||||
inElement->SetRelativeY((int)y);
|
||||
return true;
|
||||
}
|
||||
|
||||
void UIAnimationSlide::Exit(UIElement *inElement)
|
||||
{
|
||||
inElement->SetRelativeX(mTargetRelativeX);
|
||||
inElement->SetRelativeY(mTargetRelativeY);
|
||||
|
||||
inElement->SetAnimatedVisible(mSlideMode == SLIDE_ON_SCREEN);
|
||||
}
|
||||
41
lib/All/JoltPhysics/TestFramework/UI/UIAnimationSlide.h
Normal file
41
lib/All/JoltPhysics/TestFramework/UI/UIAnimationSlide.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIAnimation.h>
|
||||
|
||||
/// Animation that slides an element on or off screen
|
||||
class UIAnimationSlide : public UIAnimation
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_ABSTRACT(JPH_NO_EXPORT, UIAnimationSlide)
|
||||
|
||||
/// Mode of sliding
|
||||
enum EMode
|
||||
{
|
||||
SLIDE_ON_SCREEN,
|
||||
SLIDE_OFF_SCREEN,
|
||||
};
|
||||
|
||||
/// Constructor
|
||||
UIAnimationSlide(EMode inMode, int inSlideDistanceH, int inSlideDistanceV, float inTimeBeforeSlide, float inSlideTime);
|
||||
|
||||
///@name Interface
|
||||
virtual void Init(UIElement *inElement) override;
|
||||
virtual bool Update(UIElement *inElement, float inDeltaTime) override;
|
||||
virtual void Exit(UIElement *inElement) override;
|
||||
|
||||
private:
|
||||
EMode mSlideMode;
|
||||
int mSlideDistanceH;
|
||||
int mSlideDistanceV;
|
||||
float mTimeBeforeSlide;
|
||||
float mSlideTime;
|
||||
int mInitialRelativeX;
|
||||
int mInitialRelativeY;
|
||||
int mTargetRelativeX;
|
||||
int mTargetRelativeY;
|
||||
float mTime;
|
||||
};
|
||||
78
lib/All/JoltPhysics/TestFramework/UI/UIButton.cpp
Normal file
78
lib/All/JoltPhysics/TestFramework/UI/UIButton.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// 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/UIButton.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UIButton)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UIButton, UITextButton)
|
||||
}
|
||||
|
||||
void UIButton::CopyTo(UIElement *ioElement) const
|
||||
{
|
||||
UITextButton::CopyTo(ioElement);
|
||||
|
||||
UIButton *element = StaticCast<UIButton>(ioElement);
|
||||
element->mUpQuad = mUpQuad;
|
||||
element->mUpColor = mUpColor;
|
||||
element->mDownQuad = mDownQuad;
|
||||
element->mDownColor = mDownColor;
|
||||
element->mSelectedQuad = mSelectedQuad;
|
||||
element->mSelectedColor = mSelectedColor;
|
||||
element->mDisabledQuad = mDisabledQuad;
|
||||
element->mDisabledColor = mDisabledColor;
|
||||
}
|
||||
|
||||
void UIButton::Draw() const
|
||||
{
|
||||
if (mUpQuad.mTexture != nullptr)
|
||||
{
|
||||
int x = GetX(), y = GetY();
|
||||
const UITexturedQuad &q = IsDisabled()? mDisabledQuad : (mPressed? mDownQuad : (mIsHighlighted? mHighlightQuad : mUpQuad));
|
||||
Color c = IsDisabled()? mDisabledColor : (mPressed? mDownColor : (mIsHighlighted? mHighlightColor : mUpColor));
|
||||
int ew = GetWidth();
|
||||
int eh = GetHeight();
|
||||
|
||||
if (!q.HasInnerPart())
|
||||
{
|
||||
// Center image in button if it is smaller than the button
|
||||
int w = min(ew, q.mWidth);
|
||||
int h = min(eh, q.mHeight);
|
||||
int x2 = x + (ew - w) / 2;
|
||||
int y2 = y + (eh - h) / 2;
|
||||
GetManager()->DrawQuad(x2, y2, w, h, q, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a scale-9 quad, it will scale itself
|
||||
GetManager()->DrawQuad(x, y, ew, eh, q, c);
|
||||
}
|
||||
|
||||
// Draw selected quad
|
||||
if (mIsSelected)
|
||||
GetManager()->DrawQuad(x, y, ew, eh, mSelectedQuad, mSelectedColor);
|
||||
}
|
||||
|
||||
DrawCustom();
|
||||
|
||||
// Skip direct base classes, we modify text color
|
||||
UIElement::Draw();
|
||||
}
|
||||
|
||||
void UIButton::SetButtonQuad(const UITexturedQuad &inQuad)
|
||||
{
|
||||
mUpQuad = inQuad;
|
||||
mDownQuad = inQuad;
|
||||
mHighlightQuad = inQuad;
|
||||
mDisabledQuad = inQuad;
|
||||
|
||||
if (GetWidth() <= 0)
|
||||
SetWidth(inQuad.mWidth);
|
||||
if (GetHeight() <= 0)
|
||||
SetHeight(inQuad.mHeight);
|
||||
}
|
||||
36
lib/All/JoltPhysics/TestFramework/UI/UIButton.h
Normal file
36
lib/All/JoltPhysics/TestFramework/UI/UIButton.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UITextButton.h>
|
||||
#include <UI/UITexturedQuad.h>
|
||||
|
||||
/// Button with a background image and text on it
|
||||
class UIButton : public UITextButton
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UIButton)
|
||||
|
||||
/// Cloning / copying
|
||||
virtual void CopyTo(UIElement *ioElement) const override;
|
||||
|
||||
/// Draw element
|
||||
virtual void Draw() const override;
|
||||
|
||||
/// Set quad
|
||||
void SetButtonQuad(const UITexturedQuad &inQuad);
|
||||
|
||||
private:
|
||||
UITexturedQuad mUpQuad;
|
||||
Color mUpColor { Color(220, 220, 220) };
|
||||
UITexturedQuad mDownQuad;
|
||||
Color mDownColor { Color::sGrey };
|
||||
UITexturedQuad mHighlightQuad;
|
||||
Color mHighlightColor { Color::sWhite };
|
||||
UITexturedQuad mSelectedQuad;
|
||||
Color mSelectedColor { Color::sWhite };
|
||||
UITexturedQuad mDisabledQuad;
|
||||
Color mDisabledColor { Color::sGrey };
|
||||
};
|
||||
98
lib/All/JoltPhysics/TestFramework/UI/UICheckBox.cpp
Normal file
98
lib/All/JoltPhysics/TestFramework/UI/UICheckBox.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UICheckBox.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UICheckBox)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UICheckBox, UIStaticText)
|
||||
}
|
||||
|
||||
void UICheckBox::CopyTo(UIElement *ioElement) const
|
||||
{
|
||||
UIStaticText::CopyTo(ioElement);
|
||||
|
||||
UICheckBox *element = StaticCast<UICheckBox>(ioElement);
|
||||
element->mDownTextColor = mDownTextColor;
|
||||
element->mHighlightTextColor = mHighlightTextColor;
|
||||
element->mPaddingBetweenCheckboxAndText = mPaddingBetweenCheckboxAndText;
|
||||
element->mState = mState;
|
||||
element->mUncheckedState = mUncheckedState;
|
||||
element->mCheckedState = mCheckedState;
|
||||
element->mClickAction = mClickAction;
|
||||
}
|
||||
|
||||
void UICheckBox::OnAdded()
|
||||
{
|
||||
mTextPadLeft = max(mUncheckedState.mWidth, mCheckedState.mWidth) + mPaddingBetweenCheckboxAndText;
|
||||
}
|
||||
|
||||
bool UICheckBox::MouseDown(int inX, int inY)
|
||||
{
|
||||
if (UIStaticText::MouseDown(inX, inY))
|
||||
return true;
|
||||
|
||||
if (Contains(inX, inY))
|
||||
{
|
||||
mPressed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UICheckBox::MouseUp(int inX, int inY)
|
||||
{
|
||||
if (UIStaticText::MouseUp(inX, inY))
|
||||
return true;
|
||||
|
||||
if (mPressed)
|
||||
{
|
||||
mPressed = false;
|
||||
|
||||
if (Contains(inX, inY))
|
||||
{
|
||||
mState = mState == STATE_CHECKED? STATE_UNCHECKED : STATE_CHECKED;
|
||||
|
||||
if (mClickAction)
|
||||
mClickAction(mState);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UICheckBox::MouseMove(int inX, int inY)
|
||||
{
|
||||
if (UIStaticText::MouseMove(inX, inY))
|
||||
return true;
|
||||
|
||||
return mPressed;
|
||||
}
|
||||
|
||||
void UICheckBox::MouseCancel()
|
||||
{
|
||||
UIStaticText::MouseCancel();
|
||||
|
||||
mPressed = false;
|
||||
}
|
||||
|
||||
void UICheckBox::Draw() const
|
||||
{
|
||||
Color color = IsDisabled()? mDisabledTextColor : (mPressed? mDownTextColor : (mIsHighlighted? mHighlightTextColor : mTextColor));
|
||||
|
||||
UIStaticText::DrawCustom(color);
|
||||
|
||||
if (mState == STATE_UNCHECKED)
|
||||
GetManager()->DrawQuad(GetX(), GetY() + (GetHeight() - mUncheckedState.mHeight) / 2, mUncheckedState.mWidth, mUncheckedState.mHeight, mUncheckedState, color);
|
||||
else if (mState == STATE_CHECKED)
|
||||
GetManager()->DrawQuad(GetX(), GetY() + (GetHeight() - mCheckedState.mHeight) / 2, mCheckedState.mWidth, mCheckedState.mHeight, mCheckedState, color);
|
||||
|
||||
// Skip direct base class, we modify the text color
|
||||
UIElement::Draw();
|
||||
}
|
||||
58
lib/All/JoltPhysics/TestFramework/UI/UICheckBox.h
Normal file
58
lib/All/JoltPhysics/TestFramework/UI/UICheckBox.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIStaticText.h>
|
||||
#include <UI/UITexturedQuad.h>
|
||||
|
||||
/// Check box control that allows the user to select between true or false
|
||||
class UICheckBox : public UIStaticText
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UICheckBox)
|
||||
|
||||
enum EState
|
||||
{
|
||||
STATE_UNCHECKED,
|
||||
STATE_CHECKED
|
||||
};
|
||||
|
||||
using ClickAction = function<void(EState)>;
|
||||
|
||||
/// Properties
|
||||
void SetState(EState inState) { mState = inState; }
|
||||
EState GetState() const { return mState; }
|
||||
void SetClickAction(ClickAction inAction) { mClickAction = inAction; }
|
||||
void SetUncheckedStateQuad(const UITexturedQuad &inQuad) { mUncheckedState = inQuad; }
|
||||
void SetCheckedStateQuad(const UITexturedQuad &inQuad) { mCheckedState = inQuad; }
|
||||
|
||||
/// When added to a parent
|
||||
virtual void OnAdded() override;
|
||||
|
||||
/// Cloning / copying
|
||||
virtual void CopyTo(UIElement *ioElement) const override;
|
||||
|
||||
/// Actions
|
||||
virtual bool MouseDown(int inX, int inY) override;
|
||||
virtual bool MouseUp(int inX, int inY) override;
|
||||
virtual bool MouseMove(int inX, int inY) override;
|
||||
virtual void MouseCancel() override;
|
||||
|
||||
/// Draw element
|
||||
virtual void Draw() const override;
|
||||
|
||||
protected:
|
||||
/// Properties
|
||||
Color mDownTextColor { Color::sGrey };
|
||||
Color mHighlightTextColor { Color::sWhite };
|
||||
int mPaddingBetweenCheckboxAndText = 8;
|
||||
ClickAction mClickAction;
|
||||
UITexturedQuad mUncheckedState;
|
||||
UITexturedQuad mCheckedState;
|
||||
|
||||
/// State
|
||||
EState mState = STATE_UNCHECKED;
|
||||
bool mPressed = false;
|
||||
};
|
||||
88
lib/All/JoltPhysics/TestFramework/UI/UIComboBox.cpp
Normal file
88
lib/All/JoltPhysics/TestFramework/UI/UIComboBox.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UIComboBox.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UIComboBox)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UIComboBox, UIElement)
|
||||
}
|
||||
|
||||
void UIComboBox::CopyTo(UIElement *ioElement) const
|
||||
{
|
||||
UIElement::CopyTo(ioElement);
|
||||
|
||||
UIComboBox *element = StaticCast<UIComboBox>(ioElement);
|
||||
element->mCurrentItem = mCurrentItem;
|
||||
element->mItems = mItems;
|
||||
element->mPreviousButton = mPreviousButton;
|
||||
element->mNextButton = mNextButton;
|
||||
element->mStaticText = mStaticText;
|
||||
element->mItemChangedAction = mItemChangedAction;
|
||||
}
|
||||
|
||||
bool UIComboBox::HandleUIEvent(EUIEvent inEvent, UIElement *inSender)
|
||||
{
|
||||
if (inEvent == EVENT_BUTTON_DOWN)
|
||||
{
|
||||
if (inSender == mPreviousButton)
|
||||
{
|
||||
SetItemInternal(mCurrentItem - 1);
|
||||
return true;
|
||||
}
|
||||
else if (inSender == mNextButton)
|
||||
{
|
||||
SetItemInternal(mCurrentItem + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return UIElement::HandleUIEvent(inEvent, inSender);
|
||||
}
|
||||
|
||||
void UIComboBox::AutoLayout()
|
||||
{
|
||||
UIElement::AutoLayout();
|
||||
|
||||
// Position previous button
|
||||
mPreviousButton->SetRelativeX(0);
|
||||
mPreviousButton->SetRelativeY((GetHeight() - mPreviousButton->GetHeight()) / 2);
|
||||
|
||||
// Position static text
|
||||
mStaticText->SetRelativeX((GetWidth() - mStaticText->GetWidth()) / 2);
|
||||
mStaticText->SetRelativeY((GetHeight() - mStaticText->GetHeight()) / 2);
|
||||
|
||||
// Position next button
|
||||
mNextButton->SetRelativeX(GetWidth() - mNextButton->GetWidth());
|
||||
mNextButton->SetRelativeY((GetHeight() - mNextButton->GetHeight()) / 2);
|
||||
}
|
||||
|
||||
void UIComboBox::SetItemInternal(int inItem)
|
||||
{
|
||||
int old_item = mCurrentItem;
|
||||
|
||||
if (inItem < 0)
|
||||
mCurrentItem = 0;
|
||||
else if (inItem > int(mItems.size()) - 1)
|
||||
mCurrentItem = int(mItems.size()) - 1;
|
||||
else
|
||||
mCurrentItem = inItem;
|
||||
|
||||
if (mCurrentItem != old_item)
|
||||
{
|
||||
if (mItemChangedAction)
|
||||
mItemChangedAction(mCurrentItem);
|
||||
|
||||
UpdateStaticText();
|
||||
}
|
||||
}
|
||||
|
||||
void UIComboBox::UpdateStaticText()
|
||||
{
|
||||
if (mStaticText != nullptr)
|
||||
mStaticText->SetText(mItems[mCurrentItem]);
|
||||
}
|
||||
49
lib/All/JoltPhysics/TestFramework/UI/UIComboBox.h
Normal file
49
lib/All/JoltPhysics/TestFramework/UI/UIComboBox.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UITexturedQuad.h>
|
||||
#include <UI/UIButton.h>
|
||||
|
||||
/// Combo box with previous and next button
|
||||
class UIComboBox : public UIElement
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UIComboBox)
|
||||
|
||||
using ItemChangedAction = function<void(int)>;
|
||||
|
||||
/// Properties
|
||||
void SetItems(const Array<String> &inItems) { mItems = inItems; }
|
||||
void SetCurrentItem(int inItem) { mCurrentItem = inItem; }
|
||||
void SetPreviousButton(UIButton *inPreviousButton) { mPreviousButton = inPreviousButton; }
|
||||
void SetNextButton(UIButton *inNextButton) { mNextButton = inNextButton; }
|
||||
void SetStaticText(UIStaticText *inStaticText) { mStaticText = inStaticText; UpdateStaticText(); }
|
||||
void SetItemChangedAction(ItemChangedAction inAction) { mItemChangedAction = inAction; }
|
||||
|
||||
/// Cloning / copying
|
||||
virtual void CopyTo(UIElement *ioElement) const override;
|
||||
|
||||
/// Event handling (returns true if the event has been handled)
|
||||
virtual bool HandleUIEvent(EUIEvent inEvent, UIElement *inSender) override;
|
||||
|
||||
/// Calculate auto layout
|
||||
virtual void AutoLayout() override;
|
||||
|
||||
protected:
|
||||
/// Internal function to update the current item
|
||||
void SetItemInternal(int inItem);
|
||||
|
||||
/// Update static text box
|
||||
void UpdateStaticText();
|
||||
|
||||
/// Properties
|
||||
Array<String> mItems;
|
||||
int mCurrentItem = 0;
|
||||
UIButton * mPreviousButton = nullptr;
|
||||
UIButton * mNextButton = nullptr;
|
||||
UIStaticText * mStaticText = nullptr;
|
||||
ItemChangedAction mItemChangedAction;
|
||||
};
|
||||
311
lib/All/JoltPhysics/TestFramework/UI/UIElement.cpp
Normal file
311
lib/All/JoltPhysics/TestFramework/UI/UIElement.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
189
lib/All/JoltPhysics/TestFramework/UI/UIElement.h
Normal file
189
lib/All/JoltPhysics/TestFramework/UI/UIElement.h
Normal file
@@ -0,0 +1,189 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Jolt/Core/RTTI.h>
|
||||
#include <Jolt/Core/Color.h>
|
||||
#include <UI/UIEventListener.h>
|
||||
|
||||
class UIManager;
|
||||
class UIElement;
|
||||
class UIAnimation;
|
||||
|
||||
using UIElementVector = Array<UIElement *>;
|
||||
using UIAnimationVector = Array<UIAnimation *>;
|
||||
|
||||
/// Base class UI element. Forms a tree of UI elements.
|
||||
class UIElement : public UIEventListener
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL_BASE(JPH_NO_EXPORT, UIElement)
|
||||
|
||||
/// Constructor
|
||||
UIElement();
|
||||
virtual ~UIElement() override;
|
||||
|
||||
/// Add / remove child elements
|
||||
void Add(UIElement *inElement);
|
||||
void Clear();
|
||||
virtual void OnAdded() { }
|
||||
|
||||
/// Start / stop animations
|
||||
void StartAnimation(UIAnimation *inAnimation);
|
||||
void StopAnimation(const RTTI *inAnimationType);
|
||||
|
||||
/// Cloning / copying
|
||||
UIElement * Clone() const;
|
||||
virtual void CopyTo(UIElement *ioElement) const;
|
||||
|
||||
/// Units
|
||||
enum EUnits
|
||||
{
|
||||
PIXELS,
|
||||
PERCENTAGE,
|
||||
};
|
||||
|
||||
/// Alignment
|
||||
enum EAlignment
|
||||
{
|
||||
LEFT,
|
||||
ONE_THIRD,
|
||||
CENTER,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
/// Properties
|
||||
int GetID() const { return mID; }
|
||||
void SetID(int inID) { mID = inID; }
|
||||
int GetX() const { return GetRelativeX() + (mParent != nullptr? mParent->GetX() : 0); }
|
||||
int GetY() const { return GetRelativeY() + (mParent != nullptr? mParent->GetY() : 0); }
|
||||
int GetRelativeX() const { return mRelativeX.GetPosition(this, &UIElement::GetWidth); }
|
||||
void SetRelativeX(int inX, EUnits inUnits = PIXELS, EAlignment inAlignment = LEFT) { mRelativeX.Set(inX, inUnits, inAlignment); }
|
||||
int GetRelativeY() const { return mRelativeY.GetPosition(this, &UIElement::GetHeight); }
|
||||
void SetRelativeY(int inY, EUnits inUnits = PIXELS, EAlignment inAlignment = LEFT) { mRelativeY.Set(inY, inUnits, inAlignment); }
|
||||
int GetWidth() const { return mWidth.GetSize(this, &UIElement::GetWidth); }
|
||||
void SetWidth(int inWidth, EUnits inUnits = PIXELS) { mWidth.Set(inWidth, inUnits); }
|
||||
int GetHeight() const { return mHeight.GetSize(this, &UIElement::GetHeight); }
|
||||
void SetHeight(int inHeight, EUnits inUnits = PIXELS) { mHeight.Set(inHeight, inUnits); }
|
||||
int GetPaddingRight() const { return mPaddingRight.GetSize(this, &UIElement::GetWidth); }
|
||||
void SetPaddingRight(int inY, EUnits inUnits = PIXELS) { mPaddingRight.Set(inY, inUnits); }
|
||||
int GetPaddingBottom() const { return mPaddingBottom.GetSize(this, &UIElement::GetHeight); }
|
||||
void SetPaddingBottom(int inY, EUnits inUnits = PIXELS) { mPaddingBottom.Set(inY, inUnits); }
|
||||
void SetVisible(bool inShow) { mIsVisible = inShow; }
|
||||
bool IsVisible() const { return mIsVisible && mAnimatedIsVisible; }
|
||||
void SetDisabled(bool inDisabled);
|
||||
bool IsDisabled() const { return mIsDisabled; }
|
||||
void SetHighlighted(bool inHighlighted);
|
||||
bool IsHighlighted() const { return mIsHighlighted; }
|
||||
void SetSelected(bool inSelected);
|
||||
bool IsSelected() const { return mIsSelected; }
|
||||
|
||||
/// Animation
|
||||
void SetAnimatedVisible(bool inShow) { mAnimatedIsVisible = inShow; } ///< Visibility flag that can be set by UIAnimations
|
||||
bool HasActivateAnimation() const { return mHasActivateAnimation; }
|
||||
bool HasDeactivateAnimation() const { return mHasDeactivateAnimation; }
|
||||
|
||||
/// Manager
|
||||
UIManager * GetManager() const { return mManager; }
|
||||
|
||||
/// Parent child linking
|
||||
UIElement * GetParent() const { return mParent; }
|
||||
int GetNumChildren() const { return (int)mChildren.size(); }
|
||||
UIElement * GetChild(int inIdx) const { return mChildren[inIdx]; }
|
||||
const UIElementVector &GetChildren() const { return mChildren; }
|
||||
|
||||
/// Hit testing
|
||||
bool Contains(int inX, int inY) const;
|
||||
bool ContainsWidened(int inX, int inY, int inBorder) const;
|
||||
|
||||
/// Calculate auto layout
|
||||
virtual void AutoLayout();
|
||||
|
||||
/// Find element by ID
|
||||
virtual UIElement * FindByID(int inID);
|
||||
|
||||
/// Update element
|
||||
virtual void Update(float inDeltaTime);
|
||||
|
||||
/// Draw element
|
||||
virtual void Draw() const;
|
||||
|
||||
/// Actions
|
||||
virtual bool MouseDown(int inX, int inY);
|
||||
virtual bool MouseUp(int inX, int inY);
|
||||
virtual bool MouseMove(int inX, int inY);
|
||||
virtual void MouseCancel();
|
||||
|
||||
/// Event handling (returns true if the event has been handled)
|
||||
virtual bool HandleUIEvent(EUIEvent inEvent, UIElement *inSender) override;
|
||||
|
||||
protected:
|
||||
/// ID
|
||||
int mID;
|
||||
|
||||
/// Hierarchy
|
||||
UIElement * mParent;
|
||||
UIElementVector mChildren;
|
||||
|
||||
/// Abstract GetSize function
|
||||
using fGetSize = int (UIElement::*)() const;
|
||||
|
||||
/// Size
|
||||
class Size
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
Size() : mSize(0), mUnit(PIXELS) { }
|
||||
|
||||
/// Get size
|
||||
int GetSize(const UIElement *inElement, fGetSize inGetSize) const;
|
||||
|
||||
/// Assignment
|
||||
void Set(int inValue, EUnits inUnits);
|
||||
|
||||
private:
|
||||
int mSize;
|
||||
EUnits mUnit;
|
||||
};
|
||||
|
||||
/// Position
|
||||
class Position
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
Position() : mAlignment(LEFT) { }
|
||||
|
||||
/// Get position
|
||||
int GetPosition(const UIElement *inElement, fGetSize inGetSize) const;
|
||||
|
||||
/// Assignment
|
||||
void Set(int inValue, EUnits inUnits, EAlignment inAlignment);
|
||||
|
||||
private:
|
||||
EAlignment mAlignment;
|
||||
Size mSize;
|
||||
};
|
||||
|
||||
/// Position
|
||||
Position mRelativeX;
|
||||
Position mRelativeY;
|
||||
Size mWidth;
|
||||
Size mHeight;
|
||||
Size mPaddingRight;
|
||||
Size mPaddingBottom;
|
||||
bool mIsVisible;
|
||||
bool mAnimatedIsVisible;
|
||||
bool mIsHighlighted;
|
||||
bool mIsSelected;
|
||||
bool mIsDisabled;
|
||||
|
||||
/// Animations
|
||||
bool mHasActivateAnimation;
|
||||
bool mHasDeactivateAnimation;
|
||||
UIAnimationVector mAnimations;
|
||||
|
||||
/// Manager
|
||||
UIManager * mManager;
|
||||
};
|
||||
24
lib/All/JoltPhysics/TestFramework/UI/UIEventListener.h
Normal file
24
lib/All/JoltPhysics/TestFramework/UI/UIEventListener.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
enum EUIEvent
|
||||
{
|
||||
EVENT_BUTTON_DOWN,
|
||||
EVENT_MENU_DEACTIVATED,
|
||||
};
|
||||
|
||||
class UIElement;
|
||||
|
||||
/// Callback class for handling events from UI elements
|
||||
class UIEventListener
|
||||
{
|
||||
public:
|
||||
/// Destructor
|
||||
virtual ~UIEventListener() = default;
|
||||
|
||||
/// Handle an UI event, function should return true if event was handled
|
||||
virtual bool HandleUIEvent(EUIEvent inEvent, UIElement *inSender) = 0;
|
||||
};
|
||||
62
lib/All/JoltPhysics/TestFramework/UI/UIHorizontalStack.cpp
Normal file
62
lib/All/JoltPhysics/TestFramework/UI/UIHorizontalStack.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UIHorizontalStack.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UIHorizontalStack)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UIHorizontalStack, UIElement)
|
||||
}
|
||||
|
||||
void UIHorizontalStack::sUniformChildWidth(UIElement *inParent)
|
||||
{
|
||||
Array<int> sizes;
|
||||
sizes.resize(1, 0);
|
||||
for (UIElement *e : inParent->GetChildren())
|
||||
{
|
||||
e->AutoLayout();
|
||||
|
||||
UIHorizontalStack *horiz = DynamicCast<UIHorizontalStack>(e);
|
||||
if (horiz != nullptr)
|
||||
{
|
||||
if (horiz->GetNumChildren() > (int)sizes.size())
|
||||
sizes.resize(horiz->GetNumChildren(), 0);
|
||||
for (int i = 0; i < horiz->GetNumChildren(); ++i)
|
||||
sizes[i] = max(sizes[i], horiz->GetChild(i)->GetWidth());
|
||||
}
|
||||
else
|
||||
{
|
||||
sizes[0] = max(sizes[0], e->GetWidth());
|
||||
}
|
||||
}
|
||||
|
||||
for (UIElement *e : inParent->GetChildren())
|
||||
{
|
||||
UIHorizontalStack *horiz = DynamicCast<UIHorizontalStack>(e);
|
||||
if (horiz != nullptr)
|
||||
{
|
||||
for (int i = 0; i < horiz->GetNumChildren(); ++i)
|
||||
horiz->GetChild(i)->SetWidth(sizes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
e->SetWidth(sizes[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIHorizontalStack::AutoLayout()
|
||||
{
|
||||
UIElement::AutoLayout();
|
||||
|
||||
mWidth.Set(0, PIXELS);
|
||||
for (UIElement *e : mChildren)
|
||||
if (e->IsVisible() || mPlaceInvisibleChildren)
|
||||
{
|
||||
e->SetRelativeX(GetWidth());
|
||||
mWidth.Set(GetWidth() + e->GetWidth() + e->GetPaddingRight() + mDeltaX, PIXELS);
|
||||
}
|
||||
}
|
||||
27
lib/All/JoltPhysics/TestFramework/UI/UIHorizontalStack.h
Normal file
27
lib/All/JoltPhysics/TestFramework/UI/UIHorizontalStack.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIElement.h>
|
||||
|
||||
/// Layout class that will horizontally place elements next to each other according to their widths
|
||||
class UIHorizontalStack : public UIElement
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UIHorizontalStack)
|
||||
|
||||
/// Helper function to resize a list of child elements consisting of UIHorizontalStack's to make them the same width.
|
||||
/// Can be used to give them the appearance of a table.
|
||||
/// Find the width of all UIHorizontalStack child elements in inParent and use the maximum width for all of them
|
||||
/// Non UIHorizontalStack elements will be treated as a UIHorizontalStack with only 1 element inside
|
||||
static void sUniformChildWidth(UIElement *inParent);
|
||||
|
||||
/// Calculate auto layout
|
||||
virtual void AutoLayout() override;
|
||||
|
||||
private:
|
||||
int mDeltaX = 0;
|
||||
bool mPlaceInvisibleChildren = false;
|
||||
};
|
||||
29
lib/All/JoltPhysics/TestFramework/UI/UIImage.cpp
Normal file
29
lib/All/JoltPhysics/TestFramework/UI/UIImage.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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/UIImage.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UIImage)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UIImage, UIElement)
|
||||
}
|
||||
|
||||
void UIImage::Draw() const
|
||||
{
|
||||
GetManager()->DrawQuad(GetX(), GetY(), GetWidth(), GetHeight(), mImage, Color::sWhite);
|
||||
|
||||
UIElement::Draw();
|
||||
}
|
||||
|
||||
void UIImage::CopyTo(UIElement *ioElement) const
|
||||
{
|
||||
UIElement::CopyTo(ioElement);
|
||||
|
||||
UIImage *element = StaticCast<UIImage>(ioElement);
|
||||
element->mImage = mImage;
|
||||
}
|
||||
27
lib/All/JoltPhysics/TestFramework/UI/UIImage.h
Normal file
27
lib/All/JoltPhysics/TestFramework/UI/UIImage.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIElement.h>
|
||||
#include <UI/UITexturedQuad.h>
|
||||
|
||||
/// A static image UI element
|
||||
class UIImage : public UIElement
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UIImage)
|
||||
|
||||
/// Set properties
|
||||
void SetImage(const UITexturedQuad &inImage) { mImage = inImage; }
|
||||
|
||||
/// Cloning / copying
|
||||
virtual void CopyTo(UIElement *ioElement) const override;
|
||||
|
||||
/// Draw element
|
||||
virtual void Draw() const override;
|
||||
|
||||
private:
|
||||
UITexturedQuad mImage;
|
||||
};
|
||||
342
lib/All/JoltPhysics/TestFramework/UI/UIManager.cpp
Normal file
342
lib/All/JoltPhysics/TestFramework/UI/UIManager.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UIManager.h>
|
||||
#include <UI/UIAnimationSlide.h>
|
||||
#include <Jolt/Core/Profiler.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Renderer/Font.h>
|
||||
|
||||
struct QuadVertex
|
||||
{
|
||||
Float3 mPosition;
|
||||
Float2 mTexCoord;
|
||||
Color mColor;
|
||||
};
|
||||
|
||||
UIManager::UIManager(Renderer *inRenderer) :
|
||||
mRenderer(inRenderer),
|
||||
mListener(nullptr),
|
||||
mState(STATE_INVALID)
|
||||
{
|
||||
mManager = this;
|
||||
|
||||
// Set dimensions of the screen
|
||||
ApplicationWindow *window = mRenderer->GetWindow();
|
||||
SetWidth(window->GetWindowWidth());
|
||||
SetHeight(window->GetWindowHeight());
|
||||
|
||||
// Create input layout
|
||||
const PipelineState::EInputDescription vertex_desc[] =
|
||||
{
|
||||
PipelineState::EInputDescription::Position,
|
||||
PipelineState::EInputDescription::TexCoord,
|
||||
PipelineState::EInputDescription::Color
|
||||
};
|
||||
|
||||
// Load vertex shader
|
||||
Ref<VertexShader> vtx = mRenderer->CreateVertexShader("UIVertexShader");
|
||||
|
||||
// Load pixel shader
|
||||
Ref<PixelShader> pix_textured = mRenderer->CreatePixelShader("UIPixelShader");
|
||||
Ref<PixelShader> pix_untextured = mRenderer->CreatePixelShader("UIPixelShaderUntextured");
|
||||
|
||||
mTextured = mRenderer->CreatePipelineState(vtx, vertex_desc, std::size(vertex_desc), pix_textured, PipelineState::EDrawPass::Normal, PipelineState::EFillMode::Solid, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::Off, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
|
||||
mUntextured = mRenderer->CreatePipelineState(vtx, vertex_desc, std::size(vertex_desc), pix_untextured, PipelineState::EDrawPass::Normal, PipelineState::EFillMode::Solid, PipelineState::ETopology::Triangle, PipelineState::EDepthTest::Off, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
|
||||
}
|
||||
|
||||
UIManager::~UIManager()
|
||||
{
|
||||
while (!mInactiveElements.empty())
|
||||
PopLayer();
|
||||
}
|
||||
|
||||
// Update elements
|
||||
void UIManager::Update(float inDeltaTime)
|
||||
{
|
||||
JPH_PROFILE_FUNCTION();
|
||||
|
||||
// Update inactive elements (array can resize at any time, so no iterators and extra checking here)
|
||||
for (int i = (int)mInactiveElements.size() - 1; i >= 0; --i)
|
||||
for (int j = 0; i < (int)mInactiveElements.size() && j < (int)mInactiveElements[i].size(); ++j)
|
||||
mInactiveElements[i][j]->Update(inDeltaTime);
|
||||
|
||||
// Update elements
|
||||
UIElement::Update(inDeltaTime);
|
||||
|
||||
// Update state
|
||||
mStateTime += inDeltaTime;
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_ACTIVATING:
|
||||
if (mStateTime > cActivateScreenTime)
|
||||
SwitchToState(STATE_ACTIVE);
|
||||
break;
|
||||
|
||||
case STATE_DEACTIVATING:
|
||||
if (mStateTime > cActivateScreenTime)
|
||||
SwitchToState(STATE_DEACTIVE);
|
||||
break;
|
||||
|
||||
case STATE_ACTIVE:
|
||||
case STATE_DEACTIVE:
|
||||
case STATE_INVALID:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UIManager::Draw() const
|
||||
{
|
||||
JPH_PROFILE_FUNCTION();
|
||||
|
||||
// Switch tho ortho mode
|
||||
mRenderer->SetOrthoMode();
|
||||
|
||||
// Draw inactive elements first
|
||||
if (mDrawInactiveElements)
|
||||
for (int i = (int)mInactiveElements.size() - 1; i >= 0; --i)
|
||||
for (const UIElement *j : mInactiveElements[i])
|
||||
if (j->IsVisible())
|
||||
j->Draw();
|
||||
|
||||
// Then draw active elements
|
||||
UIElement::Draw();
|
||||
|
||||
// Restore state
|
||||
mRenderer->SetProjectionMode();
|
||||
}
|
||||
|
||||
void UIManager::PushLayer()
|
||||
{
|
||||
mInactiveElements.push_back(mChildren);
|
||||
mChildren.clear();
|
||||
}
|
||||
|
||||
void UIManager::PopLayer()
|
||||
{
|
||||
Clear();
|
||||
|
||||
mChildren = mInactiveElements.back();
|
||||
mInactiveElements.pop_back();
|
||||
}
|
||||
|
||||
UIElement *UIManager::FindByID(int inID)
|
||||
{
|
||||
UIElement *element = UIElement::FindByID(inID);
|
||||
if (element != nullptr)
|
||||
return element;
|
||||
|
||||
for (int i = (int)mInactiveElements.size() - 1; i >= 0; --i)
|
||||
for (int j = 0; j < (int)mInactiveElements[i].size(); ++j)
|
||||
{
|
||||
element = mInactiveElements[i][j]->FindByID(inID);
|
||||
if (element != nullptr)
|
||||
return element;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UIManager::HandleUIEvent(EUIEvent inEvent, UIElement *inSender)
|
||||
{
|
||||
if (UIElement::HandleUIEvent(inEvent, inSender))
|
||||
return true;
|
||||
|
||||
return mListener != nullptr && mListener->HandleUIEvent(inEvent, inSender);
|
||||
}
|
||||
|
||||
void UIManager::GetMaxElementDistanceToScreenEdge(int &outMaxH, int &outMaxV)
|
||||
{
|
||||
outMaxH = 0;
|
||||
outMaxV = 0;
|
||||
|
||||
ApplicationWindow *window = mRenderer->GetWindow();
|
||||
for (const UIElement *e : mChildren)
|
||||
if (e->HasDeactivateAnimation())
|
||||
{
|
||||
int dl = e->GetX() + e->GetWidth();
|
||||
int dr = window->GetWindowWidth() - e->GetX();
|
||||
outMaxH = max(outMaxH, min(dl, dr));
|
||||
int dt = e->GetY() + e->GetHeight();
|
||||
int db = window->GetWindowHeight() - e->GetY();
|
||||
outMaxV = max(outMaxV, min(dt, db));
|
||||
}
|
||||
}
|
||||
|
||||
void UIManager::SwitchToState(EState inState)
|
||||
{
|
||||
// Clean up old state
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_ACTIVATING:
|
||||
case STATE_DEACTIVATING:
|
||||
for (UIElement *e : mChildren)
|
||||
e->StopAnimation(JPH_RTTI(UIAnimationSlide));
|
||||
break;
|
||||
|
||||
case STATE_ACTIVE:
|
||||
case STATE_DEACTIVE:
|
||||
case STATE_INVALID:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Store new state
|
||||
mState = inState;
|
||||
mStateTime = 0.0f;
|
||||
|
||||
// Calculate max horizontal and vertical distance of elements to edge of screen
|
||||
int max_h, max_v;
|
||||
GetMaxElementDistanceToScreenEdge(max_h, max_v);
|
||||
|
||||
switch (inState)
|
||||
{
|
||||
case STATE_ACTIVATING:
|
||||
for (UIElement *e : mChildren)
|
||||
if (e->HasActivateAnimation())
|
||||
e->StartAnimation(new UIAnimationSlide(UIAnimationSlide::SLIDE_ON_SCREEN, max_h, max_v, 0.0f, cActivateScreenTime));
|
||||
break;
|
||||
|
||||
case STATE_DEACTIVATING:
|
||||
for (UIElement *e : mChildren)
|
||||
if (e->HasDeactivateAnimation())
|
||||
e->StartAnimation(new UIAnimationSlide(UIAnimationSlide::SLIDE_OFF_SCREEN, max_h, max_v, 0.0f, cActivateScreenTime));
|
||||
break;
|
||||
|
||||
case STATE_DEACTIVE:
|
||||
HandleUIEvent(EVENT_MENU_DEACTIVATED, this);
|
||||
|
||||
if (mDeactivatedAction)
|
||||
mDeactivatedAction();
|
||||
break;
|
||||
|
||||
case STATE_ACTIVE:
|
||||
case STATE_INVALID:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void sDrawQuad(QuadVertex *&v ,float x1, float y1, float x2, float y2, float tx1, float ty1, float tx2, float ty2, ColorArg inColor)
|
||||
{
|
||||
v->mPosition = Float3(x1, y1, 0);
|
||||
v->mTexCoord = Float2(tx1, ty1);
|
||||
v->mColor = inColor;
|
||||
++v;
|
||||
|
||||
v->mPosition = Float3(x1, y2, 0);
|
||||
v->mTexCoord = Float2(tx1, ty2);
|
||||
v->mColor = inColor;
|
||||
++v;
|
||||
|
||||
v->mPosition = Float3(x2, y2, 0);
|
||||
v->mTexCoord = Float2(tx2, ty2);
|
||||
v->mColor = inColor;
|
||||
++v;
|
||||
|
||||
v->mPosition = Float3(x1, y1, 0);
|
||||
v->mTexCoord = Float2(tx1, ty1);
|
||||
v->mColor = inColor;
|
||||
++v;
|
||||
|
||||
v->mPosition = Float3(x2, y2, 0);
|
||||
v->mTexCoord = Float2(tx2, ty2);
|
||||
v->mColor = inColor;
|
||||
++v;
|
||||
|
||||
v->mPosition = Float3(x2, y1, 0);
|
||||
v->mTexCoord = Float2(tx2, ty1);
|
||||
v->mColor = inColor;
|
||||
++v;
|
||||
}
|
||||
|
||||
void UIManager::DrawQuad(int inX, int inY, int inWidth, int inHeight, const UITexturedQuad &inQuad, ColorArg inColor)
|
||||
{
|
||||
// Outer area - screen coordinates
|
||||
float x1 = float(inX);
|
||||
float y1 = float(inY);
|
||||
float x2 = float(inX + inWidth);
|
||||
float y2 = float(inY + inHeight);
|
||||
|
||||
if (inQuad.mTexture != nullptr)
|
||||
{
|
||||
bool has_inner = inQuad.HasInnerPart();
|
||||
|
||||
Ref<RenderPrimitive> primitive = mRenderer->CreateRenderPrimitive(PipelineState::ETopology::Triangle);
|
||||
primitive->CreateVertexBuffer(has_inner? 9 * 6 : 6, sizeof(QuadVertex));
|
||||
|
||||
float w = float(inQuad.mTexture->GetWidth()), h = float(inQuad.mTexture->GetHeight());
|
||||
|
||||
// Outer area - texture coordinates
|
||||
float tx1 = float(inQuad.mX);
|
||||
float ty1 = float(inQuad.mY);
|
||||
float tx2 = float(inQuad.mX + inQuad.mWidth);
|
||||
float ty2 = float(inQuad.mY + inQuad.mHeight);
|
||||
tx1 /= w; ty1 /= h;
|
||||
tx2 /= w; ty2 /= h;
|
||||
|
||||
QuadVertex *v = (QuadVertex *)primitive->LockVertexBuffer();
|
||||
|
||||
if (has_inner)
|
||||
{
|
||||
// Inner area - screen coordinates
|
||||
float ix1 = float(inX + inQuad.mInnerX - inQuad.mX);
|
||||
float iy1 = float(inY + inQuad.mInnerY - inQuad.mY);
|
||||
float ix2 = float(inX + inWidth - (inQuad.mWidth - inQuad.mInnerWidth - (inQuad.mInnerX - inQuad.mX)));
|
||||
float iy2 = float(inY + inHeight - (inQuad.mHeight - inQuad.mInnerHeight - (inQuad.mInnerY - inQuad.mY)));
|
||||
|
||||
// Inner area - texture coordinates
|
||||
float itx1 = float(inQuad.mInnerX);
|
||||
float ity1 = float(inQuad.mInnerY);
|
||||
float itx2 = float(inQuad.mInnerX + inQuad.mInnerWidth);
|
||||
float ity2 = float(inQuad.mInnerY + inQuad.mInnerHeight);
|
||||
itx1 /= w; ity1 /= h;
|
||||
itx2 /= w; ity2 /= h;
|
||||
|
||||
sDrawQuad(v, x1, y1, ix1, iy1, tx1, ty1, itx1, ity1, inColor);
|
||||
sDrawQuad(v, ix1, y1, ix2, iy1, itx1, ty1, itx2, ity1, inColor);
|
||||
sDrawQuad(v, ix2, y1, x2, iy1, itx2, ty1, tx2, ity1, inColor);
|
||||
|
||||
sDrawQuad(v, x1, iy1, ix1, iy2, tx1, ity1, itx1, ity2, inColor);
|
||||
sDrawQuad(v, ix1, iy1, ix2, iy2, itx1, ity1, itx2, ity2, inColor);
|
||||
sDrawQuad(v, ix2, iy1, x2, iy2, itx2, ity1, tx2, ity2, inColor);
|
||||
|
||||
sDrawQuad(v, x1, iy2, ix1, y2, tx1, ity2, itx1, ty2, inColor);
|
||||
sDrawQuad(v, ix1, iy2, ix2, y2, itx1, ity2, itx2, ty2, inColor);
|
||||
sDrawQuad(v, ix2, iy2, x2, y2, itx2, ity2, tx2, ty2, inColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
sDrawQuad(v, x1, y1, x2, y2, tx1, ty1, tx2, ty2, inColor);
|
||||
}
|
||||
|
||||
primitive->UnlockVertexBuffer();
|
||||
inQuad.mTexture->Bind();
|
||||
mTextured->Activate();
|
||||
primitive->Draw();
|
||||
}
|
||||
else
|
||||
{
|
||||
Ref<RenderPrimitive> primitive = mRenderer->CreateRenderPrimitive(PipelineState::ETopology::Triangle);
|
||||
primitive->CreateVertexBuffer(6, sizeof(QuadVertex));
|
||||
QuadVertex *v = (QuadVertex *)primitive->LockVertexBuffer();
|
||||
sDrawQuad(v, x1, y1, x2, y2, 0, 0, 0, 0, inColor);
|
||||
primitive->UnlockVertexBuffer();
|
||||
mUntextured->Activate();
|
||||
primitive->Draw();
|
||||
}
|
||||
}
|
||||
|
||||
void UIManager::DrawText(int inX, int inY, const string_view &inText, const Font *inFont, ColorArg inColor)
|
||||
{
|
||||
Vec4 pos(float(inX), float(inY), 0.0f, 1.0f);
|
||||
Vec4 right(float(inFont->GetCharHeight()), 0.0f, 0.0f, 0.0f);
|
||||
Vec4 up(0.0f, float(-inFont->GetCharHeight()), 0.0f, 0.0f);
|
||||
Vec4 forward(0.0f, 0.0f, 1.0f, 0.0f);
|
||||
Mat44 transform(right, up, forward, pos);
|
||||
inFont->DrawText3D(transform, inText, inColor);
|
||||
}
|
||||
86
lib/All/JoltPhysics/TestFramework/UI/UIManager.h
Normal file
86
lib/All/JoltPhysics/TestFramework/UI/UIManager.h
Normal file
@@ -0,0 +1,86 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIElement.h>
|
||||
#include <UI/UITexturedQuad.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Renderer/PipelineState.h>
|
||||
#include <memory>
|
||||
|
||||
class Font;
|
||||
|
||||
const float cActivateScreenTime = 0.2f;
|
||||
|
||||
/// Manager class that manages UIElements
|
||||
class UIManager : public UIElement
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
UIManager(Renderer *inRenderer);
|
||||
virtual ~UIManager() override;
|
||||
|
||||
/// Update elements
|
||||
virtual void Update(float inDeltaTime) override;
|
||||
|
||||
/// Draw elements
|
||||
virtual void Draw() const override;
|
||||
|
||||
/// Only one layer can be active, if you push a layer it will exit in the background and no longer be updated
|
||||
void PushLayer();
|
||||
void PopLayer();
|
||||
int GetNumLayers() const { return (int)mInactiveElements.size() + 1; }
|
||||
void SetDrawInactiveLayers(bool inDraw) { mDrawInactiveElements = inDraw; }
|
||||
|
||||
/// Find element by ID
|
||||
virtual UIElement * FindByID(int inID) override;
|
||||
|
||||
/// Listeners
|
||||
void SetListener(UIEventListener *inListener) { mListener = inListener; }
|
||||
UIEventListener * GetListener() const { return mListener; }
|
||||
|
||||
/// Actions
|
||||
void SetDeactivatedAction(function<void()> inAction) { mDeactivatedAction = inAction; }
|
||||
|
||||
/// Event handling (returns true if the event has been handled)
|
||||
virtual bool HandleUIEvent(EUIEvent inEvent, UIElement *inSender) override;
|
||||
|
||||
/// Current state
|
||||
enum EState
|
||||
{
|
||||
STATE_INVALID,
|
||||
STATE_ACTIVATING,
|
||||
STATE_ACTIVE,
|
||||
STATE_DEACTIVATING,
|
||||
STATE_DEACTIVE
|
||||
};
|
||||
|
||||
void SwitchToState(EState inState);
|
||||
EState GetState() const { return mState; }
|
||||
|
||||
/// Calculate max horizontal and vertical distance of elements to edge of screen
|
||||
void GetMaxElementDistanceToScreenEdge(int &outMaxH, int &outMaxV);
|
||||
|
||||
/// Access to the renderer
|
||||
Renderer * GetRenderer() { return mRenderer; }
|
||||
|
||||
/// Drawing
|
||||
void DrawQuad(int inX, int inY, int inWidth, int inHeight, const UITexturedQuad &inQuad, ColorArg inColor);
|
||||
|
||||
/// Draw a string in screen coordinates (assumes that the projection matrix has been set up correctly)
|
||||
void DrawText(int inX, int inY, const string_view &inText, const Font *inFont, ColorArg inColor = Color::sWhite);
|
||||
|
||||
private:
|
||||
Renderer * mRenderer;
|
||||
UIEventListener * mListener;
|
||||
Array<UIElementVector> mInactiveElements;
|
||||
bool mDrawInactiveElements = true;
|
||||
unique_ptr<PipelineState> mTextured;
|
||||
unique_ptr<PipelineState> mUntextured;
|
||||
function<void()> mDeactivatedAction;
|
||||
|
||||
EState mState;
|
||||
float mStateTime;
|
||||
};
|
||||
186
lib/All/JoltPhysics/TestFramework/UI/UISlider.cpp
Normal file
186
lib/All/JoltPhysics/TestFramework/UI/UISlider.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UISlider.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UISlider)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UISlider, UIElement)
|
||||
}
|
||||
|
||||
void UISlider::CopyTo(UIElement *ioElement) const
|
||||
{
|
||||
UIElement::CopyTo(ioElement);
|
||||
|
||||
UISlider *element = StaticCast<UISlider>(ioElement);
|
||||
element->mCurrentValue = mCurrentValue;
|
||||
element->mMinValue = mMinValue;
|
||||
element->mMaxValue = mMaxValue;
|
||||
element->mStepValue = mStepValue;
|
||||
element->mDecreaseButton = mDecreaseButton;
|
||||
element->mIncreaseButton = mIncreaseButton;
|
||||
element->mSpaceBetweenButtonAndSlider = mSpaceBetweenButtonAndSlider;
|
||||
element->mSlider = mSlider;
|
||||
element->mThumb = mThumb;
|
||||
element->mValueChangedAction = mValueChangedAction;
|
||||
}
|
||||
|
||||
void UISlider::GetSliderRange(int &outSliderStart, int &outSliderEnd) const
|
||||
{
|
||||
outSliderStart = GetX() + mDecreaseButton->GetWidth() + mSpaceBetweenButtonAndSlider;
|
||||
outSliderEnd = GetX() + GetWidth() - mIncreaseButton->GetWidth() - mSpaceBetweenButtonAndSlider;
|
||||
}
|
||||
|
||||
int UISlider::GetThumbStart(int inSliderStart, int inSliderEnd) const
|
||||
{
|
||||
return inSliderStart + int(float(inSliderEnd - inSliderStart - mThumb.mWidth) * (mCurrentValue - mMinValue) / (mMaxValue - mMinValue));
|
||||
}
|
||||
|
||||
bool UISlider::HandleUIEvent(EUIEvent inEvent, UIElement *inSender)
|
||||
{
|
||||
if (inEvent == EVENT_BUTTON_DOWN)
|
||||
{
|
||||
if (inSender == mDecreaseButton)
|
||||
{
|
||||
SetValueInternal(mCurrentValue - mStepValue);
|
||||
return true;
|
||||
}
|
||||
else if (inSender == mIncreaseButton)
|
||||
{
|
||||
SetValueInternal(mCurrentValue + mStepValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return UIElement::HandleUIEvent(inEvent, inSender);
|
||||
}
|
||||
|
||||
bool UISlider::MouseDown(int inX, int inY)
|
||||
{
|
||||
if (Contains(inX, inY))
|
||||
{
|
||||
int slider_start, slider_end;
|
||||
GetSliderRange(slider_start, slider_end);
|
||||
|
||||
int tx = GetThumbStart(slider_start, slider_end);
|
||||
if (inX >= tx && inX < tx + mThumb.mWidth)
|
||||
{
|
||||
mThumbDragPoint = inX - tx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return UIElement::MouseDown(inX, inY);
|
||||
}
|
||||
|
||||
bool UISlider::MouseUp(int inX, int inY)
|
||||
{
|
||||
if (mThumbDragPoint != -1)
|
||||
{
|
||||
mThumbDragPoint = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return UIElement::MouseUp(inX, inY);
|
||||
}
|
||||
|
||||
bool UISlider::MouseMove(int inX, int inY)
|
||||
{
|
||||
if (mThumbDragPoint != -1)
|
||||
{
|
||||
// Calculate new value
|
||||
int slider_start, slider_end;
|
||||
GetSliderRange(slider_start, slider_end);
|
||||
SetValueInternal(mMinValue + float(inX - mThumbDragPoint - slider_start) * (mMaxValue - mMinValue) / float(slider_end - slider_start - mThumb.mWidth));
|
||||
return true;
|
||||
}
|
||||
|
||||
return UIElement::MouseMove(inX, inY);
|
||||
}
|
||||
|
||||
void UISlider::MouseCancel()
|
||||
{
|
||||
UIElement::MouseCancel();
|
||||
|
||||
mThumbDragPoint = -1;
|
||||
}
|
||||
|
||||
void UISlider::Draw() const
|
||||
{
|
||||
UIElement::Draw();
|
||||
|
||||
int slider_start, slider_end;
|
||||
GetSliderRange(slider_start, slider_end);
|
||||
|
||||
// Draw slider
|
||||
int sy = (GetHeight() - mSlider.mHeight) / 2;
|
||||
GetManager()->DrawQuad(slider_start, GetY() + sy, slider_end - slider_start, mSlider.mHeight, mSlider, Color::sWhite);
|
||||
|
||||
// Draw thumb
|
||||
int tx = GetThumbStart(slider_start, slider_end);
|
||||
int ty = (GetHeight() - mThumb.mHeight) / 2;
|
||||
GetManager()->DrawQuad(tx, GetY() + ty, mThumb.mWidth, mThumb.mHeight, mThumb, Color::sWhite);
|
||||
}
|
||||
|
||||
void UISlider::AutoLayout()
|
||||
{
|
||||
UIElement::AutoLayout();
|
||||
|
||||
// Position decrease button
|
||||
mDecreaseButton->SetRelativeX(0);
|
||||
mDecreaseButton->SetRelativeY((GetHeight() - mDecreaseButton->GetHeight()) / 2);
|
||||
|
||||
// Position increase button
|
||||
mIncreaseButton->SetRelativeX(GetWidth() - mIncreaseButton->GetWidth());
|
||||
mIncreaseButton->SetRelativeY((GetHeight() - mIncreaseButton->GetHeight()) / 2);
|
||||
}
|
||||
|
||||
void UISlider::SetValueInternal(float inValue)
|
||||
{
|
||||
float old_value = mCurrentValue;
|
||||
|
||||
float step = round((inValue - mMinValue) / mStepValue);
|
||||
mCurrentValue = Clamp(mMinValue + step * mStepValue, mMinValue, mMaxValue);
|
||||
|
||||
if (mCurrentValue != old_value)
|
||||
{
|
||||
if (mValueChangedAction)
|
||||
mValueChangedAction(mCurrentValue);
|
||||
|
||||
UpdateStaticText();
|
||||
}
|
||||
}
|
||||
|
||||
void UISlider::UpdateStaticText()
|
||||
{
|
||||
if (mStaticText != nullptr)
|
||||
{
|
||||
float step_frac = mStepValue - trunc(mStepValue);
|
||||
float min_frac = mMinValue - trunc(mMinValue);
|
||||
float max_frac = mMaxValue - trunc(mMaxValue);
|
||||
|
||||
float smallest = step_frac;
|
||||
if (min_frac < smallest && abs(min_frac) > 1.0e-6f)
|
||||
smallest = min_frac;
|
||||
if (max_frac < smallest && abs(max_frac) > 1.0e-6f)
|
||||
smallest = max_frac;
|
||||
|
||||
if (smallest == 0.0f)
|
||||
{
|
||||
// Integer values
|
||||
mStaticText->SetText(ConvertToString(int(round(mCurrentValue))));
|
||||
}
|
||||
else
|
||||
{
|
||||
int num_digits = -int(floor(log10(smallest)));
|
||||
stringstream ss;
|
||||
ss.precision(num_digits);
|
||||
ss << fixed << mCurrentValue;
|
||||
mStaticText->SetText(ss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
74
lib/All/JoltPhysics/TestFramework/UI/UISlider.h
Normal file
74
lib/All/JoltPhysics/TestFramework/UI/UISlider.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UITexturedQuad.h>
|
||||
#include <UI/UIButton.h>
|
||||
|
||||
/// Slider control with up/down button and thumb to select a value
|
||||
class UISlider : public UIElement
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UISlider)
|
||||
|
||||
using ValueChangedAction = function<void(float)>;
|
||||
|
||||
/// Properties
|
||||
void SetValue(float inValue) { mCurrentValue = inValue; }
|
||||
void SetRange(float inMin, float inMax, float inStep) { mMinValue = inMin; mMaxValue = inMax; mStepValue = inStep; }
|
||||
void SetDecreaseButton(UIButton *inDecreaseButton) { mDecreaseButton = inDecreaseButton; }
|
||||
void SetIncreaseButton(UIButton *inIncreaseButton) { mIncreaseButton = inIncreaseButton; }
|
||||
void SetStaticText(UIStaticText *inStaticText) { mStaticText = inStaticText; UpdateStaticText(); }
|
||||
void SetSlider(const UITexturedQuad &inSlider) { mSlider = inSlider; }
|
||||
void SetThumb(const UITexturedQuad &inThumb) { mThumb = inThumb; }
|
||||
void SetValueChangedAction(ValueChangedAction inAction) { mValueChangedAction = inAction; }
|
||||
|
||||
/// Cloning / copying
|
||||
virtual void CopyTo(UIElement *ioElement) const override;
|
||||
|
||||
/// Actions
|
||||
virtual bool MouseDown(int inX, int inY) override;
|
||||
virtual bool MouseUp(int inX, int inY) override;
|
||||
virtual bool MouseMove(int inX, int inY) override;
|
||||
virtual void MouseCancel() override;
|
||||
|
||||
/// Draw element
|
||||
virtual void Draw() const override;
|
||||
|
||||
/// Event handling (returns true if the event has been handled)
|
||||
virtual bool HandleUIEvent(EUIEvent inEvent, UIElement *inSender) override;
|
||||
|
||||
/// Calculate auto layout
|
||||
virtual void AutoLayout() override;
|
||||
|
||||
protected:
|
||||
/// Pixel range of slider relative to parent
|
||||
void GetSliderRange(int &outSliderStart, int &outSliderEnd) const;
|
||||
|
||||
/// X coordinate of thumb start
|
||||
int GetThumbStart(int inSliderStart, int inSliderEnd) const;
|
||||
|
||||
/// Internal function to update the value
|
||||
void SetValueInternal(float inValue);
|
||||
|
||||
/// Update static text box
|
||||
void UpdateStaticText();
|
||||
|
||||
/// Properties
|
||||
float mCurrentValue = 0.0f;
|
||||
float mMinValue = 0.0f;
|
||||
float mMaxValue = 1.0f;
|
||||
float mStepValue = 0.1f;
|
||||
UIButton * mDecreaseButton = nullptr;
|
||||
UIButton * mIncreaseButton = nullptr;
|
||||
UIStaticText * mStaticText = nullptr;
|
||||
int mSpaceBetweenButtonAndSlider = 5;
|
||||
UITexturedQuad mSlider;
|
||||
UITexturedQuad mThumb;
|
||||
ValueChangedAction mValueChangedAction;
|
||||
|
||||
/// State
|
||||
int mThumbDragPoint = -1;
|
||||
};
|
||||
168
lib/All/JoltPhysics/TestFramework/UI/UIStaticText.cpp
Normal file
168
lib/All/JoltPhysics/TestFramework/UI/UIStaticText.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UIStaticText.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Renderer/Font.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UIStaticText)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UIStaticText, UIElement)
|
||||
}
|
||||
|
||||
void UIStaticText::CopyTo(UIElement *ioElement) const
|
||||
{
|
||||
UIElement::CopyTo(ioElement);
|
||||
|
||||
UIStaticText *element = StaticCast<UIStaticText>(ioElement);
|
||||
element->mFont = mFont;
|
||||
element->mText = mText;
|
||||
element->mTextColor = mTextColor;
|
||||
element->mDisabledTextColor = mDisabledTextColor;
|
||||
element->mTextPadLeft = mTextPadLeft;
|
||||
element->mTextPadRight = mTextPadRight;
|
||||
element->mTextPadTop = mTextPadTop;
|
||||
element->mTextPadBottom = mTextPadBottom;
|
||||
element->mTextAlignment = mTextAlignment;
|
||||
element->mWrap = mWrap;
|
||||
}
|
||||
|
||||
void UIStaticText::Draw() const
|
||||
{
|
||||
DrawCustom(IsDisabled()? mDisabledTextColor : mTextColor);
|
||||
|
||||
UIElement::Draw();
|
||||
}
|
||||
|
||||
void UIStaticText::AutoLayout()
|
||||
{
|
||||
UIElement::AutoLayout();
|
||||
|
||||
// Update size
|
||||
if (mFont != nullptr)
|
||||
{
|
||||
Float2 size = mFont->MeasureText(GetWrappedText());
|
||||
int w = int(size.x * mFont->GetCharHeight()) + mTextPadLeft + mTextPadRight;
|
||||
int h = int(size.y * mFont->GetCharHeight()) + mTextPadTop + mTextPadBottom;
|
||||
if (GetWidth() <= 0)
|
||||
mWidth.Set(w, PIXELS);
|
||||
if (GetHeight() <= 0)
|
||||
mHeight.Set(h, PIXELS);
|
||||
}
|
||||
}
|
||||
|
||||
String UIStaticText::GetWrappedText() const
|
||||
{
|
||||
String text;
|
||||
|
||||
if (mWrap)
|
||||
{
|
||||
int width = GetWidth() - mTextPadLeft - mTextPadRight;
|
||||
|
||||
size_t start_pos = 0, prev_end_pos = size_t(-1);
|
||||
for (;;)
|
||||
{
|
||||
// Find next space or end of text
|
||||
size_t end_pos = mText.find(' ', prev_end_pos + 1);
|
||||
if (end_pos == String::npos)
|
||||
end_pos = mText.length();
|
||||
|
||||
// Get line to test for width
|
||||
String sub = mText.substr(start_pos, end_pos - start_pos);
|
||||
|
||||
// Measure width
|
||||
Float2 size = mFont->MeasureText(sub);
|
||||
int w = int(size.x * mFont->GetCharHeight());
|
||||
|
||||
// Check if still fits
|
||||
if (width < w)
|
||||
{
|
||||
// If nothing was found yet, add the last word anyhow so that we don't get into an infinite loop
|
||||
if (start_pos >= prev_end_pos
|
||||
|| prev_end_pos == size_t(-1))
|
||||
prev_end_pos = end_pos;
|
||||
|
||||
// Add current line
|
||||
text += mText.substr(start_pos, prev_end_pos - start_pos);
|
||||
text += "\n";
|
||||
|
||||
// Start here for new line
|
||||
start_pos = prev_end_pos + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store last fitting line
|
||||
prev_end_pos = end_pos;
|
||||
}
|
||||
|
||||
// Check end
|
||||
if (end_pos >= mText.length())
|
||||
break;
|
||||
}
|
||||
|
||||
// Add last line
|
||||
if (start_pos < mText.length())
|
||||
text += mText.substr(start_pos, mText.length() - start_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't autowrap
|
||||
text = mText;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void UIStaticText::DrawCustom(ColorArg inColor) const
|
||||
{
|
||||
if (mFont != nullptr && !mText.empty())
|
||||
{
|
||||
String text = GetWrappedText();
|
||||
|
||||
int y = GetY() + mTextPadTop;
|
||||
|
||||
if (mTextAlignment == LEFT)
|
||||
{
|
||||
GetManager()->DrawText(GetX() + mTextPadLeft, y, text, mFont, inColor);
|
||||
}
|
||||
else if (mTextAlignment == CENTER)
|
||||
{
|
||||
// Split lines
|
||||
Array<String> lines;
|
||||
StringToVector(text, lines, "\n");
|
||||
|
||||
// Amount of space we have horizontally
|
||||
int width = GetWidth() - mTextPadLeft - mTextPadRight;
|
||||
|
||||
// Center each line individually
|
||||
for (const String &l : lines)
|
||||
{
|
||||
Float2 size = mFont->MeasureText(l);
|
||||
int w = int(size.x * mFont->GetCharHeight());
|
||||
GetManager()->DrawText(GetX() + (width - w) / 2 + mTextPadLeft, y, l, mFont, inColor);
|
||||
y += mFont->GetCharHeight();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JPH_ASSERT(mTextAlignment == RIGHT);
|
||||
|
||||
// Split lines
|
||||
Array<String> lines;
|
||||
StringToVector(text, lines, "\n");
|
||||
|
||||
// Center each line individually
|
||||
for (const String &l : lines)
|
||||
{
|
||||
Float2 size = mFont->MeasureText(l);
|
||||
int w = int(size.x * mFont->GetCharHeight());
|
||||
GetManager()->DrawText(GetX() + GetWidth() - mTextPadRight - w, y, l, mFont, inColor);
|
||||
y += mFont->GetCharHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
lib/All/JoltPhysics/TestFramework/UI/UIStaticText.h
Normal file
50
lib/All/JoltPhysics/TestFramework/UI/UIStaticText.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIElement.h>
|
||||
#include <Renderer/Font.h>
|
||||
|
||||
/// Static text string
|
||||
class UIStaticText : public UIElement
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UIStaticText)
|
||||
|
||||
/// Cloning / copying
|
||||
virtual void CopyTo(UIElement *ioElement) const override;
|
||||
|
||||
/// Set properties
|
||||
void SetTextColor(ColorArg inColor) { mTextColor = inColor; }
|
||||
void SetDisabledTextColor(ColorArg inColor) { mDisabledTextColor = inColor; }
|
||||
void SetFont(const Font *inFont) { mFont = inFont; }
|
||||
void SetText(const string_view &inText) { mText = inText; }
|
||||
void SetTextPadding(int inTop, int inLeft, int inBottom, int inRight) { mTextPadTop = inTop; mTextPadLeft = inLeft; mTextPadBottom = inBottom; mTextPadRight = inRight; }
|
||||
void SetTextAlignment(EAlignment inAlignment) { JPH_ASSERT(inAlignment == LEFT || inAlignment == RIGHT || inAlignment == CENTER); mTextAlignment = inAlignment; }
|
||||
void SetWrap(bool inWrap) { mWrap = inWrap; }
|
||||
|
||||
/// Draw element
|
||||
virtual void Draw() const override;
|
||||
|
||||
/// Calculate auto layout
|
||||
virtual void AutoLayout() override;
|
||||
|
||||
protected:
|
||||
/// Draw element custom
|
||||
void DrawCustom(ColorArg inColor) const;
|
||||
|
||||
String GetWrappedText() const;
|
||||
|
||||
RefConst<Font> mFont;
|
||||
String mText;
|
||||
Color mTextColor { Color(220, 220, 200) };
|
||||
Color mDisabledTextColor { Color::sGrey };
|
||||
int mTextPadLeft = 0;
|
||||
int mTextPadRight = 0;
|
||||
int mTextPadTop = 0;
|
||||
int mTextPadBottom = 0;
|
||||
EAlignment mTextAlignment = LEFT;
|
||||
bool mWrap = false;
|
||||
};
|
||||
114
lib/All/JoltPhysics/TestFramework/UI/UITextButton.cpp
Normal file
114
lib/All/JoltPhysics/TestFramework/UI/UITextButton.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UITextButton.h>
|
||||
#include <UI/UIManager.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UITextButton)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UITextButton, UIStaticText)
|
||||
}
|
||||
|
||||
void UITextButton::CopyTo(UIElement *ioElement) const
|
||||
{
|
||||
UIStaticText::CopyTo(ioElement);
|
||||
|
||||
UITextButton *element = StaticCast<UITextButton>(ioElement);
|
||||
element->mDownTextColor = mDownTextColor;
|
||||
element->mHighlightTextColor = mHighlightTextColor;
|
||||
element->mSelectedTextColor = mSelectedTextColor;
|
||||
element->mRepeatStartTime = mRepeatStartTime;
|
||||
element->mRepeatTime = mRepeatTime;
|
||||
element->mClickAction = mClickAction;
|
||||
}
|
||||
|
||||
bool UITextButton::MouseDown(int inX, int inY)
|
||||
{
|
||||
if (UIStaticText::MouseDown(inX, inY))
|
||||
return true;
|
||||
|
||||
if (Contains(inX, inY))
|
||||
{
|
||||
mPressed = true;
|
||||
mIsRepeating = false;
|
||||
mRepeatTimeLeft = mRepeatStartTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UITextButton::MouseUp(int inX, int inY)
|
||||
{
|
||||
if (UIStaticText::MouseUp(inX, inY))
|
||||
return true;
|
||||
|
||||
if (mPressed)
|
||||
{
|
||||
mPressed = false;
|
||||
|
||||
if (!mIsRepeating && Contains(inX, inY))
|
||||
{
|
||||
HandleUIEvent(EVENT_BUTTON_DOWN, this);
|
||||
|
||||
if (mClickAction)
|
||||
mClickAction();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UITextButton::MouseMove(int inX, int inY)
|
||||
{
|
||||
if (UIStaticText::MouseMove(inX, inY))
|
||||
return true;
|
||||
|
||||
return mPressed;
|
||||
}
|
||||
|
||||
void UITextButton::MouseCancel()
|
||||
{
|
||||
UIStaticText::MouseCancel();
|
||||
|
||||
mPressed = false;
|
||||
}
|
||||
|
||||
void UITextButton::Update(float inDeltaTime)
|
||||
{
|
||||
UIStaticText::Update(inDeltaTime);
|
||||
|
||||
if (mPressed && mRepeatStartTime > 0)
|
||||
{
|
||||
// Check repeat
|
||||
mRepeatTimeLeft -= inDeltaTime;
|
||||
if (mRepeatTimeLeft <= 0.0f)
|
||||
{
|
||||
// We're repeating
|
||||
mIsRepeating = true;
|
||||
mRepeatTimeLeft = mRepeatTime;
|
||||
|
||||
HandleUIEvent(EVENT_BUTTON_DOWN, this);
|
||||
|
||||
if (mClickAction)
|
||||
mClickAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UITextButton::DrawCustom() const
|
||||
{
|
||||
UIStaticText::DrawCustom(IsDisabled()? mDisabledTextColor : (mPressed? mDownTextColor : (mIsHighlighted? mHighlightTextColor : (mIsSelected? mSelectedTextColor : mTextColor))));
|
||||
}
|
||||
|
||||
void UITextButton::Draw() const
|
||||
{
|
||||
DrawCustom();
|
||||
|
||||
// Skip direct base class, we modify the text color
|
||||
UIElement::Draw();
|
||||
}
|
||||
55
lib/All/JoltPhysics/TestFramework/UI/UITextButton.h
Normal file
55
lib/All/JoltPhysics/TestFramework/UI/UITextButton.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIStaticText.h>
|
||||
|
||||
/// Clickable text button
|
||||
class UITextButton : public UIStaticText
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UITextButton)
|
||||
|
||||
using ClickAction = function<void()>;
|
||||
|
||||
/// Properties
|
||||
void SetDownColor(ColorArg inColor) { mDownTextColor = inColor; }
|
||||
void SetHighlightColor(ColorArg inColor) { mHighlightTextColor = inColor; }
|
||||
void SetSelectedColor(ColorArg inColor) { mSelectedTextColor = inColor; }
|
||||
void SetRepeat(float inRepeatStartTime, float inRepeatTime) { mRepeatStartTime = inRepeatStartTime; mRepeatTime = inRepeatTime; }
|
||||
void SetClickAction(ClickAction inAction) { mClickAction = inAction; }
|
||||
|
||||
/// Cloning / copying
|
||||
virtual void CopyTo(UIElement *ioElement) const override;
|
||||
|
||||
/// Actions
|
||||
virtual bool MouseDown(int inX, int inY) override;
|
||||
virtual bool MouseUp(int inX, int inY) override;
|
||||
virtual bool MouseMove(int inX, int inY) override;
|
||||
virtual void MouseCancel() override;
|
||||
|
||||
/// Update element
|
||||
virtual void Update(float inDeltaTime) override;
|
||||
|
||||
/// Draw element
|
||||
virtual void Draw() const override;
|
||||
|
||||
protected:
|
||||
/// Draw element custom
|
||||
void DrawCustom() const;
|
||||
|
||||
/// Properties
|
||||
Color mDownTextColor { Color::sGrey };
|
||||
Color mHighlightTextColor { Color::sWhite };
|
||||
Color mSelectedTextColor { Color::sWhite };
|
||||
float mRepeatStartTime = -1.0f;
|
||||
float mRepeatTime = 0.5f;
|
||||
ClickAction mClickAction;
|
||||
|
||||
/// State
|
||||
bool mPressed = false;
|
||||
bool mIsRepeating = false;
|
||||
float mRepeatTimeLeft = 0;
|
||||
};
|
||||
36
lib/All/JoltPhysics/TestFramework/UI/UITexturedQuad.h
Normal file
36
lib/All/JoltPhysics/TestFramework/UI/UITexturedQuad.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Renderer/Texture.h>
|
||||
|
||||
/// Helper class that points to a subsection of a texture for rendering it as a quad. Can specify borders which won't scale (only inner part of the quad will scale).
|
||||
class UITexturedQuad
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
UITexturedQuad() = default;
|
||||
UITexturedQuad(const Texture *inTexture) : mTexture(inTexture), mWidth(inTexture->GetWidth()), mHeight(inTexture->GetHeight()) { }
|
||||
UITexturedQuad(const Texture *inTexture, int inX, int inY, int inWidth, int inHeight) : mTexture(inTexture), mX(inX), mY(inY), mWidth(inWidth), mHeight(inHeight) { }
|
||||
UITexturedQuad(const Texture *inTexture, int inX, int inY, int inWidth, int inHeight, int inInnerX, int inInnerY, int inInnerWidth, int inInnerHeight) : mTexture(inTexture), mX(inX), mY(inY), mWidth(inWidth), mHeight(inHeight), mInnerX(inInnerX), mInnerY(inInnerY), mInnerWidth(inInnerWidth), mInnerHeight(inInnerHeight) { }
|
||||
|
||||
/// Check if this quad consists of 9 parts
|
||||
bool HasInnerPart() const { return mInnerX >= 0 && mInnerY >= 0 && mInnerWidth >= 0 && mInnerHeight >= 0; }
|
||||
|
||||
/// The texture to use
|
||||
RefConst<Texture> mTexture;
|
||||
|
||||
/// These are the normal texel coordinates for the quad
|
||||
int mX = 0;
|
||||
int mY = 0;
|
||||
int mWidth = 0;
|
||||
int mHeight = 0;
|
||||
|
||||
/// This quad can also scale its inner part leaving borders in tact, in this case the inner scaling part is defined here
|
||||
int mInnerX = -1;
|
||||
int mInnerY = -1;
|
||||
int mInnerWidth = -1;
|
||||
int mInnerHeight = -1;
|
||||
};
|
||||
25
lib/All/JoltPhysics/TestFramework/UI/UIVerticalStack.cpp
Normal file
25
lib/All/JoltPhysics/TestFramework/UI/UIVerticalStack.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <UI/UIVerticalStack.h>
|
||||
|
||||
JPH_IMPLEMENT_RTTI_VIRTUAL(UIVerticalStack)
|
||||
{
|
||||
JPH_ADD_BASE_CLASS(UIVerticalStack, UIElement)
|
||||
}
|
||||
|
||||
void UIVerticalStack::AutoLayout()
|
||||
{
|
||||
UIElement::AutoLayout();
|
||||
|
||||
mHeight.Set(0, PIXELS);
|
||||
for (UIElement *e : mChildren)
|
||||
if (e->IsVisible() || mPlaceInvisibleChildren)
|
||||
{
|
||||
e->SetRelativeY(GetHeight());
|
||||
mHeight.Set(GetHeight() + e->GetHeight() + e->GetPaddingBottom() + mDeltaY, PIXELS);
|
||||
}
|
||||
}
|
||||
21
lib/All/JoltPhysics/TestFramework/UI/UIVerticalStack.h
Normal file
21
lib/All/JoltPhysics/TestFramework/UI/UIVerticalStack.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <UI/UIElement.h>
|
||||
|
||||
/// Layout class that will automatically layout child elements vertically, stacking them
|
||||
class UIVerticalStack : public UIElement
|
||||
{
|
||||
public:
|
||||
JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, UIVerticalStack)
|
||||
|
||||
/// Calculate auto layout
|
||||
virtual void AutoLayout() override;
|
||||
|
||||
private:
|
||||
int mDeltaY = 0;
|
||||
bool mPlaceInvisibleChildren = false;
|
||||
};
|
||||
Reference in New Issue
Block a user