1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 #include "DialogPane.h" 36 37 #include <LayoutUtils.h> 38 39 #include "Thread.h" 40 #include "Utilities.h" 41 #include "Window.h" 42 43 44 const uint32 kValueChanged = 'swch'; 45 46 const rgb_color kNormalColor = {150, 150, 150, 255}; 47 const rgb_color kHighlightColor = {100, 100, 0, 255}; 48 49 50 static void 51 AddSelf(BView *self, BView *to) 52 { 53 to->AddChild(self); 54 } 55 56 57 void 58 ViewList::RemoveAll(BView *) 59 { 60 EachListItemIgnoreResult(this, &BView::RemoveSelf); 61 } 62 63 64 void 65 ViewList::AddAll(BView *toParent) 66 { 67 EachListItem(this, &AddSelf, toParent); 68 } 69 70 71 // #pragma mark - 72 73 74 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, int32 initialMode, 75 const char *name, uint32 followFlags, uint32 flags) 76 : BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode2Frame), 77 name, followFlags, flags), 78 fMode(initialMode), 79 fMode1Frame(mode1Frame), 80 fMode2Frame(mode2Frame), 81 fMode3Frame(mode2Frame) 82 { 83 SetMode(fMode, true); 84 } 85 86 87 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, BRect mode3Frame, 88 int32 initialMode, const char *name, uint32 followFlags, uint32 flags) 89 : BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode3Frame), 90 name, followFlags, flags), 91 fMode(initialMode), 92 fMode1Frame(mode1Frame), 93 fMode2Frame(mode2Frame), 94 fMode3Frame(mode3Frame) 95 { 96 SetMode(fMode, true); 97 } 98 99 100 DialogPane::~DialogPane() 101 { 102 fMode3Items.RemoveAll(this); 103 fMode2Items.RemoveAll(this); 104 } 105 106 107 void 108 DialogPane::SetMode(int32 mode, bool initialSetup) 109 { 110 ASSERT(mode < 3 && mode >= 0); 111 112 if (!initialSetup && mode == fMode) 113 return; 114 115 int32 oldMode = fMode; 116 fMode = mode; 117 118 bool followBottom = (ResizingMode() & B_FOLLOW_BOTTOM) != 0; 119 // if we are follow bottom, we will move ourselves, need to place us back 120 float bottomOffset = 0; 121 if (followBottom && Window() != NULL) 122 bottomOffset = Window()->Bounds().bottom - Frame().bottom; 123 124 BRect newBounds(BoundsForMode(fMode)); 125 if (!initialSetup) 126 ResizeParentWindow(fMode, oldMode); 127 128 ResizeTo(newBounds.Width(), newBounds.Height()); 129 130 float delta = 0; 131 if (followBottom && Window() != NULL) 132 delta = (Window()->Bounds().bottom - Frame().bottom) - bottomOffset; 133 134 if (delta != 0) { 135 MoveBy(0, delta); 136 if (fLatch && (fLatch->ResizingMode() & B_FOLLOW_BOTTOM)) 137 fLatch->MoveBy(0, delta); 138 } 139 140 switch (fMode) { 141 case 0: 142 { 143 if (oldMode > 1) 144 fMode3Items.RemoveAll(this); 145 if (oldMode > 0) 146 fMode2Items.RemoveAll(this); 147 148 BView *separator = FindView("separatorLine"); 149 if (separator) { 150 BRect frame(separator->Frame()); 151 frame.InsetBy(-1, -1); 152 RemoveChild(separator); 153 Invalidate(); 154 } 155 156 AddChild(new SeparatorLine(BPoint(newBounds.left, newBounds.top 157 + newBounds.Height() / 2), newBounds.Width(), false, 158 "separatorLine")); 159 break; 160 } 161 case 1: 162 { 163 if (oldMode > 1) 164 fMode3Items.RemoveAll(this); 165 else 166 fMode2Items.AddAll(this); 167 168 BView *separator = FindView("separatorLine"); 169 if (separator) { 170 BRect frame(separator->Frame()); 171 frame.InsetBy(-1, -1); 172 RemoveChild(separator); 173 Invalidate(); 174 } 175 break; 176 } 177 case 2: 178 { 179 fMode3Items.AddAll(this); 180 if (oldMode < 1) 181 fMode2Items.AddAll(this); 182 183 BView *separator = FindView("separatorLine"); 184 if (separator) { 185 BRect frame(separator->Frame()); 186 frame.InsetBy(-1, -1); 187 RemoveChild(separator); 188 Invalidate(); 189 } 190 break; 191 } 192 } 193 } 194 195 196 void 197 DialogPane::AttachedToWindow() 198 { 199 BView *parent = Parent(); 200 if (parent) { 201 SetViewColor(parent->ViewColor()); 202 SetLowColor(parent->LowColor()); 203 } 204 } 205 206 207 void 208 DialogPane::ResizeParentWindow(int32 from, int32 to) 209 { 210 if (!Window()) 211 return; 212 213 BRect oldBounds = BoundsForMode(from); 214 BRect newBounds = BoundsForMode(to); 215 216 BPoint by = oldBounds.RightBottom() - newBounds.RightBottom(); 217 if (by != BPoint(0, 0)) 218 Window()->ResizeBy(by.x, by.y); 219 } 220 221 222 void 223 DialogPane::AddItem(BView *view, int32 toMode) 224 { 225 if (toMode == 1) 226 fMode2Items.AddItem(view); 227 else if (toMode == 2) 228 fMode3Items.AddItem(view); 229 if (fMode >= toMode) 230 AddChild(view); 231 } 232 233 234 BRect 235 DialogPane::FrameForMode(int32 mode) 236 { 237 switch (mode) { 238 case 0: 239 return fMode1Frame; 240 case 1: 241 return fMode2Frame; 242 case 2: 243 return fMode3Frame; 244 } 245 return fMode1Frame; 246 } 247 248 249 BRect 250 DialogPane::BoundsForMode(int32 mode) 251 { 252 BRect result; 253 switch (mode) { 254 case 0: 255 result = fMode1Frame; 256 break; 257 case 1: 258 result = fMode2Frame; 259 break; 260 case 2: 261 result = fMode3Frame; 262 break; 263 } 264 result.OffsetTo(0, 0); 265 return result; 266 } 267 268 269 BRect 270 DialogPane::FrameForMode(int32 mode, BRect mode1Frame, BRect mode2Frame, 271 BRect mode3Frame) 272 { 273 switch (mode) { 274 case 0: 275 return mode1Frame; 276 case 1: 277 return mode2Frame; 278 case 2: 279 return mode3Frame; 280 } 281 return mode1Frame; 282 } 283 284 285 void 286 DialogPane::SetSwitch(BControl *control) 287 { 288 fLatch = control; 289 control->SetMessage(new BMessage(kValueChanged)); 290 control->SetTarget(this); 291 } 292 293 294 void 295 DialogPane::MessageReceived(BMessage *message) 296 { 297 if (message->what == kValueChanged) { 298 int32 value; 299 if (message->FindInt32("be:value", &value) == B_OK) 300 SetMode(value); 301 } else 302 _inherited::MessageReceived(message); 303 } 304 305 306 // #pragma mark - PaneSwitch 307 308 309 PaneSwitch::PaneSwitch(BRect frame, const char *name, bool leftAligned, 310 uint32 resizeMask, uint32 flags) 311 : 312 BControl(frame, name, "", 0, resizeMask, flags), 313 fLeftAligned(leftAligned), 314 fPressing(false), 315 fLabelOn(NULL), 316 fLabelOff(NULL) 317 { 318 } 319 320 321 PaneSwitch::PaneSwitch(const char *name, bool leftAligned, uint32 flags) 322 : 323 BControl(name, "", 0, flags), 324 fLeftAligned(leftAligned), 325 fPressing(false), 326 fLabelOn(NULL), 327 fLabelOff(NULL) 328 { 329 } 330 331 332 PaneSwitch::~PaneSwitch() 333 { 334 free(fLabelOn); 335 free(fLabelOff); 336 } 337 338 339 void 340 PaneSwitch::Draw(BRect) 341 { 342 BRect bounds(Bounds()); 343 344 // Draw the label, if any 345 const char* label = fLabelOff; 346 if (fLabelOn != NULL && Value() == B_CONTROL_ON) 347 label = fLabelOn; 348 349 if (label != NULL) { 350 BPoint point; 351 float labelDist = sLatchSize + ceilf(sLatchSize / 2.0); 352 if (fLeftAligned) 353 point.x = labelDist; 354 else 355 point.x = bounds.right - labelDist - StringWidth(label); 356 357 font_height fontHeight; 358 GetFontHeight(&fontHeight); 359 point.y = (bounds.top + bounds.bottom 360 - ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2 361 + ceilf(fontHeight.ascent); 362 363 DrawString(label, point); 364 } 365 366 // draw the latch 367 if (fPressing) 368 DrawInState(kPressed); 369 else if (Value()) 370 DrawInState(kExpanded); 371 else 372 DrawInState(kCollapsed); 373 374 // ...and the focus indication 375 if (!IsFocus() || !Window()->IsActive()) 376 return; 377 378 rgb_color markColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 379 380 BeginLineArray(2); 381 AddLine(BPoint(bounds.left + 2, bounds.bottom - 1), 382 BPoint(bounds.right - 2, bounds.bottom - 1), markColor); 383 AddLine(BPoint(bounds.left + 2, bounds.bottom), 384 BPoint(bounds.right - 2, bounds.bottom), kWhite); 385 EndLineArray(); 386 } 387 388 389 void 390 PaneSwitch::MouseDown(BPoint) 391 { 392 if (!IsEnabled()) 393 return; 394 395 fPressing = true; 396 MouseDownThread<PaneSwitch>::TrackMouse(this, &PaneSwitch::DoneTracking, 397 &PaneSwitch::Track); 398 Invalidate(); 399 } 400 401 402 void 403 PaneSwitch::GetPreferredSize(float* _width, float* _height) 404 { 405 BSize size = MinSize(); 406 if (_width) 407 *_width = size.width; 408 if (_height) 409 *_height = size.height; 410 } 411 412 413 BSize 414 PaneSwitch::MinSize() 415 { 416 BSize size; 417 float onLabelWidth = StringWidth(fLabelOn); 418 float offLabelWidth = StringWidth(fLabelOff); 419 float labelWidth = max_c(onLabelWidth, offLabelWidth); 420 size.width = sLatchSize; 421 if (labelWidth > 0.0) 422 size.width += ceilf(sLatchSize / 2.0) + labelWidth; 423 font_height fontHeight; 424 GetFontHeight(&fontHeight); 425 size.height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 426 size.height = max_c(size.height, sLatchSize); 427 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); 428 } 429 430 431 BSize 432 PaneSwitch::MaxSize() 433 { 434 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), MinSize()); 435 } 436 437 438 BSize 439 PaneSwitch::PreferredSize() 440 { 441 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize()); 442 } 443 444 445 void 446 PaneSwitch::SetLabels(const char* labelOn, const char* labelOff) 447 { 448 free(fLabelOn); 449 free(fLabelOff); 450 451 if (labelOn != NULL) 452 fLabelOn = strdup(labelOn); 453 else 454 fLabelOn = NULL; 455 456 if (labelOff != NULL) 457 fLabelOff = strdup(labelOff); 458 else 459 fLabelOff = NULL; 460 461 Invalidate(); 462 InvalidateLayout(); 463 } 464 465 466 void 467 PaneSwitch::DoneTracking(BPoint point) 468 { 469 BRect bounds(Bounds()); 470 bounds.InsetBy(-3, -3); 471 472 fPressing = false; 473 Invalidate(); 474 if (bounds.Contains(point)) { 475 SetValue(!Value()); 476 Invoke(); 477 } 478 } 479 480 481 void 482 PaneSwitch::Track(BPoint point, uint32) 483 { 484 BRect bounds(Bounds()); 485 bounds.InsetBy(-3, -3); 486 487 bool newPressing = bounds.Contains(point); 488 if (newPressing != fPressing) { 489 fPressing = newPressing; 490 Invalidate(); 491 } 492 } 493 494 495 void 496 PaneSwitch::DrawInState(PaneSwitch::State state) 497 { 498 BRect rect(0, 0, 10, 10); 499 500 rgb_color outlineColor = {0, 0, 0, 255}; 501 rgb_color middleColor = state == kPressed ? kHighlightColor : kNormalColor; 502 503 SetDrawingMode(B_OP_COPY); 504 505 switch (state) { 506 case kCollapsed: 507 BeginLineArray(6); 508 509 if (fLeftAligned) { 510 AddLine(BPoint(rect.left + 3, rect.top + 1), 511 BPoint(rect.left + 3, rect.bottom - 1), outlineColor); 512 AddLine(BPoint(rect.left + 3, rect.top + 1), 513 BPoint(rect.left + 7, rect.top + 5), outlineColor); 514 AddLine(BPoint(rect.left + 7, rect.top + 5), 515 BPoint(rect.left + 3, rect.bottom - 1), outlineColor); 516 517 AddLine(BPoint(rect.left + 4, rect.top + 3), 518 BPoint(rect.left + 4, rect.bottom - 3), middleColor); 519 AddLine(BPoint(rect.left + 5, rect.top + 4), 520 BPoint(rect.left + 5, rect.bottom - 4), middleColor); 521 AddLine(BPoint(rect.left + 5, rect.top + 5), 522 BPoint(rect.left + 6, rect.top + 5), middleColor); 523 } else { 524 AddLine(BPoint(rect.right - 3, rect.top + 1), 525 BPoint(rect.right - 3, rect.bottom - 1), outlineColor); 526 AddLine(BPoint(rect.right - 3, rect.top + 1), 527 BPoint(rect.right - 7, rect.top + 5), outlineColor); 528 AddLine(BPoint(rect.right - 7, rect.top + 5), 529 BPoint(rect.right - 3, rect.bottom - 1), outlineColor); 530 531 AddLine(BPoint(rect.right - 4, rect.top + 3), 532 BPoint(rect.right - 4, rect.bottom - 3), middleColor); 533 AddLine(BPoint(rect.right - 5, rect.top + 4), 534 BPoint(rect.right - 5, rect.bottom - 4), middleColor); 535 AddLine(BPoint(rect.right - 5, rect.top + 5), 536 BPoint(rect.right - 6, rect.top + 5), middleColor); 537 } 538 EndLineArray(); 539 break; 540 541 case kPressed: 542 BeginLineArray(7); 543 if (fLeftAligned) { 544 AddLine(BPoint(rect.left + 1, rect.top + 7), 545 BPoint(rect.left + 7, rect.top + 7), outlineColor); 546 AddLine(BPoint(rect.left + 7, rect.top + 1), 547 BPoint(rect.left + 7, rect.top + 7), outlineColor); 548 AddLine(BPoint(rect.left + 1, rect.top + 7), 549 BPoint(rect.left + 7, rect.top + 1), outlineColor); 550 551 AddLine(BPoint(rect.left + 3, rect.top + 6), 552 BPoint(rect.left + 6, rect.top + 6), middleColor); 553 AddLine(BPoint(rect.left + 4, rect.top + 5), 554 BPoint(rect.left + 6, rect.top + 5), middleColor); 555 AddLine(BPoint(rect.left + 5, rect.top + 4), 556 BPoint(rect.left + 6, rect.top + 4), middleColor); 557 AddLine(BPoint(rect.left + 6, rect.top + 3), 558 BPoint(rect.left + 6, rect.top + 4), middleColor); 559 } else { 560 AddLine(BPoint(rect.right - 1, rect.top + 7), 561 BPoint(rect.right - 7, rect.top + 7), outlineColor); 562 AddLine(BPoint(rect.right - 7, rect.top + 1), 563 BPoint(rect.right - 7, rect.top + 7), outlineColor); 564 AddLine(BPoint(rect.right - 1, rect.top + 7), 565 BPoint(rect.right - 7, rect.top + 1), outlineColor); 566 567 AddLine(BPoint(rect.right - 3, rect.top + 6), 568 BPoint(rect.right - 6, rect.top + 6), middleColor); 569 AddLine(BPoint(rect.right - 4, rect.top + 5), 570 BPoint(rect.right - 6, rect.top + 5), middleColor); 571 AddLine(BPoint(rect.right - 5, rect.top + 4), 572 BPoint(rect.right - 6, rect.top + 4), middleColor); 573 AddLine(BPoint(rect.right - 6, rect.top + 3), 574 BPoint(rect.right - 6, rect.top + 4), middleColor); 575 } 576 EndLineArray(); 577 break; 578 579 case kExpanded: 580 BeginLineArray(6); 581 AddLine(BPoint(rect.left + 1, rect.top + 3), 582 BPoint(rect.right - 1, rect.top + 3), outlineColor); 583 AddLine(BPoint(rect.left + 1, rect.top + 3), 584 BPoint(rect.left + 5, rect.top + 7), outlineColor); 585 AddLine(BPoint(rect.left + 5, rect.top + 7), 586 BPoint(rect.right - 1, rect.top + 3), outlineColor); 587 588 AddLine(BPoint(rect.left + 3, rect.top + 4), 589 BPoint(rect.right - 3, rect.top + 4), middleColor); 590 AddLine(BPoint(rect.left + 4, rect.top + 5), 591 BPoint(rect.right - 4, rect.top + 5), middleColor); 592 AddLine(BPoint(rect.left + 5, rect.top + 5), 593 BPoint(rect.left + 5, rect.top + 6), middleColor); 594 EndLineArray(); 595 break; 596 } 597 } 598 599