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