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 AdoptParentColors(); 206 } 207 208 209 void 210 DialogPane::ResizeParentWindow(int32 from, int32 to) 211 { 212 if (Window() == NULL) 213 return; 214 215 BRect oldBounds = BoundsForMode(from); 216 BRect newBounds = BoundsForMode(to); 217 218 BPoint by = oldBounds.RightBottom() - newBounds.RightBottom(); 219 if (by != BPoint(0, 0)) 220 Window()->ResizeBy(by.x, by.y); 221 } 222 223 224 void 225 DialogPane::AddItem(BView* view, int32 toMode) 226 { 227 if (toMode == 1) 228 fMode2Items.AddItem(view); 229 else if (toMode == 2) 230 fMode3Items.AddItem(view); 231 232 if (fMode >= toMode) 233 AddChild(view); 234 } 235 236 237 BRect 238 DialogPane::FrameForMode(int32 mode) 239 { 240 switch (mode) { 241 case 0: 242 return fMode1Frame; 243 244 case 1: 245 return fMode2Frame; 246 247 case 2: 248 return fMode3Frame; 249 } 250 251 return fMode1Frame; 252 } 253 254 255 BRect 256 DialogPane::BoundsForMode(int32 mode) 257 { 258 BRect result; 259 switch (mode) { 260 case 0: 261 result = fMode1Frame; 262 break; 263 264 case 1: 265 result = fMode2Frame; 266 break; 267 268 case 2: 269 result = fMode3Frame; 270 break; 271 } 272 result.OffsetTo(0, 0); 273 274 return result; 275 } 276 277 278 BRect 279 DialogPane::FrameForMode(int32 mode, BRect mode1Frame, BRect mode2Frame, 280 BRect mode3Frame) 281 { 282 switch (mode) { 283 case 0: 284 return mode1Frame; 285 286 case 1: 287 return mode2Frame; 288 289 case 2: 290 return mode3Frame; 291 } 292 293 return mode1Frame; 294 } 295 296 297 void 298 DialogPane::SetSwitch(BControl* control) 299 { 300 fLatch = control; 301 control->SetMessage(new BMessage(kValueChanged)); 302 control->SetTarget(this); 303 } 304 305 306 void 307 DialogPane::MessageReceived(BMessage* message) 308 { 309 if (message->what == kValueChanged) { 310 int32 value; 311 if (message->FindInt32("be:value", &value) == B_OK) 312 SetMode(value); 313 } else 314 _inherited::MessageReceived(message); 315 } 316 317 318 // #pragma mark - PaneSwitch 319 320 321 PaneSwitch::PaneSwitch(BRect frame, const char* name, bool leftAligned, 322 uint32 resizeMask, uint32 flags) 323 : 324 BControl(frame, name, "", 0, resizeMask, flags), 325 fLeftAligned(leftAligned), 326 fPressing(false), 327 fLabelOn(NULL), 328 fLabelOff(NULL) 329 { 330 } 331 332 333 PaneSwitch::PaneSwitch(const char* name, bool leftAligned, uint32 flags) 334 : 335 BControl(name, "", 0, flags), 336 fLeftAligned(leftAligned), 337 fPressing(false), 338 fLabelOn(NULL), 339 fLabelOff(NULL) 340 { 341 } 342 343 344 PaneSwitch::~PaneSwitch() 345 { 346 free(fLabelOn); 347 free(fLabelOff); 348 } 349 350 351 void 352 PaneSwitch::Draw(BRect) 353 { 354 BRect bounds(Bounds()); 355 356 // Draw the label, if any 357 const char* label = fLabelOff; 358 if (fLabelOn != NULL && Value() == B_CONTROL_ON) 359 label = fLabelOn; 360 361 if (label != NULL) { 362 BPoint point; 363 float labelDist = sLatchSize + ceilf(sLatchSize / 2.0); 364 if (fLeftAligned) 365 point.x = labelDist; 366 else 367 point.x = bounds.right - labelDist - StringWidth(label); 368 369 SetHighUIColor(B_PANEL_TEXT_COLOR); 370 font_height fontHeight; 371 GetFontHeight(&fontHeight); 372 point.y = (bounds.top + bounds.bottom 373 - ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2 374 + ceilf(fontHeight.ascent); 375 376 DrawString(label, point); 377 } 378 379 // draw the latch 380 if (fPressing) 381 DrawInState(kPressed); 382 else if (Value()) 383 DrawInState(kExpanded); 384 else 385 DrawInState(kCollapsed); 386 387 // ...and the focus indication 388 if (!IsFocus() || !Window()->IsActive()) 389 return; 390 391 rgb_color markColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 392 393 BeginLineArray(2); 394 AddLine(BPoint(bounds.left + 2, bounds.bottom - 1), 395 BPoint(bounds.right - 2, bounds.bottom - 1), markColor); 396 AddLine(BPoint(bounds.left + 2, bounds.bottom), 397 BPoint(bounds.right - 2, bounds.bottom), kWhite); 398 EndLineArray(); 399 } 400 401 402 void 403 PaneSwitch::MouseDown(BPoint) 404 { 405 if (!IsEnabled()) 406 return; 407 408 fPressing = true; 409 MouseDownThread<PaneSwitch>::TrackMouse(this, &PaneSwitch::DoneTracking, 410 &PaneSwitch::Track); 411 Invalidate(); 412 } 413 414 415 void 416 PaneSwitch::GetPreferredSize(float* _width, float* _height) 417 { 418 BSize size = MinSize(); 419 if (_width != NULL) 420 *_width = size.width; 421 422 if (_height != NULL) 423 *_height = size.height; 424 } 425 426 427 BSize 428 PaneSwitch::MinSize() 429 { 430 BSize size; 431 float onLabelWidth = StringWidth(fLabelOn); 432 float offLabelWidth = StringWidth(fLabelOff); 433 float labelWidth = max_c(onLabelWidth, offLabelWidth); 434 size.width = sLatchSize; 435 if (labelWidth > 0.0) 436 size.width += ceilf(sLatchSize / 2.0) + labelWidth; 437 438 font_height fontHeight; 439 GetFontHeight(&fontHeight); 440 size.height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 441 size.height = max_c(size.height, sLatchSize); 442 443 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); 444 } 445 446 447 BSize 448 PaneSwitch::MaxSize() 449 { 450 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), MinSize()); 451 } 452 453 454 BSize 455 PaneSwitch::PreferredSize() 456 { 457 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize()); 458 } 459 460 461 void 462 PaneSwitch::SetLabels(const char* labelOn, const char* labelOff) 463 { 464 free(fLabelOn); 465 free(fLabelOff); 466 467 if (labelOn != NULL) 468 fLabelOn = strdup(labelOn); 469 else 470 fLabelOn = NULL; 471 472 if (labelOff != NULL) 473 fLabelOff = strdup(labelOff); 474 else 475 fLabelOff = NULL; 476 477 Invalidate(); 478 InvalidateLayout(); 479 } 480 481 482 void 483 PaneSwitch::DoneTracking(BPoint point) 484 { 485 BRect bounds(Bounds()); 486 bounds.InsetBy(-3, -3); 487 488 fPressing = false; 489 Invalidate(); 490 if (bounds.Contains(point)) { 491 SetValue(!Value()); 492 Invoke(); 493 } 494 } 495 496 497 void 498 PaneSwitch::Track(BPoint point, uint32) 499 { 500 BRect bounds(Bounds()); 501 bounds.InsetBy(-3, -3); 502 503 bool newPressing = bounds.Contains(point); 504 if (newPressing != fPressing) { 505 fPressing = newPressing; 506 Invalidate(); 507 } 508 } 509 510 511 void 512 PaneSwitch::DrawInState(PaneSwitch::State state) 513 { 514 BRect rect(0, 0, be_plain_font->Size(), be_plain_font->Size()); 515 rect.OffsetBy(1, 1); 516 517 rgb_color arrowColor = state == kPressed ? kHighlightColor : kNormalColor; 518 int32 arrowDirection = BControlLook::B_RIGHT_ARROW; 519 float tint = IsEnabled() && Window()->IsActive() ? B_DARKEN_3_TINT 520 : B_DARKEN_1_TINT; 521 522 switch (state) { 523 case kCollapsed: 524 arrowDirection = BControlLook::B_RIGHT_ARROW; 525 break; 526 527 case kPressed: 528 arrowDirection = BControlLook::B_RIGHT_DOWN_ARROW; 529 break; 530 531 case kExpanded: 532 arrowDirection = BControlLook::B_DOWN_ARROW; 533 break; 534 } 535 536 SetDrawingMode(B_OP_COPY); 537 be_control_look->DrawArrowShape(this, rect, rect, arrowColor, 538 arrowDirection, 0, tint); 539 } 540