1 #include "footprint_generator_grid.hpp"
2 #include "widgets/pool_browser_button.hpp"
3 #include "document/idocument_package.hpp"
4 #include "pool/ipool.hpp"
5 #include "pool/package.hpp"
6
7 namespace horizon {
FootprintGeneratorGrid(IDocumentPackage & c)8 FootprintGeneratorGrid::FootprintGeneratorGrid(IDocumentPackage &c)
9 : Glib::ObjectBase(typeid(FootprintGeneratorGrid)),
10 FootprintGeneratorBase("/org/horizon-eda/horizon/imp/footprint_generator/grid.svg", c)
11 {
12 update_preview();
13
14 sp_pitch_h = Gtk::manage(new SpinButtonDim());
15 sp_pitch_h->set_range(0, 50_mm);
16 sp_pitch_h->set_valign(Gtk::ALIGN_CENTER);
17 sp_pitch_h->set_halign(Gtk::ALIGN_END);
18 sp_pitch_h->set_value(3_mm);
19 overlay->add_at_sub(*sp_pitch_h, "#pitch_h");
20 sp_pitch_h->show();
21
22 sp_pitch_v = Gtk::manage(new SpinButtonDim());
23 sp_pitch_v->set_range(0, 50_mm);
24 sp_pitch_v->set_valign(Gtk::ALIGN_CENTER);
25 sp_pitch_v->set_halign(Gtk::ALIGN_START);
26 sp_pitch_v->set_value(3_mm);
27 sp_pitch_v->signal_value_changed().connect(sigc::mem_fun(*this, &FootprintGeneratorGrid::update_xy_lock));
28 overlay->add_at_sub(*sp_pitch_v, "#pitch_v");
29 sp_pitch_v->show();
30
31 sp_pad_height = Gtk::manage(new SpinButtonDim());
32 sp_pad_height->set_range(0, 50_mm);
33 sp_pad_height->set_valign(Gtk::ALIGN_CENTER);
34 sp_pad_height->set_halign(Gtk::ALIGN_START);
35 sp_pad_height->set_value(.5_mm);
36 sp_pad_height->signal_value_changed().connect(sigc::mem_fun(*this, &FootprintGeneratorGrid::update_xy_lock));
37 overlay->add_at_sub(*sp_pad_height, "#pad_height");
38 sp_pad_height->show();
39
40 sp_pad_width = Gtk::manage(new SpinButtonDim());
41 sp_pad_width->set_range(0, 50_mm);
42 sp_pad_width->set_valign(Gtk::ALIGN_CENTER);
43 sp_pad_width->set_halign(Gtk::ALIGN_START);
44 sp_pad_width->set_value(.5_mm);
45 overlay->add_at_sub(*sp_pad_width, "#pad_width");
46 sp_pad_width->show();
47
48 {
49 auto tbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 4));
50 auto la = Gtk::manage(new Gtk::Label("Count H:"));
51 tbox->pack_start(*la, false, false, 0);
52
53 sp_count_h = Gtk::manage(new Gtk::SpinButton());
54 sp_count_h->set_range(4, 512);
55 sp_count_h->set_increments(1, 1);
56 tbox->pack_start(*sp_count_h, false, false, 0);
57
58 box_top->pack_start(*tbox, false, false, 0);
59 }
60 {
61 auto tbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 4));
62 auto la = Gtk::manage(new Gtk::Label("Count V:"));
63 tbox->pack_start(*la, false, false, 0);
64
65 sp_count_v = Gtk::manage(new Gtk::SpinButton());
66 sp_count_v->set_range(4, 512);
67 sp_count_v->set_increments(1, 1);
68 tbox->pack_start(*sp_count_v, false, false, 0);
69
70 box_top->pack_start(*tbox, false, false, 0);
71 }
72 {
73 cb_xy_lock = Gtk::manage(new Gtk::CheckButton("XY Lock"));
74 cb_xy_lock->signal_toggled().connect(sigc::mem_fun(*this, &FootprintGeneratorGrid::update_xy_lock));
75 cb_xy_lock->set_active(true);
76 box_top->pack_start(*cb_xy_lock, false, false, 0);
77 }
78
79 sp_count_h->signal_value_changed().connect([this] {
80 pad_count_h = sp_count_h->get_value_as_int();
81 update_preview();
82 });
83 sp_count_v->signal_value_changed().connect([this] {
84 pad_count_v = sp_count_v->get_value_as_int();
85 update_preview();
86 });
87
88 sp_count_h->set_value(4);
89 sp_count_v->set_value(4);
90 }
91
update_xy_lock()92 void FootprintGeneratorGrid::update_xy_lock()
93 {
94 auto locked = cb_xy_lock->get_active();
95 sp_pad_width->set_sensitive(!locked);
96 sp_pitch_h->set_sensitive(!locked);
97 if (locked) {
98 sp_pitch_h->set_value(sp_pitch_v->get_value());
99 sp_pad_width->set_value(sp_pad_height->get_value());
100 }
101 }
102
103 static const std::string bga_letters = "ABCDEFGHJKLMNPRTUVWY";
104
get_bga_letter(int x)105 static std::string get_bga_letter(int x)
106 {
107 x -= 1;
108 int n_bga_letters = bga_letters.size();
109 if (x < n_bga_letters) {
110 char c[2] = {0};
111 c[0] = bga_letters.at(x);
112 return c;
113 }
114 else {
115 char c[3] = {0};
116 c[0] = bga_letters.at((x / n_bga_letters) - 1);
117 c[1] = bga_letters.at(x % n_bga_letters);
118 return c;
119 }
120 }
121
generate()122 bool FootprintGeneratorGrid::generate()
123 {
124 if (!property_can_generate())
125 return false;
126 int64_t pitch_h = sp_pitch_h->get_value_as_int();
127 int64_t pitch_v = sp_pitch_v->get_value_as_int();
128 int64_t pad_width = sp_pad_width->get_value_as_int();
129 int64_t pad_height = sp_pad_height->get_value_as_int();
130
131 auto padstack = core.get_pool().get_padstack(browser_button->property_selected_uuid());
132
133 for (size_t x = 0; x < pad_count_h; x++) {
134 for (size_t y = 0; y < pad_count_v; y++) {
135 auto uu = UUID::random();
136 auto &pad = package.pads.emplace(uu, Pad(uu, padstack)).first->second;
137 pad.placement.shift.x = pitch_h * x - (pitch_h * (pad_count_h - 1)) / 2;
138 pad.placement.shift.y = -pitch_v * y + (pitch_v * (pad_count_v - 1)) / 2;
139 update_pad_parameters(*padstack, pad, pad_width, pad_height);
140 pad.name = get_bga_letter(x + 1) + std::to_string(y + 1);
141 }
142 }
143 return true;
144 }
145
update_preview()146 void FootprintGeneratorGrid::update_preview()
147 {
148 overlay->sub_texts["#padx1"] = "A";
149 overlay->sub_texts["#padx2"] = "B";
150 overlay->sub_texts["#padx3"] = get_bga_letter(pad_count_h - 1);
151 overlay->sub_texts["#padx4"] = get_bga_letter(pad_count_h);
152
153 overlay->sub_texts["#pady1"] = "1";
154 overlay->sub_texts["#pady2"] = "2";
155 overlay->sub_texts["#pady3"] = std::to_string(pad_count_v - 1);
156 overlay->sub_texts["#pady4"] = std::to_string(pad_count_v);
157
158 overlay->queue_draw();
159 }
160 } // namespace horizon
161