Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 68b3479

Browse files
daniilStimhoffm
andcommitted
Change colour of Tk toolbar icons on dark backgrounds
Co-Authored-By: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
1 parent eaadeb6 commit 68b3479

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

‎lib/matplotlib/backends/_backend_tk.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -649,12 +649,59 @@ def _set_image_for_button(self, button):
649649
path_large = path_regular.with_name(
650650
path_regular.name.replace('.png', '_large.png'))
651651
size = button.winfo_pixels('18p')
652+
653+
# Nested functions because ToolbarTk calls _Button.
654+
def _get_color(color_name):
655+
# `winfo_rgb` returns an (r, g, b) tuple in the range 0-65535
656+
return button.winfo_rgb(button.cget(color_name))
657+
658+
def _is_dark(color):
659+
if isinstance(color, str):
660+
color = _get_color(color)
661+
return max(color) < 65535 / 2
662+
663+
def _recolor_icon(image, color):
664+
image_data = np.asarray(image).copy()
665+
black_mask = (image_data[..., :3] == 0).all(axis=-1)
666+
image_data[black_mask, :3] = color
667+
return Image.fromarray(image_data, mode="RGBA")
668+
652669
# Use the high-resolution (48x48 px) icon if it exists and is needed
653670
with Image.open(path_large if (size > 24 and path_large.exists())
654671
else path_regular) as im:
655672
image = ImageTk.PhotoImage(im.resize((size, size)), master=self)
656-
button.configure(image=image, height='18p', width='18p')
657-
button._ntimage = image # Prevent garbage collection.
673+
button._ntimage = image
674+
675+
# create a version of the icon with the button's text color
676+
foreground = (255 / 65535) * np.array(
677+
button.winfo_rgb(button.cget("foreground")))
678+
im_alt = _recolor_icon(im, foreground)
679+
image_alt = ImageTk.PhotoImage(
680+
im_alt.resize((size, size)), master=self)
681+
button._ntimage_alt = image_alt
682+
683+
if _is_dark("background"):
684+
button.configure(image=image_alt)
685+
else:
686+
button.configure(image=image)
687+
if (
688+
isinstance(button, tk.Checkbutton)
689+
and button.cget("selectcolor") != ""
690+
):
691+
if self._windowingsystem != "x11":
692+
selectcolor = "selectcolor"
693+
else:
694+
# On X11, selectcolor isn't used directly for indicator-less
695+
# buttons.
696+
r1, g1, b1 = _get_color("selectcolor")
697+
r2, g2, b2 = _get_color("activebackground")
698+
selectcolor = ((r1+r2)/2, (g1+g2)/2, (b1+b2)/2)
699+
if _is_dark(selectcolor):
700+
button.configure(selectimage=image_alt)
701+
else:
702+
button.configure(selectimage=image)
703+
704+
button.configure(height='18p', width='18p')
658705

659706
def _Button(self, text, image_file, toggle, command):
660707
if not toggle:

‎lib/matplotlib/tests/test_backend_tk.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,42 @@ class Toolbar(NavigationToolbar2Tk):
185185
print("success")
186186
Toolbar(fig.canvas, fig.canvas.manager.window) # This should not raise.
187187
print("success")
188+
189+
190+
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
191+
@_isolated_tk_test(success_count=2)
192+
def test_embedding(): # pragma: no cover
193+
import tkinter as tk
194+
from matplotlib.backends.backend_tkagg import (
195+
FigureCanvasTkAgg, NavigationToolbar2Tk)
196+
from matplotlib.backend_bases import key_press_handler
197+
from matplotlib.figure import Figure
198+
199+
root = tk.Tk()
200+
201+
def test_figure(master):
202+
fig = Figure()
203+
ax = fig.add_subplot()
204+
ax.plot([1, 2, 3])
205+
206+
canvas = FigureCanvasTkAgg(fig, master=master)
207+
canvas.draw()
208+
canvas.mpl_connect("key_press_event", key_press_handler)
209+
canvas.get_tk_widget().pack(expand=True, fill="both")
210+
211+
toolbar = NavigationToolbar2Tk(canvas, master, pack_toolbar=False)
212+
toolbar.pack(expand=True, fill="x")
213+
214+
canvas.get_tk_widget().forget()
215+
toolbar.forget()
216+
217+
test_figure(root)
218+
print("success")
219+
220+
# Test with a dark button color. Doesn't actually check whether the icon
221+
# color becomes lighter, just that the code doesn't break.
222+
223+
root.tk_setPalette(background="sky blue", selectColor="midnight blue",
224+
foreground="white")
225+
test_figure(root)
226+
print("success")

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /