![]() |
SWMMVis
6.0.0-alpha.4
Qt6/C++ GIS-based graphical user interface for the SWMMVis engine (6.0.0-alpha.4)
|
Namespaces | |
| namespace | extcol |
| namespace | theme |
Typedefs | |
| using | ReportViewerDialog = StatusReportDialog |
| using | Style = OpenSWMM::Render::LegendOverlayStyle |
Enumerations | |
| enum | ActionTag : unsigned { NoTags = 0u , RequiresProject = 1u << 0 , RequiresEditSession = 1u << 1 , Contextual2D = 1u << 2 } |
| enum class | LayerCapability : unsigned int { Information = 1u << 0 , Source = 1u << 1 , Symbology = 1u << 2 , Labels = 1u << 3 , Rendering = 1u << 4 , Metadata = 1u << 5 } |
| Which tabs apply to a given layer type. More... | |
| enum | CategoryId { CatSwmm = 0 , CatMeshes , CatSwmm1DOutputs , CatSwmm2DOutputs , CatFeatureLayers , CatRasterLayers , CatBasemaps , CatTables , CatCount } |
| Top-level layer-tree groups. More... | |
| enum class | LayerTypeOrdinal : int { SWMMDefaultLayer = 0 , SWMMModelLayer = 1 , SWMMResultsLayer = 2 , SWMMGISLayer = 3 , SWMMVectorLayer = 4 , SWMMRasterLayer = 5 , SWMMImageryLayer = 6 , SWMMTabularDataLayer = 7 , SWMMTabularyTimeSeriesLayer = 8 , SWMMSubProjectLayer = 9 , SWMMWMSLayer = 10 , SWMMWMTSLayer = 11 , SWMM2DMeshLayer = 12 , SWMM2DResultsLayer = 13 , SWMMAnnotationLayer = 14 } |
| Mirror of OpenSWMMVisLayer::OpenSWMMVisLayerType — same ordinals, no Qt include cost. Used by tests so they can call categoryForLayerType() without pulling openswmmvislayer.h. More... | |
| enum class | RibbonMode { Collapsed = 0 , Compact = 1 , Full = 2 } |
| enum class | FigureLane { Offscreen , Live , Human } |
| Which platform a figure can be captured on. More... | |
Functions | |
| void | saveDialogLayout (QWidget *root) |
| Persist the dialog's geometry + every named QSplitter under it. | |
| bool | restoreDialogLayout (QWidget *root) |
| Inverse of saveDialogLayout — restore geometry + splitter states. | |
| QRect | clampToVisibleScreen (const QRect &saved, int titleBarStrip=-1) |
| Clamp a saved top-level geometry into currently-available screen space, so a window can never be restored somewhere unreachable. | |
| void | ensureWindowOnScreen (QWidget *widget, const QScreen *preferred=nullptr) |
Move/resize widget's window so it is reachable on a connected screen, using the live frame geometry to size the title-bar allowance. | |
| void | applyAlwaysOnTopPolicy (QDialog *d) |
| Step H — pin the dialog above the main window so a map click doesn't hide it. Idempotent. Harmless on modal dialogs and on dialogs that already have the flag set. On macOS this is a no-op (the always-on-top hint would also float above other applications; Qt::Tool already keeps the dialog above the main window). | |
| Qt::WindowFlags | floatingPanelFlags () |
| Window flags for a modeless "floating panel" dialog that must stay above the application's OWN windows but never above other applications. macOS: a plain Qt::Dialog window (no Qt::Tool — that would hide the dialog when the app is deactivated; no WindowStaysOnTopHint — that floats above every app system-wide). The "stay above the main window" behaviour is instead provided by attaching the dialog as an NSWindow child window (see openswmmvis::platform::attachAsChildWindow, driven from the app-wide show event filter). Windows/X11: Qt::Tool + WindowStaysOnTopHint keeps the dialog above the main window (it does not leak across applications there). | |
| Qt::WindowFlags | stayAboveAppFlags () |
| Just the "keep above the app's other windows" hint, for full top-level (Qt::Window) dialogs that should NOT be turned into Tool panels. Empty on macOS — those dialogs are kept above the main window by the NSWindow child-window attachment instead; WindowStaysOnTopHint elsewhere. | |
| LayerCapabilities | layerCapabilities (OpenSWMMVisLayer *layer) |
| QList< SWMMResultsLayer * > | profileResultSources (AnimationController *anim, SWMMVisProjectWindow *projectWindow, MapCanvas *canvas=nullptr) |
| std::vector< std::unique_ptr< ILayerStyleSubject > > | subjectsFromRuleList (OpenSWMM::Render::RuleList *list) |
Build one RuleStyleSubject per Rule in list. Empty / null list yields an empty vector. RoutingIds are auto-assigned as "rule.0", "rule.1", ... — stable for the duration of the dialog session. | |
| EngineCapabilities | probeEngineCapabilities (SWMM_Engine e, const QString &version) |
| Probe e once for everything the dialog gates on. | |
| const char * | transport2DKey (int speciesClass) |
The [2D_OPTIONS] key carrying one SWMM_TRANSPORT_CLASS_*, or "" for an unknown class. | |
| QDoubleSpinBox * | makeDSpin (QWidget *parent, double lo, double hi, double step, int decimals, double value, const QString &suffix=QString()) |
| QSpinBox * | makeSpin (QWidget *parent, int lo, int hi, int value) |
| QWidget * | makeSublayerHeader (QWidget *parent, OpenSWMM::Render::ISublayer *sub, const QString &showLabel) |
| void | installMdiWorkspaceChrome (QMdiArea *area, QWidget *welcome=nullptr) |
| Make area's backdrop track the theme and give welcome an opaque background of its own. | |
| CategoryId | categoryForLayerType (int layerTypeOrdinal) |
| Maps a layer-type ordinal to its tree category. | |
| CategoryId | categoryForLayerType (LayerTypeOrdinal t) |
| Convenience overload taking the typed ordinal directly. | |
| CategoryInfo | categoryInfo (CategoryId id) |
| Returns the display label + icon alias for a category. | |
| const ThemeColors & | lightColors () |
| const ThemeColors & | darkColors () |
| int | ribbonRowWidth (const QVector< RibbonGroupWidths > &groups, const QVector< RibbonMode > &modes, int spacing) |
| QVector< RibbonMode > | solveRibbonModes (int availableWidth, const QVector< RibbonGroupWidths > &groups, int spacing) |
| QVector< RibbonMode > | applyRibbonHysteresis (const QVector< RibbonMode > &previous, int availableWidth, const QVector< RibbonGroupWidths > &groups, int spacing, int deadBand=32) |
| QStringList | readHeaders (const QString &path, QString *errorOut=nullptr, bool *fabricatedOut=nullptr) |
| Enumerate the value-column names of path (time column excluded). | |
| int | readColumn (const QString &path, const QString &columnSelector, QVector< ExternalSeriesPoint > &pointsOut, QStringList *headersOut=nullptr, QString *errorOut=nullptr, bool *fabricatedOut=nullptr) |
| Read one column of path into pointsOut. | |
| QString | reconcileColumnSelector (const QString &path, const QString ¤t) |
| The column selector path should carry, given current. | |
| int | fuzzyScore (const QString &pattern, const QString &candidate) |
| QPropertyItemDelegate * | makeStyleDelegate (QObject *parent) |
| REGISTER_STYLE_EDITOR (PointFeatureSublayerStyle, [](QObject *obj, QWidget *parent) -> IStyleEditorWidget *{ if(auto *s=qobject_cast< PointFeatureSublayerStyle * >(obj)) return new PointFeatureStyleEditor(s, parent);return nullptr;}) REGISTER_STYLE_EDITOR(LineFeatureSublayerStyle | |
| REGISTER_STYLE_EDITOR (PointSymbolStyleAdapter, [](QObject *obj, QWidget *parent) -> IStyleEditorWidget *{ if(auto *a=qobject_cast< PointSymbolStyleAdapter * >(obj)) return new PointSymbolStyleEditor(a, parent);return nullptr;}) REGISTER_STYLE_EDITOR(LineSymbolStyleAdapter | |
Variables | |
| constexpr ActionCatalogEntry | kActionCatalog [] |
| constexpr std::size_t | kActionCatalogSize = std::size(kActionCatalog) |
| constexpr const char * | kActionCatalogTabs [] |
| Known compact-toolbar tab ids ("" = menu-only entry). | |
| constexpr char | kNoLayoutPersistenceProp [] = "noLayoutPersistence" |
| Dynamic property opting a QDialog out of automatic persistence. | |
| constexpr char | kLayoutRestoredOnceProp [] = "layoutRestoredOnce" |
| Instance property marking that the first-show restore already ran. | |
| constexpr int | kSpinMinWidthPx = 110 |
| constexpr int | kComboMinWidthPx = 140 |
| constexpr int | kDefaultCategoryDisplayOrder [CatCount] |
| Default top-to-bottom order of the category groups in the layer tree AND in the canvas paint stack (index 0 = top of tree = drawn last). Results groups sit on top because they overlay the model / mesh for analysis; tables sit at the bottom. | |
| constexpr int | kRibbonRowHeight = 100 |
| constexpr int | kRibbonIconFull = 32 |
| Icon edge in Full mode. | |
| constexpr int | kRibbonIconCompact = 24 |
| Icon edge in Compact mode. | |
| QObject * | obj |
| QObject QWidget *parent IStyleEditorWidget *return | nullptr |
| using openswmmvis::ui::ReportViewerDialog = typedef StatusReportDialog |
| using openswmmvis::ui::Style = typedef OpenSWMM::Render::LegendOverlayStyle |
| enum openswmmvis::ui::ActionTag : unsigned |
Top-level layer-tree groups.
Order is the default display order. Categories with no layers are hidden by rebuildCategories() in layertreepanel.cpp. The user can permute the order via the right-click "Move Category Up/Down" menu or by dragging the header — that permutation is per project (MapCanvas::layerGroupOrder()), not here.
| Enumerator | |
|---|---|
| CatSwmm | |
| CatMeshes | |
| CatSwmm1DOutputs | |
| CatSwmm2DOutputs | |
| CatFeatureLayers | |
| CatRasterLayers | |
| CatBasemaps | |
| CatTables | |
| CatCount | |
|
strong |
|
strong |
Which tabs apply to a given layer type.
Information / Rendering / Metadata are universal (every layer type has them). Source applies when the layer has an editable CRS or filter expression. Symbology and Labels are gated per the §X.3.1 table. The dialog skips any tab whose capability flag is false — no empty placeholders.
| Enumerator | |
|---|---|
| Information | |
| Source | |
| Symbology | |
| Labels | |
| Rendering | |
| Metadata | |
|
strong |
Mirror of OpenSWMMVisLayer::OpenSWMMVisLayerType — same ordinals, no Qt include cost. Used by tests so they can call categoryForLayerType() without pulling openswmmvislayer.h.
The .cpp static_asserts this stays in lockstep with the source enum, so adding a new layer type without updating both will fail the build instead of silently mis-bucketing.
|
strong |
| void openswmmvis::ui::applyAlwaysOnTopPolicy | ( | QDialog * | d | ) |
Step H — pin the dialog above the main window so a map click doesn't hide it. Idempotent. Harmless on modal dialogs and on dialogs that already have the flag set. On macOS this is a no-op (the always-on-top hint would also float above other applications; Qt::Tool already keeps the dialog above the main window).
|
inline |
solveRibbonModes with a promotion dead band.
Demotions (vs previous) apply immediately — shrinking must always fit. A promotion is accepted only if it would also hold with deadBand fewer pixels, so a window dragged across a boundary doesn't flap between modes. A previous of a different size (group added/removed) falls back to the plain solve.
| CategoryId openswmmvis::ui::categoryForLayerType | ( | int | layerTypeOrdinal | ) |
Maps a layer-type ordinal to its tree category.
Unrecognised ordinals return CatFeatureLayers (matches the runtime fall-back behaviour, but without the qWarning() that the full layertreepanel.cpp version emits — a headless helper has nowhere sensible to log).
|
inline |
Convenience overload taking the typed ordinal directly.
| CategoryInfo openswmmvis::ui::categoryInfo | ( | CategoryId | id | ) |
Returns the display label + icon alias for a category.
| QRect openswmmvis::ui::clampToVisibleScreen | ( | const QRect & | saved, |
| int | titleBarStrip = -1 |
||
| ) |
Clamp a saved top-level geometry into currently-available screen space, so a window can never be restored somewhere unreachable.
saved is a CLIENT rect (what QWidget::geometry() / setGeometry() use). titleBarStrip is the height of the frame decoration above that rect — the window's only drag handle, which must stay inside the available area or the window cannot be moved at all. Pass -1 for a platform default.
Rules, in order:
Pure function of its inputs plus the current screen layout: safe to unit test and reusable by any window-recovery path.
|
inline |
| void openswmmvis::ui::ensureWindowOnScreen | ( | QWidget * | widget, |
| const QScreen * | preferred = nullptr |
||
| ) |
Move/resize widget's window so it is reachable on a connected screen, using the live frame geometry to size the title-bar allowance.
With preferred non-null the window is additionally CENTERED on that screen unconditionally — the "Reset Window Positions" recovery path, which gathers every open window onto the main window's display. No-op when preferred is null and the window is already well placed.
|
inline |
Window flags for a modeless "floating panel" dialog that must stay above the application's OWN windows but never above other applications. macOS: a plain Qt::Dialog window (no Qt::Tool — that would hide the dialog when the app is deactivated; no WindowStaysOnTopHint — that floats above every app system-wide). The "stay above the main window" behaviour is instead provided by attaching the dialog as an NSWindow child window (see openswmmvis::platform::attachAsChildWindow, driven from the app-wide show event filter). Windows/X11: Qt::Tool + WindowStaysOnTopHint keeps the dialog above the main window (it does not leak across applications there).
| int openswmmvis::ui::fuzzyScore | ( | const QString & | pattern, |
| const QString & | candidate | ||
| ) |
Fuzzy relevance of pattern against candidate (case-insensitive). -1 = no subsequence match; higher is better. Prefix matches beat word-boundary subsequences beat scattered subsequences; shorter candidates win ties.
| void openswmmvis::ui::installMdiWorkspaceChrome | ( | QMdiArea * | area, |
| QWidget * | welcome = nullptr |
||
| ) |
Make area's backdrop track the theme and give welcome an opaque background of its own.
Backdrop: QMdiArea snapshots palette(QPalette::Dark) once in its constructor and has no PaletteChange handling, so a theme installed after construction — as ThemeManager is, SWMMVis being built first — leaves the workspace painted in the pre-theme brush.
Welcome: uic emits welcomeWidget as a bare QWidget, so it has no autoFillBackground and paints nothing behind its own children. That is why the backdrop showed through the whole welcome tab — and the backdrop is not the only thing below it. In TabbedView QMdiArea never hides the outgoing sub-window; _q_deactivateAllWindows merely showNormal()s it (qmdiarea.cpp:685) and relies on the incoming maximized window to cover the viewport. So after welcome → model → welcome the model sub-window is still sitting in the viewport as a 200x150 framed child, and a transparent welcome on top of it is not a cover: the user sees a detached, undocked model window painted over the welcome screen.
setAutoFillBackground() fills with QPalette::Window, which ThemeManager sets to surfaceWindow (thememanager.cpp:87) — the same token the backdrop uses, so the welcome looks unchanged — and it is re-read at every paint, so the Appearance switch needs no extra hook here.
Safe to call once per area; a null area or welcome is a no-op.
| LayerCapabilities openswmmvis::ui::layerCapabilities | ( | OpenSWMMVisLayer * | layer | ) |
Return the capability mask for a layer based on its layerType + class.
|
inline |
|
inline |
|
inline |
| QPropertyItemDelegate * openswmmvis::ui::makeStyleDelegate | ( | QObject * | parent | ) |
New a QPropertyItemDelegate, register the ClassificationScheme cell editor on it, and return it. Caller installs it via QTreeView::setItemDelegate.
|
inline |
"Show <name>" checkbox + opacity spin bound to the sublayer's visibility / opacity — the shared header row of every tab.
| EngineCapabilities openswmmvis::ui::probeEngineCapabilities | ( | SWMM_Engine | e, |
| const QString & | version | ||
| ) |
Probe e once for everything the dialog gates on.
| e | Engine handle; may be null (every capability reads false). |
| version | Engine version string as passed to the dialog. |
|
inline |
| int openswmmvis::ui::readColumn | ( | const QString & | path, |
| const QString & | columnSelector, | ||
| QVector< ExternalSeriesPoint > & | pointsOut, | ||
| QStringList * | headersOut = nullptr, |
||
| QString * | errorOut = nullptr, |
||
| bool * | fabricatedOut = nullptr |
||
| ) |
Read one column of path into pointsOut.
| columnSelector | Column name; matched case-insensitively against readHeaders() names (engine parity). Empty selects the first data column; a non-empty name that matches nothing FAILS (the engine errors on it — review B-3 — so no silent first-column fallback). A headerless file resolves no name at all: only an empty selector reads it. |
| pointsOut | Cleared, then filled sorted ascending in time. Cells that are missing or non-numeric are skipped (mirrors the engine's copy-out of NaN cells). For a headerless file the first content line is consumed as the header row, exactly as the engine does, so both agree on which rows are data. |
| headersOut | Optional; receives the same list readHeaders() returns, from the same single pass — populated even when the column selector fails to resolve. |
| errorOut | Optional; human-readable reason on failure. |
| fabricatedOut | Optional; see readHeaders(). |
| QStringList openswmmvis::ui::readHeaders | ( | const QString & | path, |
| QString * | errorOut = nullptr, |
||
| bool * | fabricatedOut = nullptr |
||
| ) |
Enumerate the value-column names of path (time column excluded).
TSF → the IDs row's tokens; CSV/TSV → header cells, or fabricated "col_N" names when the first content line is itself a data row. Returns an empty list for unreadable files and for headerless whitespace formats (SWMM .dat / standard rain files) — those have no columns to pick.
| errorOut | Optional; receives a human-readable reason on failure. |
| fabricatedOut | Optional; true when the names are fabricated (headerless file). Such a name cannot be resolved by the engine, so callers must not persist it in a "path:col" token — only the first data column of a headerless file is addressable, via an EMPTY selector (review B-4 / risk R1). |
| QString openswmmvis::ui::reconcileColumnSelector | ( | const QString & | path, |
| const QString & | current | ||
| ) |
The column selector path should carry, given current.
Answers the "the file just changed — now what?" question for every editor that binds a column to a path, so the timeseries dialog, the rain-gage property row and the rain-gage attribute cell all reconcile identically:
Callers compare the result with current and write only on a change, so a path edit that leaves the binding valid costs nothing.
| openswmmvis::ui::REGISTER_STYLE_EDITOR | ( | PointFeatureSublayerStyle | , |
| [] (QObject *obj, QWidget *parent) -> IStyleEditorWidget *{ if(auto *s=qobject_cast< PointFeatureSublayerStyle * >(obj)) return new PointFeatureStyleEditor(s, parent);return nullptr;} | |||
| ) |
| openswmmvis::ui::REGISTER_STYLE_EDITOR | ( | PointSymbolStyleAdapter | , |
| [] (QObject *obj, QWidget *parent) -> IStyleEditorWidget *{ if(auto *a=qobject_cast< PointSymbolStyleAdapter * >(obj)) return new PointSymbolStyleEditor(a, parent);return nullptr;} | |||
| ) |
| bool openswmmvis::ui::restoreDialogLayout | ( | QWidget * | root | ) |
Inverse of saveDialogLayout — restore geometry + splitter states.
Restored geometry is clamped to currently-available screen real estate so a saved position on a now-disconnected monitor doesn't render off-screen.
|
inline |
Total row width of groups under modes, with spacing between adjacent groups.
| void openswmmvis::ui::saveDialogLayout | ( | QWidget * | root | ) |
Persist the dialog's geometry + every named QSplitter under it.
Walks root->findChildren<QSplitter*>() and stores each splitter's saveState() under Dialogs/<root-objectName>/splitter/<splitter-objectName>. Splitters without an objectName are skipped (forces deliberate opt-in).
No-op when root has no objectName (we'd have nowhere to file it). Safe to call on any QWidget — passes through to its window.
|
inline |
Demote trailing groups until the row fits availableWidth.
Pass 1 walks from the trailing end demoting Full → Compact; if the row still overflows, pass 2 walks again demoting Compact → Collapsed (collapsible groups only). A row that cannot fit even fully demoted returns the maximally-demoted assignment — the toolbar's extension chevron is the final backstop.
|
inline |
Just the "keep above the app's other windows" hint, for full top-level (Qt::Window) dialogs that should NOT be turned into Tool panels. Empty on macOS — those dialogs are kept above the main window by the NSWindow child-window attachment instead; WindowStaysOnTopHint elsewhere.
| std::vector< std::unique_ptr< ILayerStyleSubject > > openswmmvis::ui::subjectsFromRuleList | ( | OpenSWMM::Render::RuleList * | list | ) |
Build one RuleStyleSubject per Rule in list. Empty / null list yields an empty vector. RoutingIds are auto-assigned as "rule.0", "rule.1", ... — stable for the duration of the dialog session.
| const char * openswmmvis::ui::transport2DKey | ( | int | speciesClass | ) |
The [2D_OPTIONS] key carrying one SWMM_TRANSPORT_CLASS_*, or "" for an unknown class.
Shared vocabulary rather than a page member: the 2D page owns the TRANSPORT_* checkboxes, while the Models page's Domain × Species matrix names the same keys in its cell tooltips (CLAUDE.md §5.1 — one model, two views).
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
Known compact-toolbar tab ids ("" = menu-only entry).
|
inlineconstexpr |
|
constexpr |
Default top-to-bottom order of the category groups in the layer tree AND in the canvas paint stack (index 0 = top of tree = drawn last). Results groups sit on top because they overlay the model / mesh for analysis; tables sit at the bottom.
Slice LTR-2026-09-19: the effective order is per project — it is held by MapCanvas::layerGroupOrder() and persisted in the .oswp canvas block. This array is only the seed for a canvas that has no saved order.
|
inlineconstexpr |
Instance property marking that the first-show restore already ran.
|
inlineconstexpr |
Dynamic property opting a QDialog out of automatic persistence.
|
inlineconstexpr |
Icon edge in Compact mode.
|
inlineconstexpr |
Icon edge in Full mode.
|
inlineconstexpr |
Fixed height of the ribbon content + caption row (ArcGIS scale; sized for a 32 px icon over TWO wrapped label lines plus the group caption — see the kShortLabels '
' wrapping in swmmvisactions.cpp).
|
inlineconstexpr |
| QObject QWidget *parent IStyleEditorWidget *return openswmmvis::ui::nullptr |
| QObject * openswmmvis::ui::obj |