src/AddObjectDialog.cc

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

mercurial