From 29e4f80e587878c7c1b595d813106fcdac19b6cc Mon Sep 17 00:00:00 2001 From: uitt_hu Date: Sun, 15 Nov 2026 18:05:42 +0100 Subject: [PATCH] A message without an object says so in the corner (#90) A message of another participant that names no object of the window (announce without selected_id, or with an id that the window does not show) stands in the upper-left corner of the view as before and says "(no object)" after the name of the participant; the docs of projects say so. Co-Authored-By: Claude Opus 5.5 --- docs/src/projects.md | 4 +++- src/LiveActivityCues.jl | 8 ++++++-- test/TestLiveActivityCues.jl | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/src/projects.md b/docs/src/projects.md index 69b0bb0..e7b719d 100644 --- a/docs/src/projects.md +++ b/docs/src/projects.md @@ -74,7 +74,9 @@ Several windows and agents can work on one project at once, also from a shared d frame in the participant's colour at the new place, a dashed ghost at the old one and a soft arc between them, a small chip with the name and the change ("claude · moved M2 by 12 mm"); new objects settle into a frame, removed ones leave a ghost. What an agent says it does next - (`announce(...; doing)`) appears as a bubble at its object. The cues fade after about 3 s. When an + (`announce(...; doing, selected_id)`) appears as a bubble at its object; one that names no object + of the window stands in the upper-left corner of the view and says "(no object)" after the name. + The cues fade after about 3 s. When an agent changes things faster than one can follow, the setup changes at once, but the cues play one after the other at a readable pace; more than 3 s behind, the waiting ones become one cue ("claude · 14 changes"). diff --git a/src/LiveActivityCues.jl b/src/LiveActivityCues.jl index 1fbd078..6027026 100644 --- a/src/LiveActivityCues.jl +++ b/src/LiveActivityCues.jl @@ -52,6 +52,8 @@ const _CHIP_CHARS = 56 # A bubble: the bar of the colour at its left edge, its padding, the wrap of the message const _BUBBLE_BAR = 3.0f0 const _BUBBLE_PAD = Vec2f(8, 5) +# after the name in the bubble of a message without an object of the window, see `_new_bubble!` +const _NO_OBJECT = " (no object)" const _BUBBLE_WRAP = 40 const _BUBBLE_LINES = 3 # z translation of the chips and bubbles: after the 3D scene and in front of it, below the cards @@ -419,11 +421,13 @@ function _new_chip!(gui::LiveView, c::_CuePlots, d::_CueDrawn) end # Adds the plots of the bubble of the message of the cue `d`: a rounded box with the colour of the -# participant as a bar at its left edge, the name in bold and the message below, wrapped +# participant as a bar at its left edge, the name in bold and the message below, wrapped. A message +# that names no object of the window stands in the corner of the view (see `_chip_anchor`) and says +# so after the name function _new_bubble!(gui::LiveView, c::_CuePlots, d::_CueDrawn) ep = d.episode t = gui.layout.theme - name = _clip_text(ep.name, 24) + name = _clip_text(ep.name, 24) * (isempty(ep.items) ? _NO_OBJECT : "") lines = _wrap_text(ep.message) lh = _CHIP_FONTSIZE * _CHIP_LINEHEIGHT w = max(_chip_width(c, name; bold = true), maximum((_chip_width(c, l) for l in lines); init = 0.0f0)) diff --git a/test/TestLiveActivityCues.jl b/test/TestLiveActivityCues.jl index 8a9dd84..542447d 100644 --- a/test/TestLiveActivityCues.jl +++ b/test/TestLiveActivityCues.jl @@ -190,17 +190,19 @@ const GUI = BeamletOpticsGUI @test d.bubble @test haskey(d.plots, :bar) && !haskey(d.plots, :dot) @test _rgb(d.plots[:bar].color[]) == _rgb(GUI._activity_color(gui, "bob@PC3")) + @test GUI._label_text(d.plots[:name]) == "Bob" lines = split(GUI._label_text(d.plots[:text]), '\n') @test length(lines) == GUI._BUBBLE_LINES @test all(l -> length(l) <= GUI._BUBBLE_WRAP, lines) @test endswith(lines[end], "…") - # a message without an object: at the corner of the view + # a message without an object: at the corner of the view, which its name says GUI._clear_cues!(gui) alone = _episode(GUI._ActivityItem[]; n = 3, who = "bob@PC3", name = "Bob", text = "", message = "back in 5") GUI._draw_cues!(gui, [(alone, 1.0)], 10.0) d = only(_drawn(gui)) @test !isempty(d.plots) @test all(isfinite, d.pos[]) + @test GUI._label_text(d.plots[:name]) == "Bob (no object)" # several cues at once at one object stack their chips GUI._clear_cues!(gui)