# Google Material Design buttons in Processing ( With the ripple effect)

**URL:** <https://discourse.processing.org/t/google-material-design-buttons-in-processing-with-the-ripple-effect/25594>\
**Category:** Gallery\
**Created:** [November 21, 2020, 5:32pm UTC](https://discourse.processing.org/t/google-material-design-buttons-in-processing-with-the-ripple-effect/25594 "2020-11-21T17:32:55Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![qewer3322](https://avatars.discourse-cdn.com/v4/letter/q/e19adc/32.png) [@qewer3322](https://discourse.processing.org/u/qewer3322)\
**Post date:** [November 21, 2020, 5:32pm UTC](https://discourse.processing.org/t/google-material-design-buttons-in-processing-with-the-ripple-effect/25594/1 "2020-11-21T17:32:55Z")

</div>

I always loved the look and feel of Google’s [Material Design](https://material.io/components/buttons) components, especially the ripple effect on the buttons. And I realized it had been some time since I did something with processing so I decided to replicate it in processing and here is the result:

![LFsdYQS2Ld](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/1/1907603d162fc1579e275ce968c04d429e875c68.gif)

![JB4Nah9t5y](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/c/c50ce6628c1c7d428b41671f6ee5632f96d7dcd2.gif)

They are not particularly perfect but they work and look pretty good! I made the code as simple as I could (but it’s still kinda sphagetti). I am also going to make a material design slider, text field and some other ui elements, I hope I will be able to release all of them in a library. Feedback would be appreciated!

Note: One thing I’m not really happy about is that you need to use text offset along with the text size correctly to properly align the text on the button. I will try doing that a bit simpler.

Button:

```auto
/*
  Material Design Button | by qewer3322 | 2020
 
 PUBLIC PROPERTIES
 - x (int | x pos of the button)
 - y (int | y pos of the button)
 - w (int | width of the button)
 - h (int | height of the button)
 - mainColor (color | color of the button)
 - textColor (color | color of the button text)
 - effectColor (color | color of hover and ripple effects)
 - icon (PImage | image icon of the button)
 - text (String | text of the button)
 - textFont (PFont | font of the button text)
 - textSize (int | size of the button text)
 - textOffsetX (int | offset of the text on the x axis)
 - textOffsetY (int | offset of the text on the y axis)
 - hoverFadeSpeed (int | controls hover fade speed, default value is 5)
 - ripple speed (int | controls the speed of the ripple effect, default value is 12)
 - rippleFadeSpeed (int | controls the fade speed of the ripple effect, default value is 5)
 
 PUBLIC FUNCTIONS
 - mouseOver() (boolean | returns true when mouse hovers the button, can be used with an if statement in mouseClicked() to do something when the button is clicked)
 - display() (displays the button, should be called in draw() in order for the button to work)
 - mousePress() (registers mouse press events, should be called in mousePressed() in order for the button to work )
 - setIcon(PImage icon) (sets the image icon of the button, optional)
 - setColor(color c) (sets the color of the button, optional)
 - setColor(int r, int g, int b) (sets the color of the button, optional)
 - setEffectColor(color c) (sets the color of hover and ripple effects, optional)
 - setEffectColor(int r, int g, int b) (sets the color of hover and ripple effects, optional)
 - setText(String text) (sets the button text)
 - setTextColor(color c) (sets the color of the button text)
 - setTextColor(int r, int g, int b) (sets the color of the button text)
 - setTextFont(PFont font) (sets the font of the button text)
 - setTextSize(int size) (sets the size of the button text)
 - setTextOffset(int offsetX, int offsetY) (sets the x and y offset of the button text)
 
 Please keep this top header if you share this code
 */

class QButton {

  //x pos, y pos, width, height and corner radius
  int x;
  int y;
  int w;
  int h;
  int r;

  //color of the button
  color mainColor = color(159, 72, 217);

  //button icon
  PImage icon;

  //button text
  String text = "";

  //PGraphics object (used for the ripple effect)
  private PGraphics pg;
  //PGraphics mask object (used for the ripple effect)
  private PGraphics maskPg;

  //constructor 1
  QButton(int x1, int y1, int w1, int h1, int r1) {
    x = x1;
    y = y1;
    w = w1;
    h = h1;
    r = r1;

    pg = createGraphics(w, h);
    maskPg = createGraphics(w, h);
  }
  //constructor2
  QButton(int x1, int y1, int w1, int h1, int r1, String text1) {
    x = x1;
    y = y1;
    w = w1;
    h = h1;
    r = r1;
    text = text1;

    pg = createGraphics(w, h);
    maskPg = createGraphics(w, h);
  }

  //text font
  PFont textFont;
  //font boolean
  private boolean fontB = false;
  //text color
  color textColor = color(255);
  //text size
  int textSize = 25;
  //text offset on x axis
  int textOffsetX = 20;
  //text offset on y axis
  int textOffsetY = 20;

  //icon boolean
  private boolean iconB = false;

  //color of the ripple and hover
  color effectColor = color(255);

  //hover fade speed
  int hoverFadeSpeed = 5;
  //hover opacity
  private int hOpacity = 0;

  //ripple diameter
  int rd = 0;
  //ripple x and y
  int rx = 0;
  int ry = 0;
  //ripplevspeed
  int rippleSpeed = 15;
  //ripple boolean
  private boolean ripple = false;
  //ripple opacity
  private int rOpacity = 0;
  //ripple fade speed
  int rippleFadeSpeed = 5;

  //public fuctions
  //display function (should be called in draw() for the button to show)
  void display() {
    noStroke();

    //pgraphics (ripple)
    image(pg, x, y);

    //hover rect
    fill(effectColor, hOpacity);
    rect(x, y, w, h, r);

    //text
    if (fontB) {
      textFont(font);
    }
    textSize(textSize);
    fill(textColor);
    if (! iconB) {
      text(text, x + textOffsetX, y + textOffsetY);
    }
    if (iconB) {
      image(icon, x + int(h/4), y + int(h/4), h - int(h/2), h - int(h/2));
      text(text, x + h + textOffsetX, y + textOffsetY);
    }

    hover();
    betterRipple();
    //ripple();
  }

  //mouse press function (should be called in mousePressed() for the button to register mouse press events)
  void mousePress() {
    if (overRect(x, y, w, h)) {
      rd = 0;
      rx = mouseX - x;
      ry = mouseY - y;

      ripple = true;
      rOpacity = 80;
    }
  }

  //getters
  boolean mouseOver() {
    if (overRect(x, y, w, h)) {
      return true;
    } else return false;
  }

  //setters
  void setColor(color c) {
    mainColor = c;
  }

  void setColor(int r, int g, int b) {
    mainColor = color(r, g, b);
  }

  void setEffectColor(color c) {
    effectColor = c;
  }

  void setEffectColor(int r, int g, int b) {
    effectColor = color(r, g, b);
  }

  void setText(String str) {
    text = str;
  }

  void setTextColor(color c) {
    textColor = c;
  }

  void setTextColor(int r, int g, int b) {
    textColor = color(r, g, b);
  }

  void setTextFont(PFont font) {
    fontB = true;
    textFont = font;
  }

  void setTextSize(int s1) {
    textSize = s1;
  }

  void setTextOffset(int x1, int y1) {
    textOffsetX = x1;
    textOffsetY = y1;
  }

  void setIcon(PImage img) {
    icon = img;
    iconB = true;
  }

  //private fuctions
  //hover effect function
  private void hover() {
    if (overRect(x, y, w, h) && hOpacity < 50) {
      hOpacity += hoverFadeSpeed;
    } else if (hOpacity > 0) {
      hOpacity -= hoverFadeSpeed;
    }
  }

  //ripple test
  private void betterRipple() {
    if (ripple) {
      rd += rippleSpeed;
    }
    if (rx > w/2 && ry > h/2 && rd > dist(0,0,rx,ry) * 2) {
      ripple = false; 
    }
    if (rx >= w/2 && ry <= h/2 && rd > dist(0,h,rx,ry) * 2) {
      ripple = false; 
    }
    if (rx < w/2 && ry > h/2 && rd > dist(w,0,rx,ry) * 2) {
      ripple = false; 
    }
    if (rx <= w/2 && ry <= h/2 && rd > dist(w,h,rx,ry) * 2) {
      ripple = false; 
    }
    if (ripple == false) {
      rOpacity -= rippleFadeSpeed;
    }
    pg.beginDraw();
    pg.noStroke();
    pg.fill(mainColor);
    pg.rect(0, 0, w, h, r);
    pg.fill(effectColor, rOpacity);
    pg.ellipse(rx, ry, rd, rd);
    pg.endDraw();
    maskPg.beginDraw();
    maskPg.rect(0, 0, w, h, r);
    maskPg.endDraw();
    pg.mask(maskPg);
  }

  private boolean overRect(int x, int y, int width, int height) {
    if (mouseX >= x && mouseX <= x+width &&
      mouseY >= y && mouseY <= y+height) {
      return true;
    } else {
      return false;
    }
  }
}

```

Circle Button:

```auto
/*
  /*
  Material Design Circle Button | by qewer3322 | 2020
 
 PUBLIC PROPERTIES
 - mouseOver() (boolean | becomes true when mouse hovers the button, can be used with an if statement in mouseClicked() to do something when the button is clicked)
 - x (int | x pos of the button)
 - y (int | y pos of the button)
 - d (int | diameter of the button)
 - mainColor (color | color of the button)
 - effectColor (color | color of hover and ripple effects)
 - icon (PImage | image icon of the button)
 - hoverFadeSpeed (int | controls hover fade speed, default value is 5)
 - ripple speed (int | controls the speed of the ripple effect, default value is 8)
 - rippleFadeSpeed (int | controls the fade speed of the ripple effect, default value is 5)
 
 PUBLIC FUNCTIONS
 - display() (displays the button, should be called in draw() in order for the button to work)
 - mousePress() (registers mouse press events, should be called in mousePressed() in order for the button to work )
 - setIcon(PImage icon) (sets the image icon of the button, optional)
 - setColor(color c) (sets the color of the button, optional)
 - setColor(int r, int g, int b) (sets the color of the button, optional)
 - setEffectColor(color c) (sets the color of hover and ripple effects, optional)
 - setEffectColor(int r, int g, int b) (sets the color of hover and ripple effects, optional)
 
 Please keep this top header if you share this code
 */

class QCircleButton {

  // x pos, y pos and diameter
  int x;
  int y;
  int d;

  //color of the button
  color mainColor = color(159, 72, 217);

  //button icon
  PImage icon;

  //constructor
  QCircleButton(int x1, int y1, int d1) {
    x = x1;
    y = y1;
    d = d1;
  }

  //icon boolean
  private boolean iconB = false;

  //color of the ripple and hover
  color effectColor = color(255);

  //hover fade speed
  int hoverFadeSpeed = 5;
  //hover opacity
  private int hOpacity = 0;

  //ripple speed
  int rippleSpeed = 8;
  //ripple boolean
  private boolean ripple = false;
  //ripple fade speed
  int rippleFadeSpeed = 5;
  //ripple circle diameter
  private int rd = 0;
  //ripple opacity (used for fade)
  private int rOpacity = 80;

  //display function (should be called in draw() for the button to show)
  void display() {
    //button
    noStroke();
    fill(mainColor);
    ellipse(x, y, d, d);

    //hover circle
    noStroke();
    fill(effectColor, hOpacity);
    ellipse(x, y, d, d);

    //ripple circle
    noStroke();
    fill(effectColor, rOpacity);
    ellipse(x, y, rd, rd);
    if (rd > d) {
      rd = d;
    }

    //icon
    if (iconB) {
      image(icon, x - (d/1.5)/2, y - (d/1.5)/2, d/1.5, d/1.5);
    }

    hover();
    ripple();
  }

  //mouse press function (should be called in mousePressed() for the button to register mouse press events)
  void mousePress() {
    if (overCircle(x, y, d)) {
      ripple = true;
      rd = 0;
      rOpacity = 80;
    }
  }

  void setColor(color c) {
    mainColor = c;
  }

  void setColor(int r, int g, int b) {
    mainColor = color(r, g, b);
  }

  void setEffectColor(color c) {
    effectColor = c;
  }

  void setEffectColor(int r, int g, int b) {
    effectColor = color(r, g, b);
  }

  void setIcon(PImage img) {
    icon = img;
    iconB = true;
  }

  boolean mouseOver() {
    if (overCircle(x, y, d)) {
      return true;
    } else return false;
  }

  //hover effect function
  private void hover() {
    if (overCircle(x, y, d) && hOpacity < 50) {
      hOpacity += hoverFadeSpeed;
    } else if (hOpacity > 0) {
      hOpacity -= hoverFadeSpeed;
    }
  }

  //ripple effect function
  private void ripple() {
    if (ripple == true && rd < d) {
      rd += rippleSpeed;
    }
    if (rd == d) {
      ripple = false;
    }
    if (ripple == false) {
      rOpacity -= rippleFadeSpeed;
    }
  }

  private boolean overCircle(int x, int y, int diameter) {
    float disX = x - mouseX;
    float disY = y - mouseY;
    if (sqrt(sq(disX) + sq(disY)) < diameter/2 ) {
      return true;
    } else {
      return false;
    }
  }
}

```

Demo:

```auto
PImage plus;
QCircleButton b1 = new QCircleButton(320, 320, 80);

PFont font;
PImage star;
QButton b2;

void setup() {
  size(640, 640);
  plus = loadImage("plus.png");
  star = loadImage("star.png");
  font = createFont("Roboto-Medium.ttf", 48);

  new QButton(210, 170, 220, 60, 15, "BUTTON");
}

void draw() {
  background(get(0, 0));

  b1.setIcon(plus);
  b1.display();

  b2.setTextSize(35);
  b2.setTextFont(font);
  b2.setTextOffset(2, 44);
  b2.setIcon(star);
  b2.display();
}

void mousePressed() {
  b1.mousePress();
  b2.mousePress();
}

```

Assets for the demo:

> **[data (1) - Google Drive](https://drive.google.com/drive/folders/1SR1g1WRU2w-UgkW1YmH8Po-ar3npQNDx?usp=sharing)**

Edit: Updated the button ripple effect.

---

<div class="post-metadata">

**Author:** ![micycle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/micycle/32/201_2.png) [@micycle](https://discourse.processing.org/u/micycle)\
**Post date:** [November 21, 2020, 8:24pm UTC](https://discourse.processing.org/t/google-material-design-buttons-in-processing-with-the-ripple-effect/25594/2 "2020-11-21T20:24:59Z")

</div>

Nice. I thought about doing this recently but you’ve beat me to it 😀. I look forward to more UI elements – it’d be nice if a material UI library like this could replace CP5 since it’s pretty ugly (not to mention the API…)

---

<div class="post-metadata">

**Author:** ![micycle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/micycle/32/201_2.png) [@micycle](https://discourse.processing.org/u/micycle)\
**Post date:** [November 21, 2020, 8:37pm UTC](https://discourse.processing.org/t/google-material-design-buttons-in-processing-with-the-ripple-effect/25594/3 "2020-11-21T20:37:27Z")

</div>

Also, looks like your on-click ‘ripple effect’ is horizontal only. For a more mature design, consider porting a ripple effect from one of the [many](https://github.com/search?l=JavaScript&q=material+ripple&type=Repositories) javascript ripple libraries. It would probably boil down to overlaying a circle of growing radius which is bounded by a mask of the button.

---

<div class="post-metadata">

**Author:** ![qewer3322](https://avatars.discourse-cdn.com/v4/letter/q/e19adc/32.png) [@qewer3322](https://discourse.processing.org/u/qewer3322)\
**Post date:** [November 21, 2020, 9:02pm UTC](https://discourse.processing.org/t/google-material-design-buttons-in-processing-with-the-ripple-effect/25594/4 "2020-11-21T21:02:50Z")

</div>

Yeah it is horizontal only, I was at first going to try making it like normal ripple but I didn’t really know how to approach it so I went with 2 rectangles growing right and left. Thanks for the tip! I will look at how they did it in other libraries. If I could figure it out, I will also try making it so the ripple on the circle button starts from mouse pos rather than the center.

---

<div class="post-metadata">

**Author:** ![qewer3322](https://avatars.discourse-cdn.com/v4/letter/q/e19adc/32.png) [@qewer3322](https://discourse.processing.org/u/qewer3322)\
**Post date:** [November 23, 2020, 12:29pm UTC](https://discourse.processing.org/t/google-material-design-buttons-in-processing-with-the-ripple-effect/25594/5 "2020-11-23T12:29:51Z")

</div>

Done! Used PGraphics and PGraphics.mask()  
 ![LFsdYQS2Ld](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/1/1907603d162fc1579e275ce968c04d429e875c68.gif)  
Looks beautiful, thanks for the advice!
