diff --git a/.gitignore b/.gitignore index 5589e10..f287c36 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /*.exe /*.so /*.dll +compile_flags.txt diff --git a/examples/a.out b/examples/a.out new file mode 100755 index 0000000..41e5acd Binary files /dev/null and b/examples/a.out differ diff --git a/examples/example.cpp b/examples/example.cpp new file mode 100644 index 0000000..b67783a --- /dev/null +++ b/examples/example.cpp @@ -0,0 +1,105 @@ +// g++ example.cpp -I ../include/ -lMw + +#include +#include + +mw::Widget *window, *button, *button2, *button3, *button4, *button5, *button6; + +void handler(MwWidget handle, void *user_data, void *call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + printf("hello world!\n"); +} + +void handler_theme(MwWidget handle, void *user_data, void *call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + window->apply(MwNdarkTheme, window->get_integer(MwNdarkTheme) == 0 ? 1 : 0, + NULL); +} + +void handler_look(MwWidget handle, void *user_data, void *call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + window->apply(MwNmodernLook, window->get_integer(MwNmodernLook) == 0 ? 1 : 0, + NULL); +} + +void handler_font(MwWidget handle, void *user_data, void *call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + window->apply(MwNbitmapFont, window->get_integer(MwNbitmapFont) == 0 ? 1 : 0, + NULL); +} + +void resize(MwWidget handle, void *user_data, void *call_data) { + unsigned int w, h, mh; + + (void)user_data; + (void)call_data; + + w = MwGetInteger(handle, MwNwidth); + h = MwGetInteger(handle, MwNheight); + + button->apply(MwNy, 50 + mh, MwNwidth, (w - 50 * 2) / 3, MwNheight, + h - 125 - 50 * 3); + + button2->apply(MwNx, 50 + (w - 50 * 2) / 3, MwNy, 50 + mh, MwNwidth, + (w - 50 * 2) / 3, MwNheight, h - 125 - 50 * 3); + + button3->apply(MwNx, 50 + (w - 50 * 2) / 3 * 2, MwNy, 50 + mh, MwNwidth, + (w - 50 * 2) / 3, MwNheight, h - 125 - 50 * 3); + + button4->apply(MwNx, 50 + (w - 50 * 2) / 3 * 0, MwNy, h - 50 - 125 + mh, + MwNwidth, (w - 50 * 2) / 3); + + button5->apply(MwNx, 50 + (w - 50 * 2) / 3 * 1, MwNy, h - 50 - 125 + mh, + MwNwidth, (w - 50 * 2) / 3); + + button6->apply(MwNx, 50 + (w - 50 * 2) / 3 * 2, MwNy, h - 50 - 125 + mh, + MwNwidth, (w - 50 * 2) / 3); +} + +int main() { + MwMenu m, m2; + + MwLibraryInit(); + + window = new mw::Window("main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, + MwNtitle, "hello world"); + // menu = new mw::Menu("menu", window, 0, 0, 0, 0); + button = new mw::Button("button", window, 50, 50, 100, 125, MwNtext, "theme"); + button2 = + new mw::Button("button", window, 150, 50, 100, 125, MwNtext, "look"); + button3 = + new mw::Button("button", window, 250, 50, 100, 125, MwNtext, "font"); + button4 = new mw::Button("button", window, 50, 225, 100, 125, MwNtext, + "lorem ipsum", MwNbackground, "#f66", MwNforeground, + "#000"); + button5 = new mw::Button("button", window, 150, 225, 100, 125, MwNtext, + "lorem ipsum", MwNbackground, "#6f6", MwNforeground, + "#000"); + button6 = new mw::Button("button", window, 250, 225, 100, 125, MwNtext, + "lorem ipsum", MwNbackground, "#66f", MwNforeground, + "#000"); + + window->add_user_handler(MwNresizeHandler, resize, NULL); + button->add_user_handler(MwNactivateHandler, handler_theme, NULL); + button2->add_user_handler(MwNactivateHandler, handler_look, NULL); + button3->add_user_handler(MwNactivateHandler, handler_font, NULL); + button4->add_user_handler(MwNactivateHandler, handler, NULL); + button5->add_user_handler(MwNactivateHandler, handler, NULL); + button6->add_user_handler(MwNactivateHandler, handler, NULL); + + // resize(window, NULL, NULL); + + window->loop(); +} diff --git a/include/mwcxx/widget.hpp b/include/mwcxx/widget.hpp new file mode 100644 index 0000000..d05735a --- /dev/null +++ b/include/mwcxx/widget.hpp @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mw { + +struct va_separator {}; // Empty; ABI may elide allocation. + +class Widget { +protected: + ::MwWidget mWidget = NULL; + Widget() : mWidget(nullptr) {}; + Widget(::MwWidget w) : mWidget(w) {}; + + template + void create(std::string name, Widget *parent, int x, int y, + unsigned int width, unsigned int height, Args &&...args) { + mWidget = ::MwVaCreateWidget(this->get_class(), name.c_str(), + parent ? parent->mWidget : nullptr, x, y, + width, height, std::forward(args)...); + }; + +public: + virtual ~Widget() { + if (mWidget) + ::MwDestroyWidget(mWidget); + } + + /*! + * @brief Executes a method specific to the widget (varadic version). + * @warning Prefer using corresponding functions for better code clarity + * and type safety. + * @param func_name Function name + * @param ... Widget function arguments. + */ + template + void execute(std::string func_name, void *out, Args &&...a) { + ::MwVaListWidgetExecute(this->mWidget, func_name.c_str(), out, a..., NULL); + }; + + /*! + * @brief Runs the main loop + */ + void loop() { ::MwLoop(mWidget); } + + /*! + * @brief Runs the single step + * @return `0` if successful + */ + int step() { return ::MwStep(mWidget); }; + + /*! + * @brief Check if any event is pending + * @return `1` if any event is pending + */ + int pending() { return ::MwPending(mWidget); }; + + /*! + * @brief Sets an integer property + * @param key Key + * @param n Value + */ + void set_integer(std::string key, int n) { + ::MwSetInteger(mWidget, key.c_str(), n); + }; + + /*! + * @brief Sets a text property + * @param key Key + * @param value Value + */ + void set_text(std::string key, std::string value) { + ::MwSetText(mWidget, key.c_str(), value.c_str()); + }; + + /*! + * @brief Sets a void pointer property + * @param key Key + * @param value Value + */ + void set_void(std::string key, void *value) { + ::MwSetVoid(mWidget, key.c_str(), value); + }; + + /*! + * @brief Gets the integer property + * @param key Key + * @return Value + */ + int get_integer(std::string key) { + return ::MwGetInteger(mWidget, key.c_str()); + }; + + /*! + * @brief Gets the text property + * @param key Key + * @return Value + */ + std::string get_text(std::string key) { + return std::string(::MwGetText(mWidget, key.c_str())); + }; + + /*! + * @brief Gets the void pointer property + * @param key Key + * @return Value + */ + void *get_void(std::string key) { return ::MwGetVoid(mWidget, key.c_str()); }; + + /*! + * @brief Sets the default property + * @warning This is called when widget is created + */ + void set_default() { ::MwSetDefault(mWidget); }; + + /*! + * @brief Sets the properties + * @param ... Properties + */ + template void apply(Args &&...a) { + ::MwVaApply(mWidget, a..., NULL); + }; + + /*! + * @brief Sets a user handler + * @param key Key + * @param handler Handler + * @param user_data User data passed to handler + */ + void add_user_handler(const char *key, MwUserHandler handler, + void *user_data) { + ::MwAddUserHandler(mWidget, key, handler, user_data); + }; + + /*! + * @brief Dispatches the user handler + * @param key Key + * @param handler_data Handler data passed to handler + */ + void dispatch_user_handler(std::string key, void *handler_data) { + ::MwDispatchUserHandler(mWidget, key.c_str(), handler_data); + }; + + /*! + * @brief Gets the before_step of widget + * @param jmpbuf jmp_buf + */ + void get_before_step(jmp_buf *jmpbuf) { ::MwGetBeforeStep(mWidget, jmpbuf); }; + + /*! + * @brief Forcefully makes widget render + */ + void force_render() { ::MwForceRender(mWidget); }; + + /*! + * @brief Adds an widget to tick handler list + */ + void add_tick_list() { ::MwAddTickList(mWidget); }; + + /*! + * @brief Focus the widget + */ + void focus() { ::MwFocus(mWidget); }; + + /*! + * @brief Grabs the pointer + * @param toggle Toggle + */ + void grab_pointer(int toggle) { ::MwGrabPointer(mWidget, toggle); }; + + /*! + * @brief Hides the cursor + */ + void hide_cursor() { ::MwHideCursor(mWidget); }; + + /*! + * @brief Toggles the dark theme + * @param toggle Toggle + * @deprecated Use NdarkTheme instead + */ + void set_dark_theme(bool toggle) { ::MwSetDarkTheme(mWidget, toggle); }; + + /*! + * @brief Gets the parent widget + * @return Parent widget + */ + /*class WidgetHandle get_parent() { + return WidgetHandle(::MwGetParent(mWidget)) + };*/ + + /*! + * @brief Show widget + * @param toggle Toggle + */ + void show(bool toggle) { ::MwShow(mWidget, toggle); }; + + /*! + * @brief Reparents widget + * @param new_parent New parent + */ + void reparent(Widget *new_parent) { + ::MwReparent(mWidget, new_parent->mWidget); + }; + + /*! + * @brief Gets class of widget + * @return Class + */ + virtual ::MwClass get_class() = 0; + + /*! + * @brief Gets name of widget + * @return Name + */ + std::string get_name() { return ::MwGetName(mWidget); }; + + // /*! + // * @brief Gets children of widget + // * @return Children (NULL-terminated array) + // */ + // std::vector get_children(); + + /*! + * @brief Gets the cursor coordinate + * @param point Point + */ + ::MwPoint get_cursor_coord() { + ::MwPoint p; + ::MwGetCursorCoord(mWidget, &p); + return p; + }; + + /*! + * @brief Gets the screen size + * @return rect Rectangle + */ + ::MwRect get_screen_size() { + ::MwRect r; + ::MwGetScreenSize(mWidget, &r); + return r; + }; + + /*! + * @brief Reports whether a widget reports global or local coordinates upon + * GetXY/SetXY. Anything with a parent reports local, and most backends report + * global coordinates being supported for top level windows, but some + * (Wayland) do not. + */ + int get_coordinate_type() { return ::MwGetCoordinateType(mWidget); }; + + /*! + * @brief Queue to get clipboard content. + * @param clipboard_type The Clipboard Type to get. See ClipboardType. This is + * ignored on backends that aren't X11/Wayland, so if you're unsure, just use + * ClipboardMain + */ + void get_clipboard(int clipboard_type) { + return ::MwGetClipboard(mWidget, clipboard_type); + }; +}; + +#define WCLASS(a) \ + ::MwClass get_class() override { return Mw##a##Class; }; \ + \ +public: \ + template \ + a(std::string name, Widget *parent, int x, int y, unsigned int width, \ + unsigned int height, Args... args) { \ + printf("%d\n", width); \ + this->create(name, parent, x, y, width, height, \ + std::forward(args)..., NULL); \ + assert(mWidget); \ + } + +class WidgetHandle : public Widget { +public: + ::MwClass get_class() override { return ::MwGetClass(mWidget); }; +}; + +class Box : public Widget { + WCLASS(Box) +}; +class Button : public Widget { + WCLASS(Button) +}; +class CheckBox : public Widget { + WCLASS(CheckBox) +}; +class ComboBox : public Widget { + WCLASS(ComboBox) +}; +class Entry : public Widget { + WCLASS(Entry) +}; +class Frame : public Widget { + WCLASS(Frame) +}; +class Image : public Widget { + WCLASS(Image) +}; +class Label : public Widget { + WCLASS(Label) +}; +class ListBox : public Widget { + WCLASS(ListBox) +}; +class Menu : public Widget { + WCLASS(Menu) +}; +class NumberEntry : public Widget { + WCLASS(NumberEntry) +}; +class OpenGL : public Widget { + WCLASS(OpenGL) +}; +class ProgressBar : public Widget { + WCLASS(ProgressBar) +}; +class RadioBox : public Widget { + WCLASS(RadioBox) +}; +class ScrollBar : public Widget { + WCLASS(ScrollBar) +}; +class Separator : public Widget { + WCLASS(Separator) +}; +class SubMenu : public Widget { + WCLASS(SubMenu) +}; +class TreeView : public Widget { + WCLASS(TreeView) +}; +class Viewport : public Widget { + WCLASS(Viewport) +}; +class Vulkan : public Widget { + WCLASS(Vulkan) +}; +class Window : public Widget { + WCLASS(Window) +}; + +} // namespace mw