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