xref: /haiku/src/kits/interface/Box.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 /*
2  * Copyright (c) 2001-2005, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stephan Aßmus <superstippi@gmx.de>
8  *		DarkWyrm <bpmagic@columbus.rr.com>
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include <Box.h>
16 #include <Message.h>
17 
18 
19 BBox::BBox(BRect frame, const char *name, uint32 resizingMode, uint32 flags,
20 		   border_style border)
21 	:	BView(frame, name, resizingMode, flags | B_FRAME_EVENTS),
22 		fStyle(border)
23 {
24 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
25 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
26 
27 	InitObject();
28 }
29 
30 
31 BBox::~BBox()
32 {
33 	ClearAnyLabel();
34 }
35 
36 
37 BBox::BBox(BMessage *archive)
38 	:	BView(archive)
39 {
40 	InitObject(archive);
41 
42 	const char *string;
43 
44 	if (archive->FindString("_label", &string) == B_OK)
45 		SetLabel(string);
46 
47 	bool aBool;
48 	int32 anInt32;
49 
50 	if (archive->FindBool("_style", &aBool) == B_OK)
51 		fStyle = aBool ? B_FANCY_BORDER : B_PLAIN_BORDER;
52 	else if (archive->FindInt32("_style", &anInt32) == B_OK)
53 		fStyle = (border_style)anInt32;
54 
55 	if (archive->FindBool("_lblview", &aBool) == B_OK)
56 		fLabelView = ChildAt(0);
57 }
58 
59 
60 BArchivable *
61 BBox::Instantiate(BMessage *archive)
62 {
63 	if (validate_instantiation(archive, "BBox"))
64 		return new BBox(archive);
65 	else
66 		return NULL;
67 }
68 
69 
70 status_t
71 BBox::Archive(BMessage *archive, bool deep) const
72 {
73 	BView::Archive(archive, deep);
74 
75 	if (fLabel)
76 		 archive->AddString("_label", fLabel);
77 
78 	if (fLabelView)
79 		 archive->AddBool("_lblview", true);
80 
81 	if (fStyle != B_FANCY_BORDER)
82 		archive->AddInt32("_style", fStyle);
83 
84 	return B_OK;
85 }
86 
87 
88 void
89 BBox::SetBorder(border_style border)
90 {
91 	fStyle = border;
92 
93 	if (Window() != NULL && LockLooper()) {
94 		Invalidate();
95 		UnlockLooper();
96 	}
97 }
98 
99 
100 border_style
101 BBox::Border() const
102 {
103 	return fStyle;
104 }
105 
106 
107 void
108 BBox::SetLabel(const char *string)
109 {
110 	ClearAnyLabel();
111 
112 	if (string) {
113 		// Update fBounds
114 		fBounds = Bounds();
115 		font_height fh;
116 		GetFontHeight(&fh);
117 
118 		fBounds.top = (float)ceil((fh.ascent + fh.descent) / 2.0f);
119 
120 		fLabel = strdup(string);
121 	}
122 
123 	if (Window())
124 		Invalidate();
125 }
126 
127 
128 status_t
129 BBox::SetLabel(BView *viewLabel)
130 {
131 	ClearAnyLabel();
132 
133 	if (viewLabel) {
134 		// Update fBounds
135 		fBounds = Bounds();
136 
137 		fBounds.top = ceilf(viewLabel->Bounds().Height() / 2.0f);
138 
139 		fLabelView = viewLabel;
140 		fLabelView->MoveTo(10.0f, 0.0f);
141 		AddChild(fLabelView, ChildAt(0));
142 	}
143 
144 	if (Window())
145 		Invalidate();
146 
147 	return B_OK;
148 }
149 
150 
151 const char *
152 BBox::Label() const
153 {
154 	return fLabel;
155 }
156 
157 
158 BView *
159 BBox::LabelView() const
160 {
161 	return fLabelView;
162 }
163 
164 
165 void
166 BBox::Draw(BRect updateRect)
167 {
168 	switch (fStyle) {
169 		case B_FANCY_BORDER:
170 			DrawFancy();
171 			break;
172 
173 		case B_PLAIN_BORDER:
174 			DrawPlain();
175 			break;
176 
177 		default:
178 			break;
179 	}
180 
181 	if (fLabel) {
182 		font_height fh;
183 		GetFontHeight(&fh);
184 
185 		SetHighColor(ViewColor());
186 
187 		FillRect(BRect(6.0f, 1.0f, 12.0f + StringWidth(fLabel),
188 			(float)ceil(fh.ascent + fh.descent))/*, B_SOLID_LOW*/);
189 
190 		SetHighColor(0, 0, 0);
191 		DrawString(fLabel, BPoint(10.0f, (float)ceil(fh.ascent - fh.descent)
192 			+ 1.0f));
193 	}
194 }
195 
196 
197 void BBox::AttachedToWindow()
198 {
199 	if (Parent()) {
200 		SetViewColor(Parent()->ViewColor());
201 		SetLowColor(Parent()->ViewColor());
202 	}
203 }
204 
205 
206 void
207 BBox::DetachedFromWindow()
208 {
209 	BView::DetachedFromWindow();
210 }
211 
212 
213 void
214 BBox::AllAttached()
215 {
216 	BView::AllAttached();
217 }
218 
219 
220 void
221 BBox::AllDetached()
222 {
223 	BView::AllDetached();
224 }
225 
226 
227 void
228 BBox::FrameResized(float width, float height)
229 {
230 	BRect bounds(Bounds());
231 
232 	// invalidate the regions that the app_server did not
233 	// (for removing the previous or drawing the new border)
234 	if (fStyle != B_NO_BORDER) {
235 
236 		int32 borderSize = fStyle == B_PLAIN_BORDER ? 0 : 1;
237 
238 		BRect invalid(bounds);
239 		if (fBounds.right < bounds.right) {
240 			// enlarging
241 			invalid.left = fBounds.right - borderSize;
242 			invalid.right = fBounds.right;
243 
244 			Invalidate(invalid);
245 		} else if (fBounds.right > bounds.right) {
246 			// shrinking
247 			invalid.left = bounds.right - borderSize;
248 
249 			Invalidate(invalid);
250 		}
251 
252 		invalid = bounds;
253 		if (fBounds.bottom < bounds.bottom) {
254 			// enlarging
255 			invalid.top = fBounds.bottom - borderSize;
256 			invalid.bottom = fBounds.bottom;
257 
258 			Invalidate(invalid);
259 		} else if (fBounds.bottom > bounds.bottom) {
260 			// shrinking
261 			invalid.top = bounds.bottom - borderSize;
262 
263 			Invalidate(invalid);
264 		}
265 	}
266 
267 	fBounds.right = bounds.right;
268 	fBounds.bottom = bounds.bottom;
269 }
270 
271 
272 void
273 BBox::MessageReceived(BMessage *message)
274 {
275 	BView::MessageReceived(message);
276 }
277 
278 
279 void
280 BBox::MouseDown(BPoint point)
281 {
282 	BView::MouseDown(point);
283 }
284 
285 
286 void
287 BBox::MouseUp(BPoint point)
288 {
289 	BView::MouseUp(point);
290 }
291 
292 
293 void
294 BBox::WindowActivated(bool active)
295 {
296 	BView::WindowActivated(active);
297 }
298 
299 
300 void
301 BBox::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
302 {
303 	BView::MouseMoved(point, transit, message);
304 }
305 
306 
307 void
308 BBox::FrameMoved(BPoint newLocation)
309 {
310 	BView::FrameMoved(newLocation);
311 }
312 
313 
314 BHandler *
315 BBox::ResolveSpecifier(BMessage *message, int32 index,
316 								 BMessage *specifier, int32 what,
317 								 const char *property)
318 {
319 	return BView::ResolveSpecifier(message, index, specifier, what, property);
320 }
321 
322 
323 void
324 BBox::ResizeToPreferred()
325 {
326 	BView::ResizeToPreferred();
327 }
328 
329 
330 void
331 BBox::GetPreferredSize(float *width, float *height)
332 {
333 	bool label = true;
334 	// acount for label
335 	if (fLabelView) {
336 		fLabelView->GetPreferredSize(width, height);
337 		*width += 10.0;
338 			// the label view is placed 10 pixels from the left
339 	} else if (fLabel) {
340 		font_height fh;
341 		GetFontHeight(&fh);
342 		*width += ceilf(StringWidth(fLabel));
343 		*height += ceilf(fh.ascent + fh.descent);
344 	} else {
345 		label = false;
346 		*width = 0;
347 		*height = 0;
348 	}
349 	// acount for border
350 	switch (fStyle) {
351 		case B_NO_BORDER:
352 			break;
353 		case B_PLAIN_BORDER:
354 			// label: (1 pixel for border + 1 pixel for padding) * 2
355 			// no label: (1 pixel for border) * 2 + 1 pixel for padding
356 			*width += label ? 4 : 3;
357 			// label: 1 pixel for bottom border + 1 pixel for padding
358 			// no label: (1 pixel for border) * 2 + 1 pixel for padding
359 			*height += label ? 2 : 3;
360 			break;
361 		case B_FANCY_BORDER:
362 			// label: (2 pixel for border + 1 pixel for padding) * 2
363 			// no label: (2 pixel for border) * 2 + 1 pixel for padding
364 			*width += label ? 6 : 5;
365 			// label: 2 pixel for bottom border + 1 pixel for padding
366 			// no label: (2 pixel for border) * 2 + 1 pixel for padding
367 			*height += label ? 3 : 5;
368 			break;
369 	}
370 	// NOTE: children are ignored, you can use BBox::GetPreferredSize()
371 	// to get the minimum size of this object, then add the size
372 	// of your child(ren) plus inner padding for the final size
373 }
374 
375 
376 void
377 BBox::MakeFocus(bool focused)
378 {
379 	BView::MakeFocus(focused);
380 }
381 
382 
383 status_t
384 BBox::GetSupportedSuites(BMessage *message)
385 {
386 	return BView::GetSupportedSuites(message);
387 }
388 
389 
390 status_t
391 BBox::Perform(perform_code d, void *arg)
392 {
393 	return BView::Perform(d, arg);
394 }
395 
396 
397 void BBox::_ReservedBox1() {}
398 void BBox::_ReservedBox2() {}
399 
400 
401 BBox &
402 BBox::operator=(const BBox &)
403 {
404 	return *this;
405 }
406 
407 
408 void
409 BBox::InitObject(BMessage *data)
410 {
411 	fLabel = NULL;
412 	fBounds = Bounds();
413 	fLabelView = NULL;
414 
415 	int32 flags = 0;
416 
417 	BFont font(be_bold_font);
418 
419 	if (!data || !data->HasString("_fname"))
420 		flags = B_FONT_FAMILY_AND_STYLE;
421 
422 	if (!data || !data->HasFloat("_fflt"))
423 		flags |= B_FONT_SIZE;
424 
425 	if (flags != 0)
426 		SetFont(&font, flags);
427 }
428 
429 
430 void
431 BBox::DrawPlain()
432 {
433 	BRect r = fBounds;
434 
435 	rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
436 	rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT);
437 
438 	BeginLineArray(4);
439 		AddLine(BPoint(r.left, r.bottom),
440 				BPoint(r.left, r.top), light);
441 		AddLine(BPoint(r.left + 1.0f, r.top),
442 				BPoint(r.right, r.top), light);
443 		AddLine(BPoint(r.left + 1.0f, r.bottom),
444 				BPoint(r.right, r.bottom), shadow);
445 		AddLine(BPoint(r.right, r.bottom - 1.0f),
446 				BPoint(r.right, r.top + 1.0f), shadow);
447 	EndLineArray();
448 }
449 
450 
451 void
452 BBox::DrawFancy()
453 {
454 	BRect r = fBounds;
455 
456 	rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
457 	rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT);
458 
459 	BeginLineArray(8);
460 		AddLine(BPoint(r.left, r.bottom),
461 				BPoint(r.left, r.top), shadow);
462 		AddLine(BPoint(r.left + 1.0f, r.top),
463 				BPoint(r.right, r.top), shadow);
464 		AddLine(BPoint(r.left + 1.0f, r.bottom),
465 				BPoint(r.right, r.bottom), light);
466 		AddLine(BPoint(r.right, r.bottom - 1.0f),
467 				BPoint(r.right, r.top + 1.0f), light);
468 
469 		r.InsetBy(1.0, 1.0);
470 
471 		AddLine(BPoint(r.left, r.bottom),
472 				BPoint(r.left, r.top), light);
473 		AddLine(BPoint(r.left + 1.0f, r.top),
474 				BPoint(r.right, r.top), light);
475 		AddLine(BPoint(r.left + 1.0f, r.bottom),
476 				BPoint(r.right, r.bottom), shadow);
477 		AddLine(BPoint(r.right, r.bottom - 1.0f),
478 				BPoint(r.right, r.top + 1.0f), shadow);
479 	EndLineArray();
480 }
481 
482 
483 void
484 BBox::ClearAnyLabel()
485 {
486 	fBounds.top = 0;
487 
488 	if (fLabel) {
489 		free(fLabel);
490 		fLabel = NULL;
491 	} else if (fLabelView) {
492 		fLabelView->RemoveSelf();
493 		delete fLabelView;
494 		fLabelView = NULL;
495 	}
496 }
497