|  | #pragma once
#include <list>
#include <memory>
#include "nanovg.h"
#include "nanosvg.h"
#include "util/common.hpp"
#include "events.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 window.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
Never inherit from Widget directly. Instead, inherit from VirtualWidget declared below.
*/
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();
	virtual 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 void onMouseDown(EventMouseDown &e);
	virtual void onMouseUp(EventMouseUp &e);
	/** Called on every frame, even if mouseRel = Vec(0, 0) */
	virtual void onMouseMove(EventMouseMove &e);
	virtual void onHoverKey(EventHoverKey &e);
	/** Called when this widget begins responding to `onMouseMove` events */
	virtual void onMouseEnter(EventMouseEnter &e) {}
	/** Called when another widget begins responding to `onMouseMove` events */
	virtual void onMouseLeave(EventMouseLeave &e) {}
	virtual void onFocus(EventFocus &e) {}
	virtual void onDefocus(EventDefocus &e) {}
	virtual void onText(EventText &e) {}
	virtual void onKey(EventKey &e) {}
	virtual void onScroll(EventScroll &e);
	/** Called when a widget responds to `onMouseDown` for a left button press */
	virtual void onDragStart(EventDragStart &e) {}
	/** Called when the left button is released and this widget is being dragged */
	virtual void onDragEnd(EventDragEnd &e) {}
	/** Called when a widget responds to `onMouseMove` and is being dragged */
	virtual void onDragMove(EventDragMove &e) {}
	/** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */
	virtual void onDragEnter(EventDragEnter &e) {}
	virtual void onDragLeave(EventDragEnter &e) {}
	virtual void onDragDrop(EventDragDrop &e) {}
	virtual void onPathDrop(EventPathDrop &e);
	virtual void onAction(EventAction &e) {}
	virtual void onChange(EventChange &e) {}
	virtual void onZoom(EventZoom &e);
	/** Helper function for creating and initializing a Widget with certain arguments (in this case just the position).
	In this project, you will find this idiom everywhere, as an easier alternative to constructor arguments, for building a Widget (or a subclass) with a one-liner.
	Example:
		addChild(Widget::create<SVGWidget>(Vec(0, 0)))
	*/
	template <typename T = Widget>
	static T *create(Vec pos) {
		T *o = new T();
		o->box.pos = pos;
		return o;
	}
};
/** Instead of inheriting from Widget directly, inherit from VirtualWidget to guarantee that only one copy of Widget's member variables are used by each instance of the Widget hierarchy.
*/
struct VirtualWidget : virtual Widget {};
struct TransformWidget : VirtualWidget {
	/** The transformation matrix */
	float transform[6];
	TransformWidget();
	Rect getChildrenBoundingBox() override;
	void identity();
	void translate(Vec delta);
	void rotate(float angle);
	void scale(Vec s);
	void draw(NVGcontext *vg) override;
};
struct ZoomWidget : VirtualWidget {
	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;
	void onMouseDown(EventMouseDown &e) override;
	void onMouseUp(EventMouseUp &e) override;
	void onMouseMove(EventMouseMove &e) override;
	void onHoverKey(EventHoverKey &e) override;
	void onScroll(EventScroll &e) override;
	void onPathDrop(EventPathDrop &e) override;
};
////////////////////
// Trait widgets
////////////////////
/** Widget that does not respond to events */
struct TransparentWidget : VirtualWidget {
	void onMouseDown(EventMouseDown &e) override {}
	void onMouseUp(EventMouseUp &e) override {}
	void onMouseMove(EventMouseMove &e) override {}
	void onScroll(EventScroll &e) override {}
};
/** Widget that automatically responds to all mouse events but gives a chance for children to respond instead */
struct OpaqueWidget : VirtualWidget {
	void onMouseDown(EventMouseDown &e) override {
		Widget::onMouseDown(e);
		if (!e.target)
			e.target = this;
		e.consumed = true;
	}
	void onMouseUp(EventMouseUp &e) override {
		Widget::onMouseUp(e);
		if (!e.target)
			e.target = this;
		e.consumed = true;
	}
	void onMouseMove(EventMouseMove &e) override {
		Widget::onMouseMove(e);
		if (!e.target)
			e.target = this;
		e.consumed = true;
	}
	void onScroll(EventScroll &e) override {
		Widget::onScroll(e);
		e.consumed = true;
	}
};
struct SpriteWidget : VirtualWidget {
	Vec spriteOffset;
	Vec spriteSize;
	std::shared_ptr<Image> spriteImage;
	int index = 0;
	void draw(NVGcontext *vg) override;
};
struct SVGWidget : VirtualWidget {
	std::shared_ptr<SVG> svg;
	/** Sets the box size to the svg image size */
	void wrap();
	/** Sets and wraps the SVG */
	void setSVG(std::shared_ptr<SVG> svg);
	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 : VirtualWidget {
	/** 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(EventZoom &e) override;
};
/** A Widget representing a float value */
struct QuantityWidget : VirtualWidget {
	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();
};
////////////////////
// globals
////////////////////
extern Widget *gHoveredWidget;
extern Widget *gDraggedWidget;
extern Widget *gDragHoveredWidget;
extern Widget *gFocusedWidget;
extern Widget *gTempWidget;
} // namespace rack
 |