Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c4c7152

Browse files
daniilStimhoffm
andcommitted
Change colour of Tk toolbar icons on dark backgrounds
Co-Authored-By: Tim Hoffmann <[email protected]>
1 parent eaadeb6 commit c4c7152

File tree

2 files changed

+75
-2
lines changed

2 files changed

+75
-2
lines changed

lib/matplotlib/backends/_backend_tk.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -649,12 +649,46 @@ 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 _is_dark(color):
655+
# `winfo_rgb` returns an (r, g, b) tuple in the range 0-65535
656+
return max(button.winfo_rgb(button.cget(color))) < 65535 / 2
657+
658+
def _recolor_icon(image, color):
659+
image_data = np.asarray(image).copy()
660+
black_mask = (image_data[..., :3] == 0).all(axis=-1)
661+
image_data[black_mask, :3] = color
662+
return Image.fromarray(image_data, mode="RGBA")
663+
652664
# Use the high-resolution (48x48 px) icon if it exists and is needed
653665
with Image.open(path_large if (size > 24 and path_large.exists())
654666
else path_regular) as im:
655667
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.
668+
button._ntimage = image
669+
670+
# create a version of the icon with the button's text color
671+
foreground = (255 / 65535) * np.array(
672+
button.winfo_rgb(button.cget("foreground")))
673+
im_alt = _recolor_icon(im, foreground)
674+
image_alt = ImageTk.PhotoImage(
675+
im_alt.resize((size, size)), master=self)
676+
button._ntimage_alt = image_alt
677+
678+
if _is_dark("background"):
679+
button.configure(image=image_alt)
680+
else:
681+
button.configure(image=image)
682+
if (
683+
isinstance(button, tk.Checkbutton)
684+
and button.cget("selectcolor") != ""
685+
):
686+
if _is_dark("selectcolor"):
687+
button.configure(selectimage=image_alt)
688+
else:
689+
button.configure(selectimage=image)
690+
691+
button.configure(height='18p', width='18p')
658692

659693
def _Button(self, text, image_file, toggle, command):
660694
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)