Skip to content

Commit 096a3ba

Browse files
committed
fix: Align breakpoints rendering
1 parent eab674a commit 096a3ba

File tree

1 file changed

+53
-19
lines changed

1 file changed

+53
-19
lines changed

sandbox/sandbox.py

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -148,23 +148,36 @@ def create_main_panel(self):
148148
editor_frame = ttk.Frame(left_frame)
149149
editor_frame.pack(fill=tk.BOTH, expand=True)
150150

151+
# Common font for alignment
152+
self.editor_font = ('Consolas', 11)
153+
151154
# Line numbers
152155
self.line_numbers = tk.Text(editor_frame, width=4, padx=3, pady=3, takefocus=0,
153-
border=0, background='lightgray', state=tk.DISABLED)
156+
border=0, background='lightgray', state=tk.DISABLED,
157+
font=self.editor_font)
154158
self.line_numbers.pack(side=tk.LEFT, fill=tk.Y)
155159

156160
# Breakpoint indicators
157-
self.breakpoint_canvas = tk.Canvas(editor_frame, width=20, bg='lightgray')
161+
self.breakpoint_canvas = tk.Canvas(editor_frame, width=20, bg='lightgray', highlightthickness=0)
158162
self.breakpoint_canvas.pack(side=tk.LEFT, fill=tk.Y)
159163

160164
# Main editor
161-
self.editor = scrolledtext.ScrolledText(editor_frame, wrap=tk.NONE, undo=True, font=('Consolas', 10))
165+
self.editor = scrolledtext.ScrolledText(editor_frame, wrap=tk.NONE, undo=True, font=self.editor_font)
162166
self.editor.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
163167

164-
# Bind events
168+
# Bind events for alignment and updates
165169
self.editor.bind('<KeyRelease>', self.on_text_change)
166170
self.editor.bind('<Button-1>', self.on_click)
167171
self.editor.bind('<Control-Button-1>', self.toggle_breakpoint)
172+
self.editor.bind('<Configure>', lambda e: self.update_line_numbers())
173+
174+
# Sync scrolling
175+
def sync_scroll(*args):
176+
self.line_numbers.yview_moveto(args[0])
177+
self.update_breakpoint_indicators()
178+
179+
# We need to hook into the underlying text widget's scroll
180+
self.editor.vbar.config(command=self.on_scroll)
168181

169182
# Bind breakpoint canvas clicks
170183
self.breakpoint_canvas.bind('<Button-1>', self.on_breakpoint_click)
@@ -263,30 +276,38 @@ def create_status_bar(self):
263276
self.debug_status_label = ttk.Label(self.status_bar, text="Not Debugging")
264277
self.debug_status_label.pack(side=tk.RIGHT, padx=5)
265278

279+
def on_scroll(self, *args):
280+
self.editor.yview(*args)
281+
self.line_numbers.yview_moveto(self.editor.yview()[0])
282+
self.update_breakpoint_indicators()
283+
266284
def update_line_numbers(self):
267285
self.line_numbers.config(state=tk.NORMAL)
268286
self.line_numbers.delete(1.0, tk.END)
269287

270288
line_count = int(self.editor.index('end-1c').split('.')[0])
271-
for i in range(1, line_count + 1):
272-
self.line_numbers.insert(tk.END, f"{i}\n")
289+
lines = "\n".join(str(i) for i in range(1, line_count + 1))
290+
self.line_numbers.insert(1.0, lines)
273291

274292
self.line_numbers.config(state=tk.DISABLED)
293+
self.line_numbers.yview_moveto(self.editor.yview()[0])
275294

276295
# Update breakpoint indicators
277296
self.update_breakpoint_indicators()
278297

279298
def update_breakpoint_indicators(self):
280299
self.breakpoint_canvas.delete("all")
281300

282-
line_count = int(self.editor.index('end-1c').split('.')[0])
283-
line_height = 21 # approximate line height
284-
285301
for line_num in self.breakpoints:
286-
if line_num <= line_count:
287-
y = (line_num - 1) * line_height + 10
288-
# Draw a red circle for breakpoint
289-
self.breakpoint_canvas.create_oval(5, y-5, 15, y+5, fill='red', outline='darkred')
302+
# Use dlineinfo to get the exact y-coordinate of the line on screen
303+
try:
304+
dinfo = self.editor.dlineinfo(f"{line_num}.0")
305+
if dinfo:
306+
y = dinfo[1] + (dinfo[3] // 2)
307+
# Draw a red circle for breakpoint
308+
self.breakpoint_canvas.create_oval(5, y-5, 15, y+5, fill='red', outline='darkred')
309+
except tk.TclError:
310+
continue
290311

291312
def on_text_change(self, event=None):
292313
self.update_line_numbers()
@@ -298,12 +319,25 @@ def on_breakpoint_click(self, event=None):
298319
if not self.current_file:
299320
return
300321

301-
line_height = 20
302-
line_num = (event.y // line_height) + 1
303-
if line_num in self.breakpoints:
304-
self.remove_breakpoint(line_num)
305-
else:
306-
self.add_breakpoint(line_num)
322+
# Find which line was clicked by comparing y-coordinate with dlineinfo
323+
line_count = int(self.editor.index('end-1c').split('.')[0])
324+
clicked_line = None
325+
326+
for i in range(1, line_count + 1):
327+
dinfo = self.editor.dlineinfo(f"{i}.0")
328+
if dinfo:
329+
y_start = dinfo[1]
330+
y_end = dinfo[1] + dinfo[3]
331+
if y_start <= event.y <= y_end:
332+
clicked_line = i
333+
break
334+
335+
if clicked_line:
336+
if clicked_line in self.breakpoints:
337+
self.remove_breakpoint(clicked_line)
338+
else:
339+
self.add_breakpoint(clicked_line)
340+
self.update_breakpoint_indicators()
307341

308342
def toggle_breakpoint(self, event=None):
309343
if not self.current_file:

0 commit comments

Comments
 (0)