A ton of edits.. I don't even know

This commit is contained in:
2025-06-16 12:02:10 -05:00
parent 1c523dafa2
commit 938be6f7ca
16 changed files with 134 additions and 32 deletions

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.18..3.27) cmake_minimum_required(VERSION 3.18..3.27)
project(JUI project(JUI
VERSION 1.1 VERSION 4.0
LANGUAGES CXX) LANGUAGES CXX)
if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)

View File

@@ -11,6 +11,16 @@
#pragma once #pragma once
/// Ideal refactor:
/// * Completely separate Component for a given behavior / area of concern
/// * XYZStyler class, stored as a pointer in the widget.
/// * Smart pointers
/// * Intelligent layout.
/// *
#include <Event.h> #include <Event.h>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -31,17 +41,37 @@ namespace JUI {
using namespace J3ML::Math; using namespace J3ML::Math;
using namespace J3ML::LinearAlgebra; using namespace J3ML::LinearAlgebra;
struct EventArgs {
};
struct FocusedArgs {};
struct UnfocusedEventArgs {};
struct ChildAddedEventArgs {};
struct ChildRemovedEventArgs {};
/// TODO: Refactor the member functions providing the parent-child hierarchy into the Node mixin.
template <class TNode>
class Node {
public:
protected:
std::vector<TNode*> children;
TNode* parent;
};
/// Widget is the base class for all JUI elements and represents any object that can be in the tree hierarchy. /// Widget is the base class for all JUI elements and represents any object that can be in the tree hierarchy.
/// Some widgets are expressly used for layout, and therefore do not strictly speaking 'Appear' on screen. /// Some widgets are expressly used for layout, and therefore do not strictly-speaking 'Appear' on screen.
/// Widgets exist in a tree hierarchy where each object has one parent, and an arbitrary number of children. No circular references are allowed. /// Widgets exist in a tree hierarchy where each object has one parent, and an arbitrary number of children. No circular references are allowed.
class Widget { class Widget {
public: public:
/// The default constructor for Widget. Generally, JUI widgets will initialize member data, /// The default constructor for Widget. Generally, JUI widgets will initialize member data,
/// and apply a default style in this constructor. Be aware of this, as this is not "idiomatic C++". /// and apply a default style in this constructor. Be aware of this, as this is not "idiomatic C++".
Widget(); Widget();
/// Construct a new widget by specifying it's parent, /// Construct a new widget by specifying its parent,
explicit Widget(Widget* parent); explicit Widget(Widget* parent);
virtual ~Widget() {} virtual ~Widget() = default;
public: public:
#pragma region Events #pragma region Events
/// An event that triggers when the widget is in-focus, generally when the mouse is hovering it. /// An event that triggers when the widget is in-focus, generally when the mouse is hovering it.
@@ -111,6 +141,8 @@ namespace JUI {
/// In a well-formed JUI menu, this **should** always be a Scene. /// In a well-formed JUI menu, this **should** always be a Scene.
Widget* GetFamilyTreeRoot() const; Widget* GetFamilyTreeRoot() const;
#pragma endregion #pragma endregion
#pragma region Layout #pragma region Layout
@@ -391,6 +423,8 @@ namespace JUI {
int layout_order = 0; int layout_order = 0;
Vector2 viewport_size{0,0}; Vector2 viewport_size{0,0};
bool is_mouse_inside = false;
/// Returns the amount of pixels this widget will be padded by from the top-left. /// Returns the amount of pixels this widget will be padded by from the top-left.
/// Generally, the widget will be shrunk and moved over by this amount, relative to the parent. /// Generally, the widget will be shrunk and moved over by this amount, relative to the parent.
Vector2 GetAbsolutePaddingTopLeft() const; Vector2 GetAbsolutePaddingTopLeft() const;
@@ -401,5 +435,8 @@ namespace JUI {
Vector2 GetAbsoluteMarginTopLeft(); Vector2 GetAbsoluteMarginTopLeft();
Vector2 GetAbsoluteMarginBottomRight(); Vector2 GetAbsoluteMarginBottomRight();
void UpdateTweens(float elapsed); void UpdateTweens(float elapsed);
/// Calculate if mouse is inside this element at the start of it's update frame.
bool ComputeIsMouseInside() const;
}; };
} }

View File

@@ -14,10 +14,27 @@
#include <J3ML/LinearAlgebra/Vector2.hpp> #include <J3ML/LinearAlgebra/Vector2.hpp>
#include <JUI/Base/Widget.hpp> #include <JUI/Base/Widget.hpp>
#include "Hoverable.hpp"
namespace JUI { namespace JUI {
struct ClickEventArgs {
public:
protected:
private:
};
struct ReleaseEventArgs {
public:
protected:
private:
};
/// A mixin helper class that provides behavior and events for clickable widgets. /// A mixin helper class that provides behavior and events for clickable widgets.
class Clickable { class Clickable {
public: public:
Event<std::optional<ClickEventArgs>> Clicked;
Event<ReleaseEventArgs> Released;
Event<Vector2, MouseButton> OnClickEvent; Event<Vector2, MouseButton> OnClickEvent;
Event<Vector2, MouseButton, bool> OnReleaseEvent; Event<Vector2, MouseButton, bool> OnReleaseEvent;

View File

@@ -18,6 +18,14 @@
namespace JUI namespace JUI
{ {
/// Interface for anything that can report mouse presence.
class IMouseAware {
public:
virtual ~IMouseAware() = default;
virtual bool IsMouseAware() const = 0;
};
/// A mixin helper class that provides behavior for hoverable objects. /// A mixin helper class that provides behavior for hoverable objects.
/// A hoverable object pays attention to when the mouse enters and leaves it's bounds. /// A hoverable object pays attention to when the mouse enters and leaves it's bounds.
class Hoverable { class Hoverable {
@@ -39,7 +47,10 @@ namespace JUI
virtual void OnExitChildren(const Vector2& mouse); virtual void OnExitChildren(const Vector2& mouse);
virtual void OnExitDescendants(const Vector2& mouse); virtual void OnExitDescendants(const Vector2& mouse);
void Update(const Vector2& m_pos, float delta); void Update(bool mouse_inside, float delta);
/// @note This member function **must** be implemented for classes that implement Hoverable.
//[[nodiscard]] virtual bool IsMouseInside() const = 0;
//virtual void SetTooltip(const std::string& content, float delay) {} //virtual void SetTooltip(const std::string& content, float delay) {}
protected: protected:
//Tooltip* tooltip = nullptr; //Tooltip* tooltip = nullptr;

View File

@@ -164,4 +164,11 @@ namespace JUI {
private: private:
}; };
class ColorPickerDialog : public Window {
public:
protected:
private:
};
} }

View File

@@ -124,6 +124,5 @@ namespace JUI {
protected: protected:
FpsGraph* data_graph; FpsGraph* data_graph;
private: private:
}; };
} }

View File

@@ -17,6 +17,8 @@
namespace JUI { namespace JUI {
struct LinkInvokedEventArgs {};
/// Controls when Link widgets fire their Cicked callback. It can fire right when the widget is clicked, or when it is is released. /// Controls when Link widgets fire their Cicked callback. It can fire right when the widget is clicked, or when it is is released.
enum class LinkClickMode { Press, Release }; enum class LinkClickMode { Press, Release };
@@ -24,8 +26,8 @@ namespace JUI {
class Link : public Text, public Clickable, public Hoverable { class Link : public Text, public Clickable, public Hoverable {
public: public:
enum LinkClickMode ClickMode = LinkClickMode::Release; enum LinkClickMode ClickMode = LinkClickMode::Release;
Event<std::optional<LinkInvokedEventArgs>> Invoked;
/// This event is fired when the user clicks/releases the link. /// This event is fired when the user clicks/releases the link.
Event<> Clicked;
Link() : Text(), Clickable(), Hoverable() {} Link() : Text(), Clickable(), Hoverable() {}
explicit Link(const std::string& content) : Link() { explicit Link(const std::string& content) : Link() {
this->Content(content); this->Content(content);
@@ -54,7 +56,7 @@ namespace JUI {
TextColor(Colors::White); TextColor(Colors::White);
if (!fire_on_release) { if (!fire_on_release) {
Clicked.Invoke(); Clicked.Invoke(std::nullopt);
already_clicked = true; already_clicked = true;
} }
} }
@@ -69,7 +71,7 @@ namespace JUI {
TextColor(Colors::Black); TextColor(Colors::Black);
if (fire_on_release) { if (fire_on_release) {
Clicked.Invoke(); Clicked.Invoke(std::nullopt);
already_clicked = true; already_clicked = true;
} }
} }
@@ -80,9 +82,8 @@ namespace JUI {
Text::Update(delta); Text::Update(delta);
// TODO: Why does hovered not handle this? // TODO: Why does hovered not handle this?
hovered = IsMouseInside();
Hoverable::Update(last_known_mouse_pos, delta); Hoverable::Update(IsMouseInside(), delta);
// TODO: This is duplicated between here and Window.cpp // TODO: This is duplicated between here and Window.cpp
// Will be abstracted away into Clickable shortly. // Will be abstracted away into Clickable shortly.

View File

@@ -0,0 +1,10 @@
#pragma once
#include "Button.hpp"
namespace JUI {
/// The
class ToggleButton : public Button {
};
}

View File

@@ -331,13 +331,21 @@ JUI::Rect* CreateWidgetList(JUI::Widget* root) {
auto* radio_c_btn = new Checkbox(radio_btn_set_layout); auto* radio_c_btn = new Checkbox(radio_btn_set_layout);
radio_c_btn->Size({20_px, 20_px}); radio_c_btn->Size({20_px, 20_px});
auto* linkbox = new Rect(collapsible->ContentBox()); auto* link_container = new Rect(collapsible->ContentBox());
linkbox->Size({100_percent, 30_px}); {
linkbox->Position({0_px, 20_px}); link_container->Size({100_percent, 30_px});
link_container->Position({0_px, 20_px});
auto* link = new JUI::Link(link_container);
link->Content("Clickable Link");
link->Clicked += [](auto event) {
std::cout << "Link Released" << std::endl;
};
}
auto* link = new JUI::Link(linkbox);
link->Content("This Dick");
// What the FUCK? // What the FUCK?
/*auto* radio_c_label = new TextRect(radio_btn_set_layout); /*auto* radio_c_label = new TextRect(radio_btn_set_layout);

View File

@@ -281,6 +281,9 @@ void Widget::UpdateTweens(float elapsed) {
} }
void Widget::Update(float delta) { void Widget::Update(float delta) {
is_mouse_inside = ComputeIsMouseInside();
UpdateChildWidgets(delta); UpdateChildWidgets(delta);
UpdateTweens(delta); UpdateTweens(delta);
} }
@@ -313,7 +316,8 @@ Widget* Widget::GetFamilyTreeRoot() const {
return parent->GetFamilyTreeRoot(); return parent->GetFamilyTreeRoot();
} }
bool Widget::IsMouseInside() const {
bool Widget::ComputeIsMouseInside() const {
float x = last_known_mouse_pos.x; float x = last_known_mouse_pos.x;
float y = last_known_mouse_pos.y; float y = last_known_mouse_pos.y;
auto pos = GetAbsolutePosition(); auto pos = GetAbsolutePosition();
@@ -325,6 +329,20 @@ bool Widget::IsMouseInside() const {
return false; return false;
} }
bool Widget::IsMouseInside() const {
return is_mouse_inside;
/*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;*/
}
bool Widget::IsMouseInsideChildren(bool include_this) const { bool Widget::IsMouseInsideChildren(bool include_this) const {
if (include_this) if (include_this)
if (IsMouseInside()) if (IsMouseInside())

View File

@@ -1,7 +1,7 @@
#include <JUI/Mixins/Clickable.hpp> #include <JUI/Mixins/Clickable.hpp>
void JUI::Clickable::Update(const Vector2 &mpos, const JUI::MouseButton &btn, bool hovering) { void JUI::Clickable::Update(const Vector2 &mpos, const JUI::MouseButton &btn, bool hovering) {
//Hoverable::Update(mpos, delta);
} }
void JUI::Clickable::OnRelease(const Vector2 &MousePos, const JUI::MouseButton &MouseButton, bool MouseStillOver) { void JUI::Clickable::OnRelease(const Vector2 &MousePos, const JUI::MouseButton &MouseButton, bool MouseStillOver) {

View File

@@ -27,8 +27,9 @@ void JUI::Hoverable::OnExitDescendants(const Vector2& mouse) {
// TODO: Implement // TODO: Implement
} }
void JUI::Hoverable::Update(const Vector2 &m_pos, float delta) { void JUI::Hoverable::Update(bool mouse_inside, float delta) {
hovered = mouse_inside;
/*if (tooltip != nullptr) /*if (tooltip != nullptr)
{ {
if (IsHovered()) { if (IsHovered()) {
@@ -41,12 +42,12 @@ void JUI::Hoverable::Update(const Vector2 &m_pos, float delta) {
if (IsHovered() && !hover_debounce) { if (IsHovered() && !hover_debounce) {
OnHover(m_pos); OnHover({0,0});
hover_debounce = true; hover_debounce = true;
} }
if (!IsHovered() && hover_debounce) { if (!IsHovered() && hover_debounce) {
OnExit(m_pos); OnExit({0,0});
hover_debounce = false; hover_debounce = false;
} }
} }

View File

@@ -46,9 +46,8 @@ namespace JUI {
} }
void Button::Update(float delta) { void Button::Update(float delta) {
hovered = IsMouseInside();
Hoverable::Update(last_known_mouse_pos, delta); Hoverable::Update(IsMouseInside(), delta);
// TODO: This is duplicated between here and Window.cpp // TODO: This is duplicated between here and Window.cpp
// Will be abstracted away into Clickable shortly. // Will be abstracted away into Clickable shortly.

View File

@@ -28,12 +28,8 @@ namespace JUI
} }
void Slider::Update(float delta) { void Slider::Update(float delta) {
bool selected = Rect::IsMouseInside();
Hoverable::Update(Rect::IsMouseInside(), delta);
hovered = IsMouseInside();
Hoverable::Update(last_known_mouse_pos, delta);
// TODO: This is duplicated between here and Window.cpp // TODO: This is duplicated between here and Window.cpp
// Will be abstracted away into Clickable shortly. // Will be abstracted away into Clickable shortly.

View File

@@ -215,9 +215,8 @@ namespace JUI {
} }
Widget::Update(delta); Widget::Update(delta);
hovered = IsMouseInside();
Hoverable::Update(last_known_mouse_pos, delta); Hoverable::Update(IsMouseInside(), delta);
// TODO: This is duplicated between here and Window.cpp // TODO: This is duplicated between here and Window.cpp
// Will be abstracted away into Clickable shortly. // Will be abstracted away into Clickable shortly.
@@ -226,7 +225,6 @@ namespace JUI {
OnClick(last_known_mouse_pos, mbtn); OnClick(last_known_mouse_pos, mbtn);
} }
if (prev_mb_state && !mb_state) if (prev_mb_state && !mb_state)
{ {
OnRelease(last_known_mouse_pos, mbtn, IsHovered()); OnRelease(last_known_mouse_pos, mbtn, IsHovered());