- 1. Mission & Scope
- 2. System Map (Mermaid)
- 3. Architectural Patterns & Invariants
- 4. Data & Contracts
- 5. Concurrency & Reliability
- 6. Testing Strategy & Oracles
- 7. Observability & Perf
- 8. Security & Secrets
- 9. Migration & Versioning
- 10. Agent Playbooks (Recipes)
- 11. Anti-Patterns & Pitfalls
- 12. Code Style: Git Commit Convention
- 13. Naming & Documentation Conventions
- 14. Reference Index
- 15. Branching & Release Policy
- 16. Documentation / Doxygen Style Guide
- 17. C++ Code Formatting
- 18. C++ Naming Conventions
- 19. C++ Code Recommendations
-
Purpose: reference for developers and AI agents working on ImGuiX.
-
Use during onboarding, code review, design discussions, and task planning.
-
Core modules:
include/imguix/core– application, windows, events, resources.include/imguix/controllers– controller hierarchy.include/imguix/widgets,extensions,utils– reusable components.
graph TD
A[Application]
WM[WindowManager]
W[WindowInstance]
C[Controller]
M[Model]
EB[EventBus]
RR[ResourceRegistry]
A-->WM
A-->M
A-->EB
A-->RR
WM-->W
W-->C
C-->EB
M-->EB
C-->RR
M-->RR
sequenceDiagram
participant Model
participant EventBus
participant Controller
Model->>EventBus: notifyAsync(Event)
Note right of EventBus: queued
EventBus-->>EventBus: process()
EventBus->>Controller: notify(Event)
graph LR
core[core]
windows[windows]
controllers[controllers]
widgets[widgets]
extensions[extensions]
utils[utils]
core --> windows
core --> controllers
windows --> controllers
controllers --> widgets
controllers --> extensions
controllers --> utils
-
Immediate-Mode MVC:
ApplicationownsWindowManager, models and controllers.- Controllers combine per-frame logic and rendering.
-
Event-driven communication:
EventBuswith async queue and listener registry- Invariant:
process()must be called on the main thread before frame render.
- Invariant:
-
Lifecycle / Template Method: windows and controllers expose hooks (
onInit,drawContent,drawUi, …) executed by the application loop. -
Factories: controllers and models are created via factory methods.
WindowInstance::createController<T>()returns a restrictedWindowInterface&. -
Strategies & Extensibility: themes, fonts and widgets register dynamically. Controllers may use
StrategicController(Strategy) andExtendedController(Composite). -
Mediator:
EventMediatorwraps subscriptions and notifications; all controllers/models inherit it. -
Resource Registry: singleton-like registry providing thread-safe resource access
- Invariant: only one instance per type; access during registration throws.
-
Event Contract: every event derives from
Pubsub::Eventand implementstype()andname() -
Model Restrictions: direct synchronous
notifyfunctions are deleted to avoid race conditions. UsenotifyAsyncoutside ofprocess(). Models may emit events synchronously via theSyncNotifierparameter passed intoprocess(). -
Feature-local models: controllers may own lightweight
FeatureModelinstances viaFeatureAccessMixin. They run on the UI thread and must avoid ImGui calls.
Sizing helpers (include/imguix/extensions/sizing.hpp):
CalcTimeComboWidth(),CalcDateComboWidth(),CalcWeekdayComboWidth()CalcHMSFieldWidth(),CalcYearFieldWidth()CalcComboPreviewTextMax(float combo_w, ImGuiComboFlags flags=0, float slack=1.0f)CalcFieldWidthForSample(const char* sample_utf8)
Combo invariants:
- Set sizes before
BeginCombo(...):ImGui::SetNextItemWidth(combo_w);ImGui::SetNextWindowSizeConstraints(min, max);— clamp popup height.
- Inside the popup when there's no frame/child:
- left:
ImGui::Indent(style.FramePadding.x); - right:
ImGui::SameLine(0,0); ImGui::Dummy(ImVec2(style.FramePadding.x, 0)); - then
ImGui::Unindent(style.FramePadding.x);
- left:
- Keep popup open for multi‑select grids:
ImGui::Selectable(..., /*selected*/, ImGuiSelectableFlags_DontClosePopups, cell_size);
- Truncate preview text by pixels:
max_text_px = CalcComboPreviewTextMax(combo_w, flags);- accumulate tokens while
ImGui::CalcTextSize(...) <= max_text_px, then append"..."
- Do not hardcode width via
GetWindowWidth()*k— use helpers/CalcItemWidth().
MWE: DaysOfWeekSelector (fragment)
const float combo_w = cfg.combo_width > 0 ? cfg.combo_width
: ImGuiX::Extensions::CalcWeekdayComboWidth();
ImGui::SetNextItemWidth(combo_w);
ImGui::SetNextWindowSizeConstraints(ImVec2(0,0),
ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing()*12));
if (ImGui::BeginCombo(cfg.label ? cfg.label : u8"Days", preview.c_str(),
ImGuiComboFlags_HeightLargest | ImGuiComboFlags_PopupAlignLeft)) {
const ImGuiStyle& st = ImGui::GetStyle();
ImGui::Indent(st.FramePadding.x);
// toolbar ...
// grid ...
if (ImGui::Selectable(token, selected,
ImGuiSelectableFlags_DontClosePopups, cell_sz)) {
selected = !selected;
}
ImGui::SameLine(0,0); ImGui::Dummy(ImVec2(st.FramePadding.x, 0));
ImGui::Unindent(st.FramePadding.x);
ImGui::EndCombo();
}-
Event types are C++ structs; no implicit serialization.
-
Identifiers:
- Windows: auto-incremented IDs inside
Application
- Windows: auto-incremented IDs inside
-
Time: use steady clocks for internal timing (see tests).
-
Table of invariants:
| Contract | Where | Check/Assert | Violation Consequence |
|---|---|---|---|
Event implements type() & name() |
All events | Compile-time review | Runtime type info missing; listeners break |
process() called each frame |
Main loop | Manual call after notifyAsync |
Events stay queued, logic stalls |
| Resource registered once | ResourceRegistry | registerResource returns bool |
Duplicate wastes memory or causes unexpected state |
Model uses notifyAsync only |
Model | Compilation fails for sync notify | Thread-safety compromised |
FontManager semantics (manual mode)
| Contract | Where | Check/Assert | Violation Consequence |
|---|---|---|---|
| Ranges preset vs explicit: last call wins | FontManager | Code review / unit test | Missing glyphs when preset is overridden |
| PUA required for icon fonts | FontManager | Visual check / glyph presence | Icons render as tofu (□) without PUA ranges |
| Preset tokens include MiscSymbols/Dingbats/Arrows | FontManager | Docs + unit test for glyphs | Symbols (⚠, ✈, ←…) miss without ranges |
| Glyph fallback for markers: U+26A0 → U+E002 → "(!)" | Widgets/Fonts | Unit test: FindGlyph chain | Empty icon if neither Unicode nor PUA exists |
-
EventBus uses mutexes for queue and subscription maps
- Lock order: queue mutex before subscriptions.
- Backpressure: event queue processed every frame; ensure
process()is called.
-
ResourceRegistry uses
shared_mutex(ormutexon Emscripten) to protect maps -
Models may spawn threads but must signal shutdown via
isClosing(). -
Retry/timeout: not implemented; recommend adding for IO.
-
Error taxonomy: use
std::runtime_errorfor missing resources; extend with custom exceptions as needed. -
Reliability checklist:
- All event subscriptions unsubscribed in destructors.
-
process()invoked per frame. - Resources registered before access.
- Threads join on shutdown.
- Unit tests: event system, resource registry, application loop (
tests/*). - Property tests: recommended for EventBus ordering and resource uniqueness.
- Integration: build
examples/smoke/core_application_demo.cppfor backend-specific flows. - Oracles: event receipt, resource retrieval, frame rendering.
- Fixtures: use minimal controllers/models with deterministic behaviour.
- When adding a module, test table:
- Font atlas metrics: log atlas texture size and glyph count after
fontsBuildNow. - Budget: keep atlas ≤ 4–8 MB; revisit if adding full CJK + symbols simultaneously.
| Aspect | Mandatory Test |
|---|---|
| Event | subscribe/notify, async queue |
| Resource | register, duplicate register, retrieval |
| Controller | drawContent/drawUi called |
| Model | thread shutdown, registry access |
-
Logging: use
stdout/stderr; avoid PII. -
Metrics: instrument event queue length and frame time.
-
Latency budget: target <16 ms per frame (60 FPS).
-
Allocation norms: avoid per-frame heap allocations in hot paths.
-
Pre-merge checklist:
- Run debug build with sanitizers when possible.
- Profile frame time if new rendering logic added.
- Ensure logs have correlation IDs for threaded models.
- No secrets should be committed; configs live under
data/config. - Never log tokens or file paths containing credentials.
- External HTTP/WebSocket not present; when added, enforce TLS and validate payloads.
- Maintain backward compatibility of events and DTOs; introduce new classes instead of mutating existing ones.
- Resource schema changes require migration functions in registry.
- Deprecation: mark APIs in headers with
[[deprecated]]and provide grace period through changelog.
- Prefer
agents/imguix-smoke-build.mdfor Windows MinGW smoke-example configure/build commands. - Prefer
agents/imguix-fonts-i18n-playbook.mdfor fonts + i18n API checks and doc updates. - Prefer
agents/imguix-windowing-playbook.mdforWindowInstance/ImGuiFramedWindowtasks. - For reusable
.hpp/.ipp/.tppownership and include-structure policy, prefer:- developer doc:
../../docs/header-implementation-guidelines.md - agent playbook:
../../agents/header-implementation-guidelines.md
- developer doc:
- For any windowing task, first verify expected behavior against
docs/WINDOWS-GUIDE.mdbefore editing code or docs. - Treat
external/ImGuiX/agents/as the concise, execution-focused playbook set. - In controller-facing docs and snippets, prefer
Controller::getFont(...); do not exposeWindowInstanceinternals as primary usage. - For windowing docs, use
docs/WINDOWS-GUIDE.mdas canonical and keepdocs/WINDOWS-GUIDE-RU.mdsynchronized. - For framed-window changes, validate both classic and corner smoke examples before finalizing.
- Prefer reusing compatible existing
build-mingwandbuild-mingw-implottrees. - Use
build-mingw-implotonly for the explicit ImPlot / ImPlot3D validation profile. - Do not create ad-hoc build directories like
build,build-sfml, orbuild-sfml-ninjaunless the user explicitly requested a distinct profile. - If a canonical build tree exists, reconfigure and rebuild in place first.
- Recreate that same canonical directory only when the existing tree has source/generator/toolchain mismatch or is known-corrupt.
- Do not run multiple independent
cmake --buildprocesses concurrently against the same build tree.
- Place headers under
include/imguix/<domain>. - Derive from
ModelorControlleras appropriate. - Register in
ApplicationviacreateModel/createWindow. - Add unit tests verifying subscriptions, drawing and resource access.
- Derive from
Pubsub::Eventand implementtype()/name(). - Define payload fields.
- Subscribe via
EventMediator::subscribe. - Test: emit via
notifyAsync, ensureprocess()routes it. - Log occurrence and add metrics counter.
- Implement
WindowInstancefor backend; place.ippnext to others. - Provide
create,handleEvents,drawContent,drawUi,present. - Add backend-specific build scripts and tests.
- Run contract tests to ensure window controls (size, visibility, active state) work.
git submodule update --init --recursiveto fetch bundled deps.sudo apt-get install -y build-essential cmake ninja-build pkg-config git \ libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev \ libgl1-mesa-dev mesa-common-dev \ libasound2-dev libflac-dev libvorbis-dev libogg-dev libsndfile1-dev libopenal-dev \ libfreetype-dev libudev-dev libdrm-dev.cmake -S . -B build -G "Ninja" \ -DIMGUIX_DEPS_MODE=BUNDLED -DIMGUIX_VENDOR_JSON=ON \ -DIMGUIX_BUILD_TESTS=ON -DBUILD_SHARED_LIBS=OFF -DIMGUIX_BUILD_SHARED=OFF \ -DIMGUIX_IMGUI_FREETYPE=ON.cmake --build build.ctest --test-dir build.
- PR: "feat(scope): summary" + motivation, test output.
- ADR: Context → Decision → Consequences. Store in
/docs/adr/(create if absent).
| Symptom | Cause | Fix |
|---|---|---|
| Events never handled | process() not called |
Process queue each frame |
| Resource retrieval throws | registerResource missing or still initializing |
Register before access and handle tryGetResource |
| Dangling subscriptions | Forgetting unsubscribeAll |
Ensure controllers/models inherit EventMediator which handles destructor unsub |
| Blocked shutdown | Threaded model not checking isClosing() |
Poll flag and join threads in destructor |
| Text shows as squares | Ranges include only PUA (icons) | Use fontsSetRangesPreset("Default+...+PUA") or add non-PUA ranges explicitly |
| Icons missing | PUA not included in ranges | Add PUA token to preset or explicit pair 0xE000–0xF8FF |
| Language switched, glyphs still broken | LangStore switched but atlas locale/ranges were not updated |
In onBeforeLanguageApply(lang) call fontsControl().setLocale(lang) and let rebuildIfNeeded() run |
| Inconsistent i18n text after file split | Duplicate keys across multiple <lang>/*.json files |
Keep keys unique per language folder; do not rely on cross-file override order |
| Plural text falls back unexpectedly | plurals.json categories do not match localized keys, or no catch-all other rule |
Keep cardinal rules aligned with base_key.<cat> keys and finish each language with { "cat": "other", "true": true } |
| Compile/docs mismatch on font role | Using nonexistent FontRole::Symbols |
Use supported roles only: Body/H1/H2/H3/Monospace/Bold/Italic/BoldItalic/Icons/Emoji |
| Compile/docs mismatch on locale API | Using old fontsSetLocale(..., bool) signature |
Use runtime facade: fontsControl().setLocale(lang) then rebuildIfNeeded() |
| PopStyleColor / PopID mismatch | PushStyleColor/PushID/PushVar called asymmetrically | Always use a flag pattern: bool pushed = false; if (cond) { ImGui::PushStyleColor(...); pushed = true; } ... if (pushed) ImGui::PopStyleColor(); |
| Misc symbols not rendered | Missing MiscSymbols/Dingbats/Arrows ranges |
Add these presets or merge a symbol font (e.g., Noto Sans Symbols) |
| Atlas bloat | Too many ranges/fonts merged | Audit ranges; split icon font; check atlas size in logs/metrics |
| Preview clipped or shaking | Real text_max_px not accounted for |
Compute via CalcComboPreviewTextMax(combo_w, flags) and fill with CalcTextSize |
| Content sticks to popup edges | No inner padding | Inside popup: Indent(style.FramePadding.x) on the left and SameLine(0,0); Dummy({style.FramePadding.x,0}) on the right; then Unindent |
| Popup closes when clicking a cell | Selectable missing flag |
Use ImGuiSelectableFlags_DontClosePopups for multi-select |
| Hardcoded width factors | GetWindowWidth()*k |
Use SetNextItemWidth(Calc*ComboWidth)/CalcItemWidth() |
| Crash before window created | Config default calls ImGui::GetColorU32 |
Store 0/IM_COL32 in config and convert at draw-time |
Quick grep patterns:
rg notifyAsyncto audit asynchronous event usage.rg registerResourceto verify unique registrations.
Follow the Conventional Commits style:
feat:new featuresfix:bug fixesdocs:documentation changesrefactor:code refactoring without behaviour changestest:when adding or modifying tests
Format: type(scope): short description where the scope is optional. Keep messages short and imperative.
- Use
snake_casefor variables and parameters. - Private members must use the
m_prefix (e.g.,m_event_hub,m_task_manager). Public variables may omit the prefix. - Optional prefixes
p_andstr_when a function or method handles more than five variables or arguments of different types. - Boolean variables start with
is,has,use,enableorm_is_,m_has_, etc., for fields. - Do not use prefixes
b_,n_, orf_.
- Write all code and Doxygen comments in English.
- Use
/// \briefbefore functions and classes. - Avoid starting descriptions with "The".
- Single-class files use
PascalCase(e.g.,TradeManager.hpp). - Multi-class or utility files use
snake_case(e.g.,trade_utils.hpp).
- Names of classes, structs, and enums use
PascalCase. - Method names use
camelCase.
- Methods are written in
camelCase. - Getter methods may drop the
get_prefix when returning existing references or values, exposing internal objects, or acting like a property (e.g.,size(),empty()). - Keep the
get_prefix when a method performs computation or when omission could mislead.
| Path | Role |
|---|---|
include/imguix/core |
Core application, window, event, resource modules |
include/imguix/controllers |
Controller hierarchy (Application, Strategic, Extended) |
include/imguix/widgets |
Reusable UI widgets |
include/imguix/extensions |
Utility helpers for ImGui |
tests |
Example programs and basic tests |
| Path | Role |
|---|---|
docs/ARCHITECTURE.md |
System architecture overview (Russian: docs/ARCHITECTURE-RU.md) |
docs/WINDOWS-GUIDE.md |
Practical windowing usage for WindowInstance and ImGuiFramedWindow (Russian: docs/WINDOWS-GUIDE-RU.md) |
docs/FONTS-GUIDE.md |
FontManager usage; init/runtime boundaries; role-based lookup (getFont) |
docs/I18N-GUIDE.md |
LangStore, PluralRules, resource layout, language-switch flow |
docs/THEMES.md |
Theme guide for built-in styles and creating custom themes |
../../docs/header-implementation-guidelines.md |
Reusable developer guidance for .hpp / .ipp / .tpp ownership and include structure |
../../agents/header-implementation-guidelines.md |
Reusable execution-focused checklist for agents changing header and implementation ownership |
agents/imguix-windowing-playbook.md |
Short agent checklist for windowing changes and backend-aware verification |
| Module | Depends On |
|---|---|
| Application | WindowManager, EventBus, ResourceRegistry, Models |
| WindowInstance | ApplicationContext, EventBus, Controllers |
| Controller | WindowInterface, EventBus, ResourceRegistry |
| Model | ApplicationContext, EventBus, ResourceRegistry |
- EventBus – publish/subscribe hub for events.
- Model – non-visual component processed each frame.
- Controller – window-bound renderer and logic unit.
- ResourceRegistry – thread-safe store for shared resources.
- WindowInstance – backend-specific window implementation.
Default workflow
- Active development happens in
main. stablecontains only tested, releasable code.- Default branch for cloning/pushing:
main.
Rules
- Do not commit directly to
stable. - Merge to
stableonly via PR frommain(or hotfix branches), with CI green and at least 1 code review. - Tag releases on
stableasvX.Y.Zafter merge. - Hotfixes: create
hotfix/*fromstable, PR back intostable, then cherry-pick or merge intomain.
Branch protection (required)
- Protect
stable: no direct pushes, require PR review, require passing CI, require up-to-date with base before merge. - (Optional) Protect
main: require CI.
CI/CD
- CI runs on
mainandstable. - Release artifacts (SDK, binaries, images) publish only on
stable(tags or merges intostable).
Local setup (recommended)
# track both branches
git fetch origin
git checkout -B main origin/main
git checkout -B stable origin/stable
# set default push to current branch name
git config push.default currentRelease flow
-
Work & merge into
main. -
Create a PR
main → stable, ensure CI passes. -
Merge; tag the commit:
git checkout stable git pull git tag -a vX.Y.Z -m "Release vX.Y.Z" git push --tags -
CI on
stablepublishes release artifacts.
Do/Don’t
- ✅
feature/*→ PR intomain. - ✅
hotfix/*fromstable→ PR intostable→ sync back tomain. - ❌ No force-push to
stable. - ❌ No direct commits to
stable.
This project’s CMake is designed around a three‑mode dependency policy and target‑only linking, with optional SDK bundling and test apps. The goals are: easy vendorless consumption, reproducible bundled builds, and clean integration as a subproject.
Each dependency supports a mode: AUTO | SYSTEM | BUNDLED. There is a global switch IMGUIX_DEPS_MODE and per‑dependency overrides (e.g. IMGUIX_DEPS_FMT_MODE, IMGUIX_DEPS_MDBX_MODE, …).
Resolution order in AUTO (or when a per‑dep mode inherits the global setting):
- SYSTEM/CONFIG:
find_package(... CONFIG QUIET); if a suitable imported target exists, use it. - Submodule: if sources are present (e.g.
libs/<dep>),add_subdirectory(...)and reuse the provided targets. - FetchContent: fallback to fetch the dependency and expose its targets.
If
SYSTEMis explicitly requested and the package cannot be found, configuration fails fast.
We never export raw include/library paths. Everything links via targets:
- Examples:
fmt::fmt,mdbx::mdbx,ImGui-SFML,SFML::Graphics/SFML::Window/SFML::System,nlohmann_json::nlohmann_json,imgui::imgui. - If a dependency’s headers/types are visible in our public interface, link it as
PUBLIC; otherwisePRIVATE. - For nonstandard packages (e.g., libmdbx) we normalize to an alias like
mdbx::mdbx(if upstream target names vary).
-
Backend options:
IMGUIX_USE_SFML_BACKEND(default ON),IMGUIX_USE_GLFW_BACKEND(OFF),IMGUIX_USE_SDL2_BACKEND(OFF). Exactly one is expected. -
Core ImGui and extras:
IMGUIX_IMGUI_FREETYPEenablesimgui_freetypeintegration (links FreeType and definesIMGUI_ENABLE_FREETYPE).IMGUIX_IMGUI_STDLIBcontrolsmisc/cpp/imgui_stdlib.cpp. Default ON for non‑SFML backends, forced OFF for SFML (ImGui‑SFML already builds it to avoid duplicate symbols).
IMGUIX_HEADER_ONLYtoggles a pure interface target vs a compiled library (STATICby default;IMGUIX_BUILD_SHAREDswitches toSHARED).- In header‑only mode we avoid linking transitives; consumers bring their own backend/ImGui/FreeType via targets.
IMGUIX_BUILD_TESTSbuilds executables intests/and registers them with CTest.- Test executables link to the selected backend + ImGui targets and copy runtime assets via helper functions.
imguix_add_assets(<target> DIRS <paths> [DEST_RUNTIME <rel>] [EXCLUDE_DIRS <names...>])copies asset directories next to the built binary (post‑build). UseEXCLUDE_DIRS webto skipassets/data/webfor native tests.imguix_copy_and_embed_app_icon(<target>)(Windows) addsapp_icon.rcto sources and copiesicon.pngto the runtimedata/resources/iconsfolder.
IMGUIX_SDK_INSTALLenables installing an SDK layout (headers, libs, CMake package exports, and optionally quickstart).IMGUIX_SDK_BUNDLE_DEPScontrols whether third‑party dependencies are also staged into the SDK (include/,lib/, and theircmake/packages when available).- Dear ImGui: only headers are installed (pruned of
.git,backends,docs, etc.). Optionally “flatten” selected headers into the SDK include root viaIMGUIX_SDK_FLATTEN_MISC_HEADERS(e.g.,imgui_stdlib.h,imgui_freetype.h). - ImGui‑SFML / fmt / libmdbx / FreeType / SFML: installed via their own
install(...)rules when available (we flip upstream install switches likeFMT_INSTALL=ON,MDBX_INSTALL_STATIC=ON), otherwise we manually install target artifacts and headers. - Quickstart template:
IMGUIX_SDK_INSTALL_QUICKSTARTinstalls a ready‑to‑build sample (quickstart/) and optional resources (quickstart/data/resources).
A parent project can bring its own dependencies; our CMake will detect existing targets and reuse them without duplication:
# Top-level CMake
find_package(fmt CONFIG REQUIRED) # or add_subdirectory(fmt)
# For MDBX: either find_package(MDBX ...) or add_subdirectory(libmdbx) and create an alias mdbx::mdbx
# Force our subproject to use system deps only:
set(IMGUIX_DEPS_MODE SYSTEM CACHE STRING "" FORCE)
add_subdirectory(external/imguix)
target_link_libraries(my_app PRIVATE ImGuiX::imguix)- We export
ImGuiXTargets.cmakeandImGuiXConfig.cmakeso that consumers canfind_package(ImGuiX CONFIG REQUIRED)and useImGuiX::imguix. - When SDK is installed, the package files land under
lib/cmake/ImGuiXwithin the SDK root.
Build tests + bundle SDK:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release ^
-DIMGUIX_BUILD_TESTS=ON -DIMGUIX_SDK_INSTALL=ON -DIMGUIX_SDK_BUNDLE_DEPS=ON
cmake --build build --target install --config ReleaseBuild SDK only (no tests):
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release ^
-DIMGUIX_BUILD_TESTS=OFF -DIMGUIX_SDK_INSTALL=ON -DIMGUIX_SDK_BUNDLE_DEPS=ON
cmake --build build --target install --config ReleaseUse system dependencies only:
cmake -S . -B build -DIMGUIX_DEPS_MODE=SYSTEMDisable SFML backend and use pure Dear ImGui with std::string helpers:
cmake -S . -B build -DIMGUIX_USE_SFML_BACKEND=OFF -DIMGUIX_IMGUI_STDLIB=ONApplies to all C++17 and newer code in this repository.
- Use
///for all Doxygen comments; avoid/** ... */blocks. - Use backslash tags (
\brief,\param, etc.). - Write comments in English.
Document entities using the following sequence:
\brief– one short sentence (≤100 chars).\tparam– one per template parameter.\param– in function signature order.\return– exactly once for non-void functions.\throws– per exception type.\pre/\post.\invariant.\complexity.\thread_safety.\note/\warning(optional).
All function parameters, template parameters, and non-void return values must be documented. Omit \return for void functions.
- Keep wording concise, imperative, and under ~100–120 columns. Avoid leading “The”.
- Public headers document behavior and usage but omit internal layout details.
- Include fenced C++ examples for key public APIs when helpful.
/// \brief Resize canvas to the target dimensions.
/// \param w Width in pixels.
/// \param h Height in pixels.
/// \pre w >= 0 && h >= 0.
/// \post New size equals (w, h).
void resize(int w, int h);
/// \brief Computes 64-bit hash of the input.
/// \tparam T Input type supporting contiguous byte access.
/// \param data Input value.
/// \return 64-bit hash.
/// \complexity O(n) over input size.
/// \thread_safety Not thread-safe.
template<class T>
uint64_t hash(const T& data);If future style conflicts arise, this section takes precedence over legacy comments.
- Use 4 spaces for every indentation level; NEVER use tabs or 2-space indents.
- Indent all code within a
namespaceby one level (4 spaces). - Soft line limit of 120 characters.
- K&R style – opening brace on the same line.
- If a function signature exceeds the line limit, break after
(. - Place each parameter on its own line with double indentation (8 spaces).
- Align the closing
) {with a single indentation (4 spaces).
- Keep
:on the line with the class name. - List each base class on a new line with double indentation (8 spaces) and trailing commas except the last.
{remains on the same line as the last base class.
namespace ImGuiX {
class FontManager :
private FontManagerViewCRTP<FontManager>,
private FontManagerControlCRTP<FontManager> {
public:
// ...
};
} // namespace ImGuiX- Break after
(and put each argument on its own line with double indentation (8 spaces). - If an argument uses a ternary
?:, break after?and before:; align both outcomes under the start of the ternary using the same double indentation. - Place the final
)on its own line aligned with the call line, then);.
Good:
return ImGui::GetIO().Fonts->AddFontFromFileTTF(
resolved.c_str(),
eff_px,
&cfg,
ranges.empty() ?
nullptr :
ranges.data()
);Bad (closing paren indented like arguments):
return ImGui::GetIO().Fonts->AddFontFromFileTTF(
resolved.c_str(),
eff_px,
&cfg,
ranges.empty() ?
nullptr :
ranges.data()
);- Bind the symbol to the type:
ImFont*,const Foo&.
- Use
///comments in English with concise\brief,\param,\return, and\notetags.
- Order includes as: header of the current file, then standard library headers
<...>, then external or project headers"...". - Separate these groups with a blank line.
- Core dependencies are aggregated in
include/imguix/core.hpp; prefer including this header to pull in core components and maintain dependency order.
- Namespaces and types: PascalCase.
- Methods and member functions: camelCase.
- Variables and parameters: snake_case.
- Private members prefixed with
m_. - Booleans start with
is,has,use, orenable; private booleans usem_is_,m_has_, etc.
- Private members prefixed with
- Constants:
kPascalCaseorUPPER_CASE(preferkPascalCaseforconstexpr). - Events: PascalCase with the
Eventsuffix. - Header guards follow
_PROJECT_MODULE_FILENAME_HPP_INCLUDED.
- Prefer early-return to reduce nesting.
- Keep functions short and cohesive.
- Avoid hidden global state; favor explicit dependencies.
- Use
enum classfor scoped enums. - Avoid macros in public APIs unless required for portability.