Making an object (e.g. ofImage) draggable?

Hi,

thanks for the help last time regarding ofVideoPlayer.
But now I am trying to overcome another hurdle, so I want to say thanks in advance for any help provided.

Currently, I am trying to make ofImage or ofVideoPlayer objects draggable. More specifically, I want to hover over and click on an ofImage or ofVideoPlayer object with my mouse and then drag the image (or video) around (much like how you would drag icons on your desktop).

And I am wondering if anyone can provide me with insight or tutorial on how that can be accomplished?

Currently, I am thinking maybe I should modify ofImage and ofVideoPlayer classes, so each instance of ofImage or ofVideoPlayer will keep track of its current x and y position. Then, on a mouseDragged event, I can see check to see if the mouse has hovered over an ofImage or ofVideoPlayer object. If it has, translate the x,y position of the ofImage or ofVideoPlayer object accordingly?

Or is there a better way of going about this?

Thanks again! :slight_smile:

Your approach sounds pretty correct.

Only thing I would suggest is that instead of modifying the ofImage and ofVideoPlayer objects directly, is that you extend them… If you want to be really smart, you could even make a generic “draggable” class in which you could centralize the actual dragging code, and then inherit from it for image or video specific classes. Doing this will give you the advantage that you could easily make anything draggable in the future, and also means you won’t have to duplicate code in the image or video classes.

Something like this…

  
  
class draggableRectangle{  
protected:  
  ofRectangle* draggableBounds;  
  bool isBeingDragged;  
  
  bool isHovered(float x, float y);  
  
public:  
  draggableRectangle();  
  ~draggableRectangle();  
  
  virtual void draw();  
  bool mouseDragged(float x, float y, int button);   
  bool mousePressed(float x, float y, int button);  
};  
  

  
  
class draggableImage : public ofImage, public draggableRectangle{  
public:  
  draggableImage();  
  ~draggableImage();  
  
  void draw();  
  void loadDraggableImage(string filename){this->loadImage(filename); this->draggableBounds->width = this->width; this->draggableBounds->height = this->height;}  
};  
  

  
  
class draggableVideo : public ofVideoPlayer, public draggableRectangle{  
public:  
  draggableVideo();  
  ~draggableVideo();  
  
  void draw();  
  void loadDraggableVideo(string filename){this->loadMovie(filename); this->draggableBounds->width = this->width; this->draggableBounds->height = this->height;}  
};  
  

I’ve left out code for most of the methods, but hopefully just the definitions should be enough to give you the idea. I also filled in the loadDraggableImage/loadDraggableVideo methods since they could have provided a bit of a “gotcha” case on defining the boundaries of the drag box.

I have a class called ofxMSAInteractiveObject that manages all the mouse checking etc. and provides methods like isMouseOver(), isMouseDown() and also event callbacks like onRollOver(), onRollOut(), onPress() (I kept the names same as flash for easy transition).
You can find it here http://addons.openframeworks.cc/project-…-nteractive

v1.x is for the current release of openFrameworks using poco (00573)
v2.0 is for the upcoming version (006) which uses a new event system. If you get your OF from the SVN then use this one.

The best way is indeed like plong says is to create a draggable class. In this case I would just extend ofxMSAInteractiveObject (to get all of the functionality of the interactive object) and have a property as an image or video etc.

But in the new coming openFrameworks there is a really cool feature which is a basic object hierarchy - abstract base classes which most other core classes extend. E.g. a ofBaseDraws class which all objects which can be drawn to screen (e.g. ofTexture, ofImage, ofVideoPlayer etc.) extend. This means that in ofxDraggable you can have a pointer to ofBaseDraws, and you can later attach whatever you want to it, you dont need to create a class for each drawable type.

So the very little code below will give you a fully functional (including different colored borders depending on state) draggable image, video, texture, opencv image, optical flow vectorfield renderer etc. thanks to the beauty of OOP! (I haven’t actually tested it, so there might be bugs :P)

  
class ofxDraggable : public ofxMSAInteractiveObject {  
public:  
	ofBaseDraws *content; // this will point to your image, video, grabber etc.  
	  
	ofxDraggable() {  
		content = NULL;  
	}  
	  
	void onPress(int mx, int my, int button) {  
		// save the offset of where the mouse was clicked...  
		// ...relative to the position of the object  
		saveX = mx - this->x;  
		saveY = my - this->y;  
	}  
	  
	void onDragOver(int mx, int my, int button) {  
		this->x = mx - saveX;    // update x position  
		this->y = my - saveY;    // update mouse y position  
	}  
	  
	void draw() {  
		if(content) {  
			width = content->getWidth();  
			height = content->getHeight();  
			content->draw(x, y, width, height);  
			  
			// add a border if mouse is pressed or over the object  
			if(isMouseDown()) {  
				ofNoFill();  
				ofSetColor(0xFF0000);  
				ofRect(x, y, width, height);  
			} else if(isMouseOver()){  
				ofNoFill();  
				ofSetColor(0x00FF00);  
				ofRect(x, y, width, height);  
			}  
		}  
	}  
	  
protected:  
	int saveX, saveY;  
};  
  

All of those methods above are called automatically by ofxMSAInteractiveObject and the event system. Basically the goal was to bring adobe flash like functionality, so you can just create an object and forget about it. It draws, updates, mouse checks etc. by itself.

Then in your testApp code you can do something like:

  
  
ofImage myImage;  
ofxDraggable imageDragger;  
  
ofVideoPlayer myVideo;  
ofxDraggable videoDragger  
  
imageDragger.content = &myImage; // tell imageDragger to use this image  
videoDragger.content = &videoDragger; // tell videoDragger to use this video  
  

and then carry on using your myImage and videoDragger to load images, videos, look at the pixels etc. But you do not need to draw them (or check any mouse stuff). the ofxDraggable imageDragger and videoDragger will automatically do all the mouse checks and draw in the right place.

thanks for the help guys.
Wow, I am definitely going to save a bunch of time from your help :smiley:

thanks again

Then in your testApp code you can do something like:

  
>       
>     ofImage myImage;  
>     ofxDraggable imageDragger;  
>       
>     ofVideoPlayer myVideo;  
>     ofxDraggable videoDragger  
>       
>     imageDragger.content = &myImage; // tell imageDragger to use this image  
>     videoDragger.content = &videoDragger; // tell videoDragger to use this video  
>       
>     

and then carry on using your myImage and videoDragger to load images, videos, look at the pixels etc. But you do not need to draw them (or check any mouse stuff). the ofxDraggable imageDragger and videoDragger will automatically do all the mouse checks and draw in the right place.

Just for the records: I tested this for images and it works fine. One thing you have to do though is to enableMouseEvents like this:

  
    imageDragger.enableMouseEvents();  

otherwise it won’t react :wink:
OF 006, Addon v.2.0

Thanks a lot for this addon!

in OF 0.9, it gets a bad access code at the following return line
ofCoreEvents & ofMainLoop::events(){
return currentWindow->events();
}

Do you aware what is the issue?

Thanks.

Yes is broken, it seams that is not updated for a long time. Can you maked work?