diff --git a/AGENTS.md b/AGENTS.md index eaf224f..f21082f 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 @@ -740,3 +742,29 @@ 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. +* 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. + +## 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..0802e74 --- /dev/null +++ b/agents/imguix-styling-playbook.md @@ -0,0 +1,64 @@ +# 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", ImVec2(0.0f, 0.0f), ImGuiChildFlags_AlwaysUseWindowPadding); + 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 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. diff --git a/agents/imguix-table-playbook.md b/agents/imguix-table-playbook.md new file mode 100644 index 0000000..d373d20 --- /dev/null +++ b/agents/imguix-table-playbook.md @@ -0,0 +1,84 @@ +# ImGuiX table playbook + +Use this playbook for scrollable tables, selectable rows, filtering, and +composed data panels. It documents reusable Dear ImGui invariants; individual +applications remain responsible for their own panel composition and visual +language. + +## 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. + +## Optional bordered data-panel pattern + +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( + "##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. +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 + +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.