agw SuperTooltip suggestion

I have noticed a problem with agw SuperTooltip. Here is a program that
demonstrates it:

import wx
from agw import supertooltip as STT

TIP_MSG="""This is button (%s,%s)

This demonstration program shows what happens if the tooltip target
widget is at the edge of the screen. Instead of placing the tip window
under the mouse position, we should place it smartly. E.g. when the
widget is at the bottom of the screen, then the tooltip window should
be placed ABOVE the widget, so that all of the contents are
visible."""

class Main(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,title="Tooltip test")
        sizer = wx.GridBagSizer()
        for row in range(10):
            for col in range(10):
                btn = wx.Button(self,-1,"%s,%s"%(row,col))
                tip = STT.SuperToolTip("Tooptip for %s,%s"%(row,col))
                tip.SetHeader(TIP_MSG%(row,col))
                tip.SetTarget(btn)
                tip.SetDrawHeaderLine(True)
                sizer.Add(btn, (row,col), (1,1), wx.EXPAND)
        for row in range(10):
            sizer.AddGrowableRow(row)
        for col in range(10):
            sizer.AddGrowableCol(col)
        self.SetSizer(sizer)
        self.Maximize()

app = wx.App(redirect=None)
frame = Main()
frame.Show()
app.MainLoop()

If you place the mouse over a button, then the tooltip is always
appears with its upper left corner positioned to the current mouse
position. One problem is that the target widget may be near the edge
of the screen. In that case, the tooltip window will be partly
invisible. The other problem is that sometimes the client area of the
widget is important to the end user. Consider a big text editor
window, where the user is supposed to write in multiple lines of text.
Most likely, the tooltip window will be shown in the middle of the
text area, preventing the user to see what he is typing.

I have a patch for this problem that can be applied against the
current subversion repository. But I'm not sure how to submit a patch.
I'm using google groups and as far as I know, this is the only way to
post to the list. But Google doesn't allow me to attach files. So I'll
just copy the changes here.

Change #1. into class TooptipWindowBase, create this new method:

    def CalculateBestPosition(self,widget):
        screen = wx.ClientDisplayRect()[2:]
        left,top = widget.ClientToScreenXY(0,0)
        right,bottom = widget.ClientToScreenXY(*widget.GetClientRect()
[2:])
        size = self.GetSize()
        if right+size[0]>screen[0]:
            xpos = left-size[0]
        else:
            xpos = right
        if bottom+size[1]>screen[1]:
            ypos = top-size[1]
        else:
            ypos = bottom
        self.SetPosition((xpos,ypos))

Change #2. Wherever SetPosition() was called, call
CalculateBestPosition() instead.

Then you can run the test app, and you will see that the tooltip is
place to the bottom right of the widget, except near the screen edges.
E.g. for a widget that is on the bottom left site, the tooltip will be
placed at the top right corder of the client rect of the widget etc.

I have another idea about how to make this better, and another "bug"
that can be fixed. But first I would like to know your opinion about
this.

Best,

   Laszlo

Thanks,

   Laszlo

Hi Laszlo,

I have noticed a problem with agw SuperTooltip. Here is a program that

demonstrates it:

import wx

from agw import supertooltip as STT

TIP_MSG=“”"This is button (%s,%s)

This demonstration program shows what happens if the tooltip target

widget is at the edge of the screen. Instead of placing the tip window

under the mouse position, we should place it smartly. E.g. when the

widget is at the bottom of the screen, then the tooltip window should

be placed ABOVE the widget, so that all of the contents are

visible.“”"

class Main(wx.Frame):

def __init__(self):

    wx.Frame.__init__(self,None,-1,title="Tooltip test")

    sizer = wx.GridBagSizer()

    for row in range(10):

        for col in range(10):

            btn = wx.Button(self,-1,"%s,%s"%(row,col))

            tip = STT.SuperToolTip("Tooptip for %s,%s"%(row,col))

            tip.SetHeader(TIP_MSG%(row,col))

            tip.SetTarget(btn)

            tip.SetDrawHeaderLine(True)

            sizer.Add(btn, (row,col), (1,1),  wx.EXPAND)

    for row in range(10):

        sizer.AddGrowableRow(row)

    for col in range(10):

        sizer.AddGrowableCol(col)

    self.SetSizer(sizer)

    self.Maximize()

app = wx.App(redirect=None)

frame = Main()

frame.Show()

app.MainLoop()

If you place the mouse over a button, then the tooltip is always

appears with its upper left corner positioned to the current mouse

position. One problem is that the target widget may be near the edge

of the screen. In that case, the tooltip window will be partly

invisible. The other problem is that sometimes the client area of the

widget is important to the end user. Consider a big text editor

window, where the user is supposed to write in multiple lines of text.

Most likely, the tooltip window will be shown in the middle of the

text area, preventing the user to see what he is typing.

I have a patch for this problem that can be applied against the

current subversion repository. But I’m not sure how to submit a patch.

I’m using google groups and as far as I know, this is the only way to

post to the list. But Google doesn’t allow me to attach files. So I’ll

just copy the changes here.

Change #1. into class TooptipWindowBase, create this new method:

def CalculateBestPosition(self,widget):

    screen = wx.ClientDisplayRect()[2:]

    left,top = widget.ClientToScreenXY(0,0)

    right,bottom = widget.ClientToScreenXY(*widget.GetClientRect()

[2:])

    size = self.GetSize()

    if right+size[0]>screen[0]:

        xpos = left-size[0]

    else:

        xpos = right

    if bottom+size[1]>screen[1]:

        ypos = top-size[1]

    else:

        ypos = bottom

    self.SetPosition((xpos,ypos))

Change #2. Wherever SetPosition() was called, call

CalculateBestPosition() instead.

Then you can run the test app, and you will see that the tooltip is

place to the bottom right of the widget, except near the screen edges.

E.g. for a widget that is on the bottom left site, the tooltip will be

placed at the top right corder of the client rect of the widget etc.

I have another idea about how to make this better, and another “bug”

that can be fixed. But first I would like to know your opinion about

this.

The best thing you can do is to provide a patch against AGW SVN. As I wrote a few days ago to another user, this is more or less the procedure you should follow:

  1. Get the latest SVN revision for that widget, using tools like TortoiseSVN (Windows), PySVN (all platforms?), from here:

http://svn.wxwidgets.org/svn/wx/wxPython/3rdParty/AGW/agw/ultimatelistctrl.py

  1. Make your modifications and add code to the file you just got from SVN;

  2. Using the same SVN tools I mentioned above, create a patch against the SVN version of ULC (in TortoiseSVN, for example, you right-click

the file you modified and select “Create patch”). On other platforms, you can simply use unified diff to create a diff between the SVN version and your revised file;

  1. Create a ticket on wxTrac:

http://trac.wxwidgets.org/

Assigning as Component=AGW, type=enhancement and maybe throw in my username (Infinity77) as owner of the ticket. Attach your patch to the

ticket. Everyone on wx-dev gets notifications about new tickets from wxTrac, so I’ll see it for sure. I’ll review your patch and, unless it

contains something very weird, I’ll simply apply it and commit a new revision to SVN.

An alternative to that (which lets you skip steps 3 and 4) is simply to send me your updated file and I’ll make the necessary steps to update it into SVN Obviously the drawback of this is that I will have more work to do, and this is why wxTrac exists in the first place :wink:

Andrea.

“Imagination Is The Only Weapon In The War Against Reality.”
http://xoomer.alice.it/infinity77/

import PyQt4.QtGui

Traceback (most recent call last):

File “”, line 1, in

ImportError: No module named PyQt4.QtGui

import pygtk

Traceback (most recent call last):

File “”, line 1, in

ImportError: No module named pygtk

···

On 29 August 2011 17:53, nagylzs wrote:

import wx

Hi Andrea,

The best thing you can do is to provide a patch against AGW SVN. As I wrote
a few days ago to another user, this is more or less the procedure you
should follow:

Thank you for your help. I just created a new ticket #13437

BTW there is another idea I would like to discuss. We could create a
shaped window that pinpoints the location of the target widget without
covering too much of its client area. I was experimenting with the
idea without success so far. The biggest problem is that the tooltip
window inherits from wx.PopupWindow (except on MAC). As far as I know,
wx.PopupWindow cannot be shaped because it lacks the style parameter
in its constructor.

And finally, here is another thing to consider. I do not understand
why we create a different tooltip window instance for every tooltip.
If you start up the demonstration program (look at the original post)
and hold the mouse several test buttons for a while, then multiple
tooltip windows will show up (on Linux/gtk at least). Some of them
will disappear automatically, but some of them will remain there until
I click them. Wouldn't it be better to re-use the same tooltip
instance for all widgets? That would make sure that only a single
tooltip is shown at a time. Which is what the user expects, I believe.

A workaround that solves both things would be the following:

#1. Create a single tooltip window that does not inherit from
wx.PopupWindow but from wx.Frame
#2. This window can have a special shape that shows and "arrow" to the
target widget but doesn't cover too much of its area
#3. Because it is a single instance, only one tooltip will be shown at
a time. If the user places the mouse over a different widget then the
old tooltip will be replaced with the new one.
#4. Since we have a single window instance, it is possible to set its
size to (1,1) pixels and move it outside the visible area of the
screen. Instead of re-showing the window, we just adjust its size,
update contents and move it to a different location. This prevents the
window manager from changing focus. I have done this before with my
own HTMLWindow based hint component, and it worked under Linux and
Windows too. I'm not sure about Mac, though.

Best,

   Laszlo

HI Laszlo,

Hi Andrea,

The best thing you can do is to provide a patch against AGW SVN. As I wrote

a few days ago to another user, this is more or less the procedure you

should follow:

Thank you for your help. I just created a new ticket #13437

BTW there is another idea I would like to discuss. We could create a

shaped window that pinpoints the location of the target widget without

covering too much of its client area. I was experimenting with the

idea without success so far. The biggest problem is that the tooltip

window inherits from wx.PopupWindow (except on MAC). As far as I know,

wx.PopupWindow cannot be shaped because it lacks the style parameter

in its constructor.

It can on Windows, I am not sure on other platforms. Using the pywin32 package from Mark Hammonds you can do pretty much every shaping/shadowing you want to any window. But wxWidgets as a whole does not support that, as probably GTK (and maybe Mac) do not support this feature. See the DropShadow method in STT to get an idea on what’s possible with pywin32.

And finally, here is another thing to consider. I do not understand

why we create a different tooltip window instance for every tooltip.

If you start up the demonstration program (look at the original post)

and hold the mouse several test buttons for a while, then multiple

tooltip windows will show up (on Linux/gtk at least). Some of them

will disappear automatically, but some of them will remain there until

I click them. Wouldn’t it be better to re-use the same tooltip

instance for all widgets? That would make sure that only a single

tooltip is shown at a time. Which is what the user expects, I believe.

A workaround that solves both things would be the following:

#1. Create a single tooltip window that does not inherit from

wx.PopupWindow but from wx.Frame

I would like to avoid that as deriving from wx.Frame is going to steal the focus away from the current focused window.

#2. This window can have a special shape that shows and “arrow” to the

target widget but doesn’t cover too much of its area

You may want to take a look at wx.lib.agw.balloontip for this kind of arrow/shaping, but be aware of the issue I mentioned above.

#3. Because it is a single instance, only one tooltip will be shown at

a time. If the user places the mouse over a different widget then the

old tooltip will be replaced with the new one.

This is a good idea, I’ll gladly accept any patch in this direction.

#4. Since we have a single window instance, it is possible to set its

size to (1,1) pixels and move it outside the visible area of the

screen. Instead of re-showing the window, we just adjust its size,

update contents and move it to a different location. This prevents the

window manager from changing focus. I have done this before with my

own HTMLWindow based hint component, and it worked under Linux and

Windows too. I’m not sure about Mac, though.

I believe this is still going to steal the focus from the current focused window unless you re-send the focus back as soon as the STT is created; in any case, I believe the user is still going to notice this focus back-and-forth gymnastic, although in my experience it has never been an issue… I am talking about wx.lib.agw.balloontip here, even if I don’t think there are many devs out there using this class.

Andrea.

“Imagination Is The Only Weapon In The War Against Reality.”
http://xoomer.alice.it/infinity77/

import PyQt4.QtGui

Traceback (most recent call last):

File “”, line 1, in

ImportError: No module named PyQt4.QtGui

import pygtk

Traceback (most recent call last):

File “”, line 1, in

ImportError: No module named pygtk

···

On 30 August 2011 09:01, nagylzs wrote:

import wx

It can on Windows, I am not sure on other platforms. Using the pywin32
package from Mark Hammonds you can do pretty much every shaping/shadowing
you want to any window. But wxWidgets as a whole does not support that, as
probably GTK (and maybe Mac) do not support this feature. See the DropShadow
method in STT to get an idea on what's possible with pywin32.

I have working code that does window shaping with pure wxPython code,
under GTK and also under Windows. (That is,
wx.Window.SetShape(wx.RegionFromPoints(points))) Unfortunately, I have
no access to Mac and I cannot test it there.

> #3. Because it is a single instance, only one tooltip will be shown at
> a time. If the user places the mouse over a different widget then the
> old tooltip will be replaced with the new one.

This is a good idea, I'll gladly accept any patch in this direction.

OK, will be working on it.

> update contents and move it to a different location. This prevents the
> window manager from changing focus. I have done this before with my

I believe this is still going to steal the focus from the current focused
window unless you re-send the focus back as soon as the STT is created; in
any case, I believe the user is still going to notice this focus
back-and-forth gymnastic, although in my experience it has never been an
issue... I am talking about wx.lib.agw.balloontip here, even if I don't
think there are many devs out there using this class.

Trust me, I have tried this before. :slight_smile: It grabs the focus only when
the tooltip window is created for the first time. After that, the
tooltip window will never be hidden or shown. It's only moved to an
invisible position when not needed. So the focus will never be
affected. (Except when you click on the tooltip window, but I guess
that's not a problem.)

All right, I'm up to making some changes. In the first phase, I'll try
to change the code so that only a single tooltip window instance will
be created. Would you accept that change, then I could work on the
shaped window version. (Maybe it won't work under Mac.)

Thanks

   Laszlo