List, Canvas: Paintpot mod undo and redo

3,628 views
Skip to first unread message

Scott Ferguson

unread,
Aug 10, 2014, 8:36:54 AM8/10/14
to
20140810:

UndoRedo2.aia

I have reworked the project to include undo on the color setting.
A list of lists with an index pointer is used to simplify the design which replaces the more complex doubly-linked list structure.




20140806:
This project was done with AI2 blocks also.

Here are the blocks for the AI2 version:

It uses a doubly-linked list and is identical to the AI Classic version.



Also, see the attached aia file.
---

My first attempt at undoing an action on the drawing canvas used a stack and was much simpler than this implementation. But I could not figure out how to easily add a redo feature which is common in many software packages. A doubly-linked list worked well in this case because it allows easy movement backwards to undo operations and forwards to repeat operations.

If you are not familiar with the concept of a doubly-linked list, it is explained HERE. I used it to store the operation and it's values in a list that includes a way to get to the previous operation that was performed (undo) and to get to the next one to be performed (redo).
The operations that need to be remembered in this example are all of the <canvas>.DrawLine and it's 4 x,y tags.

Here's the simplified Hello Kitty app with just the Drawline tool enabled.
The default line width is 2, and PaintColor is RED. By dragging a finger on the screen a line is drawn - in this case, glasses with a nose support...

The nose support was the last thing drawn, and we want to do a monacle on the left eye instead, so the nose support is removed...

And the handle for the monacle added...



Screen Designer:

Blocks:

A block is created to help add the Drawline data to the list. Notice that it begins and ends with two number sevens. Those two 7's are the distance from the start of this group of items to the next and from the end of the group to the previous group in the list. This is the double-linking of the doubly-linked list. For other operations you will need to make similar blocks to handle tools like 
DrawText, DrawCircle, etc.

The undo and redo functions just navigate backward or forward , get the operation to be performed and the data, then call the DrawLine block. The only difference between the two is that for undoing a drawn line, the PaintColor must be set to NONE before the line is drawn which erases the line that was previously drawn there.

Here is a closeup of the blocks needed for the DrawLine tool. To add other tools like DrawText or DrawCircle, etc. you need to add blocks like these here for them:



UndoRedoAndLinkedLists.zip
UndoRedoAndLinkedLists.aia
UndoRedo2.aia

thrishul h

unread,
Nov 8, 2015, 9:20:49 AM11/8/15
to App Inventor Developers Library
hI SCOTT REALY NICE BUT HOW TO UNDO A DOT

Scott Ferguson

unread,
Nov 8, 2015, 9:51:25 AM11/8/15
to App Inventor Developers Library
To undo anything 'properly' you must first save the commands that were entered in a list.
This may include any PaintColor changes that were made.
Next you clear the canvas.
Then redraw everything that was drawn from the top of the list to the second to last item (the dot that was drawn).
So if the second-to-last operation was to also draw a dot, you would need to store at least the x,y values of that dot in order to redraw it.
For DrawLine, you would need to store x1,y1,x2,y2 in the list.
So each item in the undo list would contain rows of values for each operation -- a list of lists.

In general one way to do it would look like

:
"color",<color number>
"drawline",4,23,6,1
"point",34,23
:

If all you did was drawlines or draw points then you could eliminate the first item in the sublists and just store the x,y values.
---
sf

Uma Bhat

unread,
Dec 14, 2015, 12:34:29 AM12/14/15
to App Inventor Developers Library
 
I stumbled upon UndoRedo2 while searching for ways to improvise my project. It works wonderfully.  May I suggest a small change? 

While undoing the line-width of the redrawn lines should be slightly more than that of the line saved in the UndoRedo list. Otherwise, it leaves a slight trace of colors on the canvas while undoing.

And is it possible to have a whole line undo-ed instead of doing it in fragments? Or is it possible to make it faster?  Like: by redrawing 3 or more lines (and removing 3 items from the list) at a time?
Please do post  if you have found anything new or interesting regarding the drawing components during the course of your experiments with AI2. It's such a joy to browse through this forum.

Regards,

Uma

Scott Ferguson

unread,
Dec 14, 2015, 5:26:38 AM12/14/15
to App Inventor Developers Library
While undoing the line-width of the redrawn lines should be slightly more than that of the line saved in the UndoRedo list. Otherwise, it leaves a slight trace of colors on the canvas while undoing.
Thanks for that tip :)

And is it possible to have a whole line undo-ed instead of doing it in fragments? Or is it possible to make it faster?
I see only three options.
Option 1 is to store all movements when the Dragged event block is triggered to get the most accurate retrace for for redraw. Also the slowest.
Option 2 is to store the start of the line x,y at TouchDown and the end of the line x,y at TouchUp or at the last Dragged CurrentX, CurrentY values (stored in two global variables to be read at TouchUp) which will be fastest and coarsest unless you are drawing only straight lines.
Option 3 is to store only the x,y values for segments that are at least a certain length such as 5 or 10 pixels.
Use TouchDown x,y (or Dragged StartX,StartY?) to set two variables global StartSegX, global StartSegY values initially and mark the start of the line.
Then each time the Dragged event block is triggered, test the distance that the finger has dragged using the distance formula using global StartSegX, global StartSegY and CurrentX,CurrentY:




If the distance is not greater than or equal to the minimum number of pixels then ignore the CurrentX,CurrentY values, otherwise save the CurrentX,CurrentY values in the undo/redo list and set global StartSegX and global StartSegY  to CurrentX, CurrenY.

Upon TouchUp, add the TouchUp x,y value as the end of the last segment.
Intermediate speed and accuracy.
---
Happy Inventing!
sf

Tyson Seable

unread,
Jan 25, 2016, 11:07:36 AM1/25/16
to App Inventor Developers Library
Hey, would you be okay with me using this in one of my google play apps?

Scott Ferguson

unread,
Jan 25, 2016, 5:02:19 PM1/25/16
to App Inventor Developers Library
Sure.
Anything you find here is fair game.
---
sf
Reply all
Reply to author
Forward
0 new messages