1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Button.cpp 23 // Author: Marc Flerackers (mflerackers@androme.be) 24 // Description: BButton displays and controls a button in a window. 25 //------------------------------------------------------------------------------ 26 27 // Standard Includes ----------------------------------------------------------- 28 29 // System Includes ------------------------------------------------------------- 30 #include <Button.h> 31 #include <Window.h> 32 #include <Errors.h> 33 34 // Project Includes ------------------------------------------------------------ 35 36 // Local Includes -------------------------------------------------------------- 37 38 // Local Defines --------------------------------------------------------------- 39 40 // Globals --------------------------------------------------------------------- 41 42 //------------------------------------------------------------------------------ 43 BButton::BButton(BRect frame, const char *name, const char *label, BMessage *message, 44 uint32 resizingMode, uint32 flags) 45 : BControl(frame, name, label, message, resizingMode, flags |= B_WILL_DRAW), 46 fDrawAsDefault(false) 47 { 48 // Resize to minimum height if needed 49 font_height fh; 50 GetFontHeight(&fh); 51 float minHeight = 12.0f + (float)ceil(fh.ascent + fh.descent); 52 if (Bounds().Height() < minHeight) 53 ResizeTo(Bounds().Width(), minHeight); 54 } 55 //------------------------------------------------------------------------------ 56 BButton::~BButton() 57 { 58 } 59 //------------------------------------------------------------------------------ 60 BButton::BButton(BMessage *archive) 61 : BControl (archive) 62 { 63 if (archive->FindBool("_default", &fDrawAsDefault) != B_OK) 64 fDrawAsDefault = false; 65 } 66 //------------------------------------------------------------------------------ 67 BArchivable *BButton::Instantiate(BMessage *archive) 68 { 69 if (validate_instantiation(archive, "BButton")) 70 return new BButton(archive); 71 else 72 return NULL; 73 } 74 //------------------------------------------------------------------------------ 75 status_t BButton::Archive(BMessage* archive, bool deep) const 76 { 77 status_t err = BControl::Archive(archive, deep); 78 79 if (err != B_OK) 80 return err; 81 82 if (IsDefault()) 83 err = archive->AddBool("_default", true); 84 85 return err; 86 } 87 //------------------------------------------------------------------------------ 88 void BButton::Draw(BRect updateRect) 89 { 90 font_height fh; 91 GetFontHeight(&fh); 92 93 BRect bounds(Bounds()); 94 95 // If the focus is changing, just redraw the focus indicator 96 if (IsFocusChanging()) 97 { 98 float x = (bounds.right - StringWidth(Label())) / 2.0f; 99 float y = bounds.bottom - fh.descent - (IsDefault() ? 6.0f : 3.0f); 100 101 if (IsFocus()) 102 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 103 else 104 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 105 B_LIGHTEN_1_TINT)); 106 107 StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y)); 108 109 return; 110 } 111 112 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 113 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 114 lighten2 = tint_color(no_tint, B_LIGHTEN_2_TINT), 115 lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT), 116 darken2 = tint_color(no_tint, B_DARKEN_2_TINT), 117 darken4 = tint_color(no_tint, B_DARKEN_4_TINT), 118 darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT); 119 120 BRect rect(bounds); 121 122 if (IsDefault()) 123 rect = DrawDefault(rect, IsEnabled()); 124 else 125 rect.InsetBy(1,1); 126 127 if (IsEnabled()) 128 { 129 // This can be set outside draw 130 SetHighColor(darken4); 131 132 // Dark border 133 StrokeRect(rect); 134 135 BeginLineArray(8); 136 137 // Corners 138 AddLine(rect.LeftBottom(), rect.LeftBottom(), no_tint); 139 AddLine(rect.LeftTop(), rect.LeftTop(), no_tint); 140 AddLine(rect.RightTop(), rect.RightTop(), no_tint); 141 AddLine(rect.RightBottom(), rect.RightBottom(), no_tint); 142 143 rect.InsetBy(1, 1); 144 145 // First bevel 146 AddLine(BPoint(rect.left + 1.0f, rect.bottom), 147 BPoint(rect.right, rect.bottom), darken2); 148 AddLine(BPoint(rect.right, rect.bottom - 1.0f), 149 BPoint(rect.right, rect.top + 1.0f), darken2); 150 151 AddLine(BPoint(rect.left, rect.top), 152 BPoint(rect.left, rect.bottom), lighten1); 153 AddLine(BPoint(rect.left + 1.0f, rect.top), 154 BPoint(rect.right, rect.top), lighten1); 155 156 EndLineArray(); 157 158 rect.InsetBy(1, 1); 159 160 // Second bevel 161 SetHighColor(lightenmax); 162 FillRect(rect); 163 164 SetHighColor(no_tint); 165 StrokeLine(BPoint(rect.right, rect.top + 1.0f), 166 BPoint(rect.right, rect.bottom)); 167 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom)); 168 169 rect.InsetBy(1, 1); 170 171 // Filling 172 rect.left += 1.0f; 173 rect.top += 1.0f; 174 SetHighColor(lighten1); 175 FillRect(rect); 176 177 if (Value()) 178 { 179 // Invert 180 rect.left -= 3; 181 rect.top -= 3; 182 rect.right += 2; 183 rect.bottom += 2; 184 InvertRect(rect); 185 } 186 187 // Label 188 float x = (bounds.right - StringWidth(Label())) / 2.0f; 189 float y = bounds.bottom - fh.descent - (IsDefault() ? 8.0f : 5.0f); 190 191 if (Value()) 192 { 193 SetHighColor(lightenmax); 194 SetLowColor(darkenmax); 195 } 196 else 197 { 198 SetHighColor(darkenmax); 199 SetLowColor(lighten2); 200 } 201 202 DrawString(Label(), BPoint(x, y)); 203 204 // Focus 205 if (IsFocus()) 206 { 207 y += 2.0f; 208 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 209 StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y)); 210 } 211 } 212 else 213 { 214 // This can be set outside draw 215 SetHighColor(darken2); 216 217 // Dark border 218 StrokeRect(rect); 219 220 BeginLineArray(8); 221 222 // Corners 223 AddLine(rect.LeftBottom(), rect.LeftBottom(), no_tint); 224 AddLine(rect.LeftTop(), rect.LeftTop(), no_tint); 225 AddLine(rect.RightTop(), rect.RightTop(), no_tint); 226 AddLine(rect.RightBottom(), rect.RightBottom(), no_tint); 227 228 rect.InsetBy(1, 1); 229 230 // First bevel 231 AddLine(BPoint(rect.left + 1.0f, rect.bottom), 232 BPoint(rect.right, rect.bottom), no_tint); 233 AddLine(BPoint(rect.right, rect.bottom - 1.0f), 234 BPoint(rect.right, rect.top + 1.0f), no_tint); 235 236 AddLine(BPoint(rect.left, rect.top), 237 BPoint(rect.left, rect.bottom), lighten1); 238 AddLine(BPoint(rect.left + 1.0f, rect.top), 239 BPoint(rect.right, rect.top), lighten1); 240 241 EndLineArray(); 242 243 rect.InsetBy(1, 1); 244 245 // Second bevel 246 SetHighColor(lightenmax); 247 FillRect(rect); 248 249 SetHighColor(no_tint); 250 StrokeLine(BPoint(rect.right, rect.top + 1.0f), 251 BPoint(rect.right, rect.bottom)); 252 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom)); 253 254 rect.InsetBy(1, 1); 255 256 // Filling 257 rect.left += 1.0f; 258 rect.top += 1.0f; 259 SetHighColor(lighten1); 260 FillRect(rect); 261 262 // Label 263 float x = (bounds.right - StringWidth(Label())) / 2.0f; 264 float y = bounds.bottom - fh.descent - 5.0f; 265 266 SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT)); 267 SetLowColor(lighten2); 268 DrawString(Label(), BPoint(x, y)); 269 } 270 } 271 //------------------------------------------------------------------------------ 272 void BButton::MouseDown(BPoint point) 273 { 274 if (!IsEnabled()) 275 return; 276 277 SetValue(B_CONTROL_ON); 278 279 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) 280 { 281 SetTracking(true); 282 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 283 } 284 else 285 { 286 BRect bounds = Bounds(); 287 uint32 buttons; 288 289 do 290 { 291 Window()->UpdateIfNeeded(); 292 293 snooze(40000); 294 295 GetMouse(&point, &buttons, true); 296 297 bool inside = bounds.Contains(ConvertFromScreen(point)); 298 299 if ((Value() == B_CONTROL_ON) != inside) 300 SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF); 301 } while (buttons != 0); 302 303 if (Value() == B_CONTROL_ON) 304 Invoke(); 305 } 306 } 307 //------------------------------------------------------------------------------ 308 void BButton::AttachedToWindow() 309 { 310 BControl::AttachedToWindow(); 311 312 if (IsDefault()) 313 Window()->SetDefaultButton(this); 314 } 315 //------------------------------------------------------------------------------ 316 void BButton::KeyDown(const char *bytes, int32 numBytes) 317 { 318 if (*bytes == B_ENTER || *bytes == B_SPACE) 319 { 320 if (!IsEnabled()) 321 return; 322 323 SetValue(B_CONTROL_ON); 324 Invoke(); 325 } 326 else 327 BControl::KeyDown(bytes, numBytes); 328 } 329 //------------------------------------------------------------------------------ 330 void BButton::MakeDefault(bool flag) 331 { 332 BButton *oldDefault = NULL; 333 BWindow *window = Window(); 334 335 if (window) 336 oldDefault = window->DefaultButton(); 337 338 if (flag) 339 { 340 if (fDrawAsDefault && oldDefault == this) 341 return; 342 343 fDrawAsDefault = true; 344 345 ResizeBy(6.0f, 6.0f); 346 MoveBy(-3.0f, -3.0f); 347 348 if (window && oldDefault != this) 349 window->SetDefaultButton(this); 350 } 351 else 352 { 353 if (!fDrawAsDefault) 354 return; 355 356 fDrawAsDefault = false; 357 358 ResizeBy(-6.0f, -6.0f); 359 MoveBy(3.0f, 3.0f); 360 361 if (window && oldDefault == this) 362 window->SetDefaultButton(NULL); 363 } 364 } 365 //------------------------------------------------------------------------------ 366 void BButton::SetLabel(const char *string) 367 { 368 BControl::SetLabel(string); 369 } 370 //------------------------------------------------------------------------------ 371 bool BButton::IsDefault() const 372 { 373 return fDrawAsDefault; 374 } 375 //------------------------------------------------------------------------------ 376 void BButton::MessageReceived(BMessage *message) 377 { 378 BControl::MessageReceived(message); 379 } 380 //------------------------------------------------------------------------------ 381 void BButton::WindowActivated(bool active) 382 { 383 BControl::WindowActivated(active); 384 } 385 //------------------------------------------------------------------------------ 386 void BButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 387 { 388 if (!IsTracking()) 389 return; 390 391 bool inside = Bounds().Contains(point); 392 393 if ((Value() == B_CONTROL_ON) != inside) 394 SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF); 395 } 396 //------------------------------------------------------------------------------ 397 void BButton::MouseUp(BPoint point) 398 { 399 if (!IsTracking()) 400 return; 401 402 if (Bounds().Contains(point)) 403 Invoke(); 404 405 SetTracking(false); 406 } 407 //------------------------------------------------------------------------------ 408 void BButton::DetachedFromWindow() 409 { 410 BControl::DetachedFromWindow(); 411 } 412 //------------------------------------------------------------------------------ 413 void BButton::SetValue(int32 value) 414 { 415 BControl::SetValue(value); 416 } 417 //------------------------------------------------------------------------------ 418 void BButton::GetPreferredSize(float *width, float *height) 419 { 420 font_height fh; 421 GetFontHeight(&fh); 422 423 *height = 12.0f + (float)ceil(fh.ascent + fh.descent); 424 *width = 20.0f + (float)ceil(StringWidth(Label())); 425 426 if (*width < 75.0f) 427 *width = 75.0f; 428 429 if (fDrawAsDefault) 430 { 431 *width += 6.0f; 432 *height += 6.0f; 433 } 434 } 435 //------------------------------------------------------------------------------ 436 void BButton::ResizeToPreferred() 437 { 438 BControl::ResizeToPreferred(); 439 } 440 //------------------------------------------------------------------------------ 441 status_t BButton::Invoke(BMessage *message) 442 { 443 Sync(); 444 snooze(50000); 445 446 status_t err = BControl::Invoke(message); 447 448 SetValue(B_CONTROL_OFF); 449 450 return err; 451 } 452 //------------------------------------------------------------------------------ 453 void BButton::FrameMoved(BPoint newLocation) 454 { 455 BControl::FrameMoved(newLocation); 456 } 457 //------------------------------------------------------------------------------ 458 void BButton::FrameResized(float width, float height) 459 { 460 BControl::FrameResized(width, height); 461 } 462 //------------------------------------------------------------------------------ 463 void BButton::MakeFocus(bool focused) 464 { 465 BControl::MakeFocus(focused); 466 } 467 //------------------------------------------------------------------------------ 468 void BButton::AllAttached() 469 { 470 BControl::AllAttached(); 471 } 472 //------------------------------------------------------------------------------ 473 void BButton::AllDetached() 474 { 475 BControl::AllDetached(); 476 } 477 //------------------------------------------------------------------------------ 478 BHandler *BButton::ResolveSpecifier(BMessage *message, int32 index, 479 BMessage *specifier, int32 what, 480 const char *property) 481 { 482 return BControl::ResolveSpecifier(message, index, specifier, what, property); 483 } 484 //------------------------------------------------------------------------------ 485 status_t BButton::GetSupportedSuites(BMessage *message) 486 { 487 return BControl::GetSupportedSuites(message); 488 } 489 //------------------------------------------------------------------------------ 490 status_t BButton::Perform(perform_code d, void *arg) 491 { 492 return BControl::Perform(d, arg); 493 } 494 //------------------------------------------------------------------------------ 495 void BButton::_ReservedButton1() {} 496 void BButton::_ReservedButton2() {} 497 void BButton::_ReservedButton3() {} 498 //------------------------------------------------------------------------------ 499 BButton &BButton::operator=(const BButton &) 500 { 501 return *this; 502 } 503 //------------------------------------------------------------------------------ 504 BRect BButton::DrawDefault(BRect bounds, bool enabled) 505 { 506 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 507 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 508 darken1 = tint_color(no_tint, B_DARKEN_1_TINT), 509 darken4 = tint_color(no_tint, B_DARKEN_4_TINT); 510 511 if (enabled) 512 { 513 // Dark border 514 BeginLineArray(4); 515 AddLine(BPoint(bounds.left, bounds.bottom - 1.0f), 516 BPoint(bounds.left, bounds.top + 1.0f), darken4); 517 AddLine(BPoint(bounds.left + 1.0f, bounds.top), 518 BPoint(bounds.right - 1.0f, bounds.top), darken4); 519 AddLine(BPoint(bounds.right, bounds.top + 1.0f), 520 BPoint(bounds.right, bounds.bottom - 1.0f), darken4); 521 AddLine(BPoint(bounds.left + 1.0f, bounds.bottom), 522 BPoint(bounds.right - 1.0f, bounds.bottom), darken4); 523 EndLineArray(); 524 525 bounds.InsetBy(1.0f, 1.0f); 526 527 // Bevel 528 SetHighColor(darken1); 529 StrokeRect(bounds); 530 531 bounds.InsetBy(1.0f, 1.0f); 532 533 // Filling 534 SetHighColor(lighten1); 535 FillRect(bounds); 536 537 bounds.InsetBy(2.0f, 2.0f); 538 } 539 else 540 { 541 // Dark border 542 BeginLineArray(4); 543 AddLine(BPoint(bounds.left, bounds.bottom - 1.0f), 544 BPoint(bounds.left, bounds.top + 1.0f), darken1); 545 AddLine(BPoint(bounds.left + 1.0f, bounds.top), 546 BPoint(bounds.right - 1.0f, bounds.top), darken1); 547 AddLine(BPoint(bounds.right, bounds.top + 1.0f), 548 BPoint(bounds.right, bounds.bottom - 1.0f), darken1); 549 AddLine(BPoint(bounds.left + 1.0f, bounds.bottom), 550 BPoint(bounds.right - 1.0f, bounds.bottom), darken1); 551 EndLineArray(); 552 553 bounds.InsetBy(1.0f, 1.0f); 554 555 // Filling 556 SetHighColor(lighten1); 557 FillRect(bounds); 558 559 bounds.InsetBy(3.0f, 3.0f); 560 } 561 562 return bounds; 563 } 564 //------------------------------------------------------------------------------ 565 status_t BButton::Execute() 566 { 567 if (!IsEnabled()) 568 return B_ERROR; 569 570 SetValue(B_CONTROL_ON); 571 return Invoke(); 572 } 573 //------------------------------------------------------------------------------ 574 575 /* 576 * $Log $ 577 * 578 * $Id $ 579 * 580 */ 581