protux-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Protux-devel] Mustux MUE - Mustux Undo Engine - First formal approa


From: Remon Sijrier
Subject: Re: [Protux-devel] Mustux MUE - Mustux Undo Engine - First formal approach
Date: Sun, 16 May 2004 22:49:14 +0200
User-agent: KMail/1.6.2

I've read it several times, hopefully I've understood everything. There are 
some things not completely clear, especially within context of contexts 
(JmbContext ;-) )

First a little more on JmbContext/Mode since thats rather important IMO.

In the JmbContext/Mode whitepaper I introduced the "ApplicationGlobal" and 
"ObjectGlobal" actions.
A application such as Protux, and probably all Mustux applications (== 
application who benefit a lot of the JMB concept) are editing some kind of 
object/objects which are displayed in 1 (one) window. (Lets call it 
'ViewPort') If you are working in a 3D program, there will be a multiview, 
but then you still are viewing lets say 3 windows in 1 (one) window, the 
ViewPort Window. This one window is the window that accepts the keyboard 
events (== JmbFacts) and is responsible for further handling of it. All the 
rest of a MustuxInterface is used to give the user Information, no JMB 
handling required here.

This leads to a conclusion:
"ApplicationGlobal" actions don't have any (direct) relationship to the 
ViewPort.
"ObjectGlobal" actions are those actions that are related to the ViewPort, and 
there can be more then one ViewPort at a time. For example, Song is a 
ViewPort and there can be more Songs loaded at a time.

The current JmbAction implementation is as follows:
JmbAction has the members JmbContext, JmbMode, and a property.
The JmbActions are ALL stored in one actionArray. This means that the actions 
for ApplicationGlobal and ObjectGlobal are threaded the same.
But it would be far more easier to make an actionArray for the 
ApplicationGlobal actions, and one for each ViewPort (ObjectGlobal) action.
(not completely true, since Jmb::UseCollectedNumber is less trivial to 
implement, but thats for later)
But to make this work, you have to explicitly set the active ViewPort to let 
the JMB engine know which action array it has to use. In my current 
implementation, it was allready unavoidable, so no problem at all.

Read on, the rest is written between the lines below. (Note, the key idea of 
the story above is:
- having one action/undo/etc array for each ViewPort
- ditto for the ApplicationGlobal one)


> 1 - The Action Stack (the Mue STACK)
>
> We can initially think that everything performed by user should be some way
> registered so it can be "undone". This is almost correct, if we think that
> there are few things that should not be undone (like Quit, or Help, or Show
> Bus Monitor, and other simple and not-undoable things) . That leads us to 2
> things
>
> - An action (an JMB action) must have a boolean flag "undoable", because
> some actions won't be undoable.
> - Undoable actions must be registered somewhere. A Stack (LIFO) must be
> implemented,
> and actions are stacked someway (more later) so they can be retrived in
> case of an undo (of course, the very undo action is NOT undoable)

Agree with all above, except the last thing. Undoing an undo action means 
"redo"? Shouldn't "redo" be possible as well?

> 2 - The superclass MustuxObject and the PerformedAction class
>
> An action to be undone must restore the data structures it modified. It can
> be a simple cursor position or a entire list of clips. We never know what
> data structure should be stacked (together the action), neither the size of
> it. Thus, we must deal with abstract objects. Every data structure that is
> supposed to be stacked for undo purposes in the application  must derive
> from a common super class MustuxObject
> Also, the stacked action must KNOW what data struct or what collection of
> data structures it affcted. Thus, the performed actions must retaing
> pointers to mustux objects, without worrying about their nature. This will
> lead us to the conclusion that we must stack not only the JMBAction
> performed, but a class that holds it and the circumstances on what it
> happened, including any aditional data that the data struct affected could
> depend, as the context of it was removed, for example.

Seems very clear to me ;-)


> 3 - The PerformedAction
>
> When performing actions, will be essentially pushing jmbactions into the
> MUE stack. When undoing, we will retrieve the antiaction by poping the last
> action up and discovering what is the antiaction related to it. One could
> think: this could be stored in a table. Actually it will be, but the
> "circumstances" won't. For example,
> we can store in a static table the Delete Clip has Insert Clip as
> antiaction, but think of "delete clip B from song 4 in project X ". We can
> just store the pure idea the delete clip has insert clip as antiaction, but
> not the whole scenario on when and how it happens. All these things must be
> part of PerformedAction class, which will be stacked . The PerformedAction
> class must then have proper atributes to hold this scenario, in the most
> abstract way possible.
>
> So, we would have a PerformedAction class like
>
> PerformedAction in pseudo-definition
> {
> JmbAction* performedJmbAction;
> MustuxObject* affectedObject;
> JmbContext* contextWhenPerforming;
> JmbMode* modeWhenPerforming;
> ProjectState* stateWhenDoing;
> }

Just for the record, JmbAction allready holds the JmbContext and JmbMode

>
> And the MUE engine would make something like
>
> PerformedAction a = MueStack.pop();
> Antiaction a = ActionAntiActionTable.getAntiaction(a); // a brings all
> // scenarios which must be restored from action
> Jmb::broadcast(a);
>
> Of course, Some static (see examples below) table would map actions to
> their respective anti-actions.
>
> The new thing here is the ProjectState. I think this could be kind of a
> property table for each application which holds the very basic information
> for a mustux project (which itself, should be promoted to libmustux as a
> superclass facility).
> In this object one can store things like current cursor position, snap mode
> status, and so on... It is up to us to decide if a undo should restore
> previous project state (sometimes it is not interesting). Anyway, Mue could
> exist without it.

It appears to me that a lot of this applies for the "ApplicationGlobal" object 
(actions). Maybe we have to keep this in mind.

> Now lets see an example of the static table that would map actions to
> antiactions.
>
> Action                AntiAction
> Delete Clip   Insert Clip
> Move Node     Move Node
> Delete node   add node
> mute track    unmute track
> split clip    glue clip
> Move Edge     Move Edge
> Delete Track  Insert Track (*)
>
> I call the attention to the last example : When you delete a track the
> affected objects are a list of audioclips, which will be treat as a
> MustuxObject* pointer. When performing the antiaction ("insert track") we
> should call a serie of insert clips. This is provided by the MustuxObject*
> pointer in the stacked action. The inserttrack could be overloaded to
> receive a list of clips to be automatcally inserted. So, when performing
> the antiaction, we should upcast MustuxObject* to (AudioClip*) list, and
> pass it it to insert_track(AudioClip*), and we get our clips back ! That is
> the importance of storing in a abstract form the data affected by an
> action

Would be great!

> 4 - The persistence
>
> The more information we store in the Performed action, more reliable will
> be the antiaction.  And since are have a single structure to hold all our
> previous actions, it is just a matter of serialize it and persist it to the
> HD in order to get a persistable behavior, just like we would have if we
> used the memory-image approach (when you store all your data structure
> every time you perform an action). The big difference here, is that you
> just persist once, when you are about to quit the application. Also, you
> dont need to persist a big number of levels (user could select how many
> previous action it should persist after a quit).

I don't get one thing here. Anti actions are (hard) linked to Objects. In case 
you restart a MustuxApplication, the "undo" stack is loaded into memory, but 
how do all the actions/antiactions know on what Object they apply since the 
relation is broken to these Objects?


About the (one) LIFO Stack.

It appeared to me that the same things apply to the MUE as for the JMB engine. 
To have a LIFO Stack for each ViewPort object (so for example each Song has 
its own LIFO Stack) and a LIFO Stack for the "ApplicationGlobal" actions. 
Then we should think of a way to perform undo in a "Global" way, a 
"ApplicationGlobal" way, and finally the "ObjectGlobal" or ViewPort way.
Then the currentActive ViewPort will for example receive the "ViewPort undo" 
action.
This could even be extended to have a "Contextual" undo.
For example, when we are UponClip, and the last action on that Clip was 
"Gain", the "Contextual Undo" action will undo the "Clip Gain" action for 
that very Clip. Wouldn't that be exciting? ;-)

Another point, as soon as a "ViewPort" closes (stops existing) the 
"ApplicationGlobal" and "Global" LIFO Stacks have to be cleaned up, and all 
actions related to this very ViewPort has to be removed. Of course, this 
ViewPorts LIFO Stack will be stored on HD.


Just some ideas from me, please if it is not clear, let me know.

Greetings,

Remon

>
>
> ________________________________________________
> Horizon Serviços Digitais
> Assine já! - 0300 789 70 90
>
>
>
> _______________________________________________
> Protux-devel mailing list
> address@hidden
> http://mail.nongnu.org/mailman/listinfo/protux-devel




reply via email to

[Prev in Thread] Current Thread [Next in Thread]