13f289665SStefano Ceccherini//--------------------------------------------------------------------
23f289665SStefano Ceccherini//
33f289665SStefano Ceccherini//	ViewLayoutFactory.cpp
43f289665SStefano Ceccherini//
53f289665SStefano Ceccherini//	Written by: Owen Smith
63f289665SStefano Ceccherini//
73f289665SStefano Ceccherini//--------------------------------------------------------------------
83f289665SStefano Ceccherini
93f289665SStefano Ceccherini/*
103f289665SStefano Ceccherini	Copyright 1999, Be Incorporated.   All Rights Reserved.
113f289665SStefano Ceccherini	This file may be used under the terms of the Be Sample Code License.
123f289665SStefano Ceccherini*/
133f289665SStefano Ceccherini
143f289665SStefano Ceccherini#include "ViewLayoutFactory.h"
153f289665SStefano Ceccherini
163f289665SStefano Ceccherini#include <Button.h>
173f289665SStefano Ceccherini#include <CheckBox.h>
183f289665SStefano Ceccherini#include <TextControl.h>
193f289665SStefano Ceccherini#include <View.h>
203f289665SStefano Ceccherini#include <List.h>
21372eb874SStefano Ceccherini#include <algorithm>
223f289665SStefano Ceccherini#include <assert.h>
233f289665SStefano Ceccherini#include <stdio.h>
243f289665SStefano Ceccherini
253f289665SStefano Ceccherinitemplate <class T>
263f289665SStefano Ceccheriniinline T average(const T& x, const T& y)
273f289665SStefano Ceccherini{
283f289665SStefano Ceccherini	return (x + y) / 2;
293f289665SStefano Ceccherini}
303f289665SStefano Ceccherini
313f289665SStefano Ceccherini
323f289665SStefano Ceccherini//--------------------------------------------------------------------
333f289665SStefano Ceccherini//	ViewLayoutFactory factory generators
343f289665SStefano Ceccherini
353f289665SStefano CeccheriniBButton* ViewLayoutFactory::MakeButton(const char* name, const char* label,
363f289665SStefano Ceccherini	uint32 msgID, BPoint pos, corner posRef)
373f289665SStefano Ceccherini{
383f289665SStefano Ceccherini	BRect dummyFrame(0,0,0,0);
393f289665SStefano Ceccherini	BButton* pButton = new BButton(dummyFrame, name, label,
403f289665SStefano Ceccherini		new BMessage(msgID));
413f289665SStefano Ceccherini	pButton->ResizeToPreferred();
423f289665SStefano Ceccherini	MoveViewCorner(*pButton, pos, posRef);
433f289665SStefano Ceccherini	return pButton;
443f289665SStefano Ceccherini}
453f289665SStefano Ceccherini
463f289665SStefano CeccheriniBCheckBox* ViewLayoutFactory::MakeCheckBox(const char* name,
473f289665SStefano Ceccherini	const char* label, uint32 msgID, BPoint pos, corner posRef)
483f289665SStefano Ceccherini{
493f289665SStefano Ceccherini	BRect dummyFrame(0,0,0,0);
503f289665SStefano Ceccherini	BCheckBox* pCheckBox = new BCheckBox(dummyFrame, name, label,
513f289665SStefano Ceccherini		new BMessage(msgID));
523f289665SStefano Ceccherini	pCheckBox->ResizeToPreferred();
533f289665SStefano Ceccherini	MoveViewCorner(*pCheckBox, pos, posRef);
543f289665SStefano Ceccherini	return pCheckBox;
553f289665SStefano Ceccherini}
563f289665SStefano Ceccherini
573f289665SStefano CeccheriniBTextControl* ViewLayoutFactory::MakeTextControl(const char* name,
583f289665SStefano Ceccherini	const char* label, const char* text, BPoint pos, float controlWidth,
593f289665SStefano Ceccherini	corner posRef)
603f289665SStefano Ceccherini{
613f289665SStefano Ceccherini	// Note: this function is almost identical to the regular
623f289665SStefano Ceccherini	// BTextControl constructor, but it minimizes the label
633f289665SStefano Ceccherini	// width and maximizes the field width, instead of divvying
643f289665SStefano Ceccherini	// them up half-&-half or 2 : 3, and gives the standard
653f289665SStefano Ceccherini	// flexibility of corner positioning.
663f289665SStefano Ceccherini	BRect dummyFrame(0,0,0,0);
673f289665SStefano Ceccherini	BTextControl* pCtrl = new BTextControl(dummyFrame, name, label,
683f289665SStefano Ceccherini		text, NULL);
693f289665SStefano Ceccherini	LayoutTextControl(*pCtrl, pos, controlWidth, posRef);
703f289665SStefano Ceccherini	return pCtrl;
713f289665SStefano Ceccherini}
723f289665SStefano Ceccherini
733f289665SStefano Ceccherinivoid ViewLayoutFactory::LayoutTextControl(BTextControl& control,
743f289665SStefano Ceccherini	BPoint pos, float controlWidth, corner posRef)
753f289665SStefano Ceccherini{
763f289665SStefano Ceccherini	control.ResizeToPreferred();
773f289665SStefano Ceccherini	BTextView* pTextView = control.TextView();
783f289665SStefano Ceccherini	float widthExpand = controlWidth;
793f289665SStefano Ceccherini	widthExpand -= control.Bounds().Width();
803f289665SStefano Ceccherini	if (widthExpand > 0) {
813f289665SStefano Ceccherini		control.ResizeBy(widthExpand, 0);
823f289665SStefano Ceccherini		pTextView->ResizeBy(widthExpand, 0);
833f289665SStefano Ceccherini	}
843f289665SStefano Ceccherini	MoveViewCorner(control, pos, posRef);
853f289665SStefano Ceccherini}
863f289665SStefano Ceccherini
873f289665SStefano Ceccherini
883f289665SStefano Ceccherini
893f289665SStefano Ceccherini//--------------------------------------------------------------------
903f289665SStefano Ceccherini//	ViewLayoutFactory implementation member functions
913f289665SStefano Ceccherini
923f289665SStefano Ceccherinivoid ViewLayoutFactory::MoveViewCorner(BView& view, BPoint pos, corner posRef)
933f289665SStefano Ceccherini{
943f289665SStefano Ceccherini	BRect frame = view.Frame();
953f289665SStefano Ceccherini	BPoint topLeft;
963f289665SStefano Ceccherini	switch (posRef) {
973f289665SStefano Ceccherini	case CORNER_TOPLEFT:
983f289665SStefano Ceccherini		topLeft = pos;
993f289665SStefano Ceccherini		break;
1003f289665SStefano Ceccherini	case CORNER_BOTTOMLEFT:
1013f289665SStefano Ceccherini		topLeft.x = pos.x;
1023f289665SStefano Ceccherini		topLeft.y = pos.y - frame.Height();
1033f289665SStefano Ceccherini		break;
1043f289665SStefano Ceccherini	case CORNER_TOPRIGHT:
1053f289665SStefano Ceccherini		topLeft.x = pos.x - frame.Width();
1063f289665SStefano Ceccherini		topLeft.y = pos.y;
1073f289665SStefano Ceccherini		break;
1083f289665SStefano Ceccherini	case CORNER_BOTTOMRIGHT:
1093f289665SStefano Ceccherini		topLeft.x = pos.x - frame.Width();
1103f289665SStefano Ceccherini		topLeft.y = pos.y - frame.Height();
1113f289665SStefano Ceccherini		break;
1123f289665SStefano Ceccherini	}
1133f289665SStefano Ceccherini
1143f289665SStefano Ceccherini	view.MoveTo(topLeft);
1153f289665SStefano Ceccherini}
1163f289665SStefano Ceccherini
1173f289665SStefano Ceccherinivoid ViewLayoutFactory::Align(BList& viewList, align_side side,
1183f289665SStefano Ceccherini	float alignLen)
1193f289665SStefano Ceccherini{
1203f289665SStefano Ceccherini	int32 i, len = viewList.CountItems();
1213f289665SStefano Ceccherini	if (len <= 1) {
1223f289665SStefano Ceccherini		return;
1233f289665SStefano Ceccherini	}
1243f289665SStefano Ceccherini
1253f289665SStefano Ceccherini	// make sure alignment is recognized
1263f289665SStefano Ceccherini	if ((side != ALIGN_LEFT) && (side != ALIGN_TOP)
1273f289665SStefano Ceccherini		&& (side != ALIGN_RIGHT) && (side != ALIGN_BOTTOM)
1283f289665SStefano Ceccherini		&& (side != ALIGN_HCENTER) && (side != ALIGN_VCENTER))
1293f289665SStefano Ceccherini	{
1303f289665SStefano Ceccherini		return;
1313f289665SStefano Ceccherini	}
1323f289665SStefano Ceccherini
1333f289665SStefano Ceccherini	// find initial location for placement, based on head item
1343f289665SStefano Ceccherini	BPoint viewLoc;
1353f289665SStefano Ceccherini	BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(0));
1363f289665SStefano Ceccherini	if (! pView) {
1373f289665SStefano Ceccherini		return;
1383f289665SStefano Ceccherini	}
1393f289665SStefano Ceccherini
1403f289665SStefano Ceccherini	BRect frame = pView->Frame();
1413f289665SStefano Ceccherini	switch (side) {
1423f289665SStefano Ceccherini	case ALIGN_LEFT:
1433f289665SStefano Ceccherini	case ALIGN_TOP:
1443f289665SStefano Ceccherini		viewLoc.Set(frame.left, frame.top);
1453f289665SStefano Ceccherini		break;
1463f289665SStefano Ceccherini	case ALIGN_RIGHT:
1473f289665SStefano Ceccherini		viewLoc.Set(frame.right, frame.top);
1483f289665SStefano Ceccherini		break;
1493f289665SStefano Ceccherini	case ALIGN_BOTTOM:
1503f289665SStefano Ceccherini		viewLoc.Set(frame.left, frame.bottom);
1513f289665SStefano Ceccherini		break;
1523f289665SStefano Ceccherini	case ALIGN_HCENTER:
1533f289665SStefano Ceccherini		viewLoc.Set(frame.left, average(frame.top, frame.bottom));
1543f289665SStefano Ceccherini		break;
1553f289665SStefano Ceccherini	case ALIGN_VCENTER:
1563f289665SStefano Ceccherini		viewLoc.Set(average(frame.left, frame.right), frame.top);
1573f289665SStefano Ceccherini		printf("Aligning along vcenter\nInitial position: ");
1583f289665SStefano Ceccherini		viewLoc.PrintToStream();
1593f289665SStefano Ceccherini		break;
1603f289665SStefano Ceccherini	}
1613f289665SStefano Ceccherini
1623f289665SStefano Ceccherini	// align items relative to head item
1633f289665SStefano Ceccherini	for (i=1; i<len; i++) {
1643f289665SStefano Ceccherini		BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(i));
1653f289665SStefano Ceccherini		if (pView) {
1663f289665SStefano Ceccherini			switch (side) {
1673f289665SStefano Ceccherini			case ALIGN_LEFT:
1683f289665SStefano Ceccherini				viewLoc.y += alignLen;
1693f289665SStefano Ceccherini				MoveViewCorner(*pView, viewLoc, CORNER_TOPLEFT);
1703f289665SStefano Ceccherini				break;
1713f289665SStefano Ceccherini			case ALIGN_TOP:
1723f289665SStefano Ceccherini				viewLoc.x += alignLen;
1733f289665SStefano Ceccherini				MoveViewCorner(*pView, viewLoc, CORNER_TOPLEFT);
1743f289665SStefano Ceccherini				break;
1753f289665SStefano Ceccherini			case ALIGN_RIGHT:
1763f289665SStefano Ceccherini				viewLoc.y += alignLen;
1773f289665SStefano Ceccherini				MoveViewCorner(*pView, viewLoc, CORNER_TOPRIGHT);
1783f289665SStefano Ceccherini				break;
1793f289665SStefano Ceccherini			case ALIGN_BOTTOM:
1803f289665SStefano Ceccherini				viewLoc.x += alignLen;
1813f289665SStefano Ceccherini				MoveViewCorner(*pView, viewLoc, CORNER_BOTTOMLEFT);
1823f289665SStefano Ceccherini				break;
1833f289665SStefano Ceccherini			case ALIGN_HCENTER:
1843f289665SStefano Ceccherini				{
1853f289665SStefano Ceccherini					viewLoc.x += alignLen;
1863f289665SStefano Ceccherini					BPoint moveLoc = viewLoc;
1873f289665SStefano Ceccherini					BRect r = pView->Frame();
1883f289665SStefano Ceccherini					moveLoc.y -= (r.bottom - r.top) / 2;
1893f289665SStefano Ceccherini					MoveViewCorner(*pView, moveLoc, CORNER_TOPLEFT);
1903f289665SStefano Ceccherini					break;
1913f289665SStefano Ceccherini				}
1923f289665SStefano Ceccherini			case ALIGN_VCENTER:
1933f289665SStefano Ceccherini				{
1943f289665SStefano Ceccherini					viewLoc.y += alignLen;
1953f289665SStefano Ceccherini					BPoint moveLoc = viewLoc;
1963f289665SStefano Ceccherini					BRect r = pView->Frame();
1973f289665SStefano Ceccherini					moveLoc.x -= (r.right - r.left) / 2;
1983f289665SStefano Ceccherini					MoveViewCorner(*pView, moveLoc, CORNER_TOPLEFT);
1993f289665SStefano Ceccherini					break;
2003f289665SStefano Ceccherini				}
2013f289665SStefano Ceccherini			}
2023f289665SStefano Ceccherini		}
2033f289665SStefano Ceccherini	}
2043f289665SStefano Ceccherini}
2053f289665SStefano Ceccherini
2063f289665SStefano Ceccherinivoid ViewLayoutFactory::ResizeToListMax(BList& viewList, rect_dim resizeDim,
2073f289665SStefano Ceccherini	corner anchor)
2083f289665SStefano Ceccherini{
2093f289665SStefano Ceccherini	int32 i, len = viewList.CountItems();
2103f289665SStefano Ceccherini	float maxWidth = 0.0f, maxHeight = 0.0f;
2113f289665SStefano Ceccherini	float curWidth = 0.0f, curHeight = 0.0f;
2123f289665SStefano Ceccherini
2133f289665SStefano Ceccherini	// find maximum dimensions
2143f289665SStefano Ceccherini	for (i=0; i<len; i++) {
2153f289665SStefano Ceccherini		BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(i));
2163f289665SStefano Ceccherini		if (pView) {
2173f289665SStefano Ceccherini			BRect frame = pView->Frame();
2183f289665SStefano Ceccherini			curWidth = frame.Width();
2193f289665SStefano Ceccherini			curHeight = frame.Height();
2203f289665SStefano Ceccherini			if (curWidth > maxWidth) {
2213f289665SStefano Ceccherini				maxWidth = curWidth;
2223f289665SStefano Ceccherini			}
2233f289665SStefano Ceccherini			if (curHeight > maxHeight) {
2243f289665SStefano Ceccherini				maxHeight = curHeight;
2253f289665SStefano Ceccherini			}
2263f289665SStefano Ceccherini		}
2273f289665SStefano Ceccherini	}
2283f289665SStefano Ceccherini
2293f289665SStefano Ceccherini	// now resize everything in the list based on selected dimension
2303f289665SStefano Ceccherini	for (i=0; i<len; i++) {
2313f289665SStefano Ceccherini		BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(i));
2323f289665SStefano Ceccherini		if (pView) {
2333f289665SStefano Ceccherini			float newWidth, newHeight;
2343f289665SStefano Ceccherini			BRect frame = pView->Frame();
2353f289665SStefano Ceccherini			newWidth = (resizeDim & RECT_WIDTH)
2363f289665SStefano Ceccherini				? maxWidth : frame.Width();
2373f289665SStefano Ceccherini			newHeight = (resizeDim & RECT_HEIGHT)
2383f289665SStefano Ceccherini				? maxHeight : frame.Height();
2393f289665SStefano Ceccherini			pView->ResizeTo(newWidth, newHeight);
2403f289665SStefano Ceccherini		}
2413f289665SStefano Ceccherini	}
2423f289665SStefano Ceccherini}
2433f289665SStefano Ceccherini
2443f289665SStefano Ceccherinivoid ViewLayoutFactory::ResizeAroundChildren(BView& view, BPoint margin)
2453f289665SStefano Ceccherini{
2463f289665SStefano Ceccherini	float fMax_x = 0.0f, fMax_y = 0.0f;
2473f289665SStefano Ceccherini	int32 numChild = view.CountChildren();
2483f289665SStefano Ceccherini	for (int32 i = 0; i < numChild; i++)
2493f289665SStefano Ceccherini	{
2503f289665SStefano Ceccherini		BView* childView = view.ChildAt(i);
2513f289665SStefano Ceccherini		if (childView) {
2523f289665SStefano Ceccherini			BRect r = childView->Frame();
253372eb874SStefano Ceccherini			fMax_x = std::max(fMax_x, r.right);
254372eb874SStefano Ceccherini			fMax_y = std::max(fMax_y, r.bottom);
2553f289665SStefano Ceccherini		}
2563f289665SStefano Ceccherini	}
2573f289665SStefano Ceccherini
2583f289665SStefano Ceccherini	fMax_x += margin.x;
2593f289665SStefano Ceccherini	fMax_y += margin.y;
2603f289665SStefano Ceccherini	view.ResizeTo(fMax_x, fMax_y);
2613f289665SStefano Ceccherini}
262