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 + 20; 214 215 if (fOverrideHeight != -1.0f) 216 *height = fOverrideHeight; 217 else { 218 *height = iconBounds.Height(); 219 float labelHeight = fLabelAscent + fLabelDescent; 220 if (labelHeight > *height) 221 *height = labelHeight; 222 *height += (kVPad * 2) + 2; 223 } 224 *height += 2; 225 } 226 227 228 void 229 TTeamMenuItem::Draw() 230 { 231 BRect frame(Frame()); 232 BMenu *menu = Menu(); 233 menu->PushState(); 234 rgb_color menuColor = menu->LowColor(); 235 236 TBarView *barview = (static_cast<TBarApp *>(be_app))->BarView(); 237 bool canHandle = !barview->Dragging() 238 || barview->AppCanHandleTypes(Signature()); 239 240 if (be_control_look != NULL) { 241 uint32 flags = 0; 242 if (_IsSelected() && canHandle) 243 flags |= BControlLook::B_ACTIVATED; 244 245 uint32 borders = BControlLook::B_TOP_BORDER; 246 if (fVertical) { 247 menu->SetHighColor(tint_color(menuColor, B_DARKEN_1_TINT)); 248 borders |= BControlLook::B_LEFT_BORDER 249 | BControlLook::B_RIGHT_BORDER; 250 menu->StrokeLine(frame.LeftBottom(), frame.RightBottom()); 251 frame.bottom--; 252 253 be_control_look->DrawMenuBarBackground(menu, frame, frame, 254 menuColor, flags, borders); 255 } else { 256 if (flags & BControlLook::B_ACTIVATED) 257 menu->SetHighColor(tint_color(menuColor, B_DARKEN_3_TINT)); 258 else 259 menu->SetHighColor(tint_color(menuColor, 1.22)); 260 borders |= BControlLook::B_BOTTOM_BORDER; 261 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom()); 262 frame.left++; 263 264 be_control_look->DrawButtonBackground(menu, frame, frame, 265 menuColor, flags, borders); 266 } 267 268 menu->MovePenTo(ContentLocation()); 269 DrawContent(); 270 menu->PopState(); 271 return; 272 } 273 274 // if not selected or being tracked on, fill with gray 275 if (!_IsSelected() && !menu->IsRedrawAfterSticky() || !canHandle 276 || !IsEnabled()) { 277 frame.InsetBy(1, 1); 278 menu->SetHighColor(menuColor); 279 menu->FillRect(frame); 280 } 281 282 // draw the gray, unselected item, border 283 if (!_IsSelected() || !IsEnabled()) { 284 rgb_color shadow = tint_color(menuColor, B_DARKEN_1_TINT); 285 rgb_color light = tint_color(menuColor, B_LIGHTEN_2_TINT); 286 287 frame = Frame(); 288 289 menu->SetHighColor(shadow); 290 if (fVertical) 291 menu->StrokeLine(frame.LeftBottom(), frame.RightBottom()); 292 else 293 menu->StrokeLine(frame.LeftBottom() + BPoint(1, 0), frame.RightBottom()); 294 295 menu->StrokeLine(frame.RightBottom(), frame.RightTop()); 296 297 menu->SetHighColor(light); 298 menu->StrokeLine(frame.RightTop() + BPoint(-1, 0), frame.LeftTop()); 299 if (fVertical) 300 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom() + BPoint(0, -1)); 301 else 302 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom()); 303 } 304 305 // if selected or being tracked on, fill with the hilite gray color 306 if (IsEnabled() && _IsSelected() && !menu->IsRedrawAfterSticky() && canHandle) { 307 // fill 308 menu->SetHighColor(tint_color(menuColor, B_HIGHLIGHT_BACKGROUND_TINT)); 309 menu->FillRect(frame); 310 311 // these continue the dark grey border on the left or top edge 312 menu->SetHighColor(tint_color(menuColor, B_DARKEN_4_TINT)); 313 if (fVertical) 314 // dark line at top 315 menu->StrokeLine(frame.LeftTop(), frame.RightTop()); 316 else 317 // dark line on the left 318 menu->StrokeLine(frame.LeftTop(), frame.LeftBottom()); 319 } else 320 menu->SetLowColor(menuColor); 321 322 menu->MovePenTo(ContentLocation()); 323 DrawContent(); 324 menu->PopState(); 325 } 326 327 328 void 329 TTeamMenuItem::DrawContent() 330 { 331 BMenu *menu = Menu(); 332 if (fIcon) { 333 if (fIcon->ColorSpace() == B_RGBA32) { 334 menu->SetDrawingMode(B_OP_ALPHA); 335 menu->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 336 } else { 337 menu->SetDrawingMode(B_OP_OVER); 338 } 339 BRect frame(Frame()); 340 341 BRect iconBounds(fIcon->Bounds()); 342 BRect dstRect(iconBounds); 343 float extra = fVertical ? 0.0f : 1.0f; 344 BPoint contLoc = ContentLocation(); 345 dstRect.OffsetTo(BPoint(contLoc.x + kHPad, contLoc.y + 346 ((frame.Height() - iconBounds.Height()) / 2) + extra)); 347 menu->DrawBitmapAsync(fIcon, dstRect); 348 349 float labelHeight = fLabelAscent + fLabelDescent; 350 BPoint drawLoc = contLoc + BPoint(kHPad, kVPad); 351 drawLoc.x += iconBounds.Width() + kLabelOffset; 352 drawLoc.y = frame.top + ((frame.Height() - labelHeight) / 2) + 1.0f; 353 menu->MovePenTo(drawLoc); 354 } 355 356 // set the pen to black so that either method will draw in the same color 357 // low color is set in inherited::DrawContent, override makes sure its 358 // what we want 359 if (fDrawLabel) { 360 menu->SetDrawingMode(B_OP_OVER); 361 menu->SetHighColor(0, 0, 0); 362 363 // override the drawing of the content when the item is disabled 364 // the wrong lowcolor is used when the item is disabled since the 365 // text color does not change 366 DrawContentLabel(); 367 } 368 369 // Draw the expandable icon. 370 TBarView *barView = (static_cast<TBarApp *>(be_app))->BarView(); 371 if (fVertical && static_cast<TBarApp *>(be_app)->Settings()->superExpando 372 && barView->Expando()) { 373 BRect frame(Frame()); 374 BRect rect(0, 0, kSwitchWidth, 10); 375 rect.OffsetTo(BPoint(frame.right - rect.Width(), 376 ContentLocation().y + ((frame.Height() - rect.Height()) / 2))); 377 378 if (be_control_look != NULL) { 379 uint32 arrowDirection = fExpanded 380 ? BControlLook::B_UP_ARROW : BControlLook::B_DOWN_ARROW; 381 be_control_look->DrawArrowShape(menu, rect, rect, menu->LowColor(), 382 arrowDirection, 0, B_DARKEN_3_TINT); 383 } else { 384 rgb_color outlineColor = {80, 80, 80, 255}; 385 rgb_color middleColor = {200, 200, 200, 255}; 386 387 menu->SetDrawingMode(B_OP_OVER); 388 389 if (!fExpanded) { 390 menu->BeginLineArray(6); 391 392 menu->AddLine(BPoint(rect.left + 3, rect.top + 1), 393 BPoint(rect.left + 3, rect.bottom - 1), outlineColor); 394 menu->AddLine(BPoint(rect.left + 3, rect.top + 1), 395 BPoint(rect.left + 7, rect.top + 5), outlineColor); 396 menu->AddLine(BPoint(rect.left + 7, rect.top + 5), 397 BPoint(rect.left + 3, rect.bottom - 1), outlineColor); 398 399 menu->AddLine(BPoint(rect.left + 4, rect.top + 3), 400 BPoint(rect.left + 4, rect.bottom - 3), middleColor); 401 menu->AddLine(BPoint(rect.left + 5, rect.top + 4), 402 BPoint(rect.left + 5, rect.bottom - 4), middleColor); 403 menu->AddLine(BPoint(rect.left + 5, rect.top + 5), 404 BPoint(rect.left + 6, rect.top + 5), middleColor); 405 menu->EndLineArray(); 406 } else { 407 // expanded state 408 409 menu->BeginLineArray(6); 410 menu->AddLine(BPoint(rect.left + 1, rect.top + 3), 411 BPoint(rect.right - 3, rect.top + 3), outlineColor); 412 menu->AddLine(BPoint(rect.left + 1, rect.top + 3), 413 BPoint(rect.left + 5, rect.top + 7), outlineColor); 414 menu->AddLine(BPoint(rect.left + 5, rect.top + 7), 415 BPoint(rect.right - 3, rect.top + 3), outlineColor); 416 417 menu->AddLine(BPoint(rect.left + 3, rect.top + 4), 418 BPoint(rect.right - 5, rect.top + 4), middleColor); 419 menu->AddLine(BPoint(rect.left + 4, rect.top + 5), 420 BPoint(rect.right - 6, rect.top + 5), middleColor); 421 menu->AddLine(BPoint(rect.left + 5, rect.top + 5), 422 BPoint(rect.left + 5, rect.top + 6), middleColor); 423 menu->EndLineArray(); 424 } 425 } 426 } 427 } 428 429 430 void 431 TTeamMenuItem::DrawContentLabel() 432 { 433 BMenu *menu = Menu(); 434 menu->MovePenBy(0, fLabelAscent); 435 436 float cachedWidth = menu->StringWidth(Label()); 437 if (Submenu() && fVertical) 438 cachedWidth += 18; 439 440 const char *label = Label(); 441 char *truncLabel = NULL; 442 float max = 0; 443 if (static_cast<TBarApp *>(be_app)->Settings()->superExpando && fVertical) 444 max = menu->MaxContentWidth() - kSwitchWidth; 445 else 446 max = menu->MaxContentWidth(); 447 448 if (max > 0) { 449 BPoint penloc = menu->PenLocation(); 450 BRect frame = Frame(); 451 float offset = penloc.x - frame.left; 452 if (cachedWidth + offset > max) { 453 truncLabel = (char *)malloc(strlen(label) + 4); 454 if (!truncLabel) 455 return; 456 TruncateLabel(max-offset, truncLabel); 457 label = truncLabel; 458 } 459 } 460 461 if (!label) 462 label = Label(); 463 464 TBarView *barview = (static_cast<TBarApp *>(be_app))->BarView(); 465 bool canHandle = !barview->Dragging() 466 || barview->AppCanHandleTypes(Signature()); 467 if (_IsSelected() && IsEnabled() && canHandle) 468 menu->SetLowColor(tint_color(menu->ViewColor(), 469 B_HIGHLIGHT_BACKGROUND_TINT)); 470 else 471 menu->SetLowColor(menu->ViewColor()); 472 473 menu->DrawString(label); 474 475 free(truncLabel); 476 } 477 478 479 bool 480 TTeamMenuItem::IsExpanded() 481 { 482 return fExpanded; 483 } 484 485 486 void 487 TTeamMenuItem::ToggleExpandState(bool resizeWindow) 488 { 489 fExpanded = !fExpanded; 490 491 if (fExpanded) { 492 // Populate Menu() with the stuff from SubMenu(). 493 TWindowMenu *sub = (static_cast<TWindowMenu *>(Submenu())); 494 if (sub) { 495 // force the menu to update it's contents. 496 bool locked = sub->LockLooper(); 497 // if locking the looper failed, the menu is just not visible 498 sub->AttachedToWindow(); 499 if (locked) 500 sub->UnlockLooper(); 501 502 if (sub->CountItems() > 1){ 503 TExpandoMenuBar *parent = static_cast<TExpandoMenuBar *>(Menu()); 504 int myindex = parent->IndexOf(this) + 1; 505 506 TWindowMenuItem *windowItem = NULL; 507 int childIndex = 0; 508 int totalChildren = sub->CountItems() - 4; // hide, show, close, separator. 509 for (; childIndex < totalChildren; childIndex++) { 510 windowItem = static_cast<TWindowMenuItem *>(sub->RemoveItem((int32)0)); 511 parent->AddItem(windowItem, myindex + childIndex); 512 windowItem->ExpandedItem(true); 513 } 514 sub->SetExpanded(true, myindex + childIndex); 515 516 if (resizeWindow) 517 parent->SizeWindow(); 518 } else 519 fExpanded = fExpanded; 520 } 521 } else { 522 // Remove the goodies from the Menu() that should be in the SubMenu(); 523 TWindowMenu *sub = static_cast<TWindowMenu *>(Submenu()); 524 525 if (sub) { 526 TExpandoMenuBar *parent = static_cast<TExpandoMenuBar *>(Menu()); 527 528 TWindowMenuItem *windowItem = NULL; 529 int childIndex = parent->IndexOf(this) + 1; 530 while (!parent->SubmenuAt(childIndex) && childIndex < parent->CountItems()) { 531 windowItem = static_cast<TWindowMenuItem *>(parent->RemoveItem(childIndex)); 532 sub->AddItem(windowItem, 0); 533 windowItem->ExpandedItem(false); 534 } 535 sub->SetExpanded(false, 0); 536 537 if (resizeWindow) 538 parent->SizeWindow(); 539 } else 540 fExpanded = fExpanded; 541 } 542 } 543 544 545 TWindowMenuItem* 546 TTeamMenuItem::ExpandedWindowItem(int32 id) 547 { 548 if (!fExpanded) // Paranoia 549 return NULL; 550 551 TExpandoMenuBar *parent = static_cast<TExpandoMenuBar *>(Menu()); 552 int childIndex = parent->IndexOf(this) + 1; 553 554 while (!parent->SubmenuAt(childIndex) && childIndex < parent->CountItems()) { 555 TWindowMenuItem *item = static_cast<TWindowMenuItem *>(parent->ItemAt(childIndex)); 556 if (item->ID() == id) 557 return item; 558 559 childIndex++; 560 } 561 return NULL; 562 } 563 564 565 BRect 566 TTeamMenuItem::ExpanderBounds() const 567 { 568 BRect bounds(Frame()); 569 bounds.left = bounds.right - kSwitchWidth; 570 return bounds; 571 } 572 573 574 bool 575 TTeamMenuItem::_IsSelected() const 576 { 577 return IsSelected() || fOverriddenSelected; 578 } 579 580