Adding Anchors and Decorator Widget types.

This commit is contained in:
2025-06-27 19:55:02 -05:00
parent 558f17fc94
commit 238a7934b3
9 changed files with 194 additions and 15 deletions

View File

@@ -129,6 +129,8 @@ namespace JUI {
[[nodiscard]] virtual Vector2 GetAbsolutePosition() const; [[nodiscard]] virtual Vector2 GetAbsolutePosition() const;
[[nodiscard]] virtual float GetAbsoluteRotation() const; [[nodiscard]] virtual float GetAbsoluteRotation() const;
[[nodiscard]] virtual Vector2 GetAbsoluteCentroid() const;
/// Returns the parent of this widget, or a nullptr if there is no parent. /// Returns the parent of this widget, or a nullptr if there is no parent.
/// @see GetFamilyTreeRoot(). /// @see GetFamilyTreeRoot().
Widget* GetParent() const; Widget* GetParent() const;

View File

@@ -0,0 +1,62 @@
/// Josh's User Interface Library
/// A C++20 Library for creating, styling, and rendering of a UI/UX widgets.
/// Developed and Maintained by Josh O'Leary @ Redacted Software.
/// Special Thanks to William Tomasine II and Maxine Hayes.
/// (c) 2024 Redacted Software
/// This work is dedicated to the public domain.
/// @file Resizable.hpp
/// @desc Resizable Mixin Helper class
/// @edit 2024-10-11
#pragma once
#include <Event.h>
#include <J3ML/LinearAlgebra/Vector2.hpp>
namespace JUI
{
/// A mixin helper class that enables a widget to be resized by the mouse.
class Focusable {
public:
Event<> OnGrabFocus;
Event<> OnDropFocus;
[[nodiscard]] bool Focused() const;
[[nodiscard]] bool IsFocused() const { return focused;}
[[nodiscard]] bool HasFocus() const { return focused;}
virtual void GrabFocus() { SetFocused(true);}
virtual void DropFocus(const Vector2& point) {
if (do_focus_cooldown_hack && focus_hack_cooldown > time_focused)
return;
SetFocused(false);
}
virtual void SetFocused(bool value) {
focused = value;
if (do_focus_cooldown_hack && value) time_focused = 0;
}
virtual void Update(float delta) {
if (do_focus_cooldown_hack)
time_focused += delta;
}
void DoFocusHackCooldown(bool value) { do_focus_cooldown_hack = value; }
bool DoFocusHackCooldown() const { return do_focus_cooldown_hack; }
float FocusHackCooldown() const { return focus_hack_cooldown; }
void FocusHackCooldown(float value) {
focus_hack_cooldown = value;
}
protected:
bool focused = false;
float time_focused = 0;
bool do_focus_cooldown_hack = false;
float focus_hack_cooldown = 0.1f;
};
}

View File

@@ -17,7 +17,6 @@
namespace JUI namespace JUI
{ {
using namespace J3ML::LinearAlgebra; using namespace J3ML::LinearAlgebra;
/// Funky Coordinate system purpose-built for screen positioning /// Funky Coordinate system purpose-built for screen positioning
@@ -26,6 +25,17 @@ namespace JUI
/// @see UDim.hpp /// @see UDim.hpp
class UDim2 class UDim2
{ {
public: // Constants
static const UDim2 Center;
static const UDim2 TopLeft;
static const UDim2 BottomRight;
static const UDim2 BottomLeft;
static const UDim2 TopRight;
static const UDim2 TopCenter;
static const UDim2 LeftCenter;
static const UDim2 BottomCenter;
static const UDim2 RightCenter;
public: // Properties public: // Properties
UDim X; UDim X;
UDim Y; UDim Y;

View File

@@ -0,0 +1,88 @@
#pragma once
#include <JUI/Base/Widget.hpp>
namespace JUI {
/// An invisible, point-like widget which is used to attach decorator-type widgets at a given point.
/// For example: The CurveSegment Widget uses two Anchors for it's endpoints.
class Anchor : public Widget {
public:
Anchor() : Widget() {
}
explicit Anchor(Widget* parent) : Anchor() {
Parent(parent);
};
explicit Anchor(Widget* parent, const UDim2& position) : Anchor(parent) {
Position(position);
Size({0_px, 0_px});
}
void Update(float elapsed) override {
}
void Draw() override {
Color4 debug_color = Colors::Red;
float debug_size = 4;
J2D::FillCircle(debug_color, GetAbsolutePosition(), debug_size, 5);
}
Vector2 Point() { return GetAbsolutePosition(); }
protected:
private:
};
class Decorator : public Widget {
public:
Decorator() : Widget(){
}
explicit Decorator(Widget* parent) : Decorator() {
Parent(parent);
}
};
class ArrowDecorator : public Decorator {
public:
explicit ArrowDecorator(Widget* parent, Anchor* a, Anchor* b) : Decorator() {
Parent(parent);
origin = a;
goal = b;
}
void Draw() override {
using namespace J3ML;
Color4 line_color = Colors::Green;
float line_size = 4;
J2D::DrawLine(line_color, origin->Point(), goal->Point(), line_size);
Vector2 lookback_dir = goal->Point() - origin->Point();
Rotation angle = lookback_dir.AimedAngle();
angle += 10_degrees;
Vector2 fan_vector_left = (Math::Cos(angle), Math::Sin(angle));
Vector2 tri_polys[3] = {
origin->Point(),
};
J2D::FillTriangle(line_color);
//J2D::FillTriangle();
}
protected:
Anchor* origin;
Anchor* goal;
private:
};
}

View File

@@ -41,7 +41,6 @@ namespace JUI
auto* rect = new JUI::TextRect(file_layout); auto* rect = new JUI::TextRect(file_layout);
rect->Size({100_percent, 20_px}); rect->Size({100_percent, 20_px});
std::string entry_type = entry.is_directory() ? "directory" : "file"; std::string entry_type = entry.is_directory() ? "directory" : "file";
std::string perms = stringify(entry.status().permissions()); std::string perms = stringify(entry.status().permissions());
std::string type = stringify(entry.status().type()); std::string type = stringify(entry.status().type());

View File

@@ -34,6 +34,7 @@
#include <JUI/Widgets/Collapsible.hpp> #include <JUI/Widgets/Collapsible.hpp>
#include <JUI/Widgets/CommandLine.hpp> #include <JUI/Widgets/CommandLine.hpp>
#include "JUI/Widgets/Anchor.hpp"
#include "JUI/Widgets/ColorPicker.hpp" #include "JUI/Widgets/ColorPicker.hpp"
#include "JUI/Widgets/FileDialog.hpp" #include "JUI/Widgets/FileDialog.hpp"
#include "JUI/Widgets/FpsGraph.hpp" #include "JUI/Widgets/FpsGraph.hpp"
@@ -160,7 +161,9 @@ JUI::UtilityBar* CreateUtilityBar(JUI::Widget* root) {
demos->AddButton("Scroll Widget Demo", [&] {}); demos->AddButton("Scroll Widget Demo", [&] {});
demos->AddButton("Command Line", [&]{ console->Toggle();}); demos->AddButton("Command Line", [&] {
console->Toggle();
});
demos->AddButton("File Dialog", [&] {CreateFileDialog();}); demos->AddButton("File Dialog", [&] {CreateFileDialog();});
@@ -176,6 +179,13 @@ JUI::UtilityBar* CreateUtilityBar(JUI::Widget* root) {
berries->AddButton("Blueberries"); berries->AddButton("Blueberries");
} }
} }
auto* ptA = new JUI::Anchor(topbar, {10_px, 20_px});
auto* ptB = new JUI::Anchor(demos, UDim2::Center);
auto* line = new JUI::ArrowDecorator(topbar, ptA, ptB);
} }
auto* edit = topbar->AddButton("Edit"); auto* edit = topbar->AddButton("Edit");
@@ -552,18 +562,6 @@ JUI::Scene* CreateScene() {
auto* widget_list = CreateWidgetList(root); auto* widget_list = CreateWidgetList(root);
//auto* horizontal = new HorizontalListLayout(root);
//horizontal->ZIndex(1);
//auto* separator_a = new Rect(radio_btn_set_layout());
//nineslice_demo_window->Padding(1_px);
// End Window //
root->SetViewportSize({800, 600}); root->SetViewportSize({800, 600});

View File

@@ -147,6 +147,10 @@ float Widget::GetAbsoluteRotation() const {
return rotation; return rotation;
} }
Vector2 Widget::GetAbsoluteCentroid() const {
return GetAbsolutePosition() + (GetAbsoluteSize() / 2.f);
}
std::vector<Widget *> Widget::GetChildren() { return children; } std::vector<Widget *> Widget::GetChildren() { return children; }
std::vector<Widget *> Widget::GetDescendants() { std::vector<Widget *> Widget::GetDescendants() {

View File

@@ -0,0 +1,3 @@
#include <JUI/Mixins/Focusable.hpp>
bool JUI::Focusable::Focused() const { return focused; }

View File

@@ -1,5 +1,18 @@
#include <JUI/UDim2.hpp> #include <JUI/UDim2.hpp>
const JUI::UDim2 JUI::UDim2::Center {50_percent, 50_percent};
const JUI::UDim2 JUI::UDim2::TopLeft {0_percent, 0_percent};
const JUI::UDim2 JUI::UDim2::BottomRight {100_percent, 100_percent};
const JUI::UDim2 JUI::UDim2::BottomLeft {0_percent, 100_percent};
const JUI::UDim2 JUI::UDim2::TopRight {100_percent, 0_percent};
const JUI::UDim2 JUI::UDim2::TopCenter {50_percent, 0_percent};
const JUI::UDim2 JUI::UDim2::LeftCenter {0_percent, 50_percent};
const JUI::UDim2 JUI::UDim2::BottomCenter {50_percent, 100_percent};
const JUI::UDim2 JUI::UDim2::RightCenter {100_percent, 50_percent};
JUI::UDim2::UDim2() { JUI::UDim2::UDim2() {
//X = {0, 0.f}; //X = {0, 0.f};
//Y = {0, 0.f}; //Y = {0, 0.f};