1//--------------------------------------------------------------------
2//
3//	ViewLayoutFactory.cpp
4//
5//	Written by: Owen Smith
6//
7//--------------------------------------------------------------------
8
9/*
10	Copyright 1999, Be Incorporated.   All Rights Reserved.
11	This file may be used under the terms of the Be Sample Code License.
12*/
13
14#include "ViewLayoutFactory.h"
15
16#include <Button.h>
17#include <CheckBox.h>
18#include <TextControl.h>
19#include <View.h>
20#include <List.h>
21#include <algorithm>
22#include <assert.h>
23#include <stdio.h>
24
25template <class T>
26inline T average(const T& x, const T& y)
27{
28	return (x + y) / 2;
29}
30
31
32//--------------------------------------------------------------------
33//	ViewLayoutFactory factory generators
34
35BButton* ViewLayoutFactory::MakeButton(const char* name, const char* label,
36	uint32 msgID, BPoint pos, corner posRef)
37{
38	BRect dummyFrame(0,0,0,0);
39	BButton* pButton = new BButton(dummyFrame, name, label,
40		new BMessage(msgID));
41	pButton->ResizeToPreferred();
42	MoveViewCorner(*pButton, pos, posRef);
43	return pButton;
44}
45
46BCheckBox* ViewLayoutFactory::MakeCheckBox(const char* name,
47	const char* label, uint32 msgID, BPoint pos, corner posRef)
48{
49	BRect dummyFrame(0,0,0,0);
50	BCheckBox* pCheckBox = new BCheckBox(dummyFrame, name, label,
51		new BMessage(msgID));
52	pCheckBox->ResizeToPreferred();
53	MoveViewCorner(*pCheckBox, pos, posRef);
54	return pCheckBox;
55}
56
57BTextControl* ViewLayoutFactory::MakeTextControl(const char* name,
58	const char* label, const char* text, BPoint pos, float controlWidth,
59	corner posRef)
60{
61	// Note: this function is almost identical to the regular
62	// BTextControl constructor, but it minimizes the label
63	// width and maximizes the field width, instead of divvying
64	// them up half-&-half or 2 : 3, and gives the standard
65	// flexibility of corner positioning.
66	BRect dummyFrame(0,0,0,0);
67	BTextControl* pCtrl = new BTextControl(dummyFrame, name, label,
68		text, NULL);
69	LayoutTextControl(*pCtrl, pos, controlWidth, posRef);
70	return pCtrl;
71}
72
73void ViewLayoutFactory::LayoutTextControl(BTextControl& control,
74	BPoint pos, float controlWidth, corner posRef)
75{
76	control.ResizeToPreferred();
77	BTextView* pTextView = control.TextView();
78	float widthExpand = controlWidth;
79	widthExpand -= control.Bounds().Width();
80	if (widthExpand > 0) {
81		control.ResizeBy(widthExpand, 0);
82		pTextView->ResizeBy(widthExpand, 0);
83	}
84	MoveViewCorner(control, pos, posRef);
85}
86
87
88
89//--------------------------------------------------------------------
90//	ViewLayoutFactory implementation member functions
91
92void ViewLayoutFactory::MoveViewCorner(BView& view, BPoint pos, corner posRef)
93{
94	BRect frame = view.Frame();
95	BPoint topLeft;
96	switch (posRef) {
97	case CORNER_TOPLEFT:
98		topLeft = pos;
99		break;
100	case CORNER_BOTTOMLEFT:
101		topLeft.x = pos.x;
102		topLeft.y = pos.y - frame.Height();
103		break;
104	case CORNER_TOPRIGHT:
105		topLeft.x = pos.x - frame.Width();
106		topLeft.y = pos.y;
107		break;
108	case CORNER_BOTTOMRIGHT:
109		topLeft.x = pos.x - frame.Width();
110		topLeft.y = pos.y - frame.Height();
111		break;
112	}
113
114	view.MoveTo(topLeft);
115}
116
117void ViewLayoutFactory::Align(BList& viewList, align_side side,
118	float alignLen)
119{
120	int32 i, len = viewList.CountItems();
121	if (len <= 1) {
122		return;
123	}
124
125	// make sure alignment is recognized
126	if ((side != ALIGN_LEFT) && (side != ALIGN_TOP)
127		&& (side != ALIGN_RIGHT) && (side != ALIGN_BOTTOM)
128		&& (side != ALIGN_HCENTER) && (side != ALIGN_VCENTER))
129	{
130		return;
131	}
132
133	// find initial location for placement, based on head item
134	BPoint viewLoc;
135	BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(0));
136	if (! pView) {
137		return;
138	}
139
140	BRect frame = pView->Frame();
141	switch (side) {
142	case ALIGN_LEFT:
143	case ALIGN_TOP:
144		viewLoc.Set(frame.left, frame.top);
145		break;
146	case ALIGN_RIGHT:
147		viewLoc.Set(frame.right, frame.top);
148		break;
149	case ALIGN_BOTTOM:
150		viewLoc.Set(frame.left, frame.bottom);
151		break;
152	case ALIGN_HCENTER:
153		viewLoc.Set(frame.left, average(frame.top, frame.bottom));
154		break;
155	case ALIGN_VCENTER:
156		viewLoc.Set(average(frame.left, frame.right), frame.top);
157		printf("Aligning along vcenter\nInitial position: ");
158		viewLoc.PrintToStream();
159		break;
160	}
161
162	// align items relative to head item
163	for (i=1; i<len; i++) {
164		BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(i));
165		if (pView) {
166			switch (side) {
167			case ALIGN_LEFT:
168				viewLoc.y += alignLen;
169				MoveViewCorner(*pView, viewLoc, CORNER_TOPLEFT);
170				break;
171			case ALIGN_TOP:
172				viewLoc.x += alignLen;
173				MoveViewCorner(*pView, viewLoc, CORNER_TOPLEFT);
174				break;
175			case ALIGN_RIGHT:
176				viewLoc.y += alignLen;
177				MoveViewCorner(*pView, viewLoc, CORNER_TOPRIGHT);
178				break;
179			case ALIGN_BOTTOM:
180				viewLoc.x += alignLen;
181				MoveViewCorner(*pView, viewLoc, CORNER_BOTTOMLEFT);
182				break;
183			case ALIGN_HCENTER:
184				{
185					viewLoc.x += alignLen;
186					BPoint moveLoc = viewLoc;
187					BRect r = pView->Frame();
188					moveLoc.y -= (r.bottom - r.top) / 2;
189					MoveViewCorner(*pView, moveLoc, CORNER_TOPLEFT);
190					break;
191				}
192			case ALIGN_VCENTER:
193				{
194					viewLoc.y += alignLen;
195					BPoint moveLoc = viewLoc;
196					BRect r = pView->Frame();
197					moveLoc.x -= (r.right - r.left) / 2;
198					MoveViewCorner(*pView, moveLoc, CORNER_TOPLEFT);
199					break;
200				}
201			}
202		}
203	}
204}
205
206void ViewLayoutFactory::ResizeToListMax(BList& viewList, rect_dim resizeDim,
207	corner anchor)
208{
209	int32 i, len = viewList.CountItems();
210	float maxWidth = 0.0f, maxHeight = 0.0f;
211	float curWidth = 0.0f, curHeight = 0.0f;
212
213	// find maximum dimensions
214	for (i=0; i<len; i++) {
215		BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(i));
216		if (pView) {
217			BRect frame = pView->Frame();
218			curWidth = frame.Width();
219			curHeight = frame.Height();
220			if (curWidth > maxWidth) {
221				maxWidth = curWidth;
222			}
223			if (curHeight > maxHeight) {
224				maxHeight = curHeight;
225			}
226		}
227	}
228
229	// now resize everything in the list based on selected dimension
230	for (i=0; i<len; i++) {
231		BView* pView = reinterpret_cast<BView*>(viewList.ItemAt(i));
232		if (pView) {
233			float newWidth, newHeight;
234			BRect frame = pView->Frame();
235			newWidth = (resizeDim & RECT_WIDTH)
236				? maxWidth : frame.Width();
237			newHeight = (resizeDim & RECT_HEIGHT)
238				? maxHeight : frame.Height();
239			pView->ResizeTo(newWidth, newHeight);
240		}
241	}
242}
243
244void ViewLayoutFactory::ResizeAroundChildren(BView& view, BPoint margin)
245{
246	float fMax_x = 0.0f, fMax_y = 0.0f;
247	int32 numChild = view.CountChildren();
248	for (int32 i = 0; i < numChild; i++)
249	{
250		BView* childView = view.ChildAt(i);
251		if (childView) {
252			BRect r = childView->Frame();
253			fMax_x = std::max(fMax_x, r.right);
254			fMax_y = std::max(fMax_y, r.bottom);
255		}
256	}
257
258	fMax_x += margin.x;
259	fMax_y += margin.y;
260	view.ResizeTo(fMax_x, fMax_y);
261}
262