Newer
Older
invertedlogic / InvertedLogic / iLFramework / toolkit / include / Widget.h
@John Ryland John Ryland on 10 Nov 2019 4 KB rename
#ifndef WIDGET_H
#define WIDGET_H


#include <list>
#include "Graphics.h"
#include "Property.h"
#include "Events.h"
#include "XmlParser.h"


#include "Namespace.h"
BEGIN_NAMESPACE


enum WidgetFlags
{
	WF_None = 0,
	WF_EraseBackground = 1 << 0
};
ENUM_AS_FLAGS(WidgetFlags)


enum MouseState 
{
	MS_Up,
	MS_Down,
	MS_DoubleClick
};


class PaintTarget
{
public:
	virtual ~PaintTarget() {}
	virtual CUTE_PaintTarget& targetBuffer() = 0;
};


/*
enum SizeFlags
{
		SF_None,
		SF_CanGrow,
		SF_CanShrink,
		SF_
		SF_Greedy,
};


enum SizePolicy
{
	//SP_Fixed,        // Only the returned fixed size value is to be used
	SP_Minimum,		 // It can be larger, but it does not require to be larger
	SP_Preferred,	 // The returned value is best but smaller or larger is fine
	SP_Maximum,		 // It can safely be smaller but can not be larger than the provided value
	SP_Expanding
};
*/

struct SizeOptions
{
	// For a fixed size, set min, preferred and max values to the same values
	// For expanding, set min and preferred to the min value and max to a very large number
	// For shrinking, set max and preferred to the max value and min to 0
	Size m_minimum;		// value that size will not be smaller than
	Size m_preferred;	// ideal size
	Size m_maximum;		// value that size will not be larger than
	//int m_policyX, m_policyY;            // hint for 

	// Algorithm
	//   For dimension being shared across widgets
	//		First try to use the preferred values summed together and compare against space
	//		It will be equal, under or over. For equal, accept the preferred values and done.
	//		If over or under, divide this by the number of widgets and try to distriubte
	//		this while still keeping within the constraints. Keep track of how many widgets
	//		that this is not in their constraints and by how much and sum this up. Now
	//		work out the count of widgets we can shrink/grow within their constraints and
	//		divide out the amount we can distribute to them. If we get to the point that
	//		we can't meet all the constraints, we will need to either force the parent
	//		to change it's size to be larger (some how need to make sure that doesn't happen)
	//		or add padding evenly to the widgets to space them out equally
};


class Widget : public PaintTarget
{
public:
	Widget(Widget* a_parent, bool a_layoutDirection, int a_x, int a_y, int a_width, int a_height);
	virtual ~Widget();

	virtual void sizeOptions(SizeOptions& a_sizeOptions);

	virtual void sizeEvent(SizeEvent& a_event);
	virtual void paintEvent(PaintEvent& a_event);
	virtual void timerEvent(TimerEvent& a_event);
	virtual void keyEvent(KeyEvent& a_event);
	virtual void mouseEvent(MouseEvent& a_event);
	virtual void mouseEnterEvent(MouseEvent& a_event);
	virtual void mouseLeaveEvent(MouseEvent& a_event);
	virtual void wheelEvent(WheelEvent& a_event);

	virtual void event(Event& a_event);

	virtual void repaint();
	virtual void update(Rectangle& a_rectangle);

	int width();
	int height();

	void setGeometry(int a_x, int a_y, int a_width, int a_height);
	Rectangle rectangle() // could rename to geometry,  perhaps could make it a property
	{
		Rectangle r = { {{0, 0}}, {{width(), height()}} }; return r;
	}

	void eraseBackground(int i = 0);

	virtual TimerId startTimer(int a_milliSeconds);

	virtual void killTimer(TimerId a_timerId);

	CUTE_PaintTarget& targetBuffer()
	{
		return m_target;
	}

	// We expose this here publically, and as a concrete Property implementaion
	// as it is a simple type and it is concrete to the widget, eg the variable
	// belongs to widgets, so it makes sense in this case that it is a Property.
	Property<WidgetFlags>   flags;
	Property<uint32_t>      backgroundBrush;
	Property<int>           layoutSpacing;
	Property<int>           layoutMargin;

protected:
	void updateLayout();

private:
	void updateTarget();

	Widget*              m_parent;
	CUTE_PaintTarget     m_target;
	int                  m_x, m_y; // offsets from parent
	int                  m_windowX, m_windowY; // offsets from window
	int                  m_goalWidth, m_goalHeight; // these could be clamped to lower values if out of the window
								// TODO: probably not handling the case of geometry being set going off the left
								// or the top of the window (with child partially inside the window)
								// Off to the right or going off the bottom is handled by the clamping
	bool				 m_watchingMouse;
	bool				 m_mouseEntered;

	void addChild(Widget*);
	bool				 m_layoutDirection;
	std::list<Widget*>   m_children;
};


END_NAMESPACE


#endif // WIDGET_H