This commit is contained in:
2024-07-29 22:25:22 -04:00
parent afa0a0545c
commit 409ccd07e3
10 changed files with 241 additions and 14 deletions

View File

@@ -48,7 +48,7 @@ CPMAddPackage(
CPMAddPackage(
NAME ReWindow
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-5.zip
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-6.zip
)
CPMAddPackage(

View File

@@ -16,43 +16,86 @@ namespace JUI
enum class V { Top, Center, Bottom }; // Vertical
}
/// How should a text widget behave when it's text runs out of room?
enum class TextOverflowMode
{
WRAP, /// Wraps at the nearest 'word', or otherwise appropriate stop in text.
WRAP_ANYWHERE, /// Wraps the text anywhere.
TRUNCATE, /// Cuts the text off and suffixes '...' to indicate the lack of the full intended message.
TRUNCATE_ANYWHERE, /// Cuts the text off and suffixes '...' to indicate the lack of the full intended message.
TRUNCATE_NO_DOTS, /// Cuts the text off at the first appropriate break in text.
TRUNCATE_ANYWHERE_NO_DOTS /// Cuts the text off at any point in the string.
};
/// TextBase class, implements core mechanics of drawing text in JUI, and is used by Text Widget class.
class TextBase {
public:
TextBase();
[[nodiscard]] std::string GetContent() const;
[[nodiscard]] Color4 GetTextColor() const;
[[nodiscard]] Color4 GetOutlineColor() const;
[[nodiscard]] TextAlign::H GetHorizontalTextAlign() const;
[[nodiscard]] TextAlign::V GetVerticalTextAlign() const;
[[nodiscard]] bool GetWordWrap() const;
TextOverflowMode GetOverflowMode() const;
/// Returns the
[[nodiscard]] Vector2 GetTextBounds() const;
[[nodiscard]] Vector2 GetTextPosition() const;
JGL::Font GetFont() const;
u32 GetTextSize() const;
[[nodiscard]] JGL::Font GetFont() const;
[[nodiscard]] u32 GetTextSize() const;
void SetOverflowMode(const TextOverflowMode& mode);
void SetTextSize(u32 size);
void SetFont(const JGL::Font& font);
void SetContent(const std::string& content);
void SetTextColor(const Color4& color);
void SetOutlineColor(const Color4& color);
/// Set the horizontal alignment of this text widget in relation to it's parent,
/// while keeping the text retained inside the parent widget's bounds.
/// @see TextAlign::H
void SetHorizontalTextAlign(const TextAlign::H& align);
/// Set the vertical alignment of this text widget in relation to it's parent,
/// while keeping the text retained inside the parent widget's bounds.
/// @see TextAlign::V
void SetVerticalTextAlign(const TextAlign::V& align);
/// Sets the horizontal and vertical alignment of this text widget.
/// @see TextAlign::H and TextAlign::V.
void SetTextAlign(const TextAlign::H& h_align, const TextAlign::V& v_align);
/// Aligns the text of this widget to the left-hand-side of the parent's bounding box.
/// @see SetHorizontalTextAlign, TextAlign::H
void AlignLeft();
/// Aligns the text of this widget to the right-hand-side of the parent's bounding box.
/// @see SetHorizontalTextAlign, TextAlign::H
void AlignRight();
/// Aligns the text of this widget to the top of the parent's bounding box.
/// @see SetVerticalTextAlign, TextAlign::V
void AlignTop();
/// Aligns the text of this widget to the bottom of the parent's bounding box.
/// @see SetVerticalTextAlign, TextAlign::V
void AlignBottom();
/// Centers the text of this widget in relation to the parent's bounding box.
/// @see SetHorizontalTextAlign, SetVerticalTextAlign, TextAlign enums
void AlignCenterBoth();
/// Alias for AlignCenterBoth().
void Center();
/// Aligns the text of this widget to the horizontal center of the parent's bounding box.
void AlignCenterHorizontally();
/// Aligns the text of this widget to the vertical center of the parent's bounding box.
void AlignCenterVertically();
/// Renders the aligned text string within a bounding-box specified by abs_pos (top-left corner), and abs_size.
/// @see Widget::Draw(), Text::Draw().
void Draw(const Vector2& abs_pos, const Vector2& abs_size);
void SetWordWrap(bool wrap);
@@ -65,8 +108,10 @@ namespace JUI
bool word_wrap = false;
TextAlign::H h_align = TextAlign::H::Left;
TextAlign::V v_align = TextAlign::V::Top;
TextOverflowMode overflow_mode;
JGL::Font set_font;
u32 text_size;
};
}

View File

@@ -44,9 +44,13 @@ namespace JUI
Event<Widget *> ChildRemoved;
Event<Widget *> Destroying;
public:
/// Adds a given widget to this widget's list of children.
/// @return The widget in question.
Widget* Add(Widget* newChild);
bool IsAncestorOf(Widget* w) const;
bool IsDescendantOf(Widget* w) const;
bool IsAncestorOf(Widget* descendant) const;
bool IsDescendantOf(Widget* ancestor) const;
/// Returns the first child widget that has the given symbolic name, Otherwise, a nullpointer is returned
/// TODO: Use std::optional here and anywhere else a nullptr could be returned.
@@ -69,8 +73,12 @@ namespace JUI
/// TODO: Use std::optional here and anywhere else a nullptr could be returned.
Widget* GetParent() const;
/// Returns the menu-coordinates that are used to position this widget in relation to its parent.
/// @see class UDim2, SetSize(),
[[nodiscard]] UDim2 GetPosition() const;
/// Returns the menu-coordinates that are used to size this widget in relation to its parent.
/// @see SetSize(), class UDim2
[[nodiscard]] UDim2 GetSize() const;
void SetPosition(const UDim2 &pos);
@@ -99,35 +107,86 @@ namespace JUI
void SetPadding(const UDim& padding);
/// Returns the margin factor on the left of this widget.
[[nodiscard]] UDim GetMarginLeft() const;
/// Returns the margin factor on the top of this widget.
[[nodiscard]] UDim GetMarginTop() const;
/// Returns the margin factor on the right of this widget.
[[nodiscard]] UDim GetMarginRight() const;
/// Returns the margin factor on the bottom of this widget.
[[nodiscard]] UDim GetMarginBottom() const;
/// Sets the amount (in Pixels + Scale) to apply margin on the left-side of the widget.
/// @see UDim, SetMargin()
void SetMarginLeft(const UDim &ml);
/// Sets the amount (in Pixels + Scale) to apply margin on the top-side of the widget.
/// @see UDim, SetMargin()
void SetMarginTop(const UDim &mt);
/// Sets the amount (in Pixels + Scale) to apply margin on the right-side of the widget.
/// @see UDim, SetMargin()
void SetMarginRight(const UDim &mr);
/// Sets the amount (in Pixels + Scale) to apply margin on the bottom-side of the widget.
/// @see UDim, SetMargin()
void SetMarginBottom(const UDim &mb);
/// Sets the margin factor of each side of the widget.
/// @param left The amount of margin to apply on the left. (Pixels, Scale)
/// @param top The amount of margin to apply on the top.
/// @param right The amount of margin to apply on the right.
/// @param bottom The amount of margin to apply on the bottom.
void SetMargin(const UDim& left, const UDim& top, const UDim& right, const UDim& bottom);
/// Sets the margin factor on all four sides of this widget to the same value.
/// @see SetMargin(const UDim&, const UDim&, const UDim&, const UDim&).
void SetMargin(const UDim& margin);
/// Returns this widgets mnemonic name.
/// Widgets can optionally be assigned a name that can be used to retrieve it from a widget tree node.
/// @see GetName().
[[nodiscard]] std::string GetName() const;
/// Sets this widgets mnemonic name.
/// Widgets can optionally be assigned a name that can be used to retrieve it from a widget tree node.
/// @see GetName().
void SetName(const std::string &new_name);
/// Returns whether the widget is to be rendered.
/// This function does not indicate whether the widget is **actually seeable** on-screen.
/// @see SetVisible().
[[nodiscard]] bool IsVisible() const;
/// Sets whether the widget is to be rendered. Children are also not rendered if disabled.
/// @see IsVisible().
void SetVisible(bool enabled);
/// Returns the first ancestor in this widgets hierarchy that does not have its own parent.
/// In a well-formed JUI menu, this **should** always be a Scene.
Widget* GetFamilyTreeRoot() const;
public:
/// Renders the widget to the current OpenGL Context using JGL.
/// The user should call this on their Scene instances only. JUI will handle the rest.
virtual void Draw();
/// Performs the update logic of the widget.
/// The user should call this on their Scene instances only. JUI will handle the rest.
virtual void Update(float delta);
/// Informs a widget that the mouse has been moved to a new location.
/// This is designed in such a way that the end-user can plug this into their existing code.
/// The user should call this on their Scene instances only. JUI will handle the rest.
/// See ReWindowIntegrationDemo for an example.
virtual void ObserveMouseMovement(const Vector2& latest_known_pos);
/// Informs a widget that a mouse button has pressed or released.
/// This is designed in such a way that the end-user can plug this into their existing code.
/// The user should call this on their Scene instances only. JUI will handle the rest.
/// See ReWindowIntegrationDemo for an example.
virtual void ObserveMouseInput(int btn, bool pressed);
protected:
void DrawChildWidgets();
void UpdateChildWidgets(float delta);
Widget* GetFamilyTreeRoot() const;
protected:
Vector2 last_known_mouse_pos;
UDim2 position;
UDim2 size;
Widget* parent = nullptr;

View File

@@ -7,6 +7,12 @@ namespace JUI
{
class Button : public Widget, public RectBase, public Clickable
{
public:
Color4 GetHoveredBGColor()
{
}
protected:
private:
};
}

View File

@@ -47,6 +47,7 @@ namespace JUI {
void SetBorderStyling(const Color4& color, float width);
protected:
bool mouse_inside_debounce;
float border_width = 1.f;
Color4 bg_color = {128,128,128, 255};
Color4 border_color = {192, 192, 192, 0};

View File

@@ -1,5 +1,5 @@
#pragma once
#include "JUI/Base/Widget.hpp"
#include <JUI/Base/Widget.hpp>
namespace JUI
@@ -12,6 +12,12 @@ namespace JUI
void Draw() override;
void SetViewportSize(int w, int h);
// TODO: Interface for passing input to JUI in a relatively
// independent way
Event<Vector2> MouseMoved;
void Update(float delta) override;
[[nodiscard]] Vector2 GetAbsolutePosition() const override;

View File

@@ -32,6 +32,16 @@ JUI::Scene* CreateScene() {
auto size = UDim2(64, 64, 0, 0);
element->SetSize({0, 0, 0.5f, 0.5f});
element->SetClipsDescendants(true);
element->SetBorderColor({255,255,255});
element->SetBorderWidth(2.f);
element->MouseEnter += [element] (auto coords) {
element->SetBGColor({0,128,0});
};
element->MouseExit += [element] (auto coords) {
element->SetBGColor({0, 64, 0});
};
Text* text = new Text(element);
text->SetContent("YO MAMA");
@@ -55,10 +65,8 @@ public:
// TODO: Delete when we update to the next release of JGL
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // NOTE: This MUST be called for text rendering to work properly!!!
}
void Update()
{
scene->Update(0.f);
@@ -95,6 +103,7 @@ public:
int main()
{
using namespace ReWindow;
//LOGLEVEL(jlog::severity::none)
auto* window = new JUIDevelopmentTestWindow("Test Window", 800, 600);
@@ -118,6 +127,36 @@ int main()
JGL::Update(size);
};
window->OnMouseMoveEvent += [&] (MouseMoveEvent e)
{
scene->ObserveMouseMovement(e.Position);
};
window->OnMouseButtonUpEvent += [&] (MouseButtonUpEvent e) {
/// Invalid operands to binary expression 'MouseButton' and 'const MouseButton'
if (e.Button == MouseButtons::Left)
scene->ObserveMouseInput(1, false);
if (e.Button == MouseButtons::Middle)
scene->ObserveMouseInput(2, false);
if (e.Button == MouseButtons::Right)
scene->ObserveMouseInput(3, false);
};
window->OnMouseButtonDownEvent += [&] (MouseButtonDownEvent e) {
if (e.Button == MouseButtons::Left)
scene->ObserveMouseInput(1, true);
if (e.Button == MouseButtons::Middle)
scene->ObserveMouseInput(2, true);
if (e.Button == MouseButtons::Right)
scene->ObserveMouseInput(3, true);
};
window->OnMouseButtonDownEvent += [&] (MouseButtonDownEvent e) {};
window->OnKeyDownEvent += [&] (KeyDownEvent e) {};
window->OnKeyUpEvent += [&] (KeyUpEvent e) {};
while (window->isAlive()) {
window->pollEvents();
window->refresh();

View File

@@ -101,8 +101,6 @@ namespace JUI {
TextAlign::V TextBase::GetVerticalTextAlign() const {return v_align;}
bool TextBase::GetWordWrap() const {return word_wrap;}
Vector2 TextBase::GetTextBounds() const { return GetFont().MeasureString(content, text_size); }
JGL::Font TextBase::GetFont() const { return set_font;}

View File

@@ -264,5 +264,51 @@ namespace JUI {
return parent->GetFamilyTreeRoot();
}
void Widget::ObserveMouseInput(int btn, bool pressed) {
for (Widget* child : children)
{
child->ObserveMouseInput(btn, pressed);
}
}
void Widget::ObserveMouseMovement(const Vector2 &latest_known_pos) {
last_known_mouse_pos = latest_known_pos;
for (Widget* child : children)
{
child->ObserveMouseMovement(latest_known_pos);
}
}
bool Widget::IsAncestorOf(Widget *descendant) const {
if (descendant == nullptr)
return false;
Widget *instance = descendant;
while (instance->GetParent()) {
instance = instance->GetParent();
if (instance == this)
return true;
}
return false;
}
bool Widget::IsDescendantOf(Widget *ancestor) const {
if (ancestor == nullptr)
return false;
const Widget *instance = this;
while (instance->GetParent()) {
instance = instance->GetParent();
if (instance == ancestor)
return true;
}
return false;
}
Widget *Widget::Add(Widget *newChild) {
newChild->SetParent(this);
return newChild;
}
}

View File

@@ -59,6 +59,22 @@ namespace JUI {
void Rect::Update(float delta) {
if (IsMouseInside() && !mouse_inside_debounce)
{
MouseEnter.Invoke(last_known_mouse_pos);
mouse_inside_debounce = true;
}
if (!IsMouseInside() && mouse_inside_debounce)
{
MouseExit.Invoke(last_known_mouse_pos);
mouse_inside_debounce = false;
}
Widget::Update(delta);
}
@@ -83,6 +99,17 @@ namespace JUI {
SetBorderWidth(width);
}
bool Rect::IsMouseInside() const {
float x = last_known_mouse_pos.x;
float y = last_known_mouse_pos.y;
auto pos = GetAbsolutePosition();
auto size = GetAbsoluteSize();
if (x > pos.x && y > pos.y && x < pos.x + size.x && y < pos.y + size.y)
return true;
return false;
}
}