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 36 #include "DialogPane.h" 37 38 #include <ControlLook.h> 39 #include <LayoutUtils.h> 40 41 #include "Thread.h" 42 #include "Utilities.h" 43 #include "Window.h" 44 45 46 const uint32 kValueChanged = 'swch'; 47 48 const rgb_color kNormalColor = {150, 150, 150, 255}; 49 const rgb_color kHighlightColor = {100, 100, 0, 255}; 50 51 52 static void 53 AddSelf(BView* self, BView* to) 54 { 55 to->AddChild(self); 56 } 57 58 59 void 60 ViewList::RemoveAll(BView*) 61 { 62 EachListItemIgnoreResult(this, &BView::RemoveSelf); 63 } 64 65 66 void 67 ViewList::AddAll(BView* toParent) 68 { 69 EachListItem(this, &AddSelf, toParent); 70 } 71 72 73 // #pragma mark - DialogPane 74 75 76 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, int32 initialMode, 77 const char* name, uint32 followFlags, uint32 flags) 78 : 79 BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode2Frame), 80 name, followFlags, flags), 81 fMode(initialMode), 82 fMode1Frame(mode1Frame), 83 fMode2Frame(mode2Frame), 84 fMode3Frame(mode2Frame) 85 { 86 SetMode(fMode, true); 87 } 88 89 90 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, BRect mode3Frame, 91 int32 initialMode, const char* name, uint32 followFlags, uint32 flags) 92 : 93 BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode3Frame), 94 name, followFlags, flags), 95 fMode(initialMode), 96 fMode1Frame(mode1Frame), 97 fMode2Frame(mode2Frame), 98 fMode3Frame(mode3Frame) 99 { 100 SetMode(fMode, true); 101 } 102 103 104 DialogPane::~DialogPane() 105 { 106 fMode3Items.RemoveAll(this); 107 fMode2Items.RemoveAll(this); 108 } 109 110 111 void 112 DialogPane::SetMode(int32 mode, bool initialSetup) 113 { 114 ASSERT(mode < 3 && mode >= 0); 115 116 if (!initialSetup && mode == fMode) 117 return; 118 119 int32 oldMode = fMode; 120 fMode = mode; 121 122 bool followBottom = (ResizingMode() & B_FOLLOW_BOTTOM) != 0; 123 // if we are follow bottom, we will move ourselves, need to place us back 124 float bottomOffset = 0; 125 if (followBottom && Window() != NULL) 126 bottomOffset = Window()->Bounds().bottom - Frame().bottom; 127 128 BRect newBounds(BoundsForMode(fMode)); 129 if (!initialSetup) 130 ResizeParentWindow(fMode, oldMode); 131 132 ResizeTo(newBounds.Width(), newBounds.Height()); 133 134 float delta = 0; 135 if (followBottom && Window() != NULL) 136 delta = (Window()->Bounds().bottom - Frame().bottom) - bottomOffset; 137 138 if (delta != 0) { 139 MoveBy(0, delta); 140 if (fLatch && (fLatch->ResizingMode() & B_FOLLOW_BOTTOM)) 141 fLatch->MoveBy(0, delta); 142 } 143 144 switch (fMode) { 145 case 0: 146 { 147 if (oldMode > 1) 148 fMode3Items.RemoveAll(this); 149 if (oldMode > 0) 150 fMode2Items.RemoveAll(this); 151 152 BView* separator = FindView("separatorLine"); 153 if (separator) { 154 BRect frame(separator->Frame()); 155 frame.InsetBy(-1, -1); 156 RemoveChild(separator); 157 Invalidate(); 158 } 159 160 AddChild(new SeparatorLine(BPoint(newBounds.left, newBounds.top 161 + newBounds.Height() / 2), newBounds.Width(), false, 162 "separatorLine")); 163 break; 164 } 165 166 case 1: 167 { 168 if (oldMode > 1) 169 fMode3Items.RemoveAll(this); 170 else 171 fMode2Items.AddAll(this); 172 173 BView* separator = FindView("separatorLine"); 174 if (separator) { 175 BRect frame(separator->Frame()); 176 frame.InsetBy(-1, -1); 177 RemoveChild(separator); 178 Invalidate(); 179 } 180 break; 181 } 182 183 case 2: 184 { 185 fMode3Items.AddAll(this); 186 if (oldMode < 1) 187 fMode2Items.AddAll(this); 188 189 BView* separator = FindView("separatorLine"); 190 if (separator) { 191 BRect frame(separator->Frame()); 192 frame.InsetBy(-1, -1); 193 RemoveChild(separator); 194 Invalidate(); 195 } 196 break; 197 } 198 } 199 } 200 201 202 void 203 DialogPane::AttachedToWindow() 204 { 205 BView* parent = Parent(); 206 if (parent != NULL) { 207 SetViewColor(parent->ViewColor()); 208 SetLowColor(parent->LowColor()); 209 } 210 } 211 212 213 void 214 DialogPane::ResizeParentWindow(int32 from, int32 to) 215 { 216 if (Window() == NULL) 217 return; 218 219 BRect oldBounds = BoundsForMode(from); 220 BRect newBounds = BoundsForMode(to); 221 222 BPoint by = oldBounds.RightBottom() - newBounds.RightBottom(); 223 if (by != BPoint(0, 0)) 224 Window()->ResizeBy(by.x, by.y); 225 } 226 227 228 void 229 DialogPane::AddItem(BView* view, int32 toMode) 230 { 231 if (toMode == 1) 232 fMode2Items.AddItem(view); 233 else if (toMode == 2) 234 fMode3Items.AddItem(view); 235 236 if (fMode >= toMode) 237 AddChild(view); 238 } 239 240 241 BRect 242 DialogPane::FrameForMode(int32 mode) 243 { 244 switch (mode) { 245 case 0: 246 return fMode1Frame; 247 248 case 1: 249 return fMode2Frame; 250 251 case 2: 252 return fMode3Frame; 253 } 254 255 return fMode1Frame; 256 } 257 258 259 BRect 260 DialogPane::BoundsForMode(int32 mode) 261 { 262 BRect result; 263 switch (mode) { 264 case 0: 265 result = fMode1Frame; 266 break; 267 268 case 1: 269 result = fMode2Frame; 270 break; 271 272 case 2: 273 result = fMode3Frame; 274 break; 275 } 276 result.OffsetTo(0, 0); 277 278 return result; 279 } 280 281 282 BRect 283 DialogPane::FrameForMode(int32 mode, BRect mode1Frame, BRect mode2Frame, 284 BRect mode3Frame) 285 { 286 switch (mode) { 287 case 0: 288 return mode1Frame; 289 290 case 1: 291 return mode2Frame; 292 293 case 2: 294 return mode3Frame; 295 } 296 297 return mode1Frame; 298 } 299 300 301 void 302 DialogPane::SetSwitch(BControl* control) 303 { 304 fLatch = control; 305 control->SetMessage(new BMessage(kValueChanged)); 306 control->SetTarget(this); 307 } 308 309 310 void 311 DialogPane::MessageReceived(BMessage* message) 312 { 313 if (message->what == kValueChanged) { 314 int32 value; 315 if (message->FindInt32("be:value", &value) == B_OK) 316 SetMode(value); 317 } else 318 _inherited::MessageReceived(message); 319 } 320 321 322 // #pragma mark - PaneSwitch 323 324 325 PaneSwitch::PaneSwitch(BRect frame, const char* name, bool leftAligned, 326 uint32 resizeMask, uint32 flags) 327 : 328 BControl(frame, name, "", 0, resizeMask, flags), 329 fLeftAligned(leftAligned), 330 fPressing(false), 331 fLabelOn(NULL), 332 fLabelOff(NULL) 333 { 334 } 335 336 337 PaneSwitch::PaneSwitch(const char* name, bool leftAligned, uint32 flags) 338 : 339 BControl(name, "", 0, flags), 340 fLeftAligned(leftAligned), 341 fPressing(false), 342 fLabelOn(NULL), 343 fLabelOff(NULL) 344 { 345 } 346 347 348 PaneSwitch::~PaneSwitch() 349 { 350 free(fLabelOn); 351 free(fLabelOff); 352 } 353 354 355 void 356 PaneSwitch::Draw(BRect) 357 { 358 BRect bounds(Bounds()); 359 360 // Draw the label, if any 361 const char* label = fLabelOff; 362 if (fLabelOn != NULL && Value() == B_CONTROL_ON) 363 label = fLabelOn; 364 365 if (label != NULL) { 366 BPoint point; 367 float labelDist = sLatchSize + ceilf(sLatchSize / 2.0); 368 if (fLeftAligned) 369 point.x = labelDist; 370 else 371 point.x = bounds.right - labelDist - StringWidth(label); 372 373 font_height fontHeight; 374 GetFontHeight(&fontHeight); 375 point.y = (bounds.top + bounds.bottom 376 - ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2 377 + ceilf(fontHeight.ascent); 378 379 DrawString(label, point); 380 } 381 382 // draw the latch 383 if (fPressing) 384 DrawInState(kPressed); 385 else if (Value()) 386 DrawInState(kExpanded); 387 else 388 DrawInState(kCollapsed); 389 390 // ...and the focus indication 391 if (!IsFocus() || !Window()->IsActive()) 392 return; 393 394 rgb_color markColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 395 396 BeginLineArray(2); 397 AddLine(BPoint(bounds.left + 2, bounds.bottom - 1), 398 BPoint(bounds.right - 2, bounds.bottom - 1), markColor); 399 AddLine(BPoint(bounds.left + 2, bounds.bottom), 400 BPoint(bounds.right - 2, bounds.bottom), kWhite); 401 EndLineArray(); 402 } 403 404 405 void 406 PaneSwitch::MouseDown(BPoint) 407 { 408 if (!IsEnabled()) 409 return; 410 411 fPressing = true; 412 MouseDownThread<PaneSwitch>::TrackMouse(this, &PaneSwitch::DoneTracking, 413 &PaneSwitch::Track); 414 Invalidate(); 415 } 416 417 418 void 419 PaneSwitch::GetPreferredSize(float* _width, float* _height) 420 { 421 BSize size = MinSize(); 422 if (_width != NULL) 423 *_width = size.width; 424 425 if (_height != NULL) 426 *_height = size.height; 427 } 428 429 430 BSize 431 PaneSwitch::MinSize() 432 { 433 BSize size; 434 float onLabelWidth = StringWidth(fLabelOn); 435 float offLabelWidth = StringWidth(fLabelOff); 436 float labelWidth = max_c(onLabelWidth, offLabelWidth); 437 size.width = sLatchSize; 438 if (labelWidth > 0.0) 439 size.width += ceilf(sLatchSize / 2.0) + labelWidth; 440 441 font_height fontHeight; 442 GetFontHeight(&fontHeight); 443 size.height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 444 size.height = max_c(size.height, sLatchSize); 445 446 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); 447 } 448 449 450 BSize 451 PaneSwitch::MaxSize() 452 { 453 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), MinSize()); 454 } 455 456 457 BSize 458 PaneSwitch::PreferredSize() 459 { 460 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize()); 461 } 462 463 464 void 465 PaneSwitch::SetLabels(const char* labelOn, const char* labelOff) 466 { 467 free(fLabelOn); 468 free(fLabelOff); 469 470 if (labelOn != NULL) 471 fLabelOn = strdup(labelOn); 472 else 473 fLabelOn = NULL; 474 475 if (labelOff != NULL) 476 fLabelOff = strdup(labelOff); 477 else 478 fLabelOff = NULL; 479 480 Invalidate(); 481 InvalidateLayout(); 482 } 483 484 485 void 486 PaneSwitch::DoneTracking(BPoint point) 487 { 488 BRect bounds(Bounds()); 489 bounds.InsetBy(-3, -3); 490 491 fPressing = false; 492 Invalidate(); 493 if (bounds.Contains(point)) { 494 SetValue(!Value()); 495 Invoke(); 496 } 497 } 498 499 500 void 501 PaneSwitch::Track(BPoint point, uint32) 502 { 503 BRect bounds(Bounds()); 504 bounds.InsetBy(-3, -3); 505 506 bool newPressing = bounds.Contains(point); 507 if (newPressing != fPressing) { 508 fPressing = newPressing; 509 Invalidate(); 510 } 511 } 512 513 514 void 515 PaneSwitch::DrawInState(PaneSwitch::State state) 516 { 517 BRect rect(0, 0, be_plain_font->Size(), be_plain_font->Size()); 518 rect.OffsetBy(1, 1); 519 520 rgb_color arrowColor = state == kPressed ? kHighlightColor : kNormalColor; 521 int32 arrowDirection = BControlLook::B_RIGHT_ARROW; 522 float tint = IsEnabled() && Window()->IsActive() ? B_DARKEN_3_TINT 523 : B_DARKEN_1_TINT; 524 525 switch (state) { 526 case kCollapsed: 527 arrowDirection = BControlLook::B_RIGHT_ARROW; 528 break; 529 530 case kPressed: 531 arrowDirection = BControlLook::B_RIGHT_DOWN_ARROW; 532 break; 533 534 case kExpanded: 535 arrowDirection = BControlLook::B_DOWN_ARROW; 536 break; 537 } 538 539 SetDrawingMode(B_OP_COPY); 540 be_control_look->DrawArrowShape(this, rect, rect, arrowColor, 541 arrowDirection, 0, tint); 542 } 543