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 if (Bounds().Height() < 24.0f) 49 ResizeTo(Bounds().Width(), 24.0f); 50 } 51 //------------------------------------------------------------------------------ 52 BButton::~BButton() 53 { 54 } 55 //------------------------------------------------------------------------------ 56 BButton::BButton(BMessage *archive) 57 : BControl (archive) 58 { 59 if ( archive->FindBool ( "_default", &fDrawAsDefault ) != B_OK ) 60 fDrawAsDefault = false; 61 } 62 //------------------------------------------------------------------------------ 63 BArchivable *BButton::Instantiate ( BMessage *archive ) 64 { 65 if (validate_instantiation(archive, "BButton")) 66 return new BButton(archive); 67 else 68 return NULL; 69 } 70 //------------------------------------------------------------------------------ 71 status_t BButton::Archive(BMessage* archive, bool deep) const 72 { 73 status_t err = BControl::Archive(archive, deep); 74 75 if (err != B_OK) 76 return err; 77 78 if (fDrawAsDefault) 79 err = archive->AddBool("_default", fDrawAsDefault); 80 81 return err; 82 } 83 //------------------------------------------------------------------------------ 84 void BButton::Draw(BRect updateRect) 85 { 86 BRect rect = Bounds(); 87 88 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 89 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 90 lighten2 = tint_color(no_tint, B_LIGHTEN_2_TINT), 91 lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT), 92 darken2 = tint_color(no_tint, B_DARKEN_2_TINT), 93 darken4 = tint_color(no_tint, B_DARKEN_4_TINT), 94 darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT); 95 96 if (IsDefault()) 97 rect = DrawDefault(rect, IsEnabled()); 98 else 99 rect.InsetBy(1,1); 100 101 if (IsEnabled()) 102 { 103 // This can be set outside draw 104 SetHighColor(darken4); 105 106 // Dark border 107 StrokeRect(rect); 108 109 BeginLineArray(8); 110 111 // Corners 112 AddLine(rect.LeftBottom(), rect.LeftBottom(), no_tint); 113 AddLine(rect.LeftTop(), rect.LeftTop(), no_tint); 114 AddLine(rect.RightTop(), rect.RightTop(), no_tint); 115 AddLine(rect.RightBottom(), rect.RightBottom(), no_tint); 116 117 rect.InsetBy(1, 1); 118 119 // First bevel 120 AddLine(BPoint(rect.left + 1.0f, rect.bottom), 121 BPoint(rect.right, rect.bottom), darken2); 122 AddLine(BPoint(rect.right, rect.bottom - 1.0f), 123 BPoint(rect.right, rect.top + 1.0f), darken2); 124 125 AddLine(BPoint(rect.left, rect.top), 126 BPoint(rect.left, rect.bottom), lighten1); 127 AddLine(BPoint(rect.left + 1.0f, rect.top), 128 BPoint(rect.right, rect.top), lighten1); 129 130 EndLineArray(); 131 132 rect.InsetBy(1, 1); 133 134 // Second bevel 135 SetHighColor(lightenmax); 136 FillRect(rect); 137 138 SetHighColor(no_tint); 139 StrokeLine(BPoint(rect.right, rect.top + 1.0f), 140 BPoint(rect.right, rect.bottom)); 141 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom)); 142 143 rect.InsetBy(1, 1); 144 145 // Filling 146 rect.left += 1.0f; 147 rect.top += 1.0f; 148 SetHighColor(lighten1); 149 FillRect(rect); 150 151 if (Value()) 152 { 153 // Invert 154 rect.left -= 3; 155 rect.top -= 3; 156 rect.right += 2; 157 rect.bottom += 2; 158 SetDrawingMode(B_OP_INVERT); 159 SetHighColor(0, 0, 0); 160 FillRect(rect); 161 SetDrawingMode(B_OP_COPY); 162 } 163 164 // Label 165 BFont font; 166 GetFont(&font); 167 168 float x = Bounds().Width() / 2 - StringWidth(Label()) / 2.0f; 169 float y = Bounds().Height() / 2.0f + (float)ceil(font.Size() / 2.0f); 170 171 if (Value()) 172 { 173 SetHighColor(lightenmax); 174 SetLowColor(darkenmax); 175 } 176 else 177 { 178 SetHighColor(darkenmax); 179 SetLowColor(lighten2); 180 } 181 182 DrawString(Label(), BPoint(x, y)); 183 184 // Focus 185 if (IsFocus()) 186 { 187 font_height fh; 188 font.GetHeight(&fh); 189 190 y += 2.0f; 191 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 192 StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y)); 193 } 194 } 195 else 196 { 197 // This can be set outside draw 198 SetHighColor(darken2); 199 200 // Dark border 201 StrokeRect(rect); 202 203 BeginLineArray(8); 204 205 // Corners 206 AddLine(rect.LeftBottom(), rect.LeftBottom(), no_tint); 207 AddLine(rect.LeftTop(), rect.LeftTop(), no_tint); 208 AddLine(rect.RightTop(), rect.RightTop(), no_tint); 209 AddLine(rect.RightBottom(), rect.RightBottom(), no_tint); 210 211 rect.InsetBy(1, 1); 212 213 // First bevel 214 AddLine(BPoint(rect.left + 1.0f, rect.bottom), 215 BPoint(rect.right, rect.bottom), no_tint); 216 AddLine(BPoint(rect.right, rect.bottom - 1.0f), 217 BPoint(rect.right, rect.top + 1.0f), no_tint); 218 219 AddLine(BPoint(rect.left, rect.top), 220 BPoint(rect.left, rect.bottom), lighten1); 221 AddLine(BPoint(rect.left + 1.0f, rect.top), 222 BPoint(rect.right, rect.top), lighten1); 223 224 EndLineArray(); 225 226 rect.InsetBy(1, 1); 227 228 // Second bevel 229 SetHighColor(lightenmax); 230 FillRect(rect); 231 232 SetHighColor(no_tint); 233 StrokeLine(BPoint(rect.right, rect.top + 1.0f), 234 BPoint(rect.right, rect.bottom)); 235 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom)); 236 237 rect.InsetBy(1, 1); 238 239 // Filling 240 rect.left += 1.0f; 241 rect.top += 1.0f; 242 SetHighColor(lighten1); 243 FillRect(rect); 244 245 // Label 246 BFont font; 247 GetFont(&font); 248 249 float x = Bounds().Width() / 2 - StringWidth(Label()) / 2.0f; 250 float y = Bounds().Height() / 2.0f + (float)ceil(font.Size() / 2.0f); 251 252 SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT)); 253 SetLowColor(lighten2); 254 DrawString(Label(), BPoint(x, y)); 255 } 256 } 257 //------------------------------------------------------------------------------ 258 void BButton::MouseDown(BPoint point) 259 { 260 if (!IsEnabled()) 261 { 262 BControl::MouseDown(point); 263 return; 264 } 265 266 SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY | B_SUSPEND_VIEW_FOCUS); 267 268 SetValue(B_CONTROL_ON); 269 SetTracking(true); 270 } 271 //------------------------------------------------------------------------------ 272 void BButton::AttachedToWindow() 273 { 274 BControl::AttachedToWindow(); 275 276 if (IsDefault()) 277 Window()->SetDefaultButton(this); 278 } 279 //------------------------------------------------------------------------------ 280 void BButton::KeyDown ( const char *bytes, int32 numBytes ) 281 { 282 if (numBytes == 1) 283 { 284 switch (bytes[0]) 285 { 286 case B_ENTER: 287 case B_SPACE: 288 SetValue(B_CONTROL_ON); 289 snooze(50000); 290 SetValue(B_CONTROL_OFF); 291 Invoke(); 292 break; 293 294 default: 295 BControl::KeyDown(bytes, numBytes); 296 } 297 } 298 else 299 BControl::KeyDown(bytes, numBytes); 300 } 301 //------------------------------------------------------------------------------ 302 void BButton::MakeDefault(bool flag) 303 { 304 if (flag == IsDefault()) 305 return; 306 307 fDrawAsDefault = flag; 308 BWindow *window = Window(); 309 310 if (flag) 311 { 312 ResizeBy(6.0f, 6.0f); 313 MoveBy(-3.0f, -3.0f); 314 315 if (window) 316 window->SetDefaultButton((BButton*)this); 317 } 318 else 319 { 320 ResizeBy(-6.0f, -6.0f); 321 MoveBy(3.0f, 3.0f); 322 323 if (window) 324 window->SetDefaultButton(NULL); 325 } 326 } 327 //------------------------------------------------------------------------------ 328 void BButton::SetLabel(const char *string) 329 { 330 BControl::SetLabel(string); 331 } 332 //------------------------------------------------------------------------------ 333 bool BButton::IsDefault() const 334 { 335 return fDrawAsDefault; 336 } 337 //------------------------------------------------------------------------------ 338 void BButton::MessageReceived(BMessage *message) 339 { 340 BControl::MessageReceived(message); 341 } 342 //------------------------------------------------------------------------------ 343 void BButton::WindowActivated(bool active) 344 { 345 BControl::WindowActivated(active); 346 } 347 //------------------------------------------------------------------------------ 348 void BButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 349 { 350 if (IsEnabled() && IsTracking()) 351 { 352 if (transit == B_EXITED_VIEW) 353 SetValue(B_CONTROL_OFF); 354 else if (transit == B_ENTERED_VIEW) 355 SetValue(B_CONTROL_ON); 356 } 357 else 358 BControl::MouseMoved(point, transit, message); 359 } 360 //------------------------------------------------------------------------------ 361 void BButton::MouseUp(BPoint point) 362 { 363 if (IsEnabled() && IsTracking()) 364 { 365 if (Bounds().Contains(point)) 366 { 367 if ( Value() == B_CONTROL_ON) 368 { 369 SetValue(B_CONTROL_OFF); 370 BControl::Invoke(); 371 } 372 } 373 374 SetTracking(false); 375 } 376 } 377 //------------------------------------------------------------------------------ 378 void BButton::DetachedFromWindow() 379 { 380 BControl::DetachedFromWindow(); 381 } 382 //------------------------------------------------------------------------------ 383 void BButton::SetValue(int32 value) 384 { 385 BControl::SetValue(value); 386 } 387 //------------------------------------------------------------------------------ 388 void BButton::GetPreferredSize (float *width, float *height) 389 { 390 font_height fh; 391 392 GetFontHeight(&fh); 393 394 *height = (float)ceil(fh.ascent + fh.descent + fh.leading) + 12.0f; 395 *width = 20.0f + (float)ceil(StringWidth(Label())); 396 397 if (*width < 75.0f) 398 *width = 75.0f; 399 400 if (fDrawAsDefault) 401 { 402 *width += 6.0f; 403 *height += 6.0f; 404 } 405 } 406 //------------------------------------------------------------------------------ 407 void BButton::ResizeToPreferred() 408 { 409 BControl::ResizeToPreferred(); 410 } 411 //------------------------------------------------------------------------------ 412 status_t BButton::Invoke(BMessage *message) 413 { 414 return BControl::Invoke(message); 415 } 416 //------------------------------------------------------------------------------ 417 void BButton::FrameMoved(BPoint newLocation) 418 { 419 BControl::FrameMoved(newLocation); 420 } 421 //------------------------------------------------------------------------------ 422 void BButton::FrameResized(float width, float height) 423 { 424 BControl::FrameResized(width, height); 425 } 426 //------------------------------------------------------------------------------ 427 void BButton::MakeFocus(bool focused) 428 { 429 BControl::MakeFocus(focused); 430 } 431 //------------------------------------------------------------------------------ 432 void BButton::AllAttached() 433 { 434 BControl::AllAttached(); 435 } 436 //------------------------------------------------------------------------------ 437 void BButton::AllDetached() 438 { 439 BControl::AllDetached(); 440 } 441 //------------------------------------------------------------------------------ 442 BHandler *BButton::ResolveSpecifier(BMessage *message, int32 index, 443 BMessage *specifier, int32 what, 444 const char *property) 445 { 446 return BControl::ResolveSpecifier(message, index, specifier, what, property); 447 } 448 //------------------------------------------------------------------------------ 449 status_t BButton::GetSupportedSuites(BMessage *message) 450 { 451 return BControl::GetSupportedSuites(message); 452 } 453 //------------------------------------------------------------------------------ 454 status_t BButton::Perform(perform_code d, void *arg) 455 { 456 return B_ERROR; 457 } 458 459 //------------------------------------------------------------------------------ 460 void BButton::_ReservedButton1() {} 461 void BButton::_ReservedButton2() {} 462 void BButton::_ReservedButton3() {} 463 //------------------------------------------------------------------------------ 464 BButton &BButton::operator=(const BButton &) 465 { 466 return *this; 467 } 468 //------------------------------------------------------------------------------ 469 BRect BButton::DrawDefault(BRect bounds, bool enabled) 470 { 471 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 472 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 473 darken1 = tint_color(no_tint, B_DARKEN_1_TINT), 474 darken4 = tint_color(no_tint, B_DARKEN_4_TINT); 475 476 if (enabled) 477 { 478 // Dark border 479 BeginLineArray(4); 480 AddLine(BPoint(bounds.left, bounds.bottom - 1.0f), 481 BPoint(bounds.left, bounds.top + 1.0f), darken4); 482 AddLine(BPoint(bounds.left + 1.0f, bounds.top), 483 BPoint(bounds.right - 1.0f, bounds.top), darken4); 484 AddLine(BPoint(bounds.right, bounds.top + 1.0f), 485 BPoint(bounds.right, bounds.bottom - 1.0f), darken4); 486 AddLine(BPoint(bounds.left + 1.0f, bounds.bottom), 487 BPoint(bounds.right - 1.0f, bounds.bottom), darken4); 488 EndLineArray(); 489 490 bounds.InsetBy(1.0f, 1.0f); 491 492 // Bevel 493 SetHighColor(darken1); 494 StrokeRect(bounds); 495 496 bounds.InsetBy(1.0f, 1.0f); 497 498 // Filling 499 SetHighColor(lighten1); 500 FillRect(bounds); 501 502 bounds.InsetBy(2.0f, 2.0f); 503 } 504 else 505 { 506 // Dark border 507 BeginLineArray(4); 508 AddLine(BPoint(bounds.left, bounds.bottom - 1.0f), 509 BPoint(bounds.left, bounds.top + 1.0f), darken1); 510 AddLine(BPoint(bounds.left + 1.0f, bounds.top), 511 BPoint(bounds.right - 1.0f, bounds.top), darken1); 512 AddLine(BPoint(bounds.right, bounds.top + 1.0f), 513 BPoint(bounds.right, bounds.bottom - 1.0f), darken1); 514 AddLine(BPoint(bounds.left + 1.0f, bounds.bottom), 515 BPoint(bounds.right - 1.0f, bounds.bottom), darken1); 516 EndLineArray(); 517 518 bounds.InsetBy(1.0f, 1.0f); 519 520 // Filling 521 SetHighColor(lighten1); 522 FillRect(bounds); 523 524 bounds.InsetBy(3.0f, 3.0f); 525 } 526 527 return bounds; 528 } 529 //------------------------------------------------------------------------------ 530 status_t Execute() 531 { 532 // TODO: 533 return B_ERROR; 534 } 535 //------------------------------------------------------------------------------ 536 537 /* 538 * $Log $ 539 * 540 * $Id $ 541 * 542 */ 543