Dragging a component


#1

I want to drag a component onto a workspace but leave the original component where it was. This action creates a new component on the workspace while leaving the original component. Like Visio or some other drawing tool where you drag a component onto a workspace or canvas.

Once I got my component drawn and draggable, I tried to create a new component in mouseDown() and have the new component as the one being dragged. I could not get this to work.

I then discovered Toolbar and its associated classes. But I can’t drag my component off of the tool bar. Here’s what I tried with toolbar:

class MyToolbar : public Toolbar
{
   MyToolbar() = default;

  void mouseDown(MouseEvent& e)
   {
      startDragging(e.eventComponent.getName(), e.eventComponent);
   }
};

‘mouseDown()’ never get called.

Now I’m thinking I should use ToolbarItemPalette and just pass it a dummy (unused) toolbar. Is there a better/standard way to do this with Juce?

Thanks,

Tom


#2

You toolbar’s mouseDown won’t get called because the toolbar is full of child components, and they’re catching the mouse-down events, not the parent toolbar. You’d need to create your own toolbar button if you want to make it do custom stuff.


#3

Thanks Jules. Yes, I can see the component’s mouseDown(…) getting called. From with in the component’s mouseDown(…) I can get a pointer to the toolbar and call startDragging on the toolbar. But this only let’s me drag the component on the toolbar. I need to also be able to drag it from the toolbar and into the component that contains the toolbar.

Thanks,

Tom


#4

Then you’d need to add the component to a suitable parent so that it can be dragged to wherever you need it.


#5

Yes trying that. Can’t seem to get it working. This is code inside the component being dragged:

    void mouseDown (const MouseEvent& e)
    {
		Toolbar* ptb = getToolbar();
		if(ptb)
		{
			printf("%s:  got toolbar\n", __func__);
			ptb->startDragging(name, this);
		}
    }

    void mouseDrag (const MouseEvent& e)
    {
	Toolbar* ptb = getToolbar();
	if(!ptb)
	{
		printf("%s:  !ptb\n", __func__);
		delete this;
	}
        else if (! parent.isValidComponent())
        {
		printf("%s:  ! parent->isValidComponent()\n", __func__);
                delete this;
        }
        else
        {
	        MouseEvent e2 (e.getEventRelativeTo(ptb));
		MouseEvent e3 (e.getEventRelativeTo(&parent));

                // inside toolbar, dragging here works
                if (e2.x >= 0 && e2.y >= 0 && e2.x < ptb->getWidth() && e2.y < ptb->getHeight())
                {
                    ptb->addChildComponent (this);
                }
                // outside of toolbar, inside of parent containing toolbar where the drop area will be
	        else if(e3.x >= 0 && e3.y >= 0 && e3.x < ptb->getWidth() && e3.y < ptb->getHeight())
                {
                    parent.addChildComponent (this);
                }
		ptb->mouseDrag(e);  // not sure what to do here ???
           }
    }

Do I need to add a ComponentDragger to my parent?

Could you please provide some code to demonstrate what you are talking about?

Thanks,

Tom


#6

Correction to my last post, the code should be:

    void mouseDown (const MouseEvent& e)
    {
      Toolbar* ptb = getToolbar();
      if(ptb)
      {
         printf("%s:  got toolbar\n", __func__);
         ptb->startDragging(name, this);
      }
    }

    void mouseDrag (const MouseEvent& e)
    {
        Toolbar* ptb = getToolbar();
        if(!ptb)
        {
            printf("%s:  !ptb\n", __func__);
            delete this;
        }
        else if (! parent.isValidComponent())
        {
            printf("%s:  ! parent->isValidComponent()\n", __func__);
            delete this;
        }
        else
        {
                MouseEvent e2 (e.getEventRelativeTo(ptb));
                MouseEvent e3 (e.getEventRelativeTo(&parent));

                // inside toolbar, dragging here works
                if (e2.x >= 0 && e2.y >= 0 && e2.x < ptb->getWidth() && e2.y < ptb->getHeight())
                {
                    ptb->addChildComponent (this);
                }
                // outside of toolbar, inside of parent containing toolbar where the drop area will be
                else if(e3.x >= 0 && e3.y >= 0 && e3.x < parent.getWidth() && e3.y < parent.getHeight())
                {
                    parent.addChildComponent (this);
                }
                ptb->mouseDrag(e);  // not sure what to do here ???
           }
    }

#7

Thanks for your help Jules. Got it working. Just made the parent of the toolbar a DragAndDropContainer and then called parent.startDragging(…) in the component’s mouseDrag(…) when the component is dragged outside the toolbar:

void CallFlowComponent::mouseDrag (const MouseEvent& e)
{
	Toolbar* ptb = getToolbar();
	
	if (! parent.isValidComponent())
	{
		printf("%s:  ! parent->isValidComponent()\n", __func__);
		delete this;
	}
	else
	{
		MouseEvent e2 (e.getEventRelativeTo(ptb));
		MouseEvent e3 (e.getEventRelativeTo(&parent));
		
		if (ptb && e2.x >= 0 && e2.y >= 0 && e2.x < ptb->getWidth() && e2.y < ptb->getHeight())
		{
			printf("%s:  inside toolbar\n", __func__);
			ptb->addChildComponent (this);
		}
		else if(e3.x >= 0 && e3.y >= 0 && e3.x < parent.getWidth() && e3.y < parent.getHeight())
		{
			printf("%s:  outside toolbar\n", __func__);
			parent.addChildComponent (this);
			parent.startDragging(name, this);
		}
	}
}

Please let me know if you think this is the right approach of if there is a better way.

Thanks,

Tom


#8

That’ll work fine, of course (I thought you were trying to actually move a component rather than just do a drag-and-drop)