Draggable Component

Introduction

draggable-component.png

In this tutorial, I will explain how to create a draggable component using ComponentDragger and ComponentBoundsConstrainer classes. As shown below, the blue rectangle can be dragged inside the grey rectangle.

finish.gif

The source code is available from the repository below:

Draggable Component - GitHub

Prerequisites

Create a project named DraggableComponent. new-project.png

Create a new header file named GreyRect. add-files.png

Add the following code to GreyRect.h

GreyRect.h
#pragma once

#include <JuceHeader.h>

class GreyRect  : public juce::Component
{
public:
    GreyRect()
    {
        addAndMakeVisible (blueRect);
    };

    void paint (juce::Graphics& g) override
    {
        auto grey = juce::Colour::fromFloatRGBA (0.28f, 0.28f, 0.28f, 1.0f);
        g.fillAll (grey.withAlpha (0.1f));

        g.setColour (grey);
        g.drawRect (getLocalBounds(), 2);
    }

    void resized () override
    {
        blueRect.setBounds (getLocalBounds().withSizeKeepingCentre (40, 40));
    }

private:
   struct  DraggableComp : public juce::Component
   {
       void paint (juce::Graphics& g) override
       {
           auto bounds = getLocalBounds().reduced (1);
           auto blue = juce::Colour::fromFloatRGBA (0.42f, 0.83f, 1.0f,  1.0f);

           g.setColour (blue.withAlpha (0.2f));
           g.fillRect (bounds);

           g.setColour (blue);
           g.drawRect (bounds, 2);
       }
   };

   DraggableComp blueRect;
};

In MainComponent.h, include this header file and create an object of GreyRect class.

MainComponent.h
#include "GreyRect.h"
MainComponent.h
class MainComponent  : public juce::Component
{
・・・
private:
    GreyRect greyRect;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

Add the following code in MainComponent.cpp and build this project.

MainComponent.cpp
MainComponent::MainComponent()
{
    setSize (600, 400);

    addAndMakeVisible (greyRect);
}

void MainComponent::paint (juce::Graphics& g)
{
    auto black = juce::Colour::fromFloatRGBA (0.08f, 0.08f, 0.08f, 1.0f);
    g.fillAll (black);
}

void MainComponent::resized()
{
    greyRect.setBounds (getLocalBounds().withSizeKeepingCentre (400, 250));
}

As shown below, a gray rectangle and a blue rectangle are drawn, and the blue one cannot be dragged yet. grey-and-blue-rect.png

ComponentDragger

In this chapter, we will make the blue rectangle draggable.

drag-component.gif

Creating the object

Create an object of ComponentDragger class in DraggableComp struct.

GreyRect.h
struct DraggableComp  : public juce::Component
{
    juce::ComponentDragger dragger;
・・・
};

startDraggingComponent()

In mouseDown() callback, call startDraggingComponent() to prepare for dragging.

GreyRect.h
・・・
struct DraggableComp  : public juce::Component
{
・・・
	void mouseDown (const juce::MouseEvent& event) override
	{
		dragger.startDraggingComponent (this, event);
	}
};

dragComponent()

In mouseDrag() callback, call dragComponent() to move the component.

GreyRect.h
struct DraggableComp  : public juce::Component
{
・・・
	void mouseDrag (const juce::MouseEvent& event) override
	{
		dragger.dragComponent (this, event, nullptr);
	}
};

Building

As shown below, you can drag the blue rectangle.

drag-component.gif

However, you would be able to drag this to outside the border of the gray rectangle. disappearing-rect.gif

ComponentBoundsConstrainer

In this chapter, we will limit the blue rectangle's position and keep it on-screen.

finish.gif

Creating the object

Create an object of ComponentBoundsConstrainer class in DraggableComp struct, and pass this object to dragComponent().

GreyRect.h
struct DraggableComp  : public juce::Component
{
	juce::ComponentDragger dragger;
	juce::ComponentBoundsConstrainer constrainer;
・・・
	void mouseDrag (const juce::MouseEvent& event) override
	{
		dragger.dragComponent (this, event, &constrainer);
	}
};

setMinimumOnscreenAmounts()

In the constructor, call setMinimumOnscreenAmounts() to set the amount by which the blue rectangle is allowed to go off-screen.

GreyRect.h
struct DraggableComp : public juce::Component
{
	juce::ComponentDragger dragger;
	juce::ComponentBoundsConstrainer constrainer;

    DraggableComp()
    {
    	constrainer.setMinimumOnscreenAmounts (20, 20, 20, 20);
    }
・・・
};

In this case, we will allow the blue rectangle to go off-screen up to half its length.

constrainer1.png

Therefore, by passing the length of the width of the blue rectangle to this function, we can restrict the position to within the gray rectangle.

GreyRect.h
・・・
    DraggableComp()
    {
    	constrainer.setMinimumOnscreenAmounts (40, 40, 40, 40);
    }
・・・

constrainer2.png

Building

finish.gif

Summary

In this tutorial, I explained the following:

  • how to use ComponentDragger class
  • how to use ComponentBoundsConstrainer class

By applying these, you can create a filter plugin UI as shown below. filter.png

References