AGT Coding Style

AGT Coding Style

AGT follows axl-sdk’s coding style (AXL-Coding-Style.md) verbatim, with the small set of C++-specific adaptations documented here. When a rule below differs from AXL’s, the AGT version wins for AGT code; when this doc is silent, AXL applies.

One prefix throughout: AGT for everything — project name, doc filenames, class names (AgtObject, AgtApp), macros (AGT_MAP_BEGIN), source filenames (src/agt-app.cpp), build artifacts (libagt.a). Same pattern as axl-sdk uses for AXL.

This doc is intentionally short — the substantive style work lives in AXL-Coding-Style.md. Don’t restate things from there here; only document deltas.

Deltas from AXL-Coding-Style.md

Message-ID enum chain

FOX-style: every class that defines AGT_MAP_COMMAND ids declares them in a public enum chained through Base::ID_LAST, so subclass and consumer IDs never collide with whatever IDs the AGT base classes happen to use today (or add tomorrow).

class MyDialog : public AgtDialog {
public:
    enum {
        ID_OK = AgtDialog::ID_LAST,
        ID_CANCEL,
        ID_LAST   // re-emit so descendants can chain
    };
    // ...
};

AgtObject::ID_LAST = 0 is the chain root. Each AGT-shipped class re-emits ID_LAST; consumer classes follow the same convention. File-scope constexpr uint16_t ID_FOO constants are an anti-pattern — they don’t chain, and collision risk grows silently as the class hierarchy evolves.

Constructor design

Common-case wiring goes in the constructor with default values; rare-case tweaks stay as setters. The goal is consumer code that reads cleanly as a single new-expression:

new AgtButton(parent, x, y, w, h, "Quit", &window, ID_QUIT);

NOT the chained variant — (new Foo(...))->set_X() is valid C++ but jars readers (operator precedence forces the parens). Match FOX’s trailing-arg pattern: identity / geometry first, target + selector last (e.g. FXButton(parent, label, icon, target, sel)).

7+ constructor args is the line where readability suffers; at that point use an AgtFooOpts struct value passed by const ref instead of a flat arg list. Optional rare-case configuration (e.g. set_enabled(false), set_normal_color(...)) stays as post-construction setters.

Naming

Element

AXL convention

AGT convention

Example

Free functions / variables / params

axl_snake_case

same (snake_case)

do_layout(parent)

Class / struct names

AxlPascalCase

AgtPascalCase (Agt prefix)

AgtWidget, AgtButton

Class methods

n/a (C)

snake_case() (matches AXL func style)

widget.layout(), app.run()

Member variables

snake_case

snake_case_ (trailing underscore)

child_count_, loop_

Macros / constants

AXL_SCREAMING_CASE

AGT_SCREAMING_CASE

AGT_MAP_BEGIN, AGT_MAX_CHILDREN

Enum values

AXL_SCREAMING_CASE

AGT_SCREAMING_CASE

AGT_EVENT_CLICK

Namespaces

n/a (C)

none — Agt prefix replaces namespace

AgtApp app; not agt::App app;

Why no agt:: namespace: AGT is FOX-shape (per AGT-Design.md), not glibmm-shape. Matches FOX’s FXObject/FXApp convention (adapted: project=AGT, prefix=Agt; FOX uses 2-letter FX for historical reasons but AGT follows axl-sdk’s 3-letter project=prefix unification). The agt/ directory in include paths and the Agt prefix together carry the namespace.

Cursor vs. pointer (terminology). Two distinct concepts, kept verbally distinct everywhere (symbols, comments, docs):

  • cursor — the text insertion point (the blinking caret in an editable widget). API: cursor(), set_cursor(), cursor_line(), cursor_color(), … (AGT does not use the word “caret”.)

  • pointer — the mouse arrow. API: AgtWindow::pointer_x(), set_pointer_enabled(), the software-pointer sprite, etc.

The one exception is the menu keyboard-navigation cursor (AgtMenuItem/AgtMenuBar highlight driven by arrow keys) — a third concept that is neither, kept as “keyboard cursor” in its (always qualified) prose.

File naming

Headers and sources use kebab-case (matching AXL):

Element

Convention

Example

Public headers

include/agt/agt-<name>.hpp

include/agt/agt-app.hpp

Umbrella header

include/agt.hpp

#include <agt.hpp>

Internal headers

agt/detail/<name>.hpp

agt/detail/handle.hpp

Source files

src/agt-<name>.cpp (flat for now; per-module subdirs src/<module>/agt-<name>.cpp when there are >3 sources)

src/agt-app.cpp

Test files

test/unit/agt-test-<module>.cpp

test/unit/agt-test-app.cpp

Examples

examples/<name>.cpp (no Agt prefix)

examples/hello.cpp

Header guards

Use #pragma once instead of #ifndef AGT_FOO_HPP guards. AGT is greenfield C++; #pragma once is universally supported by GCC and the cross-compiler we target (ARM bare-metal toolchain). Saves a line, removes the chance of a typo’d guard.

(AXL uses #ifndef guards because it’s older C code and the guard convention is established; AGT doesn’t inherit that history.)

Includes

Order: freestanding C → axl-sdk → AGT headers → C++ stdlib.

#include <stddef.h>          // freestanding C
#include <stdint.h>

#include <axl.h>             // axl-sdk (or specific axl/axl-X.h)

#include <agt/agt-app.hpp>   // AGT headers
#include <agt/agt-widget.hpp>

#include <utility>           // C++ stdlib (header-only subset only)
#include <span>

axl-sdk umbrella <axl.h> is fine for examples; internal AGT sources should prefer specific headers (<axl/axl-loop.h> etc.) to minimize compile cost.

Forbidden C++ features (per AXLMM-Design.md toolchain

constraints)

Feature

Status

Why

Exceptions (throw/catch)

forbidden

libsupc++ symbols unresolvable in freestanding link

RTTI (typeid, dynamic_cast)

forbidden

__dynamic_cast + typeinfo vtables unresolvable

<string>, <vector>, etc.

forbidden

libstdc++ allocator + exception machinery

<stdexcept>, std::runtime_error

forbidden

chains to exception machinery

thread_local

forbidden

needs __tls_get_addr; UEFI is single-threaded anyway

<format>

deferred

not in C++23 freestanding subset (P0829); revisit if a real need surfaces

std::shared_ptr / std::weak_ptr

avoid

ref-counted ownership conflicts with AGT’s parent-child tree model

Usable: <array>, <span>, <string_view>, <type_traits>, <utility>, <initializer_list>, <new>, <optional>, <variant>, <expected> (C++23), header-only subsets of <algorithm> / <numeric> / <functional>.

Full list + rationale: AXLMM-Design.md §”Toolchain & constraints”.

Source file header

// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 AximCode

Two-line SPDX header on every .cpp/.hpp. Same content as AXL, different comment syntax (// C++-native instead of /* */).

Source file order

Matches AXL (1: includes → 2: log domain → 3: macros → 4: types → 5: file-scope vars → 6: forward decls → 7: implementations). See AXL-Coding-Style.md §”Source File Layout”.

Doc comments

Use /// line-comments + /// @brief block style for exported API (Doxygen-compatible). Per-param ///< on the same line as the parameter (matches AXL).

class AgtWidget {
public:
    /// Construct a widget with the given bounding rect.
    ///
    /// @param parent Owning parent widget; widget is added as the
    ///               last child of @a parent.
    /// @param x,y,w,h Bounding rectangle in parent-local coordinates.
    AgtWidget(
        AgtWidget *parent,   ///< owning parent (cascade-delete root)
        int x, int y,        ///< top-left in parent coords
        int w, int h         ///< width / height in pixels
    );
};

Everything else: see AXL-Coding-Style.md

Formatting (4-space indent, K&R braces, always-braces, return type on its own line, pointer-with-variable, explicit NULL checks, etc.), return value conventions (predicates / pointers / int / typed status enum), event-loop callback convention, printf and variadic style — all carry over from AXL verbatim.