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