Re: general undo methods?
Chipp Walters wrote: Richard Gaskin wrote: That's prettyt much where I'm headed now, but there's one aspect that's still problematic: Rev's built-in undo for text editing operations is something I don't want to replicate. For a single-level Undo it's easy enough to put a flag in the undo string to tell it to use the built-in undo command rather than any custom routine. But how would one handle this for multi-level undo? Richard, I'm sure you've already thought of this, but why not create a number of customProps in a customPropSet: fwUndo["fred",1] fwUndo["fred",2] etc.. where 'fred' refers to a field name and the number refers to the last change made. Then each time a close field is sent to the "fred" fld, store the htmlText of the field in the appropriate customProp. Then it's a simple matter to find the highest number and 'undo' to the htmlText of it. StripAndShip will kill the whole property set. I'm sure you already thought of this, but thought I'd mention it anyway. In general I like it, but I've gone the route of stashing undo commands instead of properties. That way the undo script doesn't need to parse the properties to figure out what action to take, making the undo script smaller and opening up more flexibility fort someone as lazy as myself. :) Another tricky aspect is one that Ken reminded me of on the phone the other day: undo needs to be window-aware. So if you do something in one window and move another to the front, choosing Edit-Undo shouldn't undo the thing in the window that no longer has focus. Currently I'm only doing one-level undo, using an array with the stack name as the key. That way I can clear the entire array at once when Undo is used, and until then I maintain undo code for each stack's last action. -- Richard Gaskin Fourth World Media Corporation ___ [EMAIL PROTECTED] http://www.FourthWorld.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
On Feb 18, 2005, at 1:53 PM, Richard Gaskin wrote: Any of you have pointers to general methods for implemening undo across an app? In a simple case, I have each undoable action push a line onto the end of a bunch of lines in a global. For an undo, the code simply pops the line and gives it to 'do'. To keep from getting confused, I put each undoable action in a handler with a name, say 'abc' and it uses the handler 'undoAbc' in the line pushed onto the end of the undo list. Dar -- ** DSC (Dar Scott Consulting & Dar's Lab) http://www.swcp.com/dsc/ Programming Services and Software ** ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
On Feb 19, 2005, at 10:57 AM, Richard Gaskin wrote: Geoff Canyon wrote: I would store a list of transcript statements designed to undo/redo the things you are doing. So if you move a rectangle to 100,300 I would get the long id of the rectangle and do something like this: put "set the loc of" && it && "to" && tNewLoc & cr after gRedoString put "set the loc of" && it && "to" && the loc of it & cr before gUndoString set the loc of it to tNewLoc I did something like this for fields and found it to be remarkably fast and efficient. The really great aspect is that you can undo/redo an arbitrary number of steps with one command: do line 1 to 100 of gUndoString undoes 100 steps, etc. That's prettyt much where I'm headed now, but there's one aspect that's still problematic: Rev's built-in undo for text editing operations is something I don't want to replicate. For a single-level Undo it's easy enough to put a flag in the undo string to tell it to use the built-in undo command rather than any custom routine. But how would one handle this for multi-level undo? If you're going to do multi-level undo, I think you have no choice but to ignore Rev's built-in undo completely. They can't be stored as far as I know, so once something else has been done they're lost. I have a stack that demonstrates multi-level undo in fields. It was a thought experiment and isn't complete: -- it doesn't concern itself with _when_ to take an undo step. -- it doesn't handle copy/paste and drag/drop efficiently. It should work correctly, but the transcript generated is inefficient. For drag/drop, the command should be nothing but chunks, since no text has changed, but it's not that smart. I'll email it to you. regards, Geoff Canyon [EMAIL PROTECTED] ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
Richard Gaskin wrote: That's prettyt much where I'm headed now, but there's one aspect that's still problematic: Rev's built-in undo for text editing operations is something I don't want to replicate. For a single-level Undo it's easy enough to put a flag in the undo string to tell it to use the built-in undo command rather than any custom routine. But how would one handle this for multi-level undo? Richard, I'm sure you've already thought of this, but why not create a number of customProps in a customPropSet: fwUndo["fred",1] fwUndo["fred",2] etc.. where 'fred' refers to a field name and the number refers to the last change made. Then each time a close field is sent to the "fred" fld, store the htmlText of the field in the appropriate customProp. Then it's a simple matter to find the highest number and 'undo' to the htmlText of it. StripAndShip will kill the whole property set. I'm sure you already thought of this, but thought I'd mention it anyway. -Chipp ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
Geoff Canyon wrote: I would store a list of transcript statements designed to undo/redo the things you are doing. So if you move a rectangle to 100,300 I would get the long id of the rectangle and do something like this: put "set the loc of" && it && "to" && tNewLoc & cr after gRedoString put "set the loc of" && it && "to" && the loc of it & cr before gUndoString set the loc of it to tNewLoc I did something like this for fields and found it to be remarkably fast and efficient. The really great aspect is that you can undo/redo an arbitrary number of steps with one command: do line 1 to 100 of gUndoString undoes 100 steps, etc. That's prettyt much where I'm headed now, but there's one aspect that's still problematic: Rev's built-in undo for text editing operations is something I don't want to replicate. For a single-level Undo it's easy enough to put a flag in the undo string to tell it to use the built-in undo command rather than any custom routine. But how would one handle this for multi-level undo? -- Richard Gaskin Fourth World Media Corporation ___ [EMAIL PROTECTED] http://www.FourthWorld.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
I would store a list of transcript statements designed to undo/redo the things you are doing. So if you move a rectangle to 100,300 I would get the long id of the rectangle and do something like this: put "set the loc of" && it && "to" && tNewLoc & cr after gRedoString put "set the loc of" && it && "to" && the loc of it & cr before gUndoString set the loc of it to tNewLoc I did something like this for fields and found it to be remarkably fast and efficient. The really great aspect is that you can undo/redo an arbitrary number of steps with one command: do line 1 to 100 of gUndoString undoes 100 steps, etc. On Feb 18, 2005, at 1:40 PM, Richard Gaskin wrote: I can see how that approach would be useful for some apps, but this one has a large stack and the changes made a very small (moving objects, deleting objects, etc.). regards, Geoff Canyon [EMAIL PROTECTED] ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
RE: general undo methods?
OK, it's starting to take shape... selections are recorded, compared with the last one, i got a control footprint with incremental temporal versioning near ready, deselections are recorded too, choice of content/control editing changes, saving of changes is there too. I got to add in the checks for field style: html, rtf or text or both three, the redo for "other" controls... and the hotkeys management and we're rolling for testing! Recording a macro is possible too I guess! Just another flag maybe. I already handle multiple objects... ;) Left to do Record all the props! Purge duplicate actions? Undo text/time frames if viable Then we got also coming - undo action filters (stick to the essentials) - redo last actions from a list, recreate a clone of the object as it was. - Reports, save or print out the changes done to stacks anyone? Hey, for project time-logging purposes... why not! Most events and controls keys are logged including copy, paste, delete or backspace, new and delete controls or cards are also in... Since we got a GUI, im going to also add menus for pasting previous clipboard texts or images. Controls is a different container I haven't mastered yet which will take extra code... Watching for dangerous redos and allowing for undo and redo exceptions or automatic repeats is now the next task... This is also where some Mac scripters could help out for mac-specific hotkeys or cutting down the scripting time. Amazing how a little stack can grow! http://www.monsieurx.com/modules.php?name=News&file=article&sid=170 I'll post the update soon... For the Curious and Testers only... cheers Xavier > -Original Message- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED] On Behalf Of MisterX > Sent: Saturday, February 19, 2005 11:01 > To: 'How to use Revolution' > Subject: RE: general undo methods? > > > I think I'll have an undo method working for HotkeysN2O in a > couple hours ;) > > If you want to test it, let me know... > > > -Original Message- > > From: [EMAIL PROTECTED] > > [mailto:[EMAIL PROTECTED] On Behalf > Of Richard > > Gaskin > > Sent: Friday, February 18, 2005 21:54 > > To: How to use Revolution > > Subject: general undo methods? > > > > I need to add more extensive undo to an app I'm working on. > > Seems like a lot of work once you step outside of the > subset of things > > the engine takes care of for you. > > > > Any of you have pointers to general methods for implemening undo > > across an app? > > > > -- > > Richard Gaskin > > Fourth World Media Corporation > > ___ > > [EMAIL PROTECTED] http://www.FourthWorld.com > > ___ > > use-revolution mailing list > > use-revolution@lists.runrev.com > > http://lists.runrev.com/mailman/listinfo/use-revolution > > > > ___ > use-revolution mailing list > use-revolution@lists.runrev.com > http://lists.runrev.com/mailman/listinfo/use-revolution > ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
RE: general undo methods?
I think I'll have an undo method working for HotkeysN2O in a couple hours ;) If you want to test it, let me know... > -Original Message- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED] On Behalf Of > Richard Gaskin > Sent: Friday, February 18, 2005 21:54 > To: How to use Revolution > Subject: general undo methods? > > I need to add more extensive undo to an app I'm working on. > Seems like a lot of work once you step outside of the subset > of things the engine takes care of for you. > > Any of you have pointers to general methods for implemening > undo across an app? > > -- > Richard Gaskin > Fourth World Media Corporation > ___ > [EMAIL PROTECTED] http://www.FourthWorld.com > ___ > use-revolution mailing list > use-revolution@lists.runrev.com > http://lists.runrev.com/mailman/listinfo/use-revolution > ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
Martin Baxter wrote: The only time I did this seriously was a while back and in Hypercard. I had a specialised multimedia authoring environment for teaching purposes that (among other things) implemented a custom interface to addColor. I used the approach you describe above, but instead of storing state information, I stored a statement that could be executed, using Do, which would reverse the action in question. So for example if the user created a rectangle, the undo list would contain something to the effect of: delete graphic "grcname" # (I forget the actual syntax now that it no longer matters) It worked well, and allowed the actual undo handler to be very short and very dumb. As has been noted however, different types of undo action may require a range of strategies. That seems to be the simplist approach. Tedious to setup on an existing app, but it does seem to represent the most useful dividing lines between centralizing code and handling a wide range of circumstances. Off to go write libUndo -- Richard Gaskin Fourth World Media Corporation ___ [EMAIL PROTECTED] http://www.FourthWorld.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
> > On Feb 18, 2005, at 3:53 PM, Richard Gaskin wrote: >> > >> Any of you have pointers to general methods for implemening undo > >> across an app? >The general method is to atomize your code so that every action the user >can do generates undo code stored in a queue, which is then invoked when >Undo is selected. >-- The only time I did this seriously was a while back and in Hypercard. I had a specialised multimedia authoring environment for teaching purposes that (among other things) implemented a custom interface to addColor. I used the approach you describe above, but instead of storing state information, I stored a statement that could be executed, using Do, which would reverse the action in question. So for example if the user created a rectangle, the undo list would contain something to the effect of: delete graphic "grcname" # (I forget the actual syntax now that it no longer matters) It worked well, and allowed the actual undo handler to be very short and very dumb. As has been noted however, different types of undo action may require a range of strategies. A snack for thought, Martin Baxter ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
In Smalltalk and probably in Java as well there was/is the notion of an undo/redo framework. The Command Pattern, for example, is designed for just this task. If we could design a framework, it should be possible for us to come up with a way for us to define user events in such a way that they "notify" the proper object(s) in the framework when they change. It would be a fascinating exercise and result in a potentially highly useful product, I think. It would probably have to be limited to certain types or categories of changes, but it does seem to me it would be feasible with sufficiently high levels of scripting skills. Dan On Feb 18, 2005, at 9:26 PM, J. Landman Gay wrote: On 2/18/05 6:53 PM, Richard Gaskin wrote: I just spent the last two hours reading up on how undo is done in other systems, and it seems that there is no magic panaea in any of them. Good undo is simply a lot of work. The general method is to atomize your code so that every action the user can do generates undo code stored in a queue, which is then invoked when Undo is selected. I wrote an extended undo for two different apps, and in both cases I used the general method you describe. One stack was my Klondike game, and "undo" in that one wasn't too hard. Since the game already needed to track the location of every playing card in the deck, I stored a line of text describing the location of all the cards after every user move, and pushed the line onto a "done" list. When the user chose "undo", I popped the top line off the list and reset the playing cards to the positions it described. At the same time, I pushed the line onto a "redo" list. This allowed unlimited undo/redo. I just kept moving the descriptive line from one list to the other. This would be hard to do in a stack that didn't lend itself to a way of storing a list of user actions. The other stack was a client project, and that was more difficult because the user actions were more varied. I used a similar method, but did not store everything the user did. They were allowed to undo only certain things that I could easily track. Other things just got lost. They complained a little bit, but not too much after I explained how much it would cost them to implement any more. Customers don't always understand how much work it is to implement "undo", since virtually all software has it. To them, it seems like it should be simple. -- Jacqueline Landman Gay | [EMAIL PROTECTED] HyperActive Software | http://www.hyperactivesw.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
RE: general undo methods?
im replying to this soon... > -Original Message- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED] On Behalf Of > Richard Gaskin > Sent: Saturday, February 19, 2005 06:42 > To: How to use Revolution > Subject: Re: general undo methods? > > J. Landman Gay wrote: > > On 2/18/05 6:53 PM, Richard Gaskin wrote: > > > >> I just spent the last two hours reading up on how undo is > done in >> other systems, and it seems that there is no > magic panaea in any of >> them. Good undo is simply a lot of work. > >> > >> The general method is to atomize your code so that every > action the >> user can do generates undo code stored in a > queue, which is then >> invoked when Undo is selected. > > > > Customers don't always understand how much work it is to > implement > "undo", since virtually all software has it. To > them, it seems like > it should be simple. > > When we consider how far Rev has gone with the hardest part, > text undo, I can't help but wonder if there might be some > general state-recording mechanism that could be created in > such a way as to be scalable to address specific needs. > > But I'm also sleep-deprived, and possibly dreaming... > > -- > Richard Gaskin > Fourth World Media Corporation > ___ > [EMAIL PROTECTED] http://www.FourthWorld.com > > ___ > use-revolution mailing list > use-revolution@lists.runrev.com > http://lists.runrev.com/mailman/listinfo/use-revolution > ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
J. Landman Gay wrote: > On 2/18/05 6:53 PM, Richard Gaskin wrote: > >> I just spent the last two hours reading up on how undo is done in >> other systems, and it seems that there is no magic panaea in any of >> them. Good undo is simply a lot of work. >> >> The general method is to atomize your code so that every action the >> user can do generates undo code stored in a queue, which is then >> invoked when Undo is selected. > > Customers don't always understand how much work it is to implement > "undo", since virtually all software has it. To them, it seems like > it should be simple. When we consider how far Rev has gone with the hardest part, text undo, I can't help but wonder if there might be some general state-recording mechanism that could be created in such a way as to be scalable to address specific needs. But I'm also sleep-deprived, and possibly dreaming... -- Richard Gaskin Fourth World Media Corporation ___ [EMAIL PROTECTED] http://www.FourthWorld.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
On 2/18/05 6:53 PM, Richard Gaskin wrote: I just spent the last two hours reading up on how undo is done in other systems, and it seems that there is no magic panaea in any of them. Good undo is simply a lot of work. The general method is to atomize your code so that every action the user can do generates undo code stored in a queue, which is then invoked when Undo is selected. I wrote an extended undo for two different apps, and in both cases I used the general method you describe. One stack was my Klondike game, and "undo" in that one wasn't too hard. Since the game already needed to track the location of every playing card in the deck, I stored a line of text describing the location of all the cards after every user move, and pushed the line onto a "done" list. When the user chose "undo", I popped the top line off the list and reset the playing cards to the positions it described. At the same time, I pushed the line onto a "redo" list. This allowed unlimited undo/redo. I just kept moving the descriptive line from one list to the other. This would be hard to do in a stack that didn't lend itself to a way of storing a list of user actions. The other stack was a client project, and that was more difficult because the user actions were more varied. I used a similar method, but did not store everything the user did. They were allowed to undo only certain things that I could easily track. Other things just got lost. They complained a little bit, but not too much after I explained how much it would cost them to implement any more. Customers don't always understand how much work it is to implement "undo", since virtually all software has it. To them, it seems like it should be simple. -- Jacqueline Landman Gay | [EMAIL PROTECTED] HyperActive Software | http://www.hyperactivesw.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
To a zeroeth approximation, use a frontscript or backscript to keep a realtime-updated record of *everything* the user does (for whatever value of "everything" you deem relevant or comfortable or etc). This record should, in each specific item, include enough information that you can reconstruct what changed in each item. For instance: delta 000111,graphic "fred" of card "george" of stack "harry",points changed from "yada yada" to "aday aday" It seems to me that something like UmbrellaMan might be a suitable foundation on which to start building a generalized Undo. ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
On Feb 18, 2005, at 4:53 PM, Richard Gaskin wrote: Good undo is simply a lot of work. Yep Looks like I've found my presentation topic for the Monterey conference And yep! Dan ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
Thomas McGrath III wrote: > On Feb 18, 2005, at 3:53 PM, Richard Gaskin wrote: > >> I need to add more extensive undo to an app I'm working on. Seems >> like a lot of work once you step outside of the subset of things the >> engine takes care of for you. >> >> Any of you have pointers to general methods for implemening undo >> across an app? > > If your using substacks you can save in different states (upon any > changes or significant changes) with a smart numbering system(backup > system) and then if/when the user saves, it writes a final version and > deletes the previous ones. > That's the simpler way. > > Other wise all kinds of things need to be kept track off to be able to > undo them. I just spent the last two hours reading up on how undo is done in other systems, and it seems that there is no magic panaea in any of them. Good undo is simply a lot of work. The general method is to atomize your code so that every action the user can do generates undo code stored in a queue, which is then invoked when Undo is selected. The discipline of writing such well-factored code appeals to the OCD side of me, but the need to do it in short order to get a project out the door doesn't. :) Looks like I've found my presentation topic for the Monterey conference -- Richard Gaskin Fourth World Media Corporation ___ [EMAIL PROTECTED] http://www.FourthWorld.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
If your using substacks you can save in different states (upon any changes or significant changes) with a smart numbering system(backup system) and then if/when the user saves, it writes a final version and deletes the previous ones. That's the simpler way. Other wise all kinds of things need to be kept track off to be able to undo them. TOM On Feb 18, 2005, at 3:53 PM, Richard Gaskin wrote: I need to add more extensive undo to an app I'm working on. Seems like a lot of work once you step outside of the subset of things the engine takes care of for you. Any of you have pointers to general methods for implemening undo across an app? -- Richard Gaskin Thomas J. McGrath III SCS 1000 Killarney Dr. Pittsburgh, PA 15234 412-885-8541 ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
Re: general undo methods?
Lynch, Jonathan wrote: >> I need to add more extensive undo to an app I'm working on. >> Seems like a lot of work once you step outside of the subset >> of things the engine takes care of for you. >> >> Any of you have pointers to general methods for implemening >> undo across an app? > > You could set it up so that every time you make a change, > you create a copy of the stack in memory. Actually, have > like 5 copies of the stack in memory, and for each change, > you replace one of those stacks, and keep a list in a > global variable of where you are in the rotation through > those five copies in memory I can see how that approach would be useful for some apps, but this one has a large stack and the changes made a very small (moving objects, deleting objects, etc.). Anyone have a link to a good paper on how folks handle undo in "real" apps? -- Richard Gaskin Fourth World Media Corporation ___ [EMAIL PROTECTED] http://www.FourthWorld.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution
RE: general undo methods?
Hi Richard... I have a suggestion that might work, if the memory requirements of your app are not too large. You could set it up so that every time you make a change, you create a copy of the stack in memory. Actually, have like 5 copies of the stack in memory, and for each change, you replace one of those stacks, and keep a list in a global variable of where you are in the rotation through those five copies in memory, so that you will always be able to recall the latest stored version, and go back at least four more steps beyond that. Once you get to a sixth copy in memory, you purge the first copy, and at a 7th copy in memory, you purge the 2nd copy, etc... Does that make sense? I can see the process in my head, but seem to have a hard time putting it into words. This would work if it was a handler that you called in various scripts - but not for all keystrokes. For fields, you could have it in a closefield handler, for buttons, you could have at the end of the process of whatever the button does. Obviously, this would too burdensome to use for every keyup event in a field. What do you think? -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Richard Gaskin Sent: Friday, February 18, 2005 3:54 PM To: How to use Revolution Subject: general undo methods? I need to add more extensive undo to an app I'm working on. Seems like a lot of work once you step outside of the subset of things the engine takes care of for you. Any of you have pointers to general methods for implemening undo across an app? -- Richard Gaskin Fourth World Media Corporation ___ [EMAIL PROTECTED] http://www.FourthWorld.com ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution ___ use-revolution mailing list use-revolution@lists.runrev.com http://lists.runrev.com/mailman/listinfo/use-revolution