G4P has evolved since its release in 2009 and the source code has gone through
- 3 major revisions as Processing went from V2 to V4
- major revision when Processing started using OpenGL for P3D
- massive increase in the number of G4P controls available since first release
so has lost some of its cleanness / clarity which make adding to it a bit of a challenge even for me.
A very good question but I think that there is an easier way to do this.
So what I am going to do is describe how I would approach adding a tooltip feature to G4P. What follows might seem a bit disjointed but I am typing as things come to me. Here we go
Step 1
Knowing what I do about G4P I would ask “Is there a control that could be repurposed to use as a tooltip?”. If you think about it, what is the difference between a label and a tooltip? Not a lot really
Step 2
Create a GTooltip class and copy all the code from the GLabel class into it. Change all GLabel references to GTooltip. (dropped the ‘text’ bit from the name because it will also support icons).
Test the class by simply creating GTooltip objects.
We do not use GLabel directly because we will want to add additional functionality to the GTooltip class but that can wait for now.
Since it is likely that the tooltip must be aware of the control it belongs too we can add some new fields to the GTooltip class
protected GAbstractControl owner = null; // reference to the control that owns this tooltip
protected long tiptime = 0; // current time when the tip is made visible
Step 3
There are several ways we could create and associate a GTooltip with another G4P control. For instance the user could instantiate a GTooltip object then add it to the G4P control object but that is rather verbose and more complicated for the G4P user than it should.
A simple solution is to have a control create its own tooltip when required. So we start with the GAbstractControl class add a new field -
protected tip = null; // reference to the tooltip for this control
Step 4*
This is the key to the whole thing we are going to add three methods to GAbstractControl, the first two control the visibility of the tool tip
protected void showTooltip(){
if(tip != null) {
tip.setVisible(true);
tip.tiptime = System.currentTimeMillis();
}
}
protected void hideTooltip(){
if(tip != null) {
tip.setVisible(false);
tip.tiptime = 0;
}
}
These will be used later but are useful in that they will help prevent NPEs.
The third method is the key and I only show an outline as additional parameters are needed to set the tooltip position relative to the control (usually they are shown adjacent to the control but we must make sure they don’t go outside the display area).
public void setTooltip("tip text", ...){ // ... variable(s) to determine relative position to control
if(tip != null) return; // Can only use this method once for this control
float tpX, tpY, tpW, tpH; // tooltip poistion
// set the values in tpX, tpY, tpW and tpW based on current position of 'this' control
// and parameters passed in the function header.
tip = new GTooltip(winApp, "tip text", tpX, tpY, tPW, tpH); // create the tooltip
tip.owner = this; // set the tooltip owner to this control
hideTooltip();// Hide the tooltip until needed
}
Step 5
Now we need to hide the tooltip after a certain amount of time has elapsed we can do this in the GTooltip draw method like this
public void draw(){
if(!visible) return;
if(System.currentTimeMillis() - tiptime > 2000) { // hide after 2 seconds
visible = false;
tiptime = 0;
return;
}
// rest of draw method code
}
Step 6
That’s just about it except to make the tooltip visible in the first place. To do that we need to be able to detect whether the mouse has moved over and moved off the control. We start by adding a new attribute to GAbstractControl
protected int lastSpot = -1;
Now we need to modify the mouseEvent method for each control class. Using GButton as an example we have
public void mouseEvent(MouseEvent event){
if(!visible || !enabled || !available) return;
calcTransformedOrigin(winApp.mouseX, winApp.mouseY);
currSpot = whichHotSpot(ox, oy);
change it to something like
public void mouseEvent(MouseEvent event){
if(!visible || !enabled || !available) return;
calcTransformedOrigin(winApp.mouseX, winApp.mouseY);
currSpot = whichHotSpot(ox, oy);
// New code to detect mouse enter and mouse enter control
if(currSpot > 0 && currSpot != lastSpot) {
showTooltip();
lastSpot = currSpot;
}
else if(lastSpot >= 0 && currSpot < 0) {
hideTooltip();
lastSpot = -1;
}
lastSpot = currSpot;
// Continue with existing code
Step 7
Pick a control e.g. GButton and change the mouseEvent method as shown. Test the tooltip thoroughly to make sure it works as expected debugging the code as necessary. When satisfied that all is well then change the mouseEvent code in the other controls that might need tooltips.
Final words - This is all off the top of my head and there is still a lot of coding and testing to do to get it right. Hope this helps