Treeview drag and drop

On 12/11/2017 at 14:44, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   R18 
Platform:   Windows  ;   Mac OSX  ; 
Language(s) :     C++  ;

I've been going down the rabbit hole of trying to make my treeview act more like the object manager and I've run into an understanding block. I've seen in other forum posts AcceptDragObject as one of the functions I need to implement. Implementing that does give me gold lines in my Treeview to insert objects in. My specific treeview is static though, I need that functionality where you drag a Meterial from the Materials palette over to an object in the Object Manager and it gives a plus icon. I'd also like to drag tags the same way.

My question is how to enable these and check that the objects inside the dragobject are what I want?

On 13/11/2017 at 10:01, xxxxxxxx wrote:


first of all, I need to mention that the Object Manager is actually not a TreeView CustomGUI. There's quite some stuff hard coded internally, so you may not completely succeed in imitating it completely.

But for the drag and drop part (with one small exception) there shouldn't be an issue.

You are already looking at the correct function: AcceptDragObject()
With the return value, you can not only specify, that you will accept or refuse a (or multiple) dragged entities, but also the type of mouse pointer Cinema 4D will display.
By returning one or multiple of the INSERT flags, you will get the "golden lines" to insert objects. But there is another flag, which may be returned additionally or also alone: ACCEPT_DRAG_OBJECT_FORCE_COPY. This will add the "plus" to the mouse pointer. If not combined with any INSERT flags, it's only possible to append to the list.)

So for example, when a material is dragged onto an object, you'd have a combination of INSERT_UNDER and ACCEPT_DRAG_OBJECT_FORCE_COPY. And here's the drawback, the golden line does still appear, and it doesn't in OM.

Then you also want to react to the type of the dragged entities. The dragdata is also passed to AcceptDragObject(). Depending on parameter type, you can inspect the drag data, before returning any of the above flags. For example, all C4DAtom derived entities (objects, materials, tags,...) get dragged as an AtomArray (DRAGTYPE_ATOMARRAY).

So you can do something like this:

Int32 MyTreeViewFuncs::AcceptDragObject(void* root, void* ud, void* obj, Int32 type, void* dragData, Bool& allowCopy)
	switch (type)
			AtomArray* const arr = static_cast<AtomArray*>(dragData);
			if (!arr)
				return 0;
			const Int32 count = arr->GetCount();
			for (Int32 i = 0; i < count; ++i)
				C4DAtom* const atom = arr->GetIndex(i);
				if (!atom || !atom->IsInstanceOf(Obase))
					return 0; // do not accept objects
	return 0;

On 14/11/2017 at 22:57, xxxxxxxx wrote:

That works thanks. A related question, I have two columns in this treeview(plus the name of the item itself). When I drag I'd like a piece of data to occupy one of the two columns. Preferably the user would drag and drop to the column they want but that'd involve a lot of drag and drop position checking I imagine. My idea was on drop a context popup(kinda like a right click menu) would ask them what type of column data it was that they were dropping.

Is it possible to have a context pop up like that with the treeview?

On 15/11/2017 at 09:10, xxxxxxxx wrote:

Sure, that's actually quite easy. Just take a look at ShowPopupMenu() and use it in InsertObject().