Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
2 changes: 2 additions & 0 deletions agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:

Expand Down
64 changes: 64 additions & 0 deletions agents/imguix-styling-playbook.md
Original file line number Diff line number Diff line change
@@ -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.
84 changes: 84 additions & 0 deletions agents/imguix-table-playbook.md
Original file line number Diff line number Diff line change
@@ -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.
Loading