src/widget/widget.h
author KUDr
Sat, 03 Mar 2007 20:25:37 +0000
branchcpp_gui
changeset 6283 7072ee68c676
parent 6282 c5b92f2d924f
child 6286 6e8eec87fa9d
permissions -rw-r--r--
(svn r8997) [cpp_gui] -Codechange: common window features are now controlled by FeatureFlags enum.
-Caption bar, close box and resize box are created automatically depending on features specified in window ctor.
/* $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)
};

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),
};

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);

	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);
};

struct Button : public Widget {
	typedef Widget super;

protected:
	bool m_pushed;
	CaptureTicket m_ticket_pressed;

public:
	Button()
		: Widget()
		, m_pushed(false)
	{}

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

	void OnCapturePressed(EvtMouseOver &e);

	/*virtual*/ void DrawBackground(EvtPaint &ev);

	/*virtual*/ void OnLeftButtonDown(EvtLeftButtonDown &ev);
};

struct TextButton : public Button {
	typedef Button super;

protected:
	StringID m_text;

public:
	TextButton()
		: Button()
	{}

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

	/*virtual*/ void OnPaint(EvtPaint &ev);
};

struct CloseBox : public Button {
	typedef Button super;

	static const int16 DEFAULT_WIDTH  = 11;
	static const int16 DEFAULT_HEIGHT = 14;

public:
	CloseBox()
		: Button()
	{}

	CloseBox(CompositeWidget *container)
		: Button(container, -102, FF_NONE, container->m_color, Rect16(), 0)
	{}

	/*virtual*/ void OnCreate(EvtCreate &ev);
	/*virtual*/ void OnPaint(EvtPaint &ev);
	/*virtual*/ void OnLeftClick(EvtLeftClick &ev);
};

struct Caption : public Widget {
	typedef Widget super;

protected:
	Point16       m_moving_offset;
	CaptureTicket m_ticket_moving;

public:
	Caption()
		: Widget()
	{}

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

	/*virtual*/ void DrawBackground(EvtPaint &ev);

	/*virtual*/ void OnPaint(EvtPaint &ev);
	/*virtual*/ void OnLeftButtonDown(EvtLeftButtonDown &ev);
	void OnCaptureMoving(EvtMouseOver &e);
};

struct CaptionBar : public CompositeWidget {
	typedef CompositeWidget super;

	static const int16 DEFAULT_HEIGHT = 14;

public:
	CaptionBar()
		: CompositeWidget()
	{}

	CaptionBar(CompositeWidget *container, WidgetId id, FeatureFlags feature_flags, byte color)
		: CompositeWidget(container, id, feature_flags, color, Rect16(0, 0, container->Right(), DEFAULT_HEIGHT - 1), 0)
	{}

	/*virtual*/ void CreateWidgets();
};


struct ResizeBox : public Widget {
	typedef Widget super;

	static const int16 DEFAULT_WIDTH  = 11;
	static const int16 DEFAULT_HEIGHT = 11;

protected:
	Point16       m_sizing_offset;
	CaptureTicket m_ticket_sizing;

public:
	ResizeBox()
		: Widget()
	{}

	ResizeBox(CompositeWidget *container)
		: Widget(container, -101, FF_NONE, container->m_color, Rect16(), 0)
	{}

	/*virtual*/ void DrawBackground(EvtPaint &ev);
	void OnCaptureSizing(EvtMouseOver &e);

	/*virtual*/ void OnCreate(EvtCreate &ev);
	/*virtual*/ void OnPaint(EvtPaint &ev);
	/*virtual*/ void OnLeftButtonDown(EvtLeftButtonDown &ev);
	/*virtual*/ void OnResizeParent(EvtResizeParent &ev);

};











}; // namespace gui


#endif /* WIDGET_H */