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