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(®ion);
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(®ion);
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