Wednesday 4 November 2009

Chunk 85 - Advanced Buttons 2 (Part 5)

...... Using our button class we have the ability to create buttons of any size, set the colour and the text of the button. We can also have buttons that display an image rather than text, and to set a colour and change of image for the button if the mouse is over the button. One remaining feature that is used in applications, primarily with image buttons, is a tooltip. This is a piece of descriptive text that appears at the position of the mouse pointer, once the mouse pointer has been over a button for a period of time. This tooltip disappears after a set period, or when the mouse pointer is moved off the button.

In the final section of Advanced Buttons 2 we will add tooltip functionality to our button class.

First we need to add an instance variable to our button class in which we can hold the text of the tooltip, and we will also add a couple of instance variables to help us with the timing of the tooltip display. The constructor method will have to be changed to set the initial values for these instance
variables.

String  btnTooltip;      // Button tooltip text
int btnStartTooltip; // Countdown to displaying the tooltip
int btnStopTooltip; // Countdown to removing the tooltip

// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object creaetd
Button (int X, int Y, int W, int H)
{
.
.
.
this.btnTooltip = ""; // Default tooltip text
this.btnStartTooltip = 0; // Display started
this.btnStopTooltip = 0; // Dispaly stopped
}

A new setter method is required in order to set the value of the tooltip text for a button.

// Set the Button tooltip
public void setButtonTooltip(String tooltipText)
{
this.btnTooltip = tooltipText;
}

Changes are required in the checkMouse() method in order to start the countdowns to the display and removal of the tooltip for a button once the mouse pointer is over the button.

// Check the location of the mouse in relation to the
// button and set instance variables accordingly
private void checkMouse()
{
// Check if the mouse is over the button
boolean mOver = this.isMouseOver();

// If the mouse is over the current button
if (mOver == true)
{
// If the mouse was not already over the button
// set the start and stop counters for the
// tooltip, if we have a tooltip defined
if (this.mouseOver == false)
{
if (!this.btnTooltip.equals(""))
{
this.btnStartTooltip = 100;
this.btnStopTooltip = 500;
}
}
else
{
// The mouse pointer was already over this button so
// provided we have a tooltip defined we should be
// counting down to tooltip counters
if (!this.btnTooltip.equals(""))
{
// Provided the counter is greather than zero
// subtract one from the counter
if (this.btnStartTooltip > 0) {this.btnStartTooltip--;}
if (this.btnStopTooltip > 0) {this.btnStopTooltip--;}
}
}
}
else
{
// The mouse pointer was over this button but it is not
// now so provided we have a tooltip defined we should
// reset the tooltip counters
if (this.mouseOver == true && !this.btnTooltip.equals(""))
{
this.btnStartTooltip = 0;
this.btnStopTooltip = 0;
}
}

// Mark the button to indicate if the mouse is over it
this.mouseOver = mOver;

// If the mouse is over the button and we have a mouse over
// image defined, set the button image accordingly.
// Otherwise set to the standard image
if (this.mouseOver && this.moverImage != null)
{
this.btnImage = this.moverImage;
}
else
{
this.btnImage = this.stdImage;
}

// If the mouse is over the button and we have a mouse over
// colour defined, set the button colour accordingly.
// Otherwise set to the standard colour
if (this.mouseOver && this.moverColour != -1)
{
this.btnColour = this.moverColour;
}
else
{
this.btnColour = this.stdColour;
}
}

We need to create a new method within the button class that will draw the tooltip for a button is required, we will call this method for each button at the end of the draw() function so that the tooltip is displayed on the top of the display.

// Check if this button should have a tooltip displayed
// for it and display accordingly
private void tooltip()
{
int textWidth;
// If the mouse is over this button, and the tooltip is not
// an empty string, and the tooltip start countdown is zero
// and the tooltip stop countdown is not zero we should
// display the tooltip
if (this.mouseOver == true && ! this.tooltip.equals("") &&
this.tooltipStart == 0 && this.tooltipStop != 0)
{
// Select the font we will use for tooltips
textFont(tooltipFont,9);

// Calculate the width of the text we want to display
float textW = textWidth(this.tooltip) + 10;

// Choose the pale yellow background colour for the tooltip
fill(241,253,191);

// Draw the rectangle in which to display the tooltip text
rect( mouseX + 10, mouseY - 20, textW, 20);

// Change the colour to black
fill(0);

// Calculate the X and Y position to ensure the tooltip text is
// aligned in the centre of the tooltip rectangle
float textX = (mouseX + 10 + (textW / 2));
textX = textX - (textWidth(this.tooltip) / 2);
float textY = (mouseY - 20 + 10 ) + 4.5;

// Display the tooltip text
text(this.tooltip, textX, textY);
}
}

You will notice that we are using a new font size for the tooltip, and the code for this will need to be added to the setup() function along with a call to the setter method to set a tooltip for one of the buttons, and we will have to change the draw() function to call our tooltip() method for each button.

Button btn1;         // On Button
Button btn2; // Off Button
Button btn3; // Image Button

PFont btnFont; // Button Label Font
PFont tooltipFont; // Tooltip Font

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Load the font we want to use on the buttons
btnFont=loadFont("Verdana-Bold-12.vlw");
tooltipFont=loadFont("Verdana-9.vlw");

// Create a new button and set the colour and label
btn1 = new Button(10,365,100,25);
btn1.setButtonColour(color(128,128,255));
btn1.setMouseOverColour(color(128,128,128));
btn1.setButtonLabel("On");

// Create a new button and set the colour and label
btn2 = new Button(120,365,100,25);
btn2.setButtonColour(color(128,128,255));
btn2.setMouseOverColour(color(128,128,128));
btn2.setButtonLabel("Off");

// Create a new button and set the colour and image
btn3 = new Button(230,359,17,33);
btn3.setButtonColour(color(128,128,255));
btn3.setButtonImage("tab-unsel-menu.gif");
btn3.setMouseOverImage("tab-sel-menu.gif");
btn3.setButtonTooltip("Select Menu");

}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.checkMouse();
btn1.drawButton();

// Process button two
btn2.checkMouse();
btn2.drawButton();

// Process button three
btn3.checkMouse();
btn3.drawButton();

// Process the tooltips for each button
btn1.tooltip();
btn2.tooltip();
btn3.tooltip();

}

Now when we run our final version of the program and place our mouse over the menu button, after a few seconds we get the display shown in figure 5.0.

Figure 5.0 Mouse Over Tooltip




// Button Class
// Development of a button class - Final Stage
// 2009 Nigel Parker

Button btn1; // On Button
Button btn2; // Off Button
Button btn3; // Image Button

PFont btnFont; // Button Label Font
PFont tooltipFont; // Tooltip Font

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Load the font we want to use on the buttons
btnFont=loadFont("Verdana-Bold-12.vlw");
tooltipFont=loadFont("Verdana-9.vlw");

// Create a new button and set the colour and label
btn1 = new Button(10,365,100,25);
btn1.setButtonColour(color(128,128,255));
btn1.setMouseOverColour(color(128,128,128));
btn1.setButtonLabel("On");

// Create a new button and set the colour and label
btn2 = new Button(120,365,100,25);
btn2.setButtonColour(color(128,128,255));
btn2.setMouseOverColour(color(128,128,128));
btn2.setButtonLabel("Off");

// Create a new button and set the colour and image
btn3 = new Button(230,359,17,33);
btn3.setButtonColour(color(128,128,255));
btn3.setButtonImage("tab-unsel-menu.gif");
btn3.setMouseOverImage("tab-sel-menu.gif");
btn3.setButtonTooltip("Select Menu");

}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.checkMouse();
btn1.drawButton();

// Process button two
btn2.checkMouse();
btn2.drawButton();

// Process button three
btn3.checkMouse();
btn3.drawButton();

// Process the tooltips for each button
btn1.tooltip();
btn2.tooltip();
btn3.tooltip();

}

// Definition of a Button class that will allow us to
// create and use buttons within our processing code
class Button {

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height
color btnColour; // Button Colour
String btnText; // Button Label Text
PImage btnImage; // Button Image
boolean mouseOver; // Is mouse over button

color stdColour; // Standard Button Colour
color moverColour; // Mouse Over Button Colour
PImage stdImage; // Standard Button Image
PImage moverImage; // Mouse Over Button Image

String btnTooltip; // Button tooltip text
int btnStartTooltip; // Countdown to displaying the tooltip
int btnStopTooltip; // Countdown to removing the tooltip

// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object creaetd
Button (int X, int Y, int W, int H)
{
this.btnTopX = X; // Set Button Top X Coordinate
this.btnTopY = Y; // Set Button Top Y Coordinate
this.btnWidth = W; // Set Button Width
this.btnHeight = H; // Set Button Height
this.btnColour = -1; // Button Colour
this.btnText = ""; // Default Button Label Text
this.btnImage = null; // Button Image
this.mouseOver = false; // Mouse over button?
this.stdColour = 128; // Standard Button Colour
this.moverColour = -1; // Mouse Over Button Colour
this.stdImage = null; // Standard Button Image
this.moverImage = null; // Mouse Over Button Image
this.btnTooltip = ""; // Default tooltip text
this.btnStartTooltip = 0; // Display started
this.btnStopTooltip = 0; // Dispaly stopped
}

// Setter Methods - Methods that can be used by an
// application to set instance variables within an
// instance of the button class

// Set the Button Label Text
public void setButtonLabel(String labelText)
{
this.btnText = labelText;
}

// Set the Button Colour
public void setButtonColour(int colourValue)
{
this.stdColour = colourValue;
this.btnColour = colourValue;
}

// Set the Button Image
public void setButtonImage(String imageValue)
{
this.stdImage = loadImage(imageValue);
this.btnImage = this.stdImage;
}

// Set the MouseOver Button Colour
public void setMouseOverColour(int colourValue)
{
this.moverColour = colourValue;
}

// Set the MouseOver Button Image
public void setMouseOverImage(String imageValue)
{
this.moverImage = loadImage(imageValue);
}

// Set the Button tooltip
public void setButtonTooltip(String tooltipText)
{
this.btnTooltip = tooltipText;
}

// Draw the button on the screen
public void drawButton()
{
// Set the button colour
fill(this.btnColour);

// Draw the button
rect(this.btnTopX, this.btnTopY, this.btnWidth, this.btnHeight);

// Draw the button image
if (this.btnImage != null)
{
image(this.btnImage, this.btnTopX, this.btnTopY);
}

// Draw the button label if the text is defined (not blank)
if (! this.btnText.equals(""))
{
// Select the font for the text
textFont(btnFont,12);

// Set the colour to white
fill(255);

// Calculate the horizontal centre of the button, then subtract half
// the width of the button label to find the starting position
float textX = (this.btnTopX + this.btnWidth / 2) - (textWidth(this.btnText) / 2);

// Calculate the vertical centre of the button
float textY = (this.btnTopY + this.btnHeight / 2) + 6;

// Output the text
text(this.btnText, textX, textY);
}
}

// Check if the mouse is currently positioned over the button
private boolean isMouseOver() {
if (mouseX >= this.btnTopX && mouseX <= this.btnTopX + this.btnWidth &&
mouseY >= this.btnTopY && mouseY <= this.btnTopY + this.btnHeight) {
return true;
}
else {
return false;
}
}

// Check the location of the mouse in relation to the
// button and set instance variables accordingly
private void checkMouse()
{
// Check if the mouse is over the button
boolean mOver = this.isMouseOver();

// If the mouse is over the current button
if (mOver == true)
{
// If the mouse was not already over the button
// set the start and stop counters for the
// tooltip, if we have a tooltip defined
if (this.mouseOver == false)
{
if (!this.btnTooltip.equals(""))
{
this.btnStartTooltip = 100;
this.btnStopTooltip = 500;
}
}
else
{
// The mouse pointer was already over this button so
// provided we have a tooltip defined we should be
// counting down to tooltip counters
if (!this.btnTooltip.equals(""))
{
// Provided the counter is greather than zero
// subtract one from the counter
if (this.btnStartTooltip > 0) {this.btnStartTooltip--;}
if (this.btnStopTooltip > 0) {this.btnStopTooltip--;}
}
}
}
else
{
// The mouse pointer was over this button but it is not
// now so provided we have a tooltip defined we should
// reset the tooltip counters
if (this.mouseOver == true && !this.btnTooltip.equals(""))
{
this.btnStartTooltip = 0;
this.btnStopTooltip = 0;
}
}

// Mark the button to indicate if the mouse is over it
this.mouseOver = mOver;

// If the mouse is over the button and we have a mouse over
// image defined, set the button image accordingly.
// Otherwise set to the standard image
if (this.mouseOver && this.moverImage != null)
{
this.btnImage = this.moverImage;
}
else
{
this.btnImage = this.stdImage;
}

// If the mouse is over the button and we have a mouse over
// colour defined, set the button colour accordingly.
// Otherwise set to the standard colour
if (this.mouseOver && this.moverColour != -1)
{
this.btnColour = this.moverColour;
}
else
{
this.btnColour = this.stdColour;
}

}

// Check if this button should have a tooltip displayed
// for it and display accordingly
private void tooltip()
{
int textWidth;
// If the mouse is over this button, and the tooltip is not
// an empty string, and the tooltip start countdown is zero
// and the tooltip stop countdown is not zero we should
// display the tooltip
if (this.mouseOver == true && ! this.btnTooltip.equals("") &&
this.btnStartTooltip == 0 && this.btnStopTooltip != 0)
{
// Select the font we will use for tooltips
textFont(tooltipFont,9);

// Calculate the width of the text we want to display
float textW = textWidth(this.btnTooltip) + 10;

// Choose the pale yellow background colour for the tooltip
fill(241,253,191);

// Draw the rectangle in which to display the tooltip text
rect( mouseX + 10, mouseY - 20, textW, 20);

// Change the colour to black
fill(0);

// Calculate the X and Y position to ensure the tooltip text is
// aligned in the centre of the tooltip rectangle
float textX = (mouseX + 10 + (textW / 2));
textX = textX - (textWidth(this.btnTooltip) / 2);
float textY = (mouseY - 20 + 10 ) + 4.5;

// Display the tooltip text
text(this.btnTooltip, textX, textY);
}
}

}

Chunk 85 - Advanced Buttons 2 (Part 4)

...... For a button to be useful in an application it must perform some action when chosen by a user, and therefore we need some method of determining if the mouse pointer is currently over a button.

Add the following method to the button class, to determine, for a button instance, if the mouse is currently over the area if occupies.

// Check if the mouse is currently positioned over the button
private boolean isMouseOver() {
if (mouseX >= this.btnTopX && mouseX <= this.btnTopX + this.btnWidth &&
mouseY >= this.btnTopY && mouseY <= this.btnTopY + this.btnHeight) { return true; }
else {return false; }
}

We will make use of this function as part of a new method that will check, and set, status information regarding each button.

We need to add new instance variables to hold the mouseOver status for the button.

boolean mouseOver;       // Is mouse over button

In addition we need to set the default mouseOver value in the class constructor.

// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object created
Button (int X, int Y, int W, int H)
{
.
.
.
this.mouseOver = false; // Mouse over button?
}

To make sure the mouseOver value is set we have to add a call to the checkMouse method in the draw() function before we draw the buttons. In that way we have the current status of the button before we draw it on the screen.

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.checkMouse();
btn1.drawButton();

// Process button two
btn2.checkMouse();
btn2.drawButton();

// Process button three
btn3.checkMouse();
btn3.drawButton();

}

The code changes we have made have now visible effect on the buttons, but we can build on the changes to enable us to change the colour and/or image of a button when the mouse is over it.

Define new instance variables to hold the standard button colour and image, and also the colour and image to be displayed when the mouse is over the button

color   stdColour;       // Standard Button Colour
color moverColour; // Mouse Over Button Colour
PImage stdImage; // Standard Button Image
PImage moverImage; // Mouse Over Button Image

Again we need to set the default values in the class constructor.

// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object created
Button (int X, int Y, int W, int H)
{
.
.
.
this.stdColour = 128; // Standard Button Colour
this.moverColour = -1; // Mouse Over Button Colour
this.stdImage = null; // Standard Button Image
this.moverImage = null; // Mouse Over Button Image
this.btnColour = -1; // Button Colour
}

Notice that we have also changed the default value and comment for the btnColour instance variable as this will now be used to store the current colour for the button.

We need to allow the user to specify the button colours and images so we will need to create some new setter methods, and adjust the existing ones for the new instance variables.

// Set the Button Colour 
public void setButtonColour(int colourValue)
{
this.stdColour = colourValue;
this.btnColour = colourValue;
}

// Set the Button Image
public void setButtonImage(String imageValue)
{
this.stdImage = loadImage(imageValue);
this.btnImage = this.stdImage;
}

// Set the MouseOver Button Colour
public void setMouseOverColour(int colourValue)
{
this.moverColour = colourValue;
}

// Set the MouseOver Button Image
public void setMouseOverImage(String imageValue)
{
this.moverImage = loadImage(imageValue);
}

Finally, add code to the checkMouse() method to set the values in btnImage and btnColour depending on mouseOver, and change the calls in setup() to set the new instances and define the mouseOver values if required.

// Check the location of the mouse in relation to the
// button and set instance variables accordingly
private void checkMouse()
{
// Check if the mouse is over the button
boolean mOver = this.isMouseOver();

// Mark the button to indicate if the mouse is over it
this.mouseOver = mOver;

// If the mouse is over the button and we have a mouse over
// image defined, set the button image accordingly.
// Otherwise set to the standard image
if (this.mouseOver && this.moverImage != null)
{
this.btnImage = this.moverImage;
}
else
{
this.btnImage = this.stdImage;
}

// If the mouse is over the button and we have a mouse over
// colour defined, set the button colour accordingly.
// Otherwise set to the standard colour
if (this.mouseOver && this.moverColour != -1)
{
this.btnColour = this.moverColour;
}
else
{
this.btnColour = this.stdColour;
}
}

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Load the font we want to use on the buttons
btnFont=loadFont("Verdana-Bold-12.vlw");

// Create a new button and set the colour and label
btn1 = new Button(10,365,100,25);
btn1.setButtonColour(color(128,128,255));
btn1.setMouseOverColour(color(128,128,128));
btn1.setButtonLabel("On");

// Create a new button and set the colour and label
btn2 = new Button(120,365,100,25);
btn2.setButtonColour(color(128,128,255));
btn2.setMouseOverColour(color(128,128,128));
btn2.setButtonLabel("Off");

// Create a new button and set the colour and image
btn3 = new Button(230,359,17,33);
btn3.setButtonColour(color(128,128,255));
btn3.setButtonImage("tab-unsel-menu.gif");
btn3.setMouseOverImage("tab-sel-menu.gif");

}

When we run our program now and move the mouse pointer over the buttons from left to right we get the results as shown in figures 4.0, 4.1, and 4.2.

Figure 4.0 Mouse Over the On Button


Figure 4.1 Mouse Over the Off Button


Figure 4.2 Mouse Over the Menu Button





// Button Class
// Development of a button class - Stage 4 of 5
// 2009 Nigel Parker

Button btn1; // On Button
Button btn2; // Off Button
Button btn3; // Image Button
PFont btnFont;

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Load the font we want to use on the buttons
btnFont=loadFont("Verdana-Bold-12.vlw");

// Create a new button and set the colour and label
btn1 = new Button(10,365,100,25);
btn1.setButtonColour(color(128,128,255));
btn1.setMouseOverColour(color(128,128,128));
btn1.setButtonLabel("On");

// Create a new button and set the colour and label
btn2 = new Button(120,365,100,25);
btn2.setButtonColour(color(128,128,255));
btn2.setMouseOverColour(color(128,128,128));
btn2.setButtonLabel("Off");

// Create a new button and set the colour and image
btn3 = new Button(230,359,17,33);
btn3.setButtonColour(color(128,128,255));
btn3.setButtonImage("tab-unsel-menu.gif");
btn3.setMouseOverImage("tab-sel-menu.gif");

}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.checkMouse();
btn1.drawButton();

// Process button two
btn2.checkMouse();
btn2.drawButton();

// Process button three
btn3.checkMouse();
btn3.drawButton();

}

// Definition of a Button class that will allow us to
// create and use buttons within our processing code
class Button {

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height
color btnColour; // Button Colour
String btnText; // Button Label Text
PImage btnImage; // Button Image
boolean mouseOver; // Is mouse over button

color stdColour; // Standard Button Colour
color moverColour; // Mouse Over Button Colour
PImage stdImage; // Standard Button Image
PImage moverImage; // Mouse Over Button Image


// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object creaetd
Button (int X, int Y, int W, int H)
{
this.btnTopX = X; // Set Button Top X Coordinate
this.btnTopY = Y; // Set Button Top Y Coordinate
this.btnWidth = W; // Set Button Width
this.btnHeight = H; // Set Button Height
this.btnColour = -1; // Button Colour
this.btnText = ""; // Default Button Label Text
this.btnImage = null; // Button Image
this.mouseOver = false; // Mouse over button?
this.stdColour = 128; // Standard Button Colour
this.moverColour = -1; // Mouse Over Button Colour
this.stdImage = null; // Standard Button Image
this.moverImage = null; // Mouse Over Button Image
}

// Setter Methods - Methods that can be used by an
// application to set instance variables within an
// instance of the button class

// Set the Button Label Text
public void setButtonLabel(String labelText)
{
this.btnText = labelText;
}

// Set the Button Colour
public void setButtonColour(int colourValue)
{
this.stdColour = colourValue;
this.btnColour = colourValue;
}

// Set the Button Image
public void setButtonImage(String imageValue)
{
this.stdImage = loadImage(imageValue);
this.btnImage = this.stdImage;
}

// Set the MouseOver Button Colour
public void setMouseOverColour(int colourValue)
{
this.moverColour = colourValue;
}

// Set the MouseOver Button Image
public void setMouseOverImage(String imageValue)
{
this.moverImage = loadImage(imageValue);
}

// Draw the button on the screen
public void drawButton()
{
// Set the button colour
fill(this.btnColour);

// Draw the button
rect(this.btnTopX, this.btnTopY, this.btnWidth, this.btnHeight);

// Draw the button image
if (this.btnImage != null)
{
image(this.btnImage, this.btnTopX, this.btnTopY);
}

// Draw the button label if the text is defined (not blank)
if (! this.btnText.equals(""))
{
// Select the font for the text
textFont(btnFont,12);

// Set the colour to white
fill(255);

// Calculate the horizontal centre of the button, then subtract half
// the width of the button label to find the starting position
float textX = (this.btnTopX + this.btnWidth / 2) - (textWidth(this.btnText) / 2);

// Calculate the vertical centre of the button
float textY = (this.btnTopY + this.btnHeight / 2) + 6;

// Output the text
text(this.btnText, textX, textY);
}
}

// Check if the mouse is currently positioned over the button
private boolean isMouseOver() {
if (mouseX >= this.btnTopX && mouseX <= this.btnTopX + this.btnWidth &&
mouseY >= this.btnTopY && mouseY <= this.btnTopY + this.btnHeight) {
return true;
}
else {
return false;
}
}

// Check the location of the mouse in relation to the
// button and set instance variables accordingly
private void checkMouse()
{
// Check if the mouse is over the button
boolean mOver = this.isMouseOver();

// Mark the button to indicate if the mouse is over it
this.mouseOver = mOver;

// If the mouse is over the button and we have a mouse over
// image defined, set the button image accordingly.
// Otherwise set to the standard image
if (this.mouseOver && this.moverImage != null)
{
this.btnImage = this.moverImage;
}
else
{
this.btnImage = this.stdImage;
}

// If the mouse is over the button and we have a mouse over
// colour defined, set the button colour accordingly.
// Otherwise set to the standard colour
if (this.mouseOver && this.moverColour != -1)
{
this.btnColour = this.moverColour;
}
else
{
this.btnColour = this.stdColour;
}

}
}

Chunk 85 - Advanced Buttons 2 (Part 3)

...... Now we have the ability to create buttons of any size, set the colour and the text of the button, but in many applications buttons do not have text, they use images or icons to convey their purpose. So now we will add the ability to define buttons that use images.

For the purposes of this example I will be using two images taken from the processing lib/themes directory. These images ‘tab-unsel-menu.gif’ and ‘tab-sel-menu.gif’ need to be placed in the data directory of the processing project.

We need to add new instance variables to hold the name of the image to be shown on the standard button.

PImage  btnImage;        // Button Image

In addition we need to set the default image value in the class constructor, and create a setter method to allow our application to specify the image to use.

// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object created
Button (int X, int Y, int W, int H)
{
.
.
.
this.btnImage = null; // Default Button Image
}

// Set the Button Image
public void setButtonImage(String imageValue)
{
this.btnImage = loadImage(imageValue);
}

And add the following code to the drawButton() method, after we have drawn the button and before we add the text.

// Draw the button image  
if (this.btnImage != null)
{
image(this.btnImage, this.btnTopX, this.btnTopY);
}

Finally we can add the definition of this new button in the setup() function and then add it to the draw() function to ensure it is drawn on the screen.

Button btn1;
Button btn2;
Button btn3;

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

.
.
.

// Create a new button and set the colour and image
btn3 = new Button(230,359,17,33);
btn3.setButtonColour(color(128,128,255));
btn3.setButtonImage("tab-unsel-menu.gif");
}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.drawButton();

// Process button two
btn2.drawButton();

// Process button three
btn3.drawButton();

}

When we run our program now we get a screen with three buttons as shown in figure 3.0

Figure 3.0 Colours, Labels and Images





// Button Class
// Development of a button class - Stage 3 of 5
// 2009 Nigel Parker

Button btn1; // On Button
Button btn2; // Off Button
Button btn3; // Image Button
PFont btnFont;

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Load the font we want to use on the buttons
btnFont=loadFont("Verdana-Bold-12.vlw");

// Create a new button and set the colour and label
btn1 = new Button(10,365,100,25);
btn1.setButtonColour(color(128,128,255));
btn1.setButtonLabel("On");

// Create a new button and set the colour and label
btn2 = new Button(120,365,100,25);
btn2.setButtonColour(color(128,128,255));
btn2.setButtonLabel("Off");

// Create a new button and set the colour and image
btn3 = new Button(230,359,17,33);
btn3.setButtonColour(color(128,128,255));
btn3.setButtonImage("tab-unsel-menu.gif");

}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.drawButton();

// Process button two
btn2.drawButton();

// Process button three
btn3.drawButton();

}

// Definition of a Button class that will allow us to
// create and use buttons within our processing code
class Button {

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height
color btnColour; // Button Colour
String btnText; // Button Label Text
PImage btnImage; // Button Image


// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object creaetd
Button (int X, int Y, int W, int H)
{
this.btnTopX = X; // Set Button Top X Coordinate
this.btnTopY = Y; // Set Button Top Y Coordinate
this.btnWidth = W; // Set Button Width
this.btnHeight = H; // Set Button Height
this.btnColour = 128; // Default Colour
this.btnText = ""; // Default Button Label Text
this.btnImage = null; // Default Button Image
}

// Setter Methods - Methods that can be used by an
// application to set instance variables within an
// instance of the button class

// Set the Button Label Text
public void setButtonLabel(String labelText)
{
this.btnText = labelText;
}

// Set the Button Colour
public void setButtonColour(int colourValue)
{
this.btnColour = colourValue;
}

// Set the Button Image
public void setButtonImage(String imageValue)
{
this.btnImage = loadImage(imageValue);
}

// Draw the button on the screen
public void drawButton()
{
// Set the button colour
fill(this.btnColour);

// Draw the button
rect(this.btnTopX, this.btnTopY, this.btnWidth, this.btnHeight);

// Draw the button image
if (this.btnImage != null)
{
image(this.btnImage, this.btnTopX, this.btnTopY);
}

// Draw the button label if the text is defined (not blank)
if (! this.btnText.equals(""))
{
// Select the font for the text
textFont(btnFont,12);

// Set the colour to white
fill(255);

// Calculate the horizontal centre of the button, then subtract half
// the width of the button label to find the starting position
float textX = (this.btnTopX + this.btnWidth / 2) - (textWidth(this.btnText) / 2);

// Calculate the vertical centre of the button
float textY = (this.btnTopY + this.btnHeight / 2) + 6;

// Output the text
text(this.btnText, textX, textY);
}
}


}

Friday 8 May 2009

Chunk 85 - Advanced Buttons 2 (Part 2)

...... Let’s start by adding the ability to change the colour of a button, and to give the button a label so that anyone using our application knows the purpose of the button.

We will need to add two more instance properties, under the ones for position and size, in order to store details of the colour and button text.

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height
color btnColour; // Button Colour
String btnText; // Button Label Text

We also need to change the constructor method to set default values for these new variables.
Button (int X, int Y, int W, int H)
{
this.btnTopX = X; // Set Button Top X Coordinate
this.btnTopY = Y; // Set Button Top Y Coordinate
this.btnWidth = W; // Set Button Width
this.btnHeight = H; // Set Button Height
this.btnColour = 128; // Default Colour
this.btnText = ""; // Default Button Label Text
}

In order for our application to set these values we have to create some ‘setter’ methods in the button class, which allow us to specify values for the text label and colour of the button. These setter methods appear within the class definition for a button, immediately after the constructor method.
// Setter Methods - Methods that can be used by an
// application to set instance variables within an
// instance of the button class

// Set the Button Label Text
public void setButtonLabel(String labelText)
{
this.btnText = labelText;
}

// Set the Button Colour
public void setButtonColour(int colourValue)
{
this.btnColour = colourValue;
}

Now we need to amend the drawButton() method to use the colour defined for the button, and to draw the button label if it is defined.
// Draw the button on the screen
public void drawButton()
{
// Set the button colour
fill(this.btnColour);

// Draw the button
rect(this.btnTopX, this.btnTopY, this.btnWidth, this.btnHeight);

// Draw the button label if the text is defined (not blank)
if (! this.btnText.equals(""))
{
// Select the font for the text
textFont(btnFont,12);

// Set the colour to white
fill(255);

// Calculate the horizontal centre of the button, then subtract half
// the width of the button label to find the starting position
float textX = (this.btnTopX + this.btnWidth / 2) – (textWidth(this.btnText) / 2);

// Calculate the vertical centre of the button
float textY = (this.btnTopY + this.btnHeight / 2) + 6;

// Output the text
text(this.btnText, textX, textY);
}
}

You will notice that we have replaced the fill statement in the drawButton method with a fill statement using the colour attribute variable defined for the button being drawn. We have also added a check to see if the button has a text label variable defined for it, and if it does we set the colour to white and output the label text on the button.

In order to make the button look as good as possible we should position the button label so it is centered, to do this we calculate the starting X position for the text as being the X position of the button (this.btnTopX) plus half the width of the button (this.btnWidth / 2) minus half the pixel length of the button label (textWidth(this.btnText) / 2). The starting Y position is calculated as the Y position of the button (this.btnTopY) plus half the height of the button (this.btnHeight / 2) plus half the size of the font being used for the text.

Finally we can change the setup procedure to load the font we want to use, and specify our additional instance properties for our buttons.

Button btn1;
Button btn2;
PFont btnFont;

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Load the font we want to use on the buttons
btnFont=loadFont("Verdana-Bold-12.vlw");

// Create a new button
btn1 = new Button(10,365,100,25);
btn1.setButtonColour(color(128,128,255));
btn1.setButtonLabel("On");

// Create a new button
btn2 = new Button(120,365,100,25);
btn2.setButtonColour(color(128,128,255));
btn2.setButtonLabel("Off");

}


When we run our program now we get a screen with two buttons as shown in figure 2.0

Figure 2.0 Colours and Labels





// Button Class
// Development of a button class - Stage 2 of 5
// 2009 Nigel Parker

Button btn1; // On Button
Button btn2; // Off Button
PFont btnFont;

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Load the font we want to use on the buttons
btnFont=loadFont("Verdana-Bold-12.vlw");

// Create a new button and set the colour and label
btn1 = new Button(10,365,100,25);
btn1.setButtonColour(color(128,128,255));
btn1.setButtonLabel("On");

// Create a new button and set the colour and label
btn2 = new Button(120,365,100,25);
btn2.setButtonColour(color(128,128,255));
btn2.setButtonLabel("Off");

}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.drawButton();

// Process button two
btn2.drawButton();

}

// Definition of a Button class that will allow us to
// create and use buttons within our processing code
class Button {

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height
color btnColour; // Button Colour
String btnText; // Button Label Text

// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object creaetd
Button (int X, int Y, int W, int H)
{
this.btnTopX = X; // Set Button Top X Coordinate
this.btnTopY = Y; // Set Button Top Y Coordinate
this.btnWidth = W; // Set Button Width
this.btnHeight = H; // Set Button Height
this.btnColour = 128; // Default Colour
this.btnText = ""; // Default Button Label Text
}

// Setter Methods - Methods that can be used by an
// application to set instance variables within an
// instance of the button class

// Set the Button Label Text
public void setButtonLabel(String labelText)
{
this.btnText = labelText;
}

// Set the Button Colour
public void setButtonColour(int colourValue)
{
this.btnColour = colourValue;
}

// Draw the button on the screen
public void drawButton()
{
// Set the button colour
fill(this.btnColour);

// Draw the button
rect(this.btnTopX, this.btnTopY, this.btnWidth, this.btnHeight);

// Draw the button label if the text is defined (not blank)
if (! this.btnText.equals(""))
{
// Select the font for the text
textFont(btnFont,12);

// Set the colour to white
fill(255);

// Calculate the horizontal centre of the button, then subtract half
// the width of the button label to find the starting position
float textX = (this.btnTopX + this.btnWidth / 2) - (textWidth(this.btnText) / 2);

// Calculate the vertical centre of the button
float textY = (this.btnTopY + this.btnHeight / 2) + 6;

// Output the text
text(this.btnText, textX, textY);
}
}
}

Thursday 7 May 2009

Chunk 85 - Advanced Buttons 2 (Part 1)

As we have seen from the previous two chapters, adding buttons to an application does not involve very complex coding, but it is a time consuming process with many lines of code being generated. Much of this code is duplicated for each button, so the obvious way to simplify this process and make it more elegant would be to develop a class for buttons. The development of such a class is covered in this chapter.

Before we start the development, however, a quick recap on the purpose of a class would be useful.

A class is used to define the common attributes and behavior of an object, so by defining a class for buttons every object we describe as a button will inherit the attributes and the methods we have specified for that class, the beauty of this in practice is that we only have to write the code for one ‘generic’ button and every button we define after that will work in the same way, for free, without any additional code changes.

This class can then be copied and reused in every processing application where we need buttons without having to develop the same functionality again, which gives us more time on the exciting bits!

This chapter will deal with the creation and development of a class for buttons, and will concentrate on the common features of a button without examining the specific function of each button.

We will start by defining the class for buttons, with some of the instance properties we will need to draw the button on the screen, such as the size and position of the button.

We need to know details of where the button should be positioned on the screen, and the most logical method of doing this is to adopt the default co-ordinate system used within the processing language where we specify the top left x and y coordinates of the object. In addition to this we need to know the width and height of the button.

// Definition of a Button class that will allow us to
// create and use buttons within our processing code
class Button {

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height
}


Now we need to add some code to this class that will allow us to create a new button and define the initial values, this constructor code is the code that will be run when we define a new button.

// Definition of a Button class that will allow us to
// create and use buttons within our processing code
class Button {

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height


// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object creaetd
Button (int X, int Y, int W, int H)
{
this.btnTopX = X; // Set Button Top X Coordinate
this.btnTopY = Y; // Set Button Top Y Coordinate
this.btnWidth = W; // Set Button Width
this.btnHeight = H; // Set Button Height
}
}


The code we have just developed will allow us to construct a new button, and define the top left x and y positions along with the height and width, but it will not draw the image of the button on the screen. To do that we need to add a method to the class, that we will call drawButton().

// Draw the button on the screen
public void drawButton()
{
// Select a colour for the button
fill(100, 100, 100);

// Draw the button
rect(this.btnTopX, this.btnTopY, this.btnWidth, this.btnHeight);
}


We could simply have added this code to the constructor method but in reality we want to be able to define all our buttons and draw them when required, so it is better to create a separate method for drawing the buttons.

In order to make use of this class we have defined we need to add the setup and draw functions as described below.

Button btn1;         // On Button
Button btn2; // Off Button

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Create a new button
btn1 = new Button(10,565,100,25);

// Create a new button
btn2 = new Button(120,565,100,25);
}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.drawButton();

// Process button two
btn2.drawButton();

}


The code we have developed so far gives us a screen with two buttons along the bottom, as shown in Figure 1.0. Now we have the basics of the button class, or at least the methods that allow us to draw the basic button shape on the screen, we can start to add functionality to our class.

Figure 1.0 Two Button Shapes






The complete code for Stage 1:

// Button Class
// Development of a button class - Stage 1 of 5
// 2009 Nigel Parker

Button btn1; // On Button
Button btn2; // Off Button

void setup() {
size(400,400); // Set screen size
smooth(); // Anti-aliased (smooth) edges

// Create a new button
btn1 = new Button(10,365,100,25);

// Create a new button
btn2 = new Button(120,365,100,25);

}

void draw () {

// Clear the background and set the background colour
background(128,128,128);

// Process button one
btn1.drawButton();

// Process button two
btn2.drawButton();

}

// Definition of a Button class that will allow us to
// create and use buttons within our processing code
class Button {

// Button Position and Size Properties
int btnTopX; // Button Top X Coordinate
int btnTopY; // Button Top Y Coordinate
int btnWidth; // Button Width
int btnHeight; // Button Height

// The button constructor is called to create a new button
// and stores the position and size information provided
// in the instance variables of the object created
Button (int X, int Y, int W, int H)
{
this.btnTopX = X; // Set Button Top X Coordinate
this.btnTopY = Y; // Set Button Top Y Coordinate
this.btnWidth = W; // Set Button Width
this.btnHeight = H; // Set Button Height
}

// Draw the button on the screen
public void drawButton()
{
// Set the button colour
fill(128,128,255);

// Draw the button
rect(this.btnTopX, this.btnTopY, this.btnWidth, this.btnHeight);

}

}

Thursday 13 November 2008

Rotating Blocks

Still waiting for my book to arrive, but in the mean time I have been busy reading the information on the Processing Web Site.

I was recently discussing this project with a friend, and he suggested I may be interested in some computer generated art he had seen recently on the Krazydad blog and one particular piece by Daniel Piker inspired me to write my first Processing code showing some Rotating Blocks.
/**
* Rotating Blocks
* by Nigel Parker
*
* Each column of blocks rotates at a different rate with the centre
* column remaining static and the left an right sides rotating in
* a different direction
*/

int [] r = new int[6];
int [] rVal = new int[6];

void setup() {

// Set up initial rotation speeds
rVal[0]=5;
rVal[1]=4;
rVal[2]=3;
rVal[3]=2;
rVal[4]=1;
rVal[5]=0;

// Set the initial screen size etc
size(640,640);
smooth();
noStroke();

}

void draw()
{

background(0);

for(int i=0;i<6;i++)
{
int xxLeft = 65 + (50 * i);
int xxRight = 565 - (50 * i);

// We will be drawing 11 boxes in a line
for(int j=0;j<11;j++)
{
int yy = 65 + (50 * j);
drawBox(xxLeft,yy,30,30,radians(r[i]));

// Don't need to draw the centre column twice
if (i < 5)
{
drawBox(xxRight,yy,30,30,radians((-1 * r[i])));
}
}
r[i] = (r[i] + rVal[i]) % 360;
}

}

void drawBox(int x, int y, int w, int h, float rot)
{
fill(0,148,255);

// Move the origin of the co-ordinate system to be the
// centre of the box we are going to draw
translate(x,y);

// Rotate the co-ordinate system by the required amount
rotate(rot);

// Draw the rectangle based around the centre co-ordinates
rectMode(CENTER);
rect(0,0,w,h);

// Rotate the co-ordinate system back by the required amount
// We have to do this as rotate is cumulative
rotate((rot * -1));

// Move the origin of the co-ordinate system back to
// its original position
// We have to do this as translate is cumulative
translate(-x,-y);
}

Tuesday 4 November 2008

A book buyer's tale ...


At the weekend I decided to get the processing book. I’m a bit impatient and didn’t want to wait for an online delivery so I phoned my local Waterstones store to check they had one in stock before going in to town. A very helpful member of staff checked on their computer system but unfortunately neither of the two stores in my nearest town had the book in stock, she also checked two other stores in neighbouring towns with the same result. I do live in the country so I thought maybe it is not the kind of book they get a lot of call for, but since I work in London I also asked if she could check the Ealing branch, same result. I thanked her for her efforts and decided to buy on line, I checked with Amazon, out of stock, before finally placing an order with Waterstones on line.

I have just received an email from Waterstones and they too are out of stock and will have to place another order with the publishers ….. This book must be in demand for some reason!