Skip to content

Commit a7aa337

Browse files
authored
better Mac support (#32)
- If dark mode is enabled on your machine, you get white text on a black background, and the highlighting color should change from light to dark to match (so the highlighted token is either black text on a yellow-instead-of-white background, or white text on a grey-instead-of-black background). - Two-finger scrolling on a touchpad uses the new-in-9.0.0 Tcl/Tk event TouchpadScroll. - Scrolling with a mouse wheel on a Mac seems to set the `delta` to +/-120 instead of +/-1, so just take the sign before zooming by that amount. * support dark mode when relevant * add support for touchpad scrolling * fix scroll-to-zoom on Mac * tweak: pre-compute the highlight color only once * linux uses a version of Tcl/Tk that doesn't have TouchpadScroll * update readme to be more confident of how to install it * tweak: make the touchpad zooming less twitchy * tweak: in dark mode, highlight with grey, not dimgrey * tweak: make zooming on a touchpad slightly more responsive
1 parent 08a6722 commit a7aa337

File tree

4 files changed

+34
-7
lines changed

4 files changed

+34
-7
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ for Python. This might require installing something outside of your virtual
3232
environment: you'll know it's set up right if you can run `python3 -m tkinter`
3333
and get a little interactive window to pop up.
3434

35-
- On Mac, try `brew install python-tk` to install that.
36-
- On Ubuntu, you might try `sudo apt-get install python3-pil.imagetk` to get
37-
Tcl/Tk set up correctly. I don't remember exactly what I did that finally
38-
worked, but that was one of the things I tried.
35+
- On Mac: `brew install python-tk`
36+
- On Ubuntu: `sudo apt-get install python3-pil.imagetk`
3937

4038
After that, just `pip3 install -r requirements.txt`, and you should be good!
4139

gui.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import darkdetect
12
from math import ceil
23
import numpy
34
import numpy.typing
@@ -57,6 +58,7 @@ def __init__(
5758
self._lines = data.lines
5859
self._boundaries = data.boundaries
5960
self._zoom_map = zoom_map
61+
self._highlight_color = "grey" if darkdetect.isDark() else "yellow"
6062

6163
def _snip_line(self, i: int) -> str:
6264
"""
@@ -114,7 +116,7 @@ def display(self, pixel: int) -> None:
114116
ac + self.PRELUDE_WIDTH),
115117
"{}.{}".format(self.CONTEXT_COUNT + 1 + br - ar,
116118
bc + self.PRELUDE_WIDTH))
117-
self.tag_config("token", background="yellow")
119+
self.tag_config("token", background=self._highlight_color)
118120

119121
# ...but don't highlight the line numbers on multi-line tokens.
120122
for i in range(self.CONTEXT_COUNT):

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ code_ast==0.1.0
44
code_tokenize==0.2.0
55
contourpy==1.3.0
66
cycler==0.12.1
7+
darkdetect==0.8.0
78
fonttools==4.54.1
89
gitdb==4.0.11
910
GitPython==3.1.43

zoom_map.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import numpy.typing
44
import PIL.Image
55
import PIL.ImageTk
6+
import platform
67
import tkinter as tk
78
from typing import Optional
89

@@ -44,6 +45,11 @@ def __init__(
4445
# every function will be Callable: some are methods and some are
4546
# functools.partial objects.
4647
self.bind(button_name, function) # type: ignore
48+
if platform.system() == "Darwin":
49+
# Macs use Tcl/Tk version 9.0.0 or later to get touchpad support,
50+
# whereas (as of January 2025) Ubuntu uses Tcl/Tk version 8.6.14,
51+
# which lacks this event type.
52+
self.bind("<TouchpadScroll>", self._zoom_touchpad)
4753

4854
def _set_image(self) -> None:
4955
"""
@@ -82,11 +88,31 @@ def _set_image(self) -> None:
8288
image=self._cached_image)
8389

8490
def _zoom_mac(self, event: tk.Event) -> None:
85-
self._zoom(-event.delta, event)
91+
sign = 1 if event.delta > 0 else -1
92+
self._zoom(-sign, event)
93+
94+
_zoom_touchpad_amount: int = 0
95+
def _zoom_touchpad(self, event: tk.Event) -> None:
96+
# The event's delta is two 2-byte signed words packed together.
97+
delta_x = (event.delta >> 16) & 0xFFFF
98+
delta_y = (event.delta >> 0) & 0xFFFF
99+
if delta_x >= 2 ** 15:
100+
delta_x -= 2 ** 16
101+
if delta_y >= 2 ** 15:
102+
delta_y -= 2 ** 16
103+
104+
# We get lots of events about tiny movements. Sum them up and only
105+
# change zoom levels if there have been a bunch all in the same
106+
# direction.
107+
self._zoom_touchpad_amount += delta_x + delta_y
108+
if abs(self._zoom_touchpad_amount) > 20:
109+
sign = 1 if self._zoom_touchpad_amount > 0 else -1
110+
self._zoom_touchpad_amount = 0
111+
self._zoom(-sign, event)
86112

87113
def _zoom(self, amount: int, event: tk.Event) -> None:
88114
if not self._pyramid.zoom(amount):
89-
return
115+
return # We're at an extreme level, and didn't actually zoom.
90116

91117
# Otherwise, we changed zoom levels, so adjust everything accordingly.
92118
# We need to move the map so the pixels that started under the mouse are

0 commit comments

Comments
 (0)