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 trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 // menu items with small icons. 36 37 #include "IconCache.h" 38 #include "IconMenuItem.h" 39 40 #include <Debug.h> 41 #include <Menu.h> 42 #include <NodeInfo.h> 43 44 45 static void 46 DimmedIconBlitter(BView* view, BPoint where, BBitmap* bitmap, void*) 47 { 48 if (bitmap->ColorSpace() == B_RGBA32) { 49 rgb_color oldHighColor = view->HighColor(); 50 view->SetHighColor(0, 0, 0, 128); 51 view->SetDrawingMode(B_OP_ALPHA); 52 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 53 view->DrawBitmap(bitmap, where); 54 view->SetHighColor(oldHighColor); 55 } else { 56 view->SetDrawingMode(B_OP_BLEND); 57 view->DrawBitmap(bitmap, where); 58 } 59 view->SetDrawingMode(B_OP_OVER); 60 } 61 62 63 // #pragma mark - ModelMenuItem 64 65 66 ModelMenuItem::ModelMenuItem(const Model* model, const char* title, 67 BMessage* message, char shortcut, uint32 modifiers, 68 bool drawText, bool extraPad) 69 : 70 BMenuItem(title, message, shortcut, modifiers), 71 fModel(*model), 72 fHeightDelta(0), 73 fDrawText(drawText), 74 fExtraPad(extraPad) 75 { 76 ThrowOnInitCheckError(&fModel); 77 // The 'fExtraPad' field is used to when this menu item is added to 78 // a menubar instead of a menu. Menus and MenuBars space out items 79 // differently (more space around items in a menu). This class wants 80 // to be able to space item the same, no matter where they are. The 81 // fExtraPad field allows for that. 82 83 if (model->IsRoot()) 84 SetLabel(model->Name()); 85 86 // ModelMenuItem is used in synchronously invoked menus, make sure 87 // we invoke with a timeout 88 SetTimeout(kSynchMenuInvokeTimeout); 89 } 90 91 92 ModelMenuItem::ModelMenuItem(const Model* model, BMenu* menu, bool drawText, 93 bool extraPad) 94 : 95 BMenuItem(menu), 96 fModel(*model), 97 fHeightDelta(0), 98 fDrawText(drawText), 99 fExtraPad(extraPad) 100 { 101 ThrowOnInitCheckError(&fModel); 102 // ModelMenuItem is used in synchronously invoked menus, make sure 103 // we invoke with a timeout 104 SetTimeout(kSynchMenuInvokeTimeout); 105 } 106 107 108 ModelMenuItem::~ModelMenuItem() 109 { 110 } 111 112 113 status_t 114 ModelMenuItem::SetEntry(const BEntry* entry) 115 { 116 return fModel.SetTo(entry); 117 } 118 119 120 void 121 ModelMenuItem::DrawContent() 122 { 123 if (fDrawText) { 124 BPoint drawPoint(ContentLocation()); 125 drawPoint.x += 20 + (fExtraPad ? 6 : 0); 126 if (fHeightDelta > 0) 127 drawPoint.y += ceil(fHeightDelta / 2); 128 Menu()->MovePenTo(drawPoint); 129 _inherited::DrawContent(); 130 } 131 DrawIcon(); 132 } 133 134 135 void 136 ModelMenuItem::Highlight(bool hilited) 137 { 138 _inherited::Highlight(hilited); 139 DrawIcon(); 140 } 141 142 143 void 144 ModelMenuItem::DrawIcon() 145 { 146 Menu()->PushState(); 147 148 BPoint where(ContentLocation()); 149 // center icon with text. 150 151 float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0; 152 where.y += ceil(deltaHeight / 2); 153 154 if (fExtraPad) 155 where.x += 6; 156 157 Menu()->SetDrawingMode(B_OP_OVER); 158 Menu()->SetLowColor(B_TRANSPARENT_32_BIT); 159 160 // draw small icon, synchronously 161 if (IsEnabled()) { 162 IconCache::sIconCache->Draw(fModel.ResolveIfLink(), Menu(), where, 163 kNormalIcon, B_MINI_ICON); 164 } else { 165 // dimmed, for now use a special blitter; icon cache should 166 // know how to blit one eventually 167 IconCache::sIconCache->SyncDraw(fModel.ResolveIfLink(), Menu(), where, 168 kNormalIcon, B_MINI_ICON, DimmedIconBlitter); 169 } 170 171 Menu()->PopState(); 172 } 173 174 175 void 176 ModelMenuItem::GetContentSize(float* width, float* height) 177 { 178 _inherited::GetContentSize(width, height); 179 fHeightDelta = 16 - *height; 180 if (*height < 16) 181 *height = 16; 182 *width = *width + 20 + (fExtraPad ? 18 : 0); 183 } 184 185 186 status_t 187 ModelMenuItem::Invoke(BMessage* message) 188 { 189 if (Menu() == NULL) 190 return B_ERROR; 191 192 if (!IsEnabled()) 193 return B_ERROR; 194 195 if (message == NULL) 196 message = Message(); 197 198 if (message == NULL) 199 return B_BAD_VALUE; 200 201 BMessage clone(*message); 202 clone.AddInt32("index", Menu()->IndexOf(this)); 203 clone.AddInt64("when", system_time()); 204 clone.AddPointer("source", this); 205 206 if ((modifiers() & B_OPTION_KEY) == 0) { 207 // if option not held, remove refs to close to prevent closing 208 // parent window 209 clone.RemoveData("nodeRefsToClose"); 210 } 211 212 return BInvoker::Invoke(&clone); 213 } 214 215 216 // #pragma mark - SpecialModelMenuItem 217 218 219 /*! 220 A ModelMenuItem subclass that draws its label in italics. 221 It's used for example in the "Copy To" menu to indicate some special 222 folders like the parent folder. 223 */ 224 SpecialModelMenuItem::SpecialModelMenuItem(const Model* model, BMenu* menu) 225 : ModelMenuItem(model, menu) 226 { 227 } 228 229 230 void 231 SpecialModelMenuItem::DrawContent() 232 { 233 Menu()->PushState(); 234 235 BFont font; 236 Menu()->GetFont(&font); 237 font.SetFace(B_ITALIC_FACE); 238 Menu()->SetFont(&font); 239 240 _inherited::DrawContent(); 241 Menu()->PopState(); 242 } 243 244 245 // #pragma mark - IconMenuItem 246 247 248 /*! 249 A menu item that draws an icon alongside the label. 250 It's currently used in the mount and new file template menus. 251 */ 252 IconMenuItem::IconMenuItem(const char* label, BMessage* message, BBitmap* icon) 253 : 254 PositionPassingMenuItem(label, message), 255 fDeviceIcon(icon), 256 fHeightDelta(0) 257 { 258 // IconMenuItem is used in synchronously invoked menus, make sure 259 // we invoke with a timeout 260 SetTimeout(kSynchMenuInvokeTimeout); 261 } 262 263 264 IconMenuItem::IconMenuItem(const char* label, BMessage* message, 265 const BNodeInfo* nodeInfo, icon_size which) 266 : 267 PositionPassingMenuItem(label, message), 268 fDeviceIcon(NULL), 269 fHeightDelta(0) 270 { 271 if (nodeInfo) { 272 #ifdef __HAIKU__ 273 fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_RGBA32); 274 #else 275 fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8); 276 #endif 277 278 if (nodeInfo->GetTrackerIcon(fDeviceIcon, B_MINI_ICON)) { 279 delete fDeviceIcon; 280 fDeviceIcon = NULL; 281 } 282 } 283 284 // IconMenuItem is used in synchronously invoked menus, make sure 285 // we invoke with a timeout 286 SetTimeout(kSynchMenuInvokeTimeout); 287 } 288 289 290 IconMenuItem::IconMenuItem(const char* label, BMessage* message, 291 const char* iconType, icon_size which) 292 : 293 PositionPassingMenuItem(label, message), 294 fDeviceIcon(NULL), 295 fHeightDelta(0) 296 { 297 BMimeType mime(iconType); 298 #ifdef __HAIKU__ 299 fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_RGBA32); 300 #else 301 fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8); 302 #endif 303 304 if (mime.GetIcon(fDeviceIcon, which) != B_OK) { 305 BMimeType super; 306 mime.GetSupertype(&super); 307 if (super.GetIcon(fDeviceIcon, which) != B_OK) { 308 delete fDeviceIcon; 309 fDeviceIcon = NULL; 310 } 311 } 312 313 // IconMenuItem is used in synchronously invoked menus, make sure 314 // we invoke with a timeout 315 SetTimeout(kSynchMenuInvokeTimeout); 316 } 317 318 319 IconMenuItem::IconMenuItem(BMenu* submenu, BMessage* message, 320 const char* iconType, icon_size which) 321 : 322 PositionPassingMenuItem(submenu, message), 323 fDeviceIcon(NULL), 324 fHeightDelta(0) 325 { 326 BMimeType mime(iconType); 327 #ifdef __HAIKU__ 328 fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_RGBA32); 329 #else 330 fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8); 331 #endif 332 333 if (mime.GetIcon(fDeviceIcon, which) != B_OK) { 334 BMimeType super; 335 mime.GetSupertype(&super); 336 if (super.GetIcon(fDeviceIcon, which) != B_OK) { 337 delete fDeviceIcon; 338 fDeviceIcon = NULL; 339 } 340 } 341 342 // IconMenuItem is used in synchronously invoked menus, make sure 343 // we invoke with a timeout 344 SetTimeout(kSynchMenuInvokeTimeout); 345 } 346 347 348 IconMenuItem::~IconMenuItem() 349 { 350 delete fDeviceIcon; 351 } 352 353 354 void 355 IconMenuItem::GetContentSize(float* width, float* height) 356 { 357 _inherited::GetContentSize(width, height); 358 359 fHeightDelta = 16 - *height; 360 if (*height < 16) 361 *height = 16; 362 363 *width += 20; 364 } 365 366 367 void 368 IconMenuItem::DrawContent() 369 { 370 BPoint drawPoint(ContentLocation()); 371 drawPoint.x += 20; 372 if (fHeightDelta > 0) 373 drawPoint.y += ceil(fHeightDelta / 2); 374 Menu()->MovePenTo(drawPoint); 375 _inherited::DrawContent(); 376 377 Menu()->PushState(); 378 379 BPoint where(ContentLocation()); 380 float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0; 381 where.y += ceil(deltaHeight / 2); 382 383 if (fDeviceIcon) { 384 if (IsEnabled()) 385 #ifdef __HAIKU__ 386 Menu()->SetDrawingMode(B_OP_ALPHA); 387 else { 388 Menu()->SetDrawingMode(B_OP_ALPHA); 389 Menu()->SetHighColor(0, 0, 0, 64); 390 Menu()->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 391 } 392 #else 393 Menu()->SetDrawingMode(B_OP_OVER); 394 else 395 Menu()->SetDrawingMode(B_OP_BLEND); 396 #endif 397 Menu()->DrawBitmapAsync(fDeviceIcon, where); 398 } 399 400 Menu()->PopState(); 401 } 402