Compare commits
87 Commits
Prerelease
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
251daa4070 | |||
fc65e9d229 | |||
2aaba5c1f7 | |||
97edc67fad | |||
1053a32317 | |||
9a70839d2e | |||
578d15200c | |||
15a2bfe667 | |||
d204d991c1 | |||
29f5125ccc | |||
c44e5c830c | |||
c78f9a045c | |||
7f2477677a | |||
fe454209f7 | |||
5673ce3b9e | |||
02cd200114 | |||
32d9615001 | |||
5efbe3fea3 | |||
1520db8dcd | |||
663355726b | |||
83ffecb91d | |||
135a1564f2 | |||
d3f29e2072 | |||
5f7a2326bd | |||
8acf32f140 | |||
d89d74052c | |||
2e65380ae6 | |||
5bf6e2cabc | |||
593ba22626 | |||
27cde1f37c | |||
103813e9c1 | |||
0ef7ec2a7f | |||
0cd3fbfc17 | |||
e7e469864f | |||
0f00cfa48d | |||
c9a9c6aeb5 | |||
355e9f975e | |||
5293a845ad | |||
a31ee731d2 | |||
389f266722 | |||
|
e32bce6b50 | ||
93632faaed | |||
e11b8c8c50 | |||
2e0d75391e | |||
bc8ba3ed02 | |||
9867f49ebf | |||
c5766aa358 | |||
3d22d683bc | |||
432a5990ce | |||
2a7b562b8f | |||
936c1902d0 | |||
e8eb018959 | |||
465d7052b7 | |||
ff84118b10 | |||
9b3bf93ea1 | |||
0ffb750f82 | |||
423dc188cd | |||
3a062a2709 | |||
146b8190b0 | |||
1cb0c1299a | |||
3ad9c615b6 | |||
19e066c835 | |||
7f38836a12 | |||
d2acf6f7ba | |||
3e636a5821 | |||
8318c5ed35 | |||
a5f2564139 | |||
0ce539862c | |||
e7a00bbd9b | |||
f84d3c7f16 | |||
9f7fd8e142 | |||
1361655557 | |||
081f948dc9 | |||
50ed453f64 | |||
dcf65516cc | |||
8a9ceb87e2 | |||
07c3433dd7 | |||
9453a57616 | |||
781c9882d4 | |||
63ff2e6ef2 | |||
53a1d7bd9c | |||
ca75a143d3 | |||
07725ded44 | |||
67fa678ca6 | |||
1065933fcb | |||
cfce294bf2 | |||
48aaff669e |
@@ -31,29 +31,34 @@ endif()
|
||||
|
||||
set_target_properties(JUI PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME jlog
|
||||
URL https://git.redacted.cc/josh/jlog/archive/Prerelease-17.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME mcolor
|
||||
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-5.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Event
|
||||
URL https://git.redacted.cc/josh/Event/archive/Release-10.zip
|
||||
URL https://git.redacted.cc/josh/Event/archive/Release-12.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME J3ML
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/Release-3.1.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME jlog
|
||||
URL https://git.redacted.cc/josh/jlog/archive/Prerelease-12.zip
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/3.4.5.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ReWindow
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-13.zip
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-32.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME JGL
|
||||
URL https://git.redacted.cc/josh/JGL/archive/Prerelease-32.zip
|
||||
URL https://git.redacted.cc/josh/JGL/archive/Prerelease-50.zip
|
||||
)
|
||||
|
||||
target_include_directories(JUI PUBLIC ${Event_SOURCE_DIR}/include)
|
||||
@@ -65,7 +70,7 @@ target_include_directories(JUI PUBLIC ${ReWindow_SOURCE_DIR}/include)
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})
|
||||
install(FILES ${JUI_HEADERS} DESTINATION include/${PROJECT_NAME})
|
||||
|
||||
target_link_libraries(JUI PUBLIC Event J3ML jlog ReWindowLibrary JGL)
|
||||
target_link_libraries(JUI PUBLIC Event J3ML jlog ReWindow JGL)
|
||||
|
||||
add_executable(RedactedJUIDemo main.cpp)
|
||||
target_link_libraries(RedactedJUIDemo PUBLIC JUI)
|
||||
|
62
README.md
62
README.md
@@ -2,31 +2,58 @@
|
||||
|
||||

|
||||
|
||||
Fourth Time's The Charm! (tm)
|
||||
Fourth Time's The Charm!™
|
||||
|
||||
JUI is a C++20 Library for building interactive menus in OpenGL / Redacted3D.
|
||||
#### JUI is a C++20 Library for building interactive menus in OpenGL / Redacted3D.
|
||||
|
||||
It is expressly built with our Redacted3D engine in mind, but steps have been taken to support OpenGL generally.
|
||||
|
||||

|
||||
|
||||
## Abstract
|
||||
|
||||
JUI provides a set of objects that we term Widgets. Widgets can be styled and laid out on-screen in relation to each other. Each widget has a single parent, and a list of child elements. Your root widget should be a Scene object.
|
||||
|
||||
Provided widgets include Scene, Rect, Text, TextRect, Button, TextButton, TextInputForms, Slider, Image, ImageRect, RadioButton
|
||||
JUI provides a set of objects that we term Widgets, which can be styled and laid out on-screen in relation to each other. Each widget has a single parent, and a list of child elements. Your root widget should be a Scene object.
|
||||
|
||||
## Features
|
||||
|
||||
### Why use this instead of imgui?
|
||||
|
||||
## Usage
|
||||
* Comprehensive list of common UI widgets:
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* 
|
||||
* Vertical and Horizontal ListLayout, GridLayout
|
||||
* Separator
|
||||
* ScrollRect
|
||||
* Extendable - Widgets can be extended via class derivation, and even combined to create complex behavior.
|
||||
* Low-overhead stateful GUI elements.
|
||||
* Easy integration with your project. Simply provide update, draw, and user-input callbacks to your scene.
|
||||
|
||||
## Examples
|
||||
|
||||

|
||||
|
||||
|
||||
Browse the src/Demos directories for examples of building and interacting with things in JUI.
|
||||
|
||||
Browse the Repository's , linked above, for further explainations and sample code on each widget.
|
||||
|
||||
## Dependencies
|
||||
|
||||
ReJUI shares dependencies with it's rendering layer, .
|
||||
Currently, the package is also integrated with  and .
|
||||
|
||||
|
||||
`Fedora/RHEL: dnf install cmake make gcc-g++ libX11 libX11-devel mesa-libGL-devel vulkan-loader-devel`
|
||||
|
||||
`Ubuntu/Debian: apt-get install cmake make gcc g++ libx11-6 libx11-dev libgl-dev libvulkan-dev libxrandr-dev`
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation is automatically generated from latest commit and is hosted at https://doc.redacted.cc/jui .
|
||||
@@ -35,17 +62,6 @@ Documentation is automatically generated from latest commit and is hosted at htt
|
||||
|
||||
Contributions to JUI are welcome! Feel free to file bug reports or feature requests by creating an Issue. Pull requests are also very welcome!
|
||||
|
||||
## History
|
||||
|
||||
JUI started out as my menu toolkit for the LOVE2D framework many years ago. Between then and now I had re-implemented it twice, once for MonoGame Framework, and again in C++ for SDL2. Legacy versions are listed below.
|
||||
|
||||
JUI v1 - LOVE2D / Lua
|
||||
|
||||
JUI v2 - MonoGame / C#
|
||||
|
||||
JUI v3 - SDL2 / C++
|
||||
|
||||
|
||||
## License
|
||||
|
||||
JUI is expressly released without a license, under no restrictions. We dedicate all of our works to the public domain for the (hopeful) betterment of humanity.
|
||||
|
BIN
assets/9slice.png
Normal file
BIN
assets/9slice.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
@@ -19,19 +19,30 @@ using J3ML::LinearAlgebra::Vector2;
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// The ImageBase class is an object that handles managing and rendering a texture reference.
|
||||
/// This class is used as a mixin on widgets that must render images. i.e. Image class
|
||||
class ImageBase
|
||||
{
|
||||
public:
|
||||
/// The default constructor initializes this ImageBase with a null pointer texture.
|
||||
ImageBase();
|
||||
ImageBase(JGL::Texture* texture);
|
||||
/// This constructor initializes this ImageBase with a JGL::Texture pointer.
|
||||
explicit ImageBase(JGL::Texture* texture);
|
||||
public:
|
||||
[[nodiscard]] JGL::Texture* Content() const { return texture;}
|
||||
[[nodiscard]] Color4 Color() const { return image_color;}
|
||||
[[nodiscard]] Vector2 Scale() const { return scale;}
|
||||
[[nodiscard]] Vector2 Origin() const { return origin;}
|
||||
/// Returns the texture pointer held by this object.
|
||||
[[nodiscard]] JGL::Texture* Content() const;
|
||||
/// Returns the color of this object. The texture is rendered with this color.
|
||||
[[nodiscard]] Color4 Color() const;
|
||||
/// Returns the scale factor of this object. The texture is scaled with this value.
|
||||
[[nodiscard]] Vector2 Scale() const;
|
||||
/// Returns the origin factor of this object. The texture's origin is determined by this value.
|
||||
[[nodiscard]] Vector2 Origin() const;
|
||||
|
||||
void SetContent(JGL::Texture* content);
|
||||
/// Sets the texture of this object.
|
||||
void Content(JGL::Texture* content);
|
||||
/// Sets the color of this object.
|
||||
void Color(const Color4& newColor);
|
||||
/// Sets the scale factor of this object.
|
||||
void Scale(const Vector2& newScale);
|
||||
void Origin(const Vector2& newOrigin);
|
||||
public:
|
||||
|
@@ -9,7 +9,6 @@
|
||||
/// @desc Base class for container objects. Container objects lay out widgets in a certain order.
|
||||
/// @edit 2024-08-02
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
|
@@ -13,8 +13,9 @@
|
||||
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <Event.h>
|
||||
#include <EventConnection.h>
|
||||
|
||||
#include <Color4.hpp>
|
||||
#include "JGL/types/RenderTarget.h"
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
@@ -36,12 +37,16 @@ namespace JUI
|
||||
//Event<Vector2> MousePress;
|
||||
//Event<Vector2, bool> MouseRelease;
|
||||
public:
|
||||
void SetCornerRounding(float radius);
|
||||
void SetCornerRounding(float tlRadius, float trRadius, float blRadius, float brRadius);
|
||||
void SetCornerRoundingTL(float radius);
|
||||
void SetCornerRoundingTR(float radius);
|
||||
void SetCornerRoundingBL(float radius);
|
||||
void SetCornerRoundingBR(float radius);
|
||||
void CornerRounding(float radius);
|
||||
|
||||
float CornerRounding() const;
|
||||
|
||||
// TODO: Implement per-corner rounding in JGL::Outline/FillRect
|
||||
//void CornerRounding(float tlRadius, float trRadius, float blRadius, float brRadius);
|
||||
//void CornerRoundingTL(float radius);
|
||||
//void CornerRoundingTR(float radius);
|
||||
//void CornerRoundingBL(float radius);
|
||||
//void CornerRoundingBR(float radius);
|
||||
|
||||
void SetClipsDescendants(bool clipping);
|
||||
void BGColor(const Color4& col);
|
||||
@@ -52,21 +57,19 @@ namespace JUI
|
||||
Color4 BGColor() const;
|
||||
Color4 GetBorderColor() const;
|
||||
float GetBorderWidth() const;
|
||||
BorderMode GetBorderMode() const;
|
||||
enum BorderMode BorderMode() const;
|
||||
|
||||
void SetBorderMode(const BorderMode& mode)
|
||||
{
|
||||
border_mode = mode;
|
||||
}
|
||||
void BorderMode(const enum BorderMode& mode);
|
||||
|
||||
bool GetClipsDescendants() const;
|
||||
|
||||
void SetBorderStyling(const Color4& color, float width);
|
||||
|
||||
void Draw(const Vector2& pos, const Vector2& size);
|
||||
|
||||
void Draw(const Color4& bgColor, const Color4& fgColor, const Vector2& pos, const Vector2& size);
|
||||
protected:
|
||||
BorderMode border_mode = BorderMode::Middle;
|
||||
|
||||
enum BorderMode border_mode = BorderMode::Middle;
|
||||
bool mouse_press_debounce;
|
||||
bool mouse_inside_debounce;
|
||||
float border_width = 1.f;
|
||||
|
@@ -1,23 +1,27 @@
|
||||
/// 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 TextBase.hpp
|
||||
/// @desc Demo Program Entry Point
|
||||
/// @edit 2024-11-16
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <Color4.hpp>
|
||||
#include <JGL/JGL.h>
|
||||
#include <JGL/types/Font.h>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// Enumerations for alignment of text within a desired "Box".
|
||||
namespace TextAlign {
|
||||
enum class H { Left, Center, Right }; // Horizontal
|
||||
enum class V { Top, Center, Bottom }; // Vertical
|
||||
}
|
||||
|
||||
namespace JUI {
|
||||
class TextBase;
|
||||
|
||||
/// How should a text widget behave when it's text runs out of room?
|
||||
enum class TextOverflowMode
|
||||
{
|
||||
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.
|
||||
@@ -25,93 +29,104 @@ namespace JUI
|
||||
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();
|
||||
/// Enumerations for alignment of text within a desired "Box".
|
||||
namespace JUI::TextAlign {
|
||||
// Horizontal
|
||||
enum class H { Left, Center, Right };
|
||||
// Vertical
|
||||
enum class V { Top, Center, Bottom };
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string GetContent() const;
|
||||
[[nodiscard]] Color4 GetTextColor() const;
|
||||
[[nodiscard]] Color4 GetOutlineColor() const;
|
||||
[[nodiscard]] TextAlign::H GetHorizontalTextAlign() const;
|
||||
[[nodiscard]] TextAlign::V GetVerticalTextAlign() const;
|
||||
/// TextBase class, implements core mechanics of drawing text in JUI, and is used by Text Widget class.
|
||||
class JUI::TextBase {
|
||||
private:
|
||||
bool state_redraw = true;
|
||||
protected:
|
||||
RenderTarget* text_canvas;
|
||||
std::string content = "Sample Text";
|
||||
Color4 text_color = {255,255,255};
|
||||
float text_outline = 1.f;
|
||||
Color4 outline_color = {255,255,255};
|
||||
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 = JGL::Fonts::Jupiteroid;
|
||||
u32 text_size = 12;
|
||||
protected:
|
||||
// I don't know why this function even exists, or why it was public. It lets you circumvent
|
||||
// the whole purpose of storing the state things are in :/ - Redacted.
|
||||
void Draw(const Vector2& abs_pos, const Vector2& abs_size, const std::string& content, uint size, const Color4& color);
|
||||
|
||||
TextOverflowMode GetOverflowMode() const;
|
||||
/// 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);
|
||||
public:
|
||||
[[nodiscard]] std::string GetContent() const;
|
||||
[[nodiscard]] Color4 GetTextColor() const;
|
||||
[[nodiscard]] Color4 GetOutlineColor() const;
|
||||
[[nodiscard]] TextAlign::H GetHorizontalTextAlign() const;
|
||||
[[nodiscard]] TextAlign::V GetVerticalTextAlign() const;
|
||||
TextOverflowMode GetOverflowMode() const;
|
||||
[[nodiscard]] Vector2 GetTextBounds();
|
||||
[[nodiscard]] Vector2 GetTextPosition() const;
|
||||
[[nodiscard]] JGL::Font GetFont() const;
|
||||
[[nodiscard]] u32 GetTextSize() const;
|
||||
public:
|
||||
void Update(float delta);
|
||||
void SetWordWrap(bool wrap);
|
||||
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);
|
||||
|
||||
/// Returns the
|
||||
[[nodiscard]] Vector2 GetTextBounds() const;
|
||||
[[nodiscard]] Vector2 GetTextPosition() const;
|
||||
[[nodiscard]] JGL::Font GetFont() const;
|
||||
[[nodiscard]] u32 GetTextSize() const;
|
||||
/// 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);
|
||||
|
||||
void SetOverflowMode(const TextOverflowMode& mode);
|
||||
/// 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);
|
||||
|
||||
void SetTextSize(u32 size);
|
||||
/// 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);
|
||||
|
||||
void SetFont(const JGL::Font& font);
|
||||
/// Aligns the text of this widget to the left-hand-side of the parent's bounding box.
|
||||
/// @see SetHorizontalTextAlign, TextAlign::H
|
||||
void AlignLeft();
|
||||
|
||||
void SetContent(const std::string& content);
|
||||
/// Aligns the text of this widget to the right-hand-side of the parent's bounding box.
|
||||
/// @see SetHorizontalTextAlign, TextAlign::H
|
||||
void AlignRight();
|
||||
|
||||
void SetTextColor(const Color4& color);
|
||||
/// Aligns the text of this widget to the top of the parent's bounding box.
|
||||
/// @see SetVerticalTextAlign, TextAlign::V
|
||||
void AlignTop();
|
||||
|
||||
void SetOutlineColor(const Color4& color);
|
||||
/// Aligns the text of this widget to the bottom of the parent's bounding box.
|
||||
/// @see SetVerticalTextAlign, TextAlign::V
|
||||
void AlignBottom();
|
||||
|
||||
/// 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);
|
||||
/// Centers the text of this widget in relation to the parent's bounding box.
|
||||
/// @see SetHorizontalTextAlign, SetVerticalTextAlign, TextAlign enums
|
||||
void AlignCenterBoth();
|
||||
|
||||
/// 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);
|
||||
/// Alias for AlignCenterBoth().
|
||||
void Center();
|
||||
|
||||
/// 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();
|
||||
/// Aligns the text of this widget to the horizontal center of the parent's bounding box.
|
||||
void AlignCenterHorizontally();
|
||||
|
||||
void Update(float delta);;
|
||||
|
||||
/// 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);
|
||||
|
||||
protected:
|
||||
std::string content = "Sample Text";
|
||||
Color4 text_color = {255,255,255,255};
|
||||
float text_outline;
|
||||
Color4 outline_color = {255,255,255,255};
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
/// Aligns the text of this widget to the vertical center of the parent's bounding box.
|
||||
void AlignCenterVertically();
|
||||
public:
|
||||
~TextBase() { delete text_canvas; };
|
||||
TextBase() : set_font(JGL::Fonts::Jupiteroid), state_redraw(true), text_canvas(new RenderTarget({1, 1}, {0, 0, 0, 0})) {};
|
||||
};
|
@@ -7,36 +7,32 @@
|
||||
|
||||
/// @file Widget.hpp
|
||||
/// @desc Base Widget Class - All JUI widgets extend their behavior from this class.
|
||||
/// @edit 2024-07-31
|
||||
/// @edit 2024-10-11
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Event.h>
|
||||
#include <EventConnection.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "J3ML/LinearAlgebra.hpp"
|
||||
#include "JUI/UDim2.hpp"
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <JUI/UDim2.hpp>
|
||||
#include <Color3.hpp>
|
||||
#include <Color4.hpp>
|
||||
|
||||
#include <JGL/JGL.h>
|
||||
#include <ReWindow/types/Key.h>
|
||||
#include <JUI/Tween.hpp>
|
||||
#include <JUI/JUI.hpp>
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
enum class MouseButton {
|
||||
Left = 1,
|
||||
Middle = 2,
|
||||
Right = 3
|
||||
};
|
||||
namespace JUI {
|
||||
|
||||
using namespace J3ML::Math;
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
/// Widget class is the base for all JUI elements.
|
||||
/// Widgets exist in a tree hierarchy where each object has one parent, and an arbitrary number of children.
|
||||
/// 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.
|
||||
/// 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
|
||||
{
|
||||
public:
|
||||
@@ -66,16 +62,76 @@ namespace JUI
|
||||
Event<Widget *> Destroying;
|
||||
public:
|
||||
|
||||
void TweenPositionTo(const UDim2& goal)
|
||||
{
|
||||
UDim2 start_position = this->Position();
|
||||
float progress = 0;
|
||||
|
||||
Tween t;
|
||||
|
||||
|
||||
std::function<void(float)> updateTillGoalReached = [this, t, start_position, progress, goal] (float elapsed) mutable
|
||||
{
|
||||
|
||||
UDim2 current_pos = this->Position();
|
||||
|
||||
// TODO: Implement UDim equality operators (with epsilon)
|
||||
// TODO: Implement UDim::Lerp
|
||||
// TODO: Implement UDim2::Lerp
|
||||
if (current_pos.X.Pixels == goal.X.Pixels && current_pos.Y.Pixels == goal.Y.Pixels && current_pos.X.Scale == goal.X.Scale && current_pos.Y.Scale == goal.Y.Scale)
|
||||
{
|
||||
// Reached Goal, Complete this tween.
|
||||
return;
|
||||
}
|
||||
|
||||
progress += elapsed;
|
||||
|
||||
if (progress >= 1.f)
|
||||
{
|
||||
progress = 1.f;
|
||||
t.Completed.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
float modified_progress = EasingFunctions::EaseOutElastic(progress);
|
||||
|
||||
|
||||
UDim2 pos = current_pos;
|
||||
|
||||
pos.X.Pixels = Math::Lerp(start_position.X.Pixels, goal.X.Pixels, modified_progress);
|
||||
pos.Y.Pixels = Math::Lerp(start_position.Y.Pixels, goal.Y.Pixels, modified_progress);
|
||||
pos.X.Scale = Math::Lerp(start_position.X.Scale, goal.X.Scale, modified_progress);
|
||||
pos.Y.Scale = Math::Lerp(start_position.Y.Scale, goal.Y.Scale, modified_progress);
|
||||
|
||||
|
||||
Position(pos);
|
||||
};
|
||||
|
||||
|
||||
t.tick_func = updateTillGoalReached;
|
||||
|
||||
tweens.push_back(t);
|
||||
|
||||
}
|
||||
void TweenPositionFromTo();
|
||||
void TweenSizeTo();
|
||||
void TweenSizeFromTo();
|
||||
|
||||
|
||||
|
||||
/// Adds a given widget to this widget's list of children.
|
||||
/// @return The widget in question.
|
||||
Widget* Add(Widget* newChild);
|
||||
|
||||
/// Returns true if this object is an ancestor to the given widget.
|
||||
bool IsAncestorOf(Widget* descendant) const;
|
||||
|
||||
/// Returns true if this object is a descendant of the given widget.
|
||||
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.
|
||||
Widget* FindFirstChild(const std::string& name);
|
||||
/// Returns the first child widget that has the given symbolic name
|
||||
std::optional<Widget*> FindFirstChild(const std::string& name);
|
||||
|
||||
/// Returns a flat list of all nodes that are lower in the hierarchy list.
|
||||
std::vector<Widget*> GetDescendants();
|
||||
@@ -90,16 +146,16 @@ namespace JUI
|
||||
[[nodiscard]] virtual Vector2 GetAbsolutePosition() const;
|
||||
[[nodiscard]] virtual float GetAbsoluteRotation() const;
|
||||
|
||||
/// Returns the parent of this widget
|
||||
/// TODO: Use std::optional here and anywhere else a nullptr could be returned.
|
||||
/// Returns the parent of this widget, or a nullptr if there is no parent.
|
||||
/// @see GetFamilyTreeRoot().
|
||||
Widget* GetParent() const;
|
||||
|
||||
/// Returns the menu-coordinates that are used to position this widget in relation to its parent.
|
||||
/// @see class UDim2, Position(const UDim2&),
|
||||
[[nodiscard]] UDim2 Position() const;
|
||||
|
||||
/// Retrieves this widgets z-index. This value determines the order in which a widget
|
||||
/// renders to the screen relative to other Widgets.
|
||||
/// Returns the Z-Index of this widget.
|
||||
/// This value determines the order in which a widget renders to the screen relative to other Widgets.
|
||||
/// @note This applies in ascending priority order,
|
||||
/// meaning lower values are rendered first, placing higher values on top of lower values.
|
||||
/// @note The range of valid values is -MAX_INT to MAX_INT.
|
||||
@@ -109,23 +165,23 @@ namespace JUI
|
||||
|
||||
/// Sets this widgets z-index.
|
||||
/// @see ZIndex().
|
||||
void SetZIndex(int zindex);
|
||||
void ZIndex(int);
|
||||
|
||||
/// Returns the menu-coordinates that are used to size this widget in relation to its parent.
|
||||
/// @see SetSize(), class UDim2
|
||||
/// @see Size(), class UDim2
|
||||
[[nodiscard]] UDim2 Size() const;
|
||||
|
||||
/// Sets the widgets pixel and scalar position using a combined data type.
|
||||
/// This position is centered around the object's anchor point.
|
||||
/// @see Position(), SetAnchorPoint(), GetAnchorPoint(), class UDim2.
|
||||
void SetPosition(const UDim2 &pos);
|
||||
/// @see Position(), AnchorPoint(), AnchorPoint(), class UDim2.
|
||||
void Position(const UDim2&);
|
||||
|
||||
/// Sets this widget's pixel and scalar size using a combined data type.
|
||||
/// @see Size(), class UDim2.
|
||||
void SetSize(const UDim2 &s);
|
||||
void Size(const UDim2&);
|
||||
|
||||
/// Sets the parent object of this widget. Positioning and sizing of a widget is relative to it's parent.
|
||||
void SetParent(Widget*);
|
||||
void Parent(Widget*);
|
||||
|
||||
/// Returns true if this widget is a 'descendant' of the specified potential ancestor. Otherwise returns false.
|
||||
bool IsDescendantOf(Widget *ancestor);
|
||||
@@ -134,93 +190,136 @@ namespace JUI
|
||||
bool IsAncestorOf(Widget *descendant);
|
||||
|
||||
/// Determines the origin point of a Widget, relative to it's absolute size.
|
||||
[[nodiscard]] Vector2 GetAnchorPoint() const;
|
||||
/// TODO: Better explain what this allows for.
|
||||
[[nodiscard]] Vector2 AnchorPoint() const;
|
||||
|
||||
void AnchorPoint(const Vector2 &point);
|
||||
|
||||
/// Returns the padding factor on the left of this widget.
|
||||
/// @see SetPaddingLeft(), class UDim.
|
||||
[[nodiscard]] UDim GetPaddingLeft() const;
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingLeft(), class UDim.
|
||||
[[nodiscard]] UDim PaddingLeft() const;
|
||||
/// Returns the padding factor on the top of this widget.
|
||||
/// @see SetPaddingTop(), class UDim.
|
||||
[[nodiscard]] UDim GetPaddingTop() const;
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingTop(), class UDim.
|
||||
[[nodiscard]] UDim PaddingTop() const;
|
||||
/// Returns the padding factor on the right of this widget.
|
||||
/// @see SetPaddingRight(), class UDim.
|
||||
[[nodiscard]] UDim GetPaddingRight() const;
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingRight(), class UDim.
|
||||
[[nodiscard]] UDim PaddingRight() const;
|
||||
/// Returns the padding factor on the bottom of this widget.
|
||||
/// @see SetPaddingBottom(), class UDim.
|
||||
[[nodiscard]] UDim GetPaddingBottom() const;
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingBottom(), class UDim.
|
||||
[[nodiscard]] UDim PaddingBottom() const;
|
||||
|
||||
void SetPaddingLeft(const UDim &pad_left);
|
||||
void SetPaddingTop(const UDim &pad_top);
|
||||
void SetPaddingRight(const UDim &pad_right);
|
||||
void SetPaddingBottom(const UDim &pad_bottom);
|
||||
/// Sets the padding factor on the left of this widget.
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingLeft(), class UDim.
|
||||
void PaddingLeft(const UDim &pad_left);
|
||||
/// Sets the padding factor on the top of this widget.
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingLeft(), class UDim.
|
||||
void PaddingTop(const UDim &pad_top);
|
||||
/// Sets the padding factor on the right of this widget.
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingLeft(), class UDim.
|
||||
void PaddingRight(const UDim &pad_right);
|
||||
/// Sets the padding factor on the bottom of this widget.
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @see PaddingLeft(), class UDim.
|
||||
void PaddingBottom(const UDim &pad_bottom);
|
||||
/// Sets the padding factor on the four respective sides of this widget.
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
/// @param left
|
||||
/// @param top
|
||||
/// @param right
|
||||
/// @param bottom
|
||||
void Padding(const UDim& left, const UDim& top, const UDim& right, const UDim& bottom);
|
||||
|
||||
void SetPadding(const UDim& left, const UDim& top, const UDim& right, const UDim& bottom);
|
||||
|
||||
void SetPadding(const UDim& padding);
|
||||
/// Sets the same padding factor on all four sides of this widget.
|
||||
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
|
||||
void Padding(const UDim& padding);
|
||||
|
||||
/// Returns the margin factor on the left of this widget.
|
||||
[[nodiscard]] UDim GetMarginLeft() const;
|
||||
[[nodiscard]] UDim MarginLeft() const;
|
||||
/// Returns the margin factor on the top of this widget.
|
||||
[[nodiscard]] UDim GetMarginTop() const;
|
||||
[[nodiscard]] UDim MarginTop() const;
|
||||
/// Returns the margin factor on the right of this widget.
|
||||
[[nodiscard]] UDim GetMarginRight() const;
|
||||
|
||||
[[nodiscard]] UDim MarginRight() const;
|
||||
/// Returns the margin factor on the bottom of this widget.
|
||||
[[nodiscard]] UDim GetMarginBottom() const;
|
||||
[[nodiscard]] UDim MarginBottom() 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);
|
||||
/// @see UDim, Margin()
|
||||
void MarginLeft(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);
|
||||
/// @see UDim, Margin()
|
||||
void MarginTop(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);
|
||||
/// @see UDim, Margin()
|
||||
void MarginRight(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);
|
||||
/// @see UDim, Margin()
|
||||
void MarginBottom(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);
|
||||
void Margin(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);
|
||||
/// @see Margin(const UDim&, const UDim&, const UDim&, const UDim&).
|
||||
void Margin(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;
|
||||
/// @see Name().
|
||||
[[nodiscard]] std::string Name() 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);
|
||||
/// @see Name().
|
||||
void Name(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().
|
||||
/// @see Visible().
|
||||
[[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);
|
||||
|
||||
void Visible(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;
|
||||
|
||||
/// Returns whether or not the mouse is inside this widget's approximate bounding-box.
|
||||
bool IsMouseInside() const;
|
||||
|
||||
void SetAnchorPoint(const Vector2 &point);
|
||||
|
||||
|
||||
/// Returns the complete bounding box around this instance that will be rendered onto.
|
||||
/// This differs from AbsolutePosition and AbsoluteSize in that they are computed for positioning elements relative to each other.
|
||||
/// Only this method represents the full bounding box of the widget.
|
||||
[[nodiscard]] virtual AABB2D GetActualRenderBounds() const;
|
||||
|
||||
AABB2D AbsoluteBounds() const;
|
||||
|
||||
void SetViewportSize(const Vector2& vps);
|
||||
|
||||
public:
|
||||
|
||||
// TODO: Consider calling J2D::Begin here.
|
||||
virtual void PreDraw() {}
|
||||
// TODO: Consider calling J2D::End here.
|
||||
virtual void PostDraw() {}
|
||||
|
||||
|
||||
virtual void InnerDraw() {}
|
||||
|
||||
/// 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();
|
||||
@@ -237,20 +336,27 @@ namespace JUI
|
||||
/// The user should call this on their Scene instances only. JUI will handle the rest.
|
||||
/// See ReWindowIntegrationDemo for an example.
|
||||
virtual void ObserveMouseInput(MouseButton btn, bool pressed);
|
||||
|
||||
/// Informs a widget that a key has been 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 ObserveKeyInput(Key key, bool pressed);
|
||||
protected:
|
||||
void DrawChildWidgets();
|
||||
void UpdateChildWidgets(float delta);
|
||||
protected:
|
||||
MouseButton mbtn;
|
||||
bool mb_state;
|
||||
bool prev_mb_state;
|
||||
bool mb_state = false;
|
||||
bool prev_mb_state = false;
|
||||
//int last_known_mouse_button;
|
||||
//bool last_known_mouse_button_state;
|
||||
Vector2 last_known_mouse_pos;
|
||||
UDim2 position;
|
||||
UDim2 size;
|
||||
Vector2 last_known_mouse_pos = {0,0};
|
||||
UDim2 position = {0_px, 0_px};
|
||||
UDim2 size = {50_px, 50_px};
|
||||
Widget* parent = nullptr;
|
||||
std::vector<Widget*> children;
|
||||
std::vector<Tween> tweens;
|
||||
float rotation = 0;
|
||||
std::string name;
|
||||
bool selected = false;
|
||||
@@ -266,97 +372,25 @@ namespace JUI
|
||||
bool visible = true;
|
||||
Widget* next = nullptr;
|
||||
Widget* prev = nullptr;
|
||||
int zindex = 0;
|
||||
|
||||
Vector2 viewport_size{0,0};
|
||||
|
||||
|
||||
/// 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.
|
||||
Vector2 GetAbsolutePaddingTopLeft() const;
|
||||
|
||||
/// Returns the amount of pixels this widget will be padded by from bottom-right.
|
||||
/// Generally, the widget will be shrunk by twice this amount, relative to the parent.
|
||||
Vector2 GetAbsolutePaddingBottomRight() const;
|
||||
|
||||
Vector2 GetAbsoluteMarginTopLeft();
|
||||
|
||||
Vector2 GetAbsoluteMarginBottomRight();
|
||||
|
||||
void UpdateTweens(float elapsed);
|
||||
};
|
||||
|
||||
/// 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.
|
||||
class Hoverable {
|
||||
public:
|
||||
Event<Vector2> OnHoverEvent;
|
||||
Event<Vector2> OnExitEvent;
|
||||
public:
|
||||
bool IsHovered() const { return hovered; };
|
||||
public:
|
||||
virtual void OnHover(const Vector2& MousePos) {
|
||||
OnHoverEvent.Invoke(MousePos);
|
||||
};
|
||||
virtual void OnExit(const Vector2& MousePos) {
|
||||
OnExitEvent.Invoke(MousePos);
|
||||
};
|
||||
|
||||
void Update(const Vector2& m_pos, float delta)
|
||||
{
|
||||
if (IsHovered() && !hover_debounce) {
|
||||
OnHover(m_pos);
|
||||
hover_debounce = true;
|
||||
}
|
||||
|
||||
if (!IsHovered() && hover_debounce) {
|
||||
OnExit(m_pos);
|
||||
hover_debounce = false;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
bool hovered;
|
||||
bool hover_debounce;
|
||||
};
|
||||
|
||||
/// A mixin helper class that provides behavior and events for clickable widgets.
|
||||
class Clickable
|
||||
{
|
||||
public:
|
||||
Event<Vector2, MouseButton> OnClickEvent;
|
||||
Event<Vector2, MouseButton, bool> OnReleaseEvent;
|
||||
public:
|
||||
bool IsClicked() const { return clicked; };
|
||||
void SetClicked(bool manual_click)
|
||||
{
|
||||
clicked = manual_click;
|
||||
}
|
||||
public:
|
||||
virtual void OnClick(const Vector2& MousePos, const MouseButton& MouseButton) {
|
||||
OnClickEvent.Invoke(MousePos, MouseButton);
|
||||
};
|
||||
virtual void OnRelease(const Vector2& MousePos, const MouseButton& MouseButton, bool MouseStillOver) {
|
||||
OnReleaseEvent.Invoke(MousePos, MouseButton, MouseStillOver);
|
||||
};
|
||||
|
||||
|
||||
void Update(const Vector2& mpos, const MouseButton& btn, bool hovering)
|
||||
{
|
||||
|
||||
}
|
||||
protected:
|
||||
bool clicked = false;
|
||||
bool click_debounce = false;
|
||||
};
|
||||
|
||||
/// A mixin helper class that provides behavior and events for a binary-state togglable widget.
|
||||
class Toggleable {
|
||||
public:
|
||||
Event<> OnToggleEvent;
|
||||
Event<> OnToggleOnEvent;
|
||||
Event<> OnToggleOffEvent;
|
||||
public:
|
||||
virtual void OnToggleOn() {
|
||||
OnToggleOnEvent.Invoke();
|
||||
}
|
||||
virtual void OnToggleOff() {
|
||||
OnToggleOffEvent.Invoke();
|
||||
}
|
||||
virtual void Update() {
|
||||
OnToggleEvent.Invoke();
|
||||
toggled = !toggled;
|
||||
|
||||
if (toggled) {
|
||||
OnToggleOn();
|
||||
} else {
|
||||
OnToggleOff();
|
||||
}
|
||||
}
|
||||
protected:
|
||||
bool toggled = false;
|
||||
};
|
||||
}
|
||||
|
@@ -1,8 +1,16 @@
|
||||
//
|
||||
// Created by dawsh on 7/10/24.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#ifndef JUI_HPP
|
||||
#define JUI_HPP
|
||||
#include <jlog/Logger.hpp>
|
||||
|
||||
#endif //JUI_HPP
|
||||
namespace JUI
|
||||
{
|
||||
extern jlog::GenericLogger UILogs;
|
||||
|
||||
/// An enumeration for mouse buttons, used by JUI to decouple from external systems.
|
||||
/// Some boilerplate is required in order to get input mechanisms up and running. See the demo files for reference.
|
||||
enum class MouseButton {
|
||||
Left = 1,
|
||||
Middle = 2,
|
||||
Right = 3
|
||||
};
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/// 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 ScrollingRect.hpp
|
||||
/// @desc Scrolling Rectangle Widget
|
||||
/// @edit 2024-10-11
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// A mixin helper class that provides behavior and events for clickable widgets.
|
||||
class Clickable
|
||||
{
|
||||
public:
|
||||
Event<Vector2, MouseButton> OnClickEvent;
|
||||
Event<Vector2, MouseButton, bool> OnReleaseEvent;
|
||||
public:
|
||||
[[nodiscard]] bool IsClicked() const { return clicked; };
|
||||
void SetClicked(bool manual_click);
|
||||
public:
|
||||
virtual void OnClick(const Vector2& MousePos, const MouseButton& MouseButton);;
|
||||
virtual void OnRelease(const Vector2& MousePos, const MouseButton& MouseButton, bool MouseStillOver);;
|
||||
|
||||
|
||||
void Update(const Vector2& mpos, const MouseButton& btn, bool hovering);
|
||||
protected:
|
||||
bool clicked = false;
|
||||
bool click_debounce = false;
|
||||
};
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
/// 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 ScrollingRect.hpp
|
||||
/// @desc Scrolling Rectangle Widget
|
||||
/// @edit 2024-10-11
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// A mixin helper class that enables a widget to be docked into a DockingStation.
|
||||
class Dockable {};
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/// 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 ScrollingRect.hpp
|
||||
/// @desc Scrolling Rectangle Widget
|
||||
/// @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 dragged around by the mouse.
|
||||
class Draggable {
|
||||
public:
|
||||
Event<> OnDragBegan;
|
||||
Event<> OnDragEnded;
|
||||
bool Dragging() const { return dragging;}
|
||||
virtual void SetDrag(bool b) {
|
||||
this->dragging = b;
|
||||
}
|
||||
virtual void StartDragging(const Vector2& point)
|
||||
{
|
||||
initial_drag_offset = point;
|
||||
}
|
||||
virtual void StopDragging() {}
|
||||
virtual void Update(float delta) {}
|
||||
protected:
|
||||
bool dragging = false;
|
||||
Vector2 initial_drag_offset = {0, 0};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,42 @@
|
||||
/// 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 Hoverable.hpp
|
||||
/// @desc Hoverable Mixin Helper Class - Added to widgets that should have special behavior when hovered by the mouse.
|
||||
/// @edit 2024-10-11
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <Event.h>
|
||||
#include <JUI/Widgets/Tooltip.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// 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.
|
||||
class Hoverable {
|
||||
public:
|
||||
Event<Vector2> OnHoverEvent;
|
||||
Event<Vector2> OnExitEvent;
|
||||
public:
|
||||
bool IsHovered() const { return hovered; };
|
||||
public:
|
||||
virtual void OnHover(const Vector2& MousePos);
|
||||
virtual void OnExit(const Vector2& MousePos);
|
||||
|
||||
void Update(const Vector2& m_pos, float delta);
|
||||
//virtual void SetTooltip(const std::string& content, float delay) {}
|
||||
protected:
|
||||
//Tooltip* tooltip = nullptr;
|
||||
//float tooltip_threshold = 0.f;
|
||||
//float tooltip_limit = 0.125f;
|
||||
bool hovered = false;
|
||||
bool hover_debounce = false;
|
||||
};
|
||||
}
|
34
include/JUI/Mixins/Resizable.hpp
Normal file
34
include/JUI/Mixins/Resizable.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/// 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 Resizable {
|
||||
public:
|
||||
Event<> OnDragBegan;
|
||||
Event<> OnDragEnded;
|
||||
[[nodiscard]] bool Resizing() const;
|
||||
virtual void SetResize(bool b);
|
||||
virtual void StartResizing(const Vector2& point);
|
||||
virtual void StopResizing();
|
||||
virtual void Update(float delta);
|
||||
protected:
|
||||
bool resizing = false;
|
||||
Vector2 initial_resize_offset = {0, 0};
|
||||
};
|
||||
}
|
||||
|
32
include/JUI/Mixins/Toggleable.hpp
Normal file
32
include/JUI/Mixins/Toggleable.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/// 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 Toggleable.hpp
|
||||
/// @desc Toggleable Mixin Helper Class - Added to widgets that should have special behavior when hovered by the mouse.
|
||||
/// @edit 2024-10-11
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Event.h>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// A mixin helper class that provides behavior and events for a binary-state togglable widget.
|
||||
class Toggleable {
|
||||
public:
|
||||
Event<> OnToggleEvent;
|
||||
Event<> OnToggleOnEvent;
|
||||
Event<> OnToggleOffEvent;
|
||||
public:
|
||||
virtual void OnToggleOn();
|
||||
virtual void OnToggleOff();
|
||||
virtual void Update();
|
||||
protected:
|
||||
bool toggled = false;
|
||||
};
|
||||
}
|
||||
|
114
include/JUI/Tween.hpp
Normal file
114
include/JUI/Tween.hpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "Event.h"
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
namespace EasingFunctions
|
||||
{
|
||||
|
||||
float EaseInOutLinear(float t);
|
||||
|
||||
/// Speed is determined by a sine wave for gentle easing motion.
|
||||
float EaseInSine(float t);
|
||||
/// Speed is determined by a sine wave for gentle easing motion.
|
||||
float EaseOutSine(float t);
|
||||
/// Speed is determined by a sine wave for gentle easing motion.
|
||||
float EaseInOutSine(float t);
|
||||
|
||||
/// Similar to Sine but with a slightly sharper curve based on quadratic interpolation.
|
||||
float EaseInQuad(float t);
|
||||
/// Similar to Sine but with a slightly sharper curve based on quadratic interpolation.
|
||||
float EaseOutQuad(float t);
|
||||
/// Similar to Sine but with a slightly sharper curve based on quadratic interpolation.
|
||||
float EaseInOutQuad(float t);
|
||||
|
||||
/// Similar to Quad but with a slightly sharper curve based on cubic interpolation.
|
||||
float EaseInCubic(float t);
|
||||
/// Similar to Quad but with a slightly sharper curve based on cubic interpolation.
|
||||
float EaseOutCubic(float t);
|
||||
/// Similar to Quad but with a slightly sharper curve based on cubic interpolation.
|
||||
float EaseInOutCubic(float t);
|
||||
|
||||
/// Similar to Cubic but with an even sharper curve based on quartic interpolation.
|
||||
float EaseInQuart(float t);
|
||||
/// Similar to Cubic but with an even sharper curve based on quartic interpolation.
|
||||
float EaseOutQuart(float t);
|
||||
/// Similar to Cubic but with an even sharper curve based on quartic interpolation.
|
||||
float EaseInOutQuart(float t);
|
||||
|
||||
/// Similar to Quart but with an even sharper curve based on quintic interpolation.
|
||||
float EaseInQuint(float t);
|
||||
/// Similar to Quart but with an even sharper curve based on quintic interpolation.
|
||||
float EaseOutQuint(float t);
|
||||
/// Similar to Quart but with an even sharper curve based on quintic interpolation.
|
||||
float EaseInOutQuint(float t);
|
||||
|
||||
/// The sharpest curve based on exponential interpolation.
|
||||
float EaseInExpo(float t);
|
||||
/// The sharpest curve based on exponential interpolation.
|
||||
float EaseOutExpo(float t);
|
||||
/// The sharpest curve based on exponential interpolation.
|
||||
float EaseInOutExpo(float t);
|
||||
|
||||
/// Follows a circular arc, such that acceleration is more sudden and deceleration more gradual versus Quint or Exponential.
|
||||
float EaseInCirc(float t);
|
||||
/// Follows a circular arc, such that acceleration is more sudden and deceleration more gradual versus Quint or Exponential.
|
||||
float EaseOutCirc(float t);
|
||||
/// Follows a circular arc, such that acceleration is more sudden and deceleration more gradual versus Quint or Exponential.
|
||||
float EaseInOutCirc(float t);
|
||||
|
||||
/// Slightly overshoots the target, then backs into place.
|
||||
float EaseInBack(float t);
|
||||
/// Slightly overshoots the target, then backs into place.
|
||||
float EaseOutBack(float t);
|
||||
/// Slightly overshoots the target, then backs into place.
|
||||
float EaseInOutBack(float t);
|
||||
|
||||
float EaseInElastic(float t);
|
||||
float EaseOutElastic(float t);
|
||||
float EaseInOutElastic(float t);
|
||||
|
||||
float EaseInBounce(float t);
|
||||
float EaseOutBounce(float t);
|
||||
float EaseInOutBounce(float t);
|
||||
}
|
||||
|
||||
/// A class that represents an animation-in-action.
|
||||
class Tween {
|
||||
public:
|
||||
Event<> Completed;
|
||||
|
||||
void Update(float elapsed)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::function<float(float)> easing_func;
|
||||
std::function<void(float)> tick_func;
|
||||
/// Duration of the tween, in seconds.
|
||||
float time;
|
||||
/// Time of delay until the tween begins, in seconds.
|
||||
float delay_time;
|
||||
/// Number of times the tween repeats. -1 indicates indefinite repetition.
|
||||
int repeat_count;
|
||||
/// Whether or not the tween interpolates in reverse once the initial tween completes.
|
||||
bool reverses;
|
||||
|
||||
|
||||
|
||||
float lifetime = 5;
|
||||
float progress = 0;
|
||||
bool alive = true;
|
||||
bool paused = false;
|
||||
bool completed = false;
|
||||
|
||||
void Pause() { paused = true; }
|
||||
void Resume() { paused = false; }
|
||||
|
||||
bool Paused() const { return paused; }
|
||||
bool HasCompleted() const { return completed; }
|
||||
};
|
||||
}
|
@@ -11,13 +11,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JUI/Base/Widget.hpp"
|
||||
#include "JUI/Base/RectBase.hpp"
|
||||
#include "JUI/Base/TextBase.hpp"
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
#include <JUI/Base/RectBase.hpp>
|
||||
#include <JUI/Base/TextBase.hpp>
|
||||
#include <JUI/Mixins/Clickable.hpp>
|
||||
#include <JUI/Mixins/Hoverable.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
enum class ButtonState
|
||||
{
|
||||
Base,
|
||||
@@ -26,49 +27,98 @@ namespace JUI
|
||||
Disabled
|
||||
};
|
||||
|
||||
|
||||
//class Button : public Widget, public RectBase, public Clickable, public Hoverable
|
||||
class Button : public Widget, public RectBase, public Clickable, public Hoverable
|
||||
/// The Button class is a basic rect widget that accepts mouse inputs, and provides event hooks.
|
||||
/// The button also provides built-in automatic coloring based on it's current state, which are listed above.
|
||||
class Button : public Rect, public Clickable, public Hoverable
|
||||
{
|
||||
|
||||
public:
|
||||
Event<> OnEnabled;
|
||||
Event<> OnDisabled;
|
||||
public:
|
||||
Button();
|
||||
explicit Button(Widget* parent);
|
||||
~Button() override {};
|
||||
public:
|
||||
// TODO: These suffice for now as a proof-of-concept
|
||||
// But I want more sophisticated style-animation support
|
||||
// for the various states of the button
|
||||
Color4 GetHoveredBGColor() const;
|
||||
Color4 GetBaseBGColor() const;
|
||||
Color4 GetPressedBGColor() const;
|
||||
Color4 GetDisabledBGColor() const;
|
||||
|
||||
Color4 GetHoveredBorderColor() const;
|
||||
Color4 GetBaseBorderColor() const;
|
||||
Color4 GetPressedBorderColor() const;
|
||||
Color4 GetDisabledBorderColor() const;
|
||||
/// Returns the background color of this object when the mouse is hovering this button.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 HoveredBGColor() const;
|
||||
/// Returns the background color of this object at rest.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 BaseBGColor() const;
|
||||
/// Returns the background color of this object when it is clicked.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 PressedBGColor() const;
|
||||
/// Returns the background color of this object when it is disabled.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 DisabledBGColor() const;
|
||||
/// Returns the border color of this object when it is hovered.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 HoveredBorderColor() const;
|
||||
/// Returns the border color of this object at rest.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 BaseBorderColor() const;
|
||||
/// Returns the border color of this object when it is clicked.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 PressedBorderColor() const;
|
||||
/// Returns the border color of this object when it is disabled.
|
||||
/// @note Setting BGColor and BorderColor directly on this class is not recommended, as it will be overwritten.
|
||||
[[nodiscard]] Color4 DisabledBorderColor() const;
|
||||
|
||||
bool IsEnabled() const;
|
||||
/// Sets the background color of this object when the mouse is hovering.
|
||||
void HoveredBGColor(const Color4& color);
|
||||
/// Sets the background color of this object at rest.
|
||||
void BaseBGColor(const Color4& color);
|
||||
/// Sets the background color of this object when it is clicked.
|
||||
void PressedBGColor(const Color4& color);
|
||||
/// Sets the background color of this object when it is disabled.
|
||||
void DisabledBGColor(const Color4& color);
|
||||
|
||||
/// Sets the border color of this object when the mouse is hovering.
|
||||
void HoveredBorderColor(const Color4& color);
|
||||
/// Sets the border color of this object at rest.
|
||||
void BaseBorderColor(const Color4& color);
|
||||
/// Sets the border color of this object when it is clicked.
|
||||
void PressedBorderColor(const Color4& color);
|
||||
/// Sets the border color of this object when it is disabled.
|
||||
void DisabledBorderColor(const Color4& color);
|
||||
|
||||
void BGColors(const Color4& base, const Color4& hover, const Color4& pressed, const Color4& disabled = Colors::Gray);
|
||||
|
||||
void BorderColors(const Color4& base, const Color4& hover, const Color4& pressed, const Color4& disabled = Colors::Gray);
|
||||
|
||||
/// Returns whether is button is interactable. If enabled, it will listen to mouse events and react accordingly.
|
||||
bool Enabled() const;
|
||||
/// Returns whether is button is interactable. If enabled, it will listen to mouse events and react accordingly.
|
||||
bool Disabled() const;
|
||||
/// Sets the interactable state of this button.
|
||||
void SetEnabled(bool enabled);
|
||||
void Draw() override;
|
||||
|
||||
/// Disables this button. Mouse events will be ignored and the button will grey-out.
|
||||
void Disable();
|
||||
/// Enables this button. @see Disable, SetEnabled
|
||||
void Enable();
|
||||
|
||||
void Update(float delta) override;
|
||||
|
||||
void GotoHoverColor();
|
||||
|
||||
|
||||
void OnClick(const Vector2& mouse_pos, const MouseButton& btn) override;
|
||||
void OnRelease(const Vector2& mouse_pos, const MouseButton& bnt, bool still_hovering) override;
|
||||
void OnHover(const J3ML::LinearAlgebra::Vector2 &MousePos) override;
|
||||
void OnExit(const J3ML::LinearAlgebra::Vector2 &MousePos) override;
|
||||
//void SetTooltip(const std::string &content, float delay = 0.2f) override;
|
||||
protected:
|
||||
bool disabled = false;
|
||||
Color4 hover_bg = Colors::Blues::SkyBlue;
|
||||
Color4 hover_border = Colors::Blues::DarkSlateBlue;
|
||||
Color4 pressed_bg = Colors::Blues::DarkSlateBlue;
|
||||
Color4 pressed_border = Colors::Blues::SkyBlue;;
|
||||
Color4 disabled_bg = Colors::Gray;
|
||||
Color4 disabled_border = Colors::Gray;
|
||||
Color4 base_bg = Colors::White;
|
||||
Color4 base_border = Colors::Black;
|
||||
|
||||
void UpdateVisualState();
|
||||
};
|
||||
|
||||
class TextButton : public Button, public TextBase {
|
||||
public:
|
||||
TextButton();
|
||||
explicit TextButton(Widget* parent);
|
||||
~TextButton() override {};
|
||||
void Update(float delta) override;
|
||||
void Draw() override;
|
||||
};
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// Created by dawsh on 8/1/24.
|
||||
//
|
||||
|
||||
#ifndef JUI_CANVAS_HPP
|
||||
#define JUI_CANVAS_HPP
|
||||
|
||||
#endif //JUI_CANVAS_HPP
|
@@ -1,8 +1,104 @@
|
||||
//
|
||||
// Created by dawsh on 8/5/24.
|
||||
//
|
||||
/// 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.
|
||||
|
||||
#ifndef JUI_CHECKBOX_HPP
|
||||
#define JUI_CHECKBOX_HPP
|
||||
/// @file Checkbox.hpp
|
||||
/// @desc It's a checkbox.
|
||||
/// @edit 2024-10-28
|
||||
|
||||
#endif //JUI_CHECKBOX_HPP
|
||||
#pragma once
|
||||
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
#include <JUI/Widgets/Rect.hpp>
|
||||
#include "JUI/Mixins/Clickable.hpp"
|
||||
#include "JUI/Mixins/Hoverable.hpp"
|
||||
#include "Button.hpp"
|
||||
#include "JUI/Base/ImageBase.hpp"
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
class Checkbox : public Button {
|
||||
public:
|
||||
Checkbox() : Button() { }
|
||||
|
||||
explicit Checkbox(Widget *parent) : Checkbox()
|
||||
{
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void Update(float delta) override
|
||||
{
|
||||
Button::Update(delta);
|
||||
}
|
||||
|
||||
|
||||
void OnRelease(const J3ML::LinearAlgebra::Vector2 &mouse_pos, const JUI::MouseButton &bnt, bool still_hovering) override
|
||||
{
|
||||
Button::OnRelease(mouse_pos, bnt, still_hovering);
|
||||
checked = !checked;
|
||||
}
|
||||
|
||||
void InnerDraw() override
|
||||
{
|
||||
Rect::InnerDraw();
|
||||
if (checked)
|
||||
{
|
||||
//J2D::Begin();
|
||||
Vector2 check_padding = {2, 2};
|
||||
RectBase::Draw(check_color, check_color, GetAbsolutePosition()+check_padding, GetAbsoluteSize()-(check_padding*2));
|
||||
//J2D::End();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Draw() override
|
||||
{
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
//J2D::Begin();
|
||||
Vector2 abs_pos = GetAbsolutePosition();
|
||||
Vector2 abs_size = GetAbsoluteSize();
|
||||
|
||||
auto root_size = GetFamilyTreeRoot()->GetAbsoluteSize();
|
||||
|
||||
GLint *old_scissor_bounds;
|
||||
bool clip_was_enabled;
|
||||
|
||||
if (clips_descendants) {
|
||||
clip_was_enabled = glIsEnabled(GL_SCISSOR_TEST);
|
||||
if (clip_was_enabled)
|
||||
glGetIntegerv(GL_SCISSOR_BOX, old_scissor_bounds);
|
||||
|
||||
float presumed_screen_height = 600;
|
||||
glScissor(abs_pos.x, presumed_screen_height-abs_size.y-abs_pos.y, abs_size.x, abs_size.y);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
RectBase::Draw(abs_pos, abs_size);
|
||||
|
||||
// Draw Child Elements with scissor clipping still active
|
||||
Widget::Draw();
|
||||
|
||||
// Returns clip to previous state
|
||||
if (clips_descendants)
|
||||
{
|
||||
//glScissor(old_scissor_bounds[0], old_scissor_bounds[1], old_scissor_bounds[2], old_scissor_bounds[3]);
|
||||
|
||||
if (!clip_was_enabled) {}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
}
|
||||
|
||||
//J2D::End();
|
||||
}
|
||||
protected:
|
||||
bool checked;
|
||||
Color4 check_color = Colors::Red;
|
||||
private:
|
||||
};
|
||||
}
|
5
include/JUI/Widgets/Collapsible.hpp
Normal file
5
include/JUI/Widgets/Collapsible.hpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// Created by dawsh on 8/1/24.
|
||||
//
|
||||
|
||||
#ifndef JUI_CONTEXTMENU_HPP
|
||||
#define JUI_CONTEXTMENU_HPP
|
||||
|
||||
#endif //JUI_CONTEXTMENU_HPP
|
19
include/JUI/Widgets/DialogWindow.hpp
Normal file
19
include/JUI/Widgets/DialogWindow.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// DialogWindow is a special case of Window which is intended to be opened over all other widgets, and present a message or option to the user.
|
||||
class DialogWindow
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// Sample cases:
|
||||
/// Single Option Dialog
|
||||
/// Multi Option Dialog
|
||||
/// File Picker Dialog
|
||||
/// Font Chooser Dialog
|
||||
/// Text Entry Dialog
|
||||
}
|
@@ -15,9 +15,41 @@
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
// TODO: TableLayout class?
|
||||
|
||||
/// A GridLayout lays out sibling UI elements in multiple rows within the parent UI element.
|
||||
class GridLayout : public LayoutContainer
|
||||
{
|
||||
public:
|
||||
GridLayout() : LayoutContainer() {
|
||||
|
||||
}
|
||||
explicit GridLayout(Widget* parent) : GridLayout()
|
||||
{
|
||||
this->Parent(parent);
|
||||
}
|
||||
~GridLayout() override {}
|
||||
|
||||
void ApplyLayout() override
|
||||
{
|
||||
int consumed_w;
|
||||
int consumed_h;
|
||||
int cells;
|
||||
|
||||
// TODO: Implement widget.LayoutOrder and sort by that number.
|
||||
for (auto& child_widget : children)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
UDim2 cell_padding;
|
||||
UDim2 cell_size;
|
||||
int max_cells;
|
||||
bool start_from_left;
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
@@ -7,7 +7,7 @@
|
||||
|
||||
/// @file Image.hpp
|
||||
/// @desc A widget that contains and renders an image provided by JGL.
|
||||
/// @edit 2024-08-05
|
||||
/// @edit 2024-10-31
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -16,11 +16,21 @@
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
/// The image class contains and renders an image provided by JGL.
|
||||
/// By default, this class renders it's image to fill the parent widget.
|
||||
/// For a self-contained image rectangle, see ImageRect.hpp
|
||||
class Image : public Widget, public ImageBase
|
||||
{
|
||||
public:
|
||||
/// The default constructor initializes the image with a nullptr texture.
|
||||
Image();
|
||||
|
||||
/// Constructs a new image by explicitly setting the parent Widget.
|
||||
explicit Image(Widget* parent);
|
||||
|
||||
/// Constructs a new image by explicitly setting both the parent Widget and the texture.
|
||||
/// @param parent
|
||||
/// @param tex
|
||||
explicit Image(Widget* parent, JGL::Texture* tex);
|
||||
~Image() override {}
|
||||
|
||||
|
17
include/JUI/Widgets/ImageButton.hpp
Normal file
17
include/JUI/Widgets/ImageButton.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <JUI/Base/ImageBase.hpp>
|
||||
#include <JUI/Widgets/Button.hpp>
|
||||
|
||||
namespace JUI {
|
||||
class ImageButton;
|
||||
}
|
||||
|
||||
class JUI::ImageButton : public ImageBase, public Button {
|
||||
public:
|
||||
void Update(float delta) override;
|
||||
void Draw() override;
|
||||
public:
|
||||
ImageButton() : ImageBase(), Button() {}
|
||||
explicit ImageButton(Widget* parent) : ImageButton() { Parent(parent); }
|
||||
public:
|
||||
~ImageButton() override = default;
|
||||
};
|
25
include/JUI/Widgets/ImageRect.hpp
Normal file
25
include/JUI/Widgets/ImageRect.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/// 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 ImageRect.hpp
|
||||
/// @desc A widget that contains and renders an image provided by JGL, within a rectangular frame.
|
||||
/// @edit 2024-08-05
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <JUI/Widgets/Rect.hpp>
|
||||
#include <JUI/Base/ImageBase.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
class ImageRect: public Rect, public ImageBase
|
||||
{
|
||||
|
||||
};
|
||||
}
|
8
include/JUI/Widgets/ListBox.hpp
Normal file
8
include/JUI/Widgets/ListBox.hpp
Normal file
@@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by dawsh on 11/24/24.
|
||||
//
|
||||
|
||||
#ifndef LISTBOX_HPP
|
||||
#define LISTBOX_HPP
|
||||
|
||||
#endif //LISTBOX_HPP
|
@@ -9,7 +9,6 @@
|
||||
/// @desc Clickable Button widget.
|
||||
/// @edit 2024-08-02
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <JUI/Base/LayoutContainer.hpp>
|
||||
@@ -30,60 +29,31 @@ namespace JUI
|
||||
enum class V { TOP, BOTTOM };
|
||||
}
|
||||
|
||||
/// Lays child elements out in a vertical descending list.
|
||||
/// Child element positions are overriden by this widget.
|
||||
/// Lays child elements out in a vertical list.
|
||||
/// Child element positions are overridden by this widget.
|
||||
class VerticalListLayout : public ListLayout
|
||||
{
|
||||
public:
|
||||
VerticalListLayout();
|
||||
explicit VerticalListLayout(Widget* parent);
|
||||
|
||||
void ApplyLayout() override
|
||||
{
|
||||
int consumed_height = 0;
|
||||
for (auto& child_widget : children)
|
||||
{
|
||||
// TODO: Implement widget.LayoutOrder property
|
||||
// TODO: Sort children by LayoutOrder
|
||||
consumed_height += pad_top.Pixels;
|
||||
child_widget->SetPosition({0, consumed_height, 0, 0});
|
||||
consumed_height += child_widget->GetAbsoluteSize().y;
|
||||
consumed_height += pad_bottom.Pixels;
|
||||
}
|
||||
}
|
||||
void ApplyLayout() override;
|
||||
void LayoutOrder(LayoutOrder::V order);
|
||||
[[nodiscard]] LayoutOrder::V LayoutOrder() const;
|
||||
protected:
|
||||
LayoutOrder::V layout = LayoutOrder::V::TOP;
|
||||
};
|
||||
|
||||
/// Lays child elements out in a horizontal list.
|
||||
/// Child element positions are overridden by this widget.
|
||||
class HorizontalListLayout : public ListLayout
|
||||
{
|
||||
public:
|
||||
HorizontalListLayout();
|
||||
explicit HorizontalListLayout(Widget* parent);
|
||||
void ApplyLayout() override
|
||||
{
|
||||
if (layout == LayoutOrder::H::LEFT)
|
||||
{
|
||||
int consumed_width = 0;
|
||||
for (auto &child_widget : children)
|
||||
{
|
||||
consumed_width += pad_left.Pixels;
|
||||
child_widget->SetPosition({consumed_width, 0, 0, 0});
|
||||
consumed_width += child_widget->GetAbsoluteSize().x;
|
||||
consumed_width += pad_right.Pixels;
|
||||
}
|
||||
}
|
||||
|
||||
if (layout == LayoutOrder::H::RIGHT)
|
||||
{
|
||||
int consumed_width = this->GetAbsoluteSize().x;
|
||||
for (auto &child_widget : children)
|
||||
{
|
||||
consumed_width -= pad_left.Pixels;
|
||||
child_widget->SetPosition({consumed_width, 0, 0, 0});
|
||||
consumed_width -= child_widget->GetAbsoluteSize().x;
|
||||
consumed_width -= pad_right.Pixels;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ApplyLayout() override;
|
||||
void LayoutOrder(LayoutOrder::H order);
|
||||
[[nodiscard]] LayoutOrder::H LayoutOrder() const;
|
||||
protected:
|
||||
LayoutOrder::H layout = LayoutOrder::H::LEFT;
|
||||
};
|
||||
|
83
include/JUI/Widgets/NineSlice.hpp
Normal file
83
include/JUI/Widgets/NineSlice.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/// 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 NineSlice.hpp
|
||||
/// @desc A widget that implements 9-slice scaling on an image.
|
||||
/// @edit 2025-2-2
|
||||
|
||||
/// https://en.wikipedia.org/wiki/9-slice_scaling
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
#include <JUI/Widgets/Rect.hpp>
|
||||
#include <JUI/Base/ImageBase.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
class NineSliceRect : public Rect, public ImageBase {
|
||||
|
||||
public:
|
||||
NineSliceRect();
|
||||
explicit NineSliceRect(Widget* parent);
|
||||
NineSliceRect(Widget* parent, JGL::Texture* texture);
|
||||
|
||||
/// Returns the bounds of the 'Top-Left' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D TopLeftQuad() const;
|
||||
/// Returns the bounds of the 'Top-Right' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D TopRightQuad() const;
|
||||
/// Returns the bounds of the 'Bottom-Left' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D BottomLeftQuad() const;
|
||||
/// Returns the bounds of the 'Bottom-Right' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D BottomRightQuad() const;
|
||||
|
||||
/// Returns the bounds of the 'Top' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D TopQuad() const;
|
||||
/// Returns the bounds of the 'Left' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D LeftQuad() const;
|
||||
/// Returns the bounds of the 'Right' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D RightQuad() const;
|
||||
/// Returns the bounds of the 'Bottom' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D BottomQuad() const;
|
||||
/// Returns the bounds of the 'Center' slice of the 9-slice.
|
||||
[[nodiscard]] AABB2D CenterQuad() const;
|
||||
|
||||
/// Sets the bounds of the quadrant for the 'Top-Left' slice of the 9-slice.
|
||||
void TopLeftQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Top-Right' slice of the 9-slice.
|
||||
void TopRightQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Bottom-Left' slice of the 9-slice.
|
||||
void BottomLeftQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Bottom-Right' slice of the 9-slice.
|
||||
void BottomRightQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Top' slice of the 9-slice.
|
||||
void TopQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Right' slice of the 9-slice.
|
||||
void RightQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Bottom' slice of the 9-slice.
|
||||
void BottomQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Left' slice of the 9-slice.
|
||||
void LeftQuad(const AABB2D& quad);
|
||||
/// Sets the bounds of the quadrant for the 'Center' slice of the 9-slice.
|
||||
void CenterQuad(const AABB2D& quad);
|
||||
|
||||
void Draw() override;
|
||||
protected:
|
||||
AABB2D top_left_quad;
|
||||
AABB2D top_right_quad;
|
||||
AABB2D bottom_left_quad;
|
||||
AABB2D bottom_right_quad;
|
||||
|
||||
AABB2D top_quad;
|
||||
AABB2D bottom_quad;
|
||||
AABB2D right_quad;
|
||||
AABB2D left_quad;
|
||||
|
||||
AABB2D center_quad;
|
||||
};
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// Created by dawsh on 8/1/24.
|
||||
//
|
||||
|
||||
#ifndef JUI_NINESLICEIMAGE_HPP
|
||||
#define JUI_NINESLICEIMAGE_HPP
|
||||
|
||||
#endif //JUI_NINESLICEIMAGE_HPP
|
@@ -1,8 +1,7 @@
|
||||
//
|
||||
// Created by dawsh on 8/1/24.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#ifndef JUI_PROGRESSBAR_HPP
|
||||
#define JUI_PROGRESSBAR_HPP
|
||||
|
||||
#endif //JUI_PROGRESSBAR_HPP
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
}
|
@@ -11,6 +11,7 @@
|
||||
|
||||
|
||||
#include <JUI/Widgets/Button.hpp>
|
||||
#include <JUI/Mixins/Toggleable.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
#include <JUI/Base/RectBase.hpp>
|
||||
#include <J3ML/Geometry/AABB2D.hpp>
|
||||
|
||||
namespace JUI {
|
||||
|
||||
@@ -27,10 +28,18 @@ namespace JUI {
|
||||
|
||||
~Rect() override {}
|
||||
|
||||
bool IsMouseInside() const;
|
||||
|
||||
AABB2D GetActualRenderBounds() const override;
|
||||
|
||||
|
||||
public:
|
||||
void PreDraw() override;
|
||||
void InnerDraw() override;
|
||||
void PostDraw() override;
|
||||
void Draw() override;
|
||||
void Update(float delta) override;
|
||||
|
||||
protected:
|
||||
GLint old_scissor_bounds[4];
|
||||
bool clip_was_enabled;
|
||||
};
|
||||
}
|
@@ -1,15 +1,25 @@
|
||||
/// 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 Scene.hpp
|
||||
/// @desc Scene class - The root class of a menu that contains child elements.
|
||||
/// @edit 2024-10-11
|
||||
|
||||
#pragma once
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
// TODO: SceneSizingBehavior - FillToWindow, CustomSized
|
||||
///
|
||||
class Scene : public Widget {
|
||||
public:
|
||||
Scene();
|
||||
~Scene() override {}
|
||||
void Draw() override;
|
||||
void SetViewportSize(int w, int h);
|
||||
|
||||
Event<Vector2> MouseMoved;
|
||||
|
||||
@@ -20,7 +30,5 @@ namespace JUI
|
||||
[[nodiscard]] Vector2 GetAbsoluteSize() const override;
|
||||
|
||||
protected:
|
||||
int viewport_w;
|
||||
int viewport_h;
|
||||
};
|
||||
}
|
||||
|
@@ -1,8 +1,72 @@
|
||||
//
|
||||
// Created by dawsh on 8/1/24.
|
||||
//
|
||||
/// 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.
|
||||
|
||||
#ifndef JUI_SCROLLINGRECT_HPP
|
||||
#define JUI_SCROLLINGRECT_HPP
|
||||
/// @file ScrollingRect.hpp
|
||||
/// @desc Scrolling Rectangle Widget
|
||||
/// @edit 2024-10-11
|
||||
|
||||
#endif //JUI_SCROLLINGRECT_HPP
|
||||
#pragma once
|
||||
#include <JUI/Widgets/Rect.hpp>
|
||||
namespace JUI {
|
||||
class ScrollingRect;
|
||||
}
|
||||
|
||||
/// A Rectangle Widget which has a larger renderable area than the visible area.
|
||||
/// This allows user-controlled scrolling of the viewable content.
|
||||
class JUI::ScrollingRect : public Rect {
|
||||
protected:
|
||||
bool vertical_scrollbar_enabled = true;
|
||||
bool horizontal_scrollbar_enabled = true;
|
||||
bool scrollbar_visible = true;
|
||||
float scrollbar_width = 12;
|
||||
Color4 scrollbar_color = Colors::Whites::Azure;
|
||||
float scroll = 0;
|
||||
JGL::RenderTarget* canvas = nullptr;
|
||||
|
||||
protected:
|
||||
/* This isn't public because nothing should ever
|
||||
* have to do this from the outside. -Redacted */
|
||||
void RecomputeRenderTarget();
|
||||
public:
|
||||
float scroll_size = 0;
|
||||
JGL::RenderTarget* GetCanvas();
|
||||
[[nodiscard]] Vector2i CanvasSize() const;
|
||||
[[nodiscard]] float ScrollPos() const { return scroll; }
|
||||
[[nodiscard]] Vector2 CanvasPosition() const;
|
||||
// TODO scrolling in either direction. Assuming vertical scroll for now.
|
||||
Vector2 CanvasAbsolutePosition() const;
|
||||
Vector2 CanvasAbsoluteSize() const;
|
||||
public:
|
||||
void ScrollPos(float pos) { scroll = pos; }
|
||||
void CanvasSize(const Vector2i& new_size);
|
||||
void InnerDraw() override;
|
||||
void Draw() override;
|
||||
void Update(float delta) override
|
||||
{
|
||||
//scroll += delta*5;
|
||||
//canvas->Resize(Vector2i(GetAbsoluteSize().x, GetAbsoluteSize().y));
|
||||
Rect::Update(delta);
|
||||
}
|
||||
|
||||
void ObserveKeyInput(Key key, bool pressed) override
|
||||
{
|
||||
if (key == Keys::UpArrow && pressed)
|
||||
{
|
||||
scroll -= 10;
|
||||
}
|
||||
if (key == Keys::DownArrow && pressed)
|
||||
{
|
||||
scroll += 10;
|
||||
}
|
||||
|
||||
}
|
||||
public:
|
||||
~ScrollingRect() override;
|
||||
|
||||
ScrollingRect();
|
||||
explicit ScrollingRect(Widget* parent);;
|
||||
};
|
@@ -5,6 +5,67 @@
|
||||
/// (c) 2024 Redacted Software
|
||||
/// This work is dedicated to the public domain.
|
||||
|
||||
/// @file Widget.hpp
|
||||
/// @desc Base Widget Class - All JUI widgets extend their behavior from this class.
|
||||
/// @edit 2024-07-31
|
||||
/// @file Slider.hpp
|
||||
/// @desc Slider widget class header.
|
||||
/// @edit 2024-10-31
|
||||
|
||||
|
||||
#pragma once
|
||||
#include "Button.hpp"
|
||||
#include "Rect.hpp"
|
||||
#include "JUI/Mixins/Draggable.hpp"
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
T roundMultiple( T value, T multiple )
|
||||
{
|
||||
if (multiple == 0) return value;
|
||||
return static_cast<T>(std::round(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
|
||||
}
|
||||
|
||||
/// A slider is a widget with a handle which can be pulled back and forth to change the value.
|
||||
class Slider : public Rect, public Clickable, public Hoverable
|
||||
{
|
||||
public:
|
||||
Event<float> ValueChanged;
|
||||
|
||||
Slider() = default;
|
||||
explicit Slider(JUI::Widget* parent);
|
||||
|
||||
[[nodiscard]] float Minimum() const;
|
||||
[[nodiscard]] float Maximum() const;
|
||||
[[nodiscard]] float Interval() const;
|
||||
[[nodiscard]] float CurrentValue() const;
|
||||
[[nodiscard]] Color4 ScrubberColor() const;
|
||||
[[nodiscard]] float ScrubberWidth() const;
|
||||
|
||||
[[nodiscard]] float Range() const;
|
||||
|
||||
void Minimum(float min);
|
||||
void Maximum(float max);
|
||||
void Interval(float inter);
|
||||
void CurrentValue(float value);
|
||||
void ScrubberColor(const Color4& color);
|
||||
void ScrubberWidth(float width);
|
||||
|
||||
|
||||
void OnClick(const J3ML::LinearAlgebra::Vector2 &MousePos, const JUI::MouseButton &MouseButton) override;
|
||||
void OnRelease(const J3ML::LinearAlgebra::Vector2 &MousePos, const JUI::MouseButton &MouseButton, bool MouseStillOver) override;
|
||||
void OnHover(const J3ML::LinearAlgebra::Vector2 &MousePos) override;
|
||||
void OnExit(const J3ML::LinearAlgebra::Vector2 &MousePos) override;
|
||||
void Update(float delta) override;
|
||||
void Draw() override;
|
||||
|
||||
protected:
|
||||
float minimum = 0;
|
||||
float maximum = 1;
|
||||
float interval = 0.1;
|
||||
float current;
|
||||
bool dragging;
|
||||
float scrubber_width = 20;
|
||||
Color4 scrubber_color = Colors::White;
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
7
include/JUI/Widgets/Table.hpp
Normal file
7
include/JUI/Widgets/Table.hpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
}
|
@@ -6,8 +6,8 @@
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
/// A Text Widget
|
||||
/// @see TextBase.hpp
|
||||
/// A Widget that displays text within the bounds of it's parent widget.
|
||||
/// @see TextRect.hpp, TextBase.hpp
|
||||
class Text : public Widget, public TextBase
|
||||
{
|
||||
public:
|
||||
|
@@ -1,9 +1,27 @@
|
||||
/// 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 TextButton.hpp
|
||||
/// @desc Button class with text. @see Button, Text
|
||||
/// @edit 2024-10-31
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <JUI/Widgets/Button.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
class TextButton : public Button, public TextBase
|
||||
{
|
||||
|
||||
/// Text-displaying button widget.
|
||||
class TextButton : public Button, public TextBase {
|
||||
public:
|
||||
TextButton();
|
||||
explicit TextButton(Widget* parent);
|
||||
~TextButton() override {};
|
||||
void Update(float delta) override;
|
||||
void Draw() override;
|
||||
};
|
||||
}
|
@@ -9,10 +9,64 @@
|
||||
/// @desc A box that accepts user keyboard input.
|
||||
/// @edit 2024-08-02
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <JUI/Mixins/Clickable.hpp>
|
||||
|
||||
#include "TextRect.hpp"
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
class TextInputForm : public TextRect, public Clickable
|
||||
{
|
||||
public:
|
||||
Event<> OnSelect;
|
||||
Event<> OnDeselect;
|
||||
Event<std::string> OnReturn;
|
||||
TextInputForm();
|
||||
explicit TextInputForm(Widget* parent);
|
||||
void Update(float elapsed) override;
|
||||
void InnerDraw() override;
|
||||
void Draw() override;
|
||||
void ObserveKeyInput(Key key, bool pressed) override;
|
||||
void ObserveMouseInput(MouseButton btn, bool pressed) override;
|
||||
void ObserveMouseMovement(const Vector2 &latest_known_pos) override;
|
||||
[[nodiscard]] std::string GetAutocompleteText() const;
|
||||
void SetAutoCompleteText(const std::string& text);
|
||||
[[nodiscard]] Color4 GetAutocompleteTextColor() const;
|
||||
void SetAutocompleteTextColor(const Color4& color);
|
||||
[[nodiscard]] bool HideAutocompleteOnSelect() const;
|
||||
void SetHideAutocompleteOnSelect(bool hide);
|
||||
[[nodiscard]] bool AutocompleteTextEnabled() const;
|
||||
void SetAutocompleteTextEnabled(bool enabled);
|
||||
|
||||
// TODO: Implement selection of part of input text.
|
||||
Color4 GetSelectionColor() const;
|
||||
void SetSelectionColor(const Color4& color);
|
||||
bool HasSelection() const;
|
||||
std::string GetSelectedText() const;
|
||||
bool HasFocus() const;
|
||||
void SetFocused(bool focused);
|
||||
|
||||
void GrabFocus();
|
||||
void DropFocus();
|
||||
|
||||
std::vector<char> GetBlacklist() const { return blacklist;}
|
||||
protected:
|
||||
bool clear_text_on_return;
|
||||
bool focused = false;
|
||||
bool selection_enabled;
|
||||
bool selection_active;
|
||||
int selection_start_index;
|
||||
int selection_end_index;
|
||||
int cursor_position = 0;
|
||||
std::string input_buffer;
|
||||
float cursor_blink_time = 0.f;
|
||||
Color4 autocomplete_color = Colors::Black;
|
||||
std::string autocomplete_text = "Hello World";
|
||||
bool hide_autocomplete_on_select = true;
|
||||
bool autocomplete_text_enabled = true;
|
||||
std::vector<char> blacklist;
|
||||
private:
|
||||
};
|
||||
}
|
@@ -11,9 +11,17 @@ namespace JUI {
|
||||
TextRect(Widget* parent);
|
||||
void Update(float delta) override;
|
||||
void Draw() override;
|
||||
[[nodiscard]] bool FitText() const { return fit_text; }
|
||||
void FitText(bool on) { fit_text = on; }
|
||||
|
||||
bool AutoFitSizeToText() const { return fit_size_to_text; }
|
||||
void AutoFitSizeToText(bool resize){ fit_size_to_text = resize; }
|
||||
|
||||
|
||||
bool TextWrap() const;
|
||||
void TextWrap(bool enable) const;
|
||||
void InnerDraw() override;
|
||||
protected:
|
||||
bool fit_text = false;
|
||||
|
||||
bool fit_size_to_text = false;
|
||||
bool wrap_text = false;
|
||||
};
|
||||
}
|
44
include/JUI/Widgets/Tooltip.hpp
Normal file
44
include/JUI/Widgets/Tooltip.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <JUI/Widgets/TextRect.hpp>
|
||||
#include "ReWindow/InputService.h"
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
class Tooltip : public TextRect
|
||||
{
|
||||
public:
|
||||
Tooltip() : TextRect()
|
||||
{
|
||||
|
||||
}
|
||||
explicit Tooltip(Widget* parent) : Tooltip()
|
||||
{
|
||||
this->Parent(parent);
|
||||
this->AutoFitSizeToText(true);
|
||||
this->ZIndex(10);
|
||||
this->Visible(false);
|
||||
this->Size({100_px, 20_px});
|
||||
|
||||
}
|
||||
|
||||
void Update(float delta) override
|
||||
{
|
||||
|
||||
if (parent && parent->IsMouseInside() || IsMouseInside())
|
||||
{
|
||||
auto coords = InputService::GetMousePosition();
|
||||
Position(UDim2::FromPixels(coords.x, coords.y));
|
||||
Visible(true);
|
||||
} else
|
||||
Visible(false);
|
||||
|
||||
|
||||
TextRect::Update(delta);
|
||||
}
|
||||
~Tooltip() override {};
|
||||
|
||||
protected:
|
||||
};
|
||||
}
|
106
include/JUI/Widgets/UtilityBar.hpp
Normal file
106
include/JUI/Widgets/UtilityBar.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
class ContextMenu : public Rect {
|
||||
public:
|
||||
ContextMenu() : Rect() {
|
||||
this->BGColor(Colors::White);
|
||||
this->Margin(2_px);
|
||||
this->Size({200, 200, 0, 0});
|
||||
layout = new VerticalListLayout(this);
|
||||
|
||||
MouseExit += [this] (Vector2 _)
|
||||
{
|
||||
this->Visible(false);
|
||||
this->Parent(nullptr);
|
||||
// TODO: Collect
|
||||
};
|
||||
}
|
||||
|
||||
explicit ContextMenu(Widget* parent) : ContextMenu()
|
||||
{
|
||||
this->Parent(parent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SetFont(const JGL::Font& use_my_font)
|
||||
{
|
||||
font = use_my_font;
|
||||
}
|
||||
TextButton* AddItem(const std::string &name)
|
||||
{
|
||||
auto* line_item = new TextButton(layout);
|
||||
line_item->SetFont(font);
|
||||
line_item->SetContent(name);
|
||||
line_item->SetTextSize(16);
|
||||
line_item->SetTextColor(Colors::Black);
|
||||
line_item->Size({0, 20, 1, 0});
|
||||
return line_item;
|
||||
}
|
||||
protected:
|
||||
VerticalListLayout* layout;
|
||||
JGL::Font font;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class UtilityBar : public Rect
|
||||
{
|
||||
public:
|
||||
UtilityBar() : Rect()
|
||||
{
|
||||
// TODO: Make a note that all JGL::Font members on widgets need to be initialized to JGL::Fonts::Jupiteroid inside the constructor.
|
||||
font = JGL::Fonts::Jupiteroid;
|
||||
|
||||
this->Size({0, 20, 1, 0});
|
||||
this->Position({0,0,0,0});
|
||||
this->BGColor(Colors::White);
|
||||
this->BorderColor(Colors::Blues::CornflowerBlue);
|
||||
this->SetBorderWidth(2);
|
||||
this->Margin(2_px);
|
||||
this->BorderMode(BorderMode::Outline);
|
||||
layout = new HorizontalListLayout(this);
|
||||
//layout->PaddingLeft(2_px);
|
||||
layout->PaddingRight(2_px);
|
||||
//layout->PaddingRight(2_px);
|
||||
}
|
||||
|
||||
explicit UtilityBar(Widget* parent) : UtilityBar() {
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
TextButton* AddSubmenu(const std::string& name)
|
||||
{
|
||||
auto btn = AddButton(name);
|
||||
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
|
||||
TextButton* AddButton(const std::string& name)
|
||||
{
|
||||
auto str_width = font.MeasureString(name, 14);
|
||||
|
||||
auto* btn = new TextButton(layout);
|
||||
btn->SetFont(font);
|
||||
btn->SetTextSize(14);
|
||||
btn->SetTextColor(Colors::Black);
|
||||
btn->Size({static_cast<int>(str_width.x)+16, 0, 0, 1});
|
||||
btn->SetBorderWidth(0.f);
|
||||
btn->SetContent(name);
|
||||
return btn;
|
||||
}
|
||||
void SetFont(const JGL::Font& use_my_font)
|
||||
{
|
||||
font = use_my_font;
|
||||
}
|
||||
protected:
|
||||
HorizontalListLayout* layout;
|
||||
JGL::Font font;
|
||||
private:
|
||||
};
|
||||
}
|
@@ -1,6 +1,14 @@
|
||||
//
|
||||
// Created by dawsh on 8/1/24.
|
||||
//
|
||||
/// 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 Viewport.hpp
|
||||
/// @desc A rectangular window that contains a 'viewport' to a
|
||||
/// @edit 2024-10-31
|
||||
|
||||
|
||||
#ifndef JUI_VIEWPORT_HPP
|
||||
#define JUI_VIEWPORT_HPP
|
||||
|
@@ -13,106 +13,101 @@
|
||||
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
|
||||
#include <JUI/Base/RectBase.hpp>
|
||||
#include <JUI/Widgets/Rect.hpp>
|
||||
#include <JUI/Widgets/Text.hpp>
|
||||
#include <JUI/Widgets/Button.hpp>
|
||||
#include <JUI/Mixins/Draggable.hpp>
|
||||
#include <JUI/Mixins/Resizable.hpp>
|
||||
#include <JUI/Mixins/Dockable.hpp>
|
||||
#include <JUI/Mixins/Hoverable.hpp>
|
||||
#include <JUI/Mixins/Clickable.hpp>
|
||||
#include <JUI/Widgets/TextButton.hpp>
|
||||
#include <JUI/Widgets/ImageButton.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
|
||||
/// A mixin helper class that enables a widget to be dragged around by the mouse.
|
||||
class Draggable {
|
||||
public:
|
||||
Event<> OnDragBegan;
|
||||
Event<> OnDragEnded;
|
||||
bool Dragging() const { return dragging;}
|
||||
virtual void SetDrag(bool b) {
|
||||
this->dragging = b;
|
||||
}
|
||||
virtual void StartDragging(const Vector2& point)
|
||||
{
|
||||
initial_drag_offset = point;
|
||||
}
|
||||
virtual void StopDragging() {}
|
||||
virtual void Update(float delta) {}
|
||||
protected:
|
||||
bool dragging = false;
|
||||
Vector2 initial_drag_offset = {0, 0};
|
||||
};
|
||||
|
||||
/// A mixin helper class that enables a widget to be resized by the mouse.
|
||||
class Resizable {
|
||||
public:
|
||||
Event<> OnDragBegan;
|
||||
Event<> OnDragEnded;
|
||||
bool Resizing() const { return resizing;}
|
||||
virtual void SetResize(bool b) {
|
||||
this->resizing = b;
|
||||
}
|
||||
virtual void StartResizing(const Vector2& point)
|
||||
{
|
||||
initial_resize_offset = point;
|
||||
}
|
||||
virtual void StopResizing() {}
|
||||
virtual void Update(float delta) {}
|
||||
protected:
|
||||
bool resizing = false;
|
||||
Vector2 initial_resize_offset = {0, 0};
|
||||
};
|
||||
|
||||
|
||||
/// A mixin helper class that enables a widget to be docked into a DockingStation.
|
||||
class Dockable {};
|
||||
|
||||
/// TODO: Scope out.
|
||||
class DockingStation {};
|
||||
|
||||
/// A container widget class, with title bar and buttons,
|
||||
/// which can be dragged around, resized, and docked into other applicable widgets.
|
||||
class Window : public Widget, RectBase, public Clickable, public Hoverable, public Draggable, public Resizable, public Dockable
|
||||
class Window : public Widget, public RectBase, public Clickable, public Hoverable, public Draggable, public Resizable, public Dockable
|
||||
{
|
||||
public:
|
||||
/// The default constructor sets a default style for this Window.
|
||||
Window();
|
||||
/// Construct a window widget by specifying it's parent.
|
||||
Window(Widget* parent);
|
||||
/// Returns the minimum size (in x,y pixels) that the Window widget is allowed to be.
|
||||
[[nodiscard]] Vector2 MinSize() const;
|
||||
/// Returns the maximum size (in x,y pixels) that the Window widget is allowed to be.
|
||||
[[nodiscard]] Vector2 MaxSize() const;
|
||||
|
||||
/// Returns the current size (in x,y pixels) of the Window widget.
|
||||
[[nodiscard]] Vector2 CurrentSize() const;
|
||||
|
||||
/// Returns the minimum size (in x,y pixels) that the Window widget is allowed to be.
|
||||
[[nodiscard]] Vector2 MinSize() const;
|
||||
/// Sets the minimum size (in x,y pixels) that the Window widget is allowed to be.
|
||||
void MinSize(const Vector2& constraint);
|
||||
/// Returns the maximum size (in x,y pixels) that the Window widget is allowed to be.
|
||||
[[nodiscard]] Vector2 MaxSize() const;
|
||||
/// Sets the maximum size (in x,y pixels) that the Window widget is allowed to be.
|
||||
void MaxSize(const Vector2& constraint);
|
||||
|
||||
|
||||
/// Returns the height (in pixels) of the Window's titlebar.
|
||||
// TODO: Decide if this will auto-scale with the titlebar's text height, or the other way around.
|
||||
int TitlebarHeight() const;
|
||||
|
||||
/// Returns the text displayed as the Window's title.
|
||||
[[nodiscard]] std::string Title() const;
|
||||
|
||||
|
||||
void SetTitle(const std::string& title);
|
||||
/// Returns whether dragging the window about with the mouse is enabled.
|
||||
/// @see class Draggable.
|
||||
bool IsDraggable() const;
|
||||
|
||||
|
||||
void SetDraggable(bool value);
|
||||
|
||||
/// Returns whether this Window is able to be 'Docked' into another widget.
|
||||
/// @see class Dockable.
|
||||
bool IsDockable() const;
|
||||
|
||||
void SetDockable(bool value);
|
||||
|
||||
/// Align topbar buttons to the left.
|
||||
void LayoutControlsLeft();
|
||||
|
||||
/// Align topbar buttons to the right.
|
||||
void LayoutControlsRight();
|
||||
|
||||
/// Returns whether resizing the window via right-click is enabled.
|
||||
/// @see class Resizable
|
||||
bool IsResizable() const;
|
||||
|
||||
/// Returns a pointer to the Text Widget that is used to render the title bar's text.
|
||||
Text* GetTitleInstance();
|
||||
/// Returns a pointer to the Rect Widget that is used to layout the title bar contents.
|
||||
Rect* GetTopbarInstance();
|
||||
/// Returns a pointer to the Rect Widget that is used to layout the contents of the window.
|
||||
Rect* GetViewportInstance();
|
||||
/// Returns a pointer to the Exit Button Widget.
|
||||
TextButton* GetExitButtonInstance();
|
||||
void SetResizable(bool value);
|
||||
|
||||
/// Returns a pointer to the Text Widget that is used to render the title bar's text.
|
||||
Text* TitleInstance();
|
||||
/// Returns a pointer to the Rect Widget that is used to layout the title bar contents.
|
||||
Rect* TopbarInstance();
|
||||
/// Returns a pointer to the Rect Widget that is used to layout the contents of the window.
|
||||
Rect* ViewportInstance();
|
||||
/// Returns a pointer to the Exit Button Widget.
|
||||
ImageButton* ExitButtonInstance();
|
||||
|
||||
Vector2 AbsoluteViewportPosition() const;
|
||||
Vector2 AbsoluteViewportSize() const;
|
||||
AABB2D AbsoluteViewportBounds() const;
|
||||
|
||||
|
||||
|
||||
|
||||
/// Sets the font used by the title-bar text on this Window.
|
||||
void SetTitleFont(const Font& f);
|
||||
|
||||
|
||||
/// Toggles whether this window is actively being dragged by the mouse.
|
||||
/// @see class Draggable.
|
||||
void SetDrag(bool d) override;
|
||||
|
||||
@@ -128,17 +123,17 @@ namespace JUI
|
||||
JUI::Rect* Topbar;
|
||||
JUI::Rect* Viewport;
|
||||
JUI::Text* TitleLabel;
|
||||
JUI::TextButton* exit_btn;
|
||||
JUI::TextButton* fs_btn;
|
||||
JUI::ImageButton* exit_btn;
|
||||
JUI::ImageButton* fs_btn;
|
||||
std::string title = "JUI Window";
|
||||
bool resizable = true;
|
||||
//bool resizing = false;
|
||||
bool draggable = true;
|
||||
bool dockable = false;
|
||||
int titlebar_height = 16;
|
||||
int titlebar_height = 20;
|
||||
int title_font_size = 16;
|
||||
Vector2 max_size;
|
||||
Vector2 min_size; //= {30, 30};
|
||||
UDim2 size_when_restart_began;
|
||||
};
|
||||
|
||||
}
|
||||
|
365
main.cpp
365
main.cpp
@@ -19,186 +19,216 @@
|
||||
#include <JUI/Widgets/ListLayout.hpp>
|
||||
#include <JUI/Widgets/TextRect.hpp>
|
||||
#include <JUI/Widgets/Image.hpp>
|
||||
#include <rewindow/types/window.h>
|
||||
#include <jlog/Logger.hpp>
|
||||
#include <JUI/Widgets/Slider.hpp>
|
||||
#include <JUI/Widgets/ScrollingRect.hpp>
|
||||
#include <JUI/Widgets/UtilityBar.hpp>
|
||||
#include <JUI/Widgets/Checkbox.hpp>
|
||||
#include <JUI/Widgets/TextInputForm.hpp>
|
||||
#include <ReWindow/types/Window.h>
|
||||
#include <ReWindow/Logger.h>
|
||||
#include "JUI/Widgets/NineSlice.hpp"
|
||||
|
||||
JGL::Font FreeSans;
|
||||
JUI::Scene* scene;
|
||||
JGL::Texture* sample_texture;
|
||||
JGL::Texture* slicer;
|
||||
JUI::VerticalListLayout* list;
|
||||
JUI::ScrollingRect* scroller;
|
||||
|
||||
JUI::Scene* CreateScene() {
|
||||
using namespace JUI;
|
||||
|
||||
Scene *root = new Scene();
|
||||
|
||||
auto* JUI = new TextRect(root);
|
||||
JUI->SetFont(FreeSans);
|
||||
JUI->SetTextSize(48);
|
||||
JUI->SetTextColor({32, 48, 192});
|
||||
JUI->SetContent("Josh User Interface");
|
||||
JUI->AlignBottom();
|
||||
JUI->AlignCenterHorizontally();
|
||||
JUI->SetAnchorPoint(Vector2(0.5f, 0.5f));
|
||||
JUI->SetPosition({50_percent, 50_percent});
|
||||
//JUI->SetSize({30_percent, 10_percent});
|
||||
JUI->FitText(true);
|
||||
JUI->SetPadding(20_px);
|
||||
JUI->BGColor({64, 64, 64, 128});
|
||||
JUI->SetBorderWidth(2);
|
||||
JUI->BorderColor({255, 255, 255, 128});
|
||||
auto* Redacted = new TextRect(root);
|
||||
Redacted->SetFont(FreeSans);
|
||||
Redacted->SetTextSize(32);
|
||||
Redacted->SetTextColor({255, 255, 255});
|
||||
Redacted->SetContent("Redacted Software Group");
|
||||
Redacted->SetPosition({50_percent, 60_percent});
|
||||
//Redacted->SetSize({30_percent, 10_percent});
|
||||
Redacted->AlignCenterHorizontally();
|
||||
Redacted->AlignTop();
|
||||
Redacted->SetAnchorPoint(Vector2(0.5f, .5f));
|
||||
Redacted->FitText(true);
|
||||
Redacted->SetPadding(10_px);
|
||||
Redacted->BGColor({32, 48, 192});
|
||||
Redacted->SetBorderWidth(1);
|
||||
Redacted->BorderColor({64, 64, 64});
|
||||
auto* nineslice_demo_window = new JUI::Window(root);
|
||||
nineslice_demo_window->CornerRounding(5);
|
||||
nineslice_demo_window->Size({50_percent, 50_percent});
|
||||
nineslice_demo_window->SetTitle("9-Slice Demo");
|
||||
nineslice_demo_window->Visible(false);
|
||||
|
||||
|
||||
// Rect //
|
||||
Rect *rect_element = new Rect(root);
|
||||
rect_element->SetName("JimBob");
|
||||
auto* topbar = new UtilityBar(root);
|
||||
topbar->ZIndex(3);
|
||||
auto* file = topbar->AddButton("Demos");
|
||||
|
||||
//Rect* element = new Rect(root);
|
||||
auto* file_tt = new JUI::Tooltip(file);
|
||||
file_tt->SetContent("Tooltip");
|
||||
|
||||
//rect_element->SetName("JimBob");
|
||||
//element->BGColor({0,255,0});
|
||||
rect_element->BGColor({0, 64, 0});
|
||||
rect_element->SetSize({0, 0, 0.1f, 0.2f});
|
||||
rect_element->SetClipsDescendants(true);
|
||||
rect_element->BorderColor({255, 255, 255});
|
||||
rect_element->SetBorderWidth(2.f);
|
||||
file->OnClickEvent += [&, root, nineslice_demo_window] (Vector2 pos, JUI::MouseButton btn)
|
||||
{
|
||||
auto* ctx_menu = new ContextMenu(root);
|
||||
ctx_menu->Position(UDim2(0,20,0,0));
|
||||
auto* open_nineslice = ctx_menu->AddItem("9-Slice Widget Demo");
|
||||
|
||||
rect_element->MouseEnter += [rect_element](auto coords) {
|
||||
open_nineslice->OnClickEvent += [&, nineslice_demo_window] (Vector2 pos, JUI::MouseButton btn) {
|
||||
nineslice_demo_window->Visible(true);
|
||||
};
|
||||
|
||||
auto* open_scroll = ctx_menu->AddItem("Scroll Widget Demo");
|
||||
|
||||
open_scroll->OnClickEvent += [&] (Vector2 pos, JUI::MouseButton btn) {};
|
||||
ctx_menu->AddItem("");
|
||||
ctx_menu->ZIndex(3);
|
||||
|
||||
rect_element->BGColor({0, 128, 0});
|
||||
};
|
||||
|
||||
rect_element->MouseExit += [rect_element](auto coords) {
|
||||
rect_element->BGColor({0, 64, 0});
|
||||
};
|
||||
topbar->AddButton("Edit");
|
||||
auto* view = topbar->AddButton("View");
|
||||
|
||||
// End Rect //
|
||||
topbar->AddButton("Help");
|
||||
|
||||
//auto* horizontal = new HorizontalListLayout(root);
|
||||
//horizontal->ZIndex(1);
|
||||
|
||||
auto* sizer_1 = new Rect(root);
|
||||
//sizer_1->ZIndex(4);
|
||||
sizer_1->Size({0,-24,0.2f, 1.f});
|
||||
sizer_1->Position({0, 24, 0, 0});
|
||||
sizer_1->BGColor(Colors::Grays::Gainsboro);
|
||||
|
||||
auto* s1_vert = new VerticalListLayout(sizer_1);
|
||||
|
||||
auto* button = new TextButton(s1_vert);
|
||||
//button->Position({5, 105, 0, 0});
|
||||
button->Size({0, 35, 1, 0});
|
||||
button->SetTextColor(Colors::Black);
|
||||
button->SetContent("Button");
|
||||
button->AlignLeft();
|
||||
button->Padding(5_px);
|
||||
|
||||
auto* tt2 = new JUI::Tooltip(button);
|
||||
tt2->SetContent("Test 123");
|
||||
|
||||
auto* button2 = new TextButton(s1_vert);
|
||||
//button2->Position({5, 105, 0, 0});
|
||||
button2->Size({0, 35, 1, 0});
|
||||
button2->SetTextColor(Colors::Black);
|
||||
button2->SetContent("Button");
|
||||
button2->AlignCenterHorizontally();
|
||||
|
||||
auto* button3 = new TextButton(s1_vert);
|
||||
//button2->Position({5, 105, 0, 0});
|
||||
button3->Size({0, 35, 1, 0});
|
||||
button3->SetTextColor(Colors::Black);
|
||||
button3->SetContent("Button");
|
||||
button3->AlignRight();
|
||||
|
||||
auto* checkbox_container = new Rect(s1_vert);
|
||||
checkbox_container->Size({0, 35, 1, 0});
|
||||
|
||||
|
||||
// Button //
|
||||
RadioButton *button_element = new RadioButton(root);
|
||||
button_element->SetName("BobJim");
|
||||
button_element->BGColor({0, 0, 64});
|
||||
button_element->SetSize({0, 0, 0.1f, 0.1f});
|
||||
button_element->SetClipsDescendants(true);
|
||||
button_element->BorderColor({255, 255, 255});
|
||||
button_element->SetBorderWidth(2.f);
|
||||
auto bpos = rect_element->Size();
|
||||
auto* checkbox_horiz = new HorizontalListLayout(checkbox_container);
|
||||
|
||||
//exit(1);
|
||||
button_element->SetPosition(
|
||||
{bpos.X.Pixels, bpos.Y.Pixels, bpos.X.Scale - 0.2f, 0}); // I don't know how to use sx and sy - maxine
|
||||
button_element->OnToggleOnEvent += [rect_element] () {
|
||||
rect_element->BGColor({64, 0, 0});
|
||||
};
|
||||
button_element->OnToggleOffEvent += [rect_element] () {
|
||||
rect_element->BGColor({0, 64, 0});
|
||||
};
|
||||
button_element->OnToggleEvent += [button_element] () {
|
||||
Color4 incbg = button_element->BGColor();
|
||||
// Once an overflow occurs it will reset anyway
|
||||
// Thanks computer science
|
||||
if (incbg.b < 255)
|
||||
incbg.b += 10;
|
||||
button_element->BGColor(incbg);
|
||||
};
|
||||
Text* btntext = new Text(button_element);
|
||||
btntext->SetContent("I AM BUTTON");
|
||||
btntext->SetFont(FreeSans);
|
||||
btntext->SetTextSize(8);
|
||||
btntext->SetTextColor({255, 0, 0});
|
||||
// End Button //
|
||||
auto* check1 = new Checkbox(checkbox_horiz);
|
||||
|
||||
// Window //
|
||||
JUI::Window* win_element = new JUI::Window(root);
|
||||
win_element->SetTitleFont(FreeSans);
|
||||
win_element->SetSize({50_percent, 50_percent});
|
||||
win_element->SetTitle("JUI Example Window Widget");
|
||||
//win_element->SetPadding(1_px);
|
||||
auto* input_form = new TextInputForm(s1_vert);
|
||||
input_form->Size({0,30, 1, 0});
|
||||
input_form->SetContent("");
|
||||
input_form->SetTextSize(14);
|
||||
|
||||
auto* other_window = new JUI::Window(root);
|
||||
other_window->Position({10_percent, 10_percent});
|
||||
other_window->Size({30_percent, 25_percent});
|
||||
other_window->SetTitle("Another Window");
|
||||
|
||||
other_window->TweenPositionTo({50_percent, 50_percent});
|
||||
|
||||
scroller = new JUI::ScrollingRect(other_window->ViewportInstance());
|
||||
scroller->Size({100_percent, 100_percent});
|
||||
scroller->BGColor(Colors::Reds::LightCoral);
|
||||
|
||||
|
||||
list = new JUI::VerticalListLayout(scroller);
|
||||
list->LayoutOrder(JUI::LayoutOrder::V::BOTTOM);
|
||||
|
||||
|
||||
|
||||
//nineslice_demo_window->Padding(1_px);
|
||||
// End Window //
|
||||
|
||||
|
||||
auto list = new VerticalListLayout(win_element->GetViewportInstance());
|
||||
list->SetPadding(10_px);
|
||||
auto* nineslice = new JUI::NineSliceRect(nineslice_demo_window);
|
||||
nineslice->Content(slicer);
|
||||
nineslice->Size({100_percent, 100_percent});
|
||||
nineslice->BGColor(Colors::Transparent);
|
||||
nineslice->TopLeftQuad({{0,0},{96,96}});
|
||||
nineslice->TopRightQuad({{384-96,0},{96,96}});
|
||||
nineslice->BottomLeftQuad({ {0, 378-96}, {96, 96}});
|
||||
nineslice->BottomRightQuad({ {384-96, 378-96}, {96, 96}});
|
||||
|
||||
nineslice->TopQuad({ {96, 0}, {192, 96} });
|
||||
nineslice->BottomQuad({ {96, 378-96}, {192, 96} });
|
||||
nineslice->RightQuad({{384-(96), 96}, {96, 378-(96*2)}});
|
||||
nineslice->LeftQuad({{0, 96}, {96, 378-(96*2)}});
|
||||
|
||||
nineslice->CenterQuad({{96, 96}, {384-(96*2), 378-(96*2)}});
|
||||
|
||||
|
||||
auto darkie = new JUI::Image(nineslice_demo_window->ViewportInstance(), sample_texture);
|
||||
darkie->FitImageToParent(true);
|
||||
darkie->Color({255,255,255,128});
|
||||
|
||||
auto list = new VerticalListLayout(nineslice_demo_window->ViewportInstance());
|
||||
list->Padding(10_px);
|
||||
|
||||
|
||||
|
||||
TextRect* a = new TextRect(list);
|
||||
a->SetTextSize(16);
|
||||
a->SetFont(FreeSans);
|
||||
a->SetSize({0, 20, 1, 0});
|
||||
a->Size({0, 20, 1, 0});
|
||||
//a->FitText(true);
|
||||
a->Center();
|
||||
a->SetContent("Greetings. This is the JUI demo program!");
|
||||
a->SetContent("This is a virtual window.");
|
||||
|
||||
|
||||
TextRect* b = new TextRect(list);
|
||||
b->SetTextSize(16);
|
||||
b->SetContent("JUI is my home-coded game menu building toolkit.");
|
||||
b->SetContent("You can drag it around via left-click, and resize via right-click.");
|
||||
//b->FitText(true);
|
||||
b->SetSize({0, 20, 1, 0});
|
||||
b->Size({0, 20, 1, 0});
|
||||
b->Center();
|
||||
b->SetFont(FreeSans);
|
||||
|
||||
TextRect* c = new TextRect(list);
|
||||
c->SetTextSize(16);
|
||||
c->SetContent("Settings");
|
||||
//c->FitText(true);
|
||||
c->SetSize({0, 20, 1, 0});
|
||||
c->Center();
|
||||
c->SetFont(FreeSans);
|
||||
|
||||
TextRect* d = new TextRect(list);
|
||||
d->SetTextSize(16);
|
||||
d->SetContent("Exit");
|
||||
//d->FitText(true);
|
||||
d->SetSize({0, 20, 1, 0});
|
||||
d->Center();
|
||||
d->SetFont(FreeSans);
|
||||
|
||||
Text *text = new Text(rect_element);
|
||||
text->SetContent("YO MAMA");
|
||||
text->SetFont(FreeSans);
|
||||
text->SetTextSize(48);
|
||||
text->SetTextColor({255, 0, 0});
|
||||
|
||||
auto darkie = new Image(win_element->GetViewportInstance(), sample_texture);
|
||||
darkie->FitImageToParent(true);
|
||||
darkie->Color({255,255,255,128});
|
||||
|
||||
root->SetViewportSize(800, 600);
|
||||
root->SetViewportSize({800, 600});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
class JUIDevelopmentTestWindow : public ReWindow::RWindow {
|
||||
float accum = 0;
|
||||
int iter = 0;
|
||||
|
||||
class JUIDevelopmentTestWindow : public ReWindow::OpenGLWindow {
|
||||
public:
|
||||
|
||||
void initGL() {
|
||||
gladLoadGL();
|
||||
JGL::Update(getSize());
|
||||
JGL::InitTextEngine();
|
||||
auto size = GetSize();
|
||||
auto vec_size = Vector2i(size.x, size.y);
|
||||
bool result = JGL::Init(vec_size, 0.f, 0.f);
|
||||
JGL::Update(vec_size);
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
// 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()
|
||||
void Update(float elapsed)
|
||||
{
|
||||
scene->Update(0.f);
|
||||
using namespace JUI::UDimLiterals;
|
||||
|
||||
accum += elapsed;
|
||||
|
||||
scene->Update(elapsed);
|
||||
|
||||
if (accum > 1.f)
|
||||
{
|
||||
iter--;
|
||||
accum = 0.f;
|
||||
auto* text = new JUI::TextRect(list);
|
||||
text->Size({50_percent, 20_px});
|
||||
text->ZIndex(iter);
|
||||
text->SetContent(std::format("{} Sampled Delta: {}ms", -iter, Math::Floor(elapsed*1000.f)));
|
||||
scroller->scroll_size += 20;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Draw()
|
||||
@@ -206,17 +236,19 @@ public:
|
||||
scene->Draw();
|
||||
}
|
||||
|
||||
JUIDevelopmentTestWindow(const std::string& title, int w, int h) : ReWindow::RWindow(title, w, h) {}
|
||||
JUIDevelopmentTestWindow(const std::string& title, int w, int h) : ReWindow::OpenGLWindow(title, w, h, 2, 1) {}
|
||||
void OnRefresh(float elapsed) override {
|
||||
Update();
|
||||
JGL::Update(getSize());
|
||||
scene->SetViewportSize(getSize().x, getSize().y);
|
||||
Update(elapsed);
|
||||
auto size = GetSize();
|
||||
Vector2i vSize = Vector2i(size.x, size.y);
|
||||
JGL::Update(vSize);
|
||||
scene->SetViewportSize(Vector2(vSize));
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
Draw();
|
||||
|
||||
this->glSwapBuffers();
|
||||
this->SwapBuffers();
|
||||
}
|
||||
|
||||
|
||||
@@ -226,40 +258,69 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent &e) override {}
|
||||
JUIDevelopmentTestWindow() : ReWindow::RWindow() {}
|
||||
};
|
||||
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent &) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent &) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OnMouseMove(const ReWindow::MouseMoveEvent &) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void OnKeyDown(const ReWindow::KeyDownEvent &) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent &e) override {}
|
||||
//JUIDevelopmentTestWindow() : ReWindow::OpenGLWindow() {}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
for (float i = 0; i < 1; i += 0.01f)
|
||||
{
|
||||
std::cout << JUI::EasingFunctions::EaseInSine(i) << std::endl;
|
||||
}
|
||||
|
||||
using namespace ReWindow;
|
||||
// TODO: Find out new jlog api for silencing specific loggers.
|
||||
|
||||
ReWindow::Logger::Debug.EnableConsole(false);
|
||||
|
||||
auto* window = new JUIDevelopmentTestWindow("Test Window", 800, 600);
|
||||
window->setRenderer(RenderingAPI::OPENGL);
|
||||
//window->SetRenderer(RenderingAPI::OPENGL);
|
||||
window->Open();
|
||||
window->initGL();
|
||||
window->setFullscreen(false);
|
||||
window->setVsyncEnabled(false);
|
||||
window->setResizable(true);
|
||||
window->SetFullscreen(false);
|
||||
window->SetVsyncEnabled(false);
|
||||
window->SetResizable(true);
|
||||
|
||||
JGL::Update({800, 600});
|
||||
|
||||
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
|
||||
sample_texture = new JGL::Texture("assets/ld.png");
|
||||
slicer = new JGL::Texture("assets/9slice.png");
|
||||
scene = CreateScene();
|
||||
|
||||
|
||||
window->OnResizeRequestEvent += [&] (ReWindow::WindowResizeRequestEvent e){
|
||||
Vector2 size = e.Size;//window->getLastKnownResize();
|
||||
scene->SetViewportSize(size.x, size.y);
|
||||
Vector2i size = Vector2i(e.Size.x, e.Size.y);//window->getLastKnownResize();
|
||||
scene->SetViewportSize(Vector2(size));
|
||||
std::cout << size.x << "," << size.y << std::endl;
|
||||
JGL::Update(size);
|
||||
};
|
||||
|
||||
window->OnMouseMoveEvent += [&] (MouseMoveEvent e)
|
||||
{
|
||||
scene->ObserveMouseMovement(e.Position);
|
||||
scene->ObserveMouseMovement(Vector2(e.Position.x, e.Position.y));
|
||||
};
|
||||
|
||||
window->OnMouseButtonUpEvent += [&] (MouseButtonUpEvent e) {
|
||||
@@ -283,13 +344,17 @@ int main()
|
||||
|
||||
window->OnMouseButtonDownEvent += [&] (MouseButtonDownEvent e) {};
|
||||
|
||||
window->OnKeyDownEvent += [&] (KeyDownEvent e) {};
|
||||
window->OnKeyDownEvent += [&] (KeyDownEvent e) {
|
||||
scene->ObserveKeyInput(e.key, true);
|
||||
};
|
||||
|
||||
window->OnKeyUpEvent += [&] (KeyUpEvent e) {};
|
||||
window->OnKeyUpEvent += [&] (KeyUpEvent e) {
|
||||
scene->ObserveKeyInput(e.key, false);
|
||||
};
|
||||
|
||||
while (window->isAlive()) {
|
||||
window->pollEvents();
|
||||
window->refresh();
|
||||
while (window->IsAlive()) {
|
||||
//window->PollEvents();
|
||||
window->ManagedRefresh();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
BIN
showcase.png
BIN
showcase.png
Binary file not shown.
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 136 KiB |
@@ -6,15 +6,15 @@ using namespace JGL;
|
||||
namespace JUI
|
||||
{
|
||||
void ImageBase::Draw(const Vector2 &pos, const Vector2 &size) {
|
||||
J2D::Begin();
|
||||
//J2D::Begin();
|
||||
// TODO: Support image rotation in the widget.
|
||||
J2D::DrawSprite(*texture, pos, 0, origin, scale, image_color);
|
||||
J2D::End();
|
||||
//J2D::End();
|
||||
}
|
||||
|
||||
ImageBase::ImageBase()
|
||||
{
|
||||
|
||||
this->texture = nullptr;
|
||||
}
|
||||
|
||||
ImageBase::ImageBase(JGL::Texture* tex) : ImageBase()
|
||||
@@ -22,7 +22,7 @@ namespace JUI
|
||||
this->texture = tex;
|
||||
}
|
||||
|
||||
void ImageBase::SetContent(JGL::Texture *content) {
|
||||
void ImageBase::Content(JGL::Texture *content) {
|
||||
this->texture = content;
|
||||
}
|
||||
|
||||
@@ -31,5 +31,13 @@ namespace JUI
|
||||
void ImageBase::Scale(const Vector2 &newScale) { scale = newScale;}
|
||||
|
||||
void ImageBase::Origin(const Vector2 &newOrigin) { origin = newOrigin; }
|
||||
|
||||
JGL::Texture *ImageBase::Content() const { return texture;}
|
||||
|
||||
Color4 ImageBase::Color() const { return image_color;}
|
||||
|
||||
Vector2 ImageBase::Scale() const { return scale;}
|
||||
|
||||
Vector2 ImageBase::Origin() const { return origin;}
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,7 @@ namespace JUI
|
||||
LayoutContainer::LayoutContainer() {}
|
||||
|
||||
LayoutContainer::LayoutContainer(Widget* parent) {
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void LayoutContainer::Update(float delta)
|
||||
|
@@ -27,22 +27,61 @@ namespace JUI {
|
||||
SetBorderWidth(width);
|
||||
}
|
||||
|
||||
void RectBase::Draw(const Vector2 &abs_pos, const Vector2 &abs_size) {
|
||||
// Background rect
|
||||
J2D::Begin();
|
||||
J2D::FillRect(bg_color, abs_pos, abs_size);
|
||||
|
||||
// Outline rect
|
||||
|
||||
Vector2 border_offset = {border_width/2, border_width/2};
|
||||
|
||||
|
||||
// TODO: implement border_mode behavior when rendering here.
|
||||
|
||||
if (corner_rounding_radius >= 0)
|
||||
J2D::OutlineRect(border_color, abs_pos - border_offset, abs_size + (border_offset*2), border_width);
|
||||
J2D::End();
|
||||
void RectBase::Draw(const Vector2& abs_pos, const Vector2& abs_size)
|
||||
{
|
||||
Draw(bg_color, border_color, abs_pos, abs_size);
|
||||
}
|
||||
|
||||
//void RectBase::Draw(const Color4& bgColor, const Color4& borderColor, const Vector2 &abs_pos, const Vector2 &abs_size) {
|
||||
|
||||
//Draw(nullptr, bgColor, borderColor, abs_pos, abs_size);
|
||||
//}
|
||||
|
||||
void RectBase::Draw(const Color4& bgColor, const Color4& borderColor, const Vector2 &abs_pos, const Vector2 &abs_size) {
|
||||
|
||||
//J2D::Begin(canvas, false);
|
||||
|
||||
// Background rect
|
||||
if (corner_rounding_radius > 0)
|
||||
J2D::FillRoundedRect(bgColor, abs_pos, abs_size, corner_rounding_radius);
|
||||
else
|
||||
J2D::FillRect(bgColor, abs_pos, abs_size);
|
||||
|
||||
// Outline rect - compute the size change to fit the border accurately.
|
||||
Vector2 border_offset = {0, 0};
|
||||
|
||||
if (border_mode == BorderMode::Inset)
|
||||
border_offset = {-border_width/2.f, -border_width/2.f};
|
||||
if (border_mode == BorderMode::Middle)
|
||||
border_offset = {0, 0};
|
||||
if (border_mode == BorderMode::Outline)
|
||||
border_offset = {border_width/2.f, border_width/2.f};
|
||||
|
||||
// Draw the outline.
|
||||
if (border_width > 0)
|
||||
{
|
||||
if (corner_rounding_radius > 0)
|
||||
J2D::OutlineRoundedRect(borderColor, abs_pos - border_offset, abs_size + (border_offset*2), corner_rounding_radius, border_width);
|
||||
else
|
||||
J2D::OutlineRect(borderColor, abs_pos - border_offset, abs_size + (border_offset*2), border_width);
|
||||
}
|
||||
|
||||
|
||||
//J2D::End();
|
||||
}
|
||||
|
||||
void RectBase::BorderMode(const enum BorderMode &mode) {
|
||||
border_mode = mode;
|
||||
}
|
||||
|
||||
BorderMode RectBase::BorderMode() const { return border_mode; }
|
||||
|
||||
void RectBase::CornerRounding(float radius) {
|
||||
corner_rounding_radius = radius;
|
||||
}
|
||||
|
||||
float RectBase::CornerRounding() const { return corner_rounding_radius; }
|
||||
|
||||
|
||||
}
|
@@ -1,124 +1,129 @@
|
||||
#include <JUI/Base/TextBase.hpp>
|
||||
#include "JGL/JGL.h"
|
||||
#include <JGL/JGL.h>
|
||||
using namespace JUI;
|
||||
|
||||
void TextBase::SetContent(const std::string& content) { this->content = content; state_redraw = true; }
|
||||
|
||||
namespace JUI {
|
||||
void TextBase::SetContent(const std::string &content) { this->content = content; }
|
||||
void TextBase::SetTextColor(const Color4& color) { this->text_color = color; state_redraw = true; }
|
||||
|
||||
void TextBase::SetTextColor(const Color4 &color) { this->text_color = color; }
|
||||
void TextBase::SetOutlineColor(const Color4& color) { this->outline_color = color; }
|
||||
|
||||
void TextBase::SetOutlineColor(const Color4 &color) { this->outline_color = color; }
|
||||
void TextBase::SetHorizontalTextAlign(const TextAlign::H& align) { this->h_align = align;}
|
||||
|
||||
void TextBase::SetHorizontalTextAlign(const TextAlign::H &align) { this->h_align = align;}
|
||||
void TextBase::SetVerticalTextAlign(const TextAlign::V& align) { this->v_align = align; }
|
||||
|
||||
void TextBase::SetVerticalTextAlign(const TextAlign::V &align) { this->v_align = align; }
|
||||
|
||||
void TextBase::SetTextAlign(const TextAlign::H &h_align, const TextAlign::V &v_align) {
|
||||
SetHorizontalTextAlign(h_align);
|
||||
SetVerticalTextAlign(v_align);
|
||||
}
|
||||
|
||||
void TextBase::AlignLeft() { SetHorizontalTextAlign(TextAlign::H::Left);}
|
||||
|
||||
void TextBase::AlignRight() { SetHorizontalTextAlign(TextAlign::H::Right);}
|
||||
|
||||
void TextBase::AlignTop() {SetVerticalTextAlign(TextAlign::V::Top);}
|
||||
|
||||
void TextBase::AlignBottom() {SetVerticalTextAlign(TextAlign::V::Bottom);}
|
||||
|
||||
void TextBase::AlignCenterBoth() {
|
||||
SetVerticalTextAlign(TextAlign::V::Center);
|
||||
SetHorizontalTextAlign(TextAlign::H::Center);
|
||||
}
|
||||
|
||||
void TextBase::Center() { AlignCenterBoth(); }
|
||||
|
||||
void TextBase::AlignCenterHorizontally() {
|
||||
SetHorizontalTextAlign(TextAlign::H::Center);
|
||||
}
|
||||
|
||||
void TextBase::AlignCenterVertically() {
|
||||
SetVerticalTextAlign(TextAlign::V::Center);
|
||||
}
|
||||
|
||||
void TextBase::SetWordWrap(bool wrap) { word_wrap = wrap; }
|
||||
|
||||
void TextBase::Draw(const Vector2 &abs_pos, const Vector2 &abs_size) {
|
||||
|
||||
// Calculate how much to origin the text based on alignment.
|
||||
float align_x = abs_pos.x;
|
||||
float align_y = abs_pos.y;
|
||||
|
||||
auto bounds = this->GetFont().MeasureString(this->content, this->text_size);
|
||||
|
||||
if (h_align == TextAlign::H::Left) {
|
||||
// Render from left-side of boundary.
|
||||
align_x = abs_pos.x;
|
||||
}
|
||||
if (h_align == TextAlign::H::Center) {
|
||||
// Render from horizontal center, origin by half of the text's width.
|
||||
align_x = abs_pos.x + (abs_size.x / 2) - (bounds.x / 2);
|
||||
}
|
||||
if (h_align == TextAlign::H::Right) {
|
||||
// Render from right-side of boundary, origin by text width.
|
||||
align_x = abs_pos.x + abs_size.x - bounds.x;
|
||||
}
|
||||
if (v_align == TextAlign::V::Top) {
|
||||
// Render from top of boundary.
|
||||
align_y = abs_pos.y;
|
||||
}
|
||||
if (v_align == TextAlign::V::Center) {
|
||||
// Render from vertical center, origin by half of the text's height.
|
||||
align_y = abs_pos.y + (abs_size.y / 2) - (bounds.y / 2);
|
||||
}
|
||||
if (v_align == TextAlign::V::Bottom) {
|
||||
// Render from bottom of boundary, origin by the text's height.
|
||||
align_y = abs_pos.y + abs_size.y - bounds.y;
|
||||
}
|
||||
|
||||
// Now we render.
|
||||
float scale = 1.f;
|
||||
|
||||
JGL::J2D::Begin();
|
||||
JGL::J2D::DrawString(
|
||||
this->text_color,
|
||||
this->content,
|
||||
align_x, align_y,
|
||||
scale,
|
||||
this->text_size,
|
||||
this->set_font);
|
||||
JGL::J2D::End();
|
||||
|
||||
}
|
||||
|
||||
std::string TextBase::GetContent() const { return content;}
|
||||
|
||||
Color4 TextBase::GetTextColor() const { return text_color;}
|
||||
|
||||
Color4 TextBase::GetOutlineColor() const { return outline_color;}
|
||||
|
||||
TextAlign::H TextBase::GetHorizontalTextAlign() const { return h_align;}
|
||||
|
||||
TextAlign::V TextBase::GetVerticalTextAlign() const {return v_align;}
|
||||
|
||||
Vector2 TextBase::GetTextBounds() const { return GetFont().MeasureString(content, text_size); }
|
||||
|
||||
JGL::Font TextBase::GetFont() const { return set_font;}
|
||||
|
||||
u32 TextBase::GetTextSize() const { return text_size; }
|
||||
|
||||
void TextBase::SetFont(const JGL::Font &font) {
|
||||
set_font = font;
|
||||
}
|
||||
|
||||
TextBase::TextBase() {}
|
||||
|
||||
void TextBase::SetTextSize(u32 size) {
|
||||
text_size = size;
|
||||
}
|
||||
|
||||
void TextBase::Update(float delta) {}
|
||||
void TextBase::SetTextAlign(const TextAlign::H& h_align, const TextAlign::V& v_align) {
|
||||
SetHorizontalTextAlign(h_align);
|
||||
SetVerticalTextAlign(v_align);
|
||||
}
|
||||
|
||||
void TextBase::AlignLeft() { SetHorizontalTextAlign(TextAlign::H::Left); }
|
||||
|
||||
void TextBase::AlignRight() { SetHorizontalTextAlign(TextAlign::H::Right); }
|
||||
|
||||
void TextBase::AlignTop() { SetVerticalTextAlign(TextAlign::V::Top); }
|
||||
|
||||
void TextBase::AlignBottom() { SetVerticalTextAlign(TextAlign::V::Bottom); }
|
||||
|
||||
void TextBase::AlignCenterBoth() {
|
||||
SetVerticalTextAlign(TextAlign::V::Center);
|
||||
SetHorizontalTextAlign(TextAlign::H::Center);
|
||||
}
|
||||
|
||||
void TextBase::Center() { AlignCenterBoth(); }
|
||||
|
||||
void TextBase::AlignCenterHorizontally() {
|
||||
SetHorizontalTextAlign(TextAlign::H::Center);
|
||||
}
|
||||
|
||||
void TextBase::AlignCenterVertically() {
|
||||
SetVerticalTextAlign(TextAlign::V::Center);
|
||||
}
|
||||
|
||||
void TextBase::SetWordWrap(bool wrap) { word_wrap = wrap; }
|
||||
|
||||
void TextBase::Draw(const Vector2& abs_pos, const Vector2& abs_size, const std::string& content, uint size, const Color4& color) {
|
||||
// Calculate how much to origin the text based on alignment.
|
||||
float align_x = abs_pos.x;
|
||||
float align_y = abs_pos.y;
|
||||
|
||||
auto bounds = this->GetFont().MeasureString(content, size);
|
||||
// Do nothing if there is no text.
|
||||
if (bounds.x == 0 || bounds.y == 0)
|
||||
return;
|
||||
|
||||
// Render from left-side of boundary.
|
||||
if (h_align == TextAlign::H::Left)
|
||||
align_x = abs_pos.x;
|
||||
// Render from horizontal center, origin by half of the text's width.
|
||||
if (h_align == TextAlign::H::Center)
|
||||
align_x = abs_pos.x + (abs_size.x / 2) - (bounds.x / 2);
|
||||
// Render from right-side of boundary, origin by text width.
|
||||
if (h_align == TextAlign::H::Right)
|
||||
align_x = abs_pos.x + abs_size.x - bounds.x;
|
||||
// Render from top of boundary.
|
||||
if (v_align == TextAlign::V::Top)
|
||||
align_y = abs_pos.y;
|
||||
// Render from vertical center, origin by half of the text's height.
|
||||
if (v_align == TextAlign::V::Center)
|
||||
align_y = abs_pos.y + (abs_size.y / 2) - (bounds.y / 2);
|
||||
// Render from bottom of boundary, origin by the text's height.
|
||||
if (v_align == TextAlign::V::Bottom)
|
||||
align_y = abs_pos.y + abs_size.y - bounds.y;
|
||||
|
||||
float scale = 1.f;
|
||||
bool use_render_target = false;
|
||||
|
||||
// Has to be checked because this function lets you pass in parameters instead
|
||||
// of using the ones we have saved. Which again, defeats the point. - Redacted.
|
||||
if (content == this->content) {
|
||||
// if Render Target needs updating.
|
||||
if (state_redraw) {
|
||||
text_canvas->Resize({(int) bounds.x, (int) bounds.y});
|
||||
J2D::Begin(text_canvas, true);
|
||||
J2D::DrawString(color, content, 0, 0, scale, size, this->set_font);
|
||||
J2D::End();
|
||||
state_redraw = false;
|
||||
}
|
||||
use_render_target = true;
|
||||
}
|
||||
|
||||
Vector2 text_pos = {align_x, align_y};
|
||||
//J2D::Begin();
|
||||
//J2D::OutlineRect(color, text_pos, bounds); // Draw bounding box for debugging.
|
||||
use_render_target ? J2D::DrawRenderTarget(text_canvas, {align_x, align_y})
|
||||
: J2D::DrawString(color, content, align_x, align_y, scale, size, this->set_font);
|
||||
//J2D::End();
|
||||
}
|
||||
|
||||
void TextBase::Draw(const Vector2& abs_pos, const Vector2& abs_size) {
|
||||
Draw(abs_pos, abs_size, this->content, this->text_size, this->text_color);
|
||||
}
|
||||
|
||||
std::string TextBase::GetContent() const { return content; }
|
||||
|
||||
Color4 TextBase::GetTextColor() const { return text_color; }
|
||||
|
||||
Color4 TextBase::GetOutlineColor() const { return outline_color; }
|
||||
|
||||
TextAlign::H TextBase::GetHorizontalTextAlign() const { return h_align; }
|
||||
|
||||
TextAlign::V TextBase::GetVerticalTextAlign() const { return v_align; }
|
||||
|
||||
Vector2 TextBase::GetTextBounds() { return GetFont().MeasureString(content, text_size); }
|
||||
|
||||
JGL::Font TextBase::GetFont() const { return set_font; }
|
||||
|
||||
u32 TextBase::GetTextSize() const { return text_size; }
|
||||
|
||||
void TextBase::SetFont(const JGL::Font& font) {
|
||||
set_font = font;
|
||||
state_redraw = true;
|
||||
}
|
||||
|
||||
void TextBase::SetTextSize(u32 size) {
|
||||
text_size = size;
|
||||
state_redraw = true;
|
||||
}
|
||||
|
||||
void TextBase::Update(float delta) {}
|
@@ -1,6 +1,6 @@
|
||||
#include "JUI/Base/Widget.hpp"
|
||||
#include <JUI/Base/Widget.hpp>
|
||||
#include <jlog/Logger.hpp>
|
||||
|
||||
#include <J3ML/Geometry/AABB2D.hpp>
|
||||
|
||||
namespace JUI {
|
||||
|
||||
@@ -11,26 +11,26 @@ namespace JUI {
|
||||
|
||||
Widget::Widget(Widget* parent) : Widget()
|
||||
{
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void Widget::SetParent(Widget* parent) {
|
||||
void Widget::Parent(Widget* newParent) {
|
||||
// hold a reference to this so it doesn't get collected as we're working.
|
||||
Widget* oldParent = this->parent;
|
||||
|
||||
// New parent is old parent, do nothing, maybe raise a warning.
|
||||
if (parent == oldParent)
|
||||
if (newParent == oldParent)
|
||||
return;
|
||||
|
||||
// Don't allow for an instance to be parented to itself
|
||||
if (this == parent)
|
||||
if (this == newParent)
|
||||
throw std::runtime_error("Cannot parent a widget to itself.");
|
||||
// You're trying to break the linearity of the object hierarchy by creating a circle in the graph.
|
||||
if (this->IsAncestorOf(parent))
|
||||
if (this->IsAncestorOf(newParent))
|
||||
throw std::runtime_error("Cannot create circular reference.");
|
||||
|
||||
for (Widget* ancestor: this->GetAncestors()) {
|
||||
if (oldParent && !ancestor->IsAncestorOf(parent) && parent != ancestor) {
|
||||
if (oldParent && !ancestor->IsAncestorOf(newParent) && newParent != ancestor) {
|
||||
ancestor->DescendantRemoved(this);
|
||||
for (Widget* descendant : this->GetDescendants()) {
|
||||
ancestor->DescendantRemoved(descendant);
|
||||
@@ -41,21 +41,21 @@ namespace JUI {
|
||||
// Remove ourselves from our parent (if we have one)
|
||||
if (this->parent) {
|
||||
// this->parent->ChildRemoved(this)
|
||||
std::erase(parent->children, this);
|
||||
std::erase(this->parent->children, this);
|
||||
}
|
||||
|
||||
// Update our old parent to the new one
|
||||
this->parent = parent;
|
||||
this->parent = newParent;
|
||||
|
||||
// If our parent is set to nullptr, we can't update it's vector of children
|
||||
if (!parent) return;
|
||||
if (!newParent) return;
|
||||
|
||||
// Add ourselves to our new parent's list of children
|
||||
parent->children.emplace_back(this);
|
||||
newParent->children.emplace_back(this);
|
||||
//newParent->ChildAdded(this);
|
||||
|
||||
for (Widget* ancestor : this->GetAncestors()) {
|
||||
if (!oldParent || (!oldParent->IsDescendantOf(parent) && oldParent != ancestor)) {
|
||||
if (!oldParent || (!oldParent->IsDescendantOf(newParent) && oldParent != ancestor)) {
|
||||
// Don't fire unless an instance is actually a new descendant
|
||||
ancestor->DescendantAdded(this);
|
||||
for (Widget* descendant: this->GetDescendants()) {
|
||||
@@ -88,65 +88,68 @@ namespace JUI {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector2 Widget::GetAnchorPoint() const {
|
||||
Vector2 Widget::AnchorPoint() const {
|
||||
return anchor_point;
|
||||
}
|
||||
|
||||
UDim Widget::GetPaddingLeft() const { return pad_left;}
|
||||
UDim Widget::GetPaddingTop() const { return pad_top;}
|
||||
UDim Widget::GetPaddingRight() const { return pad_right;}
|
||||
UDim Widget::GetPaddingBottom() const { return pad_bottom;}
|
||||
UDim Widget::PaddingLeft() const { return pad_left;}
|
||||
UDim Widget::PaddingTop() const { return pad_top;}
|
||||
UDim Widget::PaddingRight() const { return pad_right;}
|
||||
UDim Widget::PaddingBottom() const { return pad_bottom;}
|
||||
|
||||
void Widget::SetPaddingLeft (const UDim& pl) { pad_left = pl;}
|
||||
void Widget::SetPaddingTop (const UDim& pt) { pad_top = pt;}
|
||||
void Widget::SetPaddingRight (const UDim& pr) { pad_right = pr;}
|
||||
void Widget::SetPaddingBottom(const UDim& pb) { pad_bottom = pb;}
|
||||
void Widget::PaddingLeft (const UDim& pad_left) { this->pad_left = pad_left; }
|
||||
void Widget::PaddingTop (const UDim& pad_top) { this->pad_top = pad_top; }
|
||||
void Widget::PaddingRight (const UDim& pad_right) { this->pad_right = pad_right; }
|
||||
void Widget::PaddingBottom(const UDim& pad_bottom) { this->pad_bottom = pad_bottom; }
|
||||
|
||||
void Widget::SetPadding(const UDim &left, const UDim &top, const UDim &right, const UDim &bottom) {
|
||||
SetPaddingLeft(left);
|
||||
SetPaddingTop(top);
|
||||
SetPaddingRight(right);
|
||||
SetPaddingBottom(bottom);
|
||||
void Widget::Padding(const UDim &left, const UDim &top, const UDim &right, const UDim &bottom) {
|
||||
PaddingLeft(left);
|
||||
PaddingTop(top);
|
||||
PaddingRight(right);
|
||||
PaddingBottom(bottom);
|
||||
}
|
||||
|
||||
void Widget::SetPadding(const UDim &padding) {
|
||||
SetPadding(padding, padding, padding, padding);
|
||||
void Widget::Padding(const UDim &padding) {
|
||||
Padding(padding, padding, padding, padding);
|
||||
}
|
||||
|
||||
UDim Widget::GetMarginLeft () const { return margin_left;}
|
||||
UDim Widget::GetMarginTop () const { return margin_top;}
|
||||
UDim Widget::GetMarginRight () const { return margin_right;}
|
||||
UDim Widget::GetMarginBottom() const { return margin_bottom;}
|
||||
UDim Widget::MarginLeft () const { return margin_left;}
|
||||
UDim Widget::MarginTop () const { return margin_top;}
|
||||
UDim Widget::MarginRight () const { return margin_right;}
|
||||
UDim Widget::MarginBottom() const { return margin_bottom;}
|
||||
|
||||
void Widget::SetMarginLeft(const UDim& ml) { margin_left = ml;}
|
||||
void Widget::SetMarginTop(const UDim& mt) { margin_top = mt;}
|
||||
void Widget::SetMarginRight(const UDim& mr) { margin_right = mr;}
|
||||
void Widget::SetMarginBottom(const UDim& mb) { margin_bottom = mb;}
|
||||
void Widget::MarginLeft(const UDim& ml) { margin_left = ml;}
|
||||
void Widget::MarginTop(const UDim& mt) { margin_top = mt;}
|
||||
void Widget::MarginRight(const UDim& mr) { margin_right = mr;}
|
||||
void Widget::MarginBottom(const UDim& mb) { margin_bottom = mb;}
|
||||
|
||||
void Widget::SetMargin(const UDim &left, const UDim &top, const UDim &right, const UDim &bottom) {
|
||||
SetMarginLeft(left);
|
||||
SetMarginTop(top);
|
||||
SetMarginRight(right);
|
||||
SetMarginBottom(bottom);
|
||||
void Widget::Margin(const UDim &left, const UDim &top, const UDim &right, const UDim &bottom) {
|
||||
MarginLeft(left);
|
||||
MarginTop(top);
|
||||
MarginRight(right);
|
||||
MarginBottom(bottom);
|
||||
}
|
||||
|
||||
void Widget::SetMargin(const UDim &margin) {
|
||||
SetMargin(margin, margin, margin, margin);
|
||||
void Widget::Margin(const UDim &margin) {
|
||||
Margin(margin, margin, margin, margin);
|
||||
}
|
||||
|
||||
std::string Widget::GetName() const { return name; }
|
||||
void Widget::SetName(const std::string& new_name) { name = new_name;}
|
||||
std::string Widget::Name() const { return name; }
|
||||
void Widget::Name(const std::string& new_name) { name = new_name;}
|
||||
|
||||
bool Widget::IsVisible() const { return visible; }
|
||||
void Widget::SetVisible(bool enabled) { visible = enabled;}
|
||||
void Widget::Visible(bool enabled) { visible = enabled;}
|
||||
|
||||
Widget* Widget::GetParent() const { return parent;}
|
||||
Widget* Widget::GetParent() const {
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
UDim2 Widget::Position() const { return position; }
|
||||
void Widget::SetPosition(const UDim2& pos) { position = pos; }
|
||||
void Widget::Position(const UDim2& pos) { position = pos; }
|
||||
|
||||
UDim2 Widget::Size() const { return size;}
|
||||
void Widget::SetSize(const UDim2& s) { size = s; }
|
||||
void Widget::Size(const UDim2& s) { size = s; }
|
||||
|
||||
float Widget::GetAbsoluteRotation() const {
|
||||
// TODO: implement rotation correctly!!
|
||||
@@ -174,9 +177,59 @@ namespace JUI {
|
||||
return ancestors;
|
||||
}
|
||||
|
||||
/*float Widget::GetAbsoluteMarginLeft() {}
|
||||
float Widget::GetAbsoluteMarginRight() {}
|
||||
float Widget::GetAbsoluteMarginTop() {}
|
||||
float Widget::GetAbsoluteMarginBottom() {}
|
||||
float Widget::GetAbsolutePaddingLeft() {}
|
||||
float Widget::GetAbsolutePaddingRight() {}
|
||||
float Widget::GetAbsolutePaddingTop() {}
|
||||
float Widget::GetAbsolutePaddingBottom() {}*/
|
||||
|
||||
|
||||
|
||||
Vector2 Widget::GetAbsolutePaddingTopLeft() const {
|
||||
auto parent_abs_size = this->GetParent()->GetAbsoluteSize();
|
||||
|
||||
UDim padding_h = parent->PaddingLeft();
|
||||
UDim padding_v = parent->PaddingTop();
|
||||
|
||||
float padding_x = padding_h.Pixels + (padding_h.Scale * parent_abs_size.x);
|
||||
float padding_y = padding_v.Pixels + (padding_v.Scale * parent_abs_size.y);
|
||||
|
||||
return {padding_x, padding_y};
|
||||
}
|
||||
|
||||
Vector2 Widget::GetAbsoluteMarginTopLeft()
|
||||
{
|
||||
// TODO: Implement correctly.
|
||||
return {0,0};
|
||||
}
|
||||
|
||||
Vector2 Widget::GetAbsolutePaddingBottomRight() const {
|
||||
UDim padding_h = parent->PaddingLeft() + parent->PaddingRight();
|
||||
float final_pad_x = padding_h.Pixels + (padding_h.Scale * parent->GetAbsoluteSize().x);
|
||||
|
||||
UDim padding_v = parent->PaddingTop() + parent->PaddingBottom();
|
||||
float final_pad_y = padding_v.Pixels + (padding_v.Scale * parent->GetAbsoluteSize().y);
|
||||
|
||||
Vector2 padding = {final_pad_x, final_pad_y};
|
||||
|
||||
return padding;
|
||||
}
|
||||
|
||||
Vector2 Widget::GetAbsoluteMarginBottomRight()
|
||||
{
|
||||
// TODO: Implement correctly.
|
||||
return {0,0};
|
||||
}
|
||||
|
||||
|
||||
Vector2 Widget::GetAbsolutePosition() const {
|
||||
|
||||
if (this->parent == nullptr)
|
||||
return {0,0};
|
||||
|
||||
auto child_pos_scale = this->Position().GetScale();
|
||||
auto child_pos_pixels = this->Position().GetPixels();
|
||||
auto parent_abs_size = this->GetParent()->GetAbsoluteSize();
|
||||
@@ -184,16 +237,9 @@ namespace JUI {
|
||||
|
||||
auto abs_size = GetAbsoluteSize();
|
||||
|
||||
auto anchor_offset = abs_size * GetAnchorPoint();
|
||||
|
||||
UDim padding_h = parent->GetPaddingLeft();
|
||||
UDim padding_v = parent->GetPaddingTop();
|
||||
|
||||
float calculated_padding_x = padding_h.Pixels + (padding_h.Scale * parent_abs_size.x);
|
||||
float calculated_padding_y = padding_v.Pixels + (padding_v.Scale * parent_abs_size.y);
|
||||
|
||||
Vector2 padding_offset = {calculated_padding_x, calculated_padding_y};
|
||||
auto anchor_offset = abs_size * AnchorPoint();
|
||||
|
||||
Vector2 padding_offset = GetAbsolutePaddingTopLeft();
|
||||
|
||||
Vector2 absolute_position =
|
||||
parent_abs_pos + child_pos_pixels + (parent_abs_size * child_pos_scale) + padding_offset;
|
||||
@@ -201,35 +247,30 @@ namespace JUI {
|
||||
return absolute_position - anchor_offset;
|
||||
}
|
||||
|
||||
// TODO: implement padding shrinking abs_size
|
||||
Vector2 Widget::GetAbsoluteSize() const {
|
||||
|
||||
if (this->GetParent() == nullptr)
|
||||
return {0,0};
|
||||
|
||||
Vector2 child_size_scale = this->Size().GetScale();
|
||||
Vector2 child_size_px = this->Size().GetPixels();
|
||||
|
||||
Vector2 parent_abs_size = this->GetParent()->GetAbsoluteSize();
|
||||
|
||||
UDim padding_h = parent->GetPaddingLeft() + parent->GetPaddingRight();
|
||||
float final_pad_x = padding_h.Pixels + (padding_h.Scale * parent->GetAbsoluteSize().x);
|
||||
|
||||
UDim padding_v = parent->GetPaddingTop() + parent->GetPaddingBottom();
|
||||
float final_pad_y = padding_v.Pixels + (padding_v.Scale * parent->GetAbsoluteSize().y);
|
||||
|
||||
Vector2 pad_size_reduction = {final_pad_x, final_pad_y};
|
||||
Vector2 pad_size_reduction = GetAbsolutePaddingBottomRight();
|
||||
|
||||
Vector2 abs_size = child_size_px + (parent_abs_size * child_size_scale) - pad_size_reduction;
|
||||
|
||||
// TODO: Take into account constraints on widgets.
|
||||
return abs_size;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Consider std::optional
|
||||
Widget* Widget::FindFirstChild(const std::string& search_name) {
|
||||
std::optional<Widget*> Widget::FindFirstChild(const std::string& search_name) {
|
||||
for (auto& child : children) {
|
||||
if (child->GetName() == search_name)
|
||||
if (child->Name() == search_name)
|
||||
return child;
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,15 +278,33 @@ namespace JUI {
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
PreDraw();
|
||||
InnerDraw();
|
||||
PostDraw();
|
||||
|
||||
DrawChildWidgets();
|
||||
}
|
||||
|
||||
void Widget::UpdateTweens(float elapsed)
|
||||
{
|
||||
for (Tween& t: tweens)
|
||||
{
|
||||
t.tick(elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::Update(float delta) {
|
||||
|
||||
UpdateChildWidgets(delta);
|
||||
UpdateTweens(delta);
|
||||
}
|
||||
|
||||
struct {
|
||||
bool operator()(Widget* a, Widget* b) const { return a->ZIndex() < b->ZIndex();}
|
||||
} zIndexSort;
|
||||
|
||||
void Widget::DrawChildWidgets() {
|
||||
std::sort(children.begin(), children.end(), zIndexSort);
|
||||
for (auto child : children) {
|
||||
child->Draw();
|
||||
}
|
||||
@@ -297,6 +356,13 @@ namespace JUI {
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::ObserveKeyInput(Key key, bool pressed) {
|
||||
for (Widget* child : children) {
|
||||
child->ObserveKeyInput(key, pressed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Widget::IsAncestorOf(Widget *descendant) const {
|
||||
if (descendant == nullptr)
|
||||
return false;
|
||||
@@ -322,12 +388,33 @@ namespace JUI {
|
||||
}
|
||||
|
||||
Widget *Widget::Add(Widget *newChild) {
|
||||
newChild->SetParent(this);
|
||||
newChild->Parent(this);
|
||||
return newChild;
|
||||
}
|
||||
|
||||
void Widget::SetAnchorPoint(const Vector2& point) {
|
||||
void Widget::AnchorPoint(const Vector2& point) {
|
||||
anchor_point = point;
|
||||
}
|
||||
|
||||
int Widget::ZIndex() const { return zindex;}
|
||||
|
||||
void Widget::ZIndex(int new_zindex) { zindex = new_zindex; }
|
||||
|
||||
AABB2D Widget::GetActualRenderBounds() const {
|
||||
return {GetAbsolutePosition(), GetAbsoluteSize()};
|
||||
}
|
||||
|
||||
void Widget::SetViewportSize(const Vector2 &vps) {
|
||||
viewport_size = vps;
|
||||
|
||||
for(auto& child : children)
|
||||
{
|
||||
child->SetViewportSize(viewport_size);
|
||||
}
|
||||
}
|
||||
|
||||
AABB2D Widget::AbsoluteBounds() const {
|
||||
return {GetAbsolutePosition(), GetAbsoluteSize()};
|
||||
}
|
||||
|
||||
}
|
@@ -1,3 +1,9 @@
|
||||
//
|
||||
// Created by dawsh on 7/10/24.
|
||||
//
|
||||
#include <JUI/JUI.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
std::ofstream GlobalLogFile("latest.log", std::ios_base::app);
|
||||
jlog::GenericLogger UILogs {"JUI", GlobalLogFile, Colors::Green, Colors::Gray, Colors::Gray, Colors::Green, Colors::White};
|
||||
|
||||
|
||||
}
|
||||
|
20
src/JUI/Mixins/Clickable.cpp
Normal file
20
src/JUI/Mixins/Clickable.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <JUI/Mixins/Clickable.hpp>
|
||||
|
||||
void JUI::Clickable::Update(const Vector2 &mpos, const JUI::MouseButton &btn, bool hovering) {
|
||||
|
||||
}
|
||||
|
||||
void JUI::Clickable::OnRelease(const Vector2 &MousePos, const JUI::MouseButton &MouseButton, bool MouseStillOver) {
|
||||
clicked = false;
|
||||
OnReleaseEvent.Invoke(MousePos, MouseButton, MouseStillOver);
|
||||
}
|
||||
|
||||
void JUI::Clickable::OnClick(const Vector2 &MousePos, const JUI::MouseButton &MouseButton) {
|
||||
|
||||
clicked = true;
|
||||
OnClickEvent.Invoke(MousePos, MouseButton);
|
||||
}
|
||||
|
||||
void JUI::Clickable::SetClicked(bool manual_click) {
|
||||
clicked = manual_click;
|
||||
}
|
1
src/JUI/Mixins/Dockable.cpp
Normal file
1
src/JUI/Mixins/Dockable.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include <JUI/Mixins/Dockable.hpp>
|
1
src/JUI/Mixins/Draggable.cpp
Normal file
1
src/JUI/Mixins/Draggable.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include <JUI/Mixins/Draggable.hpp>
|
37
src/JUI/Mixins/Hoverable.cpp
Normal file
37
src/JUI/Mixins/Hoverable.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <JUI/Mixins/Hoverable.hpp>
|
||||
|
||||
void JUI::Hoverable::OnHover(const Vector2 &MousePos) {
|
||||
OnHoverEvent.Invoke(MousePos);
|
||||
}
|
||||
|
||||
void JUI::Hoverable::OnExit(const Vector2 &MousePos) {
|
||||
OnExitEvent.Invoke(MousePos);
|
||||
|
||||
//tooltip_threshold = 0;
|
||||
}
|
||||
|
||||
void JUI::Hoverable::Update(const Vector2 &m_pos, float delta) {
|
||||
|
||||
/*if (tooltip != nullptr)
|
||||
{
|
||||
if (IsHovered()) {
|
||||
tooltip->Visible(true);
|
||||
tooltip->Position(UDim2::FromPixels(m_pos.x, m_pos.y));
|
||||
} else {
|
||||
tooltip->Visible(false);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
if (IsHovered() && !hover_debounce) {
|
||||
OnHover(m_pos);
|
||||
hover_debounce = true;
|
||||
}
|
||||
|
||||
if (!IsHovered() && hover_debounce) {
|
||||
OnExit(m_pos);
|
||||
hover_debounce = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
15
src/JUI/Mixins/Resizable.cpp
Normal file
15
src/JUI/Mixins/Resizable.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <JUI/Mixins/Resizable.hpp>
|
||||
|
||||
void JUI::Resizable::SetResize(bool b) {
|
||||
this->resizing = b;
|
||||
}
|
||||
|
||||
void JUI::Resizable::StartResizing(const Vector2 &point) {
|
||||
initial_resize_offset = point;
|
||||
}
|
||||
|
||||
void JUI::Resizable::StopResizing() {}
|
||||
|
||||
void JUI::Resizable::Update(float delta) {}
|
||||
|
||||
bool JUI::Resizable::Resizing() const { return resizing; }
|
20
src/JUI/Mixins/Toggleable.cpp
Normal file
20
src/JUI/Mixins/Toggleable.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <JUI/Mixins/Toggleable.hpp>
|
||||
|
||||
void JUI::Toggleable::OnToggleOn() {
|
||||
OnToggleOnEvent.Invoke();
|
||||
}
|
||||
|
||||
void JUI::Toggleable::OnToggleOff() {
|
||||
OnToggleOffEvent.Invoke();
|
||||
}
|
||||
|
||||
void JUI::Toggleable::Update() {
|
||||
OnToggleEvent.Invoke();
|
||||
toggled = !toggled;
|
||||
|
||||
if (toggled) {
|
||||
OnToggleOn();
|
||||
} else {
|
||||
OnToggleOff();
|
||||
}
|
||||
}
|
151
src/JUI/Tween.cpp
Normal file
151
src/JUI/Tween.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <JUI/Tween.hpp>
|
||||
#include <J3ML/J3ML.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
using namespace J3ML;
|
||||
|
||||
float EasingFunctions::EaseInSine(float t) { return Math::Sin(Math::PiOverTwo * t); }
|
||||
|
||||
float EasingFunctions::EaseOutSine(float t) { return 1 + Math::Sin(Math::PiOverTwo * (--t)); }
|
||||
|
||||
float EasingFunctions::EaseInOutSine(float t) { return 0.5f * (1 + Math::Sin(Math::Pi * (t - 0.5f))); }
|
||||
|
||||
float EasingFunctions::EaseInQuad(float t) { return t * t;}
|
||||
|
||||
float EasingFunctions::EaseOutQuad(float t) { return t * (2.f - t);}
|
||||
|
||||
float EasingFunctions::EaseInOutQuad(float t) { return t < 0.5f ? 2.f * t * t : t * (4.f - 2.f * t) - 1; }
|
||||
|
||||
float EasingFunctions::EaseInCubic(float t) { return t * t * t;}
|
||||
|
||||
float EasingFunctions::EaseOutCubic(float t) { return 1.f + (--t) * t * t; }
|
||||
|
||||
float EasingFunctions::EaseInOutCubic(float t) { return t < 0.5f ? 4.f * t * t * t : 1 + (--t) * (2 * (--t)) * (2 * t); }
|
||||
|
||||
float EasingFunctions::EaseInQuart(float t) {
|
||||
t *= t;
|
||||
return t * t;
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseOutQuart(float t) {
|
||||
t = (--t) * t;
|
||||
return 1.f - t * t;
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInOutQuart(float t) {
|
||||
if (t < 0.5f) {
|
||||
t *= t;
|
||||
return 8 * t * t;
|
||||
} else {
|
||||
t = (--t) * t;
|
||||
return 1 - 8 * t * t;
|
||||
}
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInQuint(float t) {
|
||||
float t2 = t * t;
|
||||
return t * t2 * t2;
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseOutQuint(float t) {
|
||||
float t2 = (--t) * t;
|
||||
return 1 + t * t2 * t2;
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInOutQuint(float t) {
|
||||
float t2;
|
||||
if ( t < 0.5f) {
|
||||
t2 = t * t;
|
||||
return 16 * t * t2 * t2;
|
||||
} else {
|
||||
t2 = (--t) * t;
|
||||
return 1 + 16 * t * t2 * t2;
|
||||
}
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInExpo(float t) {
|
||||
return (Math::Pow(2, 8*t) - 1) / 255;
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseOutExpo(float t) {
|
||||
return 1 - Math::Pow(2, -8*t);
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInOutExpo(float t) {
|
||||
if (t < 0.5f) {
|
||||
return (Math::Pow(2, 16 * t) - 1) / 510;
|
||||
} else {
|
||||
return 1 - 0.5f * Math::Pow(2, -16 * (t - 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInCirc(float t) {
|
||||
return 1 - Math::Sqrt(1 - t);
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseOutCirc(float t) {
|
||||
return Math::Sqrt(t);
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInOutCirc(float t) {
|
||||
if (t < 0.5f) {
|
||||
return (1 - Math::Sqrt(1 - 2 * t)) * 0.5f;
|
||||
} else {
|
||||
return (1 + Math::Sqrt(2 * t - 1)) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInBack(float t) { return t * t * (2.70158f * t - 1.70158f); }
|
||||
|
||||
float EasingFunctions::EaseOutBack(float t) { return 1 + (--t) * t * (2.70158 * t + 1.70158); }
|
||||
|
||||
float EasingFunctions::EaseInOutBack(float t) {
|
||||
if (t < 0.5f) {
|
||||
return t * t * (7 * t - 2.5f) * 2.f;
|
||||
} else {
|
||||
return 1 + (--t) * t * 2 * (7 * t + 2.5f);
|
||||
}
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInElastic(float t) {
|
||||
float t2 = t * t;
|
||||
return t2 * t2 * Math::Sin(t * Math::Pi * 4.5f);
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseOutElastic(float t) {
|
||||
float t2 = (t - 1) * (t - 1);
|
||||
return 1 - t2 * t2 * Math::Cos(t * Math::Pi * 4.5f);
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInOutElastic(float t) {
|
||||
float t2;
|
||||
if (t < 0.45f) {
|
||||
t2 = t * t;
|
||||
return 8 * t2 * t2 * Math::Sin(t * Math::Pi * 9);
|
||||
} else if (t < 0.55f) {
|
||||
return 0.5f + 0.75f * Math::Sin(t * Math::Pi * 4);
|
||||
} else {
|
||||
t2 = (t - 1) * (t - 1);
|
||||
return 1 - 8 * t2 * t2 * Math::Sin(t * Math::Pi * 9);
|
||||
}
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInBounce(float t) {
|
||||
return Math::Pow(2, 6 * (t - 1)) * Math::Abs(Math::Sin(t * Math::Pi * 3.5f));
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseOutBounce(float t) {
|
||||
return 1 - Math::Pow(2, -6 * t ) * Math::Abs(Math::Cos(t * Math::Pi * 3.5f));
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInOutBounce(float t) {
|
||||
if (t < 0.5f) {
|
||||
return 8 * Math::Pow(2, 8 * (t - 1)) * Math::Abs(Math::Sin(t * Math::Pi));
|
||||
} else {
|
||||
return 1 - 8 * Math::Pow(2, -8 * t) * Math::Abs(Math::Sin(t * Math::Pi * 7));
|
||||
}
|
||||
}
|
||||
|
||||
float EasingFunctions::EaseInOutLinear(float t) { return t;}
|
||||
}
|
@@ -4,64 +4,54 @@
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
Button::Button(): Widget() {}
|
||||
|
||||
Button::Button(Widget *parent): Clickable() {
|
||||
this->SetParent(parent);
|
||||
};
|
||||
|
||||
void Button::Draw() {
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
J2D::Begin();
|
||||
Vector2 abs_pos = GetAbsolutePosition();
|
||||
Vector2 abs_size = GetAbsoluteSize();
|
||||
|
||||
auto root_size = GetFamilyTreeRoot()->GetAbsoluteSize();
|
||||
|
||||
GLint *old_scissor_bounds;
|
||||
bool clip_was_enabled;
|
||||
// TODO: Re-enable clipping
|
||||
if (clips_descendants) {
|
||||
clip_was_enabled = glIsEnabled(GL_SCISSOR_TEST);
|
||||
if (clip_was_enabled)
|
||||
glGetIntegerv(GL_SCISSOR_BOX, old_scissor_bounds);
|
||||
|
||||
float presumed_screen_height = 600;
|
||||
glScissor(abs_pos.x, presumed_screen_height-abs_size.y-abs_pos.y, abs_size.x, abs_size.y);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
RectBase::Draw(abs_pos, abs_size);
|
||||
|
||||
// Draw Child Elements with scissor clipping still active
|
||||
Widget::Draw();
|
||||
|
||||
// Returns clip to previous state
|
||||
if (clips_descendants)
|
||||
{
|
||||
//glScissor(old_scissor_bounds[0], old_scissor_bounds[1], old_scissor_bounds[2], old_scissor_bounds[3]);
|
||||
|
||||
if (!clip_was_enabled) {}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
}
|
||||
|
||||
J2D::End();
|
||||
Button::Button(): Rect(), Clickable() {
|
||||
BGColor(BaseBGColor());
|
||||
BorderColor(BaseBorderColor());
|
||||
}
|
||||
|
||||
Button::Button(Widget *parent): Button() {
|
||||
this->Parent(parent);
|
||||
};
|
||||
|
||||
void Button::OnClick(const Vector2& mouse_pos, const MouseButton& btn)
|
||||
{
|
||||
if (disabled)
|
||||
return;
|
||||
|
||||
Clickable::OnClick(mouse_pos, btn);
|
||||
clicked = true;
|
||||
|
||||
//BGColor(PressedBGColor());
|
||||
//BorderColor(PressedBorderColor());
|
||||
}
|
||||
|
||||
void Button::OnRelease(const J3ML::LinearAlgebra::Vector2 &mouse_pos, const JUI::MouseButton &btn,
|
||||
bool still_hovering) {
|
||||
|
||||
if (disabled)
|
||||
return;
|
||||
|
||||
Clickable::OnRelease(mouse_pos, btn, still_hovering);
|
||||
clicked = false;
|
||||
|
||||
//BGColor(BaseBGColor());
|
||||
//BorderColor(BaseBorderColor());
|
||||
}
|
||||
|
||||
void Button::UpdateVisualState()
|
||||
{
|
||||
|
||||
if (Disabled()) {
|
||||
BGColor(DisabledBGColor());
|
||||
BorderColor(DisabledBorderColor());
|
||||
} else if (IsClicked()) {
|
||||
BGColor(PressedBGColor());
|
||||
BorderColor(PressedBorderColor());
|
||||
} else if (IsHovered()) {
|
||||
BGColor(HoveredBGColor());
|
||||
BorderColor(HoveredBorderColor());
|
||||
} else {
|
||||
BGColor(BaseBGColor());
|
||||
BorderColor(BaseBorderColor());
|
||||
}
|
||||
}
|
||||
|
||||
void Button::Update(float delta) {
|
||||
@@ -81,23 +71,124 @@ namespace JUI
|
||||
OnRelease(last_known_mouse_pos, mbtn, IsHovered());
|
||||
}
|
||||
|
||||
|
||||
UpdateVisualState();
|
||||
|
||||
prev_mb_state = mb_state;
|
||||
|
||||
Rect::Update(delta);
|
||||
}
|
||||
|
||||
TextButton::TextButton() : Button(), TextBase() {}
|
||||
TextButton::TextButton(Widget* parent) : TextButton() {
|
||||
this->SetParent(parent);
|
||||
void Button::Enable() {
|
||||
SetEnabled(true);
|
||||
}
|
||||
|
||||
void TextButton::Update(float delta) {
|
||||
Button::Update(delta);
|
||||
TextBase::Update(delta);
|
||||
void Button::Disable() {
|
||||
SetEnabled(false);
|
||||
}
|
||||
|
||||
void TextButton::Draw() {
|
||||
Button::Draw();
|
||||
TextBase::Draw(this->GetAbsolutePosition(), this->GetAbsoluteSize());
|
||||
bool Button::Enabled() const {
|
||||
return !disabled;
|
||||
}
|
||||
|
||||
bool Button::Disabled() const {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
void Button::SetEnabled(bool enabled) {
|
||||
|
||||
// if state actually changed
|
||||
if (disabled != enabled)
|
||||
return;
|
||||
|
||||
if (disabled)
|
||||
OnDisabled.Invoke();
|
||||
else
|
||||
OnEnabled.Invoke();
|
||||
|
||||
disabled = !enabled;
|
||||
|
||||
BGColor(DisabledBGColor());
|
||||
BorderColor(DisabledBorderColor());
|
||||
}
|
||||
|
||||
void Button::OnHover(const Vector2 &MousePos) {
|
||||
Hoverable::OnHover(MousePos);
|
||||
|
||||
if (Disabled() || IsClicked())
|
||||
return;
|
||||
|
||||
//BGColor(HoveredBGColor());
|
||||
//BorderColor(HoveredBorderColor());
|
||||
}
|
||||
|
||||
void Button::OnExit(const Vector2 &MousePos) {
|
||||
Hoverable::OnExit(MousePos);
|
||||
|
||||
if (Disabled() || IsClicked())
|
||||
return;
|
||||
|
||||
//BGColor(BaseBGColor());
|
||||
//BorderColor(BaseBorderColor());
|
||||
}
|
||||
|
||||
Color4 Button::HoveredBGColor() const { return hover_bg; }
|
||||
|
||||
Color4 Button::BaseBGColor() const { return base_bg; }
|
||||
|
||||
Color4 Button::PressedBGColor() const { return pressed_bg; }
|
||||
|
||||
Color4 Button::DisabledBGColor() const { return disabled_bg;}
|
||||
|
||||
Color4 Button::HoveredBorderColor() const { return hover_border;}
|
||||
|
||||
Color4 Button::BaseBorderColor() const { return base_border;}
|
||||
|
||||
Color4 Button::PressedBorderColor() const { return pressed_border;}
|
||||
|
||||
Color4 Button::DisabledBorderColor() const { return disabled_border;}
|
||||
|
||||
void Button::HoveredBGColor(const Color4 &color) { hover_bg = color;}
|
||||
|
||||
void Button::BaseBGColor(const Color4 &color) { base_bg = color;}
|
||||
|
||||
void Button::PressedBGColor(const Color4 &color) { pressed_bg = color;}
|
||||
|
||||
void Button::DisabledBGColor(const Color4 &color) { disabled_bg = color;}
|
||||
|
||||
void Button::HoveredBorderColor(const Color4 &color) { hover_border = color;}
|
||||
|
||||
void Button::BaseBorderColor(const Color4 &color) {base_border = color; }
|
||||
|
||||
void Button::PressedBorderColor(const Color4 &color) { pressed_border = color;}
|
||||
|
||||
void Button::DisabledBorderColor(const Color4 &color) { disabled_border = color; }
|
||||
|
||||
void Button::BorderColors(const Color4 &base, const Color4 &hover, const Color4 &pressed, const Color4 &disabled) {
|
||||
BaseBorderColor(base);
|
||||
HoveredBorderColor(hover);
|
||||
PressedBorderColor(pressed);
|
||||
DisabledBGColor(disabled);
|
||||
|
||||
UpdateVisualState();
|
||||
}
|
||||
|
||||
void Button::BGColors(const Color4 &base, const Color4 &hover, const Color4 &pressed, const Color4 &disabled) {
|
||||
BaseBGColor(base);
|
||||
HoveredBGColor(hover);
|
||||
PressedBGColor(pressed);
|
||||
DisabledBGColor(disabled);
|
||||
|
||||
UpdateVisualState();
|
||||
}
|
||||
|
||||
//void Button::SetTooltip(const std::string &content, float delay) {
|
||||
//tooltip_limit = delay;
|
||||
// TODO: Verify this is okay to do:
|
||||
//tooltip = new Tooltip(this);
|
||||
//tooltip->SetContent(content);
|
||||
//tooltip->ZIndex(5);
|
||||
//tooltip->Visible(false);
|
||||
//}
|
||||
|
||||
|
||||
}
|
8
src/JUI/Widgets/Checkbox.cpp
Normal file
8
src/JUI/Widgets/Checkbox.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <JUI/Widgets/Checkbox.hpp>
|
||||
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
|
||||
}
|
@@ -9,12 +9,12 @@ namespace JUI
|
||||
|
||||
Image::Image(Widget* parent) : Image()
|
||||
{
|
||||
SetParent(parent);
|
||||
Parent(parent);
|
||||
}
|
||||
|
||||
Image::Image(Widget *parent, JGL::Texture *tex) : Widget(), ImageBase(tex)
|
||||
{
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
Vector2 Image::GetAbsoluteSize() const {
|
||||
@@ -31,7 +31,7 @@ namespace JUI
|
||||
if (fit_image_to_parent)
|
||||
{
|
||||
auto old_scale = scale;
|
||||
scale = GetAbsoluteSize() / texture->GetDimensions();
|
||||
scale = GetAbsoluteSize() / Vector2(texture->GetDimensions());
|
||||
ImageBase::Draw(GetAbsolutePosition(), GetAbsoluteSize());
|
||||
scale = old_scale;
|
||||
} else
|
||||
|
10
src/JUI/Widgets/ImageButton.cpp
Normal file
10
src/JUI/Widgets/ImageButton.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <JUI/Widgets/ImageButton.hpp>
|
||||
|
||||
void JUI::ImageButton::Update(float delta) {
|
||||
Button::Update(delta);
|
||||
}
|
||||
|
||||
void JUI::ImageButton::Draw() {
|
||||
Button::Draw();
|
||||
ImageBase::Draw(GetAbsolutePosition()+GetAbsolutePaddingTopLeft(), GetAbsoluteSize()-GetAbsolutePaddingBottomRight());
|
||||
}
|
2
src/JUI/Widgets/ImageRect.cpp
Normal file
2
src/JUI/Widgets/ImageRect.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#include <JUI/Widgets/ImageRect.hpp>
|
||||
|
@@ -8,13 +8,86 @@ namespace JUI
|
||||
VerticalListLayout::VerticalListLayout() : ListLayout() {}
|
||||
VerticalListLayout::VerticalListLayout(Widget* parent) : VerticalListLayout()
|
||||
{
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void VerticalListLayout::ApplyLayout() {
|
||||
|
||||
if (layout == LayoutOrder::V::TOP)
|
||||
{
|
||||
int consumed_height = 0;
|
||||
for (auto& child_widget : children)
|
||||
{
|
||||
// TODO: Implement widget.LayoutOrder property
|
||||
// TODO: Sort children by LayoutOrder
|
||||
consumed_height += pad_top.Pixels;
|
||||
child_widget->Position({0, consumed_height, 0, 0});
|
||||
consumed_height += child_widget->GetAbsoluteSize().y;
|
||||
consumed_height += pad_bottom.Pixels;
|
||||
}
|
||||
}
|
||||
|
||||
if (layout == LayoutOrder::V::BOTTOM)
|
||||
{
|
||||
int consumed_height = this->GetAbsoluteSize().y;
|
||||
for (auto& child_widget : children)
|
||||
{
|
||||
// TODO: Implement widget.LayoutOrder property
|
||||
// TODO: Sort children by LayoutOrder
|
||||
consumed_height -= pad_top.Pixels;
|
||||
consumed_height -= child_widget->GetAbsoluteSize().y;
|
||||
child_widget->Position({0, consumed_height, 0, 0});
|
||||
consumed_height -= pad_bottom.Pixels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VerticalListLayout::LayoutOrder(LayoutOrder::V order) {
|
||||
layout = order;
|
||||
}
|
||||
|
||||
LayoutOrder::V VerticalListLayout::LayoutOrder() const { return layout;}
|
||||
|
||||
HorizontalListLayout::HorizontalListLayout() : ListLayout() {}
|
||||
|
||||
|
||||
HorizontalListLayout::HorizontalListLayout(Widget* parent) : HorizontalListLayout() {
|
||||
SetParent(parent);
|
||||
Parent(parent);
|
||||
}
|
||||
|
||||
void HorizontalListLayout::ApplyLayout() {
|
||||
// TODO: Implement widget.LayoutOrder and sort by that number.
|
||||
|
||||
if (layout == LayoutOrder::H::LEFT)
|
||||
{
|
||||
int consumed_width = 0;
|
||||
for (auto &child_widget : children)
|
||||
{
|
||||
consumed_width += pad_left.Pixels;
|
||||
child_widget->Position({consumed_width, 0, 0, 0});
|
||||
consumed_width += child_widget->GetAbsoluteSize().x;
|
||||
consumed_width += pad_right.Pixels;
|
||||
}
|
||||
}
|
||||
|
||||
if (layout == LayoutOrder::H::RIGHT)
|
||||
{
|
||||
int consumed_width = this->GetAbsoluteSize().x;
|
||||
for (auto &child_widget : children)
|
||||
{
|
||||
consumed_width -= pad_left.Pixels;
|
||||
consumed_width -= child_widget->GetAbsoluteSize().x;
|
||||
child_widget->Position({consumed_width, 0, 0, 0});
|
||||
consumed_width -= pad_right.Pixels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HorizontalListLayout::LayoutOrder(LayoutOrder::H order) {
|
||||
layout = order;
|
||||
}
|
||||
|
||||
LayoutOrder::H HorizontalListLayout::LayoutOrder() const {
|
||||
return layout;
|
||||
}
|
||||
}
|
121
src/JUI/Widgets/NineSlice.cpp
Normal file
121
src/JUI/Widgets/NineSlice.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include <JUI/Widgets/NineSlice.hpp>
|
||||
#include <JGL/JGL.h>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
AABB2D JUI::NineSliceRect::TopLeftQuad() const { return top_left_quad; }
|
||||
|
||||
AABB2D NineSliceRect::TopRightQuad() const { return top_right_quad; }
|
||||
|
||||
AABB2D NineSliceRect::BottomLeftQuad() const { return bottom_left_quad; }
|
||||
|
||||
AABB2D NineSliceRect::BottomRightQuad() const { return bottom_right_quad; }
|
||||
|
||||
AABB2D NineSliceRect::TopQuad() const { return top_quad; }
|
||||
|
||||
AABB2D NineSliceRect::LeftQuad() const { return left_quad; }
|
||||
|
||||
AABB2D NineSliceRect::RightQuad() const { return right_quad; }
|
||||
|
||||
AABB2D NineSliceRect::BottomQuad() const { return bottom_quad; }
|
||||
|
||||
AABB2D NineSliceRect::CenterQuad() const { return center_quad; }
|
||||
|
||||
void NineSliceRect::TopLeftQuad(const AABB2D &quad) { top_left_quad = quad; }
|
||||
|
||||
void NineSliceRect::TopRightQuad(const AABB2D &quad) { top_right_quad = quad; }
|
||||
|
||||
void NineSliceRect::BottomLeftQuad(const AABB2D &quad) { bottom_left_quad = quad; }
|
||||
|
||||
void NineSliceRect::BottomRightQuad(const AABB2D &quad) { bottom_right_quad = quad; }
|
||||
|
||||
void NineSliceRect::TopQuad(const AABB2D &quad) { top_quad = quad;}
|
||||
|
||||
void NineSliceRect::RightQuad(const AABB2D &quad) { right_quad = quad;}
|
||||
|
||||
void NineSliceRect::BottomQuad(const AABB2D &quad) { bottom_quad = quad;}
|
||||
|
||||
void NineSliceRect::LeftQuad(const AABB2D &quad) { left_quad = quad;}
|
||||
|
||||
void NineSliceRect::CenterQuad(const AABB2D &quad) { center_quad = quad;}
|
||||
|
||||
void NineSliceRect::Draw() {
|
||||
Rect::Draw();
|
||||
|
||||
//JGL::J2D::Begin();
|
||||
|
||||
Vector2 abs_pos = GetAbsolutePosition();
|
||||
|
||||
Vector2 abs_size = GetAbsoluteSize();
|
||||
|
||||
// Draw Top-Left Quad.
|
||||
Vector2 tl_computed_pos = abs_pos;
|
||||
auto tl_quad = TopLeftQuad();
|
||||
JGL::J2D::DrawPartialSprite(texture, tl_computed_pos, tl_quad.minPoint, tl_quad.maxPoint);
|
||||
|
||||
// Draw Top-Right Quad.
|
||||
auto tr_quad = TopRightQuad();
|
||||
Vector2 tr_computed_pos = abs_pos + Vector2(abs_size.x - tr_quad.maxPoint.x, 0);
|
||||
JGL::J2D::DrawPartialSprite(texture, tr_computed_pos, tr_quad.minPoint, tr_quad.maxPoint);
|
||||
|
||||
|
||||
// Draw Bottom Left Quad
|
||||
auto bl_quad = BottomLeftQuad();
|
||||
Vector2 bl_computed_pos = abs_pos + Vector2(0, abs_size.y - bl_quad.maxPoint.y);
|
||||
JGL::J2D::DrawPartialSprite(texture, bl_computed_pos, bl_quad.minPoint, bl_quad.maxPoint);
|
||||
|
||||
// Draw Bottom Right Quad
|
||||
auto br_quad = BottomRightQuad();
|
||||
Vector2 br_computed_pos = abs_pos + abs_size - br_quad.maxPoint;
|
||||
JGL::J2D::DrawPartialSprite(texture, br_computed_pos, br_quad.minPoint, br_quad.maxPoint);
|
||||
|
||||
|
||||
|
||||
// Draw Top-Quad.
|
||||
Vector2 t_computed_pos = abs_pos + Vector2(tl_quad.maxPoint.x, 0);
|
||||
auto t_quad = TopQuad();
|
||||
float abs_width_minus_corners = abs_size.x - (tl_quad.maxPoint.x + tr_quad.maxPoint.x);
|
||||
float t_scaling = abs_width_minus_corners / t_quad.maxPoint.x;
|
||||
JGL::J2D::DrawPartialSprite(texture, t_computed_pos, t_quad.minPoint, t_quad.maxPoint, 0, {0,0}, {t_scaling, 1});
|
||||
|
||||
// Draw Bottom Quad
|
||||
auto b_quad = BottomQuad();
|
||||
Vector2 b_computed_pos = abs_pos + Vector2(tl_quad.maxPoint.x, abs_size.y - b_quad.maxPoint.y);
|
||||
float b_scaling = abs_width_minus_corners / b_quad.maxPoint.x;
|
||||
JGL::J2D::DrawPartialSprite(texture, b_computed_pos, b_quad.minPoint, b_quad.maxPoint, 0, {0,0}, {b_scaling, 1});
|
||||
|
||||
// Draw Left Quad
|
||||
Vector2 l_computed_pos = abs_pos + Vector2(0, tl_quad.maxPoint.y);
|
||||
auto l_quad = LeftQuad();
|
||||
float abs_height_minus_corners = abs_size.y - (tl_quad.maxPoint.y + tr_quad.maxPoint.y);
|
||||
float l_scaling = abs_height_minus_corners / l_quad.maxPoint.y;
|
||||
JGL::J2D::DrawPartialSprite(texture, l_computed_pos, l_quad.minPoint, l_quad.maxPoint, 0, {0, 0}, {1, l_scaling});
|
||||
|
||||
|
||||
// Draw Right Quad
|
||||
auto r_quad = RightQuad();
|
||||
Vector2 r_computed_pos = abs_pos + Vector2(abs_size.x - tr_quad.maxPoint.x, tr_quad.maxPoint.y);
|
||||
float r_scaling = abs_height_minus_corners / r_quad.maxPoint.y;
|
||||
|
||||
JGL::J2D::DrawPartialSprite(texture, r_computed_pos, r_quad.minPoint, r_quad.maxPoint, 0, {0,0}, {1, r_scaling});
|
||||
|
||||
// Draw Center Quad
|
||||
|
||||
auto c_quad = CenterQuad();
|
||||
Vector2 c_computed_pos = abs_pos + tl_quad.maxPoint;
|
||||
Vector2 c_scaling = Vector2(abs_width_minus_corners, abs_height_minus_corners) / c_quad.maxPoint;
|
||||
|
||||
JGL::J2D::DrawPartialSprite(texture, c_computed_pos, c_quad.minPoint, c_quad.maxPoint, 0, {0,0}, c_scaling);
|
||||
|
||||
|
||||
//JGL::J2D::End();
|
||||
}
|
||||
|
||||
NineSliceRect::NineSliceRect() : Rect(), ImageBase() {}
|
||||
|
||||
NineSliceRect::NineSliceRect(Widget *parent) : Rect(parent), ImageBase() {}
|
||||
|
||||
NineSliceRect::NineSliceRect(Widget *parent, JGL::Texture *texture) : Rect(parent), ImageBase(texture) {}
|
||||
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#include <JUI/Mixins/Toggleable.hpp>
|
||||
#include <JUI/Widgets/RadioButton.hpp>
|
||||
|
||||
namespace JUI
|
||||
@@ -5,7 +6,7 @@ namespace JUI
|
||||
|
||||
RadioButton::RadioButton() : Button(), Toggleable() {}
|
||||
RadioButton::RadioButton(Widget* parent) : RadioButton() {
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,56 +1,55 @@
|
||||
#include "JGL/JGL.h"
|
||||
#include "JUI/Widgets/Rect.hpp"
|
||||
#include <JGL/JGL.h>
|
||||
#include <JUI/Widgets/Rect.hpp>
|
||||
#include <jlog/Logger.hpp>
|
||||
|
||||
namespace JUI {
|
||||
Rect::Rect(): Widget(), RectBase() {}
|
||||
|
||||
Rect::Rect(Widget *parent): Rect() {
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void Rect::Draw() {
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
J2D::Begin();
|
||||
|
||||
void Rect::PreDraw()
|
||||
{
|
||||
Vector2 abs_pos = GetAbsolutePosition();
|
||||
Vector2 abs_size = GetAbsoluteSize();
|
||||
|
||||
auto root_size = GetFamilyTreeRoot()->GetAbsoluteSize();
|
||||
|
||||
GLint *old_scissor_bounds;
|
||||
bool clip_was_enabled;
|
||||
// TODO: Re-enable clipping
|
||||
if (clips_descendants) {
|
||||
clip_was_enabled = glIsEnabled(GL_SCISSOR_TEST);
|
||||
if (clip_was_enabled)
|
||||
glGetIntegerv(GL_SCISSOR_BOX, old_scissor_bounds);
|
||||
|
||||
float presumed_screen_height = 600;
|
||||
|
||||
float presumed_screen_height = viewport_size.y;
|
||||
glScissor(abs_pos.x, presumed_screen_height-abs_size.y-abs_pos.y, abs_size.x, abs_size.y);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RectBase::Draw(abs_pos, abs_size);
|
||||
|
||||
// Draw Child Elements with scissor clipping still active
|
||||
Widget::Draw();
|
||||
|
||||
void Rect::PostDraw()
|
||||
{
|
||||
// Returns clip to previous state
|
||||
if (clips_descendants)
|
||||
{
|
||||
//glScissor(old_scissor_bounds[0], old_scissor_bounds[1], old_scissor_bounds[2], old_scissor_bounds[3]);
|
||||
glScissor(old_scissor_bounds[0], old_scissor_bounds[1], old_scissor_bounds[2], old_scissor_bounds[3]);
|
||||
|
||||
if (!clip_was_enabled) {}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
}
|
||||
|
||||
J2D::End();
|
||||
}
|
||||
|
||||
void Rect::InnerDraw()
|
||||
{
|
||||
//J2D::Begin();
|
||||
RectBase::Draw(GetAbsolutePosition(), GetAbsoluteSize());
|
||||
//J2D::End();
|
||||
// Draw Child Elements with scissor clipping still active
|
||||
//Widget::DrawChildWidgets();
|
||||
}
|
||||
|
||||
void Rect::Update(float delta) {
|
||||
if (IsMouseInside() && !mouse_inside_debounce)
|
||||
@@ -68,18 +67,24 @@ namespace JUI {
|
||||
Widget::Update(delta);
|
||||
}
|
||||
|
||||
bool Rect::IsMouseInside() const {
|
||||
float x = last_known_mouse_pos.x;
|
||||
float y = last_known_mouse_pos.y;
|
||||
auto pos = GetAbsolutePosition();
|
||||
auto size = GetAbsoluteSize();
|
||||
AABB2D Rect::GetActualRenderBounds() const {
|
||||
|
||||
//DEBUG(std::format("X {} {} Y {} {}", x,pos.x, y,pos.y));
|
||||
Vector2 border = {border_width, border_width};
|
||||
|
||||
if (x > pos.x && y > pos.y && x < pos.x + size.x && y < pos.y + size.y){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (border_mode == BorderMode::Inset)
|
||||
return { GetAbsolutePosition(), GetAbsoluteSize()};
|
||||
|
||||
if (border_mode == BorderMode::Outline)
|
||||
return {GetAbsolutePosition() - border, GetAbsoluteSize() + border};
|
||||
|
||||
if (border_mode == BorderMode::Middle)
|
||||
return { GetAbsolutePosition() - (border/2), GetAbsoluteSize() + (border/2)};
|
||||
|
||||
return { GetAbsolutePosition(), GetAbsoluteSize()};
|
||||
}
|
||||
|
||||
void Rect::Draw() {
|
||||
Widget::Draw();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,15 +5,12 @@ namespace JUI {
|
||||
|
||||
Vector2 Scene::GetAbsolutePosition() const { return {0,0};}
|
||||
|
||||
Vector2 Scene::GetAbsoluteSize() const { return {(float)viewport_w,(float)viewport_h};}
|
||||
Vector2 Scene::GetAbsoluteSize() const { return viewport_size;}
|
||||
|
||||
void Scene::Draw() {
|
||||
Widget::Draw();
|
||||
}
|
||||
|
||||
void Scene::SetViewportSize(int w, int h) {
|
||||
viewport_w = w;
|
||||
viewport_h = h;
|
||||
J2D::Begin();
|
||||
Widget::Draw();
|
||||
J2D::End();
|
||||
}
|
||||
|
||||
void Scene::Update(float delta) {
|
||||
|
@@ -1,7 +1,87 @@
|
||||
#include <JUI/Widgets/ScrollingRect.hpp>
|
||||
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
using namespace JUI;
|
||||
|
||||
}
|
||||
void ScrollingRect::RecomputeRenderTarget() {
|
||||
//
|
||||
//Rect::PreDraw();
|
||||
InnerDraw();
|
||||
//Rect::PostDraw();
|
||||
}
|
||||
|
||||
void ScrollingRect::Draw() {
|
||||
|
||||
// TODO: Only recompute when something has changed.
|
||||
// Q: How do we know when something has changed?
|
||||
RecomputeRenderTarget();
|
||||
|
||||
//J2D::DrawRenderTarget(canvas, GetAbsolutePosition());
|
||||
J2D::DrawPartialRenderTarget(canvas, GetAbsolutePosition(), {0, 0}, Vector2(GetAbsoluteSize().x, GetAbsoluteSize().y));
|
||||
|
||||
bool canvas_larger_than_widget = scroll_size > GetAbsoluteSize().y;
|
||||
float ratio = scroll_size / GetAbsoluteSize().y;
|
||||
|
||||
if (vertical_scrollbar_enabled && canvas_larger_than_widget)
|
||||
{
|
||||
//std::cout << "Ratio " << ratio << std::endl;
|
||||
Vector2 vscroll_pos = GetAbsolutePosition() + Vector2(GetAbsoluteSize().x-scrollbar_width, 0);
|
||||
Vector2 vscroll_size = {scrollbar_width, GetAbsoluteSize().y-scrollbar_width};
|
||||
J2D::FillRect(Colors::LightGray, vscroll_pos, vscroll_size);
|
||||
J2D::FillRoundedRect(scrollbar_color, {vscroll_pos.x, vscroll_pos.y + scroll}, {vscroll_size.x, (vscroll_size.y / ratio)}, 4);
|
||||
|
||||
// Draw little square box at the point where the vertical and horizontal scrollbars would meet.
|
||||
Vector2 lil_box_size = {scrollbar_width, scrollbar_width};
|
||||
Vector2 lil_box_pos = GetAbsolutePosition() + GetAbsoluteSize() - lil_box_size;
|
||||
J2D::FillRect(Colors::DarkGray, lil_box_pos, lil_box_size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vector2 ScrollingRect::CanvasPosition() const {
|
||||
return {GetAbsolutePosition().x, GetAbsolutePosition().y - scroll};
|
||||
}
|
||||
|
||||
// Wouldn't inner draw actually render everything onto the RenderTarget?
|
||||
void ScrollingRect::InnerDraw() {
|
||||
|
||||
J2D::Begin(canvas, true);
|
||||
auto saved_pos = position;
|
||||
auto saved_size = size;
|
||||
|
||||
// Kind of a hack to get the child widgets onto the rendertarget at the correct position.
|
||||
// We basically set the position for just long enough to lie to the child widgets.
|
||||
// The amount we offset by is the absolute position.
|
||||
// If you work the formulas out, the child widgets will believe their parent's AbsolutePosition is {0,0}.
|
||||
|
||||
Position(UDim2::FromPixels(-GetAbsolutePosition().x, -GetAbsolutePosition().y + scroll));
|
||||
Size({200_percent, 500_percent});
|
||||
|
||||
Rect::InnerDraw();
|
||||
DrawChildWidgets();
|
||||
|
||||
J2D::DrawPoint(Colors::Blue, {1,1}, 2);
|
||||
J2D::DrawPoint(Colors::Blue, Vector2(GetAbsoluteSize()), 2);
|
||||
|
||||
// Set our position back once we're done.
|
||||
Size(saved_size);
|
||||
Position(saved_pos);
|
||||
J2D::End();
|
||||
|
||||
}
|
||||
|
||||
const Vector2i default_initialize_canvas_size {1024, 4096};
|
||||
|
||||
ScrollingRect::~ScrollingRect() { delete canvas; }
|
||||
|
||||
ScrollingRect::ScrollingRect() : canvas(new RenderTarget(default_initialize_canvas_size)) {
|
||||
bool success = canvas->SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE::MSAA_8X);
|
||||
}
|
||||
|
||||
ScrollingRect::ScrollingRect(Widget *parent) : Rect(parent), canvas(new RenderTarget(default_initialize_canvas_size)) {
|
||||
bool success = canvas->SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE::MSAA_8X);
|
||||
}
|
||||
|
||||
JGL::RenderTarget *ScrollingRect::GetCanvas() { return canvas; }
|
||||
|
||||
Vector2i ScrollingRect::CanvasSize() const { return canvas->GetDimensions(); }
|
||||
|
@@ -4,4 +4,115 @@
|
||||
namespace JUI
|
||||
{
|
||||
|
||||
Slider::Slider(JUI::Widget *parent)
|
||||
{
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void Slider::OnClick(const Vector2 &MousePos, const MouseButton &MouseButton) {
|
||||
Clickable::OnClick(MousePos, MouseButton);
|
||||
dragging = true;
|
||||
}
|
||||
|
||||
void Slider::OnRelease(const Vector2 &MousePos, const MouseButton &MouseButton, bool MouseStillOver) {
|
||||
Clickable::OnRelease(MousePos, MouseButton, MouseStillOver);
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
void Slider::OnHover(const Vector2 &MousePos) {
|
||||
Hoverable::OnHover(MousePos);
|
||||
}
|
||||
|
||||
void Slider::OnExit(const Vector2 &MousePos) {
|
||||
Hoverable::OnExit(MousePos);
|
||||
}
|
||||
|
||||
void Slider::Update(float delta) {
|
||||
bool selected = Rect::IsMouseInside();
|
||||
|
||||
|
||||
hovered = IsMouseInside();
|
||||
|
||||
Hoverable::Update(last_known_mouse_pos, delta);
|
||||
|
||||
// TODO: This is duplicated between here and Window.cpp
|
||||
// Will be abstracted away into Clickable shortly.
|
||||
if (IsHovered() && mb_state && !prev_mb_state)
|
||||
{
|
||||
OnClick(last_known_mouse_pos, mbtn);
|
||||
}
|
||||
|
||||
if (IsClicked() && !mb_state)
|
||||
{
|
||||
OnRelease(last_known_mouse_pos, mbtn, IsHovered());
|
||||
}
|
||||
|
||||
prev_mb_state = mb_state;
|
||||
|
||||
if (dragging)
|
||||
{
|
||||
float range = maximum - minimum;
|
||||
Vector2 mouse = last_known_mouse_pos;
|
||||
|
||||
float slider_abs_left = this->GetAbsolutePosition().x;
|
||||
float slider_abs_right = (this->GetAbsolutePosition().x + this->GetAbsoluteSize().x) - scrubber_width;
|
||||
float slider_total_width = this->GetAbsoluteSize().x - scrubber_width;
|
||||
|
||||
float scrubberP = Math::Clamp(mouse.x, slider_abs_left, slider_abs_right);
|
||||
|
||||
float offset = scrubberP - slider_abs_left;
|
||||
|
||||
float percentage = offset / slider_total_width;
|
||||
|
||||
float translated = Math::Clamp(roundMultiple(percentage * Range(), interval), 0.f, Range());
|
||||
|
||||
float value = translated + minimum;
|
||||
|
||||
if (current != value)
|
||||
ValueChanged(value);
|
||||
|
||||
current = value;
|
||||
//std::cout << "slider value: " << value << std::endl;
|
||||
}
|
||||
Rect::Update(delta);
|
||||
}
|
||||
|
||||
void Slider::Draw() {
|
||||
//scrubber->Draw();
|
||||
Rect::Draw();
|
||||
Vector2 pos = {
|
||||
current * (GetAbsoluteSize().x - scrubber_width) + GetAbsolutePosition().x
|
||||
,GetAbsolutePosition().y
|
||||
};
|
||||
/// TODO: Implement internal padding on scrubber element?
|
||||
//J2D::Begin();
|
||||
JGL::J2D::FillRect(scrubber_color, pos, {scrubber_width, GetAbsoluteSize().y});
|
||||
//J2D::End();
|
||||
}
|
||||
|
||||
float Slider::Minimum() const { return minimum; }
|
||||
|
||||
float Slider::Maximum() const { return maximum; }
|
||||
|
||||
float Slider::Interval() const { return interval; }
|
||||
|
||||
float Slider::CurrentValue() const { return current; }
|
||||
|
||||
Color4 Slider::ScrubberColor() const { return scrubber_color; }
|
||||
|
||||
float Slider::ScrubberWidth() const { return scrubber_width; }
|
||||
|
||||
float Slider::Range() const { return maximum - minimum; }
|
||||
|
||||
void Slider::Minimum(float min) { minimum = min; }
|
||||
|
||||
void Slider::Maximum(float max) { maximum = max; }
|
||||
|
||||
void Slider::Interval(float inter) { interval = inter; }
|
||||
|
||||
void Slider::CurrentValue(float value) { current = value; }
|
||||
|
||||
void Slider::ScrubberColor(const Color4 &color) { scrubber_color = color;}
|
||||
|
||||
void Slider::ScrubberWidth(float width) { scrubber_width = width;}
|
||||
}
|
@@ -6,12 +6,12 @@ namespace JUI {
|
||||
|
||||
Text::Text(Widget* parent) : Text()
|
||||
{
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
Text::~Text() {}
|
||||
Vector2 Text::GetAbsolutePosition() const {
|
||||
auto parent =this->GetParent();
|
||||
auto parent = this->GetParent();
|
||||
if (parent)
|
||||
return parent->GetAbsolutePosition();
|
||||
//return {0,0};
|
||||
|
@@ -1,3 +1,20 @@
|
||||
//
|
||||
// Created by dawsh on 7/16/24.
|
||||
//
|
||||
#include <JUI/Widgets/TextButton.hpp>
|
||||
|
||||
namespace JUI
|
||||
{
|
||||
TextButton::TextButton() : Button(), TextBase() {}
|
||||
TextButton::TextButton(Widget* parent) : TextButton() {
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void TextButton::Update(float delta) {
|
||||
Button::Update(delta);
|
||||
TextBase::Update(delta);
|
||||
}
|
||||
|
||||
void TextButton::Draw() {
|
||||
Button::Draw();
|
||||
// TODO: Factor in padding here.
|
||||
TextBase::Draw(this->GetAbsolutePosition()+GetAbsolutePaddingTopLeft(), this->GetAbsoluteSize()-GetAbsolutePaddingBottomRight());
|
||||
}
|
||||
}
|
||||
|
216
src/JUI/Widgets/TextInputForm.cpp
Normal file
216
src/JUI/Widgets/TextInputForm.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include <JUI/Widgets/TextInputForm.hpp>
|
||||
#include <ReWindow/InputService.h>
|
||||
|
||||
namespace JUI {
|
||||
TextInputForm::TextInputForm() : TextRect(), Clickable() { }
|
||||
TextInputForm::TextInputForm(Widget* parent) : TextInputForm() {
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void TextInputForm::ObserveMouseMovement(const Vector2 &latest_known_pos) {
|
||||
Widget::ObserveMouseMovement(latest_known_pos);
|
||||
}
|
||||
|
||||
std::string TextInputForm::GetAutocompleteText() const { return autocomplete_text;}
|
||||
|
||||
void TextInputForm::SetAutoCompleteText(const std::string &text) { autocomplete_text = text;}
|
||||
|
||||
Color4 TextInputForm::GetAutocompleteTextColor() const { return autocomplete_color; }
|
||||
|
||||
void TextInputForm::SetAutocompleteTextColor(const Color4 &color) { autocomplete_color = color; }
|
||||
|
||||
bool TextInputForm::HideAutocompleteOnSelect() const { return hide_autocomplete_on_select; }
|
||||
|
||||
void TextInputForm::SetHideAutocompleteOnSelect(bool hide) { hide_autocomplete_on_select = hide; }
|
||||
|
||||
bool TextInputForm::AutocompleteTextEnabled() const { return autocomplete_text_enabled; }
|
||||
|
||||
void TextInputForm::SetAutocompleteTextEnabled(bool enabled) { autocomplete_text_enabled = enabled; }
|
||||
|
||||
void TextInputForm::ObserveMouseInput(MouseButton btn, bool pressed) {
|
||||
Widget::ObserveMouseInput(btn, pressed);
|
||||
if (pressed && btn == MouseButton::Left) {
|
||||
if (IsMouseInside()) {
|
||||
if (!focused) {
|
||||
OnSelect.Invoke();
|
||||
|
||||
}
|
||||
focused = true;
|
||||
}
|
||||
else {
|
||||
if (focused)
|
||||
OnDeselect.Invoke();
|
||||
focused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextInputForm::InnerDraw()
|
||||
{
|
||||
|
||||
Rect::InnerDraw();
|
||||
|
||||
Vector2 abs_pos = this->GetAbsolutePosition();
|
||||
Vector2 abs_size = this->GetAbsoluteSize();
|
||||
|
||||
|
||||
// TODO: Apply this everywhere..
|
||||
Vector2 pad_shifts_pos_by = {
|
||||
pad_left.Pixels + (pad_left.Scale * abs_size.x),
|
||||
pad_top.Pixels + (pad_left.Scale * abs_size.y)
|
||||
};
|
||||
|
||||
Vector2 pad_shrinks_size_by = {
|
||||
pad_right.Pixels + (pad_left.Scale * abs_size.x),
|
||||
pad_bottom.Pixels + (pad_right.Scale * abs_size.y)
|
||||
};
|
||||
|
||||
Vector2 pos = abs_pos + pad_shifts_pos_by;
|
||||
Vector2 size = abs_pos - (pad_shrinks_size_by*2.f);
|
||||
|
||||
if (!focused || !hide_autocomplete_on_select)
|
||||
TextBase::Draw(pos, size, autocomplete_text, this->text_size, autocomplete_color);
|
||||
|
||||
TextBase::Draw(pos, size);
|
||||
|
||||
//TextRect::InnerDraw();
|
||||
}
|
||||
|
||||
void TextInputForm::Draw() {
|
||||
TextRect::Draw();
|
||||
}
|
||||
|
||||
void TextInputForm::Update(float elapsed) {
|
||||
TextRect::Update(elapsed);
|
||||
|
||||
// TODO: Make cursor actually blink
|
||||
if (focused) {
|
||||
cursor_blink_time += elapsed;
|
||||
|
||||
if (cursor_blink_time > 1.f)
|
||||
cursor_blink_time = 0.f;
|
||||
|
||||
if (cursor_blink_time > 0.5f) {
|
||||
std::string result = input_buffer;
|
||||
|
||||
result.insert(cursor_position, 1, '|');
|
||||
SetContent(result);
|
||||
} else {
|
||||
SetContent(input_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string uppercase(const std::string& input) {
|
||||
std::string s = input;
|
||||
std::ranges::transform(s, s.begin(), ::toupper);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string lowercase(const std::string& input) {
|
||||
std::string s = input;
|
||||
std::ranges::transform(s, s.begin(), ::tolower);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TextInputForm::ObserveKeyInput(Key key, bool pressed) {
|
||||
Widget::ObserveKeyInput(key, pressed);
|
||||
|
||||
if (!pressed)
|
||||
return;
|
||||
|
||||
if (!focused)
|
||||
return;
|
||||
|
||||
// TODO: Text Selection
|
||||
// TODO: Support Copy
|
||||
// TODO: Support Paste
|
||||
// TODO: Support Cut
|
||||
// TODO: Support insert at cursor
|
||||
// TODO: Simulate key repeat.
|
||||
|
||||
if (key == Keys::Return || key == Keys::NumPadReturn) {
|
||||
|
||||
OnReturn.Invoke(input_buffer);
|
||||
|
||||
if (clear_text_on_return) {
|
||||
|
||||
input_buffer = "";
|
||||
cursor_position = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == Keys::LeftArrow) {
|
||||
if (cursor_position > 0)
|
||||
cursor_position -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == Keys::RightArrow) {
|
||||
if (cursor_position < input_buffer.length() - 1)
|
||||
cursor_position += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (InputService::IsKeyDown(Keys::LeftControl)) {
|
||||
|
||||
if (key == Keys::C) {
|
||||
|
||||
// TODO: Implement Copy
|
||||
|
||||
return;
|
||||
}
|
||||
if (key == Keys::V) {
|
||||
// TODO: Implement Paste
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == Keys::X) {
|
||||
// TODO: Implement Cut
|
||||
cursor_position = 0; // TODO: Set to size of pasted content.
|
||||
return;
|
||||
}
|
||||
|
||||
//input_buffer = input_buffer.insert(cursor_position, uppercase( key.Mnemonic));
|
||||
//return;
|
||||
}
|
||||
|
||||
if (key == Keys::LeftShift || key == Keys::RightShift || key == Keys::LeftControl || key == Keys::RightControl
|
||||
|| key == Keys::LeftAlt || key == Keys::RightAlt || key == Keys::Super || key == Keys::Escape
|
||||
|| key == Keys::F1 || key == Keys::F2 || key == Keys::F3 || key == Keys::F4 || key == Keys::F5 || key == Keys::F6
|
||||
|| key == Keys::F7 || key == Keys::F8 || key == Keys::F9 || key == Keys::F10 || key == Keys::F11 || key == Keys::F12) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (key == Keys::Backspace) {
|
||||
if (cursor_position > 0) {
|
||||
input_buffer = input_buffer.erase(cursor_position-1, 1);
|
||||
//input_buffer = input_buffer.substr(0, input_buffer.length()-1);
|
||||
cursor_position--;
|
||||
}
|
||||
} else {
|
||||
if (InputService::IsKeyDown(Keys::LeftShift) || InputService::IsKeyDown(Keys::RightShift)) {
|
||||
input_buffer = input_buffer.insert(cursor_position, uppercase( key.Mnemonic));
|
||||
cursor_position++;
|
||||
} else {
|
||||
input_buffer = input_buffer.insert(cursor_position, lowercase( key.Mnemonic));
|
||||
cursor_position++;
|
||||
}
|
||||
//SetContent(GetContent() + key.Mnemonic);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool TextInputForm::HasFocus() const { return focused; }
|
||||
|
||||
void TextInputForm::SetFocused(bool focused) { this->focused = focused;}
|
||||
|
||||
void TextInputForm::GrabFocus() { SetFocused(true); }
|
||||
|
||||
void TextInputForm::DropFocus() { SetFocused(false); }
|
||||
|
||||
}
|
@@ -3,12 +3,12 @@
|
||||
namespace JUI {
|
||||
TextRect::TextRect() : Rect(), TextBase() {}
|
||||
TextRect::TextRect(Widget* parent) : TextRect() {
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
void TextRect::Update(float delta) {
|
||||
|
||||
if (fit_text)
|
||||
if (fit_size_to_text)
|
||||
{
|
||||
|
||||
Vector2 abs_pos = this->GetAbsolutePosition();
|
||||
@@ -39,11 +39,9 @@ namespace JUI {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TextRect::Draw() {
|
||||
Rect::Draw();
|
||||
|
||||
|
||||
void TextRect::InnerDraw()
|
||||
{
|
||||
Rect::InnerDraw();
|
||||
Vector2 abs_pos = this->GetAbsolutePosition();
|
||||
Vector2 abs_size = this->GetAbsoluteSize();
|
||||
|
||||
@@ -60,6 +58,11 @@ namespace JUI {
|
||||
TextBase::Draw(abs_pos + pad_shifts_pos_by, abs_size - pad_shrinks_size_by*2);
|
||||
}
|
||||
|
||||
void TextRect::Draw() {
|
||||
Rect::Draw();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
1
src/JUI/Widgets/Tooltip.cpp
Normal file
1
src/JUI/Widgets/Tooltip.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include <JUI/Widgets/Tooltip.hpp>
|
@@ -6,33 +6,13 @@
|
||||
namespace JUI
|
||||
{
|
||||
Window::Window() : Widget(), Clickable(), Hoverable(), RectBase(), Draggable(), Resizable(), Dockable() {
|
||||
this->SetPosition({200, 200, 0, 0});
|
||||
this->SetSize({400, 200, 0, 0});
|
||||
this->Position({200, 200, 0, 0});
|
||||
this->Size({400, 200, 0, 0});
|
||||
min_size = {400, 200};
|
||||
this->BGColor({0,0,0,0});
|
||||
this->BGColor({64,64,64,255});
|
||||
this->BorderColor({92,92,192});
|
||||
this->SetBorderWidth(2);
|
||||
this->SetBorderMode(BorderMode::Outline);
|
||||
|
||||
//this->OnHoverEvent += [&] (Vector2 MousePos) {
|
||||
|
||||
//};
|
||||
|
||||
//this->OnExitEvent += [&] (Vector2 MousePos) {
|
||||
// hovered;
|
||||
//};
|
||||
|
||||
/*
|
||||
this->OnClickEvent += [&] (Vector2 dummy, MouseButton btn) {
|
||||
if (draggable && btn == MouseButton::Left) {
|
||||
DEBUG("Window draggable")
|
||||
SetDrag(true);
|
||||
}
|
||||
|
||||
if (resizable && btn == MouseButton::Right)
|
||||
DEBUG("Window resizable")
|
||||
};
|
||||
*/
|
||||
this->BorderMode(BorderMode::Middle);
|
||||
|
||||
// TODO: Move out of Event callback
|
||||
this->OnReleaseEvent += [&] (Vector2 dummy, MouseButton btn, bool dummy3) {
|
||||
@@ -42,64 +22,90 @@ namespace JUI
|
||||
};
|
||||
|
||||
Viewport = new Rect(this);
|
||||
Viewport->SetName("Viewport");
|
||||
Viewport->BGColor({64,64,64, 255});
|
||||
Viewport->SetSize({0, -20, 1, 1});
|
||||
Viewport->SetPosition({0,20,0,0});
|
||||
// TODO: Viewport->SetAnchorPoint({0.f, 0.f});
|
||||
//Viewport->BorderColor({128, 128, 128, 255});
|
||||
//Viewport->SetBorderWidth(1);
|
||||
//Viewport->SetPadding(1_px);
|
||||
Viewport->Name("Viewport");
|
||||
Viewport->BGColor({64,64,64, 0});
|
||||
|
||||
Viewport->Size({0, -20, 1, 1});
|
||||
Viewport->Position({0, 20, 0, 0});
|
||||
// TODO: Viewport->AnchorPoint({0.f, 0.f});
|
||||
Viewport->BorderColor({128, 128, 128, 255});
|
||||
Viewport->SetBorderWidth(0);
|
||||
//Viewport->Padding(1_px);
|
||||
|
||||
// TODO: Viewport->SetBorderRadius(0);
|
||||
|
||||
Topbar = new Rect(this);
|
||||
Topbar->SetPosition({0_px, 0_px});
|
||||
Topbar->SetSize({100_percent, 20_px});
|
||||
Topbar->Position({0_px, 0_px});
|
||||
Topbar->Size({100_percent, UDim(titlebar_height, 0)});
|
||||
Topbar->BGColor({92,92,192, 255});
|
||||
//Topbar->BorderColor({128, 128, 128, 255});
|
||||
//Topbar->SetBorderWidth(1);
|
||||
Topbar->BorderColor({128, 128, 128, 0});
|
||||
Topbar->SetBorderWidth(0);
|
||||
|
||||
TitleLabel = new Text(Topbar);
|
||||
TitleLabel->Center();
|
||||
TitleLabel->SetContent(title);
|
||||
TitleLabel->SetTextSize(titlebar_height);
|
||||
TitleLabel->SetTextSize(title_font_size);
|
||||
|
||||
|
||||
// TODO: auto* list = new HorizontalListLayout(Topbar);
|
||||
|
||||
// TODO: exit_btn
|
||||
exit_btn = new TextButton(Topbar);
|
||||
//exit_btn->SetAnchorPoint({1.f, 0.f});
|
||||
//exit_btn->SetSize({30_px, 100_percent});
|
||||
exit_btn->SetSize({titlebar_height, titlebar_height, 0, 0});
|
||||
//exit_btn->BorderColor({128, 128, 128, 255});
|
||||
//exit_btn->SetBaseColor({192, 64, 64, 255});
|
||||
//exit_btn->SetHoverColor({255, 0, 0, 255});
|
||||
//exit_btn->BGColor({192, 64, 64, 255});
|
||||
exit_btn->SetContent("X");
|
||||
exit_btn->BGColor({92,92,192, 255});
|
||||
//JGL::Font FreeSans
|
||||
|
||||
auto* exb_tex = new Texture({titlebar_height, titlebar_height });
|
||||
auto* exb_rt = new RenderTarget(exb_tex);
|
||||
|
||||
if (exb_rt->SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE::MSAA_8X)) {/* using msaa to make the circle nicer. */}
|
||||
std::array<Color4, 2> exb_circle_colors
|
||||
{
|
||||
Color4(168, 28, 28, 255),
|
||||
Color4(212, 25, 25, 255)
|
||||
|
||||
};
|
||||
|
||||
std::array<Vector2, 2> exb_circle_positions
|
||||
{
|
||||
Vector2(exb_rt->GetDimensions()) / 2,
|
||||
Vector2(exb_rt->GetDimensions()) / 2
|
||||
};
|
||||
|
||||
std::array<float, 2> exb_circle_radii
|
||||
{
|
||||
(float) (exb_rt->GetDimensions().x * 0.33),
|
||||
(float) (exb_rt->GetDimensions().x * 0.28)
|
||||
};
|
||||
|
||||
J2D::Begin(exb_rt, true);
|
||||
J2D::BatchFillCircle(exb_circle_colors.data(), exb_circle_positions.data(), exb_circle_radii.data(), 24, 2);
|
||||
J2D::End();
|
||||
delete exb_rt;
|
||||
|
||||
exit_btn = new ImageButton(Topbar);
|
||||
exit_btn->Content(exb_tex);
|
||||
//exit_btn->AnchorPoint({1.f, 0.f});
|
||||
//exit_btn->Size({30_px, 100_percent});
|
||||
exit_btn->Size({titlebar_height, titlebar_height, 0, 0});
|
||||
|
||||
// exit_btn->BorderColor({128, 128, 128, 255});
|
||||
|
||||
exit_btn->BaseBGColor({92,92,192, 255});
|
||||
exit_btn->BGColor(exit_btn->BaseBGColor());
|
||||
exit_btn->BorderColors({0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0});
|
||||
exit_btn->BorderColor({0,0,0,0});
|
||||
exit_btn->SetBorderWidth(0.f);
|
||||
|
||||
//exit_btn_text->SetFont(TitleLabel->GetFont());
|
||||
exit_btn->SetTextSize(titlebar_height);
|
||||
exit_btn->SetTextColor({255, 0, 0});
|
||||
//exit_btn->SetTextSize(title_font_size);
|
||||
//exit_btn->SetTextColor({255, 0, 0});
|
||||
//exit_btn->Center();
|
||||
|
||||
exit_btn->OnClickEvent += [&] (auto... _) {
|
||||
this->SetVisible(false);
|
||||
this->Visible(false);
|
||||
};
|
||||
|
||||
jlog::Debug(std::format("{} {} {} {}", Topbar->Size().X.Pixels, Topbar->Size().Y.Pixels, Topbar->Size().X.Scale,
|
||||
Topbar->Size().Y.Scale));
|
||||
//min_size = exit_btn->GetSize() + Topbar->GetSize() + TitleLabel->Size();
|
||||
//= Topbar->GetSize();//+ exit_btn->Size();
|
||||
// TODO: fs_btn
|
||||
|
||||
|
||||
}
|
||||
|
||||
Window::Window(Widget* parent) : Window() {
|
||||
this->SetParent(parent);
|
||||
this->Parent(parent);
|
||||
}
|
||||
|
||||
Vector2 Window::MinSize() const { return min_size; }
|
||||
@@ -116,11 +122,11 @@ namespace JUI
|
||||
|
||||
bool Window::IsResizable() const { return resizable; }
|
||||
|
||||
Text *Window::GetTitleInstance() { return TitleLabel; }
|
||||
Text *Window::TitleInstance() { return TitleLabel; }
|
||||
|
||||
Rect *Window::GetTopbarInstance() { return Topbar; }
|
||||
Rect *Window::TopbarInstance() { return Topbar; }
|
||||
|
||||
Rect *Window::GetViewportInstance() { return Viewport; }
|
||||
Rect *Window::ViewportInstance() { return Viewport; }
|
||||
|
||||
void Window::SetDrag(bool d) {
|
||||
Draggable::SetDrag(d);
|
||||
@@ -129,7 +135,7 @@ namespace JUI
|
||||
|
||||
void Window::SetTitleFont(const Font& f) {
|
||||
TitleLabel->SetFont(f);
|
||||
exit_btn->SetFont(f);
|
||||
//exit_btn->SetFont(f);
|
||||
}
|
||||
|
||||
void Window::OnClick(const Vector2& mouse_pos, const MouseButton& btn)
|
||||
@@ -137,10 +143,10 @@ namespace JUI
|
||||
Clickable::OnClick(mouse_pos, btn);
|
||||
clicked = true;
|
||||
|
||||
if (draggable && btn == MouseButton::Left)
|
||||
if (draggable && btn == MouseButton::Left && TitleInstance()->IsMouseInside())
|
||||
this->SetDrag(true);
|
||||
|
||||
if (resizable && btn == MouseButton::Right) {
|
||||
if (resizable && btn == MouseButton::Right && TitleInstance()->IsMouseInside()) {
|
||||
this->StartResizing(last_known_mouse_pos);
|
||||
this->SetResize(true);
|
||||
size_when_restart_began = Size();
|
||||
@@ -160,9 +166,9 @@ namespace JUI
|
||||
|
||||
void Window::Update(float delta) {
|
||||
if (dragging) {
|
||||
jlog::Debug(std::format("mpos {} {}", last_known_mouse_pos.x, last_known_mouse_pos.y));
|
||||
//jlog::Debug(std::format("mpos {} {}", last_known_mouse_pos.x, last_known_mouse_pos.y));
|
||||
Vector2 mpos = last_known_mouse_pos - initial_drag_offset;
|
||||
this->SetPosition(UDim2{(int)mpos.x, (int)mpos.y, 0,0});
|
||||
this->Position(UDim2{(int) mpos.x, (int) mpos.y, 0, 0});
|
||||
}
|
||||
|
||||
if (resizing) {
|
||||
@@ -170,7 +176,7 @@ namespace JUI
|
||||
|
||||
Vector2 resize_amt = mpos - initial_resize_offset;
|
||||
|
||||
SetSize(size_when_restart_began + UDim2(resize_amt.x, resize_amt.y, 0, 0));
|
||||
Size(size_when_restart_began + UDim2(resize_amt.x, resize_amt.y, 0, 0));
|
||||
|
||||
Vector2 abs_size = this->GetAbsoluteSize();
|
||||
|
||||
@@ -178,14 +184,14 @@ namespace JUI
|
||||
if (abs_size.x < min_size.x)
|
||||
{
|
||||
float needed_amt_to_resize = min_size.x - abs_size.x;
|
||||
SetSize(Size() + UDim2(needed_amt_to_resize, 0, 0, 0));
|
||||
Size(Size() + UDim2(needed_amt_to_resize, 0, 0, 0));
|
||||
}
|
||||
|
||||
// Clamp Y-axis.
|
||||
if (abs_size.y < min_size.y)
|
||||
{
|
||||
float needed_amt_to_resize = min_size.y - abs_size.y;
|
||||
SetSize(Size() + UDim2(0, needed_amt_to_resize, 0, 0));
|
||||
Size(Size() + UDim2(0, needed_amt_to_resize, 0, 0));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -218,6 +224,52 @@ namespace JUI
|
||||
}
|
||||
|
||||
void Window::SetTitle(const std::string &title) {
|
||||
GetTitleInstance()->SetContent(title);
|
||||
TitleInstance()->SetContent(title);
|
||||
}
|
||||
|
||||
void Window::MinSize(const Vector2 &constraint) {
|
||||
min_size = constraint;
|
||||
}
|
||||
|
||||
void Window::MaxSize(const Vector2 &constraint) {
|
||||
max_size = constraint;
|
||||
}
|
||||
|
||||
void Window::SetDraggable(bool value) {
|
||||
draggable = value;
|
||||
}
|
||||
|
||||
void Window::SetDockable(bool value) {
|
||||
dockable = value;
|
||||
}
|
||||
|
||||
void Window::SetResizable(bool value) {
|
||||
resizable = value;
|
||||
}
|
||||
|
||||
ImageButton* Window::ExitButtonInstance() {
|
||||
return exit_btn;
|
||||
}
|
||||
|
||||
void Window::LayoutControlsLeft() {
|
||||
exit_btn->AnchorPoint({0.f, 0.f});
|
||||
exit_btn->Position({0_px, 0_px});
|
||||
}
|
||||
|
||||
void Window::LayoutControlsRight() {
|
||||
exit_btn->AnchorPoint({1.f, 0.f});
|
||||
exit_btn->Position({100_percent, 0_px});
|
||||
}
|
||||
|
||||
Vector2 Window::AbsoluteViewportPosition() const {
|
||||
return Viewport->GetAbsolutePosition();
|
||||
}
|
||||
|
||||
Vector2 Window::AbsoluteViewportSize() const {
|
||||
return Viewport->GetAbsoluteSize();
|
||||
}
|
||||
|
||||
AABB2D Window::AbsoluteViewportBounds() const {
|
||||
return {AbsoluteViewportPosition(), AbsoluteViewportSize()};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user