python / cpython

The Python programming language
https://www.python.org
Other
62.76k stars 30.08k forks source link

Add IDLE Hovertip foreground color needed for recent macOS #120083

Open JRiggles opened 4 months ago

JRiggles commented 4 months ago

Bug report

Bug description:

Minimal Reproducible Example

import tkinter as tk
from idlelib.tooltip import Hovertip

root = tk.Tk()
root.geometry('200x100')
label = tk.Label(root, text='Hover Me!')
label.pack()
tip = Hovertip(label, text='Pro Tip')
root.mainloop()

CleanShot 2024-06-04 at 20 04 12@2x

Proposed Fix

Specifying a foreground color, e.g. foreground="black", at the Label declaration in Hovertip.showcontents() fixes the issue

class Hovertip(OnHoverTooltipBase):
    "A tooltip that pops up when a mouse hovers over an anchor widget."
    def __init__(self, anchor_widget, text, hover_delay=1000):
        """Create a text tooltip with a mouse hover delay.

        anchor_widget: the widget next to which the tooltip will be shown
        hover_delay: time to delay before showing the tooltip, in milliseconds

        Note that a widget will only be shown when showtip() is called,
        e.g. after hovering over the anchor widget with the mouse for enough
        time.
        """
        super().__init__(anchor_widget, hover_delay=hover_delay)
        self.text = text

    def showcontents(self):
        label = Label(self.tipwindow, text=self.text, justify=LEFT,
                      foreground="black", background="#ffffe0", relief=SOLID, borderwidth=1)
        label.pack()

CleanShot 2024-06-04 at 20 08 07@2x

CPython versions tested on:

3.12

Operating systems tested on:

macOS

Linked PRs

sobolevn commented 4 months ago

cc @terryjreedy

terryjreedy commented 4 months ago

IDLE widgets are only intended for use in IDLE; any other use is as-is and at your own risk of IDLE's code changing. (Hence, copying and adjusting the code as needed is safest.)

The code as is works on macOS Catalina. IDLE only uses hovertip widget for a fixed color black on white label, from which the black foreground in normally inherited. (I am not sure if the background arg is really needed.) Does this fail in IDLE on Sonoma? To test, start IDLE and in Shell, enter

>>> import itertools
>>> help(itertools)

Unless you turn off sqeezing in Options, you will see a lable with [Squeezed text (707 lines)]. Hover over that long enough and you should see a popup with Double-click.... There is only an IDLE bug if not black on white.

In any case, there is no tkinter bug though there may be mac version-dependent behavior. I suspect the example above could have been fixed by removing the background argument. (I am not sure why it is there.) I would expect a white on brown popup when hovering over a white on brown label.

JRiggles commented 4 months ago

@terryjreedy Thanks for looking into this a bit - I'll try running that test in the IDLE console later to see what I get. As far as the background argument goes, that off-white/pale yellow (#ffffe0) is the default specified in Hovertip.showcontents, even on Windows. I'll also try removing the background argument (in addition to removing forergound, to start with a "clean slate") to see if that is another potential fix.

For a quick test, I just tried removing background altogether (on Windows) and the tooltip background changed to the default background color for tkinter on Windows (#f0f0f0). For further sanity checking I also tried background='red' which, unsurprisingly, led to a red Hovertip.

As far as using this in tkinter goes, it's the closest thing I'm aware of to native tooltips. That said, given that

IDLE widgets are only intended for use in IDLE; any other use is as-is and at your own risk of IDLE's code changing. (Hence, copying and adjusting the code as needed is safest.)

I may just look into working up a basic tooltip module myself.

FWIW, I submitted this report because I had originally looked into this related issue https://github.com/python/cpython/issues/78456 and I noticed that the proposed solution had been integrated into idlelib.tooltip.TooltipBase (lines 44 and 45). I'll have to see if this affects IDLE directly when running under Sonoma (though I suspect it will!)

JRiggles commented 4 months ago

Here's a screenshot of what I see in IDLE with Hovertip.showcontents unmodified

CleanShot 2024-06-05 at 20 49 08@2x

Looks like the hovertip is blank here as well.

As before, setting the foreground color (to 'black' in this case) in Hovertip.showcontents seems to fix the issue

CleanShot 2024-06-05 at 20 51 42@2x

AtsushiSakai commented 3 months ago

I also encountered this issue when I tried to create a GUI application with tkinter on Mac.

@JRiggle 's suggestion is to add the optional function text_foreground to the __init__ function of Hovertip, and it doesn't seem like a particularly risky change. I know this IDLE widget is only intended for use in IDLE, but I believe it would be beneficial for users who want to display text in various colors. I can create a PR for this if it is needed.

JRiggles commented 3 months ago

@AtsushiSakai Yeah, adding an optional arg to Hovertip __init__ seems like the cleanest option, and defaulting to 'black' should be safe. If I have some concurrence on this, I'll put together a PR.

terryjreedy commented 3 months ago

Add fg=#000020, bg=#ffffe0 to the __init__ call and fg, bg = foreground, background color for hovertip. adjust showcontent(), and assign PR to me. Or I can do it.

JRiggles commented 3 months ago

@terryjreedy Do you mean the call to super().__init__(), or do you want me to add fg and bg in addition to the changes I already made with foreground and background in the referenced PR? And I think you're already on the PR as reviewer. Let me know if not, and I'll dig into it!