|
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 <QFileDialog> |
|
20 #include <QMessageBox> |
|
21 #include <QTextEdit> |
|
22 #include <QBoxLayout> |
|
23 #include <QDialogButtonBox> |
|
24 #include <QPushButton> |
|
25 #include <QInputDialog> |
|
26 |
|
27 #include "../MainWindow.h" |
|
28 #include "../Document.h" |
|
29 #include "../EditHistory.h" |
|
30 #include "../ConfigurationDialog.h" |
|
31 #include "../AddObjectDialog.h" |
|
32 #include "../Misc.h" |
|
33 #include "../GLRenderer.h" |
|
34 #include "../Dialogs.h" |
|
35 #include "../Primitives.h" |
|
36 #include "../Widgets.h" |
|
37 #include "../Colors.h" |
|
38 #include "ui_newpart.h" |
|
39 |
|
40 extern_cfg (Bool, gl_wireframe); |
|
41 extern_cfg (Bool, gl_colorbfc); |
|
42 extern_cfg (String, ld_defaultname); |
|
43 extern_cfg (String, ld_defaultuser); |
|
44 extern_cfg (Int, ld_defaultlicense); |
|
45 extern_cfg (Bool, gl_drawangles); |
|
46 |
|
47 // ============================================================================= |
|
48 // ----------------------------------------------------------------------------- |
|
49 DEFINE_ACTION (New, CTRL_SHIFT (N)) |
|
50 { |
|
51 QDialog* dlg = new QDialog (g_win); |
|
52 Ui::NewPartUI ui; |
|
53 ui.setupUi (dlg); |
|
54 |
|
55 QString authortext = ld_defaultname; |
|
56 |
|
57 if (!ld_defaultuser.isEmpty()) |
|
58 authortext.append (fmt (" [%1]", ld_defaultuser)); |
|
59 |
|
60 ui.le_author->setText (authortext); |
|
61 |
|
62 switch (ld_defaultlicense) |
|
63 { |
|
64 case 0: |
|
65 ui.rb_license_ca->setChecked (true); |
|
66 break; |
|
67 |
|
68 case 1: |
|
69 ui.rb_license_nonca->setChecked (true); |
|
70 break; |
|
71 |
|
72 case 2: |
|
73 ui.rb_license_none->setChecked (true); |
|
74 break; |
|
75 |
|
76 default: |
|
77 QMessageBox::warning (null, "Warning", |
|
78 fmt ("Unknown ld_defaultlicense value %1!", ld_defaultlicense)); |
|
79 break; |
|
80 } |
|
81 |
|
82 if (dlg->exec() == false) |
|
83 return; |
|
84 |
|
85 newFile(); |
|
86 |
|
87 const LDBFC::Type BFCType = |
|
88 ui.rb_bfc_ccw->isChecked() ? LDBFC::CertifyCCW : |
|
89 ui.rb_bfc_cw->isChecked() ? LDBFC::CertifyCW : LDBFC::NoCertify; |
|
90 |
|
91 const QString license = |
|
92 ui.rb_license_ca->isChecked() ? CALicense : |
|
93 ui.rb_license_nonca->isChecked() ? NonCALicense : ""; |
|
94 |
|
95 getCurrentDocument()->addObjects ( |
|
96 { |
|
97 new LDComment (ui.le_title->text()), |
|
98 new LDComment ("Name: <untitled>.dat"), |
|
99 new LDComment (fmt ("Author: %1", ui.le_author->text())), |
|
100 new LDComment (fmt ("!LDRAW_ORG Unofficial_Part")), |
|
101 (license != "" ? new LDComment (license) : null), |
|
102 new LDEmpty, |
|
103 new LDBFC (BFCType), |
|
104 new LDEmpty, |
|
105 }); |
|
106 |
|
107 doFullRefresh(); |
|
108 } |
|
109 |
|
110 // ============================================================================= |
|
111 // ----------------------------------------------------------------------------- |
|
112 DEFINE_ACTION (NewFile, CTRL (N)) |
|
113 { |
|
114 newFile(); |
|
115 } |
|
116 |
|
117 // ============================================================================= |
|
118 // ----------------------------------------------------------------------------- |
|
119 DEFINE_ACTION (Open, CTRL (O)) |
|
120 { |
|
121 QString name = QFileDialog::getOpenFileName (g_win, "Open File", "", "LDraw files (*.dat *.ldr)"); |
|
122 |
|
123 if (name.length() == 0) |
|
124 return; |
|
125 |
|
126 openMainFile (name); |
|
127 } |
|
128 |
|
129 // ============================================================================= |
|
130 // ----------------------------------------------------------------------------- |
|
131 DEFINE_ACTION (Save, CTRL (S)) |
|
132 { |
|
133 save (getCurrentDocument(), false); |
|
134 } |
|
135 |
|
136 // ============================================================================= |
|
137 // ----------------------------------------------------------------------------- |
|
138 DEFINE_ACTION (SaveAs, CTRL_SHIFT (S)) |
|
139 { |
|
140 save (getCurrentDocument(), true); |
|
141 } |
|
142 |
|
143 // ============================================================================= |
|
144 // ----------------------------------------------------------------------------- |
|
145 DEFINE_ACTION (SaveAll, CTRL (L)) |
|
146 { |
|
147 for (LDDocument* file : g_loadedFiles) |
|
148 { |
|
149 if (file->isImplicit()) |
|
150 continue; |
|
151 |
|
152 save (file, false); |
|
153 } |
|
154 } |
|
155 |
|
156 // ============================================================================= |
|
157 // ----------------------------------------------------------------------------- |
|
158 DEFINE_ACTION (Close, CTRL (W)) |
|
159 { |
|
160 if (!getCurrentDocument()->isSafeToClose()) |
|
161 return; |
|
162 |
|
163 delete getCurrentDocument(); |
|
164 } |
|
165 |
|
166 // ============================================================================= |
|
167 // ----------------------------------------------------------------------------- |
|
168 DEFINE_ACTION (CloseAll, 0) |
|
169 { |
|
170 if (!safeToCloseAll()) |
|
171 return; |
|
172 |
|
173 closeAll(); |
|
174 } |
|
175 |
|
176 // ============================================================================= |
|
177 // ----------------------------------------------------------------------------- |
|
178 DEFINE_ACTION (Settings, 0) |
|
179 { |
|
180 (new ConfigDialog)->exec(); |
|
181 } |
|
182 |
|
183 // ============================================================================= |
|
184 // ----------------------------------------------------------------------------- |
|
185 DEFINE_ACTION (SetLDrawPath, 0) |
|
186 { |
|
187 (new LDrawPathDialog (true))->exec(); |
|
188 } |
|
189 |
|
190 // ============================================================================= |
|
191 // ----------------------------------------------------------------------------- |
|
192 DEFINE_ACTION (Exit, CTRL (Q)) |
|
193 { |
|
194 exit (0); |
|
195 } |
|
196 |
|
197 // ============================================================================= |
|
198 // ----------------------------------------------------------------------------- |
|
199 DEFINE_ACTION (NewSubfile, 0) |
|
200 { |
|
201 AddObjectDialog::staticDialog (LDObject::ESubfile, null); |
|
202 } |
|
203 |
|
204 // ============================================================================= |
|
205 // ----------------------------------------------------------------------------- |
|
206 DEFINE_ACTION (NewLine, 0) |
|
207 { |
|
208 AddObjectDialog::staticDialog (LDObject::ELine, null); |
|
209 } |
|
210 |
|
211 // ============================================================================= |
|
212 // ----------------------------------------------------------------------------- |
|
213 DEFINE_ACTION (NewTriangle, 0) |
|
214 { |
|
215 AddObjectDialog::staticDialog (LDObject::ETriangle, null); |
|
216 } |
|
217 |
|
218 // ============================================================================= |
|
219 // ----------------------------------------------------------------------------- |
|
220 DEFINE_ACTION (NewQuad, 0) |
|
221 { |
|
222 AddObjectDialog::staticDialog (LDObject::EQuad, null); |
|
223 } |
|
224 |
|
225 // ============================================================================= |
|
226 // ----------------------------------------------------------------------------- |
|
227 DEFINE_ACTION (NewCLine, 0) |
|
228 { |
|
229 AddObjectDialog::staticDialog (LDObject::ECondLine, null); |
|
230 } |
|
231 |
|
232 // ============================================================================= |
|
233 // ----------------------------------------------------------------------------- |
|
234 DEFINE_ACTION (NewComment, 0) |
|
235 { |
|
236 AddObjectDialog::staticDialog (LDObject::EComment, null); |
|
237 } |
|
238 |
|
239 // ============================================================================= |
|
240 // ----------------------------------------------------------------------------- |
|
241 DEFINE_ACTION (NewBFC, 0) |
|
242 { |
|
243 AddObjectDialog::staticDialog (LDObject::EBFC, null); |
|
244 } |
|
245 |
|
246 // ============================================================================= |
|
247 // ----------------------------------------------------------------------------- |
|
248 DEFINE_ACTION (NewVertex, 0) |
|
249 { |
|
250 AddObjectDialog::staticDialog (LDObject::EVertex, null); |
|
251 } |
|
252 |
|
253 // ============================================================================= |
|
254 // ----------------------------------------------------------------------------- |
|
255 DEFINE_ACTION (Edit, 0) |
|
256 { |
|
257 if (selection().size() != 1) |
|
258 return; |
|
259 |
|
260 LDObject* obj = selection() [0]; |
|
261 AddObjectDialog::staticDialog (obj->getType(), obj); |
|
262 } |
|
263 |
|
264 // ============================================================================= |
|
265 // ----------------------------------------------------------------------------- |
|
266 DEFINE_ACTION (Help, KEY (F1)) |
|
267 { |
|
268 } |
|
269 |
|
270 // ============================================================================= |
|
271 // ----------------------------------------------------------------------------- |
|
272 DEFINE_ACTION (About, 0) |
|
273 { |
|
274 AboutDialog().exec(); |
|
275 } |
|
276 |
|
277 // ============================================================================= |
|
278 // ----------------------------------------------------------------------------- |
|
279 DEFINE_ACTION (AboutQt, 0) |
|
280 { |
|
281 QMessageBox::aboutQt (g_win); |
|
282 } |
|
283 |
|
284 // ============================================================================= |
|
285 // ----------------------------------------------------------------------------- |
|
286 DEFINE_ACTION (SelectAll, CTRL (A)) |
|
287 { |
|
288 for (LDObject* obj : getCurrentDocument()->getObjects()) |
|
289 obj->select(); |
|
290 |
|
291 updateSelection(); |
|
292 } |
|
293 |
|
294 // ============================================================================= |
|
295 // ----------------------------------------------------------------------------- |
|
296 DEFINE_ACTION (SelectByColor, CTRL_SHIFT (A)) |
|
297 { |
|
298 int colnum = getSelectedColor(); |
|
299 |
|
300 if (colnum == -1) |
|
301 return; // no consensus on color |
|
302 |
|
303 getCurrentDocument()->clearSelection(); |
|
304 |
|
305 for (LDObject* obj : getCurrentDocument()->getObjects()) |
|
306 if (obj->getColor() == colnum) |
|
307 obj->select(); |
|
308 |
|
309 updateSelection(); |
|
310 } |
|
311 |
|
312 // ============================================================================= |
|
313 // ----------------------------------------------------------------------------- |
|
314 DEFINE_ACTION (SelectByType, 0) |
|
315 { |
|
316 if (selection().isEmpty()) |
|
317 return; |
|
318 |
|
319 LDObject::Type type = getUniformSelectedType(); |
|
320 |
|
321 if (type == LDObject::EUnidentified) |
|
322 return; |
|
323 |
|
324 // If we're selecting subfile references, the reference filename must also |
|
325 // be uniform. |
|
326 QString refName; |
|
327 |
|
328 if (type == LDObject::ESubfile) |
|
329 { |
|
330 refName = static_cast<LDSubfile*> (selection()[0])->getFileInfo()->getName(); |
|
331 |
|
332 for (LDObject* obj : selection()) |
|
333 if (static_cast<LDSubfile*> (obj)->getFileInfo()->getName() != refName) |
|
334 return; |
|
335 } |
|
336 |
|
337 getCurrentDocument()->clearSelection(); |
|
338 |
|
339 for (LDObject* obj : getCurrentDocument()->getObjects()) |
|
340 { |
|
341 if (obj->getType() != type) |
|
342 continue; |
|
343 |
|
344 if (type == LDObject::ESubfile && static_cast<LDSubfile*> (obj)->getFileInfo()->getName() != refName) |
|
345 continue; |
|
346 |
|
347 obj->select(); |
|
348 } |
|
349 |
|
350 updateSelection(); |
|
351 } |
|
352 |
|
353 // ============================================================================= |
|
354 // ----------------------------------------------------------------------------- |
|
355 DEFINE_ACTION (GridCoarse, 0) |
|
356 { |
|
357 grid = Grid::Coarse; |
|
358 updateGridToolBar(); |
|
359 } |
|
360 |
|
361 DEFINE_ACTION (GridMedium, 0) |
|
362 { |
|
363 grid = Grid::Medium; |
|
364 updateGridToolBar(); |
|
365 } |
|
366 |
|
367 DEFINE_ACTION (GridFine, 0) |
|
368 { |
|
369 grid = Grid::Fine; |
|
370 updateGridToolBar(); |
|
371 } |
|
372 |
|
373 // ============================================================================= |
|
374 // ----------------------------------------------------------------------------- |
|
375 DEFINE_ACTION (ResetView, CTRL (0)) |
|
376 { |
|
377 R()->resetAngles(); |
|
378 R()->update(); |
|
379 } |
|
380 |
|
381 // ============================================================================= |
|
382 // ----------------------------------------------------------------------------- |
|
383 DEFINE_ACTION (InsertFrom, 0) |
|
384 { |
|
385 QString fname = QFileDialog::getOpenFileName(); |
|
386 int idx = getInsertionPoint(); |
|
387 |
|
388 if (!fname.length()) |
|
389 return; |
|
390 |
|
391 QFile f (fname); |
|
392 |
|
393 if (!f.open (QIODevice::ReadOnly)) |
|
394 { |
|
395 critical (fmt ("Couldn't open %1 (%2)", fname, f.errorString())); |
|
396 return; |
|
397 } |
|
398 |
|
399 LDObjectList objs = loadFileContents (&f, null); |
|
400 |
|
401 getCurrentDocument()->clearSelection(); |
|
402 |
|
403 for (LDObject* obj : objs) |
|
404 { |
|
405 getCurrentDocument()->insertObj (idx, obj); |
|
406 obj->select(); |
|
407 R()->compileObject (obj); |
|
408 |
|
409 idx++; |
|
410 } |
|
411 |
|
412 refresh(); |
|
413 scrollToSelection(); |
|
414 } |
|
415 |
|
416 // ============================================================================= |
|
417 // ----------------------------------------------------------------------------- |
|
418 DEFINE_ACTION (ExportTo, 0) |
|
419 { |
|
420 if (selection().isEmpty()) |
|
421 return; |
|
422 |
|
423 QString fname = QFileDialog::getSaveFileName(); |
|
424 |
|
425 if (fname.length() == 0) |
|
426 return; |
|
427 |
|
428 QFile file (fname); |
|
429 |
|
430 if (!file.open (QIODevice::WriteOnly | QIODevice::Text)) |
|
431 { |
|
432 critical (fmt ("Unable to open %1 for writing (%2)", fname, file.errorString())); |
|
433 return; |
|
434 } |
|
435 |
|
436 for (LDObject* obj : selection()) |
|
437 { |
|
438 QString contents = obj->raw(); |
|
439 QByteArray data = contents.toUtf8(); |
|
440 file.write (data, data.size()); |
|
441 file.write ("\r\n", 2); |
|
442 } |
|
443 } |
|
444 |
|
445 // ============================================================================= |
|
446 // ----------------------------------------------------------------------------- |
|
447 DEFINE_ACTION (InsertRaw, 0) |
|
448 { |
|
449 int idx = getInsertionPoint(); |
|
450 |
|
451 QDialog* const dlg = new QDialog; |
|
452 QVBoxLayout* const layout = new QVBoxLayout; |
|
453 QTextEdit* const te_edit = new QTextEdit; |
|
454 QDialogButtonBox* const bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); |
|
455 |
|
456 layout->addWidget (te_edit); |
|
457 layout->addWidget (bbx_buttons); |
|
458 dlg->setLayout (layout); |
|
459 dlg->setWindowTitle (APPNAME ": Insert Raw"); |
|
460 dlg->connect (bbx_buttons, SIGNAL (accepted()), dlg, SLOT (accept())); |
|
461 dlg->connect (bbx_buttons, SIGNAL (rejected()), dlg, SLOT (reject())); |
|
462 |
|
463 if (dlg->exec() == false) |
|
464 return; |
|
465 |
|
466 getCurrentDocument()->clearSelection(); |
|
467 |
|
468 for (QString line : QString (te_edit->toPlainText()).split ("\n")) |
|
469 { |
|
470 LDObject* obj = parseLine (line); |
|
471 |
|
472 getCurrentDocument()->insertObj (idx, obj); |
|
473 obj->select(); |
|
474 R()->compileObject (obj); |
|
475 idx++; |
|
476 } |
|
477 |
|
478 refresh(); |
|
479 scrollToSelection(); |
|
480 } |
|
481 |
|
482 // ============================================================================= |
|
483 // ----------------------------------------------------------------------------- |
|
484 DEFINE_ACTION (Screenshot, 0) |
|
485 { |
|
486 setlocale (LC_ALL, "C"); |
|
487 |
|
488 int w, h; |
|
489 uchar* imgdata = R()->getScreencap (w, h); |
|
490 QImage img = imageFromScreencap (imgdata, w, h); |
|
491 |
|
492 QString root = basename (getCurrentDocument()->getName()); |
|
493 |
|
494 if (root.right (4) == ".dat") |
|
495 root.chop (4); |
|
496 |
|
497 QString defaultname = (root.length() > 0) ? fmt ("%1.png", root) : ""; |
|
498 QString fname = QFileDialog::getSaveFileName (g_win, "Save Screencap", defaultname, |
|
499 "PNG images (*.png);;JPG images (*.jpg);;BMP images (*.bmp);;All Files (*.*)"); |
|
500 |
|
501 if (fname.length() > 0 && !img.save (fname)) |
|
502 critical (fmt ("Couldn't open %1 for writing to save screencap: %2", fname, strerror (errno))); |
|
503 |
|
504 delete[] imgdata; |
|
505 } |
|
506 |
|
507 // ============================================================================= |
|
508 // ----------------------------------------------------------------------------- |
|
509 extern_cfg (Bool, gl_axes); |
|
510 DEFINE_ACTION (Axes, 0) |
|
511 { |
|
512 gl_axes = !gl_axes; |
|
513 updateActions(); |
|
514 R()->update(); |
|
515 } |
|
516 |
|
517 // ============================================================================= |
|
518 // ----------------------------------------------------------------------------- |
|
519 DEFINE_ACTION (VisibilityToggle, 0) |
|
520 { |
|
521 for (LDObject* obj : selection()) |
|
522 obj->toggleHidden(); |
|
523 |
|
524 refresh(); |
|
525 } |
|
526 |
|
527 // ============================================================================= |
|
528 // ----------------------------------------------------------------------------- |
|
529 DEFINE_ACTION (VisibilityHide, 0) |
|
530 { |
|
531 for (LDObject* obj : selection()) |
|
532 obj->setHidden (true); |
|
533 |
|
534 refresh(); |
|
535 } |
|
536 |
|
537 // ============================================================================= |
|
538 // ----------------------------------------------------------------------------- |
|
539 DEFINE_ACTION (VisibilityReveal, 0) |
|
540 { |
|
541 for (LDObject* obj : selection()) |
|
542 obj->setHidden (false); |
|
543 refresh(); |
|
544 } |
|
545 |
|
546 // ============================================================================= |
|
547 // ----------------------------------------------------------------------------- |
|
548 DEFINE_ACTION (Wireframe, 0) |
|
549 { |
|
550 gl_wireframe = !gl_wireframe; |
|
551 R()->refresh(); |
|
552 } |
|
553 |
|
554 // ============================================================================= |
|
555 // ----------------------------------------------------------------------------- |
|
556 DEFINE_ACTION (SetOverlay, 0) |
|
557 { |
|
558 OverlayDialog dlg; |
|
559 |
|
560 if (!dlg.exec()) |
|
561 return; |
|
562 |
|
563 R()->setupOverlay ((GL::EFixedCamera) dlg.camera(), dlg.fpath(), dlg.ofsx(), |
|
564 dlg.ofsy(), dlg.lwidth(), dlg.lheight()); |
|
565 } |
|
566 |
|
567 // ============================================================================= |
|
568 // ----------------------------------------------------------------------------- |
|
569 DEFINE_ACTION (ClearOverlay, 0) |
|
570 { |
|
571 R()->clearOverlay(); |
|
572 } |
|
573 |
|
574 // ============================================================================= |
|
575 // ----------------------------------------------------------------------------- |
|
576 DEFINE_ACTION (ModeSelect, CTRL (1)) |
|
577 { |
|
578 R()->setEditMode (ESelectMode); |
|
579 } |
|
580 |
|
581 // ============================================================================= |
|
582 // ----------------------------------------------------------------------------- |
|
583 DEFINE_ACTION (ModeDraw, CTRL (2)) |
|
584 { |
|
585 R()->setEditMode (EDrawMode); |
|
586 } |
|
587 |
|
588 // ============================================================================= |
|
589 // ----------------------------------------------------------------------------- |
|
590 DEFINE_ACTION (ModeCircle, CTRL (3)) |
|
591 { |
|
592 R()->setEditMode (ECircleMode); |
|
593 } |
|
594 |
|
595 // ============================================================================= |
|
596 // ----------------------------------------------------------------------------- |
|
597 DEFINE_ACTION (DrawAngles, 0) |
|
598 { |
|
599 gl_drawangles = !gl_drawangles; |
|
600 R()->refresh(); |
|
601 } |
|
602 |
|
603 // ============================================================================= |
|
604 // ----------------------------------------------------------------------------- |
|
605 DEFINE_ACTION (SetDrawDepth, 0) |
|
606 { |
|
607 if (R()->camera() == GL::EFreeCamera) |
|
608 return; |
|
609 |
|
610 bool ok; |
|
611 double depth = QInputDialog::getDouble (g_win, "Set Draw Depth", |
|
612 fmt ("Depth value for %1 Camera:", R()->getCameraName()), |
|
613 R()->getDepthValue(), -10000.0f, 10000.0f, 3, &ok); |
|
614 |
|
615 if (ok) |
|
616 R()->setDepthValue (depth); |
|
617 } |
|
618 |
|
619 #if 0 |
|
620 // This is a test to draw a dummy axle. Meant to be used as a primitive gallery, |
|
621 // but I can't figure how to generate these pictures properly. Multi-threading |
|
622 // these is an immense pain. |
|
623 DEFINE_ACTION (testpic, "Test picture", "", "", (0)) |
|
624 { |
|
625 LDDocument* file = getFile ("axle.dat"); |
|
626 setlocale (LC_ALL, "C"); |
|
627 |
|
628 if (!file) |
|
629 { |
|
630 critical ("couldn't load axle.dat"); |
|
631 return; |
|
632 } |
|
633 |
|
634 int w, h; |
|
635 |
|
636 GLRenderer* rend = new GLRenderer; |
|
637 rend->resize (64, 64); |
|
638 rend->setAttribute (Qt::WA_DontShowOnScreen); |
|
639 rend->show(); |
|
640 rend->setFile (file); |
|
641 rend->setDrawOnly (true); |
|
642 rend->compileAllObjects(); |
|
643 rend->initGLData(); |
|
644 rend->drawGLScene(); |
|
645 |
|
646 uchar* imgdata = rend->screencap (w, h); |
|
647 QImage img = imageFromScreencap (imgdata, w, h); |
|
648 |
|
649 if (img.isNull()) |
|
650 { |
|
651 critical ("Failed to create the image!\n"); |
|
652 } |
|
653 else |
|
654 { |
|
655 QLabel* label = new QLabel; |
|
656 QDialog* dlg = new QDialog; |
|
657 label->setPixmap (QPixmap::fromImage (img)); |
|
658 QVBoxLayout* layout = new QVBoxLayout (dlg); |
|
659 layout->addWidget (label); |
|
660 dlg->exec(); |
|
661 } |
|
662 |
|
663 delete[] imgdata; |
|
664 rend->deleteLater(); |
|
665 } |
|
666 #endif |
|
667 |
|
668 // ============================================================================= |
|
669 // ----------------------------------------------------------------------------- |
|
670 DEFINE_ACTION (ScanPrimitives, 0) |
|
671 { |
|
672 PrimitiveScanner::start(); |
|
673 } |
|
674 |
|
675 // ============================================================================= |
|
676 // ----------------------------------------------------------------------------- |
|
677 DEFINE_ACTION (BFCView, SHIFT (B)) |
|
678 { |
|
679 gl_colorbfc = !gl_colorbfc; |
|
680 updateActions(); |
|
681 R()->refresh(); |
|
682 } |
|
683 |
|
684 // ============================================================================= |
|
685 // ----------------------------------------------------------------------------- |
|
686 DEFINE_ACTION (JumpTo, CTRL (G)) |
|
687 { |
|
688 bool ok; |
|
689 int defval = 0; |
|
690 LDObject* obj; |
|
691 |
|
692 if (selection().size() == 1) |
|
693 defval = selection()[0]->getIndex(); |
|
694 |
|
695 int idx = QInputDialog::getInt (null, "Go to line", "Go to line:", defval, |
|
696 1, getCurrentDocument()->getObjectCount(), 1, &ok); |
|
697 |
|
698 if (!ok || (obj = getCurrentDocument()->getObject (idx - 1)) == null) |
|
699 return; |
|
700 |
|
701 getCurrentDocument()->clearSelection(); |
|
702 obj->select(); |
|
703 updateSelection(); |
|
704 } |
|
705 |
|
706 // ============================================================================= |
|
707 // ----------------------------------------------------------------------------- |
|
708 DEFINE_ACTION (SubfileSelection, 0) |
|
709 { |
|
710 if (selection().size() == 0) |
|
711 return; |
|
712 |
|
713 QString parentpath = getCurrentDocument()->getFullPath(); |
|
714 |
|
715 // BFC type of the new subfile - it shall inherit the BFC type of the parent document |
|
716 LDBFC::Type bfctype = LDBFC::NoCertify; |
|
717 |
|
718 // Dirname of the new subfile |
|
719 QString subdirname = dirname (parentpath); |
|
720 |
|
721 // Title of the new subfile |
|
722 QString subtitle; |
|
723 |
|
724 // Comment containing the title of the parent document |
|
725 LDComment* titleobj = dynamic_cast<LDComment*> (getCurrentDocument()->getObject (0)); |
|
726 |
|
727 // License text for the subfile |
|
728 QString license = getLicenseText (ld_defaultlicense); |
|
729 |
|
730 // LDraw code body of the new subfile (i.e. code of the selection) |
|
731 QStringList code; |
|
732 |
|
733 // Full path of the subfile to be |
|
734 QString fullsubname; |
|
735 |
|
736 // Where to insert the subfile reference? |
|
737 int refidx = selection()[0]->getIndex(); |
|
738 |
|
739 // Determine title of subfile |
|
740 if (titleobj != null) |
|
741 subtitle = "~" + titleobj->text; |
|
742 else |
|
743 subtitle = "~subfile"; |
|
744 |
|
745 // Remove duplicate tildes |
|
746 while (subtitle[0] == '~' && subtitle[1] == '~') |
|
747 subtitle.remove (0, 1); |
|
748 |
|
749 // If this the parent document isn't already in s/, we need to stuff it into |
|
750 // a subdirectory named s/. Ensure it exists! |
|
751 QString topdirname = basename (dirname (getCurrentDocument()->getFullPath())); |
|
752 |
|
753 if (topdirname != "s") |
|
754 { |
|
755 QString desiredPath = subdirname + "/s"; |
|
756 QString title = tr ("Create subfile directory?"); |
|
757 QString text = fmt (tr ("The directory <b>%1</b> is suggested for " |
|
758 "subfiles. This directory does not exist, create it?"), desiredPath); |
|
759 |
|
760 if (QDir (desiredPath).exists() || confirm (title, text)) |
|
761 { |
|
762 subdirname = desiredPath; |
|
763 QDir().mkpath (subdirname); |
|
764 } |
|
765 } |
|
766 |
|
767 // Determine the body of the name of the subfile |
|
768 if (!parentpath.isEmpty()) |
|
769 { |
|
770 if (parentpath.endsWith (".dat")) |
|
771 parentpath.chop (4); |
|
772 |
|
773 // Remove the s?? suffix if it's there, otherwise we'll get filenames |
|
774 // like s01s01.dat when subfiling subfiles. |
|
775 QRegExp subfilesuffix ("s[0-9][0-9]$"); |
|
776 if (subfilesuffix.indexIn (parentpath) != -1) |
|
777 parentpath.chop (subfilesuffix.matchedLength()); |
|
778 |
|
779 int subidx = 1; |
|
780 QString digits; |
|
781 QFile f; |
|
782 QString testfname; |
|
783 |
|
784 do |
|
785 { |
|
786 digits.setNum (subidx++); |
|
787 |
|
788 // pad it with a zero |
|
789 if (digits.length() == 1) |
|
790 digits.prepend ("0"); |
|
791 |
|
792 fullsubname = subdirname + "/" + basename (parentpath) + "s" + digits + ".dat"; |
|
793 } while (findDocument ("s\\" + basename (fullsubname)) != null || QFile (fullsubname).exists()); |
|
794 } |
|
795 |
|
796 // Determine the BFC winding type used in the main document - it is to |
|
797 // be carried over to the subfile. |
|
798 for (LDObject* obj : getCurrentDocument()->getObjects()) |
|
799 { |
|
800 LDBFC* bfc = dynamic_cast<LDBFC*> (obj); |
|
801 |
|
802 if (!bfc) |
|
803 continue; |
|
804 |
|
805 LDBFC::Type a = bfc->type; |
|
806 |
|
807 if (a == LDBFC::CertifyCCW || a == LDBFC::CertifyCW || a == LDBFC::NoCertify) |
|
808 { |
|
809 bfctype = a; |
|
810 break; |
|
811 } |
|
812 } |
|
813 |
|
814 // Get the body of the document in LDraw code |
|
815 for (LDObject* obj : selection()) |
|
816 code << obj->raw(); |
|
817 |
|
818 // Create the new subfile document |
|
819 LDDocument* doc = new LDDocument; |
|
820 doc->setImplicit (false); |
|
821 doc->setFullPath (fullsubname); |
|
822 doc->setName (LDDocument::shortenName (fullsubname)); |
|
823 doc->addObjects ( |
|
824 { |
|
825 new LDComment (subtitle), |
|
826 new LDComment ("Name: "), |
|
827 new LDComment (fmt ("Author: %1 [%2]", ld_defaultname, ld_defaultuser)), |
|
828 new LDComment (fmt ("!LDRAW_ORG Unofficial_Subpart")), |
|
829 (license != "" ? new LDComment (license) : null), |
|
830 new LDEmpty, |
|
831 new LDBFC (bfctype), |
|
832 new LDEmpty, |
|
833 }); |
|
834 |
|
835 // Add the actual subfile code to the new document |
|
836 for (QString line : code) |
|
837 { |
|
838 LDObject* obj = parseLine (line); |
|
839 doc->addObject (obj); |
|
840 } |
|
841 |
|
842 // Try save it |
|
843 if (save (doc, true)) |
|
844 { |
|
845 // Remove the selection now |
|
846 for (LDObject* obj : selection()) |
|
847 obj->deleteSelf(); |
|
848 |
|
849 // Compile all objects in the new subfile |
|
850 for (LDObject* obj : doc->getObjects()) |
|
851 R()->compileObject (obj); |
|
852 |
|
853 g_loadedFiles << doc; |
|
854 |
|
855 // Add a reference to the new subfile to where the selection was |
|
856 LDSubfile* ref = new LDSubfile(); |
|
857 ref->setColor (maincolor); |
|
858 ref->setFileInfo (doc); |
|
859 ref->setPosition (g_origin); |
|
860 ref->setTransform (g_identity); |
|
861 getCurrentDocument()->insertObj (refidx, ref); |
|
862 R()->compileObject (ref); |
|
863 |
|
864 // Refresh stuff |
|
865 updateDocumentList(); |
|
866 doFullRefresh(); |
|
867 } |
|
868 else |
|
869 { |
|
870 // Failed to save. |
|
871 delete doc; |
|
872 } |
|
873 } |