/* GWEN Copyright (c) 2010 Facepunch Studios See license in Gwen.h */ #include "Gwen/Gwen.h" #include "Gwen/DragAndDrop.h" #include "Gwen/Utility.h" #include "Gwen/Platform.h" using namespace Gwen; using namespace Gwen::DragAndDrop; DragAndDrop::Package* DragAndDrop::CurrentPackage = NULL; Gwen::Controls::Base* DragAndDrop::HoveredControl = NULL; Gwen::Controls::Base* DragAndDrop::SourceControl = NULL; static Gwen::Controls::Base* LastPressedControl = NULL; static Gwen::Controls::Base* NewHoveredControl = NULL; static Gwen::Point LastPressedPos; void DragAndDrop::ControlDeleted(Gwen::Controls::Base* pControl) { if (SourceControl == pControl) { SourceControl = NULL; CurrentPackage = NULL; HoveredControl = NULL; LastPressedControl = NULL; } if (LastPressedControl == pControl) LastPressedControl = NULL; if (HoveredControl == pControl) HoveredControl = NULL; if (NewHoveredControl == pControl) NewHoveredControl = NULL; } static int m_iMouseX = 0; static int m_iMouseY = 0; bool DragAndDrop::Start(Gwen::Controls::Base* pControl, Package* pPackage) { if (CurrentPackage) { return false; } CurrentPackage = pPackage; SourceControl = pControl; return true; } bool OnDrop(int x, int y) { bool bSuccess = false; if (DragAndDrop::HoveredControl) { DragAndDrop::HoveredControl->DragAndDrop_HoverLeave(DragAndDrop::CurrentPackage); bSuccess = DragAndDrop::HoveredControl->DragAndDrop_HandleDrop(DragAndDrop::CurrentPackage, x, y); } // Report back to the source control, to tell it if we've been successful. DragAndDrop::SourceControl->DragAndDrop_EndDragging(bSuccess, x, y); DragAndDrop::CurrentPackage = NULL; DragAndDrop::SourceControl = NULL; return true; } bool DragAndDrop::OnMouseButton(Gwen::Controls::Base* pHoveredControl, int x, int y, bool bDown) { if (!bDown) { LastPressedControl = NULL; // Not carrying anything, allow normal actions if (!CurrentPackage) return false; // We were carrying something, drop it. OnDrop(x, y); return true; } if (!pHoveredControl) return false; if (!pHoveredControl->DragAndDrop_Draggable()) return false; // Store the last clicked on control. Don't do anything yet, // we'll check it in OnMouseMoved, and if it moves further than // x pixels with the mouse down, we'll start to drag. LastPressedPos = Gwen::Point(x, y); LastPressedControl = pHoveredControl; return false; } bool ShouldStartDraggingControl(int x, int y) { // We're not holding a control down.. if (!LastPressedControl) return false; // Not been dragged far enough int iLength = abs(x - LastPressedPos.x) + abs(y - LastPressedPos.y); if (iLength < 5) return false; // Create the dragging package DragAndDrop::CurrentPackage = LastPressedControl->DragAndDrop_GetPackage(LastPressedPos.x, LastPressedPos.y); // We didn't create a package! if (!DragAndDrop::CurrentPackage) { LastPressedControl = NULL; DragAndDrop::SourceControl = NULL; return false; } // Now we're dragging something! DragAndDrop::SourceControl = LastPressedControl; Gwen::MouseFocus = NULL; LastPressedControl = NULL; DragAndDrop::CurrentPackage->drawcontrol = NULL; // Some controls will want to decide whether they should be dragged at that moment. // This function is for them (it defaults to true) if (!DragAndDrop::SourceControl->DragAndDrop_ShouldStartDrag()) { DragAndDrop::SourceControl = NULL; DragAndDrop::CurrentPackage = NULL; return false; } DragAndDrop::SourceControl->DragAndDrop_StartDragging(DragAndDrop::CurrentPackage, LastPressedPos.x, LastPressedPos.y); return true; } void UpdateHoveredControl(Gwen::Controls::Base* pCtrl, int x, int y) { // // We use this global variable to represent our hovered control // That way, if the new hovered control gets deleted in one of the // Hover callbacks, we won't be left with a hanging pointer. // This isn't ideal - but it's minimal. // NewHoveredControl = pCtrl; // Nothing to change.. if (DragAndDrop::HoveredControl == NewHoveredControl) return; // We changed - tell the old hovered control that it's no longer hovered. if (DragAndDrop::HoveredControl && DragAndDrop::HoveredControl != NewHoveredControl) DragAndDrop::HoveredControl->DragAndDrop_HoverLeave(DragAndDrop::CurrentPackage); // If we're hovering where the control came from, just forget it. // By changing it to NULL here we're not going to show any error cursors // it will just do nothing if you drop it. if (NewHoveredControl == DragAndDrop::SourceControl) NewHoveredControl = NULL; // Check to see if the new potential control can accept this type of package. // If not, ignore it and show an error cursor. while (NewHoveredControl && !NewHoveredControl->DragAndDrop_CanAcceptPackage(DragAndDrop::CurrentPackage)) { // We can't drop on this control, so lets try to drop // onto its parent.. NewHoveredControl = NewHoveredControl->GetParent(); // Its parents are dead. We can't drop it here. // Show the NO WAY cursor. if (!NewHoveredControl) { Platform::SetCursor(CursorType::No); } } // Become out new hovered control DragAndDrop::HoveredControl = NewHoveredControl; // If we exist, tell us that we've started hovering. if (DragAndDrop::HoveredControl) { DragAndDrop::HoveredControl->DragAndDrop_HoverEnter(DragAndDrop::CurrentPackage, x, y); } NewHoveredControl = NULL; } void DragAndDrop::OnMouseMoved(Gwen::Controls::Base* pHoveredControl, int x, int y) { // Always keep these up to date, they're used to draw the dragged control. m_iMouseX = x; m_iMouseY = y; // If we're not carrying anything, then check to see if we should // pick up from a control that we're holding down. If not, then forget it. if (!CurrentPackage && !ShouldStartDraggingControl(x, y)) return; // Swap to this new hovered control and notify them of the change. UpdateHoveredControl(pHoveredControl, x, y); if (!HoveredControl) return; // Update the hovered control every mouse move, so it can show where // the dropped control will land etc.. HoveredControl->DragAndDrop_Hover(CurrentPackage, x, y); // Override the cursor - since it might have been set my underlying controls // Ideally this would show the 'being dragged' control. TODO Platform::SetCursor(CursorType::Normal); pHoveredControl->Redraw(); } void DragAndDrop::RenderOverlay(Gwen::Controls::Canvas* /*pCanvas*/, Skin::Base* skin) { if (!CurrentPackage) return; if (!CurrentPackage->drawcontrol) return; Gwen::Point pntOld = skin->GetRender()->GetRenderOffset(); skin->GetRender()->AddRenderOffset(Gwen::Rect(m_iMouseX - SourceControl->X() - CurrentPackage->holdoffset.x, m_iMouseY - SourceControl->Y() - CurrentPackage->holdoffset.y, 0, 0)); CurrentPackage->drawcontrol->DoRender(skin); skin->GetRender()->SetRenderOffset(pntOld); }