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 <Debug.h> 36 37 #include "TeamMenuItem.h" 38 39 #include <string.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 43 #include <Bitmap.h> 44 #include <ControlLook.h> 45 #include <Font.h> 46 #include <Region.h> 47 #include <Roster.h> 48 #include <Resources.h> 49 50 #include "BarApp.h" 51 #include "BarMenuBar.h" 52 #include "ExpandoMenuBar.h" 53 #include "ResourceSet.h" 54 #include "ShowHideMenuItem.h" 55 #include "TeamMenu.h" 56 #include "WindowMenu.h" 57 #include "WindowMenuItem.h" 58 59 60 const float kHPad = 8.0f; 61 const float kVPad = 1.0f; 62 const float kLabelOffset = 8.0f; 63 const float kSwitchWidth = 12; 64 65 66 TTeamMenuItem::TTeamMenuItem(BList* team, BBitmap* icon, char* name, char* sig, 67 float width, float height, bool drawLabel, bool vertical) 68 : BMenuItem(new TWindowMenu(team, sig)) 69 { 70 InitData(team, icon, name, sig, width, height, drawLabel, vertical); 71 } 72 73 74 TTeamMenuItem::TTeamMenuItem(float width,float height,bool vertical) 75 : BMenuItem("", NULL) 76 { 77 InitData(NULL, NULL, strdup(""), strdup(""), width, height, false, vertical); 78 } 79 80 81 void 82 TTeamMenuItem::InitData(BList* team, BBitmap* icon, char* name, char* sig, 83 float width, float height, bool drawLabel, bool vertical) 84 { 85 fTeam = team; 86 fIcon = icon; 87 fName = name; 88 fSig = sig; 89 if (fName == NULL) { 90 char temp[32]; 91 snprintf(temp, sizeof(temp), "team %ld", (int32)team->ItemAt(0)); 92 fName = strdup(temp); 93 } 94 95 SetLabel(fName); 96 97 BFont font(be_plain_font); 98 fLabelWidth = ceilf(font.StringWidth(fName)); 99 font_height fontHeight; 100 font.GetHeight(&fontHeight); 101 fLabelAscent = ceilf(fontHeight.ascent); 102 fLabelDescent = ceilf(fontHeight.descent + fontHeight.leading); 103 104 fOverrideWidth = width; 105 fOverrideHeight = height; 106 fOverriddenSelected = false; 107 108 fDrawLabel = drawLabel; 109 fVertical = vertical; 110 111 fExpanded = false; 112 } 113 114 115 TTeamMenuItem::~TTeamMenuItem() 116 { 117 delete fTeam; 118 delete fIcon; 119 free(fName); 120 free(fSig); 121 } 122 123 124 status_t 125 TTeamMenuItem::Invoke(BMessage* message) 126 { 127 if ((static_cast<TBarApp*>(be_app))->BarView()->InvokeItem(Signature())) 128 // handles drop on application 129 return B_OK; 130 131 // if the app could not handle the drag message 132 // and we were dragging, then kill the drag 133 // should never get here, disabled item will not invoke 134 TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView(); 135 if (barview && barview->Dragging()) 136 barview->DragStop(); 137 138 // bring to front or minimize shortcuts 139 uint32 mods = modifiers(); 140 if (mods & B_CONTROL_KEY) 141 TShowHideMenuItem::TeamShowHideCommon((mods & B_SHIFT_KEY) 142 ? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT, Teams()); 143 144 return BMenuItem::Invoke(message); 145 } 146 147 148 void 149 TTeamMenuItem::SetOverrideWidth(float width) 150 { 151 fOverrideWidth = width; 152 } 153 154 155 void 156 TTeamMenuItem::SetOverrideHeight(float height) 157 { 158 fOverrideHeight = height; 159 } 160 161 162 void 163 TTeamMenuItem::SetOverrideSelected(bool selected) 164 { 165 fOverriddenSelected = selected; 166 Highlight(selected); 167 } 168 169 170 float 171 TTeamMenuItem::LabelWidth() const 172 { 173 return fLabelWidth; 174 } 175 176 177 BList* 178 TTeamMenuItem::Teams() const 179 { 180 return fTeam; 181 } 182 183 184 const char* 185 TTeamMenuItem::Signature() const 186 { 187 return fSig; 188 } 189 190 191 const char* 192 TTeamMenuItem::Name() const 193 { 194 return fName; 195 } 196 197 198 void 199 TTeamMenuItem::GetContentSize(float* width, float* height) 200 { 201 BRect iconBounds; 202 203 if (fIcon) 204 iconBounds = fIcon->Bounds(); 205 else 206 iconBounds = BRect(0, 0, 15, 15); 207 208 BMenuItem::GetContentSize(width, height); 209 210 if (fOverrideWidth != -1.0f) 211 *width = fOverrideWidth; 212 else 213 *width = kHPad + iconBounds.Width() + kLabelOffset + fLabelWidth + kHPad 214 + 20; 215 216 if (fOverrideHeight != -1.0f) 217 *height = fOverrideHeight; 218 else { 219 *height = iconBounds.Height(); 220 float labelHeight = fLabelAscent + fLabelDescent; 221 if (labelHeight > *height) 222 *height = labelHeight; 223 *height += (kVPad * 2) + 2; 224 } 225 *height += 2; 226 } 227 228 229 void 230 TTeamMenuItem::Draw() 231 { 232 BRect frame(Frame()); 233 BMenu* menu = Menu(); 234 menu->PushState(); 235 rgb_color menuColor = menu->LowColor(); 236 237 TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView(); 238 bool canHandle = !barview->Dragging() 239 || barview->AppCanHandleTypes(Signature()); 240 241 if (be_control_look != NULL) { 242 uint32 flags = 0; 243 if (_IsSelected() && canHandle) 244 flags |= BControlLook::B_ACTIVATED; 245 246 uint32 borders = BControlLook::B_TOP_BORDER; 247 if (fVertical) { 248 menu->SetHighColor(tint_color(menuColor, B_DARKEN_1_TINT)); 249 borders |= BControlLook::B_LEFT_BORDER 250 | BControlLook::B_RIGHT_BORDER; 251 menu->StrokeLine(frame.LeftBottom(), frame.RightBottom()); 252 frame.bottom--; 253 254 be_control_look->DrawMenuBarBackground(menu, frame, frame, 255 menuColor, flags, borders); 256 } else { 257 if (flags & BControlLook::B_ACTIVATED) 258 menu->SetHighColor(tint_color(menuColor, B_DARKEN_3_TINT)); 259 else 260 menu->SetHighColor(tint_color(menuColor, 1.22)); 261 borders |= BControlLook::B_BOTTOM_BORDER; 262 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom()); 263 frame.left++; 264 265 be_control_look->DrawButtonBackground(menu, frame, frame, 266 menuColor, flags, borders); 267 } 268 269 menu->MovePenTo(ContentLocation()); 270 DrawContent(); 271 menu->PopState(); 272 return; 273 } 274 275 // if not selected or being tracked on, fill with gray 276 if ((!_IsSelected() && !menu->IsRedrawAfterSticky()) || !canHandle 277 || !IsEnabled()) { 278 frame.InsetBy(1, 1); 279 menu->SetHighColor(menuColor); 280 menu->FillRect(frame); 281 } 282 283 // draw the gray, unselected item, border 284 if (!_IsSelected() || !IsEnabled()) { 285 rgb_color shadow = tint_color(menuColor, B_DARKEN_1_TINT); 286 rgb_color light = tint_color(menuColor, B_LIGHTEN_2_TINT); 287 288 frame = Frame(); 289 290 menu->SetHighColor(shadow); 291 if (fVertical) 292 menu->StrokeLine(frame.LeftBottom(), frame.RightBottom()); 293 else 294 menu->StrokeLine(frame.LeftBottom() + BPoint(1, 0), 295 frame.RightBottom()); 296 297 menu->StrokeLine(frame.RightBottom(), frame.RightTop()); 298 299 menu->SetHighColor(light); 300 menu->StrokeLine(frame.RightTop() + BPoint(-1, 0), frame.LeftTop()); 301 if (fVertical) 302 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom() 303 + BPoint(0, -1)); 304 else 305 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom()); 306 } 307 308 // if selected or being tracked on, fill with the hilite gray color 309 if (IsEnabled() && _IsSelected() && !menu->IsRedrawAfterSticky() 310 && canHandle) { 311 // fill 312 menu->SetHighColor(tint_color(menuColor, B_HIGHLIGHT_BACKGROUND_TINT)); 313 menu->FillRect(frame); 314 315 // these continue the dark grey border on the left or top edge 316 menu->SetHighColor(tint_color(menuColor, B_DARKEN_4_TINT)); 317 if (fVertical) 318 // dark line at top 319 menu->StrokeLine(frame.LeftTop(), frame.RightTop()); 320 else 321 // dark line on the left 322 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom()); 323 } else 324 menu->SetLowColor(menuColor); 325 326 menu->MovePenTo(ContentLocation()); 327 DrawContent(); 328 menu->PopState(); 329 } 330 331 332 void 333 TTeamMenuItem::DrawContent() 334 { 335 BMenu* menu = Menu(); 336 if (fIcon) { 337 if (fIcon->ColorSpace() == B_RGBA32) { 338 menu->SetDrawingMode(B_OP_ALPHA); 339 menu->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 340 } else { 341 menu->SetDrawingMode(B_OP_OVER); 342 } 343 BRect frame(Frame()); 344 345 BRect iconBounds(fIcon->Bounds()); 346 BRect dstRect(iconBounds); 347 float extra = fVertical ? 0.0f : 1.0f; 348 BPoint contLoc = ContentLocation(); 349 dstRect.OffsetTo(BPoint(contLoc.x + kHPad, contLoc.y + 350 ((frame.Height() - iconBounds.Height()) / 2) + extra)); 351 menu->DrawBitmapAsync(fIcon, dstRect); 352 353 float labelHeight = fLabelAscent + fLabelDescent; 354 BPoint drawLoc = contLoc + BPoint(kHPad, kVPad); 355 drawLoc.x += iconBounds.Width() + kLabelOffset; 356 drawLoc.y = frame.top + ((frame.Height() - labelHeight) / 2) + 1.0f; 357 menu->MovePenTo(drawLoc); 358 } 359 360 // set the pen to black so that either method will draw in the same color 361 // low color is set in inherited::DrawContent, override makes sure its 362 // what we want 363 if (fDrawLabel) { 364 menu->SetDrawingMode(B_OP_OVER); 365 menu->SetHighColor(0, 0, 0); 366 367 // override the drawing of the content when the item is disabled 368 // the wrong lowcolor is used when the item is disabled since the 369 // text color does not change 370 DrawContentLabel(); 371 } 372 373 // Draw the expandable icon. 374 TBarView* barView = (static_cast<TBarApp*>(be_app))->BarView(); 375 if (fVertical && static_cast<TBarApp*>(be_app)->Settings()->superExpando 376 && barView->Expando()) { 377 BRect frame(Frame()); 378 BRect rect(0, 0, kSwitchWidth, 10); 379 rect.OffsetTo(BPoint(frame.right - rect.Width(), 380 ContentLocation().y + ((frame.Height() - rect.Height()) / 2))); 381 382 if (be_control_look != NULL) { 383 uint32 arrowDirection = fExpanded 384 ? BControlLook::B_UP_ARROW : BControlLook::B_DOWN_ARROW; 385 be_control_look->DrawArrowShape(menu, rect, rect, menu->LowColor(), 386 arrowDirection, 0, B_DARKEN_3_TINT); 387 } else { 388 rgb_color outlineColor = {80, 80, 80, 255}; 389 rgb_color middleColor = {200, 200, 200, 255}; 390 391 menu->SetDrawingMode(B_OP_OVER); 392 393 if (!fExpanded) { 394 menu->BeginLineArray(6); 395 396 menu->AddLine(BPoint(rect.left + 3, rect.top + 1), 397 BPoint(rect.left + 3, rect.bottom - 1), outlineColor); 398 menu->AddLine(BPoint(rect.left + 3, rect.top + 1), 399 BPoint(rect.left + 7, rect.top + 5), outlineColor); 400 menu->AddLine(BPoint(rect.left + 7, rect.top + 5), 401 BPoint(rect.left + 3, rect.bottom - 1), outlineColor); 402 403 menu->AddLine(BPoint(rect.left + 4, rect.top + 3), 404 BPoint(rect.left + 4, rect.bottom - 3), middleColor); 405 menu->AddLine(BPoint(rect.left + 5, rect.top + 4), 406 BPoint(rect.left + 5, rect.bottom - 4), middleColor); 407 menu->AddLine(BPoint(rect.left + 5, rect.top + 5), 408 BPoint(rect.left + 6, rect.top + 5), middleColor); 409 menu->EndLineArray(); 410 } else { 411 // expanded state 412 413 menu->BeginLineArray(6); 414 menu->AddLine(BPoint(rect.left + 1, rect.top + 3), 415 BPoint(rect.right - 3, rect.top + 3), outlineColor); 416 menu->AddLine(BPoint(rect.left + 1, rect.top + 3), 417 BPoint(rect.left + 5, rect.top + 7), outlineColor); 418 menu->AddLine(BPoint(rect.left + 5, rect.top + 7), 419 BPoint(rect.right - 3, rect.top + 3), outlineColor); 420 421 menu->AddLine(BPoint(rect.left + 3, rect.top + 4), 422 BPoint(rect.right - 5, rect.top + 4), middleColor); 423 menu->AddLine(BPoint(rect.left + 4, rect.top + 5), 424 BPoint(rect.right - 6, rect.top + 5), middleColor); 425 menu->AddLine(BPoint(rect.left + 5, rect.top + 5), 426 BPoint(rect.left + 5, rect.top + 6), middleColor); 427 menu->EndLineArray(); 428 } 429 } 430 } 431 } 432 433 434 void 435 TTeamMenuItem::DrawContentLabel() 436 { 437 BMenu* menu = Menu(); 438 menu->MovePenBy(0, fLabelAscent); 439 440 float cachedWidth = menu->StringWidth(Label()); 441 if (Submenu() && fVertical) 442 cachedWidth += 18; 443 444 const char* label = Label(); 445 char* truncLabel = NULL; 446 float max = 0; 447 if (static_cast<TBarApp*>(be_app)->Settings()->superExpando && fVertical) 448 max = menu->MaxContentWidth() - kSwitchWidth; 449 else 450 max = menu->MaxContentWidth(); 451 452 if (max > 0) { 453 BPoint penloc = menu->PenLocation(); 454 BRect frame = Frame(); 455 float offset = penloc.x - frame.left; 456 if (cachedWidth + offset > max) { 457 truncLabel = (char*)malloc(strlen(label) + 4); 458 if (!truncLabel) 459 return; 460 TruncateLabel(max-offset, truncLabel); 461 label = truncLabel; 462 } 463 } 464 465 if (!label) 466 label = Label(); 467 468 TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView(); 469 bool canHandle = !barview->Dragging() 470 || barview->AppCanHandleTypes(Signature()); 471 if (_IsSelected() && IsEnabled() && canHandle) 472 menu->SetLowColor(tint_color(menu->ViewColor(), 473 B_HIGHLIGHT_BACKGROUND_TINT)); 474 else 475 menu->SetLowColor(menu->ViewColor()); 476 477 menu->DrawString(label); 478 479 free(truncLabel); 480 } 481 482 483 bool 484 TTeamMenuItem::IsExpanded() 485 { 486 return fExpanded; 487 } 488 489 490 void 491 TTeamMenuItem::ToggleExpandState(bool resizeWindow) 492 { 493 fExpanded = !fExpanded; 494 495 if (fExpanded) { 496 // Populate Menu() with the stuff from SubMenu(). 497 TWindowMenu* sub = (static_cast<TWindowMenu*>(Submenu())); 498 if (sub) { 499 // force the menu to update it's contents. 500 bool locked = sub->LockLooper(); 501 // if locking the looper failed, the menu is just not visible 502 sub->AttachedToWindow(); 503 if (locked) 504 sub->UnlockLooper(); 505 506 if (sub->CountItems() > 1){ 507 TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu()); 508 int myindex = parent->IndexOf(this) + 1; 509 510 TWindowMenuItem* windowItem = NULL; 511 int childIndex = 0; 512 int totalChildren = sub->CountItems() - 4; 513 // hide, show, close, separator. 514 for (; childIndex < totalChildren; childIndex++) { 515 windowItem = static_cast<TWindowMenuItem*> 516 (sub->RemoveItem((int32)0)); 517 parent->AddItem(windowItem, myindex + childIndex); 518 windowItem->ExpandedItem(true); 519 } 520 sub->SetExpanded(true, myindex + childIndex); 521 522 if (resizeWindow) 523 parent->SizeWindow(); 524 } else 525 fExpanded = fExpanded; 526 } 527 } else { 528 // Remove the goodies from the Menu() that should be in the SubMenu(); 529 TWindowMenu* sub = static_cast<TWindowMenu*>(Submenu()); 530 531 if (sub) { 532 TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu()); 533 534 TWindowMenuItem* windowItem = NULL; 535 int childIndex = parent->IndexOf(this) + 1; 536 while (!parent->SubmenuAt(childIndex) && childIndex 537 < parent->CountItems()) { 538 windowItem = static_cast<TWindowMenuItem*> 539 (parent->RemoveItem(childIndex)); 540 sub->AddItem(windowItem, 0); 541 windowItem->ExpandedItem(false); 542 } 543 sub->SetExpanded(false, 0); 544 545 if (resizeWindow) 546 parent->SizeWindow(); 547 } else 548 fExpanded = fExpanded; 549 } 550 } 551 552 553 TWindowMenuItem* 554 TTeamMenuItem::ExpandedWindowItem(int32 id) 555 { 556 if (!fExpanded) // Paranoia 557 return NULL; 558 559 TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu()); 560 int childIndex = parent->IndexOf(this) + 1; 561 562 while (!parent->SubmenuAt(childIndex) 563 && childIndex < parent->CountItems()) { 564 TWindowMenuItem* item 565 = static_cast<TWindowMenuItem*>(parent->ItemAt(childIndex)); 566 if (item->ID() == id) 567 return item; 568 569 childIndex++; 570 } 571 return NULL; 572 } 573 574 575 BRect 576 TTeamMenuItem::ExpanderBounds() const 577 { 578 BRect bounds(Frame()); 579 bounds.left = bounds.right - kSwitchWidth; 580 return bounds; 581 } 582 583 584 bool 585 TTeamMenuItem::_IsSelected() const 586 { 587 return IsSelected() || fOverriddenSelected; 588 } 589 590