zz_addObjectDialog.cpp

changeset 183
f1b8cb53d2a2
parent 182
9374fea8f77f
child 184
fae3bc9ce319
equal deleted inserted replaced
182:9374fea8f77f 183:f1b8cb53d2a2
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 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.h>
20 #include <qradiobutton.h>
21 #include <qcheckbox.h>
22 #include "gui.h"
23 #include "zz_addObjectDialog.h"
24 #include "file.h"
25 #include "colors.h"
26 #include "zz_colorSelectDialog.h"
27 #include "history.h"
28 #include "zz_setContentsDialog.h"
29
30 #define APPLY_COORDS(OBJ, N) \
31 for (short i = 0; i < N; ++i) \
32 for (const Axis ax : g_Axes) \
33 OBJ->vaCoords[i][ax] = dlg.dsb_coords[(i * 3) + ax]->value ();
34
35 // =============================================================================
36 class SubfileListItem : public QTreeWidgetItem {
37 public:
38 SubfileListItem (QTreeWidgetItem* parent, int subfileID) :
39 QTreeWidgetItem (parent), subfileID (subfileID) {}
40 SubfileListItem (QTreeWidget* parent, int subfileID) :
41 QTreeWidgetItem (parent), subfileID (subfileID) {}
42
43 int subfileID;
44 };
45
46 // =============================================================================
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
48 // =============================================================================
49 AddObjectDialog::AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent) :
50 QDialog (parent)
51 {
52 setlocale (LC_ALL, "C");
53
54 short coordCount = 0;
55
56 switch (type) {
57 case LDObject::Comment:
58 le_comment = new QLineEdit;
59 if (obj)
60 le_comment->setText (static_cast<LDComment*> (obj)->text);
61 break;
62
63 case LDObject::Line:
64 coordCount = 6;
65 break;
66
67 case LDObject::Triangle:
68 coordCount = 9;
69 break;
70
71 case LDObject::Quad:
72 case LDObject::CondLine:
73 coordCount = 12;
74 break;
75
76 case LDObject::Vertex:
77 coordCount = 3;
78 break;
79
80 case LDObject::BFC:
81 rb_bfcType = new RadioBox ("Statement", {}, 0, Qt::Vertical);
82
83 for (int i = 0; i < LDBFC::NumStatements; ++i)
84 rb_bfcType->addButton (new QRadioButton (LDBFC::statements[i]));
85
86 if (obj)
87 rb_bfcType->setValue ((int) static_cast<LDBFC*> (obj)->type);
88 break;
89
90 case LDObject::Subfile:
91 coordCount = 3;
92
93 enum {
94 Parts,
95 Subparts,
96 Primitives,
97 HiRes,
98 };
99
100 tw_subfileList = new QTreeWidget ();
101 for (int i : vector<int> ({Parts, Subparts, Primitives, HiRes})) {
102 SubfileListItem* parentItem = new SubfileListItem (tw_subfileList, -1);
103 parentItem->setText (0, (i == Parts) ? "Parts" :
104 (i == Subparts) ? "Subparts" :
105 (i == Primitives) ? "Primitives" :
106 "Hi-Res");
107
108 ulong j = 0;
109 for (partListEntry& part : g_PartList) {
110 QList<QTreeWidgetItem*> subfileItems;
111
112 str fileName = part.sName;
113 const bool isSubpart = fileName.substr (0, 2) == "s\\";
114 const bool isPrimitive = str (part.sTitle).substr (0, 9) == "Primitive";
115 const bool isHiRes = fileName.substr (0, 3) == "48\\";
116
117 if ((i == Subparts && isSubpart) ||
118 (i == Primitives && isPrimitive) ||
119 (i == HiRes && isHiRes) ||
120 (i == Parts && !isSubpart && !isPrimitive && !isHiRes))
121 {
122 SubfileListItem* item = new SubfileListItem (parentItem, j);
123 item->setText (0, fmt ("%s - %s", part.sName, part.sTitle));
124 subfileItems.append (item);
125 }
126
127 j++;
128 }
129
130 tw_subfileList->addTopLevelItem (parentItem);
131 }
132
133 connect (tw_subfileList, SIGNAL (itemSelectionChanged ()), this, SLOT (slot_subfileTypeChanged ()));
134 lb_subfileName = new QLabel ("File:");
135 le_subfileName = new QLineEdit;
136 le_subfileName->setFocus ();
137
138 if (obj) {
139 LDSubfile* ref = static_cast<LDSubfile*> (obj);
140 le_subfileName->setText (ref->zFileName);
141 }
142 break;
143
144 case LDObject::Radial:
145 coordCount = 3;
146
147 lb_radType = new QLabel ("Type:");
148 lb_radResolution = new QLabel ("Resolution:");
149 lb_radSegments = new QLabel ("Segments:");
150 lb_radRingNum = new QLabel ("Ring number:");
151
152 rb_radType = new RadioBox ("Type", {}, 0, Qt::Vertical);
153
154 for (int i = 0; i < LDRadial::NumTypes; ++i) {
155 if (i % (LDRadial::NumTypes / 2) == 0)
156 rb_radType->rowBreak ();
157
158 rb_radType->addButton (new QRadioButton (LDRadial::radialTypeName ((LDRadial::Type) i)));
159 }
160
161 connect (rb_radType, SIGNAL (sig_buttonPressed (int)), this, SLOT (slot_radialTypeChanged (int)));
162
163 cb_radHiRes = new QCheckBox ("Hi-Res");
164
165 sb_radSegments = new QSpinBox;
166 sb_radSegments->setMinimum (1);
167
168 sb_radRingNum = new QSpinBox;
169 sb_radRingNum->setEnabled (false);
170
171 if (obj) {
172 LDRadial* rad = static_cast<LDRadial*> (obj);
173
174 rb_radType->setValue (rad->eRadialType);
175 sb_radSegments->setValue (rad->dSegments);
176 cb_radHiRes->setChecked ((rad->dDivisions == 48) ? Qt::Checked : Qt::Unchecked);
177 sb_radRingNum->setValue (rad->dRingNum);
178 }
179 break;
180
181 default:
182 assert (false);
183 return;
184 }
185
186 QPixmap icon = getIcon (fmt ("add-%s", g_saObjTypeIcons[type]));
187 LDObject* defaults = LDObject::getDefault (type);
188
189 lb_typeIcon = new QLabel;
190 lb_typeIcon->setPixmap (icon);
191
192 // Show a color edit dialog for the types that actually use the color
193 if (defaults->isColored ()) {
194 if (obj != null)
195 dColor = obj->dColor;
196 else
197 dColor = (type == LDObject::CondLine || type == LDObject::Line) ? edgecolor : maincolor;
198
199 pb_color = new QPushButton;
200 setButtonBackground (pb_color, dColor);
201 connect (pb_color, SIGNAL (clicked ()), this, SLOT (slot_colorButtonClicked ()));
202 }
203
204 for (short i = 0; i < coordCount; ++i) {
205 dsb_coords[i] = new QDoubleSpinBox;
206 dsb_coords[i]->setDecimals (5);
207 dsb_coords[i]->setMinimum (-10000.0);
208 dsb_coords[i]->setMaximum (10000.0);
209 }
210
211 IMPLEMENT_DIALOG_BUTTONS
212
213 QGridLayout* const layout = new QGridLayout;
214 layout->addWidget (lb_typeIcon, 0, 0);
215
216 switch (type) {
217 case LDObject::Line:
218 case LDObject::CondLine:
219 case LDObject::Triangle:
220 case LDObject::Quad:
221 // Apply coordinates
222 if (obj) {
223 for (short i = 0; i < coordCount / 3; ++i)
224 for (short j = 0; j < 3; ++j)
225 dsb_coords[(i * 3) + j]->setValue (obj->vaCoords[i].coord (j));
226 }
227 break;
228
229 case LDObject::Comment:
230 layout->addWidget (le_comment, 0, 1);
231 break;
232
233 case LDObject::BFC:
234 layout->addWidget (rb_bfcType, 0, 1);
235 break;
236
237 case LDObject::Radial:
238 layout->addWidget (rb_radType, 1, 1, 3, 2);
239 layout->addWidget (cb_radHiRes, 1, 3);
240 layout->addWidget (lb_radSegments, 2, 3);
241 layout->addWidget (sb_radSegments, 2, 4);
242 layout->addWidget (lb_radRingNum, 3, 3);
243 layout->addWidget (sb_radRingNum, 3, 4);
244
245 if (obj)
246 for (short i = 0; i < 3; ++i)
247 dsb_coords[i]->setValue (static_cast<LDRadial*> (obj)->vPosition.coord (i));
248 break;
249
250 case LDObject::Subfile:
251 layout->addWidget (tw_subfileList, 1, 1, 1, 2);
252 layout->addWidget (lb_subfileName, 2, 1);
253 layout->addWidget (le_subfileName, 2, 2);
254
255 if (obj)
256 for (short i = 0; i < 3; ++i)
257 dsb_coords[i]->setValue (static_cast<LDSubfile*> (obj)->vPosition.coord (i));
258 break;
259
260 default:
261 break;
262 }
263
264 if (type == LDObject::Subfile || type == LDObject::Radial) {
265 QLabel* lb_matrix = new QLabel ("Matrix:");
266 le_matrix = new QLineEdit;
267 // le_matrix->setValidator (new QDoubleValidator);
268 matrix<3> defval = g_identity;
269
270 if (obj) {
271 if (obj->getType () == LDObject::Subfile)
272 defval = static_cast<LDSubfile*> (obj)->mMatrix;
273 else
274 defval = static_cast<LDRadial*> (obj)->mMatrix;
275 }
276
277 le_matrix->setText (defval.stringRep ());
278 layout->addWidget (lb_matrix, 4, 1);
279 layout->addWidget (le_matrix, 4, 2, 1, 3);
280 }
281
282 if (defaults->isColored ())
283 layout->addWidget (pb_color, 1, 0);
284
285 if (coordCount > 0) {
286 QGridLayout* const qCoordLayout = new QGridLayout;
287
288 for (short i = 0; i < coordCount; ++i)
289 qCoordLayout->addWidget (dsb_coords[i], (i / 3), (i % 3));
290
291 layout->addLayout (qCoordLayout, 0, 1, (coordCount / 3), 3);
292 }
293
294 layout->addWidget (bbx_buttons, 5, 0, 1, 4);
295 setLayout (layout);
296 setWindowTitle (fmt (APPNAME ": New %s",
297 g_saObjTypeNames[type]).chars());
298
299 setWindowIcon (icon);
300 delete defaults;
301 }
302
303 // =============================================================================
304 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
305 // =============================================================================
306 void AddObjectDialog::setButtonBackground (QPushButton* button, short color) {
307 button->setIcon (getIcon ("palette"));
308 button->setAutoFillBackground (true);
309 button->setStyleSheet (
310 fmt ("background-color: %s", getColor (color)->zColorString.chars()).chars()
311 );
312 }
313
314 // =============================================================================
315 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
316 // =============================================================================
317 char* AddObjectDialog::currentSubfileName() {
318 SubfileListItem* item = static_cast<SubfileListItem*> (tw_subfileList->currentItem ());
319
320 if (item->subfileID == -1)
321 return null; // selected a heading
322
323 return g_PartList[item->subfileID].sName;
324 }
325
326 // =============================================================================
327 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
328 // =============================================================================
329 void AddObjectDialog::slot_colorButtonClicked () {
330 ColorSelectDialog::staticDialog (dColor, dColor, this);
331 setButtonBackground (pb_color, dColor);
332 }
333
334 // =============================================================================
335 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
336 // =============================================================================
337 void AddObjectDialog::slot_radialTypeChanged (int dType) {
338 LDRadial::Type eType = (LDRadial::Type) dType;
339 sb_radRingNum->setEnabled (eType == LDRadial::Ring || eType == LDRadial::Cone);
340 }
341
342 // =============================================================================
343 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
344 // =============================================================================
345 void AddObjectDialog::slot_subfileTypeChanged () {
346 char* name = currentSubfileName ();
347
348 if (name)
349 le_subfileName->setText (name);
350 }
351
352 // =============================================================================
353 template<class T> T* initObj (LDObject*& obj) {
354 if (obj == null)
355 obj = new T;
356
357 return static_cast<T*> (obj);
358 }
359
360 // =============================================================================
361 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
362 // =============================================================================
363 void AddObjectDialog::staticDialog (const LDObject::Type type, LDObject* obj) {
364 setlocale (LC_ALL, "C");
365
366 // Redirect editing of gibberish to the set contents dialog
367 if (obj && obj->getType () == LDObject::Gibberish) {
368 SetContentsDialog::staticDialog (obj);
369 return;
370 }
371
372 if (type == LDObject::Empty)
373 return; // Nothing to edit with empties
374
375 const bool newObject = (obj == null);
376 AddObjectDialog dlg (type, obj);
377
378 if (obj)
379 assert (obj->getType () == type);
380
381 if (dlg.exec () == false)
382 return;
383
384 LDObject* backup = null;
385 if (!newObject)
386 backup = obj->clone ();
387
388 matrix<3> transform = g_identity;
389 if (type == LDObject::Subfile || type == LDObject::Radial) {
390 vector<str> matrixstrvals = str (dlg.le_matrix->text ()).split (" ", true);
391
392 if (matrixstrvals.size () == 9) {
393 double matrixvals[9];
394 int i = 0;
395
396 for (str val : matrixstrvals)
397 matrixvals[i++] = atof (val);
398
399 transform = matrix<3> (matrixvals);
400 }
401 }
402
403 switch (type) {
404 case LDObject::Comment:
405 {
406 LDComment* comm = initObj<LDComment> (obj);
407 comm->text = dlg.le_comment->text ();
408 }
409 break;
410
411 case LDObject::Line:
412 {
413 LDLine* line = initObj<LDLine> (obj);
414 line->dColor = dlg.dColor;
415 APPLY_COORDS (line, 2)
416 }
417 break;
418
419 case LDObject::Triangle:
420 {
421 LDTriangle* tri = initObj<LDTriangle> (obj);
422 tri->dColor = dlg.dColor;
423 APPLY_COORDS (tri, 3)
424 }
425 break;
426
427 case LDObject::Quad:
428 {
429 LDQuad* quad = initObj<LDQuad> (obj);
430 quad->dColor = dlg.dColor;
431 APPLY_COORDS (quad, 4)
432 }
433 break;
434
435 case LDObject::CondLine:
436 {
437 LDCondLine* line = initObj<LDCondLine> (obj);
438 line->dColor = dlg.dColor;
439 APPLY_COORDS (line, 4)
440 }
441 break;
442
443 case LDObject::BFC:
444 {
445 LDBFC* bfc = initObj<LDBFC> (obj);
446 bfc->type = (LDBFC::Type) dlg.rb_bfcType->value ();
447 }
448 break;
449
450 case LDObject::Vertex:
451 {
452 LDVertex* vert = initObj<LDVertex> (obj);
453 vert->dColor = dlg.dColor;
454
455 for (const Axis ax : g_Axes)
456 vert->vPosition[ax] = dlg.dsb_coords[ax]->value ();
457 }
458 break;
459
460 case LDObject::Radial:
461 {
462 LDRadial* pRad = initObj<LDRadial> (obj);
463 pRad->dColor = dlg.dColor;
464
465 for (const Axis ax : g_Axes)
466 pRad->vPosition[ax] = dlg.dsb_coords[ax]->value ();
467
468 pRad->dDivisions = (dlg.cb_radHiRes->checkState () != Qt::Checked) ? 16 : 48;
469 pRad->dSegments = min<short> (dlg.sb_radSegments->value (), pRad->dDivisions);
470 pRad->eRadialType = (LDRadial::Type) dlg.rb_radType->value ();
471 pRad->dRingNum = dlg.sb_radRingNum->value ();
472 pRad->mMatrix = transform;
473 }
474 break;
475
476 case LDObject::Subfile:
477 {
478 str name = dlg.le_subfileName->text ();
479 if (~name == 0)
480 return; // no subfile filename
481
482 OpenFile* file = loadSubfile (name);
483 if (!file)
484 return;
485
486 LDSubfile* ref = initObj<LDSubfile> (obj);
487 ref->dColor = dlg.dColor;
488
489 for (const Axis ax : g_Axes)
490 ref->vPosition[ax] = dlg.dsb_coords[ax]->value ();
491
492 ref->zFileName = name;
493 ref->mMatrix = transform;
494 ref->pFile = file;
495 }
496 break;
497
498 default:
499 break;
500 }
501
502 if (newObject) {
503 ulong idx = g_win->getInsertionPoint ();
504 g_curfile->insertObj (idx, obj);
505 History::addEntry (new AddHistory ({(ulong) idx}, {obj->clone ()}));
506 } else {
507 History::addEntry (new EditHistory ({(ulong) obj->getIndex (g_curfile)}, {backup}, {obj->clone ()}));
508 }
509
510 g_win->refresh ();
511 }

mercurial