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