# An undo and redo button for my drawing program

**URL:** <https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194>\
**Category:** Coding Questions\
**Tags:** homework\
**Created:** [May 20, 2021, 3:54pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194 "2021-05-20T15:54:47Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kenga123456](https://avatars.discourse-cdn.com/v4/letter/k/f08c70/32.png) [@Kenga123456](https://discourse.processing.org/u/Kenga123456)\
**Post date:** [May 20, 2021, 3:54pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/1 "2021-05-20T15:54:47Z")

</div>

I have seen other peoples code of how to do it but I can’t seem to fully understand how it works. Especially when they have arrays and stuff. Someone please explain to me.

---

<div class="post-metadata">

**Author:** ![paulgoux](https://avatars.discourse-cdn.com/v4/letter/p/b9bd4f/32.png) [@paulgoux](https://discourse.processing.org/u/paulgoux)\
**Post date:** [May 20, 2021, 4:15pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/2 "2021-05-20T16:15:34Z")

</div>

Here is a sketch with two different buttons. I have added click functionality. This is set to true when mouse is pressed.

The functionality you add to that is up to you.

```auto
Button b;
Button2 b1;

void setup(){
  size(400,400);
  b = new Button(20,20,"Test");
  b1 = new Button2(60,20,90,30,"Test");
};

void draw(){
  b.display();
  if(b.click())println(b.label);
  b1.display();
  if(b1.click())println(b1.label);
};

class Button {

  PVector pos;
  String label;
  int radius = 20;
  boolean mdown,toggle,click,m2down;

  Button(float _x, float _y, String _label) {
    pos = new PVector(_x, _y);
    label = _label;
  }

  void display() {
    if (pos()) fill(220);
    else noFill();
    stroke(150);
    ellipse(pos.x, pos.y, radius*2, radius*2);
    fill(150);
    text(label, pos.x-13, pos.y+4);
  }

  void toggle() {
    
    if (pos()&&mousePressed&&!mdown)mdown = true;
    if(!mdown&&!toggle){
      
      toggle = true;
      m2down = true;
    }
    if(!mdown&&toggle){
      toggle = false;
      m2down = true;
    }
    
    if(!mousePressed){
      mdown = false;
      m2down = false;
    }
    
  };
  
  boolean click(){
      boolean k = false;
      if (pos()&&mousePressed&&!click){
        click = true;
        k = true;
      }
      if(!mousePressed)click = false;
      
      return k;
  };
  
  boolean pos(){
    PVector mouse = new PVector(mouseX, mouseY);
    return mouse.dist(pos) < radius;
  };
  
  boolean hold(){
    if(mdown)return true;
    else return false;
      
  };
  
};

class Button2{
  
  float x,y,w,h;
  boolean mclick,mdown,click;
  String label;
  
  Button2(){
    
  };
  
  Button2(float x,float y,float w,float h,String label){
    
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.label = label;
    
    if(this.w<textWidth(label)+5)this.w = textWidth(label)+5;
    
  };
  
  void display(){
    
    fill(255);
    if(pos())fill(200);
    stroke(200);
    strokeWeight(1);
    noStroke();
    rect(x,y,w,h);
    fill(50);
    text(label,x+2,y+14);
    
    //logic();
    //click = false;
    
  };
  
  boolean click(){
      boolean k = false;
      if (pos()&&mousePressed&&!click){
        click = true;
        k = true;
      }
      if(!mousePressed)click = false;
      
      return k;
  };
  
  boolean mouseDown(){
    boolean k = false;
    if(pos()&&mousePressed)k = true;
    if(!mousePressed)k = false;
    return k;
  };
  
  
  boolean pos(){
    return mouseX>x&&mouseX<x+w&&mouseY>y&&mouseY<y+h;
  };
  
};

```

seperate button classes  
button 1;

```auto
class Button {

  PVector pos;
  String label;
  int radius = 20;
  boolean mdown,toggle,click,m2down;

  Button(float _x, float _y, String _label) {
    pos = new PVector(_x, _y);
    label = _label;
  }

  void display() {
    if (pos()) fill(220);
    else noFill();
    stroke(150);
    ellipse(pos.x, pos.y, radius*2, radius*2);
    fill(150);
    text(label, pos.x-13, pos.y+4);
  }

  void toggle() {
    
    if (pos()&&mousePressed&&!mdown)mdown = true;
    if(!mdown&&!toggle){
      
      toggle = true;
      m2down = true;
    }
    if(!mdown&&toggle){
      toggle = false;
      m2down = true;
    }
    
    if(!mousePressed){
      mdown = false;
      m2down = false;
    }
    
  };
  
  boolean click(){
      boolean k = false;
      if (pos()&&mousePressed&&!click){
        click = true;
        k = true;
      }
      if(!mousePressed)click = false;
      
      return k;
  };
  
  boolean pos(){
    PVector mouse = new PVector(mouseX, mouseY);
    return mouse.dist(pos) < radius;
  };
  
  boolean hold(){
    if(mdown)return true;
    else return false;
      
  };
  
};

```

button 2

```auto
class Button2{
  
  float x,y,w,h;
  boolean mclick,mdown,click;
  String label;
  
  Button2(){
    
  };
  
  Button2(float x,float y,float w,float h,String label){
    
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.label = label;
    
    if(this.w<textWidth(label)+5)this.w = textWidth(label)+5;
    
  };
  
  void display(){
    
    fill(255);
    if(pos())fill(200);
    stroke(200);
    strokeWeight(1);
    noStroke();
    rect(x,y,w,h);
    fill(50);
    text(label,x+2,y+14);
    
    //logic();
    //click = false;
    
  };
  
  boolean click(){
      boolean k = false;
      if (pos()&&mousePressed&&!click){
        click = true;
        k = true;
      }
      if(!mousePressed)click = false;
      
      return k;
  };
  
  boolean mouseDown(){
    boolean k = false;
    if(pos()&&mousePressed)k = true;
    if(!mousePressed)k = false;
    return k;
  };
  
  
  boolean pos(){
    return mouseX>x&&mouseX<x+w&&mouseY>y&&mouseY<y+h;
  };
  
};

```

---

<div class="post-metadata">

**Author:** ![paulgoux](https://avatars.discourse-cdn.com/v4/letter/p/b9bd4f/32.png) [@paulgoux](https://discourse.processing.org/u/paulgoux)\
**Post date:** [May 20, 2021, 4:17pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/3 "2021-05-20T16:17:46Z")

</div>

Alternatively feel free to use controlp5 or g4p

---

<div class="post-metadata">

**Author:** ![debxyz](https://avatars.discourse-cdn.com/v4/letter/d/58956e/32.png) [@debxyz](https://discourse.processing.org/u/debxyz)\
**Post date:** [May 20, 2021, 5:23pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/4 "2021-05-20T17:23:14Z")

</div>

Hello!  
Are you talking about a button that functions like an on-off switch?

---

<div class="post-metadata">

**Author:** ![Kenga123456](https://avatars.discourse-cdn.com/v4/letter/k/f08c70/32.png) [@Kenga123456](https://discourse.processing.org/u/Kenga123456)\
**Post date:** [May 20, 2021, 6:44pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/5 "2021-05-20T18:44:03Z")

</div>

Can you explain a bit of the logic behind this code? I still don’t quite understand

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 20, 2021, 7:27pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/6 "2021-05-20T19:27:09Z")

</div>

Are you interested in

- how a button (for the mouse) might work (no matter its function) (see code by paulgoux) OR
- how to do undo and redo? (Even with keyboard)

The latter depends very strong on how your drawing Sketch stores the shapes.

- Do you just put new shapes on the canvas (without using `background()` in `draw()`)? Then you could store every image/frame (before a change is drawn) in an array using get() and use undo in that array OR
- do you have all shapes in an ArrayList? Then this Sketch is useful for you.

**Sketch for an ArrayList**

```auto
ArrayList<PVector> list = new ArrayList(); 

void setup() {
  size(400, 400);
}

void draw() {
  background(0); 

  text("click mouse, Backspace to undo", 17, 17);

  for (PVector pv : list)
    ellipse(pv.x, pv.y, 
      19, 19);
}

void mousePressed() {
  list.add(new PVector(mouseX, mouseY));
}

void keyPressed() {
  if (key==BACKSPACE) 
    if (list.size()>0)
      list.remove(list.size()-1);
}

// ==================================================

```

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 20, 2021, 7:40pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/7 "2021-05-20T19:40:23Z")

</div>

> [@Kenga123456](#):
>
> Can you explain a bit of the logic behind this code? I still don’t quite understand

What part don’t you understand? To explain the _entire_ Sketch is a bit much to ask.

**Explanation**

The Sketch by paulgoux just shows 2 buttons _ **without** _ undo/redo. (The `};` is the same as `}` by the way.)

It uses objects, are you familiar with this paradigm of OOP?

see [Objects / Processing.org](https://www.processing.org/tutorials/objects/)

We have 2 different classes and 2 buttons derived from them.

Hey, and welcome to the forum! Great to have you here!

Warm regards,

Chrisir 😉

---

<div class="post-metadata">

**Author:** ![Kenga123456](https://avatars.discourse-cdn.com/v4/letter/k/f08c70/32.png) [@Kenga123456](https://discourse.processing.org/u/Kenga123456)\
**Post date:** [May 20, 2021, 8:39pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/8 "2021-05-20T20:39:05Z")

</div>

Thanks for the welcome! Tbh I feel like these codes are above my level in several ways as I don’t understand too much of them (especially arrays). I will probably just try to learn a bit more about the codes in processing before I attempt to do this.

---

<div class="post-metadata">

**Author:** ![paulgoux](https://avatars.discourse-cdn.com/v4/letter/p/b9bd4f/32.png) [@paulgoux](https://discourse.processing.org/u/paulgoux)\
**Post date:** [May 20, 2021, 8:45pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/9 "2021-05-20T20:45:24Z")

</div>

a slightly simpler sketch it holds only two states. It outputs a toggle boolean. Its up to you to add conditions and code based on the state of the toggle which can be either true or false;

```auto
boolean click, toggle;

void setup() {
  size(600,600);
};

void draw() {
  background(50);
  fill(255);
  rect(200, 200, 200, 50);
  click();
};
//check if mouse has been clicked
boolean click() {
  boolean k = false;
  if (pos()&&mousePressed&&!click) {
    click = true;
    
  } else if (click&&!mousePressed) {
    k = true;
    click = false;
  }
//this now assigns your toggle variable
  if (k&&toggle)toggle = false;
  else if (k&&!toggle)toggle = true;
  if (k)println("toggle", toggle);
  return k;
};
// this checks the location of the mouse 
boolean pos() {
  return mouseX>200&&mouseX<200+400&&mouseY>200&&mouseY<200+50;
};

```

---

<div class="post-metadata">

**Author:** ![paulgoux](https://avatars.discourse-cdn.com/v4/letter/p/b9bd4f/32.png) [@paulgoux](https://discourse.processing.org/u/paulgoux)\
**Post date:** [May 20, 2021, 8:49pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/10 "2021-05-20T20:49:23Z")

</div>

simpler still, this makes use of processing’s own mousePressed function

```auto
boolean click, toggle;

void setup() {
  size(600,600);
};

void draw() {
  background(50);
  fill(255);
  if(toggle)fill(255,50);
  rect(200, 200, 200, 50);
};

void mousePressed(){
  if(pos()){
    if(toggle)toggle = false;
    else toggle = true;
    println("toggle", toggle);
  }
};

boolean pos() {
  return mouseX>200&&mouseX<200+400&&mouseY>200&&mouseY<200+50;
};

```

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 21, 2021, 8:31am UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/11 "2021-05-21T08:31:54Z")

</div>

You don’t need ; after }

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 21, 2021, 9:14am UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/12 "2021-05-21T09:14:09Z")

</div>

> [@Kenga123456](#):
>
> Tbh I feel like these codes are above my level in several ways as I don’t understand too much of them (especially arrays). I will probably just try to learn a bit more about the codes in processing before I attempt to do this.

Hello,

Learning is the fun part!

There are lots of resources (tutorials, references, examples, etc.) here:  
_[processing.org](http://processing.org)_

Check out the examples that come with Processing.  
These are in the menu under _File \> Examples…\>_ :

![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/3/35f05e0e0227932c25f0c7f86269d86609c2c294.png)

Also check out YouTube for the [Coding Train](https://www.youtube.com/channel/UCvjgXvBlbQiydffZU7m1_aw).

There are _arrays_ and _ArrayLists_:

- [Array / Reference / Processing.org](https://www.processing.org/reference/Array.html)
- [ArrayList / Reference / Processing.org](https://processing.org/reference/ArrayList.html)
- _[Arrays / Processing.org](https://processing.org/tutorials/arrays/)_

Example of mouse movement displaying elements of array:

```auto
// Array Example
// v1.0.0
// GLV 2021-05-21

// Declare arrays for x, y; can be replace with PVectors later!
int x[] = new int[100];
int y[] = new int[100];

//Runs once
void setup() 
  {
  size(500, 500);
  
  // Shows initial values of array... all 0
  //printArray(x); 
  //printArray(y);
  
  //Initialize values of array with random values
  for(int i = 0; i<100; i++)
    {
    x[i] = int (random(width));
    y[i] = int (random(height));
    }
  
  // Shows values of array in console
  //printArray(x);
  //printArray(y);    
  }

//Loops at a rate of 60 frames per sec
void draw() 
  {
  background(0);
  strokeWeight(2);
  stroke(255, 255, 0);
  
  int max = mouseX/5; // Also see map();
  
  println(mouseX, max); // Shows values in console
  
  for(int i = 0; i<max; i++)
  //for(int i = 0; i<100; i++)
    {
    point(x[i], y[i]);
    }  
 }

```

I tried to keep it simple.

Lookup all the references such as setup(), draw(), random() and so on to fully understand them.

The various print() functions can be very helpful in coding and I use these often in development.

`:)`

---

<div class="post-metadata">

**Author:** ![pokelan](https://avatars.discourse-cdn.com/v4/letter/p/b19c9b/32.png) [@pokelan](https://discourse.processing.org/u/pokelan)\
**Post date:** [May 21, 2021, 6:09pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/13 "2021-05-21T18:09:27Z")

</div>

Hello Paul

I have a question to a part of your code. The way I try to make sense of it confuses myself 😉

```auto
void mousePressed(){
  if(pos()){ // if the boolean "pos" is true then execute the following?
    if(toggle)toggle = false; // if the boolean "toggle" is true then set it to false? would seem a little strange to me, but don't have any better idea...
    else toggle = true;
    println("toggle", toggle);
  }
};

```

Thanks for your explanation!

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 21, 2021, 7:18pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/14 "2021-05-21T19:18:39Z")

</div>

Yeah, toggle means switch it to the other value it can have.

On becomes off and vice versa

Short form: toggle = ! toggle;

---

<div class="post-metadata">

**Author:** ![paulgoux](https://avatars.discourse-cdn.com/v4/letter/p/b9bd4f/32.png) [@paulgoux](https://discourse.processing.org/u/paulgoux)\
**Post date:** [May 21, 2021, 7:19pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/15 "2021-05-21T19:19:48Z")

</div>

You have to think about what you are trying to achieve, and what the state of the bool is after each click.

Button is off  
If click  
I want button on

Now we can stop there and we could use this to trigger an event or function.

my code takes it one step further and considers what if our program does more than just set this button on.  
Or what if we want to be able to set it again later.

So do we want the button to automatically switch back to off without user input, say based on another condition, such as another bool state or an elapsed time.

Again you can choose to do nothing, or you can change it back using another condition.

In this case the condition is another button press.

Button is on  
If click  
I want button off

---

<div class="post-metadata">

**Author:** ![pokelan](https://avatars.discourse-cdn.com/v4/letter/p/b19c9b/32.png) [@pokelan](https://discourse.processing.org/u/pokelan)\
**Post date:** [May 21, 2021, 7:37pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/16 "2021-05-21T19:37:04Z")

</div>

Ok. Thanks!  
Just needed some time to wrap my head around this concept ^^

---

<div class="post-metadata">

**Author:** ![Kenga123456](https://avatars.discourse-cdn.com/v4/letter/k/f08c70/32.png) [@Kenga123456](https://discourse.processing.org/u/Kenga123456)\
**Post date:** [May 24, 2021, 4:43pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/17 "2021-05-24T16:43:15Z")

</div>

I’m wondering how I can store images before and after a change has been made to the drawing and call it by either tapping undo(deletes the previous action) or redo which restores the thing previously undone using undo button

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 24, 2021, 9:07pm UTC](https://discourse.processing.org/t/an-undo-and-redo-button-for-my-drawing-program/30194/18 "2021-05-24T21:07:18Z")

</div>

```auto

color[] c = new color[3];
int x;
int i = 40; 
int index; 

PImage[] listForUndo = new PImage[0]; 

void setup() {
  size(1400, 400);

  c[0]=color(255, 0, 0); // first color
  c[1]=color(0, 255, 0); // second
  c[2]=color(0, 0, 255); // third

  listForUndo = (PImage[]) append(listForUndo, get() ); // append
  index++;
}

void draw() {
  //
}//func

void keyPressed() {

  if (key==BACKSPACE) {
    //UNDO
    index--;
    if (index<0)
      index=0; 
    image(listForUndo[index], 0, 0);
    return;
  }

  if (keyCode==RIGHT) {
    //REDO
    index++; 
    if (index>=listForUndo.length-1)
      index=listForUndo.length-1; 
    image(listForUndo[index], 0, 0);
    return;
  }

  if (key==' ') {

    fill(c[x]);
    ellipse(i, 100, 30, 80);
    i+=80;

    listForUndo = (PImage[]) append(listForUndo, get() ); // append
    index++; 

    x = x + 1;
    if (x>2) { 
      x=0;
    }
    return;
  }
}
//

```
