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 "WindowMenuItem.h" 38 39 #include <stdio.h> 40 41 #include <Bitmap.h> 42 #include <Debug.h> 43 #include <NaturalCompare.h> 44 45 #include "BarApp.h" 46 #include "BarMenuBar.h" 47 #include "BarView.h" 48 #include "ExpandoMenuBar.h" 49 #include "icons.h" 50 #include "ResourceSet.h" 51 #include "TeamMenu.h" 52 #include "WindowMenu.h" 53 54 55 const float kHPad = 10.0f; 56 const float kVPad = 2.0f; 57 const float kLabelOffset = 8.0f; 58 const BRect kIconRect(1.0f, 1.0f, 13.0f, 14.0f); 59 60 61 TWindowMenuItem::TWindowMenuItem(const char* title, int32 id, bool mini, 62 bool currentWorkspace, bool dragging) 63 : 64 BMenuItem(title, NULL), 65 fID(id), 66 fMini(mini), 67 fCurrentWorkSpace(currentWorkspace), 68 fDragging(dragging), 69 fExpanded(false), 70 fRequireUpdate(false), 71 fModified(false), 72 fFullTitle("") 73 { 74 Initialize(title); 75 } 76 77 78 void 79 TWindowMenuItem::Initialize(const char* title) 80 { 81 if (fMini) { 82 fBitmap = fCurrentWorkSpace 83 ? AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowHiddenIcon) 84 : AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowHiddenSwitchIcon); 85 } else { 86 fBitmap = fCurrentWorkSpace 87 ? AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowShownIcon) 88 : AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowShownSwitchIcon); 89 } 90 91 BFont font(be_plain_font); 92 fTitleWidth = ceilf(font.StringWidth(title)); 93 fFullTitle = title; 94 font_height fontHeight; 95 font.GetHeight(&fontHeight); 96 fTitleAscent = ceilf(fontHeight.ascent); 97 fTitleDescent = ceilf(fontHeight.descent + fontHeight.leading); 98 } 99 100 101 void 102 TWindowMenuItem::SetTo(const char* title, int32 id, bool mini, 103 bool currentWorkspace, bool dragging) 104 { 105 fModified = fCurrentWorkSpace != currentWorkspace || fMini != mini; 106 107 fID = id; 108 fMini = mini; 109 fCurrentWorkSpace = currentWorkspace; 110 fDragging = dragging; 111 fRequireUpdate = false; 112 113 Initialize(title); 114 } 115 116 117 bool 118 TWindowMenuItem::ChangedState() 119 { 120 return fModified; 121 } 122 123 124 void 125 TWindowMenuItem::SetLabel(const char* string) 126 { 127 fFullTitle = string; 128 BString truncatedTitle = fFullTitle; 129 130 if (fExpanded && Menu()) { 131 BPoint contLoc = ContentLocation() + BPoint(kHPad, kVPad); 132 contLoc.x += kIconRect.Width() + kLabelOffset; 133 134 be_plain_font->TruncateString(&truncatedTitle, B_TRUNCATE_MIDDLE, 135 Frame().Width() - contLoc.x - 3.0f); 136 } 137 138 if (strcmp(Label(), truncatedTitle.String()) != 0) 139 BMenuItem::SetLabel(truncatedTitle.String()); 140 } 141 142 143 const char* 144 TWindowMenuItem::FullTitle() const 145 { 146 return fFullTitle.String(); 147 } 148 149 150 /*static*/ int32 151 TWindowMenuItem::InsertIndexFor(BMenu* menu, int32 startIndex, 152 TWindowMenuItem* newItem) 153 { 154 for (int32 index = startIndex;; index++) { 155 TWindowMenuItem* item 156 = dynamic_cast<TWindowMenuItem*>(menu->ItemAt(index)); 157 if (item == NULL || NaturalCompare(item->FullTitle(), 158 newItem->FullTitle()) > 0) 159 return index; 160 } 161 } 162 163 164 int32 165 TWindowMenuItem::ID() 166 { 167 return fID; 168 } 169 170 171 void 172 TWindowMenuItem::GetContentSize(float* width, float* height) 173 { 174 if (width != NULL) { 175 if (!fExpanded) { 176 *width = kHPad + fTitleWidth + kHPad; 177 if (fID >= 0) 178 *width += fBitmap->Bounds().Width() + kLabelOffset; 179 } else 180 *width = Frame().Width()/* - kHPad*/; 181 } 182 183 // Note: when the item is in "expanded mode", ie embedded into 184 // the Deskbar itself, then a truncated label is used in SetLabel() 185 // The code here is ignorant of this fact, but it doesn't seem to 186 // hurt anything. 187 188 if (height != NULL) { 189 *height = (fID >= 0) ? fBitmap->Bounds().Height() : 0.0f; 190 float labelHeight = fTitleAscent + fTitleDescent; 191 *height = (labelHeight > *height) ? labelHeight : *height; 192 *height += kVPad * 2; 193 } 194 } 195 196 197 void 198 TWindowMenuItem::Draw() 199 { 200 if (!fExpanded) { 201 BMenuItem::Draw(); 202 return; 203 } 204 205 // TODO: Tint this smartly based on the low color, this does 206 // nothing to black. 207 rgb_color menuColor = tint_color(Menu()->LowColor(), 1.07); 208 BRect frame(Frame()); 209 BMenu* menu = Menu(); 210 211 menu->PushState(); 212 213 // if not selected or being tracked on, fill with gray 214 TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView(); 215 if ((!IsSelected() && !menu->IsRedrawAfterSticky()) 216 || barview->Dragging() || !IsEnabled()) { 217 218 rgb_color shadow = tint_color(menuColor, 1.09); 219 menu->SetHighColor(shadow); 220 frame.right = frame.left + kHPad / 2; 221 menu->FillRect(frame); 222 223 menu->SetHighColor(menuColor); 224 frame.left = frame.right + 1; 225 frame.right = Frame().right; 226 menu->FillRect(frame); 227 } 228 229 if (IsEnabled() && IsSelected() && !menu->IsRedrawAfterSticky()) { 230 // fill 231 menu->SetHighColor(tint_color(menuColor, 232 B_HIGHLIGHT_BACKGROUND_TINT)); 233 menu->FillRect(frame); 234 } else 235 menu->SetLowColor(menuColor); 236 237 DrawContent(); 238 menu->PopState(); 239 } 240 241 242 void 243 TWindowMenuItem::DrawContent() 244 { 245 BMenu* menu = Menu(); 246 menu->PushState(); 247 248 BRect frame(Frame()); 249 BPoint contLoc = ContentLocation() + BPoint(kHPad, kVPad); 250 //if (fExpanded) 251 // contLoc.x += kHPad; 252 253 if (fID >= 0) { 254 menu->SetDrawingMode(B_OP_OVER); 255 256 float width = fBitmap->Bounds().Width(); 257 258 if (width > 16) 259 contLoc.x -= 8; 260 261 menu->MovePenTo(contLoc); 262 menu->DrawBitmapAsync(fBitmap); 263 264 if (width > 16) 265 contLoc.x += 8; 266 267 contLoc.x += kIconRect.Width() + kLabelOffset; 268 } 269 270 menu->SetDrawingMode(B_OP_COPY); 271 272 contLoc.y = frame.top 273 + ((frame.Height() - fTitleAscent - fTitleDescent) / 2) + 1.0f; 274 275 menu->MovePenTo(contLoc); 276 277 if (IsSelected()) 278 menu->SetHighColor(ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR)); 279 else 280 menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR)); 281 282 BMenuItem::DrawContent(); 283 284 menu->PopState(); 285 } 286 287 288 status_t 289 TWindowMenuItem::Invoke(BMessage* /*message*/) 290 { 291 if (!fDragging) { 292 if (fID >= 0) { 293 int32 action = (modifiers() & B_CONTROL_KEY) != 0 294 ? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT; 295 296 bool doZoom = false; 297 BRect zoomRect(0.0f, 0.0f, 0.0f, 0.0f); 298 BMenuItem* item; 299 if (!fExpanded) 300 item = Menu()->Superitem(); 301 else 302 item = this; 303 304 if (item->Menu()->Window() != NULL) { 305 zoomRect = item->Menu()->ConvertToScreen(item->Frame()); 306 doZoom = (fMini && action == B_BRING_TO_FRONT) 307 || (!fMini && action == B_MINIMIZE_WINDOW); 308 } 309 310 do_window_action(fID, action, zoomRect, doZoom); 311 } 312 } 313 return B_OK; 314 } 315 316 317 void 318 TWindowMenuItem::ExpandedItem(bool status) 319 { 320 if (fExpanded != status) { 321 fExpanded = status; 322 SetLabel(fFullTitle.String()); 323 } 324 } 325 326 327 void 328 TWindowMenuItem::SetRequireUpdate() 329 { 330 fRequireUpdate = true; 331 } 332 333 334 bool 335 TWindowMenuItem::RequiresUpdate() 336 { 337 return fRequireUpdate; 338 } 339