Cairn

Cairn is a lightweight, modernized Addon Framework

File Details

48

  • R
  • May 13, 2026
  • 15.22 MB
  • 11
  • 12.0.7+4
  • Classic + 3

File Name

Cairn-48.zip

Supported Versions

  • 12.0.7
  • 12.0.5
  • 5.5.3
  • 2.5.5
  • 1.15.8

Cairn

48 (2026-05-13)

Full Changelog Previous Releases

  • release 48
    Cairn-Gui-Widgets-Standard-2.0 MINOR 12 -> 15:
    • MINOR 13: TabGroup wraps to multi-row on overflow. Auto-grows
      strip height + re-anchors content panes; OnSizeChanged repacks
      rows live on window resize.
    • MINOR 14: TreeView widget. Generic expand/collapse hierarchical
      list. Single-click toggles expansion + fires Click event. Frame
      height auto-grows to fit visible rows.
    • MINOR 15: TreeView honors node.expandable=true so consumers can
      mark a branch expandable without pre-building children, populating
      on the Toggle event.
      Cairn-Util-1.0 MINOR 32 -> 35:
    • MINOR 33: String.SafePreview(s, maxLen). pcall-wrapped preview;
      returns nil on WoW "secret string" values so callers can render
      a placeholder instead of tainting on :gsub.
    • MINOR 34: Table.SafeKeys(t, sortFn?). pcall-wrapped pairs() that
      returns nil on tables protected from addon iteration.
    • MINOR 35: Table.SafeCount(t). Same protection, count only (no
      array build).
      All five Cairn TOC flavors registered the new TreeView.lua file.
      First consumers: Forge_APIBrowser v2, Forge_Tables v2, Forge_CVars
      v2 (in the Forge repo).
  • Cairn: safe-introspection helpers + TreeView lazy expansion
    Cairn-Util-1.0 MINOR 32 -> 35:
    • String.SafePreview(s, maxLen): pcall-wrapped preview that returns
      nil on WoW "secret string" values (locale entries, protected
      globals) so callers can render a placeholder instead of tainting
      on :gsub.
    • Table.SafeKeys(t, sortFn?): pcall-wrapped pairs() that returns
      nil on tables protected from addon iteration (Blizzard internal
      frames, secure containers).
    • Table.SafeCount(t): same protection, returns just the count
      without allocating the key array.
      All three pulled up from inline pcall code in Forge_Tables. The
      hazards are general (any inspector tool walking unknown data hits
      them); centralizing in Cairn-Util means Forge_Console, future API
      introspectors, and anything else avoid re-rolling.
      Cairn-Gui-Widgets-Standard-2.0 MINOR 14 -> 15:
    • TreeView honors node.expandable=true even when children is empty.
      Consumer populates children on the Toggle event and calls Refresh,
      so walking large trees becomes pay-as-you-go. Hit on Forge_Tables:
      eagerly walking _G at depth 2 did 500k+ ops and froze the client.
      Lazy expansion via this flag keeps initial build to root keys only.
      Tested in-game on interface 120005 via Forge_Tables (separate Forge
      commit).
  • Cairn-Gui-Widgets-Standard-2.0 MINOR 14: TreeView widget
    Generic expand/collapse hierarchical list. Consumer provides
    { id, label, aux, children } nodes; widget renders one row per
    visible node with indent + indicator. Collapsed branches contribute
    one row regardless of how many descendants they have, so the
    widget naturally handles large data sets that overwhelm a flat
    list (Forge_APIBrowser has ~3000+ entries).
    • Single-click toggles expansion on branches and fires "Click" with
      the original node, so consumers can still do click-to-select.
      "Toggle" event also fires on expand/collapse for programmatic
      consumers.
    • Frame height auto-grows to fit visible rows; wrap in a ScrollFrame
      for tall trees. Consumer hooks OnSizeChanged to push the tree
      height into ScrollFrame:SetContentHeight.
    • SetNodes preserves expansion state by id, so consumers that filter
      trees by rebuilding don't lose user-expanded branches across
      filter changes (ids that survive the filter stay expanded).
    • Registered in all 5 TOCs (Cairn.toc + Mists/TBC/Vanilla/XPTR flavor
      variants).
      First consumer: Forge_APIBrowser v2 (separate Forge commit).
  • Cairn-Gui-Widgets-Standard-2.0 MINOR 13: TabGroup wraps to multi-row on overflow
    Previously the tab strip extended past the TabGroup frame's right edge
    when total tab width exceeded the strip width (visible on Forge with
    18 sub-addons at default window width: "About" clipped past the Forge
    window's right edge).
    • relayoutTabs tracks current x and wraps to a new row when the next
      button won't fit. Skips the wrap when x == STRIP_PAD so a single
      oversized button still renders (clipped) rather than wrapping
      infinitely.
    • Strip auto-grows in height to fit all rows. Content panes re-anchor
      to the new strip bottom via reanchorPanes() so tab content always
      starts directly below the (possibly multi-row) strip.
    • HookScript("OnSizeChanged") on the TabGroup frame re-runs relayout
      on resize, so widening the host window repacks tabs into fewer
      rows live.
      Header doc updated; "no tabs that scroll horizontally - deferred"
      removed (multi-row wrap subsumes the use case).
      Tested in-game on Forge with 18 tabs across two rows; resizing the
      window repacked them as expected.