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