src/widget/widget_composite.cpp
author KUDr
Mon, 26 Mar 2007 21:00:16 +0000
branchcpp_gui
changeset 6301 e0251f797d59
parent 6297 4bf29d14edba
permissions -rw-r--r--
(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
/* $Id$ */

#include "../stdafx.h"
#include <stdarg.h>
#include "../openttd.h"
#include "../debug.h"
#include "../functions.h"
#include "../map.h"
#include "../player.h"
#include "../window.h"
#include "../gfx.h"
#include "../viewport.h"
#include "../console.h"
#include "../variables.h"
#include "../table/sprites.h"
#include "../genworld.h"
#include "../helpers.hpp"
#include "window_events.hpp"

#include <algorithm>

namespace gui {

Size16 CompositeWidget::CalcInternalBorder()
{
	/* 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 */
		WidgetPtr &wi = (*it);
		/* check its id */
		if (wi == NULL || wi->m_id != id) continue;
		return it;
	}
	return m_widgets.end();
}

Widget* CompositeWidget::GetWidget(WidgetId id)
{
	WidgetIterator it = FindWidget(id);
	return it != m_widgets.end() ? (WidgetPtr&)(*it) : NULL;
}

Widget* CompositeWidget::RemoveWidget(WidgetId id)
{
	WidgetIterator it = FindWidget(id);
	if (it == m_widgets.end()) return NULL;
	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_local)
{
	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_t->m_wi;
		/* ask the child recursively */
		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;
			/* the point is outside me. The widget is clipped unless it is on-top widget */
			if (wd->m_dont_clip) return wd;
			/* try next child */
		}
	}
	return inside_me ? this : NULL;
}

/*virtual*/ void CompositeWidget::Close()
{
	/* mark all children as closed in safe way */
	for (WidgetReverseIterator rit = m_widgets.rbegin(); rit != m_widgets.rend(); ) {
		/* get child */
		Widget *wi = (*(rit++)).m_t->m_wi;
		/* tell him we are closing */
		wi->Close();
	}
	/* remove children */
	m_widgets.clear();
	/* mark self as closed */
	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)
{
	/* if there are any non-client widgets, create them */
	CreateNcWidgets();
	/* create standard children */
	CreateWidgets();

	/* notify all children that we are creating */
	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ) {
		/* get child */
		Widget *wi = (*(it++)).m_t->m_wi;
		/* tell him we are creating window */
		wi->OnCreate(ev);
	}

	super::OnCreate(ev);
}

/*virtual*/ void CompositeWidget::OnPaint(EvtPaint &ev)
{
	/* paint background */
	DrawBackground(ev);

	/* paint all children */
	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ) {
		/* get child */
		Widget *wi = (*(it++)).m_t->m_wi;
		/* tell him we are painting */
		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 *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);
}

/*virtual*/ void CompositeWidget::OnRightButtonDown(EvtRightButtonDown &ev)
{
	//Point16 pt(ev->we.click.pt.x, ev->we.click.pt.y);
	Widget *wi = WidgetFromPt(ev.m_pt);
	if (wi != NULL && wi != this) {
		wi->OnRightButtonDown(ev);
		return;
	}
	super::OnRightButtonDown(ev);
}

/*virtual*/ void CompositeWidget::OnResize(EvtResize &ev)
{
	if (ev.m_change == Point16(0, 0)) return;

	EvtResizeParent evp(ev);
	/* notify all children */
	for (WidgetIterator it = m_widgets.begin(); it != m_widgets.end(); ) {
		/* get child */
		Widget *wi = (*(it++)).m_t->m_wi;
		/* tell him we are resizing */
		wi->OnResizeParent(evp);
	}
	super::OnResize(ev);
}

}; // namespace gui