xref: /haiku/src/kits/interface/SeparatorView.cpp (revision aabebc302e9b34c10a0a65baad4cb7729adc395c)
1 /*
2  * Copyright 2001-2009, Stephan Aßmus <superstippi@gmx.de>
3  * Copyright 2001-2009, Ingo Weinhold <ingo_weinhold@gmx.de>
4  * All rights reserved. Distributed under the terms of the MIT license.
5  */
6 
7 
8 #include "SeparatorView.h"
9 
10 #include <new>
11 
12 #include <math.h>
13 #include <stdio.h>
14 
15 #include <ControlLook.h>
16 #include <LayoutUtils.h>
17 #include <Region.h>
18 
19 
20 static const float kMinBorderLength = 5.0f;
21 
22 
23 // TODO: Actually implement alignment support!
24 // TODO: More testing, especially archiving.
25 
26 
BSeparatorView(orientation orientation,border_style border)27 BSeparatorView::BSeparatorView(orientation orientation, border_style border)
28 	:
29 	BView(NULL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
30 {
31 	_Init(NULL, NULL, orientation, BAlignment(B_ALIGN_HORIZONTAL_CENTER,
32 		B_ALIGN_VERTICAL_CENTER), border);
33 }
34 
35 
BSeparatorView(const char * name,const char * label,orientation orientation,border_style border,const BAlignment & alignment)36 BSeparatorView::BSeparatorView(const char* name, const char* label,
37 	orientation orientation, border_style border, const BAlignment& alignment)
38 	:
39 	BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
40 {
41 	_Init(label, NULL, orientation, alignment, border);
42 }
43 
44 
BSeparatorView(const char * name,BView * labelView,orientation orientation,border_style border,const BAlignment & alignment)45 BSeparatorView::BSeparatorView(const char* name, BView* labelView,
46 	orientation orientation, border_style border, const BAlignment& alignment)
47 	:
48 	BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
49 {
50 	_Init(NULL, labelView, orientation, alignment, border);
51 }
52 
53 
BSeparatorView(const char * label,orientation orientation,border_style border,const BAlignment & alignment)54 BSeparatorView::BSeparatorView(const char* label,
55 	orientation orientation, border_style border, const BAlignment& alignment)
56 	:
57 	BView("", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
58 {
59 	_Init(label, NULL, orientation, alignment, border);
60 }
61 
62 
BSeparatorView(BView * labelView,orientation orientation,border_style border,const BAlignment & alignment)63 BSeparatorView::BSeparatorView(BView* labelView,
64 	orientation orientation, border_style border, const BAlignment& alignment)
65 	:
66 	BView("", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
67 {
68 	_Init(NULL, labelView, orientation, alignment, border);
69 }
70 
71 
BSeparatorView(BMessage * archive)72 BSeparatorView::BSeparatorView(BMessage* archive)
73 	:
74 	BView(archive),
75 	fLabel(),
76 	fLabelView(NULL),
77 	fOrientation(B_HORIZONTAL),
78 	fAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER,
79 		B_ALIGN_VERTICAL_CENTER)),
80 	fBorder(B_FANCY_BORDER)
81 {
82 	// NULL archives will be caught by BView.
83 
84 	const char* label;
85 	if (archive->FindString("_labelview", &label) == B_OK) {
86 		fLabelView = FindView(label);
87 	} else if (archive->FindString("_label", &label) == B_OK) {
88 		fLabel.SetTo(label);
89 	}
90 
91 	int32 orientation;
92 	if (archive->FindInt32("_orientation", &orientation) == B_OK)
93 		fOrientation = (enum orientation)orientation;
94 
95 	int32 hAlignment;
96 	int32 vAlignment;
97 	if (archive->FindInt32("_halignment", &hAlignment) == B_OK
98 		&& archive->FindInt32("_valignment", &vAlignment) == B_OK) {
99 		fAlignment.horizontal = (alignment)hAlignment;
100 		fAlignment.vertical = (vertical_alignment)vAlignment;
101 	}
102 
103 	int32 borderStyle;
104 	if (archive->FindInt32("_border", &borderStyle) != B_OK)
105 		fBorder = (border_style)borderStyle;
106 }
107 
108 
~BSeparatorView()109 BSeparatorView::~BSeparatorView()
110 {
111 }
112 
113 
114 // #pragma mark - Archiving
115 
116 
117 BArchivable*
Instantiate(BMessage * archive)118 BSeparatorView::Instantiate(BMessage* archive)
119 {
120 	if (validate_instantiation(archive, "BSeparatorView"))
121 		return new (std::nothrow) BSeparatorView(archive);
122 
123 	return NULL;
124 }
125 
126 
127 status_t
Archive(BMessage * into,bool deep) const128 BSeparatorView::Archive(BMessage* into, bool deep) const
129 {
130 	// TODO: Test this.
131 	status_t result = BView::Archive(into, deep);
132 	if (result != B_OK)
133 		return result;
134 
135 	if (fLabelView != NULL)
136 		result = into->AddString("_labelview", fLabelView->Name());
137 	else
138 		result = into->AddString("_label", fLabel.String());
139 
140 	if (result == B_OK)
141 		result = into->AddInt32("_orientation", fOrientation);
142 
143 	if (result == B_OK)
144 		result = into->AddInt32("_halignment", fAlignment.horizontal);
145 
146 	if (result == B_OK)
147 		result = into->AddInt32("_valignment", fAlignment.vertical);
148 
149 	if (result == B_OK)
150 		result = into->AddInt32("_border", fBorder);
151 
152 	return result;
153 }
154 
155 
156 // #pragma mark -
157 
158 
159 void
Draw(BRect updateRect)160 BSeparatorView::Draw(BRect updateRect)
161 {
162 	rgb_color bgColor = ui_color(B_PANEL_BACKGROUND_COLOR);
163 	rgb_color highColor = ui_color(B_PANEL_TEXT_COLOR);
164 
165 	if (BView* parent = Parent()) {
166 		if (parent->ViewColor() != B_TRANSPARENT_COLOR) {
167 			bgColor = parent->ViewColor();
168 			highColor = parent->HighColor();
169 		}
170 	}
171 
172 	BRect labelBounds;
173 	if (fLabelView != NULL) {
174 		labelBounds = fLabelView->Frame();
175 	} else if (fLabel.CountChars() > 0) {
176 		labelBounds = _MaxLabelBounds();
177 		float labelWidth = StringWidth(fLabel.String());
178 		if (fOrientation == B_HORIZONTAL) {
179 			switch (fAlignment.horizontal) {
180 				case B_ALIGN_LEFT:
181 				default:
182 					labelBounds.right = labelBounds.left + labelWidth;
183 					break;
184 
185 				case B_ALIGN_RIGHT:
186 					labelBounds.left = labelBounds.right - labelWidth;
187 					break;
188 
189 				case B_ALIGN_CENTER:
190 					labelBounds.left = (labelBounds.left + labelBounds.right
191 						- labelWidth) / 2;
192 					labelBounds.right = labelBounds.left + labelWidth;
193 					break;
194 			}
195 		} else {
196 			switch (fAlignment.vertical) {
197 				case B_ALIGN_TOP:
198 				default:
199 					labelBounds.bottom = labelBounds.top + labelWidth;
200 					break;
201 
202 				case B_ALIGN_BOTTOM:
203 					labelBounds.top = labelBounds.bottom - labelWidth;
204 					break;
205 
206 				case B_ALIGN_MIDDLE:
207 					labelBounds.top = (labelBounds.top + labelBounds.bottom
208 						- labelWidth) / 2;
209 					labelBounds.bottom = labelBounds.top + labelWidth;
210 					break;
211 			}
212 		}
213 	}
214 
215 	BRect bounds = Bounds();
216 	BRegion region(bounds);
217 	if (labelBounds.IsValid()) {
218 		region.Exclude(labelBounds);
219 		ConstrainClippingRegion(&region);
220 	}
221 
222 	float borderSize = _BorderSize();
223 	if (borderSize > 0.0f) {
224 		if (fOrientation == B_HORIZONTAL) {
225 			bounds.top = floorf((bounds.top + bounds.bottom + 1 - borderSize)
226 				/ 2);
227 			bounds.bottom = bounds.top + borderSize - 1;
228 			region.Exclude(bounds);
229 			be_control_look->DrawBorder(this, bounds, updateRect, bgColor,
230 				fBorder, 0, BControlLook::B_TOP_BORDER);
231 		} else {
232 			bounds.left = floorf((bounds.left + bounds.right + 1 - borderSize)
233 				/ 2);
234 			bounds.right = bounds.left + borderSize - 1;
235 			region.Exclude(bounds);
236 			be_control_look->DrawBorder(this, bounds, updateRect, bgColor,
237 				fBorder, 0, BControlLook::B_LEFT_BORDER);
238 		}
239 		if (labelBounds.IsValid())
240 			region.Include(labelBounds);
241 
242 		ConstrainClippingRegion(&region);
243 	}
244 
245 	SetLowColor(bgColor);
246 	FillRect(updateRect, B_SOLID_LOW);
247 
248 	if (fLabel.CountChars() > 0) {
249 		font_height fontHeight;
250 		GetFontHeight(&fontHeight);
251 
252 		SetHighColor(highColor);
253 
254 		if (fOrientation == B_HORIZONTAL) {
255 			DrawString(fLabel.String(), BPoint(labelBounds.left,
256 				labelBounds.top + ceilf(fontHeight.ascent)));
257 		} else {
258 			DrawString(fLabel.String(), BPoint(labelBounds.left
259 				+ ceilf(fontHeight.ascent), labelBounds.bottom));
260 		}
261 	}
262 }
263 
264 
265 void
GetPreferredSize(float * _width,float * _height)266 BSeparatorView::GetPreferredSize(float* _width, float* _height)
267 {
268 	float width = 0.0f;
269 	float height = 0.0f;
270 
271 	if (fLabelView != NULL) {
272 		fLabelView->GetPreferredSize(&width, &height);
273 	} else if (fLabel.CountChars() > 0) {
274 		width = StringWidth(fLabel.String());
275 		font_height fontHeight;
276 		GetFontHeight(&fontHeight);
277 		height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
278 		if (fOrientation == B_VERTICAL) {
279 			// swap width and height
280 			float temp = height;
281 			height = width;
282 			width = temp;
283 		}
284 	}
285 
286 	float borderSize = _BorderSize();
287 
288 	// Add some room for the border
289 	if (fOrientation == B_HORIZONTAL) {
290 		width += kMinBorderLength * 2.0f;
291 		height = max_c(height, borderSize - 1.0f);
292 	} else {
293 		height += kMinBorderLength * 2.0f;
294 		width = max_c(width, borderSize - 1.0f);
295 	}
296 
297 	if (_width != NULL)
298 		*_width = width;
299 
300 	if (_height != NULL)
301 		*_height = height;
302 }
303 
304 
305 BSize
MinSize()306 BSeparatorView::MinSize()
307 {
308 	BSize size;
309 	GetPreferredSize(&size.width, &size.height);
310 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
311 }
312 
313 
314 BSize
MaxSize()315 BSeparatorView::MaxSize()
316 {
317 	BSize size(MinSize());
318 	if (fOrientation == B_HORIZONTAL)
319 		size.width = B_SIZE_UNLIMITED;
320 	else
321 		size.height = B_SIZE_UNLIMITED;
322 
323 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
324 }
325 
326 
327 BSize
PreferredSize()328 BSeparatorView::PreferredSize()
329 {
330 	BSize size;
331 	GetPreferredSize(&size.width, &size.height);
332 
333 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size);
334 }
335 
336 
337 // #pragma mark -
338 
339 
340 void
SetOrientation(orientation orientation)341 BSeparatorView::SetOrientation(orientation orientation)
342 {
343 	if (orientation == fOrientation)
344 		return;
345 
346 	fOrientation = orientation;
347 
348 	BFont font;
349 	GetFont(&font);
350 	if (fOrientation == B_VERTICAL)
351 		font.SetRotation(90.0f);
352 
353 	SetFont(&font);
354 
355 	Invalidate();
356 	InvalidateLayout();
357 }
358 
359 
360 void
SetAlignment(const BAlignment & aligment)361 BSeparatorView::SetAlignment(const BAlignment& aligment)
362 {
363 	if (aligment == fAlignment)
364 		return;
365 
366 	fAlignment = aligment;
367 
368 	Invalidate();
369 	InvalidateLayout();
370 }
371 
372 
373 void
SetBorderStyle(border_style border)374 BSeparatorView::SetBorderStyle(border_style border)
375 {
376 	if (border == fBorder)
377 		return;
378 
379 	fBorder = border;
380 
381 	Invalidate();
382 }
383 
384 
385 void
SetLabel(const char * label)386 BSeparatorView::SetLabel(const char* label)
387 {
388 	if (label == NULL)
389 		label = "";
390 
391 	if (fLabel == label)
392 		return;
393 
394 	fLabel.SetTo(label);
395 
396 	Invalidate();
397 	InvalidateLayout();
398 }
399 
400 
401 void
SetLabel(BView * view,bool deletePrevious)402 BSeparatorView::SetLabel(BView* view, bool deletePrevious)
403 {
404 	if (fLabelView == view)
405 		return;
406 
407 	if (fLabelView != NULL) {
408 		fLabelView->RemoveSelf();
409 		if (deletePrevious)
410 			delete fLabelView;
411 	}
412 
413 	fLabelView = view;
414 
415 	if (fLabelView != NULL)
416 		AddChild(view);
417 }
418 
419 
420 status_t
Perform(perform_code code,void * data)421 BSeparatorView::Perform(perform_code code, void* data)
422 {
423 	return BView::Perform(code, data);
424 }
425 
426 
427 // #pragma mark - protected/private
428 
429 
430 void
DoLayout()431 BSeparatorView::DoLayout()
432 {
433 	BView::DoLayout();
434 
435 	if (fLabelView == NULL)
436 		return;
437 
438 	BRect bounds = _MaxLabelBounds();
439 	BRect frame = BLayoutUtils::AlignInFrame(bounds, fLabelView->MaxSize(),
440 		fAlignment);
441 
442 	fLabelView->MoveTo(frame.LeftTop());
443 	fLabelView->ResizeTo(frame.Width(), frame.Height());
444 }
445 
446 
447 void
_Init(const char * label,BView * labelView,orientation orientation,BAlignment alignment,border_style border)448 BSeparatorView::_Init(const char* label, BView* labelView,
449 	orientation orientation, BAlignment alignment, border_style border)
450 {
451 	fLabel = "";
452 	fLabelView = NULL;
453 
454 	fOrientation = B_HORIZONTAL;
455 	fAlignment = alignment;
456 	fBorder = border;
457 
458 	SetFont(be_bold_font);
459 	SetViewColor(B_TRANSPARENT_32_BIT);
460 
461 	SetLabel(label);
462 	SetLabel(labelView, true);
463 	SetOrientation(orientation);
464 }
465 
466 
467 float
_BorderSize() const468 BSeparatorView::_BorderSize() const
469 {
470 	// TODO: Get these values from the BControlLook class.
471 	switch (fBorder) {
472 		case B_PLAIN_BORDER:
473 			return 1.0f;
474 
475 		case B_FANCY_BORDER:
476 			return 2.0f;
477 
478 		case B_NO_BORDER:
479 		default:
480 			return 0.0f;
481 	}
482 }
483 
484 
485 BRect
_MaxLabelBounds() const486 BSeparatorView::_MaxLabelBounds() const
487 {
488 	BRect bounds = Bounds();
489 	if (fOrientation == B_HORIZONTAL)
490 		bounds.InsetBy(kMinBorderLength, 0.0f);
491 	else
492 		bounds.InsetBy(0.0f, kMinBorderLength);
493 
494 	return bounds;
495 }
496 
497 
498 // #pragma mark - FBC padding
499 
500 
_ReservedSeparatorView1()501 void BSeparatorView::_ReservedSeparatorView1() {}
_ReservedSeparatorView2()502 void BSeparatorView::_ReservedSeparatorView2() {}
_ReservedSeparatorView3()503 void BSeparatorView::_ReservedSeparatorView3() {}
_ReservedSeparatorView4()504 void BSeparatorView::_ReservedSeparatorView4() {}
_ReservedSeparatorView5()505 void BSeparatorView::_ReservedSeparatorView5() {}
_ReservedSeparatorView6()506 void BSeparatorView::_ReservedSeparatorView6() {}
_ReservedSeparatorView7()507 void BSeparatorView::_ReservedSeparatorView7() {}
_ReservedSeparatorView8()508 void BSeparatorView::_ReservedSeparatorView8() {}
_ReservedSeparatorView9()509 void BSeparatorView::_ReservedSeparatorView9() {}
_ReservedSeparatorView10()510 void BSeparatorView::_ReservedSeparatorView10() {}
511