Skip to content

develop#2

Merged
skmp merged 96 commits intomainfrom
develop
Mar 27, 2026
Merged

develop#2
skmp merged 96 commits intomainfrom
develop

Conversation

@skmp
Copy link
Copy Markdown
Member

@skmp skmp commented Mar 27, 2026

No description provided.

skmp added 20 commits March 26, 2026 22:19
- Created IEditorPane interface in editor_pane.h to unify editor pane functionality.
- Updated Editor1Pane and Editor2Pane to implement IEditorPane, ensuring consistent method signatures for loading, drawing, and state checks.
- Added TabState struct to manage editor pane instances, providing convenience accessors for loaded state and file paths.
- Enhanced Editor2Pane to inherit from IEditorPane, aligning it with the new architecture.
- docs/instructions.md: Guide covering build system, architectural layers,
  instrument anatomy, audio callback patterns, and codebase conventions
- docs/names.md: Naming philosophy and guidelines for the project
- README.md: Link new docs from the Instructions section
Copilot AI review requested due to automatic review settings March 27, 2026 09:11
@skmp skmp changed the title Develop develop Mar 27, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the attoflow editor by replacing the legacy monolithic editor with a layered Editor2 architecture built around GraphBuilder (observer-driven model) and a reusable VisualEditor canvas interaction layer, plus extensive accompanying documentation.

Changes:

  • Introduces GraphBuilder + editor observer interfaces and migrates the editor UI to FlowEditorWindow + Editor2Pane + VisualEditor.
  • Adds a dedicated nets view (NetsEditor) and shared selection state across panes/tabs.
  • Embeds Liberation Mono for ImGui and adds a large documentation suite describing architecture, style, patterns, and format rules.

Reviewed changes

Copilot reviewed 42 out of 45 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/legacy/editor1.h Adds legacy Editor1 pane header in legacy/ for compatibility/transition.
src/attoflow/window.h New top-level window class API (tabs, build/run, child process mgmt).
src/attoflow/visual_editor.h New reusable canvas interaction base class (pan/zoom/hover/drag/wire ops).
src/attoflow/visual_editor.cpp Implements canvas drawing + interactions (selection, dragging, wire drag/grab).
src/attoflow/tooltip_renderer.h Declares tooltip render helpers for pins/nodes/wires.
src/attoflow/tooltip_renderer.cpp Implements tooltip content for pins, node body, and wire info.
src/attoflow/tab.h Defines per-tab state to hold GraphBuilder, shared editor state, and pane instance.
src/attoflow/sdl_imgui_window.h Switches to embedded Liberation Mono font and DPI-aware font rebuilding.
src/attoflow/node_renderer.h Declares rendering + hit-testing primitives and hover item types.
src/attoflow/nets_editor.h Adds a nets-focused editor pane built on VisualEditor.
src/attoflow/nets_editor.cpp Implements nets layout/rendering + hover highlighting in a baseline-style view.
src/attoflow/main.cpp Updates entry include to use the new window.h entry point.
src/attoflow/fonts/LICENSE-LiberationFonts Adds font license for Liberation fonts.
src/attoflow/editor_style.h Adds centralized editor style constants (Editor2Style, global S).
src/attoflow/editor_style.cpp Defines default values for Editor2Style and instantiates global S.
src/attoflow/editor_pane.h Introduces IEditorPane interface for pluggable panes per tab.
src/attoflow/editor2.h Declares Editor2 pane, per-item editor impls, and wire connection hooks.
src/attoflow/editor2.cpp Implements Editor2 rendering, hover, wire rebuild, connect/disconnect/delete logic.
src/attoflow/editor.h Removes the legacy monolithic editor window/header.
src/attoflow/atto_editor_shared_state.h Adds shared selection state used across panes.
src/atto/node_types.h Adds NodeTypeID::Error descriptor entry.
src/atto/graph_editor_interfaces.h Adds editor observer interfaces (IGraphEditor, INodeEditor, etc.).
src/atto/graph_builder.h Adds the GraphBuilder model (entries/pins/sentinels, batching, observer hooks).
src/atto/args.h Adds split_args API and clarifies legacy wrapper comment.
src/atto/args.cpp Implements split_args tokenizer/splitting logic for arg strings.
scenes/klavier/main.atto Updates shadow expr nodes to encode return types inline (folding -> nodes).
docs/thinking.md New design/philosophy write-up for major project decisions.
docs/style.md New comprehensive code + visual style guide.
docs/patterns.md New catalog of recurring design patterns used throughout the codebase.
docs/names.md New naming philosophy and naming history document.
docs/differential.md New document on incremental/differential concepts across the system.
docs/coding.md New C++ coding conventions and repository practices guide.
docs/changelog.md New project evolution and milestone changelog.
docs/attolang.md Updates language spec sections (inline args, bang semantics, file format details).
docs/architecture.md New high-level architecture overview and subsystem breakdown.
README.md Adds pointers to the new documentation suite.
CMakeLists.txt Adds graph_builder.cpp to core library and generates embedded font header for editor build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +46 to +50
// Find which visual input pin of dst_node receives this net entry, using VisualPinMap
static int find_dest_input_pin(const VisualPinMap& vpm, const BuilderEntryPtr& net_entry) {
for (int i = 0; i < (int)vpm.inputs.size(); i++) {
auto& pin = vpm.inputs[i];
if (!pin.arg) continue;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper appears unused in this TU, which can trip -Werror=unused-function builds. Either remove it or use it for destination pin lookup.

Copilot uses AI. Check for mistakes.
Comment on lines +295 to +299
ImVec2 label_sz = ImGui::CalcTextSize(net_id.c_str());
float label_w = label_sz.x * canvas_zoom_ * 0.8f / ImGui::GetFontSize() * ImGui::GetFontSize();
// Simpler: just use a fixed estimate
float label_half = (label_sz.x * zoom * 0.8f + 6.0f) * 0.5f;
float label_cx = label_x + label_half;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

label_w / label_cx are computed but never used, which can trigger unused-variable warnings. Either remove them or use them in the label-gap computation.

Copilot uses AI. Check for mistakes.
Comment thread src/attoflow/editor2.cpp
Comment on lines +463 to +467
// Remove from net's destinations if this is a dest pin
auto node = pin->node();
auto& dests = net->destinations();
dests.erase(std::remove_if(dests.begin(), dests.end(),
[&](auto& w) { return w.lock() == node; }), dests.end());
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This removal always treats the pin as a destination (destinations() entry). If the disconnected pin is an output/source pin, you need to clear net->source() instead; otherwise the net is left with a stale source. Use the pos parameter (or equivalent) to branch.

Suggested change
// Remove from net's destinations if this is a dest pin
auto node = pin->node();
auto& dests = net->destinations();
dests.erase(std::remove_if(dests.begin(), dests.end(),
[&](auto& w) { return w.lock() == node; }), dests.end());
// Update net endpoints based on pin position
auto node = pin->node();
if (pos == PortPosition2::Output) {
// Disconnecting a source/output pin: clear the net's source
net->source({});
} else {
// Disconnecting a destination/input pin: remove from destinations
auto& dests = net->destinations();
dests.erase(std::remove_if(dests.begin(), dests.end(),
[&](auto& w) { return w.lock() == node; }), dests.end());
}

Copilot uses AI. Check for mistakes.
Comment thread src/attoflow/editor2.cpp
Comment on lines +515 to +520
// Remove this node from the net's destinations
auto node = pin->node();
auto& dests = net->destinations();
dests.erase(std::remove_if(dests.begin(), dests.end(),
[&](auto& w) { return w.lock() == node; }), dests.end());

Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code always removes the pin’s node from net->destinations(). Deleting/disconnecting an output/source pin should clear net->source() instead (and keep the net consistent), otherwise the net retains a stale source.

Suggested change
// Remove this node from the net's destinations
auto node = pin->node();
auto& dests = net->destinations();
dests.erase(std::remove_if(dests.begin(), dests.end(),
[&](auto& w) { return w.lock() == node; }), dests.end());
auto node = pin->node();
auto& dests = net->destinations();
auto& src = net->source();
// If this node is the net's source, clear the source; otherwise, remove it from destinations
if (src.lock() == node) {
src.reset();
} else {
dests.erase(std::remove_if(dests.begin(), dests.end(),
[&](auto& w) { return w.lock() == node; }), dests.end());
}

Copilot uses AI. Check for mistakes.
Comment thread src/attoflow/editor2.cpp

// ─── Wire rebuilding ───

void Editor2Pane::rebuild_wires(ImVec2 canvas_origin) {
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rebuild_wires() always clears and rebuilds cached_wires_ even though the class tracks wires_dirty_. Consider early-returning when !wires_dirty_ (and only setting dirty via observer callbacks / on_nodes_moved) to avoid rebuilding wires every frame.

Suggested change
void Editor2Pane::rebuild_wires(ImVec2 canvas_origin) {
void Editor2Pane::rebuild_wires(ImVec2 canvas_origin) {
if (!wires_dirty_)
return;

Copilot uses AI. Check for mistakes.
Comment thread src/atto/args.cpp
Comment on lines +303 to +306
paren_depth--;
if (paren_depth < 0)
return std::string("Mismatched ')' at position " + std::to_string(i));
current += c;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split_args builds error strings using std::string("...") around an expression that starts with a string literal plus std::to_string(...). This is invalid C++ (const char* + std::string) and will not compile. Build the message with std::string("...") + std::to_string(...) (and similarly for the "Unclosed" cases).

Copilot uses AI. Check for mistakes.
Comment thread src/atto/args.cpp
Comment on lines +311 to +314
brace_depth--;
if (brace_depth < 0)
return std::string("Mismatched '}' at position " + std::to_string(i));
current += c;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error return uses std::string("...") around a const char* + std::string expression, which is invalid C++. Build the message as std::string("...") + std::to_string(i) (or similar).

Copilot uses AI. Check for mistakes.
Comment thread src/atto/args.cpp
Comment on lines +331 to +334
if (paren_depth > 0)
return std::string("Unclosed '(' — " + std::to_string(paren_depth) + " level(s) deep");
if (brace_depth > 0)
return std::string("Unclosed '{' — " + std::to_string(brace_depth) + " level(s) deep");
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Unclosed error returns use the same invalid const char* + std::string concatenation pattern and won’t compile. Construct the string via std::string(...) + ... (or ostringstream).

Copilot uses AI. Check for mistakes.
Comment thread src/attoflow/editor2.cpp
Comment on lines +490 to +493
// Re-add to net's destinations
auto net = grab_undo_.old_entry ? grab_undo_.old_entry->as_net() : nullptr;
if (net) {
net->destinations().push_back(pin->node());
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do_reconnect_pin always pushes pin->node() into net->destinations(). If the pin being reconnected is an output/source pin, the correct restore action is to set net->source() back to the node, not add it as a destination.

Suggested change
// Re-add to net's destinations
auto net = grab_undo_.old_entry ? grab_undo_.old_entry->as_net() : nullptr;
if (net) {
net->destinations().push_back(pin->node());
// Re-add to net's destinations, but avoid adding the source node as a destination
auto net = grab_undo_.old_entry ? grab_undo_.old_entry->as_net() : nullptr;
if (net) {
auto node = pin->node();
if (node) {
auto src = net->source().lock();
if (!src || src != node) {
net->destinations().push_back(node);
}
}

Copilot uses AI. Check for mistakes.
Comment thread src/attoflow/editor2.cpp
Comment on lines +121 to +125
int source_pin = 0;

if (auto net = entry->as_net()) {
if (net->is_the_unconnected()) continue;
auto src_ptr = net->source().lock();
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source_pin is initialized to 0, but output index 0 is a valid value. Using if (source_pin == 0) as a “not found” check is ambiguous; initialize to -1 and check source_pin < 0 instead.

Copilot uses AI. Check for mistakes.
@skmp skmp merged commit 67f6b15 into main Mar 27, 2026
0 of 2 checks passed
@skmp skmp deleted the develop branch March 27, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants