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