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