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