/* $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 */