(svn r8931) [cpp_gui] -Add: first OO widget type (TextButton) added only with basic functionality cpp_gui
authorKUDr
Tue, 27 Feb 2007 22:47:59 +0000
branchcpp_gui
changeset 6264 9fc3b5467396
parent 6263 19dab6a68886
child 6265 7054c910251d
(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)
projects/openttd.vcproj
projects/openttd_vs80.vcproj
source.list
src/intro_gui.cpp
src/misc/rect.hpp
src/openttd.h
src/widget/widget.h
src/widget/widget_base.cpp
src/widget/widget_button.cpp
src/widget/widget_button_img.cpp
src/widget/widget_button_img2.cpp
src/widget/widget_button_txt.cpp
src/widget/widget_button_txt2.cpp
src/widget/widget_caption.cpp
src/widget/widget_closebox.cpp
src/widget/widget_composite.cpp
src/widget/widget_frame.cpp
src/widget/widget_hscrollbar.cpp
src/widget/widget_inset.cpp
src/widget/widget_label.cpp
src/widget/widget_list.cpp
src/widget/widget_panel.cpp
src/widget/widget_resizebox.cpp
src/widget/widget_scrollbar.cpp
src/widget/widget_stickybox.cpp
src/widget/window_event_base.h
src/widget/window_events.hpp
src/window.cpp
src/window.h
--- 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 */