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 rgb_color menuColor = tint_color(Menu()->ViewColor(), 1.07); 205 BRect frame(Frame()); 206 BMenu* menu = Menu(); 207 208 menu->PushState(); 209 210 // if not selected or being tracked on, fill with gray 211 TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView(); 212 if ((!IsSelected() && !menu->IsRedrawAfterSticky()) 213 || barview->Dragging() || !IsEnabled()) { 214 215 rgb_color shadow = tint_color(menuColor, 1.09); 216 menu->SetHighColor(shadow); 217 frame.right = frame.left + kHPad / 2; 218 menu->FillRect(frame); 219 220 menu->SetHighColor(menuColor); 221 frame.left = frame.right + 1; 222 frame.right = Frame().right; 223 menu->FillRect(frame); 224 } 225 226 if (IsEnabled() && IsSelected() && !menu->IsRedrawAfterSticky()) { 227 // fill 228 menu->SetHighColor(tint_color(menuColor, 229 B_HIGHLIGHT_BACKGROUND_TINT)); 230 menu->FillRect(frame); 231 } else 232 menu->SetLowColor(menuColor); 233 234 DrawContent(); 235 menu->PopState(); 236 } 237 238 239 void 240 TWindowMenuItem::DrawContent() 241 { 242 BMenu* menu = Menu(); 243 menu->PushState(); 244 245 BRect frame(Frame()); 246 BPoint contLoc = ContentLocation() + BPoint(kHPad, kVPad); 247 //if (fExpanded) 248 // contLoc.x += kHPad; 249 250 if (fID >= 0) { 251 menu->SetDrawingMode(B_OP_OVER); 252 253 float width = fBitmap->Bounds().Width(); 254 255 if (width > 16) 256 contLoc.x -= 8; 257 258 menu->MovePenTo(contLoc); 259 menu->DrawBitmapAsync(fBitmap); 260 261 if (width > 16) 262 contLoc.x += 8; 263 264 contLoc.x += kIconRect.Width() + kLabelOffset; 265 } 266 267 menu->SetDrawingMode(B_OP_COPY); 268 269 contLoc.y = frame.top 270 + ((frame.Height() - fTitleAscent - fTitleDescent) / 2) + 1.0f; 271 272 menu->MovePenTo(contLoc); 273 // Set the pen color so that the label is always visible. 274 menu->SetHighColor(0, 0, 0); 275 276 BMenuItem::DrawContent(); 277 278 menu->PopState(); 279 } 280 281 282 status_t 283 TWindowMenuItem::Invoke(BMessage* /*message*/) 284 { 285 if (!fDragging) { 286 if (fID >= 0) { 287 int32 action = (modifiers() & B_CONTROL_KEY) != 0 288 ? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT; 289 290 bool doZoom = false; 291 BRect zoomRect(0.0f, 0.0f, 0.0f, 0.0f); 292 BMenuItem* item; 293 if (!fExpanded) 294 item = Menu()->Superitem(); 295 else 296 item = this; 297 298 if (item->Menu()->Window() != NULL) { 299 zoomRect = item->Menu()->ConvertToScreen(item->Frame()); 300 doZoom = (fMini && action == B_BRING_TO_FRONT) 301 || (!fMini && action == B_MINIMIZE_WINDOW); 302 } 303 304 do_window_action(fID, action, zoomRect, doZoom); 305 } 306 } 307 return B_OK; 308 } 309 310 311 void 312 TWindowMenuItem::ExpandedItem(bool status) 313 { 314 if (fExpanded != status) { 315 fExpanded = status; 316 SetLabel(fFullTitle.String()); 317 } 318 } 319 320 321 void 322 TWindowMenuItem::SetRequireUpdate() 323 { 324 fRequireUpdate = true; 325 } 326 327 328 bool 329 TWindowMenuItem::RequiresUpdate() 330 { 331 return fRequireUpdate; 332 } 333