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), 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 / 2 - 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 / 2 - 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 / 2 - 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 BRect bounds = Bounds(); 282 uint32 buttons; 283 284 do 285 { 286 snooze(40000); 287 288 GetMouse(&point, &buttons, true); 289 290 bool inside = bounds.Contains(point); 291 292 if ((Value() == B_CONTROL_ON) != inside) 293 SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF); 294 } while (buttons != 0); 295 296 if (Value() == B_CONTROL_ON) 297 Invoke(); 298 } 299 else 300 { 301 SetTracking(true); 302 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 303 } 304 } 305 //------------------------------------------------------------------------------ 306 void BButton::AttachedToWindow() 307 { 308 BControl::AttachedToWindow(); 309 310 if (IsDefault()) 311 Window()->SetDefaultButton(this); 312 } 313 //------------------------------------------------------------------------------ 314 void BButton::KeyDown(const char *bytes, int32 numBytes) 315 { 316 if (*bytes == B_ENTER || *bytes == B_SPACE) 317 { 318 if (!IsEnabled()) 319 return; 320 321 SetValue(B_CONTROL_ON); 322 Invoke(); 323 } 324 else 325 BControl::KeyDown(bytes, numBytes); 326 } 327 //------------------------------------------------------------------------------ 328 void BButton::MakeDefault(bool flag) 329 { 330 BButton *oldDefault = NULL; 331 BWindow *window = Window(); 332 333 if (window) 334 oldDefault = window->DefaultButton(); 335 336 if (flag) 337 { 338 if (fDrawAsDefault && oldDefault == this) 339 return; 340 341 fDrawAsDefault = true; 342 343 ResizeBy(6.0f, 6.0f); 344 MoveBy(-3.0f, -3.0f); 345 346 if (window && oldDefault != this) 347 window->SetDefaultButton(this); 348 } 349 else 350 { 351 if (!fDrawAsDefault) 352 return; 353 354 fDrawAsDefault = false; 355 356 ResizeBy(-6.0f, -6.0f); 357 MoveBy(3.0f, 3.0f); 358 359 if (window && oldDefault == this) 360 window->SetDefaultButton(NULL); 361 } 362 } 363 //------------------------------------------------------------------------------ 364 void BButton::SetLabel(const char *string) 365 { 366 BControl::SetLabel(string); 367 } 368 //------------------------------------------------------------------------------ 369 bool BButton::IsDefault() const 370 { 371 return fDrawAsDefault; 372 } 373 //------------------------------------------------------------------------------ 374 void BButton::MessageReceived(BMessage *message) 375 { 376 BControl::MessageReceived(message); 377 } 378 //------------------------------------------------------------------------------ 379 void BButton::WindowActivated(bool active) 380 { 381 BControl::WindowActivated(active); 382 } 383 //------------------------------------------------------------------------------ 384 void BButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 385 { 386 if (!IsTracking()) 387 return; 388 389 bool inside = Bounds().Contains(point); 390 391 if ((Value() == B_CONTROL_ON) != inside) 392 SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF); 393 } 394 //------------------------------------------------------------------------------ 395 void BButton::MouseUp(BPoint point) 396 { 397 if (!IsTracking()) 398 return; 399 400 if (Bounds().Contains(point)) 401 Invoke(); 402 403 SetTracking(false); 404 } 405 //------------------------------------------------------------------------------ 406 void BButton::DetachedFromWindow() 407 { 408 BControl::DetachedFromWindow(); 409 } 410 //------------------------------------------------------------------------------ 411 void BButton::SetValue(int32 value) 412 { 413 BControl::SetValue(value); 414 } 415 //------------------------------------------------------------------------------ 416 void BButton::GetPreferredSize(float *width, float *height) 417 { 418 font_height fh; 419 GetFontHeight(&fh); 420 421 *height = 12.0f + (float)ceil(fh.ascent + fh.descent); 422 *width = 20.0f + (float)ceil(StringWidth(Label())); 423 424 if (*width < 75.0f) 425 *width = 75.0f; 426 427 if (fDrawAsDefault) 428 { 429 *width += 6.0f; 430 *height += 6.0f; 431 } 432 } 433 //------------------------------------------------------------------------------ 434 void BButton::ResizeToPreferred() 435 { 436 BControl::ResizeToPreferred(); 437 } 438 //------------------------------------------------------------------------------ 439 status_t BButton::Invoke(BMessage *message) 440 { 441 Sync(); 442 snooze(50000); 443 444 status_t err = BControl::Invoke(message); 445 446 SetValue(B_CONTROL_OFF); 447 448 return err; 449 } 450 //------------------------------------------------------------------------------ 451 void BButton::FrameMoved(BPoint newLocation) 452 { 453 BControl::FrameMoved(newLocation); 454 } 455 //------------------------------------------------------------------------------ 456 void BButton::FrameResized(float width, float height) 457 { 458 BControl::FrameResized(width, height); 459 } 460 //------------------------------------------------------------------------------ 461 void BButton::MakeFocus(bool focused) 462 { 463 BControl::MakeFocus(focused); 464 } 465 //------------------------------------------------------------------------------ 466 void BButton::AllAttached() 467 { 468 BControl::AllAttached(); 469 } 470 //------------------------------------------------------------------------------ 471 void BButton::AllDetached() 472 { 473 BControl::AllDetached(); 474 } 475 //------------------------------------------------------------------------------ 476 BHandler *BButton::ResolveSpecifier(BMessage *message, int32 index, 477 BMessage *specifier, int32 what, 478 const char *property) 479 { 480 return BControl::ResolveSpecifier(message, index, specifier, what, property); 481 } 482 //------------------------------------------------------------------------------ 483 status_t BButton::GetSupportedSuites(BMessage *message) 484 { 485 return BControl::GetSupportedSuites(message); 486 } 487 //------------------------------------------------------------------------------ 488 status_t BButton::Perform(perform_code d, void *arg) 489 { 490 return BControl::Perform(d, arg); 491 } 492 //------------------------------------------------------------------------------ 493 void BButton::_ReservedButton1() {} 494 void BButton::_ReservedButton2() {} 495 void BButton::_ReservedButton3() {} 496 //------------------------------------------------------------------------------ 497 BButton &BButton::operator=(const BButton &) 498 { 499 return *this; 500 } 501 //------------------------------------------------------------------------------ 502 BRect BButton::DrawDefault(BRect bounds, bool enabled) 503 { 504 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 505 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 506 darken1 = tint_color(no_tint, B_DARKEN_1_TINT), 507 darken4 = tint_color(no_tint, B_DARKEN_4_TINT); 508 509 if (enabled) 510 { 511 // Dark border 512 BeginLineArray(4); 513 AddLine(BPoint(bounds.left, bounds.bottom - 1.0f), 514 BPoint(bounds.left, bounds.top + 1.0f), darken4); 515 AddLine(BPoint(bounds.left + 1.0f, bounds.top), 516 BPoint(bounds.right - 1.0f, bounds.top), darken4); 517 AddLine(BPoint(bounds.right, bounds.top + 1.0f), 518 BPoint(bounds.right, bounds.bottom - 1.0f), darken4); 519 AddLine(BPoint(bounds.left + 1.0f, bounds.bottom), 520 BPoint(bounds.right - 1.0f, bounds.bottom), darken4); 521 EndLineArray(); 522 523 bounds.InsetBy(1.0f, 1.0f); 524 525 // Bevel 526 SetHighColor(darken1); 527 StrokeRect(bounds); 528 529 bounds.InsetBy(1.0f, 1.0f); 530 531 // Filling 532 SetHighColor(lighten1); 533 FillRect(bounds); 534 535 bounds.InsetBy(2.0f, 2.0f); 536 } 537 else 538 { 539 // Dark border 540 BeginLineArray(4); 541 AddLine(BPoint(bounds.left, bounds.bottom - 1.0f), 542 BPoint(bounds.left, bounds.top + 1.0f), darken1); 543 AddLine(BPoint(bounds.left + 1.0f, bounds.top), 544 BPoint(bounds.right - 1.0f, bounds.top), darken1); 545 AddLine(BPoint(bounds.right, bounds.top + 1.0f), 546 BPoint(bounds.right, bounds.bottom - 1.0f), darken1); 547 AddLine(BPoint(bounds.left + 1.0f, bounds.bottom), 548 BPoint(bounds.right - 1.0f, bounds.bottom), darken1); 549 EndLineArray(); 550 551 bounds.InsetBy(1.0f, 1.0f); 552 553 // Filling 554 SetHighColor(lighten1); 555 FillRect(bounds); 556 557 bounds.InsetBy(3.0f, 3.0f); 558 } 559 560 return bounds; 561 } 562 //------------------------------------------------------------------------------ 563 status_t BButton::Execute() 564 { 565 if (!IsEnabled()) 566 return B_ERROR; 567 568 SetValue(B_CONTROL_ON); 569 return Invoke(); 570 } 571 //------------------------------------------------------------------------------ 572 573 /* 574 * $Log $ 575 * 576 * $Id $ 577 * 578 */ 579