#include <AUI/Platform/Entry.h>
#include <AUI/Platform/AWindow.h>
#include <AUI/Util/UIBuildingHelpers.h>
#include "AUI/View/AProgressBar.h"
#include "AUI/View/ASlider.h"
#include "AUI/View/AButton.h"
using namespace declarative;
struct Circle {
glm::vec2 position;
float radius = 10_dp;
};
class IAction {
public:
virtual ~IAction() = default;
virtual void undo() = 0;
virtual void redo() = 0;
};
class UndoStack {
public:
using Container = std::list<_unique<IAction>>;
using Iterator = Container::const_iterator;
private:
Container mStack;
public:
void undo() {
if (nextAction == mStack.begin()) {
return;
}
nextAction = std::prev(*nextAction);
(**nextAction)->undo();
}
void redo() {
if (nextAction == mStack.end()) {
return;
}
(**nextAction)->redo();
nextAction = std::next(*nextAction);
}
void add(_unique<IAction> action) {
action->redo();
nextAction = std::next(mStack.insert(mStack.erase(*nextAction, mStack.end()), std::move(action)));
nextAction.notify();
}
Iterator begin() const {
return mStack.begin();
}
Iterator end() const {
return mStack.end();
}
AProperty<Iterator> nextAction = mStack.end();
};
struct State {
AProperty<std::list<Circle>> circles;
UndoStack history;
};
static constexpr auto MAX_RADIUS = 128.f;
class CircleDrawArea :
public AView {
public:
CircleDrawArea(_<State> state) : mState(std::move(state)) {
setCustomStyle({
Expanding(),
BackgroundSolid(AColor::WHITE),
Border(1_px, AColor::GRAY),
});
connect(mState->circles.changed, me::redraw);
connect(mHoveredCircle.changed, me::redraw);
}
void render(ARenderContext ctx)
override {
for (const auto& circle : *mState->circles) {
if (&circle == mHoveredCircle) {
ASolidBrush { AColor::GRAY }, circle.position - circle.radius, glm::vec2(circle.radius * 2.f),
circle.radius);
}
ASolidBrush { AColor::BLACK }, circle.position - circle.radius, glm::vec2(circle.radius * 2.f),
circle.radius, 1);
}
}
void onPointerMove(glm::vec2 pos,
const APointerMoveEvent& event)
override {
mHoveredCircle = [&] {
Circle* result = nullptr;
float nearestDistanceToCursor = std::numeric_limits<float>::max();
for (auto& circle : mState->circles.raw) {
float distanceToCursor = glm::distance2(circle.position, pos);
if (distanceToCursor > nearestDistanceToCursor) {
continue;
}
if (distanceToCursor > circle.radius * circle.radius) {
continue;
}
result = &circle;
nearestDistanceToCursor = distanceToCursor;
}
return result;
}();
}
protected:
auto circle = *mHoveredCircle;
if (circle == nullptr) {
return {};
}
return {
{},
{
.name = "Adjust radius...",
.onAction =
[this, circle] {
auto radiusPopup = _new<AWindow>(
"", 200_dp, 50_dp,
dynamic_cast<AWindow*
>(
AWindow::current()), WindowStyle::MODAL);
radiusPopup->setContents(Vertical {
Label { "Adjust diameter of circle at {}."_format(circle->position) },
it->setValue(circle->radius / MAX_RADIUS);
it->valueChanging, [this, circle](aui::float_within_0_1 s) {
circle->radius = s * MAX_RADIUS;
mState->circles.notify();
});
},
});
connect(radiusPopup->closed, [
this, circle, oldRadius = circle->radius] {
if (oldRadius == circle->radius) {
return;
}
class ActionChangeRadius : public IAction {
public:
ActionChangeRadius(Circle* circle, float prevRadius, float newRadius)
: mCircle(circle), mPrevRadius(prevRadius), mNewRadius(newRadius) {}
~ActionChangeRadius() override = default;
void undo() override {
mCircle->radius = mPrevRadius;
}
void redo() override {
mCircle->radius = mNewRadius;
}
private:
Circle* mCircle;
float mPrevRadius;
float mNewRadius;
};
mState->history.add(std::make_unique<ActionChangeRadius>(circle, oldRadius, circle->radius));
});
radiusPopup->show();
},
},
};
}
public:
if (event.
asButton != AInput::LBUTTON) {
return;
}
class ActionAddCircle : public IAction {
public:
ActionAddCircle(_<State> state, Circle circle) : mState(std::move(state)), mCircle(std::move(circle)) {}
~ActionAddCircle() override = default;
void undo() override {
mState->circles.writeScope()->pop_back();
}
void redo() override {
mState->circles.writeScope()->push_back(mCircle);
}
private:
_<State> mState;
Circle mCircle;
};
mState->history.add(std::make_unique<ActionAddCircle>(mState, Circle { .position = event.position }));
}
private:
};
class CircleDrawerWindow :
public AWindow {
public:
CircleDrawerWindow() : AWindow("AUI - 7GUIs - Circle Drawer", 300_dp, 250_dp) {
Centered {
Horizontal {
it & mState.history.nextAction.readProjected([&](UndoStack::Iterator i) { return i != mState.history.begin(); }) > &AView::setEnabled;
},
it & mState.history.nextAction.readProjected([&](UndoStack::Iterator i) { return i != mState.history.end(); }) > &AView::setEnabled;
},
},
},
});
}
private:
State mState;
void undo() {
mState.history.undo();
}
void redo() {
mState.history.redo();
}
};
_new<CircleDrawerWindow>()->show();
return 0;
}
void setContents(const _< AViewContainer > &container)
Moves (like via std::move) all children and layout of the specified container to this container.
Base class of all UI objects.
Definition AView.h:78
virtual void render(ARenderContext ctx)
Draws this AView. Noone should call this function except rendering routine.
virtual void onPointerMove(glm::vec2 pos, const APointerMoveEvent &event)
Handles pointer hover events.
virtual AMenuModel composeContextMenu()
Produce context (right click) menu.
virtual void onPointerReleased(const APointerReleasedEvent &event)
Called on pointer (mouse) released event.
Represents a window in the underlying windowing system.
Definition AWindow.h:45
static AWindowBase * current()
virtual void roundedRectangleBorder(const ABrush &brush, glm::vec2 position, glm::vec2 size, float radius, int borderWidth)=0
Draws rounded rectangle's border.
virtual void roundedRectangle(const ABrush &brush, glm::vec2 position, glm::vec2 size, float radius)=0
Draws rounded rect (with antialiasing, if msaa enabled).
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:179
@ HIDDEN_FROM_THIS
Like HIDDEN, but view's ASS-styled background is also affected by mask.
Definition AOverflow.h:40
static decltype(auto) connect(const Signal &signal, Object *object, Function &&function)
Connects signal to the slot of the specified object.
Definition AObject.h:86
#define let
Performs multiple operations on a single object without repeating its name (in place) This function c...
Definition kAUI.h:262
#define AUI_ENTRY
Application entry point.
Definition Entry.h:90
Button
Specifies button(s) to be displayed.
Definition AMessageBox.h:79
Pointing method press event.
Definition APointerReleasedEvent.h:19
AInput::Key asButton
pointerIndex treated as mouse button.
Definition APointerReleasedEvent.h:41
Basic easy-to-use property implementation containing T.
Definition AProperty.h:30
static _< T > fake(T *raw)
Creates fake shared pointer to T* raw with empty destructor, which does nothing. It's useful when som...
Definition SharedPtrTypes.h:429