1 /* 2 * Copyright 2006-2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "LaunchButton.h" 10 11 #include <malloc.h> // string.h is not enough on Haiku?!? 12 #include <stdio.h> 13 #include <string.h> 14 15 #include <AppDefs.h> 16 #include <AppFileInfo.h> 17 #include <Bitmap.h> 18 #include <File.h> 19 #include <Node.h> 20 #include <NodeInfo.h> 21 #include <Region.h> 22 #include <Roster.h> 23 #include <Window.h> 24 25 //#include "BubbleHelper.h" 26 #include "PadView.h" 27 28 static const float kDragStartDist = 10.0; 29 static const float kDragBitmapAlphaScale = 0.6; 30 //static const char* kEmptyHelpString = "You can drag an icon here."; 31 32 bigtime_t 33 LaunchButton::fClickSpeed = 0; 34 35 // constructor 36 LaunchButton::LaunchButton(const char* name, uint32 id, const char* label, 37 BMessage* message, BHandler* target) 38 : IconButton(name, id, label, message, target), 39 fRef(NULL), 40 fAppSig(NULL), 41 fDescription(""), 42 fAnticipatingDrop(false), 43 fLastClickTime(0) 44 { 45 if (fClickSpeed == 0 || get_click_speed(&fClickSpeed) < B_OK) 46 fClickSpeed = 500000; 47 48 BSize size(32.0 + 8.0, 32.0 + 8.0); 49 SetExplicitMinSize(size); 50 SetExplicitMaxSize(size); 51 } 52 53 // destructor 54 LaunchButton::~LaunchButton() 55 { 56 delete fRef; 57 if (fAppSig) 58 free(fAppSig); 59 } 60 61 // AttachedToWindow 62 void 63 LaunchButton::AttachedToWindow() 64 { 65 IconButton::AttachedToWindow(); 66 _UpdateToolTip(); 67 } 68 69 // DetachedFromWindow 70 void 71 LaunchButton::DetachedFromWindow() 72 { 73 // BubbleHelper::Default()->SetHelp(this, NULL); 74 } 75 76 // Draw 77 void 78 LaunchButton::Draw(BRect updateRect) 79 { 80 if (fAnticipatingDrop) { 81 rgb_color color = fRef ? ui_color(B_KEYBOARD_NAVIGATION_COLOR) 82 : (rgb_color){ 0, 130, 60, 255 }; 83 SetHighColor(color); 84 // limit clipping region to exclude the blue rect we just drew 85 BRect r(Bounds()); 86 StrokeRect(r); 87 r.InsetBy(1.0, 1.0); 88 BRegion region(r); 89 ConstrainClippingRegion(®ion); 90 } 91 if (IsValid()) { 92 IconButton::Draw(updateRect); 93 } else { 94 rgb_color background = LowColor(); 95 rgb_color lightShadow = tint_color(background, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0); 96 rgb_color shadow = tint_color(background, B_DARKEN_1_TINT); 97 rgb_color light = tint_color(background, B_LIGHTEN_1_TINT); 98 BRect r(Bounds()); 99 _DrawFrame(r, shadow, light, lightShadow, lightShadow); 100 r.InsetBy(2.0, 2.0); 101 SetHighColor(lightShadow); 102 FillRect(r); 103 } 104 } 105 106 // MessageReceived 107 void 108 LaunchButton::MessageReceived(BMessage* message) 109 { 110 switch (message->what) { 111 case B_SIMPLE_DATA: 112 case B_REFS_RECEIVED: { 113 entry_ref ref; 114 if (message->FindRef("refs", &ref) >= B_OK) { 115 if (fRef) { 116 if (ref != *fRef) { 117 BEntry entry(fRef, true); 118 if (entry.IsDirectory()) { 119 message->PrintToStream(); 120 // copy stuff into the directory 121 } else { 122 message->what = B_REFS_RECEIVED; 123 team_id team; 124 if (fAppSig) 125 team = be_roster->TeamFor(fAppSig); 126 else 127 team = be_roster->TeamFor(fRef); 128 if (team < B_OK) { 129 if (fAppSig) 130 be_roster->Launch(fAppSig, message, &team); 131 else 132 be_roster->Launch(fRef, message, &team); 133 } else { 134 app_info appInfo; 135 if (team >= B_OK && be_roster->GetRunningAppInfo(team, &appInfo) >= B_OK) { 136 BMessenger messenger(appInfo.signature, team); 137 if (messenger.IsValid()) 138 messenger.SendMessage(message); 139 } 140 } 141 } 142 } 143 } else { 144 SetTo(&ref); 145 } 146 } 147 break; 148 } 149 case B_PASTE: 150 case B_MODIFIERS_CHANGED: 151 default: 152 IconButton::MessageReceived(message); 153 break; 154 } 155 } 156 157 // MouseDown 158 void 159 LaunchButton::MouseDown(BPoint where) 160 { 161 bigtime_t now = system_time(); 162 bool callInherited = true; 163 if (now - fLastClickTime < fClickSpeed) 164 callInherited = false; 165 fLastClickTime = now; 166 if (BMessage* message = Window()->CurrentMessage()) { 167 uint32 buttons; 168 message->FindInt32("buttons", (int32*)&buttons); 169 if (buttons & B_SECONDARY_MOUSE_BUTTON) { 170 if (PadView* parent = dynamic_cast<PadView*>(Parent())) { 171 parent->DisplayMenu(ConvertToParent(where), this); 172 _ClearFlags(STATE_INSIDE); 173 callInherited = false; 174 } 175 } else { 176 fDragStart = where; 177 } 178 } 179 if (callInherited) 180 IconButton::MouseDown(where); 181 } 182 183 // MouseUp 184 void 185 LaunchButton::MouseUp(BPoint where) 186 { 187 if (fAnticipatingDrop) { 188 fAnticipatingDrop = false; 189 Invalidate(); 190 } 191 IconButton::MouseUp(where); 192 } 193 194 // MouseMoved 195 void 196 LaunchButton::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 197 { 198 if ((dragMessage && (transit == B_ENTERED_VIEW || transit == B_INSIDE_VIEW)) 199 && ((dragMessage->what == B_SIMPLE_DATA 200 || dragMessage->what == B_REFS_RECEIVED) || fRef)) { 201 if (!fAnticipatingDrop) { 202 fAnticipatingDrop = true; 203 Invalidate(); 204 } 205 } 206 if (!dragMessage || (transit == B_EXITED_VIEW || transit == B_OUTSIDE_VIEW)) { 207 if (fAnticipatingDrop) { 208 fAnticipatingDrop = false; 209 Invalidate(); 210 } 211 } 212 // see if we should create a drag message 213 if (_HasFlags(STATE_TRACKING) && fRef) { 214 BPoint diff = where - fDragStart; 215 float dist = sqrtf(diff.x * diff.x + diff.y * diff.y); 216 if (dist >= kDragStartDist) { 217 // stop tracking 218 _ClearFlags(STATE_PRESSED | STATE_TRACKING | STATE_INSIDE); 219 // create drag bitmap and message 220 if (BBitmap* bitmap = Bitmap()) { 221 if (bitmap->ColorSpace() == B_RGB32) { 222 // make semitransparent 223 uint8* bits = (uint8*)bitmap->Bits(); 224 uint32 width = bitmap->Bounds().IntegerWidth() + 1; 225 uint32 height = bitmap->Bounds().IntegerHeight() + 1; 226 uint32 bpr = bitmap->BytesPerRow(); 227 for (uint32 y = 0; y < height; y++) { 228 uint8* bitsHandle = bits; 229 for (uint32 x = 0; x < width; x++) { 230 bitsHandle[3] = uint8(bitsHandle[3] * kDragBitmapAlphaScale); 231 bitsHandle += 4; 232 } 233 bits += bpr; 234 } 235 } 236 BMessage message(B_SIMPLE_DATA); 237 message.AddPointer("button", this); 238 message.AddRef("refs", fRef); 239 DragMessage(&message, bitmap, B_OP_ALPHA, fDragStart); 240 } 241 } 242 } 243 IconButton::MouseMoved(where, transit, dragMessage); 244 } 245 246 // SetTo 247 void 248 LaunchButton::SetTo(const entry_ref* ref) 249 { 250 free(fAppSig); 251 fAppSig = NULL; 252 253 delete fRef; 254 if (ref) { 255 fRef = new entry_ref(*ref); 256 // follow links 257 BEntry entry(fRef, true); 258 entry.GetRef(fRef); 259 260 _UpdateIcon(fRef); 261 // see if this is an application 262 BFile file(ref, B_READ_ONLY); 263 BAppFileInfo info; 264 if (info.SetTo(&file) >= B_OK) { 265 char mimeSig[B_MIME_TYPE_LENGTH]; 266 if (info.GetSignature(mimeSig) >= B_OK) { 267 SetTo(mimeSig, false); 268 } else { 269 fprintf(stderr, "no MIME signature for '%s'\n", fRef->name); 270 } 271 } else { 272 fprintf(stderr, "no BAppFileInfo for '%s'\n", fRef->name); 273 } 274 } else { 275 fRef = NULL; 276 ClearIcon(); 277 } 278 _UpdateToolTip(); 279 } 280 281 // Ref 282 entry_ref* 283 LaunchButton::Ref() const 284 { 285 return fRef; 286 } 287 288 // SetTo 289 void 290 LaunchButton::SetTo(const char* appSig, bool updateIcon) 291 { 292 if (appSig) { 293 if (fAppSig) 294 free(fAppSig); 295 fAppSig = strdup(appSig); 296 if (updateIcon) { 297 entry_ref ref; 298 if (be_roster->FindApp(fAppSig, &ref) >= B_OK) 299 SetTo(&ref); 300 } 301 } 302 _UpdateToolTip(); 303 } 304 305 // SetDesciption 306 void 307 LaunchButton::SetDescription(const char* text) 308 { 309 fDescription.SetTo(text); 310 _UpdateToolTip(); 311 } 312 313 // _UpdateToolTip 314 void 315 LaunchButton::_UpdateToolTip() 316 { 317 if (fRef) { 318 BString helper(fRef->name); 319 if (fDescription.CountChars() > 0) { 320 helper << "\n\n" << fDescription.String(); 321 } else { 322 BFile file(fRef, B_READ_ONLY); 323 BAppFileInfo appFileInfo; 324 version_info info; 325 if (appFileInfo.SetTo(&file) >= B_OK 326 && appFileInfo.GetVersionInfo(&info, 327 B_APP_VERSION_KIND) >= B_OK 328 && strlen(info.short_info) > 0) { 329 helper << "\n\n" << info.short_info; 330 } 331 } 332 // BubbleHelper::Default()->SetHelp(this, helper.String()); 333 } else { 334 // BubbleHelper::Default()->SetHelp(this, kEmptyHelpString); 335 } 336 } 337 338 // _UpdateIcon 339 void 340 LaunchButton::_UpdateIcon(const entry_ref* ref) 341 { 342 BBitmap* icon = new BBitmap(BRect(0.0, 0.0, 31.0, 31.0), B_RGBA32); 343 if (BNodeInfo::GetTrackerIcon(ref, icon, B_LARGE_ICON) >= B_OK) 344 SetIcon(icon); 345 346 delete icon; 347 } 348