|  | #pragma once
#include <list>
#include <memory>
#include "../ext/nanovg/src/nanovg.h"
#include "../ext/oui-blendish/blendish.h"
#include "../ext/nanosvg/src/nanosvg.h"
#include "math.hpp"
#include "util.hpp"
namespace rack {
////////////////////
// resources
////////////////////
// Constructing these directly will load from the disk each time. Use the load() functions to load from disk and cache them as long as the shared_ptr is held.
// Implemented in gui.cpp
struct Font {
	int handle;
	Font(const std::string &filename);
	~Font();
	static std::shared_ptr<Font> load(const std::string &filename);
};
struct Image {
	int handle;
	Image(const std::string &filename);
	~Image();
	static std::shared_ptr<Image> load(const std::string &filename);
};
struct SVG {
	NSVGimage *handle;
	SVG(const std::string &filename);
	~SVG();
	static std::shared_ptr<SVG> load(const std::string &filename);
};
////////////////////
// Base widget
////////////////////
/** A node in the 2D scene graph */
struct Widget {
	/** Stores position and size */
	Rect box = Rect(Vec(), Vec(INFINITY, INFINITY));
	Widget *parent = NULL;
	std::list<Widget*> children;
	bool visible = true;
	virtual ~Widget();
	Rect getChildrenBoundingBox();
	/**  Returns `v` transformed into the coordinate system of `relative` */
	virtual Vec getRelativeOffset(Vec v, Widget *relative);
	/** Returns `v` transformed into world coordinates */
	Vec getAbsoluteOffset(Vec v) {
		return getRelativeOffset(v, NULL);
	}
	/** Returns a subset of the given Rect bounded by the box of this widget and all ancestors */
	virtual Rect getViewport(Rect r);
	template <class T>
	T *getAncestorOfType() {
		if (!parent) return NULL;
		T *p = dynamic_cast<T*>(parent);
		if (p) return p;
		return parent->getAncestorOfType<T>();
	}
	template <class T>
	T *getFirstDescendantOfType() {
		for (Widget *child : children) {
			T *c = dynamic_cast<T*>(child);
			if (c) return c;
			c = child->getFirstDescendantOfType<T>();
			if (c) return c;
		}
		return NULL;
	}
	/** Adds widget to list of children.
	Gives ownership of widget to this widget instance.
	*/
	void addChild(Widget *widget);
	/** Removes widget from list of children if it exists.
	Does not delete widget but transfers ownership to caller
	Silently fails if widget is not a child
	*/
	void removeChild(Widget *widget);
	void clearChildren();
	/** Recursively finalizes event start/end pairs as needed */
	void finalizeEvents();
	/** Advances the module by one frame */
	virtual void step();
	/** Draws to NanoVG context */
	virtual void draw(NVGcontext *vg);
	// Events
	/** Called when a mouse button is pressed over this widget
	0 for left, 1 for right, 2 for middle.
	Return `this` to accept the event.
	Return NULL to reject the event and pass it to the widget behind this one.
	*/
	virtual Widget *onMouseDown(Vec pos, int button);
	virtual Widget *onMouseUp(Vec pos, int button);
	/** Called on every frame, even if mouseRel = Vec(0, 0) */
	virtual Widget *onMouseMove(Vec pos, Vec mouseRel);
	virtual Widget *onHoverKey(Vec pos, int key);
	/** Called when this widget begins responding to `onMouseMove` events */
	virtual void onMouseEnter() {}
	/** Called when another widget begins responding to `onMouseMove` events */
	virtual void onMouseLeave() {}
	virtual bool onFocus() {return false;}
	virtual void onDefocus() {}
	virtual bool onFocusText(int codepoint) {return false;}
	virtual bool onFocusKey(int key) {return false;}
	virtual Widget *onScroll(Vec pos, Vec scrollRel);
	/** Called when a widget responds to `onMouseDown` for a left button press */
	virtual void onDragStart() {}
	/** Called when the left button is released and this widget is being dragged */
	virtual void onDragEnd() {}
	/** Called when a widget responds to `onMouseMove` and is being dragged */
	virtual void onDragMove(Vec mouseRel) {}
	/** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */
	virtual void onDragEnter(Widget *origin) {}
	virtual void onDragLeave(Widget *origin) {}
	virtual void onDragDrop(Widget *origin) {}
	virtual void onAction() {}
	virtual void onChange() {}
	virtual void onZoom();
};
struct TransformWidget : Widget {
	/** The transformation matrix */
	float transform[6];
	TransformWidget();
	void identity();
	void translate(Vec delta);
	void rotate(float angle);
	void scale(Vec s);
	void draw(NVGcontext *vg) override;
};
struct ZoomWidget : Widget {
	float zoom = 1.0;
	Vec getRelativeOffset(Vec v, Widget *relative) override;
	Rect getViewport(Rect r) override;
	void setZoom(float zoom);
	void draw(NVGcontext *vg) override;
	Widget *onMouseDown(Vec pos, int button) override;
	Widget *onMouseUp(Vec pos, int button) override;
	Widget *onMouseMove(Vec pos, Vec mouseRel) override;
	Widget *onHoverKey(Vec pos, int key) override;
	Widget *onScroll(Vec pos, Vec scrollRel) override;
};
////////////////////
// Trait widgets
////////////////////
/** Widget that does not respond to events */
struct TransparentWidget : virtual Widget {
	Widget *onMouseDown(Vec pos, int button) override {return NULL;}
	Widget *onMouseUp(Vec pos, int button) override {return NULL;}
	Widget *onMouseMove(Vec pos, Vec mouseRel) override {return NULL;}
	Widget *onScroll(Vec pos, Vec scrollRel) override {return NULL;}
};
/** Widget that automatically responds to all mouse events but gives a chance for children to respond instead */
struct OpaqueWidget : virtual Widget {
	Widget *onMouseDown(Vec pos, int button) override {
		Widget *w = Widget::onMouseDown(pos, button);
		if (w) return w;
		onMouseDownOpaque(button);
		return this;
	}
	Widget *onMouseUp(Vec pos, int button) override {
		Widget *w = Widget::onMouseUp(pos, button);
		if (w) return w;
		onMouseUpOpaque(button);
		return this;
	}
	Widget *onMouseMove(Vec pos, Vec mouseRel) override {
		Widget *w = Widget::onMouseMove(pos, mouseRel);
		if (w) return w;
		onMouseMoveOpaque(mouseRel);
		return this;
	}
	Widget *onScroll(Vec pos, Vec scrollRel) override {
		Widget *w = Widget::onScroll(pos, scrollRel);
		if (w) return w;
		if (onScrollOpaque(scrollRel))
			return this;
		return NULL;
	}
	/** "High level" events called by the above lower level events.
	Use these if you don't care about the clicked position.
	*/
	virtual void onMouseDownOpaque(int button) {}
	virtual void onMouseUpOpaque(int button) {}
	virtual void onMouseMoveOpaque(Vec mouseRel) {}
	virtual bool onScrollOpaque(Vec scrollRel) {return false;}
};
struct SpriteWidget : virtual Widget {
	Vec spriteOffset;
	Vec spriteSize;
	std::shared_ptr<Image> spriteImage;
	int index = 0;
	void draw(NVGcontext *vg) override;
};
struct SVGWidget : virtual Widget {
	std::shared_ptr<SVG> svg;
	/** Sets the box size to the svg image size */
	void wrap();
	void draw(NVGcontext *vg) override;
};
/** Caches a widget's draw() result to a framebuffer so it is called less frequently
When `dirty` is true, its children will be re-rendered on the next call to step() override.
Events are not passed to the underlying scene.
*/
struct FramebufferWidget : virtual Widget {
	/** Set this to true to re-render the children to the framebuffer the next time it is drawn */
	bool dirty = true;
	/** A margin in pixels around the children in the framebuffer
	This prevents cutting the rendered SVG off on the box edges.
	*/
	float oversample;
	/** The root object in the framebuffer scene
	The FramebufferWidget owns the pointer
	*/
	struct Internal;
	Internal *internal;
	FramebufferWidget();
	~FramebufferWidget();
	void draw(NVGcontext *vg) override;
	int getImageHandle();
	void onZoom() override;
};
struct QuantityWidget : virtual Widget {
	float value = 0.0;
	float minValue = 0.0;
	float maxValue = 1.0;
	float defaultValue = 0.0;
	std::string label;
	/** Include a space character if you want a space after the number, e.g. " Hz" */
	std::string unit;
	/** The decimal place to round for displaying values.
	A precision of 2 will display as "1.00" for example.
	*/
	int precision = 2;
	QuantityWidget();
	void setValue(float value);
	void setLimits(float minValue, float maxValue);
	void setDefaultValue(float defaultValue);
	/** Generates the display value */
	std::string getText();
};
////////////////////
// GUI widgets
////////////////////
struct Label : Widget {
	std::string text;
	Label() {
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override;
};
// Deletes itself from parent when clicked
struct MenuOverlay : OpaqueWidget {
	void onDragDrop(Widget *origin) override;
	bool onScrollOpaque(Vec scrollRel) override {return true;}
	Widget *onHoverKey(Vec pos, int key) override;
};
struct MenuEntry;
struct Menu : OpaqueWidget {
	Menu *parentMenu = NULL;
	Menu *childMenu = NULL;
	/** The entry which created the child menu */
	MenuEntry *activeEntry = NULL;
	Menu() {
		box.size = Vec(0, 0);
	}
	~Menu();
	// Resizes menu and calls addChild()
	void pushChild(Widget *child);
	void setChildMenu(Menu *menu);
	void step() override;
	void draw(NVGcontext *vg) override;
	bool onScrollOpaque(Vec scrollRel) override;
};
struct MenuEntry : OpaqueWidget {
	std::string text;
	std::string rightText;
	MenuEntry() {
		box.size = Vec(0, BND_WIDGET_HEIGHT);
	}
	void step() override;
};
struct MenuLabel : MenuEntry {
	void draw(NVGcontext *vg) override;
};
struct MenuItem : MenuEntry {
	void draw(NVGcontext *vg) override;
	virtual Menu *createChildMenu() {return NULL;}
	void onMouseEnter() override;
	void onDragDrop(Widget *origin) override;
};
struct Button : OpaqueWidget {
	std::string text;
	BNDwidgetState state = BND_DEFAULT;
	Button() {
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override;
	void onMouseEnter() override;
	void onMouseLeave() override;
	void onDragStart() override;
	void onDragEnd() override;
	void onDragDrop(Widget *origin) override;
};
struct ChoiceButton : Button {
	void draw(NVGcontext *vg) override;
};
struct RadioButton : OpaqueWidget, QuantityWidget {
	BNDwidgetState state = BND_DEFAULT;
	RadioButton() {
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override;
	void onMouseEnter() override;
	void onMouseLeave() override;
	void onDragDrop(Widget *origin) override;
};
struct Slider : OpaqueWidget, QuantityWidget {
	BNDwidgetState state = BND_DEFAULT;
	Slider() {
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override;
	void onDragStart() override;
	void onDragMove(Vec mouseRel) override;
	void onDragEnd() override;
	void onMouseDownOpaque(int button) override;
};
/** Parent must be a ScrollWidget */
struct ScrollBar : OpaqueWidget {
	enum { VERTICAL, HORIZONTAL } orientation;
	BNDwidgetState state = BND_DEFAULT;
	ScrollBar() {
		box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT);
	}
	void draw(NVGcontext *vg) override;
	void onDragStart() override;
	void onDragMove(Vec mouseRel) override;
	void onDragEnd() override;
};
/** Handles a container with ScrollBar */
struct ScrollWidget : OpaqueWidget {
	Widget *container;
	ScrollBar *horizontalScrollBar;
	ScrollBar *verticalScrollBar;
	Vec offset;
	ScrollWidget();
	void step() override;
	bool onScrollOpaque(Vec scrollRel) override;
};
struct TextField : OpaqueWidget {
	std::string text;
	std::string placeholder;
	bool multiline = false;
	int begin = 0;
	int end = 0;
	TextField() {
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override;
	Widget *onMouseDown(Vec pos, int button) override;
	bool onFocusText(int codepoint) override;
	bool onFocusKey(int key) override;
	bool onFocus() override;
	void insertText(std::string newText);
	virtual void onTextChange() {}
};
struct PasswordField : TextField {
	void draw(NVGcontext *vg) override;
};
struct ProgressBar : TransparentWidget, QuantityWidget {
	ProgressBar() {
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override;
};
struct Tooltip : Widget {
	void step() override;
	void draw(NVGcontext *vg) override;
};
struct Scene : OpaqueWidget {
	Widget *overlay = NULL;
	void setOverlay(Widget *w);
	Menu *createMenu();
	void step() override;
};
////////////////////
// globals
////////////////////
extern Widget *gHoveredWidget;
extern Widget *gDraggedWidget;
extern Widget *gDragHoveredWidget;
extern Widget *gFocusedWidget;
extern Scene *gScene;
} // namespace rack
 |