From 889d1022fa74a07c0a8f27f9784b613075504442 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Sat, 12 Sep 2026 14:01:12 +0300 Subject: [PATCH 1/4] docs(agents): document scoped styling and theme guidance --- AGENTS.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index eaf224f..2c92b0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -740,3 +740,17 @@ return ImGui::GetIO().Fonts->AddFontFromFileTTF( * Avoid hidden global state; favor explicit dependencies. * Use `enum class` for scoped enums. * Avoid macros in public APIs unless required for portability. + +## 20. Scoped styling and theme extensions + +* Use `ImGuiX::Extensions::ScopedStyleVar` and + `ImGuiX::Extensions::ScopedStyleColor` for temporary style changes. Their + RAII lifetime must cover the widget or child window that consumes the style. +* Keep reusable design values in theme roles or custom theme tokens. Consumers + should resolve the active theme instead of hardcoding product colors. +* Screen-specific geometry may stay local until it is repeated. Promote a + metric to a theme/widget token only when it is part of the shared design + language. +* Every `BeginChild`, `BeginTable`, popup, and matching ImGui `Begin*` call must + have an unconditional matching `End*` after the call; never make cleanup + depend on the boolean content return value. From d499ae6e0125b20274f6ce4301577974a286e1a4 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Sat, 12 Sep 2026 14:21:25 +0300 Subject: [PATCH 2/4] docs(agents): add styling and table playbooks --- AGENTS.md | 20 ++++++-- agents/README.md | 2 + agents/imguix-styling-playbook.md | 60 ++++++++++++++++++++++ agents/imguix-table-playbook.md | 82 +++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 agents/imguix-styling-playbook.md create mode 100644 agents/imguix-table-playbook.md diff --git a/AGENTS.md b/AGENTS.md index 2c92b0a..cc22774 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,6 +19,8 @@ * [17. C++ Code Formatting](#17-c-code-formatting) * [18. C++ Naming Conventions](#18-c-naming-conventions) * [19. C++ Code Recommendations](#19-c-code-recommendations) +* [20. Scoped Styling and Theme Extensions](#20-scoped-styling-and-theme-extensions) +* [21. Agent Playbooks](#21-agent-playbooks) ## 1. Mission & Scope @@ -751,6 +753,18 @@ return ImGui::GetIO().Fonts->AddFontFromFileTTF( * Screen-specific geometry may stay local until it is repeated. Promote a metric to a theme/widget token only when it is part of the shared design language. -* Every `BeginChild`, `BeginTable`, popup, and matching ImGui `Begin*` call must - have an unconditional matching `End*` after the call; never make cleanup - depend on the boolean content return value. +* Follow the Dear ImGui lifecycle contract for every `Begin*` call: + `Begin`, `BeginChild`, and `BeginTabBar` require their matching `End*` + even when the boolean return value is `false`; `BeginTable`, `BeginPopup`, + `BeginCombo`, and similar conditional scopes require `End*` exactly once + only when they return `true`. +* For the detailed recipes and review checklists, use: + - `agents/imguix-styling-playbook.md` for scoped styling and theme ownership. + - `agents/imguix-table-playbook.md` for table composition and filtered selection. + +## 21. Agent playbooks + +Keep `AGENTS.md` focused on architectural invariants. Execution-oriented +recipes belong in `external/ImGuiX/agents/` and must be linked from +`agents/README.md`. Update the relevant playbook when an API invariant or +recommended integration pattern changes. diff --git a/agents/README.md b/agents/README.md index 7e4579b..d3bbf9b 100644 --- a/agents/README.md +++ b/agents/README.md @@ -7,6 +7,8 @@ Files: - `imguix-smoke-build.md` - Known-good commands to configure and rebuild smoke examples with MinGW. - `imguix-fonts-i18n-playbook.md` - Quick operational checklist for documenting and validating fonts + i18n behavior. - `imguix-windowing-playbook.md` - Practical checklist for `WindowInstance` / `ImGuiFramedWindow` changes and docs sync. +- `imguix-styling-playbook.md` - RAII style guards, theme ownership, and styling review checks. +- `imguix-table-playbook.md` - Table surfaces, bordered data panels, filtering, and range-selection rules. When to use `imguix-fonts-i18n-playbook.md`: diff --git a/agents/imguix-styling-playbook.md b/agents/imguix-styling-playbook.md new file mode 100644 index 0000000..a3fc9d2 --- /dev/null +++ b/agents/imguix-styling-playbook.md @@ -0,0 +1,60 @@ +# ImGuiX styling playbook + +Use this playbook when adding or reviewing temporary styling, theme integration, +or panel layout code in an ImGuiX consumer. + +## Scoped style overrides + +Use the RAII guards from `imguix/extensions/scoped_style.hpp` for temporary +style changes: + +```cpp +{ + const ImGuiX::Extensions::ScopedStyleVar padding( + ImGuiStyleVar_WindowPadding, ImVec2(24.0f, 20.0f)); + const ImGuiX::Extensions::ScopedStyleColor border( + ImGuiCol_Border, ImGui::GetStyle().Colors[ImGuiCol_Border]); + + const bool content_visible = ImGui::BeginChild("panel"); + if (content_visible) { + draw_content(); + } + ImGui::EndChild(); +} +``` + +The guard must cover the `Begin*` call and any drawing that consumes the style +for a window, child, popup, table, or widget. Follow the API-specific cleanup +rule: `End`/`EndChild` is unconditional, while `EndTable`/`EndPopup`/`EndCombo` +is called exactly once only when its `Begin*` call returns `true`. + +`ScopedStyleVar` and `ScopedStyleColor` are deliberately non-copyable and +non-movable. Create named local guards; do not return them, store them in a +container, or manually pair their stack operations elsewhere. + +## Theme ownership + +Prefer the active theme for values that express the shared design language: + +```cpp +const ImGuiStyle& style = ImGui::GetStyle(); +const ImVec4 selected = style.Colors[ImGuiCol_NavHighlight]; +``` + +Use `ThemeManager` custom values/colors for reusable tokens that are not Dear +ImGui style roles. Keep screen-specific geometry local until it is repeated in +more than one screen. Do not add a large JSON token catalogue for one-off +coordinates. + +Product colors must not be hardcoded in a reusable ImGuiX widget. If a +consumer needs a product-specific role, define it in the consumer theme and +resolve it at draw time. + +## Review checklist + +- Search consumer code for raw `PushStyleVar`, `PushStyleColor`, and matching + `PopStyle*` calls. Replace temporary overrides with RAII guards. +- Verify every `Begin*` has an unconditional matching `End*`. +- Confirm style guards remain alive for the widget/window that consumes them. +- Use `docs/THEMES.md` for the complete `ThemeManager` and custom-token API. +- Build at least one relevant smoke example after changing style or theme code. diff --git a/agents/imguix-table-playbook.md b/agents/imguix-table-playbook.md new file mode 100644 index 0000000..5aaaf8d --- /dev/null +++ b/agents/imguix-table-playbook.md @@ -0,0 +1,82 @@ +# ImGuiX table playbook + +Use this playbook for scrollable tables, selectable rows, filtering, and +toolbar-plus-table panels. + +## Separate table responsibilities + +Give each visual mechanism one responsibility: + +| Mechanism | Responsibility | +| --- | --- | +| `ImGuiTableFlags_RowBg` | Zebra/background rows | +| `Selectable` | Hover, pressed, and selected interaction surface | +| `ImGuiTableFlags_BordersInnerH/V` | Row and column separators | +| `TableSetupScrollFreeze(0, 1)` | Keep the header visible while scrolling | + +Do not draw the selected state twice by combining a selected `Selectable` with +`TableSetBgColor(ImGuiTableBgTarget_RowBg0, ...)`. Do not zero the theme's +vertical `CellPadding` and compensate with a fake spacer row. Keep the active +theme padding and adjust a local widget style only when there is a demonstrated +layout requirement. + +## Bordered data-panel pattern + +For a dataset with controls, keep the toolbar and table inside one bordered +child: + +```cpp +const bool panel_visible = ImGui::BeginChild( + "##data_panel", ImVec2(0.0f, 0.0f), + ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding); + +if (panel_visible) { + draw_toolbar(); + ImGui::Separator(); + + if (ImGui::BeginTable( + "##data", column_count, + ImGuiTableFlags_RowBg | + ImGuiTableFlags_BordersInnerH | + ImGuiTableFlags_BordersInnerV | + ImGuiTableFlags_ScrollY)) { + ImGui::TableSetupScrollFreeze(0, 1); + draw_header(); + draw_rows(); + ImGui::EndTable(); + } +} +ImGui::EndChild(); +``` + +The child owns the outer border and padding; the table owns inner separators. +Avoid adding a second outer table border unless the design explicitly calls +for it. + +## Filtering and range selection + +Render and interact with a visible projection rather than raw backing indices: + +```text +backing collection -> visible projection -> render / range selection / copy +``` + +Shift-range selection must use positions in the visible projection. Copy and +export must use the same projection and selection rules. Otherwise hidden rows +can be selected and copied after a filter is applied. + +The application owns the policy for hidden selections when a filter changes +(prune them, preserve them, or ask the user). Document that policy in the +feature's model/controller guide. + +## Review checklist + +- Keep `CellPadding` inherited from the active theme unless a local override is + justified. +- Use one selected/hover surface, one separator mechanism, and one zebra + mechanism. +- Freeze the header for scrollable data tables. +- Call `EndTable` exactly once when `BeginTable` returns `true`; do not call it + on a `false` return. +- Keep `EndChild` unconditional after `BeginChild`. +- Test filtering followed by Shift-selection and copy/export. From ac79a68b5d3db2207610747e2925a41784c5a0bd Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Sat, 12 Sep 2026 15:51:52 +0300 Subject: [PATCH 3/4] docs(agents): clarify ImGui lifecycle cleanup --- AGENTS.md | 10 +++++----- agents/imguix-styling-playbook.md | 8 ++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index cc22774..f21082f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -753,11 +753,11 @@ return ImGui::GetIO().Fonts->AddFontFromFileTTF( * Screen-specific geometry may stay local until it is repeated. Promote a metric to a theme/widget token only when it is part of the shared design language. -* Follow the Dear ImGui lifecycle contract for every `Begin*` call: - `Begin`, `BeginChild`, and `BeginTabBar` require their matching `End*` - even when the boolean return value is `false`; `BeginTable`, `BeginPopup`, - `BeginCombo`, and similar conditional scopes require `End*` exactly once - only when they return `true`. +* Follow the Dear ImGui lifecycle contract for every `Begin*` call. Always + call `End` and `EndChild` after `Begin` and `BeginChild`, even when their + boolean return value is `false`. Call `EndTable`, `EndPopup`, `EndCombo`, + `EndTabBar`, and similar conditional cleanup exactly once only when the + corresponding `Begin*` call returns `true`. * For the detailed recipes and review checklists, use: - `agents/imguix-styling-playbook.md` for scoped styling and theme ownership. - `agents/imguix-table-playbook.md` for table composition and filtered selection. diff --git a/agents/imguix-styling-playbook.md b/agents/imguix-styling-playbook.md index a3fc9d2..0802e74 100644 --- a/agents/imguix-styling-playbook.md +++ b/agents/imguix-styling-playbook.md @@ -15,7 +15,8 @@ style changes: const ImGuiX::Extensions::ScopedStyleColor border( ImGuiCol_Border, ImGui::GetStyle().Colors[ImGuiCol_Border]); - const bool content_visible = ImGui::BeginChild("panel"); + const bool content_visible = ImGui::BeginChild( + "panel", ImVec2(0.0f, 0.0f), ImGuiChildFlags_AlwaysUseWindowPadding); if (content_visible) { draw_content(); } @@ -54,7 +55,10 @@ resolve it at draw time. - Search consumer code for raw `PushStyleVar`, `PushStyleColor`, and matching `PopStyle*` calls. Replace temporary overrides with RAII guards. -- Verify every `Begin*` has an unconditional matching `End*`. +- Verify lifecycle cleanup follows the Dear ImGui API contract: `End` and + `EndChild` are unconditional, while `EndTable`, `EndPopup`, `EndCombo`, + `EndTabBar`, and similar cleanup run exactly once only when `Begin*` returns + `true`. - Confirm style guards remain alive for the widget/window that consumes them. - Use `docs/THEMES.md` for the complete `ThemeManager` and custom-token API. - Build at least one relevant smoke example after changing style or theme code. From 53c6569cd8f3155c9276bc90c38643a1d34fc6f3 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Sat, 12 Sep 2026 19:52:23 +0300 Subject: [PATCH 4/4] docs(agents): keep table playbook generic --- agents/imguix-table-playbook.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/agents/imguix-table-playbook.md b/agents/imguix-table-playbook.md index 5aaaf8d..d373d20 100644 --- a/agents/imguix-table-playbook.md +++ b/agents/imguix-table-playbook.md @@ -1,7 +1,9 @@ # ImGuiX table playbook Use this playbook for scrollable tables, selectable rows, filtering, and -toolbar-plus-table panels. +composed data panels. It documents reusable Dear ImGui invariants; individual +applications remain responsible for their own panel composition and visual +language. ## Separate table responsibilities @@ -20,10 +22,10 @@ vertical `CellPadding` and compensate with a fake spacer row. Keep the active theme padding and adjust a local widget style only when there is a demonstrated layout requirement. -## Bordered data-panel pattern +## Optional bordered data-panel pattern -For a dataset with controls, keep the toolbar and table inside one bordered -child: +When a consumer wants controls and a dataset to read as one component, it may +keep them inside one bordered child: ```cpp const bool panel_visible = ImGui::BeginChild( @@ -50,8 +52,8 @@ ImGui::EndChild(); ``` The child owns the outer border and padding; the table owns inner separators. -Avoid adding a second outer table border unless the design explicitly calls -for it. +This is a composition recipe, not a required application layout. Avoid adding +a second outer table border unless the consuming design explicitly calls for it. ## Filtering and range selection