Files
ReJUI/main.cpp
2025-02-19 16:54:44 -06:00

452 lines
14 KiB
C++

/// 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 main.cpp
/// @desc Demo Program Entry Point
/// @edit 2024-07-11
#include <iostream>
#include <JGL/JGL.h>
#include <JUI/Widgets/Rect.hpp>
#include <JUI/Widgets/RadioButton.hpp>
#include <JUI/Widgets/Window.hpp>
#include <JUI/Widgets/Scene.hpp>
#include <JUI/Widgets/Text.hpp>
#include <JUI/Widgets/ListLayout.hpp>
#include <JUI/Widgets/TextRect.hpp>
#include <JUI/Widgets/Image.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"
#include <JUI/Widgets/Collapsible.hpp>
JUI::Scene* scene;
JGL::Texture* sample_texture;
JGL::Texture* slicer;
JUI::VerticalListLayout* list;
JUI::ScrollingRect* scroller;
JUI::TextRect* widget_count;
int count_descendants(JUI::Widget* w) {
return w->GetDescendants().size();
}
JUI::Scene* CreateScene() {
using namespace JUI;
auto *root = new Scene();
/*root->DescendantAdded += [&] (auto* node) {
widget_count->SetContent("Widgets: " + count_descendants(root));
};
root->DescendantRemoved += [&] (auto* node) {
widget_count->SetContent("Widgets: " + count_descendants(root));
};*/
auto* nineslice_demo_window = new JUI::Window(root);
nineslice_demo_window->Name("NineSlice Demo Window");
nineslice_demo_window->CornerRounding(10);
nineslice_demo_window->Size({50_percent, 50_percent});
nineslice_demo_window->SetTitle("9-Slice Demo");
nineslice_demo_window->Visible(false);
nineslice_demo_window->TitlebarHeight(12);
auto* topbar = new UtilityBar(root);
topbar->ZIndex(3);
auto* file = topbar->AddButton("Demos");
auto* file_tt = new JUI::Tooltip(file);
file_tt->SetContent("Tooltip");
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");
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);
};
topbar->AddButton("Edit");
auto* view = topbar->AddButton("View");
topbar->AddButton("Help");
widget_count = new JUI::TextRect(topbar);
widget_count->Size(UDim2(100,20,0,0));
widget_count->AnchorPoint({1, 0});
widget_count->Position({100_percent, 0_percent});
widget_count->BGColor(Colors::Transparent);
widget_count->SetTextColor(Colors::Black);
widget_count->BorderColor(Colors::Transparent);
widget_count->BorderWidth(0);
widget_count->Center();
widget_count->AlignRight();
//auto* horizontal = new HorizontalListLayout(root);
//horizontal->ZIndex(1);
auto* column_rect = new Rect(root);
//column_rect->ZIndex(4);
column_rect->Size({0, -24, 0.2f, 1.f});
column_rect->Position({0, 24, 0, 0});
column_rect->BGColor(Colors::Grays::Gainsboro);
auto* column_layout = new VerticalListLayout(column_rect);
auto* btn_container1 = new Rect(column_layout);
btn_container1->Size({100_percent, 24_px});
auto* btn_h_layout1 = new HorizontalListLayout(btn_container1);
btn_h_layout1->Padding({2_px});
auto* button = new TextButton(btn_h_layout1);
//button->Position({5, 105, 0, 0});
button->Size({0, 20, 0.32f, 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(btn_h_layout1);
//button2->Position({5, 105, 0, 0});
button2->Size({0, 20, 0.32f, 0});
button2->SetTextColor(Colors::Black);
button2->SetContent("Button");
button2->AlignCenterHorizontally();
auto* button3 = new TextButton(btn_h_layout1);
//button2->Position({5, 105, 0, 0});
button3->Size({0, 20, 0.32f, 0});
button3->SetTextColor(Colors::Black);
button3->SetContent("Button");
button3->AlignRight();
auto* btn_container2 = new Rect(column_layout);
btn_container2->Size({100_percent, 24_px});
btn_container2->BGColor(Colors::DarkGray);
auto* btn_h_layout2 = new HorizontalListLayout(btn_container2);
btn_h_layout2->Padding({2_px});
auto* button4 = new TextButton(btn_h_layout2);
//button->Position({5, 105, 0, 0});
button4->Size({0, 20, 0.32f, 0});
button4->SetTextColor(Colors::Black);
button4->SetContent("Button");
button4->AlignLeft();
//button4->CornerRounding(4);
auto* button5 = new TextButton(btn_h_layout2);
//button2->Position({5, 105, 0, 0});
button5->Size({0, 20, 0.32f, 0});
button5->SetTextColor(Colors::Black);
button5->SetContent("Button");
button5->AlignCenterHorizontally();
//button5->CornerRounding(4);
auto* button6 = new TextButton(btn_h_layout2);
//button2->Position({5, 105, 0, 0});
button6->Size({0, 20, 0.32f, 0});
button6->SetTextColor(Colors::Black);
button6->SetContent("Button");
button6->AlignRight();
//button6->CornerRounding(4);
auto* checkbox_container = new Rect(column_layout);
checkbox_container->Size({0, 24, 1, 0});
auto* checkbox_horiz = new HorizontalListLayout(checkbox_container);
checkbox_horiz->Padding(2_px);
auto* label = new TextRect(checkbox_horiz);
label->SetContent("Checkboxes");
label->BorderWidth(0);
label->AutoFitSizeToText(true);
auto* check1 = new Checkbox(checkbox_horiz);
check1->Size({20_px, 20_px});
auto* check2 = new Checkbox(checkbox_horiz);
check2->Size({20_px, 20_px});
check2->CheckedColor(Colors::Blue);
check2->CornerRounding(7);
auto* check3 = new Checkbox(checkbox_horiz);
check3->Size({20_px, 20_px});
check3->CheckedColor(Colors::Oranges::Coral);
check3->CornerRounding(7);
auto* input_form = new TextInputForm(column_layout);
input_form->Size({0,24, 1, 0});
input_form->SetContent("");
input_form->SetTextSize(14);
auto* collapsible = new Collapsible(column_layout);
collapsible->Size({100_percent, 200_px});
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");
Tween* t = other_window->TweenPosition({50_percent, 50_percent}, {.time = 5});
t->Completed += [] () { std::cout << "Tween type test!!" << std::endl; };
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* 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->Size({0, 20, 1, 0});
//a->FitText(true);
a->Center();
a->SetContent("This is a virtual window.");
TextRect* b = new TextRect(list);
b->SetTextSize(16);
b->SetContent("You can drag it around via left-click, and resize via right-click. Isn't that cool??");
//b->FitText(true);
b->Size({0, 20, 1, 0});
b->Center();
root->SetViewportSize({800, 600});
return root;
}
float scale = 1.f;
float accum = 0;
int iter = 0;
class JUIDevelopmentTestWindow : public ReWindow::OpenGLWindow {
public:
void initGL() {
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(float elapsed)
{
widget_count->SetContent(std::format("Widgets: {}", count_descendants(scene)));
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->LayoutOrder(-iter);
text->SetContent(std::format("{} Sampled Delta: {}ms", -iter, Math::Floor(elapsed*1000.f)));
scroller->scroll_size += 20;
}
}
void Draw()
{
scene->Draw();
}
JUIDevelopmentTestWindow(const std::string& title, int w, int h) : ReWindow::OpenGLWindow(title, w, h, 2, 1) {}
void OnRefresh(float elapsed) override {
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->SwapBuffers();
}
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override {
std::cout << "RESIZED:" << e.Size.x << ", " << e.Size.y << std::endl;
return true;
}
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent &) override
{
}
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent &) override
{
}
void OnMouseMove(const ReWindow::MouseMoveEvent &) override
{
}
void OnKeyDown(const ReWindow::KeyDownEvent &) override {
}
void OnMouseWheel(const ReWindow::MouseWheelEvent &w) override {
scale += w.WheelMovement * 0.125f;
scene->GlobalUIScale({scale, scale});
}
};
void inspect_widget(JUI::Widget* w, int depth = 1) {
std::cout << std::setw(depth*4);
std::cout << w->Name() << std::endl;
std::cout << std::setw(0);
depth++;
for (auto* child : w->GetChildren())
{
inspect_widget(child, depth);
}
}
int main() {
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->Open();
window->initGL();
window->SetFullscreen(false);
window->SetVsyncEnabled(false);
window->SetResizable(true);
JGL::Update({800, 600});
sample_texture = new JGL::Texture("assets/ld.png");
slicer = new JGL::Texture("assets/9slice.png");
scene = CreateScene();
inspect_widget(scene);
window->OnResizeRequestEvent += [&] (ReWindow::WindowResizeRequestEvent e){
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(Vector2(e.Position.x, e.Position.y));
};
window->OnMouseButtonUpEvent += [&] (MouseButtonUpEvent e) {
/// Invalid operands to binary expression 'MouseButton' and 'const MouseButton'
if (e.Button == MouseButtons::Left)
scene->ObserveMouseInput(JUI::MouseButton::Left, false);
if (e.Button == MouseButtons::Middle)
scene->ObserveMouseInput(JUI::MouseButton::Middle, false);
if (e.Button == MouseButtons::Right)
scene->ObserveMouseInput(JUI::MouseButton::Right, false);
};
window->OnMouseButtonDownEvent += [&] (MouseButtonDownEvent e) {
if (e.Button == MouseButtons::Left)
scene->ObserveMouseInput(JUI::MouseButton::Left, true);
if (e.Button == MouseButtons::Middle)
scene->ObserveMouseInput(JUI::MouseButton::Middle, true);
if (e.Button == MouseButtons::Right)
scene->ObserveMouseInput(JUI::MouseButton::Right, true);
};
window->OnMouseButtonDownEvent += [&] (MouseButtonDownEvent e) {};
window->OnKeyDownEvent += [&] (KeyDownEvent e) {
scene->ObserveKeyInput(e.key, true);
};
window->OnKeyUpEvent += [&] (KeyUpEvent e) {
scene->ObserveKeyInput(e.key, false);
};
while (window->IsAlive()) {
//window->PollEvents();
window->ManagedRefresh();
}
return 0;
}