Styling

first_graph drew bare boxes. The editor’s look is layered, and each layer is independent — reach for the smallest one that does the job: a canvas-wide theme, per-node tints, scoped style var / color brackets for one-off nodes, pin pivots that move the link-attach point onto the node edge, and a background draw list for custom art.

apply_daslang_node_editor_style(g_ed)          // canvas theme (warm-dark + amber)

node(1, (color = float4(0.15, 0.35, 0.18, 0.78))) {   // per-node background tint
    text("Source")
    pin(12, (kind = PinKind.Output, pivot_alignment = float2(1.0, 0.5))) { text("out ->") }
}

with_style_var(imgui_node_editor::StyleVar.NodeRounding, 10.0) {        // scoped VAR
    with_style_color(imgui_node_editor::StyleColor.NodeBorder, amber) { // scoped COLOR
        node(3, (color = red)) { ... }
    }
}
with_node_background_drawlist(3) $(var dl) {                            // custom art
    let p = imgui_node_editor::GetNodePosition(3)
    let s = imgui_node_editor::GetNodeSize(3)
    dl |> add_rect_filled(p, float2(p.x + 5.0, p.y + s.y), rgba(255u, 90u, 90u, 220u))
}

Source: examples/tutorial/styling.das.

Walkthrough

  1options gen2
  2
  3require imgui/imgui_harness
  4require imgui/imgui_node_editor_boost_v2
  5require imgui/imgui_node_editor_live
  6require imgui/imgui_node_editor_theme_daslang
  7
  8// =============================================================================
  9// TUTORIAL: styling — make nodes look the way you want.
 10//
 11//   apply_daslang_node_editor_style(ed)        -- canvas theme (warm-dark + amber)
 12//   node(id, (color = float4(r,g,b,a)))        -- per-node background tint
 13//   pin(id, (kind=, pivot_alignment=))         -- where the link attaches on the pin
 14//   with_style_var(StyleVar.NodeRounding, 10)  -- scoped style VAR around a node
 15//   with_style_color(StyleColor.NodeBorder, c) -- scoped style COLOR (composes with the var)
 16//   with_node_background_drawlist(id) $(var dl) -- raw drawing behind a node
 17//
 18// first_graph drew bare boxes. The editor's look is layered: a canvas-wide THEME,
 19// per-node TINTS (the `color` arg), SCOPED style var/color brackets for one-off
 20// nodes, pin PIVOTS that move the link-attach point onto the node edge, and a
 21// background DRAW LIST for custom art. Each layer is independent — reach for the
 22// smallest one that does the job.
 23//
 24// STANDALONE: daslang.exe modules/dasImguiNodeEditor/examples/tutorial/styling.das
 25// LIVE:       daslang-live modules/dasImguiNodeEditor/examples/tutorial/styling.das
 26// =============================================================================
 27
 28var g_ed : imgui_node_editor::EditorContext? = null
 29var g_seeded : bool = false
 30
 31def draw_editor() {
 32    node_editor("graph", (editor = g_ed)) {
 33        if (!g_seeded) {
 34            imgui_node_editor::SetNodePosition(1, float2(80.0, 80.0))
 35            imgui_node_editor::SetNodePosition(2, float2(360.0, 120.0))
 36            imgui_node_editor::SetNodePosition(3, float2(660.0, 160.0))
 37            g_seeded = true
 38        }
 39        // (1) A plain tint: the `color` arg fills the node background. Green for a source.
 40        node(1, (color = float4(0.15, 0.35, 0.18, 0.78))) {
 41            text("Source")
 42            pin(12, (kind = PinKind.Output, pivot_alignment = float2(1.0, 0.5))) {
 43                text("out ->")
 44            }
 45        }
 46        // (2) Default look — no tint, square corners, default border. Inputs attach on
 47        // the left edge (pivot x = 0), outputs on the right (x = 1); without a pivot the
 48        // link springs from the pin label's center, which looks untidy on a multi-pin node.
 49        // Every pin id is unique across the whole editor — 21/22 here, distinct from node 1's
 50        // output 12 and node 3's input 31 (same-id pins silently merge into one).
 51        node(2) {
 52            text("Passthrough")
 53            pin(21, (kind = PinKind.Input, pivot_alignment = float2(0.0, 0.5))) {
 54                text("-> in")
 55            }
 56            pin(22, (kind = PinKind.Output, pivot_alignment = float2(1.0, 0.5))) {
 57                text("out ->")
 58            }
 59        }
 60        // (3) The showcase node: a red tint, PLUS scoped style brackets — rounded
 61        // corners (a style VAR) and an amber border (a style COLOR). The two wrappers
 62        // compose; each restores its previous value when the block ends.
 63        with_style_var(imgui_node_editor::StyleVar.NodeRounding, 10.0) {
 64            with_style_color(imgui_node_editor::StyleColor.NodeBorder, float4(0.910, 0.631, 0.227, 1.0)) {
 65                node(3, (color = float4(0.40, 0.18, 0.18, 0.78))) {
 66                    text("Output")
 67                    pin(31, (kind = PinKind.Input, pivot_alignment = float2(0.0, 0.5))) {
 68                        text("-> in")
 69                    }
 70                }
 71            }
 72        }
 73        // A custom accent stripe down node 3's left edge. The node's draw channels only
 74        // exist once it is fully built, so this runs AFTER the node block, reading the
 75        // editor-owned geometry back (GetNodePosition / GetNodeSize).
 76        with_node_background_drawlist(3) $(var dl) {
 77            let p = imgui_node_editor::GetNodePosition(3)
 78            let s = imgui_node_editor::GetNodeSize(3)
 79            dl |> add_rect_filled(p, float2(p.x + 5.0, p.y + s.y), rgba(255u, 90u, 90u, 220u))
 80        }
 81        link(100, 12, 31)
 82    }
 83}
 84
 85[export]
 86def init() {
 87    harness_init("Styling", 1000, 600)
 88    g_ed = create_node_editor()
 89    apply_daslang_node_editor_style(g_ed)   // warm-dark canvas + amber grid to match daslang's ImGui theme
 90}
 91
 92[export]
 93def update() {
 94    if (!harness_begin_frame()) return
 95    harness_new_frame()
 96    let io & = unsafe(GetIO())
 97    SetNextWindowPos(float2(0.0, 0.0), ImGuiCond.Always)
 98    SetNextWindowSize(io.DisplaySize, ImGuiCond.Always)
 99    let flags = (ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize |
100                 ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoScrollbar |
101                 ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoSavedSettings |
102                 ImGuiWindowFlags.NoBringToFrontOnFocus)
103    window(MAIN_WIN, (text = "Styling", closable = false, flags = flags)) {
104        draw_editor()
105    }
106    harness_end_frame()
107}
108
109[export]
110def shutdown() {
111    destroy_node_editor(g_ed)
112    harness_shutdown()
113}
114
115[export]
116def main() {
117    init()
118    while (!exit_requested()) {
119        update()
120    }
121    shutdown()
122}

Canvas theme

apply_daslang_node_editor_style(ed) (from imgui/imgui_node_editor_theme_daslang) sets the canvas background, grid, and link colors to the warm-dark + amber palette that matches daslang’s ImGui theme. It is one call at init and affects the whole editor — the broadest styling layer.

Per-node tint

The color tuple arg on node(id, (color = float4(r, g, b, a))) fills that one node’s background. Node 1 is green (a source), node 3 red (an output); node 2 passes no color and keeps the editor default. This is the cheapest per-node knob — no scope, no restore.

Scoped style var + color

For properties that aren’t a node arg — corner rounding, border color — wrap the node in a scoped bracket. with_style_var(StyleVar.NodeRounding, 10.0) rounds the corners; with_style_color(StyleColor.NodeBorder, amber) recolors the border. They compose (nest one inside the other), and each restores the previous value when its block ends, so only the node inside is affected.

Pin pivots

pivot_alignment on a pin moves the point where links attach. float2(0.0, 0.5) is the pin’s left edge (use it for inputs), float2(1.0, 0.5) the right edge (outputs). Without a pivot the link springs from the pin label’s center, which looks untidy once a node has several pins. (pivot_size and pivot_scale are the other two knobs — see shader_graph.das.)

Background draw list

with_node_background_drawlist(id) $(var dl) { ... } hands you a draw list behind the node for custom art — here a red accent stripe down node 3’s left edge. The node’s draw channels only exist once it is fully built, so this runs after the node block, reading the editor-owned geometry back with GetNodePosition / GetNodeSize.