1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2004, Haiku 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Dragger.cpp 23 // Author: Marc Flerackers (mflerackers@androme.be) 24 // Description: BDragger represents a replicant "handle". 25 //------------------------------------------------------------------------------ 26 #include <Alert.h> 27 #include <Beep.h> 28 #include <Bitmap.h> 29 #include <Dragger.h> 30 #include <MenuItem.h> 31 #include <Message.h> 32 #include <PopUpMenu.h> 33 #include <Shelf.h> 34 #include <Window.h> 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 39 #include <ViewAux.h> 40 41 bool BDragger::sVisible; 42 bool BDragger::sInited; 43 BLocker BDragger::sLock("BDragger_sLock"); 44 BList BDragger::sList; 45 46 const static rgb_color kZombieColor = {220, 220, 220, 255}; 47 48 const unsigned char 49 kHandBitmap[] = { 50 255, 255, 0, 0, 0, 255, 255, 255, 51 255, 255, 0, 131, 131, 0, 255, 255, 52 0, 0, 0, 0, 131, 131, 0, 0, 53 0, 131, 0, 0, 131, 131, 0, 0, 54 0, 131, 131, 131, 131, 131, 0, 0, 55 255, 0, 131, 131, 131, 131, 0, 0, 56 255, 255, 0, 0, 0, 0, 0, 0, 57 255, 255, 255, 255, 255, 255, 0, 0 58 }; 59 60 61 BDragger::BDragger(BRect bounds, BView *target, uint32 rmask, uint32 flags) 62 : BView(bounds, "_dragger_", rmask, flags), 63 fTarget(target), 64 fRelation(TARGET_UNKNOWN), 65 fShelf(NULL), 66 fTransition(false), 67 fIsZombie(false), 68 fErrCount(0), 69 fPopUp(NULL) 70 { 71 fBitmap = new BBitmap(BRect(0.0f, 0.0f, 7.0f, 7.0f), B_CMAP8, false, false); 72 fBitmap->SetBits(kHandBitmap, fBitmap->BitsLength(), 0, B_CMAP8); 73 } 74 75 76 BDragger::BDragger(BMessage *data) 77 : BView(data), 78 fTarget(NULL), 79 fRelation(TARGET_UNKNOWN), 80 fShelf(NULL), 81 fTransition(false), 82 fIsZombie(false), 83 fErrCount(0), 84 fPopUp(NULL) 85 { 86 data->FindInt32("_rel", (int32 *)&fRelation); 87 88 fBitmap = new BBitmap(BRect(0.0f, 0.0f, 7.0f, 7.0f), B_CMAP8, false, false); 89 fBitmap->SetBits(kHandBitmap, fBitmap->BitsLength(), 0, B_CMAP8); 90 91 BMessage popupMsg; 92 93 if (data->FindMessage("_popup", &popupMsg) == B_OK) { 94 BArchivable *archivable = instantiate_object(&popupMsg); 95 96 if (archivable) 97 fPopUp = dynamic_cast<BPopUpMenu *>(archivable); 98 } 99 } 100 101 102 BDragger::~BDragger() 103 { 104 SetPopUp(NULL); 105 106 delete fBitmap; 107 } 108 109 110 BArchivable * 111 BDragger::Instantiate(BMessage *data) 112 { 113 if (validate_instantiation(data, "BDragger")) 114 return new BDragger(data); 115 else 116 return NULL; 117 } 118 119 120 status_t 121 BDragger::Archive(BMessage *data, bool deep) const 122 { 123 BMessage popupMsg; 124 125 if (fPopUp) { 126 fPopUp->Archive(&popupMsg); 127 data->AddMessage("_popup", &popupMsg); 128 } 129 130 data->AddInt32("_rel", fRelation); 131 132 return BView::Archive(data, deep); 133 } 134 135 136 void 137 BDragger::AttachedToWindow() 138 { 139 if (fIsZombie) { 140 SetLowColor(kZombieColor); 141 SetViewColor(kZombieColor); 142 143 } else { 144 SetLowColor(B_TRANSPARENT_COLOR); 145 SetViewColor(B_TRANSPARENT_COLOR); 146 } 147 148 determine_relationship(); 149 ListManage(true); 150 } 151 152 153 void 154 BDragger::DetachedFromWindow() 155 { 156 ListManage(false); 157 } 158 159 160 void 161 BDragger::Draw(BRect update) 162 { 163 BRect bounds(Bounds()); 164 165 if (AreDraggersDrawn() && (!fShelf || fShelf->AllowsDragging())) { 166 SetDrawingMode(B_OP_OVER); 167 DrawBitmap(fBitmap, bounds.LeftTop()); 168 SetDrawingMode(B_OP_COPY); 169 170 if (fIsZombie) { 171 // TODO: should draw it differently ? 172 } 173 } else if (IsVisibilityChanging()) { 174 if (Parent()) 175 Parent()->Invalidate(Frame()); 176 177 else { 178 SetHighColor(255, 255, 255); 179 FillRect(bounds); 180 } 181 } 182 } 183 184 185 void 186 BDragger::MouseDown(BPoint where) 187 { 188 if (!fTarget || !AreDraggersDrawn()) 189 return; 190 191 int32 buttons; 192 193 Window()->CurrentMessage()->FindInt32("buttons", &buttons); 194 195 if (buttons & B_SECONDARY_MOUSE_BUTTON) { 196 if (!fShelf || !fTarget) { 197 beep(); 198 return; 199 } 200 201 ShowPopUp(fTarget, where); 202 203 } else { 204 // TODO code to determine drag or menu 205 /*bigtime_t time = system_time(); 206 bigtime_t click_speed = 0; 207 208 get_click_speed(&click_speed);*/ 209 210 bool drag = false; 211 212 while (true) { 213 BPoint mousePoint; 214 uint32 buttons; 215 216 GetMouse(&mousePoint, &buttons); 217 218 if (!buttons) 219 break; 220 221 if (mousePoint != where) { 222 drag = true; 223 break; 224 } 225 226 snooze(40000); 227 } 228 229 if (drag) { 230 BMessage archive(B_ARCHIVED_OBJECT); 231 232 if (fRelation == TARGET_IS_PARENT) 233 fTarget->Archive(&archive); 234 else if (fRelation == TARGET_IS_CHILD) 235 Archive(&archive); 236 else { 237 if (fTarget->Archive(&archive)) { 238 BMessage widget(B_ARCHIVED_OBJECT); 239 240 if (Archive(&widget)) 241 archive.AddMessage("__widget", &widget); 242 } 243 } 244 245 archive.AddInt32("be:actions", B_TRASH_TARGET); 246 247 BPoint offset; 248 drawing_mode mode; 249 BBitmap *bitmap = DragBitmap(&offset, &mode); 250 if (bitmap) 251 DragMessage(&archive, bitmap, mode, offset, this); 252 else 253 DragMessage(&archive, 254 ConvertFromScreen(fTarget->ConvertToScreen(fTarget->Bounds())), 255 this); 256 } else 257 ShowPopUp(fTarget, where); 258 } 259 } 260 261 262 void 263 BDragger::MouseUp(BPoint point) 264 { 265 BView::MouseUp(point); 266 } 267 268 269 void 270 BDragger::MouseMoved(BPoint point, uint32 code, const BMessage *msg) 271 { 272 BView::MouseMoved(point, code, msg); 273 } 274 275 276 void 277 BDragger::MessageReceived(BMessage *msg) 278 { 279 if (msg->what == B_TRASH_TARGET) { 280 if (fShelf) 281 Window()->PostMessage(kDeleteDragger, fTarget, NULL); 282 else 283 (new BAlert("??", 284 "Can't delete this replicant from its original application. Life goes on.", 285 "OK", NULL, NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT))->Go(NULL); 286 287 } else if (msg->what == B_SCREEN_CHANGED) { 288 if (fRelation == TARGET_IS_CHILD) { 289 fTransition = true; 290 Draw(BRect()); 291 fTransition = false; 292 293 } else { 294 if ((fShelf && (fShelf->AllowsDragging() && AreDraggersDrawn())) 295 || AreDraggersDrawn()) 296 Show(); 297 else 298 Hide(); 299 } 300 } else 301 BView::MessageReceived(msg); 302 } 303 304 305 void 306 BDragger::FrameMoved(BPoint newPosition) 307 { 308 BView::FrameMoved(newPosition); 309 } 310 311 312 void 313 BDragger::FrameResized(float newWidth, float newHeight) 314 { 315 BView::FrameResized(newWidth, newHeight); 316 } 317 318 319 status_t 320 BDragger::ShowAllDraggers() 321 { 322 // TODO: Implement. Should ask the registrar or the app server 323 return B_OK; 324 } 325 326 327 status_t 328 BDragger::HideAllDraggers() 329 { 330 // TODO: Implement. Should ask the registrar or the app server 331 return B_OK; 332 } 333 334 335 bool 336 BDragger::AreDraggersDrawn() 337 { 338 // TODO: Implement. Should ask the registrar or the app server 339 return true; 340 } 341 342 343 BHandler *BDragger::ResolveSpecifier(BMessage *msg, int32 index, 344 BMessage *specifier, int32 form, 345 const char *property) 346 { 347 return BView::ResolveSpecifier(msg, index, specifier, form, property); 348 } 349 350 351 status_t 352 BDragger::GetSupportedSuites(BMessage *data) 353 { 354 return BView::GetSupportedSuites(data); 355 } 356 357 358 status_t 359 BDragger::Perform(perform_code d, void *arg) 360 { 361 return BView::Perform(d, arg); 362 } 363 364 365 void 366 BDragger::ResizeToPreferred() 367 { 368 BView::ResizeToPreferred(); 369 } 370 371 372 void 373 BDragger::GetPreferredSize(float *width, float *height) 374 { 375 BView::GetPreferredSize(width, height); 376 } 377 378 379 void 380 BDragger::MakeFocus(bool state) 381 { 382 BView::MakeFocus(state); 383 } 384 385 386 void 387 BDragger::AllAttached() 388 { 389 BView::AllAttached(); 390 } 391 392 393 void 394 BDragger::AllDetached() 395 { 396 BView::AllDetached(); 397 } 398 399 400 status_t 401 BDragger::SetPopUp(BPopUpMenu *context_menu) 402 { 403 if (fPopUp && fPopUp != context_menu) 404 delete fPopUp; 405 406 fPopUp = context_menu; 407 return B_OK; 408 } 409 410 411 BPopUpMenu * 412 BDragger::PopUp() const 413 { 414 if (!fPopUp && fTarget) 415 const_cast<BDragger *>(this)->BuildDefaultPopUp(); 416 417 return fPopUp; 418 } 419 420 421 bool 422 BDragger::InShelf() const 423 { 424 return fShelf != NULL; 425 } 426 427 428 BView * 429 BDragger::Target() const 430 { 431 return fTarget; 432 } 433 434 435 BBitmap * 436 BDragger::DragBitmap(BPoint *offset, drawing_mode *mode) 437 { 438 return NULL; 439 } 440 441 442 bool 443 BDragger::IsVisibilityChanging() const 444 { 445 return fTransition; 446 } 447 448 449 void BDragger::_ReservedDragger2() {} 450 void BDragger::_ReservedDragger3() {} 451 void BDragger::_ReservedDragger4() {} 452 453 454 BDragger & 455 BDragger::operator=(const BDragger &) 456 { 457 return *this; 458 } 459 460 461 void 462 BDragger::ListManage(bool add) 463 { 464 if (sLock.Lock()) { 465 bool drawn = AreDraggersDrawn(); 466 467 if (add) { 468 bool dragging = true; 469 470 sList.AddItem(this); 471 472 if (fShelf) 473 dragging = fShelf->AllowsDragging(); 474 475 if (!drawn && !dragging) { 476 if (fRelation != TARGET_IS_CHILD) 477 Hide(); 478 } 479 } else 480 sList.RemoveItem(this); 481 482 sLock.Unlock(); 483 } 484 } 485 486 487 status_t 488 BDragger::determine_relationship() 489 { 490 status_t err = B_OK; 491 492 if (fTarget) { 493 if (fTarget == Parent()) 494 fRelation = TARGET_IS_PARENT; 495 else if (fTarget == ChildAt(0)) 496 fRelation = TARGET_IS_CHILD; 497 else 498 fRelation = TARGET_IS_SIBLING; 499 } else { 500 if (fRelation == TARGET_IS_PARENT) 501 fTarget = Parent(); 502 else if (fRelation == TARGET_IS_CHILD) 503 fTarget = ChildAt(0); 504 else 505 err = B_ERROR; 506 } 507 508 return err; 509 } 510 511 512 status_t 513 BDragger::SetViewToDrag(BView *target) 514 { 515 if (target->Window() != Window()) 516 return B_ERROR; 517 518 fTarget = target; 519 520 if (Window()) 521 determine_relationship(); 522 523 return B_OK; 524 } 525 526 527 void 528 BDragger::SetShelf(BShelf *shelf) 529 { 530 fShelf = shelf; 531 } 532 533 534 void 535 BDragger::SetZombied(bool state) 536 { 537 fIsZombie = state; 538 539 SetLowColor(kZombieColor); 540 SetViewColor(kZombieColor); 541 } 542 543 544 void 545 BDragger::BuildDefaultPopUp() 546 { 547 fPopUp = new BPopUpMenu("Shelf", false, false, B_ITEMS_IN_COLUMN); 548 549 // About 550 BMessage *msg = new BMessage(B_ABOUT_REQUESTED); 551 552 const char *name = fTarget->Name(); 553 554 if (name) 555 msg->AddString("target", name); 556 557 char about[B_OS_NAME_LENGTH]; 558 snprintf(about, B_OS_NAME_LENGTH, "About %s", name); 559 560 fPopUp->AddItem(new BMenuItem(about, msg)); 561 562 // Separator 563 fPopUp->AddItem(new BSeparatorItem()); 564 565 // Delete 566 fPopUp->AddItem(new BMenuItem("Delete", new BMessage(kDeleteDragger))); 567 } 568 569 570 void 571 BDragger::ShowPopUp(BView *target, BPoint where) 572 { 573 BPoint point = ConvertToScreen(where); 574 575 if (!fPopUp && fTarget) 576 BuildDefaultPopUp(); 577 578 fPopUp->SetTargetForItems(fTarget); 579 580 fPopUp->Go(point, true, false, /*BRect(), */true); 581 } 582