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