The current Mask Painter panel has several layout and usability issues that are particularly visible in narrow side-panel contexts:
- Horizontal overflow in the class color list — The 30%/70%
HBox split gives the sorting container only ~105px at typical panel widths, causing TagsInput chips to overflow and the "Show all classes" label to truncate to "Show all c...".
ToggleButtons for outline/fill are too wide — Each row renders a ToggleButtons at 160px, causing horizontal overflow in the per-class list.
- Palette tabs always visible — The Save/Load/Manage
Tab occupies permanent vertical space even when not in use, contributing to a cluttered, scroll-heavy panel.
Output widget for feedback — Uses a console-style Output widget for status/error messages, which looks out of place and doesn't support styled text.
- No visual sectioning — There are no dividers between the identifier row, the color pickers, and palette management, making the panel hard to scan.
- "No identifier selected" warning on Save — The Save button is always enabled even before an identifier or name is set, leading to dead-end warning messages.
Proposed Changes
1. Fix the class color list layout — vertical, full-width
Replace the 30%/70% HBox split with a vertical VBox. Move TagsInput and Default color above the per-class list at full width:
VBox
├─ HBox: [Label "Class order / visible:"] [Show all □]
├─ TagsInput (full width)
├─ HBox: [Label "Default color:"] [ColorPicker]
├─ HTML <hr>
└─ VBox (per-class rows, scrollable)
[□ vis] [■ ColorPicker "ClassName"] [□ fill]
...
2. Compact outline/fill toggle
Replace ToggleButtons(options=["outline","fill"], style={"button_width":"70px"}) with a single Checkbox(description="fill", layout=Layout(width="60px")). Saves ~100px per row.
3. Wrap palette management in a collapsed Accordion
palette_accordion = Accordion(children=[color_set_tab], selected_index=None)
palette_accordion.set_title(0, "Palette: Save / Load / Manage")
Takes zero height by default; expands on demand.
4. Replace Output feedback widget with a styled HTML label
# error
feedback_label.value = '<span style="color:orange">⚠️ No identifier selected.</span>'
# success
feedback_label.value = '<span style="color:green">✓ Colors applied.</span>'
5. Two-row top bar
Row 1: [☑ Enable] [Identifier ▾──────────────────]
Row 2: [Update Colors] [Apply saved ▾──────]
Moving Enable to the left as the primary toggle, and consolidating Apply saved + saved_sets_dropdown into the action row reduces the need to navigate into the Manage tab for the common apply workflow.
6. Disable Save button reactively
Disable save_button until both a palette name is entered and an identifier is selected. This prevents the current dead-end warning flow.
Final Layout
VBox (max_height=600px, overflow_y=auto)
├─ HBox: [☑ Enable] [Identifier ▾──────────────]
├─ HBox: [Update Colors] [Apply: saved_sets_dropdown ▾] [Manage...]
├─ HTML <hr>
├─ HBox: [Label "Class order:"] [Show all □]
├─ TagsInput (full width)
├─ HBox: [Label "Default color:"] [■ ColorPicker]
├─ HTML <hr>
├─ VBox (scrollable per-class rows)
│ [□] [■ ColorPicker "CD4+"] [□ fill]
│ [□] [■ ColorPicker "CD8+"] [□ fill]
│ ...
├─ Accordion (collapsed): "Palette: Save / Load / Manage"
│ └─ Tab: Save | Load | Manage
└─ HTML feedback_label (inline styled)
Acceptance Criteria
Files Affected
ueler/viewer/plugin/mask_painter.py — UiComponent.__init__(), MaskPainterDisplay.initiate_ui(), MaskPainterDisplay.on_identifier_change(), MaskPainterDisplay._log()
- mask_painter.py —
UiComponent.__init__(), MaskPainterDisplay.initiate_ui(), MaskPainterDisplay.on_identifier_change(), MaskPainterDisplay._log()
The current Mask Painter panel has several layout and usability issues that are particularly visible in narrow side-panel contexts:
HBoxsplit gives the sorting container only ~105px at typical panel widths, causingTagsInputchips to overflow and the "Show all classes" label to truncate to "Show all c...".ToggleButtonsfor outline/fill are too wide — Each row renders aToggleButtonsat 160px, causing horizontal overflow in the per-class list.Taboccupies permanent vertical space even when not in use, contributing to a cluttered, scroll-heavy panel.Outputwidget for feedback — Uses a console-styleOutputwidget for status/error messages, which looks out of place and doesn't support styled text.Proposed Changes
1. Fix the class color list layout — vertical, full-width
Replace the 30%/70%
HBoxsplit with a verticalVBox. MoveTagsInputandDefault colorabove the per-class list at full width:2. Compact outline/fill toggle
Replace
ToggleButtons(options=["outline","fill"], style={"button_width":"70px"})with a singleCheckbox(description="fill", layout=Layout(width="60px")). Saves ~100px per row.3. Wrap palette management in a collapsed
AccordionTakes zero height by default; expands on demand.
4. Replace
Outputfeedback widget with a styledHTMLlabel5. Two-row top bar
Moving
Enableto the left as the primary toggle, and consolidatingApply saved+saved_sets_dropdowninto the action row reduces the need to navigate into the Manage tab for the common apply workflow.6. Disable Save button reactively
Disable
save_buttonuntil both a palette name is entered and an identifier is selected. This prevents the current dead-end warning flow.Final Layout
Acceptance Criteria
TagsInputandDefault colorrender at full panel width without truncationvis checkbox+ColorPicker+fill checkbox)Enablecheckbox is the leftmost, most prominent control in the top barSave setbutton is disabled until both an identifier is selected and a palette name is enteredFiles Affected
ueler/viewer/plugin/mask_painter.py—UiComponent.__init__(),MaskPainterDisplay.initiate_ui(),MaskPainterDisplay.on_identifier_change(),MaskPainterDisplay._log()UiComponent.__init__(),MaskPainterDisplay.initiate_ui(),MaskPainterDisplay.on_identifier_change(),MaskPainterDisplay._log()