@@ -116,33 +116,17 @@ void PedalBoard::render_signal_chain() {
116116 ui_state.target_zoom = 1 .0f ;
117117 }
118118 }
119- if (ui_state.show_grid ) {
120- float GRID_SZ = 32 .0f * ui_state.zoom ;
121- ImU32 GRID_COLOR = IM_COL32 (36 , 34 , 30 , 255 );
122- for (float x = std::fmod (ui_state.scrolling .x , GRID_SZ ); x < canvas_size.x ;
123- x += GRID_SZ ) {
124- draw_list->AddLine (ImVec2 (canvas_pos.x + x, canvas_pos.y ),
125- ImVec2 (canvas_pos.x + x, canvas_end.y ), GRID_COLOR );
126- }
127- for (float y = std::fmod (ui_state.scrolling .y , GRID_SZ ); y < canvas_size.y ;
128- y += GRID_SZ ) {
129- draw_list->AddLine (ImVec2 (canvas_pos.x , canvas_pos.y + y),
130- ImVec2 (canvas_end.x , canvas_pos.y + y), GRID_COLOR );
131- }
132- }
133- draw_list->PushClipRect (canvas_pos, canvas_end, true );
134- ImVec2 offset = ImVec2 (canvas_pos.x + ui_state.scrolling .x ,
135- canvas_pos.y + ui_state.scrolling .y );
136- std::unordered_map<int , ImVec2> pin_positions_cache;
137- int node_to_delete = -1 ; // Safely track deletions outside the render loop
138- // Prune stale nodes from the UI state if the backend graph was reset or
139- // rebuilt
140119 std::vector<int > stale_ids;
141- for (auto &pair : ui_state.node_positions ) {
142- if (!audio_graph.find_node (pair.first )) {
143- stale_ids.push_back (pair.first );
120+ for (auto it = ui_state.node_positions .begin (); it != ui_state.node_positions .end (); ) {
121+ bool found = false ;
122+ for (const auto &node : audio_graph.get_nodes ()) {
123+ if (node.id == it->first ) { found = true ; break ; }
144124 }
125+ if (!found) { stale_ids.push_back (it->first ); it = ui_state.node_positions .erase (it); }
126+ else ++it;
145127 }
128+ draw_list->PushClipRect (canvas_pos, canvas_end, true );
129+ ImVec2 offset (canvas_pos.x + ui_state.scrolling .x , canvas_pos.y + ui_state.scrolling .y );
146130 for (int id : stale_ids) {
147131 ui_state.node_positions .erase (id);
148132 }
@@ -178,6 +162,8 @@ void PedalBoard::render_signal_chain() {
178162 float level = engine_.get_output_level ();
179163 float time = (float )ImGui::GetTime ();
180164 bool is_running = engine_.is_running ();
165+ int node_to_delete = -1 ;
166+ std::unordered_map<int , ImVec2> pin_positions_cache;
181167 for (const auto &node : audio_graph.get_nodes ()) {
182168 auto &node_layout = ui_state.node_positions [node.id ];
183169 ImVec2 node_screen_pos =
@@ -260,14 +246,57 @@ void PedalBoard::render_signal_chain() {
260246 node_layout.is_dragging = true ;
261247 node_layout.drag_start_pos = node_layout.position ;
262248 }
263- node_layout.position .x += ImGui::GetIO ().MouseDelta .x / ui_state.zoom ;
264- node_layout.position .y += ImGui::GetIO ().MouseDelta .y / ui_state.zoom ;
265- } else if (node_layout.is_dragging && ImGui::IsItemDeactivated ()) {
266- node_layout.is_dragging = false ;
267- if (node_layout.position .x != node_layout.drag_start_pos .x ||
268- node_layout.position .y != node_layout.drag_start_pos .y ) {
269- history_.push_executed (std::make_unique<MoveGraphNodeCommand>(
270- node.id , node_layout.drag_start_pos , node_layout.position ));
249+ float node_width = (target_widget ? (is_mb_comp ? 190 .0f * 2 .2f : 190 .0f ) : 110 .0f ) * ui_state.zoom ;
250+ float node_height = (target_widget ? 360 .0f : 70 .0f ) * ui_state.zoom ;
251+ ImGui::PushID (node.id );
252+ if (target_widget) {
253+ ImGui::SetCursorScreenPos (node_screen_pos);
254+ ImGui::BeginGroup ();
255+ ImGui::SetWindowFontScale (ui_state.zoom );
256+ target_widget->render (ui_state.zoom );
257+ ImGui::SetWindowFontScale (1 .0f );
258+ ImGui::EndGroup ();
259+ ImGui::SetCursorScreenPos (node_screen_pos);
260+ ImGui::SetNextItemAllowOverlap ();
261+ ImGui::InvisibleButton (" native_drag_handle" , ImVec2 (node_width - 25 .0f * ui_state.zoom , 30 .0f * ui_state.zoom ));
262+ if (ImGui::IsItemActive () && ImGui::IsMouseDragging (ImGuiMouseButton_Left)) {
263+ if (!node_layout.is_dragging ) {
264+ node_layout.is_dragging = true ;
265+ node_layout.drag_start_pos = node_layout.position ;
266+ }
267+ node_layout.position .x += ImGui::GetIO ().MouseDelta .x / ui_state.zoom ;
268+ node_layout.position .y += ImGui::GetIO ().MouseDelta .y / ui_state.zoom ;
269+ } else if (node_layout.is_dragging && ImGui::IsItemDeactivated ()) {
270+ node_layout.is_dragging = false ;
271+ if (node_layout.position .x != node_layout.drag_start_pos .x || node_layout.position .y != node_layout.drag_start_pos .y ) {
272+ history_.push_executed (std::make_unique<MoveGraphNodeCommand>(node.id , node_layout.drag_start_pos , node_layout.position ));
273+ }
274+ }
275+ } else {
276+ ImVec2 node_end = ImVec2 (node_screen_pos.x + node_width, node_screen_pos.y + node_height);
277+ ImU32 bg_color = IM_COL32 (50 , 35 , 60 , 255 );
278+ draw_list->AddRectFilled (node_screen_pos, node_end, bg_color, Theme::ROUNDING_MD * ui_state.zoom );
279+ draw_list->AddRect (node_screen_pos, node_end, IM_COL32 (180 , 140 , 80 , 180 ), Theme::ROUNDING_MD * ui_state.zoom , 0 , 1 .5f * ui_state.zoom );
280+ ImGui::SetCursorScreenPos (node_screen_pos);
281+ ImGui::SetNextItemAllowOverlap ();
282+ ImGui::InvisibleButton (" util_drag_handle" , ImVec2 (node_width - 25 .0f * ui_state.zoom , node_height));
283+ if (ImGui::IsItemActive () && ImGui::IsMouseDragging (ImGuiMouseButton_Left)) {
284+ if (!node_layout.is_dragging ) {
285+ node_layout.is_dragging = true ;
286+ node_layout.drag_start_pos = node_layout.position ;
287+ }
288+ node_layout.position .x += ImGui::GetIO ().MouseDelta .x / ui_state.zoom ;
289+ node_layout.position .y += ImGui::GetIO ().MouseDelta .y / ui_state.zoom ;
290+ } else if (node_layout.is_dragging && ImGui::IsItemDeactivated ()) {
291+ node_layout.is_dragging = false ;
292+ if (node_layout.position .x != node_layout.drag_start_pos .x || node_layout.position .y != node_layout.drag_start_pos .y ) {
293+ history_.push_executed (std::make_unique<MoveGraphNodeCommand>(node.id , node_layout.drag_start_pos , node_layout.position ));
294+ }
295+ }
296+ ImVec2 text_pos = ImVec2 (node_screen_pos.x + 12 .0f * ui_state.zoom , node_screen_pos.y + 25 .0f * ui_state.zoom );
297+ ImGui::SetWindowFontScale (ui_state.zoom );
298+ draw_list->AddText (text_pos, IM_COL32 (255 , 255 , 255 , 255 ), node.name .c_str ());
299+ ImGui::SetWindowFontScale (1 .0f );
271300 }
272301 }
273302 ImVec2 text_pos = ImVec2 (node_screen_pos.x + 12 .0f * ui_state.zoom , node_screen_pos.y + 25 .0f * ui_state.zoom );
0 commit comments