(svn r9484) [cpp_gui] -Add: Auto layout/resize ability of widgets. cpp_gui
authorKUDr
Mon, 26 Mar 2007 21:00:16 +0000
branchcpp_gui
changeset 6301 e0251f797d59
parent 6300 1f0d2abac815
child 6302 bd80897189ba
(svn r9484) [cpp_gui] -Add: Auto layout/resize ability of widgets.
-Add: Panel widget with DoLayout() method that moves/resizes widgets with respect to their minimal sizes.
-Add: QuerySizes() method added to widget. Widgets are now able to calculate their minimal size.
-Add: SizeT class added (similar to PointT) to make Point/Size/Rectangle math simpler
src/intro_gui.cpp
src/misc/rect.hpp
src/misc_gui.cpp
src/widget/widget.h
src/widget/widget_base.cpp
src/widget/widget_button.cpp
src/widget/widget_button_txt.cpp
src/widget/widget_caption.cpp
src/widget/widget_closebox.cpp
src/widget/widget_composite.cpp
src/widget/widget_label.cpp
src/widget/widget_panel.cpp
src/widget/widget_resizebox.cpp
src/widget/widget_stickybox.cpp
src/widget/widget_types.h
src/window.cpp
src/window.h
--- a/src/intro_gui.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/intro_gui.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -161,36 +161,117 @@
 	NULL
 };
 
+template <> struct WindowT<WC_TEST1> : public BaseWindow {
 
-
-template <> struct WindowT<WC_TEST1> : public BaseWindow {
+	CCountedPtr<gui::Panel> m_panel1;
+	CCountedPtr<gui::Panel> m_panel2;
+	CCountedPtr<gui::Panel> m_panel3;
+	CCountedPtr<gui::Panel> m_panel4;
 
 	gui::WidgetPtr m_label1;
 	gui::WidgetPtr m_button1;
+	CCountedPtr<gui::TextButton> m_button_add;
+	CCountedPtr<gui::TextButton> m_button_remove;
+	//CCountedPtr<gui::WidgetArrayY> m_ary_1;
+
+	int m_num_dyn_buttons;
 
 	WindowT()
-		: BaseWindow(WC_TEST1, STR_015B_OPENTTD, COLOUR_BROWN, gui::FF_NONE)
+		: BaseWindow(WC_TEST1, STR_015B_OPENTTD, COLOUR_BROWN, gui::FF_NO_RESIZE_BOX)
+		, m_num_dyn_buttons(5)
 	{
 	}
 
 	/*virtual*/ void CreateWidgets()
 	{
 		/* set common window properties */
-		SetTopLeft(Point16(140, 40));
-		SetSize(Point16(336, 195));
+		SetRect(Rect16(Point16(140, 40), Size16(336, 195)));
 
-		/* add controls */
-		m_label1 = new gui::Label(this, 22, gui::FF_NONE, Rect16(104, 155, 231, 166), STR_0305_QUIT_OPENTTD, STR_0305_QUIT_OPENTTD, COLOUR_BROWN);
-		m_label1->SetAnchors(PIN_RIGHT | PIN_BOTTOM);
-		AddWidget(m_label1);
+		m_panel1 = new gui::Panel(this, gui::FF_NO_FRAME | gui::FF_IGNORE_PARENT_FRAME, 0, COLOUR_TRANSPARENT);
 
-		/* add controls */
-		m_button1 = new gui::TextButton(this, 23, gui::FF_NONE, COLOUR_YELLOW, Rect16(104, 175, 231, 186), STR_0305_QUIT_OPENTTD, STR_0304_QUIT);
-		m_button1->SetAnchors(PIN_RIGHT | PIN_BOTTOM);
-		AddWidget(m_button1);
+		m_button_add = new gui::TextButton(m_panel1, STR_NULL, gui::FF_MIN_SIZE | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_0305_QUIT_OPENTTD, COLOUR_YELLOW);
+		m_button_add->m_text = "Add";
+		m_button_add->AddReflectHandlerT(&WindowT::ButtonAdd_OnClick);
+		m_panel1->AddWidget(m_button_add, gui::Panel::LEFT);
 
-		/* connect control callbacks */
+		m_button_remove = new gui::TextButton(m_panel1, STR_NULL, gui::FF_MIN_SIZE | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_0305_QUIT_OPENTTD, COLOUR_YELLOW);
+		m_button_remove->m_text = "Del";
+		m_button_remove->AddReflectHandlerT(&WindowT::ButtonRemove_OnClick);
+		m_panel1->AddWidget(m_button_remove, gui::Panel::LEFT);
+
+		m_button1 = new gui::TextButton(m_panel1, STR_0304_QUIT, gui::FF_MIN_SIZE | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_0305_QUIT_OPENTTD, COLOUR_YELLOW);
 		m_button1->AddReflectHandlerT(&WindowT::Button1_OnClick);
+		m_panel1->AddWidget(m_button1, gui::Panel::CENTER);
+
+		m_panel1->AddWidget(new gui::ResizeBox(m_panel1), gui::Panel::RIGHT);
+		AddWidget(m_panel1, gui::Panel::BOTTOM);
+
+
+		m_panel2 = new gui::Panel(this, gui::FF_NONE, 0, COLOUR_GREY);
+		for (int i = 0; i < m_num_dyn_buttons; i++) {
+			CCountedPtr<gui::TextButton> bu = new gui::TextButton(m_panel2, STR_000F_PASSENGERS + i, gui::FF_MIN_SIZE | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_00D0_NOTHING + i, COLOUR_PARENT);
+			m_panel2->AddWidget(bu, gui::Panel::TOP);
+		}
+		AddWidget(m_panel2, gui::Panel::LEFT);
+
+
+		m_panel3 = new gui::Panel(this, gui::FF_NONE, 0, COLOUR_GREY);
+		for (int i = 0; i < m_num_dyn_buttons; i++) {
+			CCountedPtr<gui::TextButton> bu = new gui::TextButton(m_panel3, STR_000F_PASSENGERS + i, gui::FF_MIN_HEIGHT | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_00D0_NOTHING + i, COLOUR_PARENT);
+			m_panel3->AddWidget(bu, gui::Panel::TOP);
+		}
+		AddWidget(m_panel3, gui::Panel::RIGHT);
+
+
+		m_panel4 = new gui::Panel(this, gui::FF_NONE, 0, COLOUR_GREY);
+		for (int i = 0; i < m_num_dyn_buttons; i++) {
+			CCountedPtr<gui::TextButton> bu = new gui::TextButton(m_panel4, STR_000F_PASSENGERS + i, gui::FF_MIN_SIZE | gui::FF_ALIGN_RIGHT | gui::FF_ALIGN_BOTTOM, STR_00D0_NOTHING + i, COLOUR_PARENT);
+			m_panel4->AddWidget(bu, gui::Panel::TOP);
+		}
+		AddWidget(m_panel4, gui::Panel::RIGHT);
+
+
+		///* add controls */
+		//m_label1 = new gui::Label(this, 22, gui::FF_NONE, Rect16(104, 155, 231, 166), STR_0305_QUIT_OPENTTD, STR_0305_QUIT_OPENTTD, COLOUR_BROWN);
+		//m_label1->SetAnchors(PIN_RIGHT | PIN_BOTTOM);
+		//AddWidget(m_label1);
+
+		///* add controls */
+		//m_button1 = new gui::TextButton(this, 23, gui::FF_NONE, COLOUR_YELLOW, Rect16(104, 175, 231, 186), STR_0305_QUIT_OPENTTD, STR_0304_QUIT);
+		//m_button1->SetAnchors(PIN_RIGHT | PIN_BOTTOM);
+		//AddWidget(m_button1);
+
+		///* connect control callbacks */
+		//m_button1->AddReflectHandlerT(&WindowT::Button1_OnClick);
+	}
+
+	void ButtonAdd_OnClick(gui::EvtLeftClick &e)
+	{
+		int i = ++m_num_dyn_buttons % (NUM_CARGO * 3);
+
+		CCountedPtr<gui::TextButton> bu;
+
+		bu = new gui::TextButton(m_panel2, STR_000F_PASSENGERS + i, gui::FF_MIN_SIZE | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_00D0_NOTHING + i, COLOUR_PARENT);
+		m_panel2->AddWidget(bu, gui::Panel::TOP);
+
+		bu = new gui::TextButton(m_panel3, STR_000F_PASSENGERS + i, gui::FF_MIN_HEIGHT | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_00D0_NOTHING + i, COLOUR_PARENT);
+		m_panel3->AddWidget(bu, gui::Panel::TOP);
+
+		bu = new gui::TextButton(m_panel4, STR_000F_PASSENGERS + i, gui::FF_MIN_SIZE | gui::FF_ALIGN_RIGHT | gui::FF_ALIGN_BOTTOM, STR_00D0_NOTHING + i, COLOUR_PARENT);
+		m_panel4->AddWidget(bu, gui::Panel::TOP);
+
+		QuerySizes();
+		CheckMinSize();
+		DoLayout();
+	}
+
+	void ButtonRemove_OnClick(gui::EvtLeftClick &e)
+	{
+		m_panel2->RemoveWidget(0);
+		m_panel3->RemoveWidget(0);
+		m_panel4->RemoveWidget(0);
+		QuerySizes();
+		DoLayout();
 	}
 
 	void Button1_OnClick(gui::EvtLeftClick &e)
@@ -198,6 +279,7 @@
 		/* move window randomly */
 		SetTopLeft(TopLeft() + Point16(rand() % 21 - 10, rand() % 21 - 10));
 		SetDirty();
+		Close();
 	}
 };
 
--- a/src/misc/rect.hpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/misc/rect.hpp	Mon Mar 26 21:00:16 2007 +0000
@@ -41,6 +41,11 @@
 		return PointRaw::x == other.x && PointRaw::y == other.y;
 	}
 
+	bool operator !=(const PointRaw &other) const
+	{
+		return PointRaw::x != other.x || PointRaw::y != other.y;
+	}
+
 	PointT operator -() const
 	{
 		return PointT(-PointRaw::x, -PointRaw::y);
@@ -116,10 +121,85 @@
 		static PointT val(std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
 		return val;
 	}
-
 };
 
+template <typename T> struct SizeT : public PointT<T> {
+	typedef PointT<T> Point;
+	typedef PointRawT<T> PointRaw;
 
+	SizeT(T x_a = 0, T y_a = 0)
+		: Point(x_a, y_a)
+	{}
+
+	template <typename Ta> SizeT(const PointRawT<Ta> &src)
+		: Point(src)
+	{}
+
+	SizeT operator -() const
+	{
+		return SizeT(-PointRaw::x, -PointRaw::y);
+	}
+
+	template <typename T2> SizeT operator +(const PointRawT<T2> &offset) const
+	{
+		SizeT pt(*this);
+		pt.DoMove(offset);
+		return pt;
+	}
+
+	template <typename T2> SizeT operator -(const PointRawT<T2> &offset) const
+	{
+		SizeT pt(*this);
+		pt.DoMove(-offset);
+		return pt;
+	}
+
+	SizeT& operator +=(const PointRaw &offset)
+	{
+		DoMove(offset);
+		return *this;
+	}
+
+	SizeT& operator -=(const PointRaw &offset)
+	{
+		DoMove(-offset);
+		return *this;
+	}
+
+	SizeT operator *(T coef) const
+	{
+		return SizeT(PointRaw::x * coef, PointRaw::y * coef);
+	}
+
+	SizeT operator /(T coef) const
+	{
+		return SizeT(PointRaw::x / coef, PointRaw::y / coef);
+	}
+
+	static const SizeT& min()
+	{
+		static SizeT val(std::numeric_limits<T>::min(), std::numeric_limits<T>::min());
+		return val;
+	}
+
+	static const SizeT& zero()
+	{
+		static SizeT val(0, 0);
+		return val;
+	}
+
+	static const SizeT& one()
+	{
+		static SizeT val(1, 1);
+		return val;
+	}
+
+	static const SizeT& max()
+	{
+		static SizeT val(std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
+		return val;
+	}
+};
 
 /** Template based rectangle */
 template <typename T> struct RectT
@@ -132,6 +212,10 @@
 		: top_left(left, top), bottom_right(right, bottom)
 	{}
 
+	template <typename Ta> RectT(const PointT<Ta> &tl, const SizeT<Ta> &size)
+		: top_left(tl), bottom_right(tl + size - PointT<T>(1, 1))
+	{}
+
 	template <typename Ta> RectT(const PointT<Ta> &tl, const PointT<Ta> &br)
 		: top_left(tl), bottom_right(br)
 	{}
@@ -180,9 +264,9 @@
 		return bottom_right;
 	}
 
-	PointT<T> Size() const
+	SizeT<T> Size() const
 	{
-		return (bottom_right - top_left + PointT<T>(1, 1));
+		return SizeT<T>(bottom_right - top_left + PointT<T>(1, 1));
 	}
 
 	PointT<T> CenterPt() const
@@ -323,6 +407,10 @@
 typedef PointT<int32> Point32;
 typedef PointT<int>   Point;
 
+typedef SizeT<int16> Size16;
+typedef SizeT<int32> Size32;
+typedef SizeT<int>   Size;
+
 typedef RectT<int16> Rect16;
 typedef RectT<int32> Rect32;
 
--- a/src/misc_gui.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/misc_gui.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -1283,7 +1283,7 @@
 	if (parent == NULL) parent = BaseWindow::FindById(WC_MAIN_WINDOW, 0);
 	w->parent = parent;
 	/* Center window to the center of parent */
-	w->SetTopLeft(parent->TopLeft() + (parent->Size() - w->Size()) / 2);
+	w->SetTopLeft(parent->TopLeft() + (parent->GetSize() - w->GetSize()) / 2);
 
 
 	/* Create a backup of the variadic arguments to strings because it will be
--- a/src/widget/widget.h	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget.h	Mon Mar 26 21:00:16 2007 +0000
@@ -5,7 +5,8 @@
 
 
 #include <list>
-#include <vector>
+//#include <vector>
+#include <map>
 #include "../macros.h"
 #include "../string.h"
 #include "../order.h"
@@ -46,13 +47,37 @@
 	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),
-	FF_FIXED_WIDTH         = (1 <<  8),
-	FF_FIXED_HEIGHT        = (1 <<  9),
+	FF_NO_FRAME            = (1 <<  5),
+	FF_IGNORE_PARENT_FRAME = (1 <<  6),
+	FF_TOGGLE_BUTTON       = (1 <<  7),
+	FF_STICKED             = (1 <<  8),
 
+	FF_MAX_WIDTH           = (1 << 16),
+	FF_MAX_HEIGHT          = (1 << 17),
+	FF_MIN_WIDTH           = (1 << 18),
+	FF_MIN_HEIGHT          = (1 << 19),
+	FF_BEST_WIDTH          = (1 << 20),
+	FF_BEST_HEIGHT         = (1 << 21),
+	FF_FIXED_WIDTH         = (1 << 22),
+	FF_FIXED_HEIGHT        = (1 << 23),
+	FF_SAME_WIDTH          = (1 << 24),
+	FF_SAME_HEIGHT         = (1 << 25),
+	FF_SAME_DIST_X         = (1 << 26),
+	FF_SAME_DIST_Y         = (1 << 27),
+
+	FF_ALIGN_LEFT          = (1 << 28),
+	FF_ALIGN_RIGHT         = (1 << 29),
+	FF_ALIGN_TOP           = (1 << 30),
+	FF_ALIGN_BOTTOM        = (1 << 31),
+
+	FF_MAX_SIZE            = FF_MAX_WIDTH   | FF_MAX_HEIGHT,
+	FF_MIN_SIZE            = FF_MIN_WIDTH   | FF_MIN_HEIGHT,
+	FF_BEST_SIZE           = FF_BEST_WIDTH  | FF_BEST_HEIGHT,
 	FF_FIXED_SIZE          = FF_FIXED_WIDTH | FF_FIXED_HEIGHT,
+	FF_SAME_SIZE           = FF_SAME_WIDTH  | FF_SAME_HEIGHT,
+
+	FF_ALIGN_HCENTER       = FF_ALIGN_LEFT | FF_ALIGN_RIGHT,
+	FF_ALIGN_VCENTER       = FF_ALIGN_TOP | FF_ALIGN_BOTTOM,
 };
 
 DECLARE_ENUM_AS_BIT_SET(FeatureFlags);
@@ -69,39 +94,39 @@
 	typedef AdaptT<EventHandlerDelegatePtr> Handler;
 	typedef std::list<Handler> Handlers;
 
+	/*------------------------------------------------------------------------------------------*/
+	ZeroInitBegin   m_zero_init_area;   ///< following members get cleared by constructor
 	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
+	uint16          m_color;            ///< Widget color, see docs/ottd-colourtext-palette.png
+	StringID        m_tooltips;         ///< Tooltips that are shown when right clicking on a widget
+	Anchors         m_anchors;          ///< Resize/move when container resizes?
 	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?
-	Point16         m_min_size;         ///< Minimum size
-	Point16         m_max_size;         ///< Maximum size
-	Point16         m_size_step;        ///< When resizing, what step is the best
+	ZeroInitEnd     m_zero_init_end;    ///< end of zero initialization area
+	/*------------------------------------------------------------------------------------------*/
+	Rect16          m_rect;             ///< The position offsets relative to the container and size
+	Size16          m_ext_border;       ///< Border around widget (for layout purposes)
+	Size16          m_min_size;         ///< Minimum size
+	Size16          m_max_size;         ///< Maximum size
+	Size16          m_size_step;        ///< When resizing, what step is the best
+
 	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)
-		, m_max_size(Point16::max()), m_size_step(1, 1)
+		: m_zero_init_area(m_zero_init_end)
 	{}
 
-	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)
+	Widget(CompositeWidget *container, FeatureFlags feature_flags, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: m_zero_init_area(m_zero_init_end)
+		, m_container(container)
 		, m_feature_flags(feature_flags)
 		, m_color(color)
 		, m_is_closing(false)
 		, m_dont_clip(false)
 		, m_tooltips(tooltips)
 		, m_anchors(PIN_NONE)
-		, m_max_size(Point16::max())
 		, m_size_step(1, 1)
 	{}
 
@@ -113,11 +138,13 @@
 	int16 Height() const;
 	const Point16& TopLeft() const;
 	const Point16& BottomRight() const;
-	Point16 Size() const;
+	Size16 GetSize() const;
 	Point16 CenterPt() const;
 	const Rect16& GetRect() const;
 	Rect16 GetLocalRect() const;
 
+	Point16 GetTopLeftInWindow() const;
+
 	void SetLeft(int16 val);
 	void SetTop(int16 val);
 	void SetRight(int16 val);
@@ -128,9 +155,12 @@
 	void SetBottomRight(const Point16 &pt);
 	void SetSize(const Point16 &pt);
 	void SetRect(const Rect16 &rect);
+	void SetSlotRect(const Rect16 &rect);
+	bool CheckMinSize();
 
-	byte GetColor() const;
-	void SetColor(byte val);
+	uint16 GetColor() const;
+	byte GetBkColor() const;
+	void SetColor(uint16 val);
 
 	void SetAnchors(Anchors a);
 
@@ -140,7 +170,8 @@
 	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 Size16 GetStringSize(StringID id);
+//	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);
 	void DrawSprite(SpriteID img, SpriteID pal, const Point16 &local_pos);
@@ -150,6 +181,8 @@
 
 	virtual void Close();
 
+	virtual void QuerySizes() {};
+	virtual void DoLayout() {};
 	virtual void DrawBackground(EvtPaint &ev);
 
 	/**
@@ -203,38 +236,54 @@
 };
 
 struct CompositeWidget : public Widget {
-	struct Slot {
+	typedef Widget super;
+	struct Slot : SimpleCountedObject {
 		WidgetPtr    m_wi;
-		uint8        m_span;
+
+		Slot(Widget *wi)
+			: m_wi(wi)
+		{}
+
+		virtual ~Slot() {};
 	};
 
-	typedef Widget super;
-	typedef std::vector<Slot> Widgets;
+	typedef CCountedPtr<Slot> SlotPtr;
+
+	typedef std::list<AdaptT<SlotPtr> > Widgets;
 	typedef Widgets::iterator WidgetIterator;
 	typedef Widgets::reverse_iterator WidgetReverseIterator;
 
 protected:
-	Widgets m_widgets;
+	Widgets         m_widgets;
+public:
+	Size16          m_int_border;       ///< Border inside (for layout purposes)
 
 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)
+	CompositeWidget(CompositeWidget *container, FeatureFlags feature_flags, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: Widget(container, feature_flags, tooltips, color)
 	{}
 
-	void AddWidget(Widget *wd);
-	WidgetIterator FindWidget(WidgetId id);
-	Widget* GetWidget(WidgetId id);
-	Widget* RemoveWidget(WidgetId id);
+	Size16 CalcInternalBorder();
+
+	virtual int NumWidgets();
+	virtual bool RemoveWidget(int idx);
+	virtual WidgetIterator AddSlot(Slot *ws);
+	//WidgetIterator FindWidget(WidgetId id);
+	//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 CreateWidgets() {};
+	/*virtual*/ void Close();
+
+	/*virtual*/ void QuerySizes();
+	/*virtual*/ void DoLayout();
 
 	/*virtual*/ void OnCreate(EvtCreate &ev);
 	/*virtual*/ void OnPaint(EvtPaint &ev);
@@ -243,6 +292,34 @@
 	/*virtual*/ void OnResize(EvtResize &ev);
 };
 
+struct Panel : CompositeWidget {
+	typedef CompositeWidget super;
+
+	enum Placement {
+		NONE,
+		LEFT,
+		TOP,
+		RIGHT,
+		BOTTOM,
+		CENTER,
+	};
+
+	static const FeatureFlags DEFAULT_FEATURES = FF_NONE;
+
+	Panel()
+		: CompositeWidget()
+	{}
+
+	Panel(CompositeWidget *container, FeatureFlags feature_flags = DEFAULT_FEATURES, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: CompositeWidget(container, feature_flags, tooltips, color)
+	{}
+
+	virtual CompositeWidget::WidgetIterator AddWidget(Widget *wd, Placement pp);
+
+	/*virtual*/ void QuerySizes();
+	/*virtual*/ void DoLayout();
+};
+
 }; // namespace gui
 
 #endif /* WIDGET_H */
--- a/src/widget/widget_base.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_base.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -12,6 +12,7 @@
 #include "../viewport.h"
 #include "../console.h"
 #include "../variables.h"
+#include "../strings.h"
 #include "../table/sprites.h"
 #include "../genworld.h"
 #include "../helpers.hpp"
@@ -59,7 +60,7 @@
 	return m_rect.BottomRight();
 }
 
-Point16 Widget::Size() const
+Size16 Widget::GetSize() const
 {
 	return m_rect.Size();
 }
@@ -79,6 +80,13 @@
 	return Rect16(Point16(0, 0), BottomRight() - TopLeft());
 }
 
+Point16 Widget::GetTopLeftInWindow() const
+{
+	Point16 pt = TopLeft();
+	if (m_container != NULL) pt += m_container->GetTopLeftInWindow();
+	return pt;
+}
+
 void Widget::SetLeft(int16 val)
 {
 	m_rect.SetRight(Right() + val - Left());
@@ -134,24 +142,80 @@
 
 void Widget::SetSize(const Point16 &pt)
 {
-	EvtResize evt_resize(pt - Size());
+	EvtResize evt_resize(pt - GetSize());
 	m_rect.SetSize(pt);
 	OnResize(evt_resize);
 }
 
 void Widget::SetRect(const Rect16 &rect)
 {
-	EvtResize evt_resize(rect.Size() - Size());
+	EvtResize evt_resize(rect.Size() - GetSize());
 	m_rect = rect;
 	OnResize(evt_resize);
 }
 
-byte Widget::GetColor() const
+void Widget::SetSlotRect(const Rect16 &rc_slot)
+{
+	Rect16 rc = rc_slot;
+	if ((m_feature_flags & FF_MIN_WIDTH) != FF_NONE) {
+		switch (m_feature_flags & (FF_ALIGN_LEFT | FF_ALIGN_RIGHT)) {
+			case FF_ALIGN_HCENTER:
+				rc.DoMove((rc.Width() - m_min_size.x) / 2, 0);
+				break;
+			case FF_ALIGN_RIGHT:
+				rc.DoMove(rc.Width() - m_min_size.x, 0);
+				/* fall down to FF_ALIGN_LEFT */
+			case FF_ALIGN_LEFT:
+			default:
+				break;
+		}
+		rc.SetWidth(m_min_size.x);
+	}
+	if ((m_feature_flags & FF_MIN_HEIGHT) != FF_NONE) {
+		switch (m_feature_flags & (FF_ALIGN_TOP | FF_ALIGN_BOTTOM)) {
+			case FF_ALIGN_VCENTER:
+				rc.DoMove(0, (rc.Height() - m_min_size.y) / 2);
+				break;
+			case FF_ALIGN_BOTTOM:
+				rc.DoMove(0, rc.Height() - m_min_size.y);
+				/* fall down to FF_ALIGN_TOP */
+			case FF_ALIGN_TOP:
+			default:
+				break;
+		}
+		rc.SetHeight(m_min_size.y);
+	}
+	SetRect(rc);
+}
+
+/** Check widget size against minimal size and resize if needed. Return true if resized. */
+bool Widget::CheckMinSize()
+{
+	Size16 size = GetSize();
+	Size16 new_size(max(size.x, m_min_size.x), max(size.y, m_min_size.y));
+	if (new_size != size) {
+		/* The current size if smaller then minimal size. */
+		SetSize(new_size);
+		return true;
+	}
+	return false;
+}
+
+uint16 Widget::GetColor() const
 {
 	return m_color;
 }
 
-void Widget::SetColor(byte val)
+byte Widget::GetBkColor() const
+{
+	if (m_color == COLOUR_PARENT || m_color == COLOUR_TRANSPARENT) {
+		if (m_container == NULL) return 0;
+		return m_container->GetBkColor();
+	}
+	return (byte)m_color;
+}
+
+void Widget::SetColor(uint16 val)
 {
 	m_color = val;
 }
@@ -182,6 +246,19 @@
 	}
 }
 
+/*static*/ Size16 Widget::GetStringSize(StringID id)
+{
+	if (id != 0) {
+		char str[512];
+		GetString(str, id, lastof(str));
+		if (str[0] != 0) {
+			BoundingRect br = GetStringBoundingBox(str);
+			return Size(br.width, br.height);
+		}
+	}
+	return Size16(0, 0);
+}
+
 /*static*/ void Widget::DrawFrameRect(int left, int top, int right, int bottom, int ctab, FrameFlags flags)
 {
 	uint dark         = _colour_gradient[ctab][3];
@@ -236,7 +313,7 @@
 
 /*virtual*/ Widget* Widget::WidgetFromPt(const Point16 &pt)
 {
-	if (m_rect.PtInRect(pt)) return this;
+	if (GetLocalRect().PtInRect(pt)) return this;
 	return NULL;
 }
 
@@ -279,7 +356,8 @@
 
 /*virtual*/ void Widget::DrawBackground(EvtPaint &ev)
 {
-	DrawFrameRect(m_color, FR_NONE);
+	bool draw_frame = (m_feature_flags & FF_NO_FRAME) == FF_NONE;
+	DrawFrameRect(GetBkColor(), draw_frame ? FR_NONE : FR_BG_ONLY);
 }
 
 /*virtual*/ void Widget::DispatchEvent(EventBase &ev)
--- a/src/widget/widget_button.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_button.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -25,9 +25,10 @@
 	BaseWindow *w = GetWindow();
 	assert(w != NULL);
 
+	/* translate the global coordinates to our parent space */
+	Point pt_local = e.m_pt - (w->TopLeft() + GetTopLeftInWindow());
+
 	if (_left_button_down) {
-		/* translate the global coordinates to our window space */
-		Point16 pt_local = e.m_pt - w->TopLeft();
 		/* determine the new button push state (is cursor inside button?) */
 		bool pushed = (WidgetFromPt(pt_local) != NULL);
 		/* did the push state change */
@@ -49,7 +50,7 @@
 		Invalidate();
 
 		/* issue click event */
-		EvtLeftClick ev(e.m_pt - w->TopLeft());
+		EvtLeftClick ev(pt_local);
 		ev.m_widget = this;
 		OnLeftClick(ev);
 	}
@@ -57,7 +58,7 @@
 
 /*virtual*/ void Button::DrawBackground(EvtPaint &ev)
 {
-	DrawFrameRect(m_color, m_pushed ? FR_LOWERED : FR_NONE);
+	DrawFrameRect(GetBkColor(), m_pushed ? FR_LOWERED : FR_NONE);
 }
 
 /*virtual*/ void Button::OnLeftButtonDown(EvtLeftButtonDown &e)
--- a/src/widget/widget_button_txt.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_button_txt.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -20,12 +20,27 @@
 
 namespace gui {
 
+StringID TextButton::GetTextId()
+{
+	if (m_text_id != STR_NULL) return m_text_id;
+	StringID temp_id = BindCString(m_text.c_str());
+	return temp_id;
+}
+
+/*virtual*/ void TextButton::QuerySizes()
+{
+	static Point16 border_size(6, 2);
+	StringID text_id = GetTextId();
+	m_min_size = GetStringSize(text_id) + border_size;
+}
+
 /*virtual*/ void TextButton::OnPaint(EvtPaint &ev)
 {
 	DrawBackground(ev);
-	Point center = Size() / 2;
+	Point center = GetSize() / 2;
 	if (m_pushed) center += Point(1, 1);
-	DrawStringCentered(center.x, center.y - 5, m_text, 0);
+	StringID text_id = GetTextId();
+	DrawStringCentered(center.x, center.y - 5, text_id, 16);
 	ev.SetHandled();
 }
 
--- a/src/widget/widget_caption.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_caption.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -21,6 +21,159 @@
 
 namespace gui {
 
+struct CloseBox : public Button {
+	typedef Button super;
+
+	static const int16 DEFAULT_WIDTH  = 11;
+	static const int16 DEFAULT_HEIGHT = 14;
+	static FeatureFlags DEFAULT_FEATURES() {return FF_MIN_SIZE | FF_IGNORE_PARENT_FRAME;}
+
+public:
+	CloseBox(CompositeWidget *container)
+		: Button(container, DEFAULT_FEATURES(), STR_018B_CLOSE_WINDOW, COLOUR_PARENT)
+	{
+		m_min_size = m_max_size = Size16(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+	}
+
+	///*virtual*/ void OnCreate(EvtCreate &ev)
+	//{
+	//	// move itself to the left of the parent
+	//	super::OnCreate(ev);
+	//}
+
+	/*virtual*/ void OnPaint(EvtPaint &ev)
+	{
+		assert(GetSize() == Point16(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+
+		DrawBackground(ev);
+		DrawString(2, 2, STR_00C5, 0);
+	}
+
+	/*virtual*/ void OnLeftClick(EvtLeftClick &ev)
+	{
+		BaseWindow *w = GetWindow();
+		assert(w != NULL);
+		w->Close();
+	}
+};
+
+struct StickyBox : public ImageButton2 {
+	typedef ImageButton2 super;
+
+	static const int16 DEFAULT_WIDTH  = 12;
+	static const int16 DEFAULT_HEIGHT = 14;
+	static const FeatureFlags DEFAULT_FEATURES() {return FF_TOGGLE_BUTTON | FF_MIN_SIZE;}
+
+public:
+	StickyBox(CompositeWidget *container)
+		: ImageButton2(container, SPR_PIN_DOWN, Point(0, 1), SPR_PIN_UP, Point(0, 1), DEFAULT_FEATURES(), STR_STICKY_BUTTON, COLOUR_PARENT)
+	{
+		m_min_size = m_max_size = Size16(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+	}
+
+	/*virtual*/ void OnCreate(EvtCreate &ev)
+	{
+		// move itself to the right side of the parent
+		super::OnCreate(ev);
+	}
+
+	/*virtual*/ void OnLeftClick(EvtLeftClick &ev)
+	{
+		BaseWindow *w = GetWindow();
+		assert(w != NULL);
+
+		/* set or reset FF_STICKED according to our 'pushed' state */
+		w->m_feature_flags = (w->m_feature_flags & ~FF_STICKED) | (m_pushed ? FF_STICKED : FF_NONE);
+	}
+
+};
+
+struct Caption : public Widget {
+	typedef Widget super;
+
+	static const FeatureFlags DEFAULT_FEATURES = FF_MIN_HEIGHT;
+
+protected:
+	Point16       m_moving_offset;
+	CaptureTicket m_ticket_moving;
+
+public:
+	Caption()
+		: Widget()
+	{}
+
+	Caption(CompositeWidget *container, FeatureFlags feature_flags = DEFAULT_FEATURES, StringID tooltips = STR_018C_WINDOW_TITLE_DRAG_THIS, uint16 color = COLOUR_PARENT)
+		: Widget(container, feature_flags, tooltips, color)
+	{}
+
+	/*virtual*/ void QuerySizes()
+	{
+		BaseWindow *w = GetWindow();
+		assert(w != NULL);
+
+		static Point16 border_size(6, 4);
+		m_min_size = GetStringSize(w->m_caption_text) + border_size;
+	}
+
+	/*virtual*/ void DrawBackground(EvtPaint &ev)
+	{
+		BaseWindow *w = GetWindow();
+		assert(w != NULL);
+
+		byte bk_color = GetBkColor();
+		byte caption_color = w->caption_color;
+		assert(Height() == 14); // XXX - to ensure the same sizes are used everywhere!
+		DrawFrameRect(bk_color, FR_BORDERONLY);
+		DrawFrameRect(1, 1, Width() - 2, Height() - 2, bk_color, (caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
+		if (caption_color != 0xFF) {
+			GfxFillRect(2, 2, Width() - 3, Height() - 3, _colour_gradient[_player_colors[caption_color]][4]);
+		}
+	}
+
+	/*virtual*/ void OnPaint(EvtPaint &ev)
+	{
+		BaseWindow *w = GetWindow();
+		assert(w != NULL);
+
+		DrawBackground(ev);
+		DrawStringCenteredTruncated(2, Width() - 3, 2, w->m_caption_text, 0x84);
+		ev.SetHandled();
+	}
+
+	/*virtual*/ void OnLeftButtonDown(EvtLeftButtonDown &ev)
+	{
+		BaseWindow *w = GetWindow();
+		assert(w != NULL);
+
+		/* if window is unmovable, do nothing */
+		if ((w->m_feature_flags & FF_UNMOVABLE) != FF_NONE) {
+			super::OnLeftButtonDown(ev);
+			return;
+		}
+
+		m_moving_offset = GetTopLeftInWindow() + ev.m_pt;
+		ev.SetHandled();
+		m_ticket_moving = CaptureEventsT(this, &Caption::OnCaptureMoving);
+		Invalidate();
+	}
+
+	void OnCaptureMoving(EvtMouseOver &e)
+	{
+		if (!_left_button_down) {
+			m_ticket_moving.Release();
+
+			EvtLeftClick ev(Point(0, 0));
+			ev.m_widget = this;
+			CallHandlers(ev);
+			return;
+		}
+		GetWindow()->SetTopLeft(e.m_pt - m_moving_offset);
+		e.SetHandled();
+		Invalidate();
+	}
+};
+
+
 /*virtual*/ void CaptionBar::CreateWidgets()
 {
 	BaseWindow *w = GetWindow();
@@ -29,83 +182,16 @@
 	bool make_close_box  = ((m_feature_flags & FF_NO_CLOSE_BOX ) == FF_NONE);
 	bool make_sticky_box = ((m_feature_flags & FF_NO_STICKY_BOX) == FF_NONE);
 
-	Rect16 rc_caption = GetLocalRect();
-
 	/* add close box */
-	if (make_close_box) {
-		CloseBox *close_box = new CloseBox(this);
-		AddWidget(close_box);
-		rc_caption.SetLeft(rc_caption.Left() + CloseBox::DEFAULT_WIDTH);
-	}
-
+	if (make_close_box ) AddWidget(new CloseBox (this), Panel::LEFT);
 	/* add sticky box */
-	if (make_sticky_box) {
-		StickyBox *sticky_box = new StickyBox(this);
-		AddWidget(sticky_box);
-		rc_caption.SetRight(rc_caption.Right() - StickyBox::DEFAULT_WIDTH);
-	}
-
+	if (make_sticky_box) AddWidget(new StickyBox(this), Panel::RIGHT);
 	/* add caption */
-	Caption *caption = new Caption(this, -100, FF_NONE, m_color, rc_caption, 0x84, STR_018C_WINDOW_TITLE_DRAG_THIS, w->m_caption_text);
-	caption->SetAnchors(PIN_LEFT | PIN_TOP | PIN_RIGHT);
-	AddWidget(caption);
-}
-
-/*virtual*/ void Caption::DrawBackground(EvtPaint &ev)
-{
-	BaseWindow *w = GetWindow();
-	assert(w != NULL);
-
-	byte caption_color = w->caption_color;
-	assert(Height() == 14); // XXX - to ensure the same sizes are used everywhere!
-	DrawFrameRect(m_color, FR_BORDERONLY);
-	DrawFrameRect(1, 1, Width() - 2, Height() - 2, m_color, (caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
-	if (caption_color != 0xFF) {
-		GfxFillRect(2, 2, Width() - 3, Height() - 3, _colour_gradient[_player_colors[caption_color]][4]);
-	}
-}
-
-/*virtual*/ void Caption::OnPaint(EvtPaint &ev)
-{
-	BaseWindow *w = GetWindow();
-	assert(w != NULL);
-
-	DrawBackground(ev);
-	DrawStringCenteredTruncated(2, Width() - 3, 2, w->m_caption_text, 0x84);
-	ev.SetHandled();
-}
-
-/*virtual*/ void Caption::OnLeftButtonDown(EvtLeftButtonDown &ev)
-{
-	BaseWindow *w = GetWindow();
-	assert(w != NULL);
-
-	/* if window is unmovable, do nothing */
-	if ((w->m_feature_flags & FF_UNMOVABLE) != FF_NONE) {
-		super::OnLeftButtonDown(ev);
-		return;
-	}
-
-	m_moving_offset = ev.m_pt;
-	ev.SetHandled();
-	m_ticket_moving = CaptureEventsT(this, &Caption::OnCaptureMoving);
-	Invalidate();
-}
-
-void Caption::OnCaptureMoving(EvtMouseOver &e)
-{
-	if (!_left_button_down) {
-		m_ticket_moving.Release();
-
-		EvtLeftClick ev(Point(0, 0));
-		ev.m_widget = this;
-		CallHandlers(ev);
-		return;
-	}
-	GetWindow()->SetTopLeft(e.m_pt - m_moving_offset);
-	e.SetHandled();
-	Invalidate();
+	AddWidget(new Caption(this), Panel::CENTER);
 }
 
 
+
+
+
 }; // namespace gui
--- a/src/widget/widget_closebox.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_closebox.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -20,31 +20,6 @@
 
 namespace gui {
 
-/*virtual*/ void CloseBox::OnCreate(EvtCreate &ev)
-{
-	Point16 size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
-	// move itself to the left of the parent
-	SetTopLeft(m_container->TopLeft());
-	SetBottomRight(TopLeft() +  size - Point16(1, 1));
-
-	SetAnchors(PIN_LEFT | PIN_TOP);
-	super::OnCreate(ev);
-}
-
-/*virtual*/ void CloseBox::OnPaint(EvtPaint &ev)
-{
-	assert(Size() == Point16(DEFAULT_WIDTH, DEFAULT_HEIGHT));
-
-	DrawBackground(ev);
-	DrawString(Left() + 2, Top() + 2, STR_00C5, 0);
-}
-
-/*virtual*/ void CloseBox::OnLeftClick(EvtLeftClick &ev)
-{
-	BaseWindow *w = GetWindow();
-	assert(w != NULL);
-	w->Close();
-}
 
 }; // namespace gui
 
--- a/src/widget/widget_composite.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_composite.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -21,21 +21,44 @@
 
 namespace gui {
 
-
-void CompositeWidget::AddWidget(Widget *wi)
+Size16 CompositeWidget::CalcInternalBorder()
 {
-	Widgets::value_type new_slot = {wi, 0};
-	m_widgets.push_back(new_slot);
+	/* internal border */
+	Size16 int_border = m_int_border;
+	if ((m_feature_flags & FF_NO_FRAME) == FF_NONE) int_border += Size16(2, 2);
+	return int_border;
 }
 
+/*virtual*/ int CompositeWidget::NumWidgets()
+{
+	return m_widgets.size();
+}
+
+/*virtual*/ CompositeWidget::WidgetIterator CompositeWidget::AddSlot(Slot *ws)
+{
+	WidgetIterator it = m_widgets.insert(m_widgets.end(), AdaptT<SlotPtr>(ws));
+	return it;
+}
+
+/*virtual*/ bool CompositeWidget::RemoveWidget(int idx)
+{
+	/* empty loop to find proper it */
+	WidgetIterator it = m_widgets.begin();
+	while (idx > 0 && it != m_widgets.end()) it++;
+	if (it == m_widgets.end()) return false;
+	m_widgets.erase(it);
+	return true;
+}
+
+#if 0
 CompositeWidget::WidgetIterator CompositeWidget::FindWidget(WidgetId id)
 {
 	/* iterate through children */
 	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ++it) {
 		/* get child */
-		Slot &child = (*it);
+		WidgetPtr &wi = (*it);
 		/* check its id */
-		if (child.m_wi == NULL || child.m_wi->m_id != id) continue;
+		if (wi == NULL || wi->m_id != id) continue;
 		return it;
 	}
 	return m_widgets.end();
@@ -44,29 +67,29 @@
 Widget* CompositeWidget::GetWidget(WidgetId id)
 {
 	WidgetIterator it = FindWidget(id);
-	return it != m_widgets.end() ? (*it).m_wi : NULL;
+	return it != m_widgets.end() ? (WidgetPtr&)(*it) : NULL;
 }
 
 Widget* CompositeWidget::RemoveWidget(WidgetId id)
 {
 	WidgetIterator it = FindWidget(id);
 	if (it == m_widgets.end()) return NULL;
-	Widget *wd = (*it).m_wi;
+	WidgetPtr &wd = (*it);
 	assert(wd->m_container == this);
 	wd->m_container = NULL;
 	m_widgets.erase(it);
 	return wd;
 }
+#endif /* 0 */
 
-/*virtual*/ Widget* CompositeWidget::WidgetFromPt(const Point16 &pt_parent)
+/*virtual*/ Widget* CompositeWidget::WidgetFromPt(const Point16 &pt_local)
 {
-	Point16 pt_local = pt_parent - TopLeft();
-	bool inside_me = m_rect.PtInRect(pt_parent);
+	bool inside_me = (super::WidgetFromPt(pt_local) == this);
 	for (WidgetReverseIterator rit = m_widgets.rbegin(); rit != m_widgets.rend(); ++rit) {
 		/* get next child */
-		Widget *wd_child = (*rit).m_wi;
+		Widget *wd_child = (*rit).m_t->m_wi;
 		/* ask the child recursively */
-		Widget *wd = wd_child->WidgetFromPt(pt_local);
+		Widget *wd = wd_child->WidgetFromPt(pt_local - wd_child->TopLeft());
 		if (wd != NULL) {
 			/* if the widget we found is inside me it is what we are searching for */
 			if (inside_me) return wd;
@@ -81,13 +104,11 @@
 /*virtual*/ void CompositeWidget::Close()
 {
 	/* mark all children as closed in safe way */
-	for (WidgetReverseIterator rit_next = m_widgets.rbegin(); rit_next != m_widgets.rend(); ) {
-		/* save the iterator (it can be invalidated) and move forward */
-		WidgetReverseIterator rit = rit_next++;
+	for (WidgetReverseIterator rit = m_widgets.rbegin(); rit != m_widgets.rend(); ) {
 		/* get child */
-		Widget *wd_child = (*rit).m_wi;
+		Widget *wi = (*(rit++)).m_t->m_wi;
 		/* tell him we are closing */
-		wd_child->Close();
+		wi->Close();
 	}
 	/* remove children */
 	m_widgets.clear();
@@ -95,21 +116,45 @@
 	super::Close();
 }
 
+/*virtual*/ void CompositeWidget::QuerySizes()
+{
+	/* query all children in a safe way */
+	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); it++) {
+		/* get child */
+		Widget *wi = (*it).m_t->m_wi;
+		/* do query */
+		wi->QuerySizes();
+	}
+	/* query itself too */
+	super::QuerySizes();
+}
+
+/*virtual*/ void CompositeWidget::DoLayout()
+{
+	/* query all children in a safe way */
+	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ) {
+		/* dereference the iterator and move forward */
+		Widget *wi = (*(it++)).m_t->m_wi;
+		/* do layout for child */
+		wi->DoLayout();
+	}
+	/* layout itself too */
+	super::DoLayout();
+}
+
 /*virtual*/ void CompositeWidget::OnCreate(EvtCreate &ev)
 {
-	/* create standard children */
-	CreateWidgets();
 	/* if there are any non-client widgets, create them */
 	CreateNcWidgets();
+	/* create standard children */
+	CreateWidgets();
 
 	/* notify all children that we are creating */
-	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++;
+	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ) {
 		/* get child */
-		Widget *wd_child = (*it).m_wi;
+		Widget *wi = (*(it++)).m_t->m_wi;
 		/* tell him we are creating window */
-		wd_child->OnCreate(ev);
+		wi->OnCreate(ev);
 	}
 
 	super::OnCreate(ev);
@@ -121,23 +166,23 @@
 	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++;
+	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ) {
 		/* get child */
-		Widget *wd_child = (*it).m_wi;
+		Widget *wi = (*(it++)).m_t->m_wi;
 		/* tell him we are painting */
-		ClipDrawContext ctx(wd_child->Left(), wd_child->Top(), wd_child->Width(), wd_child->Height());
-		if (!ctx.IsEmpty()) wd_child->OnPaint(ev);
+		ClipDrawContext ctx(wi->Left(), wi->Top(), wi->Width(), wi->Height());
+		if (!ctx.IsEmpty()) wi->OnPaint(ev);
 	}
 }
 
 /*virtual*/ void CompositeWidget::OnLeftButtonDown(EvtLeftButtonDown &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->OnLeftButtonDown(ev);
+	Widget *wi = WidgetFromPt(ev.m_pt);
+	if (wi != NULL && wi != this) {
+		EvtLeftButtonDown ev_child(ev.m_pt - wi->GetTopLeftInWindow());
+		wi->OnLeftButtonDown(ev_child);
+		ev.SetHandled(ev_child.IsHandled());
 		return;
 	}
 	super::OnLeftButtonDown(ev);
@@ -146,9 +191,9 @@
 /*virtual*/ void CompositeWidget::OnRightButtonDown(EvtRightButtonDown &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->OnRightButtonDown(ev);
+	Widget *wi = WidgetFromPt(ev.m_pt);
+	if (wi != NULL && wi != this) {
+		wi->OnRightButtonDown(ev);
 		return;
 	}
 	super::OnRightButtonDown(ev);
@@ -160,13 +205,11 @@
 
 	EvtResizeParent evp(ev);
 	/* notify 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++;
+	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ) {
 		/* get child */
-		Widget *wd_child = (*it).m_wi;
+		Widget *wi = (*(it++)).m_t->m_wi;
 		/* tell him we are resizing */
-		wd_child->OnResizeParent(evp);
+		wi->OnResizeParent(evp);
 	}
 	super::OnResize(ev);
 }
--- a/src/widget/widget_label.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_label.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -22,15 +22,14 @@
 
 /*virtual*/ void Label::DrawBackground(EvtPaint &ev)
 {
-	if ((m_feature_flags & FF_TRANSPARENT) == FF_NONE) {
-		DrawFrameRect(m_color, FR_BG_ONLY);
-	}
+	if (GetColor() == COLOUR_TRANSPARENT) return;
+	DrawFrameRect(GetBkColor(), FR_BG_ONLY);
 }
 
 /*virtual*/ void Label::OnPaint(EvtPaint &ev)
 {
 	DrawBackground(ev);
-	Point center = Size() / 2;
+	Point center = GetSize() / 2;
 	DrawStringCentered(center.x, center.y - 5, m_text, 0);
 	ev.SetHandled();
 }
--- a/src/widget/widget_panel.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_panel.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -15,7 +15,361 @@
 #include "../table/sprites.h"
 #include "../genworld.h"
 #include "../helpers.hpp"
+#include "../misc/blob.hpp"
 #include "window_events.hpp"
 #include "widget_types.h"
 
+namespace gui {
 
+typedef Panel::Placement Placement;
+struct QuerySizesData;
+struct DoLayoutData;
+
+struct PanelSlot : CompositeWidget::Slot {
+	typedef CompositeWidget::Slot super;
+
+	Placement  m_placement;        ///< which side of the container is this widget sticked to
+	Rect16     m_rc_slot;          ///< Bounding rectangle of the widget slot
+	bool       m_edge_left   : 1;  ///< widget is on left edge
+	bool       m_edge_top    : 1;  ///< widget is on top edge
+	bool       m_edge_right  : 1;  ///< widget is on right edge
+	bool       m_edge_bottom : 1;  ///< widget is on bottom edge
+
+	PanelSlot(Widget *wi, Placement placement)
+		: super(wi)
+		, m_placement(placement)
+		, m_edge_left(false)
+		, m_edge_top(false)
+		, m_edge_right(false)
+		, m_edge_bottom(false)
+	{}
+
+	/*virtual*/ ~PanelSlot() {};
+
+	virtual void QuerySizes(QuerySizesData &d) = 0;
+	virtual void DoLayout(DoLayoutData &d) = 0;
+};
+
+template <Placement Tplacement>
+struct PanelSlotT : PanelSlot {
+	typedef PanelSlot super;
+
+	PanelSlotT(Widget *wi)
+		: PanelSlot(wi, Tplacement)
+	{}
+
+	/*virtual*/ ~PanelSlotT() {};
+
+	/*virtual*/ void QuerySizes(QuerySizesData &d);
+	/*virtual*/ void DoLayout(DoLayoutData &d);
+};
+
+typedef PanelSlotT<Panel::LEFT  > PanelSlotLeft;
+typedef PanelSlotT<Panel::TOP   > PanelSlotTop;
+typedef PanelSlotT<Panel::RIGHT > PanelSlotRight;
+typedef PanelSlotT<Panel::BOTTOM> PanelSlotBottom;
+typedef PanelSlotT<Panel::CENTER> PanelSlotCenter;
+
+struct QuerySizesData {
+	Panel      *m_panel;
+	Size16     m_int_border;
+	Point16    m_accu_top_left;
+	Point16    m_accu_bottom_right;
+	bool       m_edge_left   : 1;  ///< widget is on left edge
+	bool       m_edge_top    : 1;  ///< widget is on top edge
+	bool       m_edge_right  : 1;  ///< widget is on right edge
+	bool       m_edge_bottom : 1;  ///< widget is on bottom edge
+
+	QuerySizesData(Panel *p)
+		: m_panel(p)
+		, m_int_border(p->CalcInternalBorder())
+		, m_edge_left(true)
+		, m_edge_top(true)
+		, m_edge_right(true)
+		, m_edge_bottom(true)
+	{}
+};
+
+template <Placement Tplacement>
+/*virtual*/ void PanelSlotT<Tplacement>::QuerySizes(QuerySizesData &d)
+{
+	m_edge_left   = d.m_edge_left;
+	m_edge_top    = d.m_edge_top;
+	m_edge_right  = d.m_edge_right;
+	m_edge_bottom = d.m_edge_bottom;
+
+	switch (Tplacement) {
+		case Panel::LEFT:   d.m_edge_left   = m_edge_right  = false; break;
+		case Panel::TOP:    d.m_edge_top    = m_edge_bottom = false; break;
+		case Panel::RIGHT:  d.m_edge_right  = m_edge_left   = false; break;
+		case Panel::BOTTOM: d.m_edge_bottom = m_edge_top    = false; break;
+		case Panel::CENTER: break;
+		default:
+			NOT_REACHED();
+			break;
+	}
+
+	/* Widget min size. */
+	Size16 wi_min_size = m_wi->m_min_size;
+	if ((m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) == FF_NONE) {
+		/* Widget doesn't ignore the parent's internal border. Increase its min size by this border. */
+		if (m_edge_left  ) wi_min_size.x += d.m_int_border.x;
+		if (m_edge_top   ) wi_min_size.y += d.m_int_border.y;
+		if (m_edge_right ) wi_min_size.x += d.m_int_border.x;
+		if (m_edge_bottom) wi_min_size.y += d.m_int_border.y;
+	}
+
+	/* New widget begins at d.m_accu_left_top. Calculate its end. */
+	Point16 wi_bottom_right = d.m_accu_top_left + wi_min_size;
+
+	/* Move the begin (top-left) of free area right or down */
+	switch (Tplacement) {
+		case Panel::LEFT:
+		case Panel::RIGHT:
+			/* Free area begin moves right by widget width. */
+			d.m_accu_top_left.x += wi_min_size.x;
+			break;
+
+		case Panel::TOP:
+		case Panel::BOTTOM:
+			/* Free area begin moves down by widget height. */
+			d.m_accu_top_left.y += wi_min_size.y;
+			break;
+
+		case Panel::CENTER:
+			break;
+
+		default:
+			NOT_REACHED();
+			break;
+	}
+
+	/* Move the end of free area if the new widget exceeds the end of free area. */
+	d.m_accu_bottom_right.x = max(wi_bottom_right.x, d.m_accu_bottom_right.x);
+	d.m_accu_bottom_right.y = max(wi_bottom_right.y, d.m_accu_bottom_right.y);
+}
+
+
+struct DoLayoutData {
+	Panel      *m_panel;
+	Size16     m_int_border;
+	Rect16     m_rc_remaining;
+
+	DoLayoutData(Panel *p)
+		: m_panel(p)
+		, m_int_border(p->CalcInternalBorder())
+		, m_rc_remaining(p->GetLocalRect())
+	{}
+};
+
+
+template <>
+/*virtual*/ void PanelSlotT<Panel::LEFT>::DoLayout(DoLayoutData &d)
+{
+	/* Does this widget respect or ignore parent's internal border? */
+	bool ignore_int_border = (m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != FF_NONE;
+
+	/* Find out where the remaining rect will split to widget rect and the new remaining rect */
+	int16 split = m_wi->m_min_size.x;
+	int16 split_border = (m_edge_left && !ignore_int_border) ? d.m_int_border.x : 0;
+
+	/* Cut widget rect from left side of the remaining rect. */
+	Rect16 rc_wi = d.m_rc_remaining;
+	rc_wi.SetWidth(split);
+	rc_wi.DoMove(split_border, 0);
+
+	/* Move the left side of remaining rect to the right. */
+	d.m_rc_remaining.SetLeft(d.m_rc_remaining.Left() + split + split_border);
+
+	/* Shrink widget rect vertically if it respects parent's internal border. */
+	if (!ignore_int_border) {
+		if (m_edge_top   ) rc_wi.SetTop   (rc_wi.Top   () + d.m_int_border.y);
+		if (m_edge_bottom) rc_wi.SetBottom(rc_wi.Bottom() - d.m_int_border.y);
+	}
+
+	/* Update the slot rectangle */
+	m_rc_slot = rc_wi;
+
+	/* Make widget to reposition/resize itself inside new slot. */
+//	printf("L:(%3d, %3d)..(%3d, %3d)\n", rc_wi.Left(), rc_wi.Top(), rc_wi.Right(), rc_wi.Bottom());
+	m_wi->SetSlotRect(rc_wi);
+}
+
+template <>
+/*virtual*/ void PanelSlotT<Panel::TOP>::DoLayout(DoLayoutData &d)
+{
+	/* Does this widget respect or ignore parent's internal border? */
+	bool ignore_int_border = (m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != FF_NONE;
+
+	/* Find out where the remaining rect will split to widget rect and the new remaining rect */
+	int16 split = m_wi->m_min_size.y;
+	int16 split_border = (m_edge_top && !ignore_int_border) ? d.m_int_border.y : 0;
+
+	/* Cut widget rect from top of the remaining rect. */
+	Rect16 rc_wi = d.m_rc_remaining;
+	rc_wi.SetHeight(split);
+	rc_wi.DoMove(0, split_border);
+
+	/* Move the top side of remaining rect down. */
+	d.m_rc_remaining.SetTop(d.m_rc_remaining.Top() + split + split_border);
+
+	/* Shrink widget rect horizontally if it respects parent's internal border. */
+	if (!ignore_int_border) {
+		if (m_edge_left ) rc_wi.SetLeft (rc_wi.Left () + d.m_int_border.x);
+		if (m_edge_right) rc_wi.SetRight(rc_wi.Right() - d.m_int_border.x);
+	}
+
+	/* Update the slot rectangle */
+	m_rc_slot = rc_wi;
+
+	/* Make widget to reposition/resize itself inside new slot. */
+//	printf("T:(%3d, %3d)..(%3d, %3d)\n", rc_wi.Left(), rc_wi.Top(), rc_wi.Right(), rc_wi.Bottom());
+	m_wi->SetSlotRect(rc_wi);
+}
+
+template <>
+/*virtual*/ void PanelSlotT<Panel::RIGHT>::DoLayout(DoLayoutData &d)
+{
+	/* Does this widget respect or ignore parent's internal border? */
+	bool ignore_int_border = (m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != FF_NONE;
+
+	/* Find out where the remaining rect will split to widget rect and the new remaining rect */
+	int16 split = d.m_rc_remaining.Width() - m_wi->m_min_size.x;
+	int16 split_border = (m_edge_right && !ignore_int_border) ? d.m_int_border.x : 0;
+
+	/* Cut widget rect from right side of the remaining rect. */
+	Rect16 rc_wi = d.m_rc_remaining;
+	rc_wi.SetLeft(rc_wi.Left() + split);
+	rc_wi.DoMove(-split_border, 0);
+
+	/* Move the right side of remaining rect to the left. */
+	d.m_rc_remaining.SetWidth(split - split_border);
+
+	/* Shrink widget rect vertically if it respects parent's internal border. */
+	if (!ignore_int_border) {
+		if (m_edge_top   ) rc_wi.SetTop   (rc_wi.Top   () + d.m_int_border.y);
+		if (m_edge_bottom) rc_wi.SetBottom(rc_wi.Bottom() - d.m_int_border.y);
+	}
+
+	/* Update the slot rectangle */
+	m_rc_slot = rc_wi;
+
+	/* Make widget to reposition/resize itself inside new slot. */
+//	printf("R:(%3d, %3d)..(%3d, %3d)\n", rc_wi.Left(), rc_wi.Top(), rc_wi.Right(), rc_wi.Bottom());
+	m_wi->SetSlotRect(rc_wi);
+}
+
+template <>
+/*virtual*/ void PanelSlotT<Panel::BOTTOM>::DoLayout(DoLayoutData &d)
+{
+	/* Does this widget respect or ignore parent's internal border? */
+	bool ignore_int_border = (m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != FF_NONE;
+
+	/* Find out where the remaining rect will split to widget rect and the new remaining rect */
+	int16 split = d.m_rc_remaining.Height() - m_wi->m_min_size.y;
+	int16 split_border = (m_edge_bottom && !ignore_int_border) ? d.m_int_border.y : 0;
+
+	/* Cut widget rect from bottom of the remaining rect. */
+	Rect16 rc_wi = d.m_rc_remaining;
+	rc_wi.SetTop(rc_wi.Top() + split);
+	rc_wi.DoMove(0, -split_border);
+
+	/* Move the bottom side of remaining rect up. */
+	d.m_rc_remaining.SetHeight(split - split_border);
+
+	/* Shrink widget rect horizontally if it respects parent's internal border. */
+	if (!ignore_int_border) {
+		if (m_edge_left ) rc_wi.SetLeft (rc_wi.Left () + d.m_int_border.x);
+		if (m_edge_right) rc_wi.SetRight(rc_wi.Right() - d.m_int_border.x);
+	}
+
+	/* Update the slot rectangle */
+	m_rc_slot = rc_wi;
+
+	/* Make widget to reposition/resize itself inside new slot. */
+//	printf("B:(%3d, %3d)..(%3d, %3d)\n", rc_wi.Left(), rc_wi.Top(), rc_wi.Right(), rc_wi.Bottom());
+	m_wi->SetSlotRect(rc_wi);
+}
+
+template <>
+/*virtual*/ void PanelSlotT<Panel::CENTER>::DoLayout(DoLayoutData &d)
+{
+	/* Does this widget respect or ignore parent's internal border? */
+	bool ignore_int_border = (m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != FF_NONE;
+
+	/* Widget rect will be the whole remaining rect. */
+	Rect16 rc_wi = d.m_rc_remaining;
+
+	/* Shrink widget rect horizontally if it respects parent's internal border. */
+	if (!ignore_int_border) {
+		if (m_edge_left  ) rc_wi.SetLeft  (rc_wi.Left  () + d.m_int_border.x);
+		if (m_edge_top   ) rc_wi.SetTop   (rc_wi.Top   () + d.m_int_border.y);
+		if (m_edge_right ) rc_wi.SetRight (rc_wi.Right () - d.m_int_border.x);
+		if (m_edge_bottom) rc_wi.SetBottom(rc_wi.Bottom() - d.m_int_border.y);
+	}
+
+	/* Update the slot rectangle */
+	m_rc_slot = rc_wi;
+
+	/* Make widget to reposition/resize itself inside new slot. */
+//	printf("C:(%3d, %3d)..(%3d, %3d)\n", rc_wi.Left(), rc_wi.Top(), rc_wi.Right(), rc_wi.Bottom());
+	m_wi->SetSlotRect(rc_wi);
+}
+
+
+
+
+
+/*virtual*/ CompositeWidget::WidgetIterator Panel::AddWidget(Widget *wi, Placement pp)
+{
+	Slot *slot = NULL;
+	switch (pp)
+	{
+	case LEFT:   slot = new PanelSlotLeft(wi);   break;
+	case TOP:    slot = new PanelSlotTop(wi);    break;
+	case RIGHT:  slot = new PanelSlotRight(wi);  break;
+	case BOTTOM: slot = new PanelSlotBottom(wi); break;
+	case CENTER: slot = new PanelSlotCenter(wi); break;
+	default:
+		NOT_REACHED();
+	}
+
+	WidgetIterator wit = super::AddSlot(slot);
+	return wit;
+}
+
+/*virtual*/ void Panel::QuerySizes()
+{
+	/* query children */
+	super::QuerySizes();
+	if (m_widgets.empty()) return;
+
+	QuerySizesData qsd(this);
+	for (WidgetIterator wit = m_widgets.begin(); wit != m_widgets.end(); wit++) {
+		PanelSlot *slot = (PanelSlot*)(CompositeWidget::Slot*)(*wit).m_t;
+		slot->QuerySizes(qsd);
+	}
+	/* Adjust by unbound sides. */
+	int num_bound_x = (qsd.m_edge_left ? 1 : 0) + (qsd.m_edge_right  ? 1 : 0);
+	int num_bound_y = (qsd.m_edge_top  ? 1 : 0) + (qsd.m_edge_bottom ? 1 : 0);
+
+	if (num_bound_x + num_bound_y == 3) {
+		if (num_bound_x == 1) qsd.m_accu_bottom_right.x += qsd.m_int_border.x;
+		if (num_bound_y == 1) qsd.m_accu_bottom_right.y += qsd.m_int_border.y;
+	}
+
+	m_min_size = qsd.m_accu_bottom_right;
+}
+
+/*virtual*/ void Panel::DoLayout()
+{
+	DoLayoutData dld(this);
+	for (WidgetIterator wit = m_widgets.begin(); wit != m_widgets.end(); wit++) {
+		PanelSlot *slot = (PanelSlot*)(CompositeWidget::Slot*)(*wit).m_t;
+		slot->DoLayout(dld);
+	}
+	/* do layout children */
+	super::DoLayout();
+}
+
+}; // namespace gui
--- a/src/widget/widget_resizebox.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_resizebox.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -23,7 +23,7 @@
 /*virtual*/ void ResizeBox::DrawBackground(EvtPaint &ev)
 {
 	bool sizing = m_ticket_sizing.IsActive();
-	DrawFrameRect(m_color, sizing ? FR_LOWERED : FR_NONE);
+	DrawFrameRect(GetBkColor(), sizing ? FR_LOWERED : FR_NONE);
 }
 
 void ResizeBox::OnCaptureSizing(EvtMouseOver &e)
@@ -39,8 +39,8 @@
 	BaseWindow *w = GetWindow();
 	w->SetDirty();
 	Point16 size = e.m_pt - w->TopLeft() + m_sizing_offset;
-	size.x = max(size.x, DEFAULT_WIDTH);
-	size.y = max(size.y, DEFAULT_HEIGHT);
+	size.x = max(size.x, w->m_min_size.x);
+	size.y = max(size.y, w->m_min_size.y);
 	w->SetSize(size);
 	e.SetHandled();
 	w->SetDirty();
@@ -58,7 +58,7 @@
 
 /*virtual*/ void ResizeBox::OnPaint(EvtPaint &ev)
 {
-	assert(Size() == Point16(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+//	assert(GetSize() == Point16(DEFAULT_WIDTH, DEFAULT_HEIGHT));
 
 	DrawBackground(ev);
 	bool sizing = m_ticket_sizing.IsActive();
@@ -69,7 +69,7 @@
 /*virtual*/ void ResizeBox::OnLeftButtonDown(EvtLeftButtonDown &ev)
 {
 	BaseWindow *w = GetWindow();
-	m_sizing_offset = w->Size() - ev.m_pt;
+	m_sizing_offset = w->GetSize() - (GetTopLeftInWindow() + ev.m_pt);
 	m_ticket_sizing = CaptureEventsT(this, &ResizeBox::OnCaptureSizing);
 	Invalidate();
 	ev.SetHandled();
--- a/src/widget/widget_stickybox.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_stickybox.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -19,25 +19,6 @@
 
 namespace gui {
 
-/*virtual*/ void StickyBox::OnCreate(EvtCreate &ev)
-{
-	// move itself to the right side of the parent
-	Rect16 rc = m_container->GetRect();
-	rc.SetLeft(rc.Right() - (DEFAULT_WIDTH - 1));
-	rc.SetBottom(rc.Top() + (DEFAULT_HEIGHT - 1));
-	SetRect(rc);
-
-	SetAnchors(PIN_TOP | PIN_RIGHT);
-	super::OnCreate(ev);
-}
-
-/*virtual*/ void StickyBox::OnLeftClick(EvtLeftClick &ev)
-{
-	BaseWindow *w = GetWindow();
-	assert(w != NULL);
-
-	w->m_feature_flags = (w->m_feature_flags & ~FF_STICKED) | (m_pushed ? FF_STICKED : FF_NONE);
-}
 
 }; // namespace gui
 
--- a/src/widget/widget_types.h	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/widget/widget_types.h	Mon Mar 26 21:00:16 2007 +0000
@@ -11,6 +11,8 @@
 struct Label : public Widget {
 	typedef Widget super;
 
+	static const FeatureFlags DEFAULT_FEATURES = FF_NONE;
+
 protected:
 	StringID m_text;
 
@@ -19,12 +21,10 @@
 		: Widget()
 	{}
 
-	Label(CompositeWidget *container, WidgetId id, FeatureFlags feature_flags, const Rect16 &rect, StringID text, StringID tooltip = 0, int color = COLOUR_NONE)
-		: Widget(container, id, feature_flags, (byte)color, rect, tooltip)
+	Label(CompositeWidget *container, StringID text, FeatureFlags feature_flags = DEFAULT_FEATURES, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: Widget(container, feature_flags, tooltips, color)
 		, m_text(text)
 	{
-		/* make the label transparent (no background) if color not provided */
-		if (color == COLOUR_NONE) m_feature_flags |= FF_TRANSPARENT;
 	}
 
 	/*virtual*/ void DrawBackground(EvtPaint &ev);
@@ -45,8 +45,8 @@
 		, 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)
+	Button(CompositeWidget *container, FeatureFlags feature_flags, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: Widget(container, feature_flags, tooltips, color)
 		, m_pushed(false)
 	{}
 
@@ -60,6 +60,8 @@
 struct ImageButton : public Button {
 	typedef Button super;
 
+	static const FeatureFlags DEFAULT_FEATURES = FF_NONE;
+
 protected:
 	SpriteID m_sprite;
 	Point16  m_sprite_offset;
@@ -70,8 +72,8 @@
 		, m_sprite(0)
 	{}
 
-	ImageButton(CompositeWidget *container, WidgetId id, FeatureFlags feature_flags, byte color, const Rect16 &rect, StringID tooltips, SpriteID sprite, Point16 sprite_offset)
-		: Button(container, id, feature_flags, color, rect, tooltips)
+	ImageButton(CompositeWidget *container, SpriteID sprite, Point16 sprite_offset, FeatureFlags feature_flags = DEFAULT_FEATURES, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: Button(container, feature_flags, tooltips, color)
 		, m_sprite(sprite)
 		, m_sprite_offset(sprite_offset)
 	{}
@@ -82,6 +84,8 @@
 struct ImageButton2 : public ImageButton {
 	typedef ImageButton super;
 
+	static const FeatureFlags DEFAULT_FEATURES = FF_NONE;
+
 protected:
 	SpriteID m_sprite_pushed;
 	Point16  m_sprite_offset_pushed;
@@ -92,8 +96,8 @@
 		, m_sprite_pushed(0)
 	{}
 
-	ImageButton2(CompositeWidget *container, WidgetId id, FeatureFlags feature_flags, byte color, const Rect16 &rect, StringID tooltips, SpriteID sprite, Point16 sprite_offset, SpriteID sprite_pushed, Point16 sprite_offset_pushed)
-		: ImageButton(container, id, feature_flags, color, rect, tooltips, sprite, sprite_offset)
+	ImageButton2(CompositeWidget *container, SpriteID sprite, Point16 sprite_offset, SpriteID sprite_pushed, Point16 sprite_offset_pushed, FeatureFlags feature_flags = DEFAULT_FEATURES, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: ImageButton(container, sprite, sprite_offset, feature_flags, tooltips, color)
 		, m_sprite_pushed(sprite_pushed)
 		, m_sprite_offset_pushed(sprite_offset_pushed)
 	{}
@@ -104,97 +108,44 @@
 struct TextButton : public Button {
 	typedef Button super;
 
+	static const FeatureFlags DEFAULT_FEATURES = FF_NONE;
+
 protected:
-	StringID m_text;
+	StringID      m_text_id;
+public:
+	std::string   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)
+	TextButton(CompositeWidget *container, StringID text_id, FeatureFlags feature_flags = DEFAULT_FEATURES, StringID tooltips = 0, uint16 color = COLOUR_PARENT)
+		: Button(container, feature_flags, tooltips, color)
+		, m_text_id(text_id)
 	{}
 
+	StringID GetTextId();
+	/*virtual*/ void QuerySizes();
+
 	/*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(), STR_018B_CLOSE_WINDOW)
-	{}
-
-	/*virtual*/ void OnCreate(EvtCreate &ev);
-	/*virtual*/ void OnPaint(EvtPaint &ev);
-	/*virtual*/ void OnLeftClick(EvtLeftClick &ev);
-};
-
-struct StickyBox : public ImageButton2 {
-	typedef ImageButton2 super;
-
-	static const int16 DEFAULT_WIDTH  = 12;
-	static const int16 DEFAULT_HEIGHT = 14;
-
-public:
-	StickyBox()
-		: ImageButton2()
-	{}
-
-	StickyBox(CompositeWidget *container)
-		: ImageButton2(container, -103, FF_TOGGLE_BUTTON, container->m_color, Rect16(), STR_STICKY_BUTTON, SPR_PIN_DOWN, Point(0, 1), SPR_PIN_UP, Point(0, 1))
-	{}
-
-	/*virtual*/ void OnCreate(EvtCreate &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;
+struct CaptionBar : public Panel {
+	typedef Panel super;
 
 	static const int16 DEFAULT_HEIGHT = 14;
 
 public:
 	CaptionBar()
-		: CompositeWidget()
+		: super()
 	{}
 
-	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)
-	{}
+	CaptionBar(CompositeWidget *container, FeatureFlags feature_flags, uint16 color = COLOUR_PARENT)
+		: super(container, feature_flags, 0, color)
+	{
+		m_feature_flags |= FF_NO_FRAME | FF_IGNORE_PARENT_FRAME;
+	}
 
 	/*virtual*/ void CreateWidgets();
 };
@@ -205,6 +156,7 @@
 
 	static const int16 DEFAULT_WIDTH  = 11;
 	static const int16 DEFAULT_HEIGHT = 11;
+	static FeatureFlags DEFAULT_FEATURES() {return FF_MIN_SIZE | FF_ALIGN_RIGHT | FF_ALIGN_BOTTOM;}
 
 protected:
 	Point16       m_sizing_offset;
@@ -216,8 +168,10 @@
 	{}
 
 	ResizeBox(CompositeWidget *container)
-		: Widget(container, -101, FF_NONE, container->m_color, Rect16(), STR_RESIZE_BUTTON)
-	{}
+		: Widget(container, DEFAULT_FEATURES(), STR_RESIZE_BUTTON, COLOUR_PARENT)
+	{
+		m_min_size = m_max_size = Size16(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+	}
 
 	/*virtual*/ void DrawBackground(EvtPaint &ev);
 	void OnCaptureSizing(EvtMouseOver &e);
--- a/src/window.cpp	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/window.cpp	Mon Mar 26 21:00:16 2007 +0000
@@ -275,14 +275,14 @@
 	if ((m_feature_flags & gui::FF_NO_CAPTION_BAR) == gui::FF_NONE) {
 		/* add caption bar */
 		gui::FeatureFlags feature_flags = m_feature_flags & (gui::FF_NO_CLOSE_BOX | gui::FF_NO_STICKY_BOX);
-		gui::CaptionBar *capt_bar = new gui::CaptionBar(this, -100, feature_flags, m_color);
-		capt_bar->SetAnchors(PIN_LEFT | PIN_TOP | PIN_RIGHT);
-		AddWidget(capt_bar);
+		feature_flags |= gui::FF_SAME_HEIGHT | gui::FF_MAX_WIDTH;
+		gui::CaptionBar *capt_bar = new gui::CaptionBar(this, feature_flags);
+		AddWidget(capt_bar, gui::Panel::TOP);
 	}
 	if ((m_feature_flags & gui::FF_NO_RESIZE_BOX) == gui::FF_NONE) {
 		/* add resize box */
 		gui::ResizeBox *resize_box = new gui::ResizeBox(this);
-		AddWidget(resize_box);
+		AddWidget(resize_box, gui::Panel::CENTER);
 	}
 }
 
@@ -292,12 +292,27 @@
 	assert(widget != NULL);
 }
 
+/*virtual*/ void BaseWindow::OnCreate(gui::EvtCreate &ev)
+{
+	super::OnCreate(ev);
+	QuerySizes();
+	DoLayout();
+}
+
 /*virtual*/ void BaseWindow::OnPaint(gui::EvtPaint &ev)
 {
 	ClipDrawContext ctx(0, 0, Width(), Height());
 	if (!ctx.IsEmpty()) super::OnPaint(ev);
 }
 
+/*virtual*/ void BaseWindow::OnResize(gui::EvtResize &ev)
+{
+	if (ev.m_change == Point16(0, 0)) return;
+	super::OnResize(ev);
+	QuerySizes();
+	DoLayout();
+}
+
 /**
 * Open a new window. If there is no space for a new window, close an open
 * window. Try to avoid stickied windows, but if there is no else, close one of
--- a/src/window.h	Mon Mar 26 20:50:18 2007 +0000
+++ b/src/window.h	Mon Mar 26 21:00:16 2007 +0000
@@ -381,9 +381,9 @@
 
 };
 
-struct BaseWindow : public gui::CompositeWidget {
+struct BaseWindow : public gui::Panel {
 public:
-	typedef gui::CompositeWidget super;
+	typedef gui::Panel super;
 
 	static WindowList s_list;
 
@@ -421,7 +421,7 @@
 
 protected:
 	BaseWindow(WindowClass cls, StringID caption_text = 0, byte color = COLOUR_GREY, gui::FeatureFlags feature_flags = gui::FF_NONE)
-		: CompositeWidget(NULL, 0, feature_flags, color, Rect16(), 0)
+		: super(NULL, feature_flags, 0, color)
 		, m_zero_init_area(m_zero_init_end)
 		, window_class(cls)
 		, m_caption_text(caption_text)
@@ -457,7 +457,9 @@
 	/*virtual*/ void CreateNcWidgets();
 	/*virtual*/ void CreateWidgets(); ///< @TODO remove it when old gui infrastructure will no longer be used
 
+	/*virtual*/ void OnCreate(gui::EvtCreate &ev);
 	/*virtual*/ void OnPaint(gui::EvtPaint &ev);
+	/*virtual*/ void OnResize(gui::EvtResize &ev);
 
 
 	static BaseWindow* Allocate(int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const OldWidget *widget);