G4P Tooltip underneath other controls

What a great library!

Just a small issue, for some reason if controls are near each other, the tooltips go under other controls.

See pic:

Is there any way to fix this, or just move the controls? It makes it harder to make a nice GUI if I have to move things around for the tooltips. Would be nice if the tooltips Z-order was always on top of all other controls…

Thanks kindly,

Mike

Can you create a very simple sketch that

  • demonstrates the problem, and
  • I can use for testing.
1 Like

Will do! I’ll get a sample made.

Ta!

Can you also raise a ticket at Sourceforge

1 Like

Yes, will do to both. Probably later today or tomorrow.

Thank you!

Mike

Hi Peter, here’s a simple working example. Only thing is, you’ll have to replace the missing image file by hand…

Note, I have not tested every single control in your library for this Z-order issue…only a few.

EDIT: have raised issue on SourceForge.

Thanks,

Mike

// Need G4P library
import g4p_controls.*;
// You can remove the PeasyCam import if you are not using
// the GViewPeasyCam control or the PeasyCam library.
import peasy.*;


public void setup(){
  size(480, 320, JAVA2D);
  createGUI();
  customGUI();
  // Place your setup code here
  button1.setTip("This is a tooltip", GAlign.CENTER, GAlign.NORTH, 5);
  button2.setTip("This is a tooltip", GAlign.CENTER, GAlign.NORTH, 5);
  button3.setTip("This is a tooltip", GAlign.CENTER, GAlign.NORTH, 5);
  button4.setTip("This is a tooltip", GAlign.CENTER, GAlign.NORTH, 5);
  imgButton1.setTip("Yet another TT!", GAlign.CENTER, GAlign.NORTH, 5);
  
}

public void draw(){
  background(230);
  
}

// Use this method to add additional statements
// to customise the GUI controls
public void customGUI(){

}

/* =========================================================
 * ====                   WARNING                        ===
 * =========================================================
 * The code in this tab has been generated from the GUI form
 * designer and care should be taken when editing this file.
 * Only add/edit code inside the event handlers i.e. only
 * use lines between the matching comment tags. e.g.

 void myBtnEvents(GButton button) { //_CODE_:button1:12356:
     // It is safe to enter your event code here  
 } //_CODE_:button1:12356:
 
 * Do not rename this tab!
 * =========================================================
 */

public void button1_click1(GButton source, GEvent event) { //_CODE_:button1:516716:
  println("button1 - GButton >> GEvent." + event + " @ " + millis());
} //_CODE_:button1:516716:

public void dropList1_click1(GDropList source, GEvent event) { //_CODE_:dropList1:282382:
  println("dropList1 - GDropList >> GEvent." + event + " @ " + millis());
} //_CODE_:dropList1:282382:

public void imgButton1_click1(GImageButton source, GEvent event) { //_CODE_:imgButton1:362407:
  println("imgButton1 - GImageButton >> GEvent." + event + " @ " + millis());
} //_CODE_:imgButton1:362407:

public void button2_click1(GButton source, GEvent event) { //_CODE_:button2:683231:
  println("button2 - GButton >> GEvent." + event + " @ " + millis());
} //_CODE_:button2:683231:

public void button3_click1(GButton source, GEvent event) { //_CODE_:button3:533149:
  println("button3 - GButton >> GEvent." + event + " @ " + millis());
} //_CODE_:button3:533149:

public void button4_click1(GButton source, GEvent event) { //_CODE_:button4:952753:
  println("button4 - GButton >> GEvent." + event + " @ " + millis());
} //_CODE_:button4:952753:



// Create all the GUI controls. 
// autogenerated do not edit
public void createGUI(){
  G4P.messagesEnabled(false);
  G4P.setGlobalColorScheme(GCScheme.BLUE_SCHEME);
  G4P.setMouseOverEnabled(false);
  surface.setTitle("Sketch Window");
  button1 = new GButton(this, 197, 145, 80, 30);
  button1.setText("Button");
  button1.addEventHandler(this, "button1_click1");
  dropList1 = new GDropList(this, 194, 183, 90, 80, 3, 10);
  dropList1.setItems(loadStrings("list_282382"), 0);
  dropList1.addEventHandler(this, "dropList1_click1");
  imgButton1 = new GImageButton(this, 201, 115, 25, 25, new String[] { "aboutDownLarger.png", "aboutDownLarger.png", "aboutDownLarger.png" } );
  imgButton1.addEventHandler(this, "imgButton1_click1");
  button2 = new GButton(this, 236, 112, 50, 30);
  button2.setText("Button");
  button2.addEventHandler(this, "button2_click1");
  button3 = new GButton(this, 156, 207, 80, 30);
  button3.setText("Button");
  button3.addEventHandler(this, "button3_click1");
  label1 = new GLabel(this, 288, 183, 80, 20);
  label1.setTextAlign(GAlign.CENTER, GAlign.MIDDLE);
  label1.setText("My label");
  label1.setOpaque(false);
  button4 = new GButton(this, 287, 207, 80, 30);
  button4.setText("Button");
  button4.addEventHandler(this, "button4_click1");
}

// Variable declarations 
// autogenerated do not edit
GButton button1; 
GDropList dropList1; 
GImageButton imgButton1; 
GButton button2; 
GButton button3; 
GLabel label1; 
GButton button4; 

Here’s the image:
aboutDownLarger

I have looked at the current implementation of tool-tips in G4P and there might not be a realistic solution to this problem :slightly_frowning_face:

1 Like

I can understand how this might be the case. You might not even have access to the Z-order controls. Rendering might not be something you can control, etc.

If you can’t change this behaviour, no worries, I can just move stuff around so tooltips don’t go under other controls.

And then it will just be a “known issue” and that’s that. Can’t expect the earth for nothing. I appreciate all you’ve done on this amazing library; it really is great!!

Thank you kindly Peter,

Mike

In G4P the tool-tip does not exist in isolation. The same can be said for the scrollbar, both of these controls are ‘child’ controls to some ‘parent’. Now a ‘parent’ control knows its absolute position on the screen but a child control does not, it only knows its position relative to its parent.

Consider a textarea; it has two children, the horizontal and vertical scrollbars so when it is rendered it uses the following algorithm

translate to the text area  position [x,y]
draw background if opaque
draw the  text background
draw the text
save the current transformation matrix
    translate to the horizontal scrollbar relative position
    render the horizontal scrollbar
restore the transformation matrix
save the current transformation matrix
    translate to the vertical scrollbar relative position
    render the vertical scrollbar
restore the transformation matrix

This means that the scrollbars

  1. are always rendered in the correct position for the text area
  2. only know their relative position with respect to the parent
  3. are always rendered immediately after its parent
  4. cannot guarantee it will not be covered by other controls.

The same logic applies to tool-tips except that because they are rendered ‘outside’ the parent control area it can more easily be hidden by other controls.

The only way I can see to overcome (4) is if the tool-tip is no longer a child control and it knows its absolute position. I believe it is possible to implement this but I am not keen on doing so since it breaks the existing semantic link between parent and child.

Having said that I suggest that you set the tool-tip position SOUTH of the parent control because it is less likely to be covered by other controls. Try the following code.

import g4p_controls.*;

public void setup() {
  size(400, 200, JAVA2D);
  createGUI();
  customGUI();
}

public void draw() {
  background(230);
}

public void customGUI() {
  btn1.setTip("Tip ONE", GAlign.RIGHT, GAlign.NORTH, 0);
  btn2.setTip("Tip TWO", GAlign.RIGHT, GAlign.NORTH, 0);
  btn3.setTip("Tip THREE", GAlign.RIGHT, GAlign.SOUTH, 0);
  btn4.setTip("Tip FOUR", GAlign.RIGHT, GAlign.SOUTH, 0);
}

public void createGUI(){
  G4P.messagesEnabled(false);
  G4P.setGlobalColorScheme(GCScheme.BLUE_SCHEME);
  G4P.setMouseOverEnabled(false);
  surface.setTitle("Sketch Window");
  btn1 = new GButton(this, 50, 70, 120, 30);
  btn1.setText("Button ONE");
  btn2 = new GButton(this, 50, 110, 120, 30);
  btn2.setText("Button TWO");
  btn3 = new GButton(this, 220, 70, 120, 30);
  btn3.setText("Button THREE");
  btn4 = new GButton(this, 220, 110, 120, 30);
  btn4.setText("Button FOUR");
}

// Variable declarations 
// autogenerated do not edit
GButton btn1; 
GButton btn2; 
GButton btn3; 
GButton btn4; 
1 Like

Thank you for explaining Peter, and for the example.

By the way in your example two of the tooltips are covered by other controls - was that on purpose?

In any case, simply re-imagining the interface and moving controls so tooltips do not get covered will work. I just wanted to ask, since it makes it a bit nicer to be able to position controls without considering tooltip covering. But I can see there’s a good reason for not changing things.

Thank you again,

Mike

Yes - it was to show the difference between having the tooltips NORTH on the left buttons and SOUTH on the right buttons.

2 Likes

Got it. Thanks! I appreciate your time.

Mike

Using the code I posted above the buttons and tips are created in the order

btn1, btn2, btn3, btn4, tip1, tip2, tip3, tip4 

but G4P has a sorting algorithm that renders them in the following order

btn3
   tip3
btn4
   tip4
btn1
   tip1
btn2
   tip2

All these controls have a positioning coordinates [x, y]. The ones for the buttons are absolute display positions but the ones for the tips and relative to their associated button so the tip is rendered immediately after its associated button.

This explains why some of the tips are covered or partially covered by other controls.

The sorting algorithm is very simple - it sorts the buttons in high Y to low Y order hence the render order above. This order was selected so that droplists appear over controls below them.

In the next version of G4P (4.3.11) the sorting algorithm has been changed. It still sorts high>low Y but when controls have the same Y position they are sorted high>low X. It means that tips to the right or south of the control should appear over any controls in that area.

The full solution would render all the buttons and then any tooltips. Unfortunately this would involve significant and messy code changes that would be detrimental to future maintenance. So having said that I will be closing this issue. :grin:

3 Likes

Hi Peter, that is fantastic news!

Any solution has to be balanced with A) feasibility; B) considerations of how the library already works; C) Time to implement; D) Code intelligibility and maintenance.

It seems like you’ve carefully considered everything and offered at a least a partial solution, for which I’m grateful. Bearing in mind you don’t owe anyone anything!! The library in version 1.0 was already a gift!

Thank you so much for the forthcoming update!

All my best,

Mike

1 Like