src/AddObjectDialog.cc

changeset 655
b376645315ab
parent 654
a74f2ff353b8
child 656
2a1c204df14d
child 706
d79083b9f74d
equal deleted inserted replaced
654:a74f2ff353b8 655:b376645315ab
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013, 2014 Santeri Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <QGridLayout>
20 #include <QCheckBox>
21 #include <QDialogButtonBox>
22 #include <QSpinBox>
23 #include <QLabel>
24 #include <QListWidget>
25 #include <QTreeWidget>
26 #include <QLineEdit>
27 #include <QPushButton>
28 #include "MainWindow.h"
29 #include "AddObjectDialog.h"
30 #include "Document.h"
31 #include "Colors.h"
32 #include "ColorSelector.h"
33 #include "EditHistory.h"
34 #include "Widgets.h"
35 #include "Misc.h"
36 #include "Primitives.h"
37
38 // =============================================================================
39 //
40 class SubfileListItem : public QTreeWidgetItem
41 {
42 PROPERTY (public, Primitive*, primitive, setPrimitive, STOCK_WRITE)
43
44 public:
45 SubfileListItem (QTreeWidgetItem* parent, Primitive* info) :
46 QTreeWidgetItem (parent),
47 m_primitive (info) {}
48
49 SubfileListItem (QTreeWidget* parent, Primitive* info) :
50 QTreeWidgetItem (parent),
51 m_primitive (info) {}
52 };
53
54 // =============================================================================
55 //
56 AddObjectDialog::AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent) :
57 QDialog (parent)
58 {
59 setlocale (LC_ALL, "C");
60
61 int coordCount = 0;
62 QString typeName = LDObject::typeName (type);
63
64 switch (type)
65 {
66 case LDObject::EComment:
67 {
68 le_comment = new QLineEdit;
69
70 if (obj)
71 le_comment->setText (static_cast<LDComment*> (obj)->text());
72
73 le_comment->setMinimumWidth (384);
74 } break;
75
76 case LDObject::ELine:
77 {
78 coordCount = 6;
79 } break;
80
81 case LDObject::ETriangle:
82 {
83 coordCount = 9;
84 } break;
85
86 case LDObject::EQuad:
87 case LDObject::ECondLine:
88 {
89 coordCount = 12;
90 } break;
91
92 case LDObject::EVertex:
93 {
94 coordCount = 3;
95 } break;
96
97 case LDObject::EBFC:
98 {
99 rb_bfcType = new RadioGroup ("Statement", {}, 0, Qt::Vertical);
100
101 for (int i = 0; i < LDBFC::NumStatements; ++i)
102 {
103 // Separate these in two columns
104 if (i == LDBFC::NumStatements / 2)
105 rb_bfcType->rowBreak();
106
107 rb_bfcType->addButton (LDBFC::k_statementStrings[i]);
108 }
109
110 if (obj)
111 rb_bfcType->setValue ( (int) static_cast<LDBFC*> (obj)->statement());
112 } break;
113
114 case LDObject::ESubfile:
115 {
116 coordCount = 3;
117 tw_subfileList = new QTreeWidget();
118 tw_subfileList->setHeaderLabel (tr ("Primitives"));
119
120 for (PrimitiveCategory* cat : g_PrimitiveCategories)
121 {
122 SubfileListItem* parentItem = new SubfileListItem (tw_subfileList, null);
123 parentItem->setText (0, cat->name());
124 QList<QTreeWidgetItem*> subfileItems;
125
126 for (Primitive& prim : cat->prims)
127 {
128 SubfileListItem* item = new SubfileListItem (parentItem, &prim);
129 item->setText (0, format ("%1 - %2", prim.name, prim.title));
130 subfileItems << item;
131
132 // If this primitive is the one the current object points to,
133 // select it by default
134 if (obj && static_cast<LDSubfile*> (obj)->fileInfo()->name() == prim.name)
135 tw_subfileList->setCurrentItem (item);
136 }
137
138 tw_subfileList->addTopLevelItem (parentItem);
139 }
140
141 connect (tw_subfileList, SIGNAL (itemSelectionChanged()), this, SLOT (slot_subfileTypeChanged()));
142 lb_subfileName = new QLabel ("File:");
143 le_subfileName = new QLineEdit;
144 le_subfileName->setFocus();
145
146 if (obj)
147 {
148 LDSubfile* ref = static_cast<LDSubfile*> (obj);
149 le_subfileName->setText (ref->fileInfo()->name());
150 }
151 } break;
152
153 default:
154 {
155 critical (format ("Unhandled LDObject type %1 (%2) in AddObjectDialog", (int) type, typeName));
156 } return;
157 }
158
159 QPixmap icon = getIcon (format ("add-%1", typeName));
160 LDObject* defaults = LDObject::getDefault (type);
161
162 lb_typeIcon = new QLabel;
163 lb_typeIcon->setPixmap (icon);
164
165 // Show a color edit dialog for the types that actually use the color
166 if (defaults->isColored())
167 {
168 if (obj != null)
169 colnum = obj->color();
170 else
171 colnum = (type == LDObject::ECondLine || type == LDObject::ELine) ? edgecolor : maincolor;
172
173 pb_color = new QPushButton;
174 setButtonBackground (pb_color, colnum);
175 connect (pb_color, SIGNAL (clicked()), this, SLOT (slot_colorButtonClicked()));
176 }
177
178 for (int i = 0; i < coordCount; ++i)
179 {
180 dsb_coords[i] = new QDoubleSpinBox;
181 dsb_coords[i]->setDecimals (5);
182 dsb_coords[i]->setMinimum (-10000.0);
183 dsb_coords[i]->setMaximum (10000.0);
184 }
185
186 QGridLayout* const layout = new QGridLayout;
187 layout->addWidget (lb_typeIcon, 0, 0);
188
189 switch (type)
190 {
191 case LDObject::ELine:
192 case LDObject::ECondLine:
193 case LDObject::ETriangle:
194 case LDObject::EQuad:
195
196 // Apply coordinates
197 if (obj)
198 {
199 for (int i = 0; i < coordCount / 3; ++i)
200 for (int j = 0; j < 3; ++j)
201 dsb_coords[ (i * 3) + j]->setValue (obj->vertex (i).getCoordinate (j));
202 }
203
204 break;
205
206 case LDObject::EComment:
207 layout->addWidget (le_comment, 0, 1);
208 break;
209
210 case LDObject::EBFC:
211 layout->addWidget (rb_bfcType, 0, 1);
212 break;
213
214 case LDObject::ESubfile:
215 layout->addWidget (tw_subfileList, 1, 1, 1, 2);
216 layout->addWidget (lb_subfileName, 2, 1);
217 layout->addWidget (le_subfileName, 2, 2);
218 break;
219
220 default:
221 break;
222 }
223
224 if (defaults->hasMatrix())
225 {
226 LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj);
227
228 QLabel* lb_matrix = new QLabel ("Matrix:");
229 le_matrix = new QLineEdit;
230 // le_matrix->setValidator (new QDoubleValidator);
231 Matrix defaultMatrix = g_identity;
232
233 if (mo)
234 {
235 for_axes (ax)
236 dsb_coords[ax]->setValue (mo->position()[ax]);
237
238 defaultMatrix = mo->transform();
239 }
240
241 le_matrix->setText (defaultMatrix.toString());
242 layout->addWidget (lb_matrix, 4, 1);
243 layout->addWidget (le_matrix, 4, 2, 1, 3);
244 }
245
246 if (defaults->isColored())
247 layout->addWidget (pb_color, 1, 0);
248
249 if (coordCount > 0)
250 {
251 QGridLayout* const qCoordLayout = new QGridLayout;
252
253 for (int i = 0; i < coordCount; ++i)
254 qCoordLayout->addWidget (dsb_coords[i], (i / 3), (i % 3));
255
256 layout->addLayout (qCoordLayout, 0, 1, (coordCount / 3), 3);
257 }
258
259 QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
260 QWidget::connect (bbx_buttons, SIGNAL (accepted()), this, SLOT (accept()));
261 QWidget::connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject()));
262 layout->addWidget (bbx_buttons, 5, 0, 1, 4);
263 setLayout (layout);
264 setWindowTitle (format (tr ("Edit %1"), typeName));
265
266 setWindowIcon (icon);
267 defaults->destroy();
268 }
269
270 // =============================================================================
271 // =============================================================================
272 void AddObjectDialog::setButtonBackground (QPushButton* button, int colnum)
273 {
274 LDColor* col = ::getColor (colnum);
275
276 button->setIcon (getIcon ("palette"));
277 button->setAutoFillBackground (true);
278
279 if (col)
280 button->setStyleSheet (format ("background-color: %1", col->hexcode));
281 }
282
283 // =============================================================================
284 // =============================================================================
285 QString AddObjectDialog::currentSubfileName()
286 {
287 SubfileListItem* item = static_cast<SubfileListItem*> (tw_subfileList->currentItem());
288
289 if (item->primitive() == null)
290 return ""; // selected a heading
291
292 return item->primitive()->name;
293 }
294
295 // =============================================================================
296 // =============================================================================
297 void AddObjectDialog::slot_colorButtonClicked()
298 {
299 ColorSelector::selectColor (colnum, colnum, this);
300 setButtonBackground (pb_color, colnum);
301 }
302
303 // =============================================================================
304 // =============================================================================
305 void AddObjectDialog::slot_subfileTypeChanged()
306 {
307 QString name = currentSubfileName();
308
309 if (name.length() > 0)
310 le_subfileName->setText (name);
311 }
312
313 // =============================================================================
314 // =============================================================================
315 template<class T> static T* initObj (LDObject*& obj)
316 {
317 if (obj == null)
318 obj = new T;
319
320 return static_cast<T*> (obj);
321 }
322
323 // =============================================================================
324 // =============================================================================
325 void AddObjectDialog::staticDialog (const LDObject::Type type, LDObject* obj)
326 {
327 setlocale (LC_ALL, "C");
328
329 // FIXME: Redirect to Edit Raw
330 if (obj && obj->type() == LDObject::EError)
331 return;
332
333 if (type == LDObject::EEmpty)
334 return; // Nothing to edit with empties
335
336 const bool newObject = (obj == null);
337 Matrix transform = g_identity;
338 AddObjectDialog dlg (type, obj);
339
340 assert (obj == null || obj->type() == type);
341
342 if (dlg.exec() == false)
343 return;
344
345 if (type == LDObject::ESubfile)
346 {
347 QStringList matrixstrvals = dlg.le_matrix->text().split (" ", QString::SkipEmptyParts);
348
349 if (matrixstrvals.size() == 9)
350 {
351 double matrixvals[9];
352 int i = 0;
353
354 for (QString val : matrixstrvals)
355 matrixvals[i++] = val.toFloat();
356
357 transform = Matrix (matrixvals);
358 }
359 }
360
361 switch (type)
362 {
363 case LDObject::EComment:
364 {
365 LDComment* comm = initObj<LDComment> (obj);
366 comm->setText (dlg.le_comment->text());
367 }
368 break;
369
370 case LDObject::ELine:
371 case LDObject::ETriangle:
372 case LDObject::EQuad:
373 case LDObject::ECondLine:
374 {
375 if (!obj)
376 obj = LDObject::getDefault (type);
377
378 for (int i = 0; i < obj->vertices(); ++i)
379 {
380 Vertex v;
381
382 for_axes (ax)
383 v[ax] = dlg.dsb_coords[ (i * 3) + ax]->value();
384
385 obj->setVertex (i, v);
386 }
387 } break;
388
389 case LDObject::EBFC:
390 {
391 LDBFC* bfc = initObj<LDBFC> (obj);
392 bfc->setStatement ((LDBFC::Statement) dlg.rb_bfcType->value());
393 } break;
394
395 case LDObject::EVertex:
396 {
397 LDVertex* vert = initObj<LDVertex> (obj);
398
399 for_axes (ax)
400 vert->pos[ax] = dlg.dsb_coords[ax]->value();
401 }
402 break;
403
404 case LDObject::ESubfile:
405 {
406 QString name = dlg.le_subfileName->text();
407
408 if (name.length() == 0)
409 return; // no subfile filename
410
411 LDDocument* file = getDocument (name);
412
413 if (!file)
414 {
415 critical (format ("Couldn't open `%1': %2", name, strerror (errno)));
416 return;
417 }
418
419 LDSubfile* ref = initObj<LDSubfile> (obj);
420 assert (ref);
421
422 for_axes (ax)
423 ref->setCoordinate (ax, dlg.dsb_coords[ax]->value());
424
425 ref->setTransform (transform);
426 ref->setFileInfo (file);
427 } break;
428
429 default:
430 break;
431 }
432
433 if (obj->isColored())
434 obj->setColor (dlg.colnum);
435
436 if (newObject)
437 {
438 int idx = g_win->getInsertionPoint();
439 getCurrentDocument()->insertObj (idx, obj);
440 }
441
442 g_win->refresh();
443 }

mercurial