Skip to content

Commit 684f410

Browse files
add button to show all labels (#243)
1 parent ba394b1 commit 684f410

File tree

1 file changed

+85
-16
lines changed

1 file changed

+85
-16
lines changed

src/ProfileView.jl

+85-16
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ function viewgui(fcolor, gdict::NestedGraphDict; data=nothing, lidict=nothing, w
277277
Gtk4.tooltip_text(tb_zoom_out, "zoom out")
278278
tb_info = GtkButton(:icon_name, "dialog-information-symbolic")
279279
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")
280282
tb_text = GtkEntry()
281283
Gtk4.has_frame(tb_text, false)
282284
Gtk4.sensitive(tb_text, false)
@@ -291,6 +293,8 @@ function viewgui(fcolor, gdict::NestedGraphDict; data=nothing, lidict=nothing, w
291293
push!(tb, GtkSeparator(:h))
292294
push!(tb, tb_info)
293295
push!(tb, GtkSeparator(:h))
296+
push!(tb, tb_labels)
297+
push!(tb, GtkSeparator(:h))
294298
push!(tb, tb_text)
295299
# FIXME: likely have to do `allkwargs` in the open/save below (add in C, combine, recur)
296300
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
302306
push!(bx, f)
303307
# don't use the actual taskid as the tab as it's very long
304308
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...)
306310
GtkObservables.gc_preserve(nb_threads, c)
307311
GtkObservables.gc_preserve(nb_threads, fdraw)
308312
_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)
343347
if !in(graphtype, (:flame, :icicle))
344348
throw(ArgumentError("Invalid option for `graphtype`: `$(repr(graphtype))`. Valid options are `:flame` and `:icicle`"))
345349
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
347351
# From a given position, find the underlying tag
348352
function gettag(tagimg, xu, yu)
349353
x = ceil(Int, Float64(xu))
@@ -365,6 +369,8 @@ function viewprof_func(fcolor, c, g, fontsize, tb_items, graphtype)
365369
BoundingBox(0, Graphics.width(c), 0, Graphics.height(c))
366370
end
367371
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
368374

369375
isempty(g.data.span) && return nothing
370376
img = flamepixels(fcolor, g)
@@ -378,34 +384,90 @@ function viewprof_func(fcolor, c, g, fontsize, tb_items, graphtype)
378384
signal_connect(zoom_fit_cb, tb_zoom_fit, "clicked", Nothing, (), false, (zr))
379385
signal_connect(zoom_out_cb, tb_zoom_out, "clicked", Nothing, (), false, (zr))
380386
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))
381389
sigrb = init_zoom_rubberband(c, zr)
382390
sigpd = init_pan_drag(c, zr)
383391
sigzs = init_zoom_scroll(c, zr)
384392
sigps = init_pan_scroll(c, zr)
385393
surf = Cairo.CairoImageSurface(img24)
386394
append!(c.preserved, Any[sigrb, sigpd, sigzs, sigps])
387395
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
389397
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)
392401
set_source(ctx, surf)
393402
p = Cairo.get_source(ctx)
394403
Cairo.pattern_set_filter(p, Cairo.FILTER_NEAREST)
395404
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
396455
end
397456
lasttextbb = Ref(BoundingBox(1,0,1,0))
398457
sigmotion = on(c.mouse.motion) do btn
399-
# Repair image from ovewritten text
400458
if c.widget.is_sized
401459
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
405467
# The bbox returned by deform/Cairo.text below is malformed when the y-axis is inverted
406468
# so redraw the whole screen in :icicle mode
407469
# TODO: Fix the bbox for efficient redraw
408-
rectangle(ctx, graphtype == :icicle ? BoundingBox(r.currentview) : lasttextbb[])
470+
rectangle(ctx, graphtype == :icicle ? bb_cv : lasttextbb[])
409471
set_source(ctx, surf)
410472
p = Cairo.get_source(ctx)
411473
Cairo.pattern_set_filter(p, Cairo.FILTER_NEAREST)
@@ -418,12 +480,14 @@ function viewprof_func(fcolor, c, g, fontsize, tb_items, graphtype)
418480
if sf != StackTraces.UNKNOWN
419481
str_long = long_info_str(sf)
420482
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 < (2xmin+xmax)/3 ? "left" : xu < (xmin+2xmax)/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 < (2xmin+xmax)/3 ? "left" : xu < (xmin+2xmax)/3 ? "center" : "right"), -2, 2, -2, 2)
490+
end
427491
else
428492
b[String]=""
429493
end
@@ -536,6 +600,11 @@ end
536600
return nothing
537601
end
538602

603+
@guarded function toggle_labels_cb(::Ptr, show_labels::Observable{Bool})
604+
show_labels[] = !show_labels[]
605+
return nothing
606+
end
607+
539608
@guarded function info_cb(::Ptr, win::Tuple)
540609
# Note: Keep this updated with the readme
541610
info = """

0 commit comments

Comments
 (0)