@@ -277,6 +277,8 @@ function viewgui(fcolor, gdict::NestedGraphDict; data=nothing, lidict=nothing, w
277
277
Gtk4. tooltip_text (tb_zoom_out, " zoom out" )
278
278
tb_info = GtkButton (:icon_name , " dialog-information-symbolic" )
279
279
Gtk4. tooltip_text (tb_info, " ProfileView tips" )
280
+ tb_labels = GtkButton (:icon_name , " font-x-generic-symbolic" )
281
+ Gtk4. tooltip_text (tb_labels, " Show labels" )
280
282
tb_text = GtkEntry ()
281
283
Gtk4. has_frame (tb_text, false )
282
284
Gtk4. sensitive (tb_text, false )
@@ -291,6 +293,8 @@ function viewgui(fcolor, gdict::NestedGraphDict; data=nothing, lidict=nothing, w
291
293
push! (tb, GtkSeparator (:h ))
292
294
push! (tb, tb_info)
293
295
push! (tb, GtkSeparator (:h ))
296
+ push! (tb, tb_labels)
297
+ push! (tb, GtkSeparator (:h ))
294
298
push! (tb, tb_text)
295
299
# FIXME : likely have to do `allkwargs` in the open/save below (add in C, combine, recur)
296
300
signal_connect (open_cb, tb_open, " clicked" , Nothing, (), false , (widget (c),gsig,kwargs))
@@ -302,7 +306,7 @@ function viewgui(fcolor, gdict::NestedGraphDict; data=nothing, lidict=nothing, w
302
306
push! (bx, f)
303
307
# don't use the actual taskid as the tab as it's very long
304
308
push! (nb_tasks, bx, task_tab_num == 1 ? string (task_tab) : string (task_tab_num - 1 ))
305
- fdraw = viewprof (fcolor, c, gsig, (tb_zoom_fit, tb_zoom_out, tb_zoom_in, tb_text), graphtype; kwargs... )
309
+ fdraw = viewprof (fcolor, c, gsig, (tb_zoom_fit, tb_zoom_out, tb_zoom_in, tb_labels, tb_text), graphtype; kwargs... )
306
310
GtkObservables. gc_preserve (nb_threads, c)
307
311
GtkObservables. gc_preserve (nb_threads, fdraw)
308
312
_c, _fdraw, _tb_open, _tb_save_as = c, fdraw, tb_open, tb_save_as
@@ -343,7 +347,7 @@ function viewprof_func(fcolor, c, g, fontsize, tb_items, graphtype)
343
347
if ! in (graphtype, (:flame , :icicle ))
344
348
throw (ArgumentError (" Invalid option for `graphtype`: `$(repr (graphtype)) `. Valid options are `:flame` and `:icicle`" ))
345
349
end
346
- tb_zoom_fit, tb_zoom_out, tb_zoom_in, tb_text = tb_items
350
+ tb_zoom_fit, tb_zoom_out, tb_zoom_in, tb_labels, tb_text = tb_items
347
351
# From a given position, find the underlying tag
348
352
function gettag (tagimg, xu, yu)
349
353
x = ceil (Int, Float64 (xu))
@@ -365,6 +369,8 @@ function viewprof_func(fcolor, c, g, fontsize, tb_items, graphtype)
365
369
BoundingBox (0 , Graphics. width (c), 0 , Graphics. height (c))
366
370
end
367
371
end
372
+ row_height (c, bb_cv) = (Graphics. height (c) / ((bb_cv. ymax - bb_cv. ymin) + 1 ))
373
+ min_row_height_show_labels = 5 # Empirically defined on macOS based on text readablility
368
374
369
375
isempty (g. data. span) && return nothing
370
376
img = flamepixels (fcolor, g)
@@ -378,34 +384,90 @@ function viewprof_func(fcolor, c, g, fontsize, tb_items, graphtype)
378
384
signal_connect (zoom_fit_cb, tb_zoom_fit, " clicked" , Nothing, (), false , (zr))
379
385
signal_connect (zoom_out_cb, tb_zoom_out, " clicked" , Nothing, (), false , (zr))
380
386
signal_connect (zoom_in_cb, tb_zoom_in, " clicked" , Nothing, (), false , (zr))
387
+ show_labels = Observable {Bool} (false ) # TODO : default on? Preference?
388
+ signal_connect (toggle_labels_cb, tb_labels, " clicked" , Nothing, (), false , (show_labels))
381
389
sigrb = init_zoom_rubberband (c, zr)
382
390
sigpd = init_pan_drag (c, zr)
383
391
sigzs = init_zoom_scroll (c, zr)
384
392
sigps = init_pan_scroll (c, zr)
385
393
surf = Cairo. CairoImageSurface (img24)
386
394
append! (c. preserved, Any[sigrb, sigpd, sigzs, sigps])
387
395
let tagimg= tagimg # julia#15276
388
- sigredraw = draw (c, zr) do widget, r
396
+ sigredraw = draw (c, zr, show_labels ) do widget, r, _show_labels
389
397
ctx = getgc (widget)
390
- set_coordinates (ctx, device_bb (ctx), BoundingBox (r. currentview))
391
- rectangle (ctx, BoundingBox (r. currentview))
398
+ bb_cv = BoundingBox (r. currentview)
399
+ set_coordinates (ctx, device_bb (ctx), bb_cv)
400
+ rectangle (ctx, bb_cv)
392
401
set_source (ctx, surf)
393
402
p = Cairo. get_source (ctx)
394
403
Cairo. pattern_set_filter (p, Cairo. FILTER_NEAREST)
395
404
fill (ctx)
405
+ row_h = row_height (c, bb_cv)
406
+ rows_tall_enough = row_h > min_row_height_show_labels
407
+ if _show_labels && rows_tall_enough
408
+ seen_sfs = IdDict {StackFrame, Tuple{Int, Int, Int, Int}} () # Store bounding boxes
409
+ for y in axes (tagimg, 2 )
410
+ for x in axes (tagimg, 1 )
411
+ sf = gettag (tagimg, x, y - 0.5 )
412
+ sf == StackTraces. UNKNOWN && continue
413
+ if ! haskey (seen_sfs, sf)
414
+ seen_sfs[sf] = (x, y, x, y) # Initialize bounding box
415
+ else
416
+ bx, by, ex, ey = seen_sfs[sf]
417
+ seen_sfs[sf] = (min (bx, x), min (by, y), max (ex, x), max (ey, y))
418
+ end
419
+ end
420
+ end
421
+ # Render text within each bounding box
422
+ for (sf, (bx, _by, ex, _ey)) in seen_sfs
423
+ for by in _by: _ey # workaround when a sf is repeated on two rows
424
+ ey = by
425
+ d_bb = device_bb (ctx)
426
+ set_coordinates (ctx, d_bb, bb_cv)
427
+ set_source (ctx, fcolor (:font ))
428
+ Cairo. set_font_size (ctx, min (row_h, fontsize))
429
+ Cairo. select_font_face (ctx, " sans-serif" , Cairo. FONT_SLANT_NORMAL, Cairo. FONT_WEIGHT_NORMAL)
430
+
431
+ str = strip (string (sf. func, " " , basename (string (sf. file)), " :" , sf. line))
432
+ _, _, tbb_width, tbb_height, _, _ = Cairo. text_extents (ctx, str)
433
+
434
+ # Define clipping region to constrain text
435
+ Cairo. rectangle (ctx, bx - 1 , by - 1 , ex - bx + 1 , ey - by + 1 )
436
+ Cairo. clip (ctx)
437
+
438
+ x_scale = (bb_cv. xmax - bb_cv. xmin) / (d_bb. xmax - d_bb. xmin)
439
+ y_scale = (bb_cv. ymax - bb_cv. ymin) / (d_bb. ymax - d_bb. ymin)
440
+ x_min, x_max = max (bx, bb_cv. xmin), min (ex, bb_cv. xmax)
441
+ y_min, y_max = max (by, bb_cv. ymin), min (ey, bb_cv. ymax)
442
+ middle_x = x_min + ((x_max - x_min) / 2 )
443
+ middle_y = y_min + ((y_max - y_min) / 2 ) - 0.5 # matches the - 0.5 above during the scan
444
+ text_x = middle_x - ((x_scale * tbb_width) / 2 ) # center-align
445
+ text_y = middle_y + ((y_scale * tbb_height) / 2 )
446
+
447
+ Cairo. move_to (ctx, text_x, text_y)
448
+ Cairo. scale (ctx, x_scale, y_scale) # otherwise text is stretched
449
+ Cairo. show_text (ctx, str)
450
+
451
+ Cairo. reset_clip (ctx)
452
+ end
453
+ end
454
+ end
396
455
end
397
456
lasttextbb = Ref (BoundingBox (1 ,0 ,1 ,0 ))
398
457
sigmotion = on (c. mouse. motion) do btn
399
- # Repair image from ovewritten text
400
458
if c. widget. is_sized
401
459
ctx = getgc (c)
402
- if Graphics. width (lasttextbb[]) > 0
403
- r = zr[]
404
- set_coordinates (ctx, device_bb (ctx), BoundingBox (r. currentview))
460
+ r = zr[]
461
+ bb_cv = BoundingBox (r. currentview)
462
+ set_coordinates (ctx, device_bb (ctx), bb_cv)
463
+ row_h = row_height (c, bb_cv)
464
+ rows_tall_enough = row_h > min_row_height_show_labels
465
+ _show_labels = rows_tall_enough && show_labels[]
466
+ if ! _show_labels && Graphics. width (lasttextbb[]) > 0
405
467
# The bbox returned by deform/Cairo.text below is malformed when the y-axis is inverted
406
468
# so redraw the whole screen in :icicle mode
407
469
# TODO : Fix the bbox for efficient redraw
408
- rectangle (ctx, graphtype == :icicle ? BoundingBox (r . currentview) : lasttextbb[])
470
+ rectangle (ctx, graphtype == :icicle ? bb_cv : lasttextbb[])
409
471
set_source (ctx, surf)
410
472
p = Cairo. get_source (ctx)
411
473
Cairo. pattern_set_filter (p, Cairo. FILTER_NEAREST)
@@ -418,12 +480,14 @@ function viewprof_func(fcolor, c, g, fontsize, tb_items, graphtype)
418
480
if sf != StackTraces. UNKNOWN
419
481
str_long = long_info_str (sf)
420
482
b[String] = str_long
421
- str = short_info_str (sf)
422
- set_source (ctx, fcolor (:font ))
423
- Cairo. set_font_face (ctx, " sans-serif $(fontsize) px" )
424
- xi = zr[]. currentview. x
425
- xmin, xmax = minimum (xi), maximum (xi)
426
- lasttextbb[] = deform (Cairo. text (ctx, xu, yu, str, halign = xu < (2 xmin+ xmax)/ 3 ? " left" : xu < (xmin+ 2 xmax)/ 3 ? " center" : " right" ), - 2 , 2 , - 2 , 2 )
483
+ if ! _show_labels
484
+ str = short_info_str (sf)
485
+ set_source (ctx, fcolor (:font ))
486
+ Cairo. set_font_face (ctx, " sans-serif $(fontsize) px" )
487
+ xi = zr[]. currentview. x
488
+ xmin, xmax = minimum (xi), maximum (xi)
489
+ lasttextbb[] = deform (Cairo. text (ctx, xu, yu, str, halign = xu < (2 xmin+ xmax)/ 3 ? " left" : xu < (xmin+ 2 xmax)/ 3 ? " center" : " right" ), - 2 , 2 , - 2 , 2 )
490
+ end
427
491
else
428
492
b[String]= " "
429
493
end
536
600
return nothing
537
601
end
538
602
603
+ @guarded function toggle_labels_cb (:: Ptr , show_labels:: Observable{Bool} )
604
+ show_labels[] = ! show_labels[]
605
+ return nothing
606
+ end
607
+
539
608
@guarded function info_cb (:: Ptr , win:: Tuple )
540
609
# Note: Keep this updated with the readme
541
610
info = """
0 commit comments