(svn r8931) [cpp_gui] -Add: first OO widget type (TextButton) added only with basic functionality
-Add: new gui events (C++)
-Add: dynamic event handlers introduced (see Widget::AddReflectHandlerT)
-Add: test window using the new features (intro_gui.cpp)
--- a/projects/openttd.vcproj Tue Feb 27 13:26:47 2007 +0000
+++ b/projects/openttd.vcproj Tue Feb 27 22:47:59 2007 +0000
@@ -1055,6 +1055,9 @@
Name="Widget"
Filter="">
<File
+ RelativePath=".\..\src\widget\widget.h">
+ </File>
+ <File
RelativePath=".\..\src\widget\widget_base.cpp">
</File>
<File
@@ -1108,6 +1111,12 @@
<File
RelativePath=".\..\src\widget\widget_stickybox.cpp">
</File>
+ <File
+ RelativePath=".\..\src\widget\window_event_base.h">
+ </File>
+ <File
+ RelativePath=".\..\src\widget\window_events.hpp">
+ </File>
</Filter>
<Filter
Name="YAPF"
--- a/projects/openttd_vs80.vcproj Tue Feb 27 13:26:47 2007 +0000
+++ b/projects/openttd_vs80.vcproj Tue Feb 27 22:47:59 2007 +0000
@@ -1338,6 +1338,9 @@
Name="Widget"
Filter="">
<File
+ RelativePath=".\..\src\widget\widget.h">
+ </File>
+ <File
RelativePath=".\..\src\widget\widget_base.cpp">
</File>
<File
@@ -1391,6 +1394,12 @@
<File
RelativePath=".\..\src\widget\widget_stickybox.cpp">
</File>
+ <File
+ RelativePath=".\..\src\widget\window_event_base.h">
+ </File>
+ <File
+ RelativePath=".\..\src\widget\window_events.hpp">
+ </File>
</Filter>
<Filter
Name="YAPF"
--- a/source.list Tue Feb 27 13:26:47 2007 +0000
+++ b/source.list Tue Feb 27 22:47:59 2007 +0000
@@ -324,6 +324,7 @@
misc/rect.hpp
# Widget
+widget/widget.h
widget/widget_base.cpp
widget/widget_button.cpp
widget/widget_button_img2.cpp
@@ -342,6 +343,8 @@
widget/widget_resizebox.cpp
widget/widget_scrollbar.cpp
widget/widget_stickybox.cpp
+widget/window_event_base.h
+widget/window_events.hpp
# YAPF
yapf/follow_track.cpp
--- a/src/intro_gui.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/intro_gui.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -100,6 +100,7 @@
void ShowSelectGameWindow(void)
{
BaseWindow::Allocate(&_select_game_desc);
+ WindowFactory::NewWindow(WC_TEST1, 0);
}
static void AskExitGameCallback(BaseWindow *w, bool confirmed)
@@ -147,3 +148,50 @@
AskExitToGameMenuCallback
);
}
+
+static const WindowDesc _select_game_desc_2 = {
+ 40, 40, 336, 195,
+ WC_SELECT_GAME, WC_NONE,
+ WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+ NULL,
+ NULL
+};
+
+
+
+template <> struct WindowT<WC_TEST1> : public BaseWindow {
+
+ gui::WidgetPtr m_button1;
+
+ WindowT()
+ : BaseWindow(WC_SELECT_GAME)
+ {
+ }
+
+ /*virtual*/ void OnCreate(gui::EvtCreate &e)
+ {
+ /* set common window properties */
+ SetTopLeft(Point16(140, 40));
+ SetSize(Point16(336, 195));
+ desc_flags = WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS;
+
+ /* add controls */
+ m_button1 = new gui::TextButton(this, 22, RESIZE_NONE, COLOUR_YELLOW, Rect16(104, 175, 231, 186), STR_0305_QUIT_OPENTTD, STR_0304_QUIT);
+ AddWidget(m_button1);
+
+ /* connect control callbacks */
+ m_button1->AddReflectHandlerT(&WindowT::Button1_OnClick);
+// m_button1->AddOnClickHandlerT(&WindowT::Button1_OnClick);
+ }
+
+ void Button1_OnClick(gui::EvtClick &e)
+ {
+ /* move window randomly */
+ SetTopLeft(TopLeft() + Point16(rand() % 21 - 10, rand() % 21 - 10));
+ SetDirty();
+ }
+};
+
+//RESIZE_NONE, 12, 104, 231, 175, 186, STR_0304_QUIT, STR_0305_QUIT_OPENTTD
+
+WindowFactoryT<WC_TEST1> _register_window_select_game;
--- a/src/misc/rect.hpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/misc/rect.hpp Tue Feb 27 22:47:59 2007 +0000
@@ -158,7 +158,7 @@
PointT<T> CenterPt() const
{
- return (top_left + bottom_right) / 2;
+ return (top_left + bottom_right + PointT<T>(1, 1)) / 2;
}
void SetLeft(T val)
--- a/src/openttd.h Tue Feb 27 13:26:47 2007 +0000
+++ b/src/openttd.h Tue Feb 27 22:47:59 2007 +0000
@@ -462,6 +462,7 @@
WC_GENERATE_LANDSCAPE,
WC_GENERATE_PROGRESS_WINDOW,
WC_CONFIRM_POPUP_QUERY,
+ WC_TEST1
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widget/widget.h Tue Feb 27 22:47:59 2007 +0000
@@ -0,0 +1,242 @@
+/* $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;
+
+namespace gui {
+
+struct Widget;
+typedef CCountedPtr<Widget> WidgetPtr;
+
+struct CompositeWidget;
+typedef CCountedPtr<CompositeWidget> CompositeWidgetPtr;
+
+typedef int32 WidgetId;
+
+struct Widget : public SimpleCountedObject {
+ struct Handler {
+ EventHandlerDelegatePtr m_delegate;
+
+ Handler(EventHandlerDelegate *d)
+ : m_delegate(d)
+ {}
+ };
+ 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
+ byte m_display_flags; ///< Resize direction, alignment, etc. during resizing, see @ResizeFlags
+ 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
+ Handlers m_handlers; ///< dynamically registered event handlers
+
+ Widget()
+ : m_container(NULL), m_id(0), m_rect(), m_data(0), m_display_flags(0), m_color(0)
+ , m_is_closing(false), m_tooltips(0)
+ {}
+
+ Widget(CompositeWidget *container, WidgetId id, byte display_flags, byte color, const Rect16 &rect, StringID tooltips)
+ : m_container(container)
+ , m_id(id)
+ , m_rect(rect)
+ , m_data(0)
+ , m_display_flags(display_flags)
+ , m_color(color)
+ , m_is_closing(false)
+ , m_dont_clip(false)
+ , m_tooltips(tooltips)
+ {}
+
+ 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);
+
+ 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 OnLeftClick(EvtClick &ev);
+ virtual void OnRightClick(EvtRightClick &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::EvtClick &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));
+ }
+};
+
+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, byte display_flags, byte color, const Rect16 &rect, StringID tooltips)
+ : Widget(container, id, display_flags, color, rect, tooltips)
+ {}
+
+ void AddWidget(Widget *wd);
+ Widget* GetWidget(WidgetId id);
+ Widget* RemoveWidget(WidgetId id);
+
+ /*virtual*/ Widget* WidgetFromPt(const Point16 &pt);
+
+ virtual void Close();
+
+ /*virtual*/ void OnPaint(EvtPaint &ev);
+ /*virtual*/ void OnLeftClick(EvtClick &ev);
+ /*virtual*/ void OnRightClick(EvtRightClick &ev);
+};
+
+struct Button : public Widget {
+ typedef Widget super;
+
+protected:
+ bool m_pushed;
+
+public:
+ Button()
+ : Widget()
+ , m_pushed(false)
+ {}
+
+ Button(CompositeWidget *container, WidgetId id, byte display_flags, byte color, const Rect16 &rect, StringID tooltips)
+ : Widget(container, id, display_flags, color, rect, tooltips)
+ , m_pushed(false)
+ {}
+
+ /*virtual*/ void DrawBackground(EvtPaint &ev);
+
+ /*virtual*/ void OnLeftClick(EvtClick &ev);
+};
+
+struct TextButton : public Button {
+ typedef Button super;
+
+protected:
+ StringID m_text;
+
+public:
+ TextButton()
+ : Button()
+ {}
+
+ TextButton(CompositeWidget *container, WidgetId id, byte display_flags, byte color, const Rect16 &rect, StringID tooltips, StringID text)
+ : Button(container, id, display_flags, color, rect, tooltips)
+ , m_text(text)
+ {}
+
+ /*virtual*/ void OnPaint(EvtPaint &ev);
+};
+
+
+
+
+
+
+
+
+
+
+
+}; // namespace gui
+
+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);
+
+
+#endif /* WIDGET_H */
--- a/src/widget/widget_base.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_base.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,6 +15,9 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
+
+namespace gui {
int16 Widget::Left() const
{
@@ -61,6 +64,11 @@
return m_rect.Size();
}
+Point16 Widget::CenterPt() const
+{
+ return m_rect.CenterPt();
+}
+
const Rect16& Widget::GetRect() const
{
return m_rect;
@@ -122,6 +130,66 @@
return m_id;
}
+void Widget::AddHandler(EventHandlerDelegate *d)
+{
+ m_handlers.push_back(Handler(d));
+}
+
+void Widget::CallHandlers(EventBase &e)
+{
+ BaseWindow *w = GetWindow();
+ if (w == NULL) return;
+ for (Handlers::iterator it = m_handlers.begin(); it != m_handlers.end(); ++it) {
+ EventHandlerDelegate *d = (*it).m_delegate;
+ if (d->m_code != e.GetCode()) continue;
+ d->HandleEvent(w, e);
+ }
+}
+
+/*static*/ void Widget::DrawFrameRect(int left, int top, int right, int bottom, int ctab, FrameFlags flags)
+{
+ uint dark = _colour_gradient[ctab][3];
+ uint medium_dark = _colour_gradient[ctab][5];
+ uint medium_light = _colour_gradient[ctab][6];
+ uint light = _colour_gradient[ctab][7];
+
+ if (flags & FR_TRANSPARENT) {
+ GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT | (1 << USE_COLORTABLE));
+ } else {
+ uint interior;
+
+ if (flags & FR_LOWERED) {
+ GfxFillRect(left, top, left, bottom, dark);
+ GfxFillRect(left + 1, top, right, top, dark);
+ GfxFillRect(right, top + 1, right, bottom - 1, light);
+ GfxFillRect(left + 1, bottom, right, bottom, light);
+ interior = (flags & FR_DARKENED ? medium_dark : medium_light);
+ } else {
+ GfxFillRect(left, top, left, bottom - 1, light);
+ GfxFillRect(left + 1, top, right - 1, top, light);
+ GfxFillRect(right, top, right, bottom - 1, dark);
+ GfxFillRect(left, bottom, right, bottom, dark);
+ interior = medium_dark;
+ }
+ if (!(flags & FR_BORDERONLY)) {
+ GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, interior);
+ }
+ }
+}
+
+void Widget::DrawFrameRect(int ctab, FrameFlags flags)
+{
+ DrawFrameRect(Left(), Top(), Right(), Bottom(), ctab, flags);
+}
+
+/*virtual*/ BaseWindow* Widget::GetWindow()
+{
+ if (m_container != NULL) {
+ return m_container->GetWindow();
+ }
+ return NULL;
+}
+
/*virtual*/ Widget* Widget::WidgetFromPt(const Point16 &pt)
{
if (m_rect.PtInRect(pt)) return this;
@@ -133,3 +201,28 @@
m_is_closing = true;
}
+/*virtual*/ void Widget::OnLeftClick(EvtClick &ev)
+{
+}
+
+/*virtual*/ void Widget::OnRightClick(EvtRightClick &ev)
+{
+ if (m_tooltips != 0) {
+ GuiShowTooltips(m_tooltips);
+ ev.SetHandled();
+ return;
+ }
+}
+
+/*virtual*/ void Widget::DrawBackground(EvtPaint &ev)
+{
+ DrawFrameRect(m_color, FR_NONE);
+}
+
+/*virtual*/ void Widget::DispatchEvent(EventBase &ev)
+{
+ if (ev.m_widget.IsNull()) ev.m_widget = this;
+ ev.Dispatch();
+}
+
+}; // namespace gui
--- a/src/widget/widget_button.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_button.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,22 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
+
+namespace gui {
+
+/*virtual*/ void Button::DrawBackground(EvtPaint &ev)
+{
+ DrawFrameRect(m_color, m_pushed ? FR_LOWERED : FR_NONE);
+}
+
+/*virtual*/ void Button::OnLeftClick(EvtClick &ev)
+{
+ m_pushed = !m_pushed;
+ CallHandlers(ev);
+ ev.SetHandled();
+ Invalidate();
+}
+}; // namespace gui
--- a/src/widget/widget_button_img.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_button_img.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_button_img2.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_button_img2.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_button_txt.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_button_txt.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,18 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
+
+namespace gui {
+
+/*virtual*/ void TextButton::OnPaint(EvtPaint &ev)
+{
+ DrawBackground(ev);
+ Point center = CenterPt();
+ if (m_pushed) center += Point(1, 1);
+ DrawStringCentered(center.x, center.y - 5, m_text, 0);
+ ev.SetHandled();
+}
+}; // namespace gui
--- a/src/widget/widget_button_txt2.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_button_txt2.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_caption.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_caption.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_closebox.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_closebox.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_composite.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_composite.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,7 +15,9 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
+namespace gui {
void CompositeWidget::AddWidget(Widget *wd)
{
@@ -78,12 +80,42 @@
super::Close();
}
-/*virtual*/ bool CompositeWidget::OnLeftClick(WindowEvent *ev)
+/*virtual*/ void CompositeWidget::OnPaint(EvtPaint &ev)
+{
+ /* paint background */
+ DrawBackground(ev);
+
+ /* paint all children */
+ for (WidgetIterator it_next = m_widgets.begin(); it_next != m_widgets.end(); ) {
+ /* save the iterator (it can be invalidated) and move forward */
+ WidgetIterator it = it_next++;
+ /* get child */
+ Widget *wd_child = (*it).second;
+ /* tell him we are closing */
+ wd_child->OnPaint(ev);
+ }
+}
+
+/*virtual*/ void CompositeWidget::OnLeftClick(EvtClick &ev)
{
//Point16 pt(ev->we.click.pt.x, ev->we.click.pt.y);
- Widget *wd_child = WidgetFromPt(ev->we.click.pt);
- if (wd_child != NULL) {
- return wd_child->OnLeftClick(ev);
+ Widget *wd_child = WidgetFromPt(ev.m_pt);
+ if (wd_child != NULL && wd_child != this) {
+ wd_child->OnLeftClick(ev);
+ return;
}
- return false;
+ super::OnLeftClick(ev);
}
+
+/*virtual*/ void CompositeWidget::OnRightClick(EvtRightClick &ev)
+{
+ //Point16 pt(ev->we.click.pt.x, ev->we.click.pt.y);
+ Widget *wd_child = WidgetFromPt(ev.m_pt);
+ if (wd_child != NULL && wd_child != this) {
+ wd_child->OnRightClick(ev);
+ return;
+ }
+ super::OnRightClick(ev);
+}
+
+}; // namespace gui
--- a/src/widget/widget_frame.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_frame.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_hscrollbar.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_hscrollbar.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_inset.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_inset.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_label.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_label.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_list.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_list.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_panel.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_panel.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_resizebox.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_resizebox.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_scrollbar.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_scrollbar.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- a/src/widget/widget_stickybox.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/widget/widget_stickybox.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,5 +15,6 @@
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
+#include "window_events.hpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widget/window_event_base.h Tue Feb 27 22:47:59 2007 +0000
@@ -0,0 +1,182 @@
+/* $Id$ */
+
+#ifndef WINDOW_EVENT_BASE_H
+#define WINDOW_EVENT_BASE_H
+
+struct BaseWindow;
+
+namespace gui {
+
+enum EventCode {
+ EVT_CREATE,
+ EVT_DESTROY,
+ EVT_PAINT,
+ EVT_KEYPRESS,
+ EVT_CLICK,
+ EVT_RCLICK,
+ EVT_MOUSEOVER,
+ EVT_MOUSELOOP,
+ EVT_MOUSEWHEEL,
+ EVT_TICK,
+ EVT_4,
+ EVT_TIMEOUT,
+ EVT_PLACE_OBJ,
+ EVT_ABORT_PLACE_OBJ,
+ EVT_ON_EDIT_TEXT,
+ EVT_ON_EDIT_TEXT_CANCEL,
+ EVT_POPUPMENU_SELECT,
+ EVT_POPUPMENU_OVER,
+ EVT_DRAGDROP,
+ EVT_PLACE_DRAG,
+ EVT_PLACE_MOUSEUP,
+ EVT_PLACE_PRESIZE,
+ EVT_DROPDOWN_SELECT,
+ EVT_RESIZE,
+ EVT_MESSAGE,
+ EVT_SCROLL,
+ EVT_INVALIDATE_DATA,
+};
+
+template <EventCode Tcode> struct EventT;
+
+typedef EventT<EVT_CREATE > EvtCreate;
+typedef EventT<EVT_DESTROY > EvtDestroy;
+typedef EventT<EVT_PAINT > EvtPaint;
+typedef EventT<EVT_KEYPRESS > EvtKeyPress;
+typedef EventT<EVT_CLICK > EvtClick;
+typedef EventT<EVT_RCLICK > EvtRightClick;
+typedef EventT<EVT_MOUSEOVER > EvtMouseOver;
+typedef EventT<EVT_MOUSELOOP > EvtMouseLoop;
+typedef EventT<EVT_MOUSEWHEEL > EvtMouseWheel;
+typedef EventT<EVT_TICK > EvtTick;
+typedef EventT<EVT_4 > Evt4;
+typedef EventT<EVT_TIMEOUT > EvtTimeout;
+typedef EventT<EVT_PLACE_OBJ > EvtPlaceObj;
+typedef EventT<EVT_ABORT_PLACE_OBJ > EvtAbortPlaceObj;
+typedef EventT<EVT_ON_EDIT_TEXT > EvtOnEditText;
+typedef EventT<EVT_ON_EDIT_TEXT_CANCEL> EvtOnEditTextCancel;
+typedef EventT<EVT_POPUPMENU_SELECT > EvtPopupMenuSelect;
+typedef EventT<EVT_POPUPMENU_OVER > EvtPopupMenuOver;
+typedef EventT<EVT_DRAGDROP > EvtDragDrop;
+typedef EventT<EVT_PLACE_DRAG > EvtPlaceDrag;
+typedef EventT<EVT_PLACE_MOUSEUP > EvtPlaceMouseUp;
+typedef EventT<EVT_PLACE_PRESIZE > EvtPlacePresize;
+typedef EventT<EVT_DROPDOWN_SELECT > EvtDropdownSelect;
+typedef EventT<EVT_RESIZE > EvtResize;
+typedef EventT<EVT_MESSAGE > EvtMessage;
+typedef EventT<EVT_SCROLL > EvtScroll;
+typedef EventT<EVT_INVALIDATE_DATA > EvtInvalidateData;
+
+struct Widget;
+typedef CCountedPtr<Widget> WidgetPtr;
+
+/** Base of all gui events. Never constructed directly. Used as base class
+ * of event types */
+struct EventBase {
+protected:
+ EventCode m_code;
+ bool m_handled;
+
+public:
+ WidgetPtr m_widget;
+
+protected:
+ /** protected constructor (called from subclasses only) */
+ EventBase(EventCode code)
+ : m_code(code)
+ , m_handled(false)
+ {}
+
+public:
+ virtual ~EventBase() {}
+
+ /** @return event code */
+ EventCode GetCode() const
+ {
+ return m_code;
+ }
+
+ /** @return true if event was already handled */
+ bool IsHandled() const
+ {
+ return m_handled;
+ }
+
+ void SetHandled(bool handled = true)
+ {
+ m_handled = handled;
+ }
+
+ /** type-safe conversion operator */
+ //template <EventCode Tcode> operator EventT<Tcode>& ()
+ //{
+ // assert(m_code == Tcode);
+ // return *(EventT<Tcode>*)this;
+ //}
+
+ virtual void Dispatch() = 0;
+};
+
+/** Intermediate event base that calls EventBase constructor with the proper event type as parameter.
+ * Used only by event subclasses */
+template <EventCode Tcode, void (Widget::*Tevt_method)(EventT<Tcode> &)> struct EventBaseT : public EventBase {
+ static const EventCode ID = Tcode; ///< allow access to event codes by class name (i.e. EvtCreate::ID)
+protected:
+ EventBaseT()
+ : EventBase(Tcode)
+ {}
+
+ /*virtual*/ void Dispatch()
+ {
+ assert(!m_widget.IsNull());
+ assert(m_code == Tcode);
+ (m_widget->*Tevt_method)(*(EventT<Tcode>*)this);
+ }
+};
+
+/**
+ * Base of all Event Handler Delegates - class that represents Event Handler object/method
+ * pair that can be called by widget when particular event is handled by a widget. Object
+ * of any type can register itself and its method as gui event callback handler by adding
+ * the appropriate delegate object into widget handler list.
+ */
+struct EventHandlerDelegate : public SimpleCountedObject {
+ EventCode m_code; ///< event code this handler is registered for
+
+ EventHandlerDelegate(EventCode code)
+ : m_code(code)
+ {}
+
+ /**
+ * The only method that delegate must provide. Called by widget if the appropriate event
+ * is reflected.
+ */
+ virtual void HandleEvent(BaseWindow *w, EventBase &e) = 0;
+};
+
+/** Reference counting pointer to the event handler delegate. */
+typedef CCountedPtr<EventHandlerDelegate> EventHandlerDelegatePtr;
+
+/**
+ * Delegate for handlers of events reflected back from widget to window.
+ */
+template <class Twnd_cls, EventCode Tevt_code> struct ReflectHandlerDelegateT : public EventHandlerDelegate {
+ void (Twnd_cls::*m_handler)(EventT<Tevt_code>&);
+
+ ReflectHandlerDelegateT(void (Twnd_cls::*handler)(EventT<Tevt_code>&))
+ : EventHandlerDelegate(Tevt_code)
+ , m_handler(handler)
+ {}
+
+ virtual void HandleEvent(BaseWindow *w, EventBase &e)
+ {
+ assert(e.GetCode() == Tevt_code);
+ Twnd_cls &wnd = *(Twnd_cls*)w;
+ EventT<Tevt_code> &ev = *(EventT<Tevt_code>*)&e;
+ (wnd.*m_handler)(ev);
+ }
+};
+
+}; // namespace gui
+
+#endif /* WINDOW_EVENT_BASE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widget/window_events.hpp Tue Feb 27 22:47:59 2007 +0000
@@ -0,0 +1,51 @@
+/* $Id$ */
+
+#ifndef WINDOW_EVENT_H
+#define WINDOW_EVENT_H
+
+namespace gui {
+
+
+template <> struct EventT<EVT_CREATE> : public EventBaseT<EVT_CREATE, &Widget::OnCreate> {
+};
+
+template <> struct EventT<EVT_DESTROY> : public EventBaseT<EVT_DESTROY, &Widget::OnDestroy> {
+};
+
+template <> struct EventT<EVT_PAINT> : public EventBaseT<EVT_PAINT, &Widget::OnPaint> {
+};
+
+template <> struct EventT<EVT_KEYPRESS> : public EventBaseT<EVT_KEYPRESS, &Widget::OnKeyPress> {
+ bool m_cont; // continue the search? (default true)
+ uint16 m_key; // 16-bit Unicode value of the key
+ uint16 m_keycode; // untranslated key (including shift-state)
+
+ EventT(bool cont, uint16 key, uint16 keycode)
+ : m_cont(cont)
+ , m_key(key)
+ , m_keycode(keycode)
+ {}
+};
+
+template <> struct EventT<EVT_CLICK> : public EventBaseT<EVT_CLICK, &Widget::OnLeftClick> {
+ Point m_pt;
+
+ EventT(const PointRaw &pt)
+ : m_pt(pt)
+ {}
+};
+
+template <> struct EventT<EVT_RCLICK> : public EventBaseT<EVT_RCLICK, &Widget::OnRightClick> {
+ Point m_pt;
+
+ EventT(const PointRaw &pt)
+ : m_pt(pt)
+ {}
+};
+
+
+
+
+}; // namespace gui
+
+#endif /* WINDOW_EVENT_H */
--- a/src/window.cpp Tue Feb 27 13:26:47 2007 +0000
+++ b/src/window.cpp Tue Feb 27 22:47:59 2007 +0000
@@ -15,6 +15,9 @@
#include "table/sprites.h"
#include "genworld.h"
#include "helpers.hpp"
+#include "widget/window_events.hpp"
+
+/*static*/ WindowFactory::Factories WindowFactory::s_factories;
// delta between mouse cursor and upper left corner of dragged window
static Point _drag_delta;
@@ -36,7 +39,26 @@
void WindowList::Remove(BaseWindow *w)
{
Iterator it = Find(w);
- if (it != m_list.end()) m_list.erase(it);
+ if (it != m_list.end()) {
+ assert(it != m_list.end());
+ Item &item = (*it);
+ assert(item.w == w);
+// w->Close();
+ m_list.erase(it);
+ }
+}
+
+void WindowList::CloseAll()
+{
+ BaseWindow *w_prev = NULL;
+ while (!m_list.empty()) {
+ Iterator it = m_list.begin();
+ Item &item = (*it);
+ BaseWindow *w = item.w;
+ assert(w != w_prev);
+ w_prev = w;
+ w->Close();
+ }
}
static bool MatchWindow(WindowList::Iterator it, BaseWindow *w)
@@ -102,6 +124,8 @@
}
+
+
int16 BaseWindow::Left() const
{
assert(super::TopLeft() == Point16(0, 0));
@@ -197,6 +221,19 @@
}
+/*virtual*/ bool BaseWindow::Create(WindowNumber num)
+{
+ window_number = num;
+ flash_timeout = 3; // just opened windows have a white border
+
+ /* add our new window into z-order list */
+ BaseWindow::s_list.Add(this);
+ wndproc = &BaseWindow::DefaultWndProc;
+
+ SetDirty();
+ CallEventNP(WE_CREATE);
+ return true;
+}
/*virtual*/ bool BaseWindow::Create(const WindowDesc *desc, WindowNumber num)
{
@@ -205,7 +242,8 @@
caption_color = 0xFF;
SetTopLeft(Point16(desc->left, desc->top));
SetSize(Point16(desc->width, desc->height));
- wndproc = desc->proc;
+
+ wndproc = desc->proc != NULL ? desc->proc : &BaseWindow::DefaultWndProc;
desc_flags = desc->flags;
AssignWidget(desc->widgets);
resize.width = Width();
@@ -354,6 +392,12 @@
// CallEventNP(WE_CREATE);
//}
+/*virtual*/ BaseWindow* BaseWindow::GetWindow()
+{
+ return this;
+}
+
+
/** Find the BaseWindow whose parent pointer points to this window
* @parent w BaseWindow to find child of
* @return return a BaseWindow pointer that is the child of w, or NULL otherwise */
@@ -375,6 +419,8 @@
/*virtual*/ void BaseWindow::FinalRelease()
{
+ assert(m_is_closing); // should be closed already
+
/* Delete any children a window might have in a head-recursive manner */
BaseWindow *v = FindChild();
if (v != NULL) v->Close();
@@ -385,7 +431,6 @@
ResetObjectToPlace();
}
- this->CallEventNP(WE_DESTROY);
if (viewport != NULL) DeleteWindowViewport(this);
SetDirty();
@@ -397,6 +442,8 @@
/*virtual*/ void BaseWindow::Close()
{
+ super::Close();
+ CallEventNP(WE_DESTROY);
s_list.Remove(this);
}
@@ -769,7 +816,10 @@
if (desc_flags & WDF_DEF_WIDGET) {
e.we.click.widget = GetWidgetFromPos(x, y);
- if (e.we.click.widget < 0) return; /* exit if clicked outside of widgets */
+ if (e.we.click.widget < 0) {
+ OldWndProc(&e); // try to handle it by new window infrastructure
+ return; /* exit if clicked outside of widgets */
+ }
/* don't allow any interaction if the button has been disabled */
if (IsWidgetDisabled(e.we.click.widget)) return;
@@ -822,22 +872,23 @@
void BaseWindow::DispatchRightClickEvent(int x, int y)
{
WindowEvent e;
+ e.event = WE_RCLICK;
+ e.we.click.pt.x = x;
+ e.we.click.pt.y = y;
/* default tooltips handler? */
if (desc_flags & WDF_STD_TOOLTIPS) {
e.we.click.widget = GetWidgetFromPos(x, y);
- if (e.we.click.widget < 0)
+ if (e.we.click.widget < 0) {
+ OldWndProc(&e); // try to handle it by new window infrastructure
return; /* exit if clicked outside of widgets */
-
+ }
if (widget[e.we.click.widget].tooltips != 0) {
GuiShowTooltips(widget[e.we.click.widget].tooltips);
return;
}
}
- e.event = WE_RCLICK;
- e.we.click.pt.x = x;
- e.we.click.pt.y = y;
wndproc(this, &e);
}
@@ -952,6 +1003,49 @@
wndproc(this, &e);
}
+void BaseWindow::OldWndProc(WindowEvent *e)
+{
+ gui::EventBase *evt = NULL;
+
+ switch(e->event) {
+ case WE_CREATE:
+ evt = new gui::EventT<gui::EVT_CREATE>();
+ break;
+
+ case WE_DESTROY:
+ evt = new gui::EventT<gui::EVT_DESTROY>();
+ break;
+
+ case WE_PAINT:
+ evt = new gui::EventT<gui::EVT_PAINT>();
+ break;
+
+ case WE_KEYPRESS:
+ evt = new gui::EventT<gui::EVT_KEYPRESS>(e->we.keypress.cont, e->we.keypress.key, e->we.keypress.keycode);
+ break;
+
+ case WE_CLICK:
+ evt = new gui::EventT<gui::EVT_CLICK>(e->we.click.pt);
+ break;
+
+ case WE_RCLICK:
+ evt = new gui::EventT<gui::EVT_RCLICK>(e->we.click.pt);
+ break;
+
+ default:
+ break;
+ }
+ if (evt == NULL) return;
+ DispatchEvent(*evt);
+ delete evt;
+}
+
+/*static*/ void BaseWindow::DefaultWndProc(BaseWindow *w, WindowEvent *e)
+{
+ w->OldWndProc(e);
+}
+
+
/** Find the z-value of a window. A window must already be open
* or the behaviour is undefined but function should never fail */
//WindowList::Iterator FindWindowZPosition(const BaseWindow *w)
@@ -1277,7 +1371,7 @@
void UnInitWindowSystem(void)
{
- BaseWindow::s_list.m_list.clear();
+ BaseWindow::s_list.CloseAll();
// BaseWindow **wz;
//
@@ -1421,6 +1515,12 @@
if (last_w->wndproc) last_w->wndproc(last_w, &e);
}
+ if (w == NULL) {
+ last_cls = WC_NONE;
+ last_num = -1;
+ return false;
+ }
+
last_cls = w->window_class;
last_num = w->window_number;
@@ -1904,6 +2004,7 @@
REVERSED_FOR_ALL_WINDOWS(w) {
if (w->flash_timeout > 0 && (--w->flash_timeout) == 0) w->SetDirty();
+ w->SetDirty();
}
DrawDirtyBlocks();
--- a/src/window.h Tue Feb 27 13:26:47 2007 +0000
+++ b/src/window.h Tue Feb 27 22:47:59 2007 +0000
@@ -3,17 +3,9 @@
#ifndef WINDOW_H
#define WINDOW_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 "widget/widget.h"
-typedef struct WindowEvent WindowEvent;
+struct WindowEvent;
typedef void WindowProc(BaseWindow *w, WindowEvent *e);
@@ -138,24 +130,6 @@
-struct Widget;
-typedef CCountedPtr<Widget> WidgetPtr;
-
-struct CompositeWidget;
-typedef CCountedPtr<CompositeWidget> CompositeWidgetPtr;
-
-typedef int32 WidgetId;
-
-typedef 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)
-} FrameFlags;
-
-DECLARE_ENUM_AS_BIT_SET(FrameFlags);
-
void DrawFrameRect(int left, int top, int right, int bottom, int color, FrameFlags flags);
enum WindowEventCodes {
@@ -326,94 +300,6 @@
};
-struct Widget : public SimpleCountedObject {
- // byte type; ///< Widget type, see @WindowWidgetTypes
- 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-matrixes) of a widget
- byte m_display_flags; ///< Resize direction, alignment, etc. during resizing, see @ResizeFlags
- byte m_color; ///< Widget colour, 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 rightclicking on a widget
-
- Widget()
- : m_container(NULL), m_id(0), m_rect(), m_data(0), m_display_flags(0), m_color(0)
- , m_is_closing(false), m_tooltips(0)
- {}
-
- Widget(CompositeWidget *container, WidgetId id, byte display_flags, byte color, const Rect16 &rect, StringID tooltips)
- : m_container(container)
- , m_id(id)
- , m_rect(rect)
- , m_data(0)
- , m_display_flags(display_flags)
- , m_color(color)
- , m_is_closing(false)
- , m_dont_clip(false)
- , m_tooltips(tooltips)
- {}
-
- 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;
- 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);
-
- WidgetId GetId() const;
-
- virtual Widget* WidgetFromPt(const Point16 &pt);
-
- virtual void Close();
- virtual bool OnLeftClick(WindowEvent *ev) = 0;
-};
-
-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, byte display_flags, byte color, const Rect16 &rect, StringID tooltips)
- : Widget(container, id, display_flags, color, rect, tooltips)
- {}
-
- void AddWidget(Widget *wd);
- Widget* GetWidget(WidgetId id);
- Widget* RemoveWidget(WidgetId id);
-
- /*virtual*/ Widget* WidgetFromPt(const Point16 &pt);
-
- virtual void Close();
-
- /*virtual*/ bool OnLeftClick(WindowEvent *ev);
-};
-
struct BaseWindow;
typedef CCountedPtr<BaseWindow> WindowPtr;
@@ -434,6 +320,7 @@
void Add(BaseWindow *w);
void Remove(BaseWindow *w);
+ void CloseAll();
Iterator Find(BaseWindow *w);
Iterator FindFirstVitalWindow();
Iterator FindByClass(WindowClass cls);
@@ -493,9 +380,9 @@
};
-struct BaseWindow : public CompositeWidget {
+struct BaseWindow : public gui::CompositeWidget {
public:
- typedef CompositeWidget super;
+ typedef gui::CompositeWidget super;
static WindowList s_list;
@@ -529,6 +416,13 @@
ZeroInitEnd m_zero_init_end; ///< end of zero initialization area
+protected:
+ BaseWindow(WindowClass cls)
+ : m_zero_init_area(m_zero_init_end)
+ , window_class(cls)
+ {}
+
+public:
BaseWindow(const WindowDesc *desc, WindowNumber num = 0)
: m_zero_init_area(m_zero_init_end)
{
@@ -552,12 +446,14 @@
void SetSize(const Point16 &pt);
void SetRect(const Rect16 &rect);
+ virtual bool Create(WindowNumber num);
virtual bool Create(const WindowDesc *desc, WindowNumber num = 0);
static BaseWindow* Allocate(int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const OldWidget *widget);
static BaseWindow* Allocate(const WindowDesc *desc, int window_number = 0);
static BaseWindow* AllocateFront(const WindowDesc *desc, int window_number = 0);
+ /*virtual*/ BaseWindow* GetWindow();
BaseWindow* FindChild() const;
void SetDirty() const;
void CDECL SetWidgetsDisabledState(bool disab_stat, int widgets, ...);
@@ -591,6 +487,9 @@
void CallEventNP(int event);
+ void OldWndProc(WindowEvent *e);
+ static void DefaultWndProc(BaseWindow *w, WindowEvent *e);
+
void AssignWidget(const OldWidget *widget);
void InvalidateData();
@@ -1125,4 +1024,56 @@
*/
//void ResizeButtons(BaseWindow *w, byte left, byte right);
+template <WindowClass Tcls> struct WindowT;
+
+struct WindowFactory
+{
+ typedef BaseWindow* (*CreateFn)(WindowNumber);
+
+ typedef std::map<WindowClass, WindowFactory*> Factories;
+
+ static Factories s_factories;
+
+ WindowClass m_cls;
+ CreateFn m_creator;
+
+ WindowFactory(WindowClass cls, CreateFn creator)
+ : m_cls(cls)
+ , m_creator(creator)
+ {
+ std::pair<Factories::iterator, bool> P = s_factories.insert(Factories::value_type(m_cls, this));
+ assert(P.second);
+ }
+
+ ~WindowFactory()
+ {
+ s_factories.erase(m_cls);
+ }
+
+ static BaseWindow* NewWindow(WindowClass cls, WindowNumber num)
+ {
+ Factories::iterator it = s_factories.find(cls);
+ if (it == s_factories.end()) return NULL;
+ WindowFactory *f = (*it).second;
+ BaseWindow *w = f->m_creator(num);
+ return w;
+ }
+
+};
+
+template <WindowClass Tcls> struct WindowFactoryT : public WindowFactory
+{
+ WindowFactoryT()
+ : WindowFactory(Tcls, &NewWindow)
+ {}
+
+ static BaseWindow* NewWindow(WindowNumber num)
+ {
+ WindowT<Tcls> *w = new WindowT<Tcls>();
+ w->Create(num);
+ return w;
+ }
+};
+
+
#endif /* WINDOW_H */