1 #include "imp.hpp"
2 #include "util/str_util.hpp"
3 #include "util/util.hpp"
4 #include "util/geom_util.hpp"
5 #include "util/selection_util.hpp"
6 #include "pool/entity.hpp"
7 #include "pool/part.hpp"
8 #include "block/block.hpp"
9 #include "board/board_junction.hpp"
10
11 namespace horizon {
hud_update()12 void ImpBase::hud_update()
13 {
14 if (core->tool_is_active())
15 return;
16
17 auto sel = canvas->get_selection();
18 if (sel.size()) {
19 std::string hud_text = get_hud_text(sel);
20 trim(hud_text);
21 hud_text += "\n\n";
22 auto text_generic = ImpBase::get_hud_text(sel);
23 trim(text_generic);
24 hud_text += text_generic;
25 trim(hud_text);
26 main_window->hud_update(hud_text);
27 }
28 else {
29 main_window->hud_update("");
30 }
31 }
32
get_hud_text(std::set<SelectableRef> & sel)33 std::string ImpBase::get_hud_text(std::set<SelectableRef> &sel)
34 {
35 std::string s;
36 if (sel_count_type(sel, ObjectType::LINE)) {
37 auto n = sel_count_type(sel, ObjectType::LINE);
38 s += "\n\n<b>" + std::to_string(n) + " " + object_descriptions.at(ObjectType::LINE).get_name_for_n(n)
39 + "</b>\n";
40 std::set<int> layers;
41 int64_t length = 0;
42 for (const auto &it : sel) {
43 if (it.type == ObjectType::LINE) {
44 const auto li = core->get_line(it.uuid);
45 layers.insert(li->layer);
46 length += (li->from->position - li->to->position).magd();
47 }
48 }
49 s += "Layers: ";
50 for (auto layer : layers) {
51 s += core->get_layer_provider().get_layers().at(layer).name + " ";
52 }
53 s += "\nTotal length: " + dim_to_string(length, false);
54 sel_erase_type(sel, ObjectType::LINE);
55 }
56
57 // Display the length if a single edge of a polygon is given
58 if (auto it = sel_find_exactly_one(sel, ObjectType::POLYGON_EDGE)) {
59 s += "\n\n<b>" + object_descriptions.at(ObjectType::POLYGON_EDGE).name + "</b>\n";
60 const auto li = core->get_polygon(it->uuid);
61 const auto pair = li->get_vertices_for_edge(it->vertex);
62 const int64_t length = (li->vertices.at(pair.first).position - li->vertices.at(pair.second).position).magd();
63 s += "Layer: ";
64 s += core->get_layer_provider().get_layers().at(li->layer).name + " ";
65 s += "\nLength: " + dim_to_string(length, false);
66 if (preferences.hud_debug)
67 s += "\nVertex: " + std::to_string(it->vertex);
68 sel_erase_type(sel, ObjectType::POLYGON_EDGE);
69 }
70
71 if (auto it = sel_find_exactly_one(sel, ObjectType::POLYGON_VERTEX)) {
72 s += "\n\n<b>" + object_descriptions.at(ObjectType::POLYGON_VERTEX).name + "</b>\n";
73 const auto poly = core->get_polygon(it->uuid);
74 s += coord_to_string(poly->vertices.at(it->vertex).position);
75 if (preferences.hud_debug)
76 s += "\nVertex: " + std::to_string(it->vertex);
77 sel_erase_type(sel, ObjectType::POLYGON_VERTEX);
78 }
79
80 if (preferences.hud_debug) {
81 if (auto it = sel_find_exactly_one(sel, ObjectType::TEXT)) {
82 const auto txt = core->get_text(it->uuid);
83 s += "\n\n<b>Text:</b>\n";
84 if (txt->overridden) {
85 s += "Overriden: " + txt->text_override;
86 }
87 else {
88 s += "Not overridden";
89 }
90 }
91 }
92
93 if (auto it = sel_find_exactly_one(sel, ObjectType::TEXT)) {
94 const auto text = core->get_text(it->uuid);
95 const auto txt = Glib::ustring(text->text);
96 auto regex = Glib::Regex::create(R"((https?:\/\/|file:\/\/\/?)([\w\.-]+)(\/\S+)?)");
97 Glib::MatchInfo ma;
98 if (regex->match(txt, ma)) {
99 s += "\n\n<b>Text with links</b>\n";
100 do {
101 auto url = ma.fetch(0);
102 auto regex_file = Glib::Regex::create(R"(file:\/\/?(\S+\/|)([^\/\s]+))");
103 Glib::MatchInfo ma_f;
104 auto name = ma.fetch(2);
105 if (regex_file->match(url, ma_f)) {
106 name = ma_f.fetch(2);
107 }
108 if (ma.fetch(1).compare("file://") == 0) {
109 url = url.replace(0, 7, "file://" + Glib::path_get_dirname(core->get_filename()) + "/");
110 }
111 s += "<a href=\"" + Glib::Markup::escape_text(url) + "\" title=\""
112 + Glib::Markup::escape_text(Glib::Markup::escape_text(url)) + "\">" + name + "</a>\n";
113 } while (ma.next());
114 sel_erase_type(sel, ObjectType::TEXT);
115 }
116 }
117
118 if (preferences.hud_debug) {
119 if (auto it = sel_find_exactly_one(sel, ObjectType::JUNCTION)) {
120 const auto ju = core->get_junction(it->uuid);
121 s += "\n\n<b>Junction:</b>\n";
122 s += "Layers " + std::to_string(ju->layer.start()) + " — " + std::to_string(ju->layer.end()) + "\n";
123 const Net *net = nullptr;
124 if (auto ju_b = dynamic_cast<BoardJunction *>(ju))
125 net = ju_b->net;
126 if (net)
127 s += "Net: " + core->get_block()->get_net_name(net->uuid);
128 else
129 s += "No net";
130 sel_erase_type(sel, ObjectType::JUNCTION);
131 }
132 }
133
134 // Display the delta if two items of these types are selected
135 for (const ObjectType type : {ObjectType::HOLE, ObjectType::POLYGON_VERTEX, ObjectType::JUNCTION}) {
136 if (sel_count_type(sel, type) == 2) {
137 s += "\n\n<b>2 " + object_descriptions.at(type).name_pl + "</b>";
138 std::vector<Coordi> positions;
139 for (const auto &iter : sel) {
140 if (iter.type == type) {
141 if (type == ObjectType::POLYGON_VERTEX) {
142 const auto poly = core->get_polygon(iter.uuid);
143 const auto vertex = &poly->vertices.at(iter.vertex);
144 positions.push_back(vertex->position);
145 }
146 else if (type == ObjectType::HOLE) {
147 const auto hole = core->get_hole(iter.uuid);
148 positions.push_back(hole->placement.shift);
149 }
150 else if (type == ObjectType::JUNCTION) {
151 const auto junction = core->get_junction(iter.uuid);
152 positions.push_back(junction->position);
153 }
154 else {
155 assert(false); // unreachable
156 }
157 }
158 }
159 assert(positions.size() == 2);
160 const auto delta = positions.at(1) - positions.at(0);
161 s += "\n" + coord_to_string(delta, true);
162 sel_erase_type(sel, type);
163 }
164 }
165
166 trim(s);
167 if (sel.size()) {
168 s += "\n\n<b>Others:</b>\n";
169 for (const auto &it : object_descriptions) {
170 auto n = std::count_if(sel.begin(), sel.end(), [&it](const auto &a) { return a.type == it.first; });
171 if (n) {
172 s += std::to_string(n) + " " + it.second.get_name_for_n(n) + "\n";
173 }
174 }
175 sel.clear();
176 }
177 return s;
178 }
179
get_hud_text_for_net(const Net * net)180 std::string ImpBase::get_hud_text_for_net(const Net *net)
181 {
182 if (!net)
183 return "No net";
184
185 std::string s = "Net: " + core->get_block()->get_net_name(net->uuid) + "\n";
186 s += "Net class " + net->net_class->name + "\n";
187 if (net->is_power)
188 s += "is power net";
189
190 trim(s);
191 return s;
192 }
193
get_hud_text_for_component(const Component * comp)194 std::string ImpBase::get_hud_text_for_component(const Component *comp)
195 {
196 const Part *part = comp->part;
197 if (!part) {
198 std::string s = "No part\n";
199 s += "Entity: " + comp->entity->name;
200 return s;
201 }
202 else {
203 std::string s = "MPN: " + Glib::Markup::escape_text(part->get_MPN()) + "\n";
204 s += "Manufacturer: " + Glib::Markup::escape_text(part->get_manufacturer()) + "\n";
205 s += "Package: " + Glib::Markup::escape_text(part->package->name) + "\n";
206 if (part->get_description().size())
207 s += Glib::Markup::escape_text(part->get_description()) + "\n";
208 if (part->get_datasheet().size())
209 s += "<a href=\"" + Glib::Markup::escape_text(part->get_datasheet()) + "\" title=\""
210 + Glib::Markup::escape_text(Glib::Markup::escape_text(part->get_datasheet())) + "\">Datasheet</a>\n";
211
212 const auto block = core->get_block();
213 if (comp->group)
214 s += "Group: " + Glib::Markup::escape_text(block->get_group_name(comp->group)) + "\n";
215 if (comp->tag)
216 s += "Tag: " + Glib::Markup::escape_text(block->get_tag_name(comp->tag)) + "\n";
217
218 trim(s);
219 return s;
220 }
221 }
222
223 } // namespace horizon
224