src/widget/widget.h
author KUDr
Sun, 04 Mar 2007 22:36:22 +0000
branchcpp_gui
changeset 6289 be3d8bd9fb02
parent 6287 e59240e63a90
child 6290 8078f7a3c8a0
permissions -rw-r--r--
(svn r9010) [cpp_gui] -Add: Sticky button widget
-Codechange: part of widget.h moved to separate file widget_types.h to minimize dependencies
/* $Id$ */

#ifndef WIDGET_H
#define WIDGET_H


#include <list>
#include <map>
#include "../macros.h"
#include "../string.h"
#include "../order.h"
#include "../rail.h"
#include "../airport.h"
#include "../misc/rect.hpp"
#include "../misc/countedptr.hpp"

#include "window_event_base.h"

enum FrameFlags {
	FR_NONE         = 0x00,
	FR_TRANSPARENT  = 0x01,  ///< Makes the background transparent if set
	FR_BORDERONLY   = 0x10,  ///< Draw border only, no background
	FR_LOWERED      = 0x20,  ///< If set the frame is lowered and the background color brighter (ie. buttons when pressed)
	FR_DARKENED     = 0x40,  ///< If set the background is darker, allows for lowered frames with normal background color when used with FR_LOWERED (ie. dropdown boxes)
	FR_BG_ONLY      = 0x80,  ///< If set only the background is drawn without any frame (labels and such)
};

DECLARE_ENUM_AS_BIT_SET(FrameFlags);

enum Anchors {
	PIN_NONE     = 0x00,
	PIN_LEFT     = 0x01,
	PIN_TOP      = 0x02,
	PIN_RIGHT    = 0x04,
	PIN_BOTTOM   = 0x08,
};

DECLARE_ENUM_AS_BIT_SET(Anchors);

namespace gui {

enum FeatureFlags {
	FF_NONE                = 0,
	FF_NO_CAPTION_BAR      = (1 <<  0),
	FF_NO_CLOSE_BOX        = (1 <<  1),
	FF_NO_STICKY_BOX       = (1 <<  2),
	FF_NO_RESIZE_BOX       = (1 <<  3),
	FF_UNMOVABLE           = (1 <<  4),
	FF_TRANSPARENT         = (1 <<  5),
	FF_TOGGLE_BUTTON       = (1 <<  6),
	FF_STICKED             = (1 <<  7),
};

DECLARE_ENUM_AS_BIT_SET(FeatureFlags);

struct Widget;
typedef CCountedPtr<Widget> WidgetPtr;

struct CompositeWidget;
typedef CCountedPtr<CompositeWidget> CompositeWidgetPtr;

typedef int32 WidgetId;

struct Widget : public SimpleCountedObject {
	typedef AdaptT<EventHandlerDelegatePtr> Handler;
	typedef std::list<Handler> Handlers;

	CompositeWidget *m_container;       ///< widget container (can be any panel or window)
	WidgetId        m_id;               ///< Widget id in its container
	Rect16          m_rect;             ///< The position offsets relative to the container
	uint16          m_data;             ///< The String/Image or special code (list-matrices) of a widget
	FeatureFlags    m_feature_flags;    ///< @see FeatureFlags
	byte            m_color;            ///< Widget color, see docs/ottd-colourtext-palette.png
	bool            m_is_closing : 1;   ///< Widget was logically destroyed
	bool            m_dont_clip : 1;    ///< should not be clipped by parent (container)
	StringID        m_tooltips;         ///< Tooltips that are shown when right clicking on a widget
	Anchors         m_anchors;          ///< Resize/move when container resizes?
	Handlers        m_handlers;         ///< dynamically registered event handlers

	Widget()
		: m_container(NULL), m_id(0), m_rect(), m_data(0), m_feature_flags(FF_NONE), m_color(0)
		, m_is_closing(false), m_tooltips(0), m_anchors(PIN_NONE)
	{}

	Widget(CompositeWidget *container, WidgetId id, FeatureFlags feature_flags, byte color, const Rect16 &rect, StringID tooltips)
		: m_container(container)
		, m_id(id)
		, m_rect(rect)
		, m_data(0)
		, m_feature_flags(feature_flags)
		, m_color(color)
		, m_is_closing(false)
		, m_dont_clip(false)
		, m_tooltips(tooltips)
		, m_anchors(PIN_NONE)
	{}

	int16 Left() const;
	int16 Top() const;
	int16 Right() const;
	int16 Bottom() const;
	int16 Width() const;
	int16 Height() const;
	const Point16& TopLeft() const;
	const Point16& BottomRight() const;
	Point16 Size() const;
	Point16 CenterPt() const;
	const Rect16& GetRect() const;

	void SetLeft(int16 val);
	void SetTop(int16 val);
	void SetRight(int16 val);
	void SetBottom(int16 val);
	void SetWidth(int16 val);
	void SetHeight(int16 val);
	void SetTopLeft(const Point16 &pt);
	void SetBottomRight(const Point16 &pt);
	void SetSize(const Point16 &pt);
	void SetRect(const Rect16 &rect);

	byte GetColor() const;
	void SetColor(byte val);

	void SetAnchors(Anchors a);

	WidgetId GetId() const;

	void AddHandler(EventHandlerDelegate *d);
	void CallHandlers(EventBase &e);

	void Invalidate() {}; ///< now we redraw gui all the time, so no processing is needed here
	static /*static*/ void FillRect(const Rect16 &rc, int color);
	static void DrawFrameRect(int left, int top, int right, int bottom, int ctab, FrameFlags flags);
	void DrawFrameRect(int ctab, FrameFlags flags);

	virtual BaseWindow* GetWindow();
	virtual Widget* WidgetFromPt(const Point16 &pt);

	virtual void Close();

	virtual void DrawBackground(EvtPaint &ev);

	/**
	 * OnCreate() handler called when window gets created. Override this method in your
	 * Window subclass and place widgets into your window from there.
	 */
	virtual void OnCreate(EvtCreate &ev) {};
	virtual void OnDestroy(EvtDestroy &ev) {};
	virtual void OnPaint(EvtPaint &ev) = 0;
	virtual void OnKeyPress(EvtKeyPress &ev) {};
	virtual void OnLeftButtonDown(EvtLeftButtonDown &ev) {};
	virtual void OnLeftClick(EvtLeftClick &ev);
	virtual void OnRightButtonDown(EvtRightButtonDown &ev);
	virtual void OnMouseOver(EvtMouseOver &ev) {};
	virtual void OnResize(EvtResize &ev) {};
	virtual void OnResizeParent(EvtResizeParent &ev);

	/**
	 * Dispatch event by its type calling appropriate OnCreate(), OnDestroy(), etc.
	 */
	virtual void DispatchEvent(EventBase &ev);

	/**
	 * @function AddReflectHandlerT Registers reflected event handler. Use it from
	 * BaseWindow subclasses (Window implementations) to register custom event handler.
	 * For example if you are implementing 'MyWindow' class and want to handle OnLeftClick()
	 * event for your button 'MyButton', define your handler method inside 'MyWindow' class
	 * like:
	 *       void MyWindow::MyButtonClickHandler(gui::EvtLeftClick &e)
	 *       {
	 *          ...
	 *       }
	 * then from inside OnCreate() handler, create your button 'my_button' and
	 * call:
	 *       my_button->AddReflectHandlerT(&MyWindow::MyButtonClickHandler);
	 * and your MyButtonClickHandler will be called on every click on my_button.
	 */
	template <class Twnd_cls, EventCode Tevt_code> void AddReflectHandlerT(void (Twnd_cls::*handler)(gui::EventT<Tevt_code>&))
	{
		typedef ReflectHandlerDelegateT<Twnd_cls, Tevt_code> Delegate;
		AddHandler(new Delegate(handler));
	}

	/** add capture handler using default delegate type (CaptureHandlerDelegateT<>) */
	template <class Twd_cls, EventCode Tevt_code> CaptureTicket CaptureEventsT(Twd_cls *wd, void (Twd_cls::*handler)(EventT<Tevt_code>&))
	{
		CaptureTicket ticket = EventCaptureStack::AddHandler(new CaptureHandlerDelegateT<Twd_cls, Tevt_code>(wd, handler));
		return ticket;
	}

};

struct CompositeWidget : public Widget {
	typedef Widget super;
	typedef std::map<WidgetId, WidgetPtr> Widgets;
	typedef Widgets::iterator WidgetIterator;
	typedef Widgets::reverse_iterator WidgetReverseIterator;

protected:
	Widgets m_widgets;

public:
	CompositeWidget()
		: Widget()
	{}

	CompositeWidget(CompositeWidget *container, WidgetId id, FeatureFlags feature_flags, byte color, const Rect16 &rect, StringID tooltips)
		: Widget(container, id, feature_flags, color, rect, tooltips)
	{}

	void AddWidget(Widget *wd);
	Widget* GetWidget(WidgetId id);
	Widget* RemoveWidget(WidgetId id);

	/*virtual*/ Widget* WidgetFromPt(const Point16 &pt);

	virtual void CreateNcWidgets() {};
	virtual void CreateWidgets() = 0;
	virtual void Close();

	/*virtual*/ void OnCreate(EvtCreate &ev);
	/*virtual*/ void OnPaint(EvtPaint &ev);
	/*virtual*/ void OnLeftButtonDown(EvtLeftButtonDown &ev);
	/*virtual*/ void OnRightButtonDown(EvtRightButtonDown &ev);
	/*virtual*/ void OnResize(EvtResize &ev);
};


}; // namespace gui

#endif /* WIDGET_H */