From 4ddd7d04b5e670d63175c4bd32b75f6539496227 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 7 Dec 2021 22:00:41 +0100 Subject: [PATCH] Overhaul the C++ GUI API so it actually looks reasonable. --- src/gui/main.cc | 22 +++--- src/gui/uipp.h | 191 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 162 insertions(+), 51 deletions(-) diff --git a/src/gui/main.cc b/src/gui/main.cc index 082e9e3c..68c2811f 100644 --- a/src/gui/main.cc +++ b/src/gui/main.cc @@ -54,18 +54,20 @@ int main(int argc, const char* argv[]) uiMenuItem* item = uiMenuAppendQuitItem(menu); uiOnShouldQuit(quit_cb, NULL); - MainWindow window; + UIAllocator a; + + auto window = + a.make() + ->setChild( + a.make() + ->add(a.make("press me!")->build()) + ->add(a.make()->setStretchy(true)->build()) + ->add(a.make("press me again!")->build()) + ->build()) + ->build(); uiOnShouldQuit(quit_cb, NULL); - UIVBox vbox; - UIHBox hbox; - vbox.append(hbox); - window.setChild(vbox); - - MainArea area; - vbox.append(area, true); - - window.show(); + window->show(); uiMain(); return 0; } diff --git a/src/gui/uipp.h b/src/gui/uipp.h index 0e1dd893..0fddb945 100644 --- a/src/gui/uipp.h +++ b/src/gui/uipp.h @@ -77,17 +77,17 @@ private: class UIControl { public: - UIControl(uiControl* control): - _control(control), - _owned(true) - {} - ~UIControl() { - if (_owned) + if (_owned && _control) uiControlDestroy(_control); } + void setControl(uiControl* control) + { + _control = control; + } + uiControl* control() const { return _control; @@ -99,67 +99,114 @@ public: return _control; } + virtual UIControl* build() = 0; + + bool stretchy() const + { + return _stretchy; + } + + UIControl* setStretchy(bool stretchy) + { + _stretchy = stretchy; + return this; + } + + bool built() const + { + return !!_control; + } + private: - uiControl* _control; - bool _owned; + uiControl* _control = nullptr; + bool _owned = true; + bool _stretchy = false; }; -template +template class UITypedControl : public UIControl { public: - UITypedControl(T* control): - UIControl(uiControl(control)) - {} + void setControl(T* control) + { + UIControl::setControl(uiControl(control)); + } - T* self() const + T* typedControl() const { return (T*) control(); } }; -class UIBox : public UITypedControl +template +class UIContainerControl : public UITypedControl { public: - UIBox(uiBox* box): - UITypedControl(box) - {} - - UIBox& append(UIControl& control, bool stretchy=false) + B* add(UIControl* child) { - uiBoxAppend(self(), control.claim(), stretchy); - return *this; + _children.push_back(child); + return (B*) this; + } + + const std::vector& children() const { return _children; } + +private: + std::vector _children; +}; + +template +class UIBox : public UIContainerControl +{ +public: + UIBox* build() + { + for (auto& child : this->children()) + uiBoxAppend(this->typedControl(), child->claim(), child->stretchy()); + return this; } }; -class UIHBox : public UIBox +class UIHBox : public UIBox { public: - UIHBox(): - UIBox(uiNewHorizontalBox()) - {} + UIHBox* build() + { + setControl(uiNewHorizontalBox()); + UIBox::build(); + return this; + } }; -class UIVBox : public UIBox +class UIVBox : public UIBox { public: - UIVBox(): - UIBox(uiNewVerticalBox()) - {} + UIVBox* build() + { + setControl(uiNewVerticalBox()); + UIBox::build(); + return this; + } }; -class UIArea : public UITypedControl +class UIArea : public UITypedControl { public: UIArea(): - UITypedControl(uiNewArea(&_handler)), _selfptr(this) {} - virtual void onRedraw(uiAreaDrawParams* params) + UIArea* build() { + setControl(uiNewArea(&_handler)); + return this; } + virtual void onRedraw(uiAreaDrawParams* params) {} + virtual void onMouseEvent(uiAreaMouseEvent* event) {} + virtual void onMouseEntryExit(bool exit) {} + virtual void onDragBroken() {} + virtual int onKeyEvent(uiAreaKeyEvent* event) { return 0; } + private: static UIArea* _getarea(uiAreaHandler* a) { @@ -173,21 +220,26 @@ private: static void _mouse_event_cb(uiAreaHandler* a, uiArea* area, uiAreaMouseEvent* event) { + _getarea(a)->onMouseEvent(event); } static void _mouse_crossed_cb(uiAreaHandler* a, uiArea* area, int left) { + _getarea(a)->onMouseEntryExit(!left); } static void _drag_broken_cb(uiAreaHandler* a, uiArea* area) { + _getarea(a)->onDragBroken(); } static int _key_event_cb(uiAreaHandler* a, uiArea* area, uiAreaKeyEvent* event) { - return 0; + return _getarea(a)->onKeyEvent(event); } + /* These two fields must be next to each other to allow _getarea to find the area + * instance pointer. */ uiAreaHandler _handler = { _draw_cb, _mouse_event_cb, @@ -198,25 +250,34 @@ private: UIArea* _selfptr; }; -class UIWindow : public UITypedControl +class UIWindow : public UITypedControl { public: UIWindow(const std::string& title, double width, double height): - UITypedControl(uiNewWindow(title.c_str(), width, height, 1)) + _title(title), + _width(width), + _height(height) + {} + + UIWindow* build() { - uiWindowOnClosing(self(), _close_cb, this); + setControl(uiNewWindow(_title.c_str(), _width, _height, 1)); + uiWindowOnClosing(this->typedControl(), _close_cb, this); + if (_child) + uiWindowSetChild(this->typedControl(), _child->claim()); + return this; } - UIWindow& setChild(UIControl& control) + UIWindow* setChild(UIControl* child) { - uiWindowSetChild(self(), control.claim()); - return *this; + _child = child; + return this; } - UIWindow& show() + UIWindow* show() { uiControlShow(claim()); - return *this; + return this; } virtual int onClose() @@ -229,6 +290,54 @@ private: { return ((UIWindow*)ptr)->onClose(); } + +private: + std::string _title; + double _width; + double _height; + UIControl* _child = nullptr; +}; + +class UIButton : public UITypedControl +{ +public: + UIButton(const std::string& text): + _text(text) + {} + + UIButton* build() + { + setControl(uiNewButton(_text.c_str())); + uiButtonOnClicked(this->typedControl(), _clicked_cb, this); + return this; + } + + virtual void onClick() {} + +private: + static void _clicked_cb(uiButton*, void* ptr) + { + ((UIButton*)ptr)->onClick(); + } + +private: + std::string _text; +}; + +class UIAllocator +{ +public: + template + T* make(Args&&... args) + { + auto uptr = std::make_unique(args...); + T* ptr = uptr.get(); + _pointers.push_back(std::move(uptr)); + return ptr; + } + +private: + std::vector> _pointers; }; #endif