src/addObjectDialog.cpp

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

mercurial