Skip to content

feat (display): RTTank-based Progress Bar backend — scale, alarm limits, and stacking support (opt-in via preference) - #3768

Open
emilioheredia-source wants to merge 4 commits into
ControlSystemStudio:masterfrom
emilioheredia-source:progressbar_scale
Open

emilioheredia-source wants to merge 4 commits into
ControlSystemStudio:masterfrom
emilioheredia-source:progressbar_scale

Conversation

@emilioheredia-source

@emilioheredia-source emilioheredia-source commented Apr 4, 2026

Copy link
Copy Markdown

Depends on #3767. This branch is stacked on display/rtscaled-tank-refactor: the first 3 commits here are #3767, only the last 3 commits are this PR. Please review and merge #3767 first; this PR will then show only its own diff. Until then the ReadTheDocs check may fail to compile RTProgressBarRepresentation, which extends RTScaledWidgetRepresentation from #3767.

Update (Sep 2026)

Rebased onto current master and reworked after re-reading it:

  • The stock ProgressBarRepresentation is no longer touched. An earlier revision of this PR edited it and, as a side effect, dropped its handling of inverted ranges (minimum > maximum, added in 2023). That is gone: with the default preference the widget is byte-for-byte the code on master, including the recent fix for vertical bars inside a Group (Vertical progress bar causes Group widget to extend further than it should #3833).
  • The parallel_rendering changes that used to be part of this PR were merged separately as perf(rtplot): add parallel_rendering preference for RTTank UpdateThrottle #3766 and are dropped here.
  • Default widget size and defaults of the pre-existing properties are unchanged.
  • The new renderer honours inverted ranges the same way the stock one does (fill from the opposite end), which relies on the small RTTank fix in fix (rtplot): RTTank ignores inverted ranges and the label format on linear scales #3929. Without that fix an inverted range is ignored, as it is for the Tank on master today.
  • The border is persisted as tank_border_width, the name the Tank already uses, for all scaled widgets: every legacy BOY .opi widget carries a <border_width> element, and a property of that name would have turned it into a bar border on import. ProgressBarWidgetUnitTest has a BOY import test for exactly that, and the importer now also maps BOY's level_hi/level_lo.
  • TankRepresentation uses the same shared listener/look helpers as the new representation, so the Tank and the Progress Bar really share the code.

Summary

This PR adds a second rendering backend for the existing ProgressBar widget, based on RTTank, the engine behind the Tank widget. It is opt-in through a preference:

org.csstudio.display.builder.representation/progressbar_scale_mode=false
  • false (default): the stock JavaFX ProgressBarRepresentation is used. Nothing changes for existing displays.
  • true: RTProgressBarRepresentation is used for all Progress Bar widgets of that Phoebus instance.

The RTTank backend uses a different rendering path than the stock control (Java2D offscreen, blitted to a Canvas), which costs more CPU while the widget updates. For a discussion with side-by-side recordings see the comments in #3766. The widget also looks slightly different from the stock control (font, scale, fill), so making it the default would change every existing screen. Hence the preference.

Screenshots

New renderer (progressbar_scale_mode=true), same .bob file:

progressbar_new_renderer

Stock renderer (default), same .bob file; the scale properties are simply ignored:
progressbar_stock_renderer

What the new renderer adds

  • Numeric scale next to the bar (scale_visible, off by default so a bar looks like a bar until asked otherwise), with format, precision, major_ticks/minor_ticks, show_minor_ticks, perpendicular_tick_labels
  • Optional second scale on the opposite side (opposite_scale_visible)
  • show_scale_labels=false draws tick marks without text, for stacking several bars under one labelled scale (see screenshot)
  • Alarm limit lines LOLO / LO / HI / HIHI, from the PV or from level_* properties; PV limits are solid, manual ones dashed
  • log_scale with a proper log axis
  • tank_border_width and inner_padding (gap between widget edge and bar, default 3 px to match the stock CSS inset)
  • font and foreground_color for the scale

Model changes

ProgressBarWidget now extends ScaledPVWidget (shared with TankWidget since #3760), which is where the range, format and alarm limit properties come from. The scale look properties (font, fill color, log scale, scale visibility, tick options, border width) are defined once in ScaledPVWidget.defineScaleLookProperties() so the Thermometer PR can reuse them; the Tank keeps its own definitions and its released tank_border_width name. Existing .bob files load unchanged: fill_color, background_color, horizontal, limits_from_pv, minimum, maximum and log_scale keep their names. Older Phoebus versions ignore the new elements.

The property panel hides the scale-only properties while the stock renderer is selected (ProgressBarWidget.SCALE_MODE_PROPS), so operators do not see settings that have no effect. This is a deliberate, small coupling between the editor and the renderer preference; if you would rather keep the editor widget-agnostic, that check can simply be dropped and the properties shown.

The BOY .opi importer picks up show_scale and scale_font; the EDM converter maps the activeBar scale flag, range, precision and border.

Design note

Two renderers for one widget type, selected globally, is a compromise. A new widget type would force every existing .bob to be migrated; a per-widget renderer property would leak the representation choice into the model. The preference keeps the model untouched, is reversible, and lets sites try the new renderer on real screens without editing files. If it proves out, it can become the default in a later release.

Files changed

Area Files
Widget model ProgressBarWidget.java, ScaledPVWidget.java (shared scale look properties), TankWidget.java (uses them), Messages.java, messages*.properties, ProgressBarWidgetUnitTest.java, TankWidgetUnitTest.java
Representation RTProgressBarRepresentation.java (new), RTScaledWidgetRepresentation.java (shared listener/look helpers), TankRepresentation.java (uses them), BaseWidgetRepresentations.java
RTTank RTTank.java (inner_padding, flat track)
Preference Preferences.java, display_representation_preferences.properties
Editor PropertyPanelSection.java
Converter Convert_activeBarClass.java

Testing

Default:

  1. Open displays with Progress Bar widgets without the preference: identical to before, including minimum > maximum bars.

With progressbar_scale_mode=true:
2. Existing .bob files open normally; the property panel shows the new properties.
3. scale_visible on/off, minimum/maximum, major_ticks/minor_ticks, show_minor_ticks, perpendicular_tick_labels.
4. format/precision: labels update.
5. limits_from_pv with a PV that carries LOLO/LO/HI/HIHI (e.g. sim://sine(0,100,2)) and show_alarm_limits=true: lines at the right positions; alarm_limits_from_pv=false with level_* gives dashed lines.
6. show_scale_labels=false on stacked bars: ticks stay, text goes.
7. inner_padding 0..20, tank_border_width 0..5, foreground_color for the scale.
8. horizontal=false; minimum > maximum in both orientations (needs #3929).
9. Tank widgets on the same display are unaffected.

Checklist

  • Testing:
    • The feature has automated tests (ProgressBarWidgetUnitTest: defaults, legacy file loads unchanged, XML round trip of the new properties, default widget writes no new elements, hidden-property list matches real properties)
    • Tests were run (mvn install with tests on the touched modules, plus the manual checks above)
  • Documentation:
    • Release notes:
      • Added an entry when adding a new feature

@sonarqubecloud

sonarqubecloud Bot commented Apr 4, 2026

Copy link
Copy Markdown

@emilioheredia-source

Copy link
Copy Markdown
Author

SonarCloud findings — triage note

SonarCloud flagged 54 issues on this PR. I reviewed all of them; here is the breakdown.

Fixed (2 issues introduced by this PR)

  • RTTank.java — "commented-out code" at L602: the multi-line inset comment contained arithmetic expressions that Sonar mis-identified as dead code. Condensed to a single descriptive line.
  • RTTank.java — cognitive complexity > 15 at L625 (updateImageBuffer): extracted the alarm-limit drawing block into a private drawAlarmLimits() helper, bringing complexity from 17 down to ~14.

Both fixes are in the latest commit on this branch.

Pre-existing / false positives (52 issues not touched)

Category Example Reason not fixed
snake_case field names fill_color, scale_visible, inner_padding, … Codebase-wide convention used by every Widget, RTPlot class, and the @Preference framework. Renaming our fields would be inconsistent.
"Extract assignment from expression" in defineProperties properties.add(x = prop.create(...)) Standard pattern in every Widget class in the project (pre-existing, not introduced here).
@Preference fields not final (parallel_rendering, progressbar_scale_mode) Activator.java, Preferences.java The AnnotatedPreferences framework writes to these fields at startup via reflection — they cannot be final. Same pattern in all other Activator/Preferences classes.
Messages.java fields not static final WidgetProperties_InnerPadding, WidgetProperties_ShowScaleLabels NLS framework populates them at class-load time via reflection, as it does for all 400+ existing fields in that file.
Method name clashes with superclass field (Blocker) propBorderWidth(), propScaleVisible(), … in ProgressBarWidget The same methods and pattern already exist in TankWidget (flagged separately as pre-existing issues in Sonar, visible with age "3 days"). We replicated the established pattern. The correct fix would be a broader refactor of the Widget accessor convention, which is out of scope for this PR.

…scale_labels to Tank

Move everything in TankRepresentation that only depends on the
ScaledPVWidget contract into an abstract RTScaledWidgetRepresentation:
creating the RTTank, forwarding value and range updates, evaluating the
alarm limits, the orientation transform and the update scheduling.
TankRepresentation keeps the Tank specific listeners and colors. The
behaviour of the Tank widget does not change.

Add a 'show_scale_labels' property (default true) to the Tank so that
stacked widgets can share one labelled scale: with the property off,
YAxisImpl draws the tick marks and the axis line only. Tick positions
are the same as with labels.

TankWidgetUnitTest covers the new property.
Move the progress bar onto the ScaledPVWidget base class that the Tank
already uses, so it carries the same range, scale and alarm limit
properties, plus an inner padding.

The scale look properties (font, foreground and fill color, log scale,
scale visibility, tick options, border width) now live in ScaledPVWidget
with a defineScaleLookProperties() helper, and the Tank uses the same
fields in its own order. The border keeps the Tank's 'tank_border_width'
name for all scaled widgets: legacy BOY files carry a 'border_width'
element for every widget, which must not become a bar border.

The stock renderer ignores the additions, and existing .bob files keep
loading unchanged since the pre-existing properties keep their names.
The BOY importer picks up 'show_scale', 'scale_font' and the 'level_hi'
and 'level_lo' names that differ from ours.

ProgressBarWidgetUnitTest covers defaults, legacy .bob and BOY files,
the XML round trip and the list of renderer-only properties.
Add RTProgressBarRepresentation, which draws the progress bar with the
RTTank engine shared with the Tank widget. This gives the bar a numeric
scale with format and precision, an optional opposite scale, minor
ticks, tick-only mode for stacked bars, and alarm limit lines.

RTTank gains an inner padding and a flat track for the progress bar
look. RTScaledWidgetRepresentation gains registerScaleLookListeners()
and applyScaleLook() for the scale look properties that ScaledPVWidget
defines; TankRepresentation and the new representation use them and
only handle their own extras.

The renderer is selected with the new preference

    org.csstudio.display.builder.representation/progressbar_scale_mode

which defaults to false. With the default, the stock JavaFX
ProgressBarRepresentation is used and nothing changes for existing
displays. The property panel hides the renderer-only properties while
the stock renderer is in use.
The EDM 'activeBar' carries a scale flag, a fixed range, a precision and
a border flag that the progress bar can now represent.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants