Skip to content

Instantly share code, notes, and snippets.

@sthairno
Created July 26, 2022 16:01
Show Gist options
  • Save sthairno/74428b38078cafe5e9424f660d9ce15c to your computer and use it in GitHub Desktop.
Save sthairno/74428b38078cafe5e9424f660d9ce15c to your computer and use it in GitHub Desktop.
即時モードのUI定義 egui風サンプル
#include "Builder.hpp"
namespace GUI
{
BuilderContext::BuilderContext(Widget& root)
: m_root(root)
{
reset();
}
Widget& BuilderContext::next(Widget::TypeID type, Widget::Generator generator)
{
auto& state = m_stack.top();
auto& children = state.widget->children();
if (state.nextItr != children.end())
{
if (state.nextItr->get()->typeId == type)
{
Widget* child = state.nextItr->get();
state.nextItr++;
return *child;
}
else
{
state.widget->removeChildrenFrom(state.nextItr);
}
}
state.widget->pushChildAtLast(std::unique_ptr<Widget>(generator()));
state.nextItr = children.end();
Widget& newChild = *children.back();
newChild.m_builder = this;
return newChild;
}
void BuilderContext::push(Widget& widget)
{
m_stack.emplace(State{
.widget = &widget,
.nextItr = widget.children().begin()
});
}
void BuilderContext::pop()
{
auto& state = m_stack.top();
state.widget->removeChildrenFrom(state.nextItr);
m_stack.pop();
}
void BuilderContext::reset()
{
while (not m_stack.empty())
{
pop();
}
push(m_root);
}
}
#pragma once
#include <Siv3D.hpp>
#include "Widget.hpp"
namespace GUI
{
class BuilderContext
{
public:
BuilderContext(Widget& root);
public:
Widget& current() const { return *m_stack.top().widget; }
Widget& next(Widget::TypeID type, Widget::Generator generator);
void push(Widget& widget);
void pop();
void reset();
private:
Widget& m_root;
struct State
{
Widget* widget;
Widget::WidgetContainer::const_iterator nextItr;
};
std::stack<State> m_stack;
};
}
#include <Siv3D.hpp> // OpenSiv3D v0.6.4
#include "Builder.hpp"
#include "Test.hpp"
void Dump(GUI::Widget& widget, int indent = 0)
{
Print << String(indent, U'\t') << widget.typeId;
indent++;
for (auto& child : widget.children())
{
Dump(*child, indent);
}
}
void Main()
{
GUI::Widget root(0);
GUI::BuilderContext ctx(root);
while (System::Update())
{
GUI::Test::New(ctx)([&] {
GUI::Test::New(ctx)([&](GUI::Test& t) {
GUI::Test::New(ctx);
});
auto& t = GUI::Test::New(ctx);
t([&] {
GUI::Test::New(ctx);
});
GUI::Test::New(ctx);
});
ctx.reset();
ClearPrint();
Dump(root);
}
}
#pragma once
#include <Siv3D.hpp>
#include "Widget.hpp"
#include "Builder.hpp"
namespace GUI
{
class Test : public Widget
{
public:
Test()
: Widget(typeid(Test).hash_code())
{ }
template<std::invocable<> Callback>
Test& operator()(Callback&& f) { builderPush(); f(); builderPop(); return *this; }
template<std::invocable<Test&> Callback>
Test& operator()(Callback&& f) { builderPush(); f(*this); builderPop(); return *this; }
public:
static Test& New(BuilderContext& ctx)
{
return reinterpret_cast<Test&>(ctx.next(typeid(Test).hash_code(), []() -> Widget* { return new Test(); }));
}
};
}
#include "Widget.hpp"
#include "Builder.hpp"
namespace GUI
{
void Widget::builderPush()
{
assert(m_builder);
m_builder->push(*this);
}
void GUI::Widget::builderPop()
{
assert(m_builder);
m_builder->pop();
}
}
#pragma once
#include <Siv3D.hpp>
namespace GUI
{
class BuilderContext;
class Widget
{
public:
using WidgetContainer = std::vector<std::unique_ptr<Widget>>;
using TypeID = size_t;
using Generator = Widget * (*)();
Widget(TypeID type)
: typeId(type)
{ }
const TypeID typeId;
Widget* parent() const { return m_parent; }
const WidgetContainer& children() const { return m_children; }
void removeChildrenFrom(WidgetContainer::const_iterator first)
{
m_children.erase(first, m_children.end());
}
void pushChildAtLast(std::unique_ptr<Widget>&& child)
{
child->m_parent = this;
m_children.emplace_back(std::move(child));
}
protected:
void builderPush();
void builderPop();
private:
friend BuilderContext;
BuilderContext* m_builder = nullptr;
private:
Widget* m_parent = nullptr;
WidgetContainer m_children;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment