OnCancelEvent - Differentiating Undo from Redo
-
In Sketchup Ruby API (at least up to version 8), the
onCancel
event uses the same flag with value 2 for both Undo and Redo. I presume this could be called a bug.Anyway, I needed to distinguish between the two operations and here is what I found
-
At the time you receive an
onCancel
event, the Undo or Redo operations are not yet performed. -
So you can avoid the undo or redo by simply starting a fake operation with model_start_operation
-
to know whether you have a redo or undo, the only way I found so far is to use the model observer
You just need to add a few lines of code in your Tool class
in the
activate
eventSketchup.active_model.add_observer self
in the
deactivate
eventSketchup.active_model.remove_observer self
You create two methods of your Tool class
def onTransactionUndo(model) ; @undo_redo = ;undo ; end def onTransactionRedo(model) ; @undo_redo = ;redo ; end
Finally, in the
onCancel
eventdef onCancel(flag, view) Sketchup.active_model.start_operation "fake" UI.start_timer(0) { execute_undo_redo } end
When you are in your method
execute_undo_redo
, you have access to the variable@undo_redo
which is either:undo
or:redo
.So you have some control on what you can do actually
- either nothing (preventing the undo and/or redo) by invoking
Sketchup.active_model.abort_operation
- or an undo, by invoking
Sketchup.undo
- or a redo, by invoking
Sketchup.send_action "editRedo:"
. CAUTION: this command actually reissue anonCancel
event, so you have to protect infinite loop execution in some way.Sketchup.redo
is another missing method in the SU API!
Indeed, you may have to adapt depending on your context of operation, but these are principles
If someone knows how to differentiate between undo and redo at the
onCancel
event firing, thanks to signal it.Fredo
-
-
Instead of the timer - would you not just make the ModelObsever trigger that on the Undo/Redo events. Because that's what you are waiting for anyway. And making the ModelObsever trigger it avoid the risk of things getting out of sync for whatever reason.
When you wrap the undo event in a start/commit operation - doesn't that interfere with the undo stack? Does it let the user undo backwards further?
Does aborting the undo block the user from undoing completely?
I'm a bit reluctant to interfering with the undo stack...
-
Tom,
Overall, my post was more to ask if someone had found a way to find out about Undo or Redo.
What I describe is cumbersome, and precisely by putting it in writing, I realize that this may lead to undesirable side effects (even if I found none so far), in particular if the SU Google team had the good idea to fix their API.
To answer your question
1) observer: the issue is that the observer methods
onTransactionUndo
andonTransactionRedo
are fired several times (3 or 4, maybe more). So you cannot do any execution here, just noting if this is Undo or redo. In addition, I always take the principle not to perform changes within any observer methods, due to the rather unpredictable implemnetation that was done in the SU API for all observers (and changes from one version to the next one).-
The method of starting a fake transaction works fine to prevent Undo and Redo. My problems was actually that I wanted to prevent the Undo, not the Redo.
-
Yes, you are right that scripts should not interfer with the undo stack in a preemptive way. My intention was simply to signal it via a confirmation dialog box before executing it.
Anyway, all this gave me the opportunity to explore a little bit of the Undo, redo and onCancel behaviors. So at least I know how it works.
Fredo
-
-
I have been working with the undo/redo stack myself for BezierSurface which I'm currentlty working on.
I also found that the tool event triggered before the undo/redo actually happened.
I also figured that I should never make model changes in response to the undo/stack - as it's mess it up. But your idea of being able to cancel an event is interesting. Making users confirm it could be useful.
However - I have not observed that the Undo/Redo event - for the ModelObserver or Tool triggers more than once. Sounds like you might have multiple observers attached...
-
@thomthom said:
However - I have not observed that the Undo/Redo event - for the ModelObserver or Tool triggers more than once. Sounds like you might have multiple observers attached...
Tom,
You are right again.
I found that you have to remove the observer (in the deactivate). Otherwise, in new instances of the Tool class, you will get the observer notifications of the ones previously created!I think I made my way now. My objective was simply to manage the history of modifications via the Sketchup standard undo and redo, while keeping some control of what is going on.
Fredo
-
@unknownuser said:
You are right again.
I found that you have to remove the observer (in the deactivate). Otherwise, in new instances of the Tool class, you will get the observer notifications of the ones previously created!I've begun to make my observers into Singletons. So I can use a factory method to get the singleton instance at any time when I need to add / remove the observer.
Advertisement