1 #include "imp_schematic.hpp"
2 #include "canvas/canvas_gl.hpp"
3 #include "export_pdf/export_pdf.hpp"
4 #include "pool/part.hpp"
5 #include "rules/rules_window.hpp"
6 #include "widgets/sheet_box.hpp"
7 #include "util/gtk_util.hpp"
8 #include "util/util.hpp"
9 #include "util/str_util.hpp"
10 #include "util/selection_util.hpp"
11 #include "bom_export_window.hpp"
12 #include "pdf_export_window.hpp"
13 #include "nlohmann/json.hpp"
14 #include "core/tools/tool_backannotate_connection_lines.hpp"
15 #include "core/tools/tool_add_part.hpp"
16 #include "core/tools/tool_map_symbol.hpp"
17 #include "widgets/unplaced_box.hpp"
18 #include "core/tool_id.hpp"
19 #include "actions.hpp"
20 #include "widgets/action_button.hpp"
21 
22 namespace horizon {
ImpSchematic(const std::string & schematic_filename,const std::string & block_filename,const std::string & pictures_dir,const PoolParams & pool_params)23 ImpSchematic::ImpSchematic(const std::string &schematic_filename, const std::string &block_filename,
24                            const std::string &pictures_dir, const PoolParams &pool_params)
25     : ImpBase(pool_params), core_schematic(schematic_filename, block_filename, pictures_dir, *pool, *pool_caching),
26       project_dir(Glib::path_get_dirname(schematic_filename)), searcher(core_schematic)
27 {
28     core = &core_schematic;
29     core_schematic.signal_tool_changed().connect(sigc::mem_fun(*this, &ImpSchematic::handle_tool_change));
30     core_schematic.signal_rebuilt().connect(sigc::mem_fun(*this, &ImpSchematic::handle_core_rebuilt));
31 }
32 
canvas_update()33 void ImpSchematic::canvas_update()
34 {
35     canvas->update(core_schematic.get_canvas_data());
36     warnings_box->update(core_schematic.get_sheet()->warnings);
37     update_highlights();
38 }
39 
handle_select_sheet(Sheet * sh)40 void ImpSchematic::handle_select_sheet(Sheet *sh)
41 {
42     if (sh == core_schematic.get_sheet())
43         return;
44 
45     auto v = canvas->get_scale_and_offset();
46     sheet_views[core_schematic.get_sheet()->uuid] = v;
47     sheet_selections[core_schematic.get_sheet()->uuid] = canvas->get_selection();
48     auto highlights_saved = highlights;
49     core_schematic.set_sheet(sh->uuid);
50     canvas_update();
51     if (sheet_views.count(sh->uuid)) {
52         auto v2 = sheet_views.at(sh->uuid);
53         canvas->set_scale_and_offset(v2.first, v2.second);
54     }
55     if (sheet_selections.count(sh->uuid)) {
56         canvas->set_selection(sheet_selections.at(sh->uuid));
57     }
58     else {
59         canvas->set_selection({});
60     }
61     highlights = highlights_saved;
62     update_highlights();
63 }
64 
handle_remove_sheet(Sheet * sh)65 void ImpSchematic::handle_remove_sheet(Sheet *sh)
66 {
67     core_schematic.delete_sheet(sh->uuid);
68     canvas_update();
69 }
70 
handle_next_prev_sheet(const ActionConnection & conn)71 void ImpSchematic::handle_next_prev_sheet(const ActionConnection &conn)
72 {
73     const auto &sch = *core_schematic.get_schematic();
74     const int sheet_idx_current = core_schematic.get_sheet()->index;
75     const int inc = conn.action_id == ActionID::PREV_SHEET ? -1 : 1;
76     const int sheet_idx_next = sheet_idx_current + inc;
77     auto next_sheet = std::find_if(sch.sheets.begin(), sch.sheets.end(),
78                                    [sheet_idx_next](const auto &x) { return (int)x.second.index == sheet_idx_next; });
79     if (next_sheet != sch.sheets.end()) {
80         sheet_box->select_sheet(next_sheet->second.uuid);
81     }
82 }
83 
update_highlights()84 void ImpSchematic::update_highlights()
85 {
86     std::map<UUID, std::set<ObjectRef>> highlights_for_sheet;
87     auto sch = core_schematic.get_schematic();
88     for (const auto &it_sheet : sch->sheets) {
89         auto sheet = &it_sheet.second;
90         for (const auto &it : highlights) {
91             if (it.type == ObjectType::NET) {
92                 for (const auto &it_line : sheet->net_lines) {
93                     if (it_line.second.net.uuid == it.uuid) {
94                         highlights_for_sheet[sheet->uuid].emplace(ObjectType::LINE_NET, it_line.first);
95                     }
96                 }
97                 for (const auto &it_junc : sheet->junctions) {
98                     if (it_junc.second.net.uuid == it.uuid) {
99                         highlights_for_sheet[sheet->uuid].emplace(ObjectType::JUNCTION, it_junc.first);
100                     }
101                 }
102                 for (const auto &it_label : sheet->net_labels) {
103                     if (it_label.second.junction->net.uuid == it.uuid) {
104                         highlights_for_sheet[sheet->uuid].emplace(ObjectType::NET_LABEL, it_label.first);
105                     }
106                 }
107                 for (const auto &it_sym : sheet->power_symbols) {
108                     if (it_sym.second.junction->net.uuid == it.uuid) {
109                         highlights_for_sheet[sheet->uuid].emplace(ObjectType::POWER_SYMBOL, it_sym.first);
110                     }
111                 }
112                 for (const auto &it_sym : sheet->symbols) {
113                     auto component = it_sym.second.component;
114                     for (const auto &it_pin : it_sym.second.symbol.pins) {
115                         UUIDPath<2> connpath(it_sym.second.gate->uuid, it_pin.second.uuid);
116                         if (component->connections.count(connpath)) {
117                             auto net = component->connections.at(connpath).net;
118                             if (net.uuid == it.uuid) {
119                                 highlights_for_sheet[sheet->uuid].emplace(ObjectType::SYMBOL_PIN, it_pin.first,
120                                                                           it_sym.first);
121                             }
122                         }
123                     }
124                 }
125             }
126             else if (it.type == ObjectType::COMPONENT) {
127                 for (const auto &it_sym : sheet->symbols) {
128                     auto component = it_sym.second.component;
129                     if (component->uuid == it.uuid) {
130                         highlights_for_sheet[sheet->uuid].emplace(ObjectType::SCHEMATIC_SYMBOL, it_sym.first);
131                     }
132                 }
133             }
134             else if (it.type == ObjectType::SCHEMATIC_SYMBOL) {
135                 if (sheet->symbols.count(it.uuid))
136                     highlights_for_sheet[sheet->uuid].emplace(it);
137             }
138             else if (it.type == ObjectType::SYMBOL_PIN) {
139                 if (sheet->symbols.count(it.uuid2))
140                     highlights_for_sheet[sheet->uuid].emplace(it);
141             }
142         }
143         sheet_box->update_highlights(sheet->uuid, highlights_for_sheet[sheet->uuid].size());
144     }
145 
146     auto sheet = core_schematic.get_sheet();
147     canvas->set_flags_all(0, TriangleInfo::FLAG_HIGHLIGHT);
148     canvas->set_highlight_enabled(highlights_for_sheet[sheet->uuid].size());
149     for (const auto &it : highlights_for_sheet[sheet->uuid]) {
150         canvas->set_flags(it, TriangleInfo::FLAG_HIGHLIGHT, 0);
151     }
152 }
153 
handle_broadcast(const json & j)154 bool ImpSchematic::handle_broadcast(const json &j)
155 {
156     if (!ImpBase::handle_broadcast(j)) {
157         std::string op = j.at("op");
158         guint32 timestamp = j.value("time", 0);
159         if (op == "place-part") {
160             force_end_tool();
161             main_window->present(timestamp);
162             auto data = std::make_unique<ToolAddPart::ToolDataAddPart>(j.at("part").get<std::string>());
163             tool_begin(ToolID::ADD_PART, false, {}, std::move(data));
164         }
165         else if (op == "assign-part" && !core->tool_is_active()) {
166             main_window->present(timestamp);
167             auto data = std::make_unique<ToolAddPart::ToolDataAddPart>(j.at("part").get<std::string>());
168             tool_begin(ToolID::ASSIGN_PART, false, {}, std::move(data));
169         }
170         else if (op == "highlight" && cross_probing_enabled && !core->tool_is_active()) {
171             highlights.clear();
172             const json &o = j["objects"];
173             for (auto it = o.cbegin(); it != o.cend(); ++it) {
174                 auto type = static_cast<ObjectType>(it.value().at("type").get<int>());
175                 UUID uu(it.value().at("uuid").get<std::string>());
176                 highlights.emplace(type, uu);
177             }
178             update_highlights();
179         }
180         else if (op == "backannotate") {
181             auto data = std::make_unique<ToolBackannotateConnectionLines::ToolDataBackannotate>();
182             const json &o = j.at("connections");
183             for (auto it = o.cbegin(); it != o.cend(); ++it) {
184                 auto &v = it.value();
185                 std::pair<ToolBackannotateConnectionLines::ToolDataBackannotate::Item,
186                           ToolBackannotateConnectionLines::ToolDataBackannotate::Item>
187                         item;
188                 auto &block = *core_schematic.get_block();
189                 item.first.from_json(block, v.at("from"));
190                 item.second.from_json(block, v.at("to"));
191                 if (item.first.is_valid() && item.second.is_valid())
192                     data->connections.push_back(item);
193             }
194             if (data->connections.size()) {
195                 force_end_tool();
196                 main_window->present(timestamp);
197                 tool_begin(ToolID::BACKANNOTATE_CONNECTION_LINES, true, {}, std::move(data));
198             }
199         }
200         else if (op == "edit-meta") {
201             force_end_tool();
202             main_window->present(timestamp);
203             tool_begin(ToolID::EDIT_SCHEMATIC_PROPERTIES);
204         }
205     }
206     return true;
207 }
208 
handle_selection_cross_probe()209 void ImpSchematic::handle_selection_cross_probe()
210 {
211     json j;
212     j["op"] = "schematic-select";
213     j["selection"] = nullptr;
214     for (const auto &it : canvas->get_selection()) {
215         json k;
216         ObjectType type = ObjectType::INVALID;
217         UUID uu;
218         auto sheet = core_schematic.get_sheet();
219         switch (it.type) {
220         case ObjectType::LINE_NET: {
221             auto &li = sheet->net_lines.at(it.uuid);
222             if (li.net) {
223                 type = ObjectType::NET;
224                 uu = li.net->uuid;
225             }
226         } break;
227         case ObjectType::NET_LABEL: {
228             auto &la = sheet->net_labels.at(it.uuid);
229             if (la.junction->net) {
230                 type = ObjectType::NET;
231                 uu = la.junction->net->uuid;
232             }
233         } break;
234         case ObjectType::POWER_SYMBOL: {
235             auto &sym = sheet->power_symbols.at(it.uuid);
236             if (sym.junction->net) {
237                 type = ObjectType::NET;
238                 uu = sym.junction->net->uuid;
239             }
240         } break;
241         case ObjectType::JUNCTION: {
242             auto &ju = sheet->junctions.at(it.uuid);
243             if (ju.net) {
244                 type = ObjectType::NET;
245                 uu = ju.net->uuid;
246             }
247         } break;
248         case ObjectType::SCHEMATIC_SYMBOL: {
249             auto &sym = sheet->symbols.at(it.uuid);
250             type = ObjectType::COMPONENT;
251             uu = sym.component->uuid;
252         } break;
253         default:;
254         }
255 
256         if (type != ObjectType::INVALID) {
257             k["type"] = static_cast<int>(type);
258             k["uuid"] = (std::string)uu;
259             j["selection"].push_back(k);
260         }
261     }
262     send_json(j);
263 }
264 
get_board_pid()265 int ImpSchematic::get_board_pid()
266 {
267     json j;
268     j["op"] = "get-board-pid";
269     return this->send_json(j);
270 }
271 
construct()272 void ImpSchematic::construct()
273 {
274     state_store = std::make_unique<WindowStateStore>(main_window, "imp-schematic");
275 
276     sheet_box = Gtk::manage(new SheetBox(&core_schematic));
277     sheet_box->show_all();
278     sheet_box->signal_add_sheet().connect([this] {
279         core_schematic.add_sheet();
280         std::cout << "add sheet" << std::endl;
281     });
282     sheet_box->signal_remove_sheet().connect(sigc::mem_fun(*this, &ImpSchematic::handle_remove_sheet));
283     sheet_box->signal_select_sheet().connect(sigc::mem_fun(*this, &ImpSchematic::handle_select_sheet));
284     main_window->left_panel->pack_start(*sheet_box, false, false, 0);
285 
286     hamburger_menu->append("Annotate", "win.annotate");
287     add_tool_action(ToolID::ANNOTATE, "annotate");
288 
289     hamburger_menu->append("Buses…", "win.manage_buses");
290     add_tool_action(ToolID::MANAGE_BUSES, "manage_buses");
291 
292     hamburger_menu->append("Net classes…", "win.manage_nc");
293     add_tool_action(ToolID::MANAGE_NET_CLASSES, "manage_nc");
294 
295     hamburger_menu->append("Power Nets…", "win.manage_pn");
296     add_tool_action(ToolID::MANAGE_POWER_NETS, "manage_pn");
297 
298     hamburger_menu->append("Schematic properties", "win.sch_properties");
299     add_tool_action(ToolID::EDIT_SCHEMATIC_PROPERTIES, "sch_properties");
300 
301     hamburger_menu->append("BOM Export", "win.bom_export");
302     main_window->add_action("bom_export", [this] { trigger_action(ActionID::BOM_EXPORT_WINDOW); });
303 
304     hamburger_menu->append("PDF Export", "win.export_pdf");
305 
306     main_window->add_action("export_pdf", [this] { trigger_action(ActionID::PDF_EXPORT_WINDOW); });
307 
308     if (sockets_connected) {
309         hamburger_menu->append("Cross probing", "win.cross_probing");
310         auto cp_action = main_window->add_action_bool("cross_probing", true);
311         cross_probing_enabled = true;
312         cp_action->signal_change_state().connect([this, cp_action](const Glib::VariantBase &v) {
313             cross_probing_enabled = Glib::VariantBase::cast_dynamic<Glib::Variant<bool>>(v).get();
314             g_simple_action_set_state(cp_action->gobj(), g_variant_new_boolean(cross_probing_enabled));
315             if (!cross_probing_enabled && !core_schematic.tool_is_active()) {
316                 highlights.clear();
317                 update_highlights();
318             }
319         });
320     }
321 
322     canvas->set_highlight_mode(CanvasGL::HighlightMode::DIM);
323 
324     connect_action(ActionID::PLACE_PART, [this](const auto &conn) {
325         if (!sockets_connected) {
326             this->tool_begin(ToolID::ADD_PART);
327         }
328         else {
329             json j;
330             j["op"] = "show-browser";
331             j["time"] = gtk_get_current_event_time();
332             allow_set_foreground_window(mgr_pid);
333             this->send_json(j);
334         }
335     });
336 
337     connect_action(ActionID::PREV_SHEET, sigc::mem_fun(*this, &ImpSchematic::handle_next_prev_sheet));
338     connect_action(ActionID::NEXT_SHEET, sigc::mem_fun(*this, &ImpSchematic::handle_next_prev_sheet));
339 
340     if (sockets_connected) {
341         connect_action(ActionID::TO_BOARD, [this](const auto &conn) {
342             json j;
343             j["op"] = "to-board";
344             j["time"] = gtk_get_current_event_time();
345             j["selection"] = nullptr;
346             for (const auto &it : canvas->get_selection()) {
347                 auto sheet = core_schematic.get_sheet();
348                 if (it.type == ObjectType::SCHEMATIC_SYMBOL) {
349                     auto &sym = sheet->symbols.at(it.uuid);
350                     json k;
351                     k["type"] = static_cast<int>(ObjectType::COMPONENT);
352                     k["uuid"] = (std::string)sym.component->uuid;
353                     j["selection"].push_back(k);
354                 }
355             }
356             canvas->set_selection({});
357             allow_set_foreground_window(this->get_board_pid());
358             this->send_json(j);
359         });
360         set_action_sensitive(make_action(ActionID::TO_BOARD), false);
361 
362         connect_action(ActionID::SHOW_IN_BROWSER, [this](const auto &conn) {
363             for (const auto &it : canvas->get_selection()) {
364                 auto sheet = core_schematic.get_sheet();
365                 if (it.type == ObjectType::SCHEMATIC_SYMBOL) {
366                     auto &sym = sheet->symbols.at(it.uuid);
367                     if (sym.component->part) {
368                         auto ev = gtk_get_current_event();
369                         json j;
370                         j["op"] = "show-in-browser";
371                         j["part"] = (std::string)sym.component->part->uuid;
372                         j["time"] = gdk_event_get_time(ev);
373                         this->send_json(j);
374                         break;
375                     }
376                 }
377             }
378         });
379 
380         connect_action(ActionID::SAVE_RELOAD_NETLIST, [this](const auto &conn) {
381             this->trigger_action(ActionID::SAVE);
382             json j;
383             j["time"] = gtk_get_current_event_time();
384             j["op"] = "reload-netlist";
385             this->send_json(j);
386         });
387         set_action_sensitive(make_action(ActionID::SAVE_RELOAD_NETLIST), false);
388 
389         connect_action(ActionID::GO_TO_BOARD, [this](const auto &conn) {
390             json j;
391             j["time"] = gtk_get_current_event_time();
392             j["op"] = "present-board";
393             auto board_pid = this->get_board_pid();
394             if (board_pid != -1)
395                 allow_set_foreground_window(board_pid);
396             this->send_json(j);
397         });
398 
399         connect_action(ActionID::SHOW_IN_POOL_MANAGER, [this](const auto &conn) {
400             for (const auto &it : canvas->get_selection()) {
401                 auto sheet = core_schematic.get_sheet();
402                 if (it.type == ObjectType::SCHEMATIC_SYMBOL) {
403                     auto &sym = sheet->symbols.at(it.uuid);
404                     if (sym.component->part) {
405                         json j;
406                         j["op"] = "show-in-pool-mgr";
407                         j["type"] = "part";
408                         UUID pool_uuid;
409                         pool->get_filename(ObjectType::PART, sym.component->part->uuid, &pool_uuid);
410                         j["pool_uuid"] = (std::string)pool_uuid;
411                         j["uuid"] = (std::string)sym.component->part->uuid;
412                         this->send_json(j);
413                         break;
414                     }
415                 }
416             }
417         });
418         set_action_sensitive(make_action(ActionID::SHOW_IN_POOL_MANAGER), false);
419     }
420 
421     connect_action(ActionID::MOVE_TO_OTHER_SHEET,
422                    std::bind(&ImpSchematic::handle_move_to_other_sheet, this, std::placeholders::_1));
423 
424     connect_action(ActionID::HIGHLIGHT_NET, [this](const auto &a) {
425         highlights.clear();
426         for (const auto &it : canvas->get_selection()) {
427             if (auto uu = net_from_selectable(it)) {
428                 highlights.emplace(ObjectType::NET, uu);
429             }
430         }
431         this->update_highlights();
432     });
433 
434     connect_action(ActionID::HIGHLIGHT_NET_CLASS, [this](const auto &a) {
435         highlights.clear();
436         for (const auto &it : canvas->get_selection()) {
437             if (auto uu = net_from_selectable(it)) {
438                 const auto &net_sel = core_schematic.get_block()->nets.at(uu);
439                 for (const auto &[net_uu, net] : core_schematic.get_block()->nets) {
440                     if (net.net_class == net_sel.net_class)
441                         highlights.emplace(ObjectType::NET, net_uu);
442                 }
443             }
444         }
445         this->update_highlights();
446     });
447 
448     connect_action(ActionID::HIGHLIGHT_GROUP, sigc::mem_fun(*this, &ImpSchematic::handle_highlight_group_tag));
449     connect_action(ActionID::HIGHLIGHT_TAG, sigc::mem_fun(*this, &ImpSchematic::handle_highlight_group_tag));
450 
451     bom_export_window = BOMExportWindow::create(main_window, *core_schematic.get_block(),
452                                                 *core_schematic.get_bom_export_settings(), *pool.get(), project_dir);
453 
454     connect_action(ActionID::BOM_EXPORT_WINDOW, [this](const auto &c) { bom_export_window->present(); });
455     connect_action(ActionID::EXPORT_BOM, [this](const auto &c) {
456         bom_export_window->present();
457         bom_export_window->generate();
458     });
459 
460     bom_export_window->signal_changed().connect([this] { core_schematic.set_needs_save(); });
461     core->signal_tool_changed().connect([this](ToolID t) { bom_export_window->set_can_export(t == ToolID::NONE); });
462     core->signal_rebuilt().connect([this] { bom_export_window->update(); });
463 
464     pdf_export_window = PDFExportWindow::create(main_window, core_schematic, *core_schematic.get_pdf_export_settings(),
465                                                 project_dir);
466     pdf_export_window->signal_changed().connect([this] { core_schematic.set_needs_save(); });
467     connect_action(ActionID::PDF_EXPORT_WINDOW, [this](const auto &c) { pdf_export_window->present(); });
468     connect_action(ActionID::EXPORT_PDF, [this](const auto &c) {
469         pdf_export_window->present();
470         pdf_export_window->generate();
471     });
472 
473     unplaced_box = Gtk::manage(new UnplacedBox("Symbol"));
474     unplaced_box->show();
475     main_window->left_panel->pack_end(*unplaced_box, true, true, 0);
476     unplaced_box->signal_place().connect([this](const auto &items) {
477         auto d = std::make_unique<ToolMapSymbol::ToolDataMapSymbol>(items);
478         this->tool_begin(ToolID::MAP_SYMBOL, false, {}, std::move(d));
479     });
480     core_schematic.signal_rebuilt().connect(sigc::mem_fun(*this, &ImpSchematic::update_unplaced));
481     update_unplaced();
482     core_schematic.signal_tool_changed().connect(
483             [this](ToolID tool_id) { unplaced_box->set_sensitive(tool_id == ToolID::NONE); });
484 
485     grid_controller->disable();
486     canvas->snap_to_targets = false;
487 
488     connect_action(ActionID::TOGGLE_SNAP_TO_TARGETS, [this](const ActionConnection &c) {
489         canvas->snap_to_targets = !canvas->snap_to_targets;
490         g_simple_action_set_state(toggle_snap_to_targets_action->gobj(),
491                                   g_variant_new_boolean(canvas->snap_to_targets));
492     });
493     view_options_menu_append_action("Snap to targets", "win.snap_to_targets");
494 
495     toggle_snap_to_targets_action = main_window->add_action_bool("snap_to_targets", canvas->snap_to_targets);
496     toggle_snap_to_targets_action->signal_change_state().connect([this](const Glib::VariantBase &v) {
497         auto b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool>>(v).get();
498         if (b != canvas->snap_to_targets) {
499             trigger_action(ActionID::TOGGLE_SNAP_TO_TARGETS);
500         }
501     });
502 
503 
504     rules_window->signal_goto().connect([this](Coordi location, UUID sheet) {
505         auto sch = core_schematic.get_schematic();
506         if (sch->sheets.count(sheet)) {
507             sheet_box->select_sheet(sheet);
508             canvas->center_and_zoom(location);
509         }
510     });
511 
512     canvas->signal_motion_notify_event().connect([this](GdkEventMotion *ev) {
513         if (target_drag_begin.type != ObjectType::INVALID) {
514             handle_drag();
515         }
516         return false;
517     });
518 
519     canvas->signal_button_release_event().connect([this](GdkEventButton *ev) {
520         target_drag_begin = Target();
521         return false;
522     });
523 
524     main_window->signal_activate_hud_link().connect(
525             [this](const std::string &url) {
526                 if (url.find("s:") == 0) {
527                     std::string sheet = url.substr(2);
528                     auto uuid = UUID(sheet);
529                     auto sch = core_schematic.get_schematic();
530                     if (sch->sheets.count(uuid)) {
531                         sheet_box->select_sheet(uuid);
532                     }
533                     return true;
534                 }
535                 return false;
536             },
537             false);
538 
539     add_action_button(make_action(ActionID::PLACE_PART));
540     add_action_button(make_action(ToolID::DRAW_NET));
541     {
542         auto &b = add_action_button(make_action(ToolID::PLACE_NET_LABEL));
543         b.add_action(make_action(ToolID::PLACE_BUS_LABEL));
544         b.add_action(make_action(ToolID::PLACE_BUS_RIPPER));
545     }
546     add_action_button(make_action(ToolID::PLACE_POWER_SYMBOL));
547     add_action_button_line();
548     add_action_button(make_action(ToolID::PLACE_TEXT));
549 
550     update_monitor();
551 
552     if (!core_schematic.get_project_meta_loaded_from_block())
553         core_schematic.set_needs_save();
554 }
555 
update_action_sensitivity()556 void ImpSchematic::update_action_sensitivity()
557 {
558     auto sel = canvas->get_selection();
559     if (sockets_connected) {
560         json req;
561         req["op"] = "has-board";
562         bool has_board = send_json(req);
563         set_action_sensitive(make_action(ActionID::SAVE_RELOAD_NETLIST), has_board);
564         auto n_sym = std::count_if(sel.begin(), sel.end(),
565                                    [](const auto &x) { return x.type == ObjectType::SCHEMATIC_SYMBOL; });
566         set_action_sensitive(make_action(ActionID::SHOW_IN_BROWSER), n_sym == 1);
567         set_action_sensitive(make_action(ActionID::SHOW_IN_POOL_MANAGER), n_sym == 1);
568         if (!has_board) {
569             set_action_sensitive(make_action(ActionID::TO_BOARD), false);
570         }
571         else {
572             set_action_sensitive(make_action(ActionID::TO_BOARD), n_sym);
573         }
574     }
575     else {
576         set_action_sensitive(make_action(ActionID::TO_BOARD), false);
577         set_action_sensitive(make_action(ActionID::SHOW_IN_BROWSER), false);
578         set_action_sensitive(make_action(ActionID::SHOW_IN_POOL_MANAGER), false);
579     }
580     set_action_sensitive(make_action(ActionID::MOVE_TO_OTHER_SHEET), sel.size() > 0);
581     set_action_sensitive(make_action(ActionID::GO_TO_BOARD), sockets_connected);
582 
583     const bool can_highlight_net = std::any_of(sel.begin(), sel.end(), [](const auto &x) {
584         switch (x.type) {
585         case ObjectType::LINE_NET:
586         case ObjectType::NET_LABEL:
587         case ObjectType::JUNCTION:
588         case ObjectType::POWER_SYMBOL:
589             return true;
590 
591         default:
592             return false;
593         }
594     });
595     set_action_sensitive(make_action(ActionID::HIGHLIGHT_NET), can_highlight_net);
596     set_action_sensitive(make_action(ActionID::HIGHLIGHT_NET_CLASS), can_highlight_net);
597     bool can_higlight_group = false;
598     bool can_higlight_tag = false;
599     if (sel.size() == 1 && (*sel.begin()).type == ObjectType::SCHEMATIC_SYMBOL) {
600         auto uu = (*sel.begin()).uuid;
601         if (core_schematic.get_sheet()->symbols.count(uu)) {
602             auto comp = core_schematic.get_schematic_symbol(uu)->component;
603             can_higlight_group = comp->group;
604             can_higlight_tag = comp->tag;
605         }
606     }
607 
608     set_action_sensitive(make_action(ActionID::HIGHLIGHT_GROUP), can_higlight_group);
609     set_action_sensitive(make_action(ActionID::HIGHLIGHT_TAG), can_higlight_tag);
610 
611     ImpBase::update_action_sensitivity();
612 }
613 
net_from_selectable(const SelectableRef & sr)614 UUID ImpSchematic::net_from_selectable(const SelectableRef &sr)
615 {
616     const auto &sheet = *core_schematic.get_sheet();
617     switch (sr.type) {
618     case ObjectType::LINE_NET: {
619         auto &li = sheet.net_lines.at(sr.uuid);
620         if (li.net) {
621             return li.net->uuid;
622         }
623     } break;
624     case ObjectType::NET_LABEL: {
625         auto &la = sheet.net_labels.at(sr.uuid);
626         if (la.junction->net) {
627             return la.junction->net->uuid;
628         }
629     } break;
630     case ObjectType::POWER_SYMBOL: {
631         auto &sym = sheet.power_symbols.at(sr.uuid);
632         if (sym.junction->net) {
633             return sym.junction->net->uuid;
634         }
635     } break;
636     case ObjectType::JUNCTION: {
637         auto &ju = sheet.junctions.at(sr.uuid);
638         if (ju.net) {
639             return ju.net->uuid;
640         }
641     } break;
642     default:;
643     }
644     return UUID();
645 }
646 
get_hud_text(std::set<SelectableRef> & sel)647 std::string ImpSchematic::get_hud_text(std::set<SelectableRef> &sel)
648 {
649     std::string s;
650     if (auto it = sel_find_exactly_one(sel, ObjectType::SCHEMATIC_SYMBOL)) {
651         const auto &sym = core_schematic.get_sheet()->symbols.at(it->uuid);
652         s += "<b>Symbol " + sym.component->refdes + "</b>\n";
653         s += get_hud_text_for_component(sym.component);
654         sel_erase_type(sel, ObjectType::SCHEMATIC_SYMBOL);
655     }
656 
657     if (auto it = sel_find_exactly_one(sel, ObjectType::TEXT)) {
658         const auto text = core->get_text(it->uuid);
659         const auto txt = Glib::ustring(text->text);
660         Glib::MatchInfo ma;
661         if (core_schematic.get_schematic()->get_sheetref_regex()->match(txt, ma)) {
662             s += "\n\n<b>Text with sheet references</b>\n";
663             do {
664                 auto uuid = ma.fetch(1);
665                 std::string url = "s:" + uuid;
666                 if (core_schematic.get_schematic()->sheets.count(UUID(uuid))) {
667                     s += make_link_markup(url, core_schematic.get_schematic()->sheets.at(UUID(uuid)).name);
668                 }
669                 else {
670                     s += "Unknown Sheet";
671                 }
672                 s += "\n";
673             } while (ma.next());
674             sel_erase_type(sel, ObjectType::TEXT);
675         }
676     }
677     trim(s);
678     return s;
679 }
680 
handle_core_rebuilt()681 void ImpSchematic::handle_core_rebuilt()
682 {
683     sheet_box->update();
684 }
685 
handle_tool_change(ToolID id)686 void ImpSchematic::handle_tool_change(ToolID id)
687 {
688     ImpBase::handle_tool_change(id);
689     sheet_box->set_sensitive(id == ToolID::NONE);
690 }
691 
handle_highlight_group_tag(const ActionConnection & a)692 void ImpSchematic::handle_highlight_group_tag(const ActionConnection &a)
693 {
694     bool tag_mode = a.action_id == ActionID::HIGHLIGHT_TAG;
695     auto sel = canvas->get_selection();
696     if (sel.size() == 1 && (*sel.begin()).type == ObjectType::SCHEMATIC_SYMBOL) {
697         auto comp = core_schematic.get_schematic_symbol((*sel.begin()).uuid)->component;
698         UUID uu = tag_mode ? comp->tag : comp->group;
699         if (!uu)
700             return;
701         highlights.clear();
702         for (const auto &it_sheet : core_schematic.get_schematic()->sheets) {
703             for (const auto &it_sym : it_sheet.second.symbols) {
704                 if ((tag_mode && (it_sym.second.component->tag == uu))
705                     || (!tag_mode && (it_sym.second.component->group == uu))) {
706                     highlights.emplace(ObjectType::COMPONENT, it_sym.second.component->uuid);
707                 }
708             }
709         }
710         this->update_highlights();
711     }
712 }
713 
handle_maybe_drag(bool ctrl)714 void ImpSchematic::handle_maybe_drag(bool ctrl)
715 {
716     if (!preferences.schematic.drag_start_net_line) {
717         ImpBase::handle_maybe_drag(ctrl);
718         return;
719     }
720 
721     auto target = canvas->get_current_target();
722     if (target.type == ObjectType::SYMBOL_PIN || target.type == ObjectType::JUNCTION) {
723         std::cout << "click pin" << std::endl;
724         canvas->inhibit_drag_selection();
725         target_drag_begin = target;
726         cursor_pos_drag_begin = canvas->get_cursor_pos_win();
727     }
728     else {
729         ImpBase::handle_maybe_drag(ctrl);
730     }
731 }
732 
drag_does_start(const Coordf & delta,Orientation orientation)733 static bool drag_does_start(const Coordf &delta, Orientation orientation)
734 {
735     float thr = 50;
736     switch (orientation) {
737     case Orientation::DOWN:
738         return delta.y > thr;
739 
740     case Orientation::UP:
741         return -delta.y > thr;
742 
743     case Orientation::RIGHT:
744         return delta.x > thr;
745 
746     case Orientation::LEFT:
747         return -delta.x > thr;
748 
749     default:
750         return false;
751     }
752 }
753 
handle_drag()754 void ImpSchematic::handle_drag()
755 {
756     auto pos = canvas->get_cursor_pos_win();
757     auto delta = pos - cursor_pos_drag_begin;
758     bool start = false;
759 
760     if (target_drag_begin.type == ObjectType::SYMBOL_PIN) {
761         const auto sym = core_schematic.get_schematic_symbol(target_drag_begin.path.at(0));
762         const auto &pin = sym->symbol.pins.at(target_drag_begin.path.at(1));
763         auto orientation = pin.get_orientation_for_placement(sym->placement);
764         start = drag_does_start(delta, orientation);
765     }
766     else if (target_drag_begin.type == ObjectType::JUNCTION) {
767         start = delta.mag_sq() > (50 * 50);
768     }
769 
770     if (start) {
771         {
772             highlights.clear();
773             update_highlights();
774             ToolArgs args;
775             args.coords = target_drag_begin.p;
776             ToolResponse r = core->tool_begin(ToolID::DRAW_NET, args, imp_interface.get());
777             tool_process(r);
778         }
779         {
780             ToolArgs args;
781             args.type = ToolEventType::ACTION;
782             args.coords = target_drag_begin.p;
783             args.action = InToolActionID::LMB;
784             args.target = target_drag_begin;
785             args.work_layer = canvas->property_work_layer();
786             ToolResponse r = core->tool_update(args);
787             tool_process(r);
788         }
789         target_drag_begin = Target();
790     }
791 }
792 
search_center(const Searcher::SearchResult & res)793 void ImpSchematic::search_center(const Searcher::SearchResult &res)
794 {
795     if (res.sheet != core_schematic.get_sheet()->uuid) {
796         sheet_box->select_sheet(res.sheet);
797     }
798     ImpBase::search_center(res);
799 }
800 
801 class SelectSheetDialog : public Gtk::Dialog {
802 public:
803     SelectSheetDialog(const Schematic *sch, const Sheet *skip);
804     UUID selected_sheet;
805 
806 private:
807     const Schematic *sch;
808 };
809 
810 class MyLabel : public Gtk::Label {
811 public:
MyLabel(const std::string & txt,const UUID & uu)812     MyLabel(const std::string &txt, const UUID &uu) : Gtk::Label(txt), uuid(uu)
813     {
814         set_xalign(0);
815         property_margin() = 5;
816     }
817 
818     const UUID uuid;
819 };
820 
SelectSheetDialog(const Schematic * s,const Sheet * skip)821 SelectSheetDialog::SelectSheetDialog(const Schematic *s, const Sheet *skip)
822     : Gtk::Dialog("Select sheet", Gtk::DIALOG_MODAL | Gtk::DIALOG_USE_HEADER_BAR), sch(s)
823 {
824     auto sc = Gtk::manage(new Gtk::ScrolledWindow);
825     sc->set_propagate_natural_height(true);
826     sc->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
827 
828     auto lb = Gtk::manage(new Gtk::ListBox);
829     lb->set_selection_mode(Gtk::SELECTION_NONE);
830     lb->set_activate_on_single_click(true);
831     lb->set_header_func(sigc::ptr_fun(header_func_separator));
832     sc->add(*lb);
833 
834     std::vector<const Sheet *> sheets;
835     for (const auto &it : sch->sheets) {
836         sheets.push_back(&it.second);
837     }
838     std::sort(sheets.begin(), sheets.end(), [](auto a, auto b) { return a->index < b->index; });
839 
840     for (const auto it : sheets) {
841         if (it != skip) {
842             auto la = Gtk::manage(new MyLabel(std::to_string(it->index) + " " + it->name, it->uuid));
843             lb->append(*la);
844         }
845     }
846     lb->signal_row_activated().connect([this](Gtk::ListBoxRow *row) {
847         auto la = dynamic_cast<MyLabel *>(row->get_child());
848         selected_sheet = la->uuid;
849         response(Gtk::RESPONSE_OK);
850     });
851 
852     sc->show_all();
853     get_content_area()->set_border_width(0);
854     get_content_area()->pack_start(*sc, true, true, 0);
855 }
856 
handle_move_to_other_sheet(const ActionConnection & conn)857 void ImpSchematic::handle_move_to_other_sheet(const ActionConnection &conn)
858 {
859     bool added = true;
860     auto selection = canvas->get_selection();
861     // try to find everything that's connected to the selection in some way
862     while (added) {
863         std::set<SelectableRef> new_sel;
864         for (const auto &it : selection) {
865             switch (it.type) {
866             case ObjectType::NET_LABEL: {
867                 auto &la = core_schematic.get_sheet()->net_labels.at(it.uuid);
868                 new_sel.emplace(la.junction->uuid, ObjectType::JUNCTION);
869             } break;
870             case ObjectType::BUS_LABEL: {
871                 auto &la = core_schematic.get_sheet()->bus_labels.at(it.uuid);
872                 new_sel.emplace(la.junction->uuid, ObjectType::JUNCTION);
873             } break;
874             case ObjectType::POWER_SYMBOL: {
875                 auto &ps = core_schematic.get_sheet()->power_symbols.at(it.uuid);
876                 new_sel.emplace(ps.junction->uuid, ObjectType::JUNCTION);
877             } break;
878             case ObjectType::BUS_RIPPER: {
879                 auto &rip = core_schematic.get_sheet()->bus_rippers.at(it.uuid);
880                 new_sel.emplace(rip.junction->uuid, ObjectType::JUNCTION);
881             } break;
882 
883             case ObjectType::LINE_NET: {
884                 auto line = &core_schematic.get_sheet()->net_lines.at(it.uuid);
885                 for (auto &it_ft : {line->from, line->to}) {
886                     if (it_ft.is_junc()) {
887                         new_sel.emplace(it_ft.junc->uuid, ObjectType::JUNCTION);
888                     }
889                     else if (it_ft.is_bus_ripper()) {
890                         new_sel.emplace(it_ft.bus_ripper->uuid, ObjectType::BUS_RIPPER);
891                     }
892                     else if (it_ft.is_pin()) {
893                         new_sel.emplace(it_ft.symbol->uuid, ObjectType::SCHEMATIC_SYMBOL);
894                     }
895                 }
896             } break;
897 
898             case ObjectType::LINE: {
899                 auto line = &core_schematic.get_sheet()->lines.at(it.uuid);
900                 for (auto &it_ft : {line->from, line->to}) {
901                     new_sel.emplace(it_ft->uuid, ObjectType::JUNCTION);
902                 }
903             } break;
904 
905             case ObjectType::ARC: {
906                 auto arc = &core_schematic.get_sheet()->arcs.at(it.uuid);
907                 for (auto &it_ft : {arc->from, arc->to, arc->center}) {
908                     new_sel.emplace(it_ft->uuid, ObjectType::JUNCTION);
909                 }
910             } break;
911 
912             case ObjectType::SCHEMATIC_SYMBOL: {
913                 auto sym = core_schematic.get_schematic_symbol(it.uuid);
914                 for (const auto &itt : sym->texts) {
915                     new_sel.emplace(itt->uuid, ObjectType::TEXT);
916                 }
917             } break;
918 
919             default:;
920             }
921         }
922 
923         // other direction
924         for (const auto &it : core_schematic.get_sheet()->net_labels) {
925             if (selection.count(SelectableRef(it.second.junction->uuid, ObjectType::JUNCTION))) {
926                 new_sel.emplace(it.first, ObjectType::NET_LABEL);
927             }
928         }
929         for (const auto &it : core_schematic.get_sheet()->bus_labels) {
930             if (selection.count(SelectableRef(it.second.junction->uuid, ObjectType::JUNCTION))) {
931                 new_sel.emplace(it.first, ObjectType::BUS_LABEL);
932             }
933         }
934         for (const auto &it : core_schematic.get_sheet()->bus_rippers) {
935             if (selection.count(SelectableRef(it.second.junction->uuid, ObjectType::JUNCTION))) {
936                 new_sel.emplace(it.first, ObjectType::BUS_RIPPER);
937             }
938         }
939         for (const auto &it : core_schematic.get_sheet()->power_symbols) {
940             if (selection.count(SelectableRef(it.second.junction->uuid, ObjectType::JUNCTION))) {
941                 new_sel.emplace(it.first, ObjectType::POWER_SYMBOL);
942             }
943         }
944         for (const auto &it : core_schematic.get_sheet()->net_lines) {
945             const auto line = it.second;
946             bool add_line = false;
947             for (auto &it_ft : {line.from, line.to}) {
948                 if (it_ft.is_junc()) {
949                     if (selection.count(SelectableRef(it_ft.junc->uuid, ObjectType::JUNCTION))) {
950                         add_line = true;
951                     }
952                 }
953                 else if (it_ft.is_bus_ripper()) {
954                     if (selection.count(SelectableRef(it_ft.bus_ripper->uuid, ObjectType::BUS_RIPPER))) {
955                         add_line = true;
956                     }
957                 }
958                 else if (it_ft.is_pin()) {
959                     if (selection.count(SelectableRef(it_ft.symbol->uuid, ObjectType::SCHEMATIC_SYMBOL))) {
960                         add_line = true;
961                     }
962                 }
963             }
964             if (add_line) {
965                 new_sel.emplace(it.first, ObjectType::LINE_NET);
966             }
967         }
968         for (const auto &it : core_schematic.get_sheet()->lines) {
969             for (const auto &it_ft : {it.second.from, it.second.to}) {
970                 if (selection.count(SelectableRef(it_ft->uuid, ObjectType::JUNCTION))) {
971                     new_sel.emplace(it.first, ObjectType::LINE);
972                 }
973             }
974         }
975         for (const auto &it : core_schematic.get_sheet()->arcs) {
976             for (const auto &it_ft : {it.second.from, it.second.to, it.second.center}) {
977                 if (selection.count(SelectableRef(it_ft->uuid, ObjectType::JUNCTION))) {
978                     new_sel.emplace(it.first, ObjectType::ARC);
979                 }
980             }
981         }
982 
983         added = false;
984         for (const auto &it : new_sel) {
985             if (selection.insert(it).second) {
986                 added = true;
987             }
988         }
989     }
990     canvas->set_selection(selection);
991 
992     auto old_sheet = core_schematic.get_sheet();
993     Sheet *new_sheet = nullptr;
994     {
995         SelectSheetDialog dia(core_schematic.get_schematic(), old_sheet);
996         dia.set_transient_for(*main_window);
997         if (dia.run() == Gtk::RESPONSE_OK) {
998             new_sheet = &core_schematic.get_schematic()->sheets.at(dia.selected_sheet);
999         }
1000     }
1001     if (!new_sheet)
1002         return;
1003     sheet_box->select_sheet(new_sheet->uuid);
1004     assert(core_schematic.get_sheet() == new_sheet);
1005 
1006     // actually move things to new sheet
1007     for (const auto &it : selection) {
1008         switch (it.type) {
1009         case ObjectType::NET_LABEL: {
1010             new_sheet->net_labels.insert(std::make_pair(it.uuid, std::move(old_sheet->net_labels.at(it.uuid))));
1011             old_sheet->net_labels.erase(it.uuid);
1012         } break;
1013         case ObjectType::BUS_LABEL: {
1014             new_sheet->bus_labels.insert(std::make_pair(it.uuid, std::move(old_sheet->bus_labels.at(it.uuid))));
1015             old_sheet->bus_labels.erase(it.uuid);
1016         } break;
1017         case ObjectType::BUS_RIPPER: {
1018             new_sheet->bus_rippers.insert(std::make_pair(it.uuid, std::move(old_sheet->bus_rippers.at(it.uuid))));
1019             old_sheet->bus_rippers.erase(it.uuid);
1020         } break;
1021         case ObjectType::JUNCTION: {
1022             new_sheet->junctions.insert(std::make_pair(it.uuid, std::move(old_sheet->junctions.at(it.uuid))));
1023             old_sheet->junctions.erase(it.uuid);
1024         } break;
1025         case ObjectType::POWER_SYMBOL: {
1026             new_sheet->power_symbols.insert(std::make_pair(it.uuid, std::move(old_sheet->power_symbols.at(it.uuid))));
1027             old_sheet->power_symbols.erase(it.uuid);
1028         } break;
1029         case ObjectType::LINE_NET: {
1030             new_sheet->net_lines.insert(std::make_pair(it.uuid, std::move(old_sheet->net_lines.at(it.uuid))));
1031             old_sheet->net_lines.erase(it.uuid);
1032         } break;
1033         case ObjectType::SCHEMATIC_SYMBOL: {
1034             new_sheet->symbols.insert(std::make_pair(it.uuid, std::move(old_sheet->symbols.at(it.uuid))));
1035             old_sheet->symbols.erase(it.uuid);
1036         } break;
1037         case ObjectType::TEXT: {
1038             new_sheet->texts.insert(std::make_pair(it.uuid, std::move(old_sheet->texts.at(it.uuid))));
1039             old_sheet->texts.erase(it.uuid);
1040         } break;
1041         case ObjectType::LINE: {
1042             new_sheet->lines.insert(std::make_pair(it.uuid, std::move(old_sheet->lines.at(it.uuid))));
1043             old_sheet->lines.erase(it.uuid);
1044         } break;
1045         case ObjectType::ARC: {
1046             new_sheet->arcs.insert(std::make_pair(it.uuid, std::move(old_sheet->arcs.at(it.uuid))));
1047             old_sheet->arcs.erase(it.uuid);
1048         } break;
1049 
1050         default:;
1051         }
1052     }
1053     core_schematic.get_schematic()->update_refs();
1054 
1055     core_schematic.set_needs_save();
1056     core_schematic.rebuild();
1057     canvas_update();
1058     canvas->set_selection(selection);
1059     tool_begin(ToolID::MOVE);
1060 }
1061 
get_doubleclick_action(ObjectType type,const UUID & uu)1062 ActionToolID ImpSchematic::get_doubleclick_action(ObjectType type, const UUID &uu)
1063 {
1064     auto a = ImpBase::get_doubleclick_action(type, uu);
1065     if (a.first != ActionID::NONE)
1066         return a;
1067     switch (type) {
1068     case ObjectType::NET_LABEL:
1069     case ObjectType::LINE_NET:
1070         return make_action(ToolID::ENTER_DATUM);
1071         break;
1072     default:
1073         return {ActionID::NONE, ToolID::NONE};
1074     }
1075 }
1076 
update_unplaced()1077 void ImpSchematic::update_unplaced()
1078 {
1079     unplaced_box->update(core_schematic.get_schematic()->get_unplaced_gates());
1080 }
1081 
get_tool_for_drag_move(bool ctrl,const std::set<SelectableRef> & sel) const1082 ToolID ImpSchematic::get_tool_for_drag_move(bool ctrl, const std::set<SelectableRef> &sel) const
1083 {
1084     if (preferences.schematic.bend_non_ortho && sel.size() == 1 && sel.begin()->type == ObjectType::LINE_NET) {
1085         const auto &ln = core_schematic.get_sheet()->net_lines.at(sel.begin()->uuid);
1086         auto from = ln.from.get_position();
1087         auto to = ln.to.get_position();
1088         if (!((from.x == to.x) || (from.y == to.y))) {
1089             return ToolID::BEND_LINE_NET;
1090         }
1091     }
1092     return ImpBase::get_tool_for_drag_move(ctrl, sel);
1093 }
1094 
handle_extra_button(const GdkEventButton * button_event)1095 void ImpSchematic::handle_extra_button(const GdkEventButton *button_event)
1096 {
1097     if (!preferences.mouse.switch_sheets)
1098         return;
1099 
1100     switch (button_event->button) {
1101     case 6:
1102     case 8:
1103         trigger_action(ActionID::NEXT_SHEET);
1104         break;
1105 
1106     case 7:
1107     case 9:
1108         trigger_action(ActionID::PREV_SHEET);
1109         break;
1110 
1111     default:;
1112     }
1113 }
1114 
expand_selection_for_property_panel(std::set<SelectableRef> & sel_extra,const std::set<SelectableRef> & sel)1115 void ImpSchematic::expand_selection_for_property_panel(std::set<SelectableRef> &sel_extra,
1116                                                        const std::set<SelectableRef> &sel)
1117 {
1118     const auto &sheet = *core_schematic.get_sheet();
1119     for (const auto &it : sel) {
1120         switch (it.type) {
1121         case ObjectType::SCHEMATIC_SYMBOL:
1122             sel_extra.emplace(core_schematic.get_schematic_symbol(it.uuid)->component->uuid, ObjectType::COMPONENT);
1123             break;
1124         case ObjectType::JUNCTION:
1125             if (sheet.junctions.at(it.uuid).net) {
1126                 sel_extra.emplace(sheet.junctions.at(it.uuid).net->uuid, ObjectType::NET);
1127             }
1128             break;
1129         case ObjectType::LINE_NET: {
1130             LineNet &li = core_schematic.get_sheet()->net_lines.at(it.uuid);
1131             if (li.net) {
1132                 sel_extra.emplace(li.net->uuid, ObjectType::NET);
1133             }
1134         } break;
1135         case ObjectType::NET_LABEL: {
1136             NetLabel &la = core_schematic.get_sheet()->net_labels.at(it.uuid);
1137             if (la.junction->net) {
1138                 sel_extra.emplace(la.junction->net->uuid, ObjectType::NET);
1139             }
1140         } break;
1141         case ObjectType::POWER_SYMBOL: {
1142             PowerSymbol &sym = core_schematic.get_sheet()->power_symbols.at(it.uuid);
1143             if (sym.net) {
1144                 sel_extra.emplace(sym.net->uuid, ObjectType::NET);
1145             }
1146         } break;
1147         default:;
1148         }
1149     }
1150 }
1151 
update_monitor()1152 void ImpSchematic::update_monitor()
1153 {
1154     ItemSet mon_items = core_schematic.get_block()->get_pool_items_used();
1155     {
1156         ItemSet items = core_schematic.get_schematic()->get_pool_items_used();
1157         mon_items.insert(items.begin(), items.end());
1158     }
1159     set_monitor_items(mon_items);
1160 }
1161 
1162 } // namespace horizon
1163