UNSOLVED NodeData Undo

As per the documentation I have provided following in the Message method of my NodeData derived plugin:

		case MSG_DESCRIPTION_INITUNDO:
		{
			DescriptionInitUndo* const uData = static_cast<DescriptionInitUndo*>(data);
			// check if data and BaseDocument can be accessed
			if (!uData || !uData->doc)
				break;
			// add undo for dependent entities
			BaseDocument* const doc = uData->doc;
			doc->AddUndo(UNDOTYPE::CHANGE_SMALL, node);

			return true;
		}

This handles the storage of the description value when changed by user, and is all that is needed to support undo/redo of the NodeData derived plugin parameters in the Attribute manager.

One of the parameters is the rotation angle of a rectangle.
This rectangle is displayed in a UserArea which the user can select and rotate interactively.
The user can thus enter the value via the Attribute Manager, or handle the rectangle in the UserArea.

However, after manipulation of the rectangle in UserArea I get the NodeData derived object (via a SceneHook), I get it's BaseContainer and sets the rotation parameter.
This is visually updated in the Attribute Manager, but I do not get a MSG_DESCRIPTION_INITUNDO triggered?

  1. When I manually enter a value in the Attribute Manager and press undo, the value reverts to the previous one.
  2. When I rotate the rectangle in the UserArea the value in Attribute Manager gets updated. But when I press undo ... value stays the same.

To make the undo work in step 2, I need to perform:

doc->StartUndo();
doc->AddUndo(UNDOTYPE::CHANGE_SMALL, node);
node->SetParameter(RECTANGLE_ROTATION_ID, GeData(angle), DESCFLAGS_SET::NONE);
doc->EndUndo();

Is there a way to avoid having to create the undo myself, and instead trigger the node's MSG_DESCRIPTION_INITUNDO?

Hi,

For what i understand, using node->SetParameter should take care of the undo. Did you try with a different DESCFLAGS_SET flag?

You can always send the message yourself to the node.

	DescriptionInitUndo uu;
	uu.doc = doc;
	uu.descid = &m_LinkID;
	obj->Message(MSG_DESCRIPTION_INITUNDO, &uu);

More lines but you will be sure that the Undo is handle in the same place.

Cheers,
Manuel

@m_magalhaes
I did try with DESCFLAGS_SET::
NONE
PARAMSET
USERINTERACTION

But none of these 3 triggered the message.
I will try to send the messaeg myself.

@m_magalhaes said in NodeData Undo:

uu.descid = &m_LinkID;

Seeing this makes me assume I will need to provide a member variable for each description ID I intend to have an undo for?
And I would need to send a message for each and every description ID?

I'd much rather prefer going with the single call to perform an AddUndo instead.

Hi,

well, the structure DescriptionInitUndo have a descid variable you can provide.

As you react to MSG_DESCRIPTION_INITUNDO this descid can be whatever you need to trigger the action you want.

Cheers,
Manuel

@m_magalhaes said in NodeData Undo:

well, the structure DescriptionInitUndo have a descid variable you can provide.

As you react to MSG_DESCRIPTION_INITUNDO this descid can be whatever you need to trigger the action you want.

Right, but that uu.descid expects a pointer.
Which means you cannot simply pass the description ID of a gadget, but need to allocate some memory and keep that active until the message has been processed.

With RECTANGLE_ROTATION_ID defined in the desription header
I can simply set the parameter via:

node->SetParameter(RECTANGLE_ROTATION_ID ...

I cannot do:

uu.descid = RECTANGLE_ROTATION_ID

Hi,

this should work.

DescriptionInitUndo uu;
uu.doc = doc;
// define the descid

uu.descid = &DescID(RECTANGLE_ROTATION_ID);
// or 
DescID tid = MSG_DESCRIPTION_INITUNDO;
uu.descid = &tid;

Cheers,
Manuel

@m_magalhaes said in NodeData Undo:

this should work.

DescriptionInitUndo uu;
uu.doc = doc;
uu.descid = &DescID(RECTANGLE_ROTATION_ID);

Unfortunately!
That's exactly what I had tried from the start but while the message gets delivered the descid didn't survive.

848746f2-955f-4c75-96d2-1a8c3386a3bb-image.png

Looking at the content of uData.descid when manually changing the gadget, I see it contains
10050 = the ID of the description float field ((RECTANGLE_ROTATION_ID)
1057224 = the plugin ID of the NodeData description.

Should the plugin ID of the NodeData description be passed somewhere during:

DescriptionInitUndo uu;
uu.doc = doc;
uu.descid = &(RECTANGLE_ROTATION_ID);
obj->Message(MSG_DESCRIPTION_INITUNDO, &uu);

?

Hi,

Sorry i forgot this thread. what version of cinema4D are you using (just in case)

Cheers,
Manuel

@m_magalhaes
At the moment I am using R20.

Hi,

sorry for that huge delay.

I tried again and it's working even on R20. The descid isn't something to consider. I mean i have the same kind of result, count = 0 and 0x00000 address but it's working.

The undo is added correctly, if the undo arrow is grey out, it become active. That mean an undo step has been added.
Just in case, what's important is to call the message before the change happen because CHANGE_SMALL must be called before.

Cheers,
Manuel