120 } |
121 } |
121 |
122 |
122 // ============================================================================= |
123 // ============================================================================= |
123 // ----------------------------------------------------------------------------- |
124 // ----------------------------------------------------------------------------- |
124 KeySequenceConfig* ForgeWindow::shortcutForAction (QAction* act) |
125 KeySequenceConfig* ForgeWindow::shortcutForAction (QAction* act) |
125 { str keycfgname = fmt ("key_%1", act->objectName()); |
126 { |
|
127 str keycfgname = fmt ("key_%1", act->objectName()); |
126 return KeySequenceConfig::getByName (keycfgname); |
128 return KeySequenceConfig::getByName (keycfgname); |
127 } |
129 } |
128 |
130 |
129 // ============================================================================= |
131 // ============================================================================= |
130 // ----------------------------------------------------------------------------- |
132 // ----------------------------------------------------------------------------- |
131 void ForgeWindow::updateActionShortcuts() |
133 void ForgeWindow::updateActionShortcuts() |
132 { for (QAction* act : findChildren<QAction*>()) |
134 { |
133 { KeySequenceConfig* cfg = shortcutForAction (act); |
135 for (QAction* act : findChildren<QAction*>()) |
|
136 { |
|
137 KeySequenceConfig* cfg = shortcutForAction (act); |
134 |
138 |
135 if (cfg) |
139 if (cfg) |
136 act->setShortcut (cfg->getValue()); |
140 act->setShortcut (cfg->getValue()); |
137 } |
141 } |
138 } |
142 } |
139 |
143 |
140 // ============================================================================= |
144 // ============================================================================= |
141 // ----------------------------------------------------------------------------- |
145 // ----------------------------------------------------------------------------- |
142 void ForgeWindow::slot_action() |
146 void ForgeWindow::slot_action() |
143 { // Get the name of the sender object and use it to compose the slot name. |
147 { |
|
148 // Get the name of the sender object and use it to compose the slot name. |
144 str methodName = fmt ("slot_%1", sender()->objectName()); |
149 str methodName = fmt ("slot_%1", sender()->objectName()); |
145 |
150 |
146 #ifdef DEBUG |
151 #ifdef DEBUG |
147 log ("Action %1 triggered", sender()->objectName()); |
152 log ("Action %1 triggered", sender()->objectName()); |
148 #endif |
153 #endif |
153 } |
158 } |
154 |
159 |
155 // ============================================================================= |
160 // ============================================================================= |
156 // ----------------------------------------------------------------------------- |
161 // ----------------------------------------------------------------------------- |
157 void ForgeWindow::endAction() |
162 void ForgeWindow::endAction() |
158 { // Add a step in the history now. |
163 { |
|
164 // Add a step in the history now. |
159 getCurrentDocument()->addHistoryStep(); |
165 getCurrentDocument()->addHistoryStep(); |
160 |
166 |
161 // Update the list item of the current file - we may need to draw an icon |
167 // Update the list item of the current file - we may need to draw an icon |
162 // now that marks it as having unsaved changes. |
168 // now that marks it as having unsaved changes. |
163 updateDocumentListItem (getCurrentDocument()); |
169 updateDocumentListItem (getCurrentDocument()); |
164 } |
170 } |
165 |
171 |
166 // ============================================================================= |
172 // ============================================================================= |
167 // ----------------------------------------------------------------------------- |
173 // ----------------------------------------------------------------------------- |
168 void ForgeWindow::slot_lastSecondCleanup() |
174 void ForgeWindow::slot_lastSecondCleanup() |
169 { delete m_renderer; |
175 { |
|
176 delete m_renderer; |
170 delete ui; |
177 delete ui; |
171 } |
178 } |
172 |
179 |
173 // ============================================================================= |
180 // ============================================================================= |
174 // ----------------------------------------------------------------------------- |
181 // ----------------------------------------------------------------------------- |
175 void ForgeWindow::updateRecentFilesMenu() |
182 void ForgeWindow::updateRecentFilesMenu() |
176 { // First, clear any items in the recent files menu |
183 { |
|
184 // First, clear any items in the recent files menu |
177 for (QAction * recent : m_recentFiles) |
185 for (QAction * recent : m_recentFiles) |
178 delete recent; |
186 delete recent; |
179 |
187 |
180 m_recentFiles.clear(); |
188 m_recentFiles.clear(); |
181 |
189 |
182 QAction* first = null; |
190 QAction* first = null; |
183 |
191 |
184 for (const QVariant& it : io_recentfiles) |
192 for (const QVariant& it : io_recentfiles) |
185 { str file = it.toString(); |
193 { |
|
194 str file = it.toString(); |
186 QAction* recent = new QAction (getIcon ("open-recent"), file, this); |
195 QAction* recent = new QAction (getIcon ("open-recent"), file, this); |
187 |
196 |
188 connect (recent, SIGNAL (triggered()), this, SLOT (slot_recentFile())); |
197 connect (recent, SIGNAL (triggered()), this, SLOT (slot_recentFile())); |
189 ui->menuOpenRecent->insertAction (first, recent); |
198 ui->menuOpenRecent->insertAction (first, recent); |
190 m_recentFiles << recent; |
199 m_recentFiles << recent; |
193 } |
202 } |
194 |
203 |
195 // ============================================================================= |
204 // ============================================================================= |
196 // ----------------------------------------------------------------------------- |
205 // ----------------------------------------------------------------------------- |
197 QList<LDQuickColor> quickColorsFromConfig() |
206 QList<LDQuickColor> quickColorsFromConfig() |
198 { QList<LDQuickColor> colors; |
207 { |
|
208 QList<LDQuickColor> colors; |
199 |
209 |
200 for (str colorname : gui_colortoolbar.split (":")) |
210 for (str colorname : gui_colortoolbar.split (":")) |
201 { if (colorname == "|") |
211 { |
|
212 if (colorname == "|") |
202 colors << LDQuickColor::getSeparator(); |
213 colors << LDQuickColor::getSeparator(); |
203 else |
214 else |
204 { LDColor* col = getColor (colorname.toLong()); |
215 { |
|
216 LDColor* col = getColor (colorname.toLong()); |
205 |
217 |
206 if (col != null) |
218 if (col != null) |
207 colors << LDQuickColor (col, null); |
219 colors << LDQuickColor (col, null); |
208 } |
220 } |
209 } |
221 } |
212 } |
224 } |
213 |
225 |
214 // ============================================================================= |
226 // ============================================================================= |
215 // ----------------------------------------------------------------------------- |
227 // ----------------------------------------------------------------------------- |
216 void ForgeWindow::updateToolBars() |
228 void ForgeWindow::updateToolBars() |
217 { m_colorButtons.clear(); |
229 { |
|
230 m_colorButtons.clear(); |
218 ui->colorToolbar->clear(); |
231 ui->colorToolbar->clear(); |
219 |
232 |
220 for (LDQuickColor& entry : m_quickColors) |
233 for (LDQuickColor& entry : m_quickColors) |
221 { if (entry.isSeparator()) |
234 { |
|
235 if (entry.isSeparator()) |
222 ui->colorToolbar->addSeparator(); |
236 ui->colorToolbar->addSeparator(); |
223 else |
237 else |
224 { QToolButton* colorButton = new QToolButton; |
238 { |
|
239 QToolButton* colorButton = new QToolButton; |
225 colorButton->setIcon (makeColorIcon (entry.getColor(), 22)); |
240 colorButton->setIcon (makeColorIcon (entry.getColor(), 22)); |
226 colorButton->setIconSize (QSize (22, 22)); |
241 colorButton->setIconSize (QSize (22, 22)); |
227 colorButton->setToolTip (entry.getColor()->name); |
242 colorButton->setToolTip (entry.getColor()->name); |
228 |
243 |
229 connect (colorButton, SIGNAL (clicked()), this, SLOT (slot_quickColor())); |
244 connect (colorButton, SIGNAL (clicked()), this, SLOT (slot_quickColor())); |
238 } |
253 } |
239 |
254 |
240 // ============================================================================= |
255 // ============================================================================= |
241 // ----------------------------------------------------------------------------- |
256 // ----------------------------------------------------------------------------- |
242 void ForgeWindow::updateGridToolBar() |
257 void ForgeWindow::updateGridToolBar() |
243 { // Ensure that the current grid - and only the current grid - is selected. |
258 { |
|
259 // Ensure that the current grid - and only the current grid - is selected. |
244 ui->actionGridCoarse->setChecked (grid == Grid::Coarse); |
260 ui->actionGridCoarse->setChecked (grid == Grid::Coarse); |
245 ui->actionGridMedium->setChecked (grid == Grid::Medium); |
261 ui->actionGridMedium->setChecked (grid == Grid::Medium); |
246 ui->actionGridFine->setChecked (grid == Grid::Fine); |
262 ui->actionGridFine->setChecked (grid == Grid::Fine); |
247 } |
263 } |
248 |
264 |
249 // ============================================================================= |
265 // ============================================================================= |
250 // ----------------------------------------------------------------------------- |
266 // ----------------------------------------------------------------------------- |
251 void ForgeWindow::updateTitle() |
267 void ForgeWindow::updateTitle() |
252 { str title = fmt (APPNAME " %1", fullVersionString()); |
268 { |
|
269 str title = fmt (APPNAME " %1", fullVersionString()); |
253 |
270 |
254 // Append our current file if we have one |
271 // Append our current file if we have one |
255 if (getCurrentDocument()) |
272 if (getCurrentDocument()) |
256 { if (getCurrentDocument()->getName().length() > 0) |
273 { |
|
274 if (getCurrentDocument()->getName().length() > 0) |
257 title += fmt (": %1", basename (getCurrentDocument()->getName())); |
275 title += fmt (": %1", basename (getCurrentDocument()->getName())); |
258 else |
276 else |
259 title += fmt (": <anonymous>"); |
277 title += fmt (": <anonymous>"); |
260 |
278 |
261 if (getCurrentDocument()->getObjectCount() > 0 && |
279 if (getCurrentDocument()->getObjectCount() > 0 && |
262 getCurrentDocument()->getObject (0)->getType() == LDObject::Comment) |
280 getCurrentDocument()->getObject (0)->getType() == LDObject::Comment) |
263 { // Append title |
281 { |
|
282 // Append title |
264 LDComment* comm = static_cast<LDComment*> (getCurrentDocument()->getObject (0)); |
283 LDComment* comm = static_cast<LDComment*> (getCurrentDocument()->getObject (0)); |
265 title += fmt (": %1", comm->text); |
284 title += fmt (": %1", comm->text); |
266 } |
285 } |
267 |
286 |
268 if (getCurrentDocument()->getHistory()->getPosition() != getCurrentDocument()->getSavePosition()) |
287 if (getCurrentDocument()->getHistory()->getPosition() != getCurrentDocument()->getSavePosition()) |
327 |
351 |
328 case LDObject::Line: |
352 case LDObject::Line: |
329 case LDObject::Triangle: |
353 case LDObject::Triangle: |
330 case LDObject::Quad: |
354 case LDObject::Quad: |
331 case LDObject::CondLine: |
355 case LDObject::CondLine: |
332 { for (int i = 0; i < obj->vertices(); ++i) |
356 { |
333 { if (i != 0) |
357 for (int i = 0; i < obj->vertices(); ++i) |
|
358 { |
|
359 if (i != 0) |
334 descr += ", "; |
360 descr += ", "; |
335 |
361 |
336 descr += obj->getVertex (i).stringRep (true); |
362 descr += obj->getVertex (i).stringRep (true); |
337 } |
363 } |
338 } break; |
364 } break; |
339 |
365 |
340 case LDObject::Error: |
366 case LDObject::Error: |
341 { descr = fmt ("ERROR: %1", obj->raw()); |
367 { |
|
368 descr = fmt ("ERROR: %1", obj->raw()); |
342 } break; |
369 } break; |
343 |
370 |
344 case LDObject::Vertex: |
371 case LDObject::Vertex: |
345 { descr = static_cast<LDVertex*> (obj)->pos.stringRep (true); |
372 { |
|
373 descr = static_cast<LDVertex*> (obj)->pos.stringRep (true); |
346 } break; |
374 } break; |
347 |
375 |
348 case LDObject::Subfile: |
376 case LDObject::Subfile: |
349 { LDSubfile* ref = static_cast<LDSubfile*> (obj); |
377 { |
|
378 LDSubfile* ref = static_cast<LDSubfile*> (obj); |
350 |
379 |
351 descr = fmt ("%1 %2, (", ref->getFileInfo()->getDisplayName(), ref->getPosition().stringRep (true)); |
380 descr = fmt ("%1 %2, (", ref->getFileInfo()->getDisplayName(), ref->getPosition().stringRep (true)); |
352 |
381 |
353 for (int i = 0; i < 9; ++i) |
382 for (int i = 0; i < 9; ++i) |
354 descr += fmt ("%1%2", ref->getTransform()[i], (i != 8) ? " " : ""); |
383 descr += fmt ("%1%2", ref->getTransform()[i], (i != 8) ? " " : ""); |
355 |
384 |
356 descr += ')'; |
385 descr += ')'; |
357 } break; |
386 } break; |
358 |
387 |
359 case LDObject::BFC: |
388 case LDObject::BFC: |
360 { descr = LDBFC::statements[static_cast<LDBFC*> (obj)->type]; |
389 { |
|
390 descr = LDBFC::statements[static_cast<LDBFC*> (obj)->type]; |
361 } break; |
391 } break; |
362 |
392 |
363 case LDObject::Overlay: |
393 case LDObject::Overlay: |
364 { LDOverlay* ovl = static_cast<LDOverlay*> (obj); |
394 { |
|
395 LDOverlay* ovl = static_cast<LDOverlay*> (obj); |
365 descr = fmt ("[%1] %2 (%3, %4), %5 x %6", g_CameraNames[ovl->getCamera()], |
396 descr = fmt ("[%1] %2 (%3, %4), %5 x %6", g_CameraNames[ovl->getCamera()], |
366 basename (ovl->getFileName()), ovl->getX(), ovl->getY(), |
397 basename (ovl->getFileName()), ovl->getX(), ovl->getY(), |
367 ovl->getWidth(), ovl->getHeight()); |
398 ovl->getWidth(), ovl->getHeight()); |
368 } |
399 } |
369 break; |
400 break; |
370 |
401 |
371 default: |
402 default: |
372 { descr = obj->getTypeName(); |
403 { |
|
404 descr = obj->getTypeName(); |
373 } break; |
405 } break; |
374 } |
406 } |
375 |
407 |
376 QListWidgetItem* item = new QListWidgetItem (descr); |
408 QListWidgetItem* item = new QListWidgetItem (descr); |
377 item->setIcon (getIcon (obj->getTypeName())); |
409 item->setIcon (getIcon (obj->getTypeName())); |
378 |
410 |
379 // Use italic font if hidden |
411 // Use italic font if hidden |
380 if (obj->isHidden()) |
412 if (obj->isHidden()) |
381 { QFont font = item->font(); |
413 { |
|
414 QFont font = item->font(); |
382 font.setItalic (true); |
415 font.setItalic (true); |
383 item->setFont (font); |
416 item->setFont (font); |
384 } |
417 } |
385 |
418 |
386 // Color gibberish orange on red so it stands out. |
419 // Color gibberish orange on red so it stands out. |
387 if (obj->getType() == LDObject::Error) |
420 if (obj->getType() == LDObject::Error) |
388 { item->setBackground (QColor ("#AA0000")); |
421 { |
|
422 item->setBackground (QColor ("#AA0000")); |
389 item->setForeground (QColor ("#FFAA00")); |
423 item->setForeground (QColor ("#FFAA00")); |
390 } |
424 } |
391 elif (lv_colorize && obj->isColored() && obj->getColor() != maincolor && obj->getColor() != edgecolor) |
425 elif (lv_colorize && obj->isColored() && obj->getColor() != maincolor && obj->getColor() != edgecolor) |
392 { // If the object isn't in the main or edge color, draw this |
426 { |
|
427 // If the object isn't in the main or edge color, draw this |
393 // list entry in said color. |
428 // list entry in said color. |
394 LDColor* col = getColor (obj->getColor()); |
429 LDColor* col = getColor (obj->getColor()); |
395 |
430 |
396 if (col) |
431 if (col) |
397 item->setForeground (col->faceColor); |
432 item->setForeground (col->faceColor); |
407 } |
442 } |
408 |
443 |
409 // ============================================================================= |
444 // ============================================================================= |
410 // ----------------------------------------------------------------------------- |
445 // ----------------------------------------------------------------------------- |
411 void ForgeWindow::scrollToSelection() |
446 void ForgeWindow::scrollToSelection() |
412 { if (selection().isEmpty()) |
447 { |
|
448 if (selection().isEmpty()) |
413 return; |
449 return; |
414 |
450 |
415 LDObject* obj = selection().last(); |
451 LDObject* obj = selection().last(); |
416 ui->objectList->scrollToItem (obj->qObjListEntry); |
452 ui->objectList->scrollToItem (obj->qObjListEntry); |
417 } |
453 } |
418 |
454 |
419 // ============================================================================= |
455 // ============================================================================= |
420 // ----------------------------------------------------------------------------- |
456 // ----------------------------------------------------------------------------- |
421 void ForgeWindow::slot_selectionChanged() |
457 void ForgeWindow::slot_selectionChanged() |
422 { if (g_isSelectionLocked == true || getCurrentDocument() == null) |
458 { |
|
459 if (g_isSelectionLocked == true || getCurrentDocument() == null) |
423 return; |
460 return; |
424 |
461 |
425 // Update the shared selection array, though don't do this if this was |
462 // Update the shared selection array, though don't do this if this was |
426 // called during GL picking, in which case the GL renderer takes care |
463 // called during GL picking, in which case the GL renderer takes care |
427 // of the selection. |
464 // of the selection. |
454 } |
494 } |
455 |
495 |
456 // ============================================================================= |
496 // ============================================================================= |
457 // ----------------------------------------------------------------------------- |
497 // ----------------------------------------------------------------------------- |
458 void ForgeWindow::slot_recentFile() |
498 void ForgeWindow::slot_recentFile() |
459 { QAction* qAct = static_cast<QAction*> (sender()); |
499 { |
|
500 QAction* qAct = static_cast<QAction*> (sender()); |
460 openMainFile (qAct->text()); |
501 openMainFile (qAct->text()); |
461 } |
502 } |
462 |
503 |
463 // ============================================================================= |
504 // ============================================================================= |
464 // ----------------------------------------------------------------------------- |
505 // ----------------------------------------------------------------------------- |
465 void ForgeWindow::slot_quickColor() |
506 void ForgeWindow::slot_quickColor() |
466 { QToolButton* button = static_cast<QToolButton*> (sender()); |
507 { |
|
508 QToolButton* button = static_cast<QToolButton*> (sender()); |
467 LDColor* col = null; |
509 LDColor* col = null; |
468 |
510 |
469 for (const LDQuickColor & entry : m_quickColors) |
511 for (const LDQuickColor & entry : m_quickColors) |
470 { if (entry.getToolButton() == button) |
512 { |
471 { col = entry.getColor(); |
513 if (entry.getToolButton() == button) |
|
514 { |
|
515 col = entry.getColor(); |
472 break; |
516 break; |
473 } |
517 } |
474 } |
518 } |
475 |
519 |
476 if (col == null) |
520 if (col == null) |
477 return; |
521 return; |
478 |
522 |
479 int newColor = col->index; |
523 int newColor = col->index; |
480 |
524 |
481 for (LDObject* obj : selection()) |
525 for (LDObject* obj : selection()) |
482 { if (obj->isColored() == false) |
526 { |
|
527 if (obj->isColored() == false) |
483 continue; // uncolored object |
528 continue; // uncolored object |
484 |
529 |
485 obj->setColor (newColor); |
530 obj->setColor (newColor); |
486 R()->compileObject (obj); |
531 R()->compileObject (obj); |
487 } |
532 } |
491 } |
536 } |
492 |
537 |
493 // ============================================================================= |
538 // ============================================================================= |
494 // ----------------------------------------------------------------------------- |
539 // ----------------------------------------------------------------------------- |
495 int ForgeWindow::getInsertionPoint() |
540 int ForgeWindow::getInsertionPoint() |
496 { // If we have a selection, put the item after it. |
541 { |
|
542 // If we have a selection, put the item after it. |
497 if (!selection().isEmpty()) |
543 if (!selection().isEmpty()) |
498 return selection().last()->getIndex() + 1; |
544 return selection().last()->getIndex() + 1; |
499 |
545 |
500 // Otherwise place the object at the end. |
546 // Otherwise place the object at the end. |
501 return getCurrentDocument()->getObjectCount(); |
547 return getCurrentDocument()->getObjectCount(); |
502 } |
548 } |
503 |
549 |
504 // ============================================================================= |
550 // ============================================================================= |
505 // ----------------------------------------------------------------------------- |
551 // ----------------------------------------------------------------------------- |
506 void ForgeWindow::doFullRefresh() |
552 void ForgeWindow::doFullRefresh() |
507 { buildObjList(); |
553 { |
|
554 buildObjList(); |
508 m_renderer->hardRefresh(); |
555 m_renderer->hardRefresh(); |
509 } |
556 } |
510 |
557 |
511 // ============================================================================= |
558 // ============================================================================= |
512 // ----------------------------------------------------------------------------- |
559 // ----------------------------------------------------------------------------- |
513 void ForgeWindow::refresh() |
560 void ForgeWindow::refresh() |
514 { buildObjList(); |
561 { |
|
562 buildObjList(); |
515 m_renderer->update(); |
563 m_renderer->update(); |
516 } |
564 } |
517 |
565 |
518 // ============================================================================= |
566 // ============================================================================= |
519 // ----------------------------------------------------------------------------- |
567 // ----------------------------------------------------------------------------- |
520 void ForgeWindow::updateSelection() |
568 void ForgeWindow::updateSelection() |
521 { g_isSelectionLocked = true; |
569 { |
|
570 g_isSelectionLocked = true; |
522 |
571 |
523 for (LDObject* obj : getCurrentDocument()->getObjects()) |
572 for (LDObject* obj : getCurrentDocument()->getObjects()) |
524 obj->setSelected (false); |
573 obj->setSelected (false); |
525 |
574 |
526 ui->objectList->clearSelection(); |
575 ui->objectList->clearSelection(); |
527 |
576 |
528 for (LDObject* obj : selection()) |
577 for (LDObject* obj : selection()) |
529 { if (obj->qObjListEntry == null) |
578 { |
|
579 if (obj->qObjListEntry == null) |
530 continue; |
580 continue; |
531 |
581 |
532 obj->qObjListEntry->setSelected (true); |
582 obj->qObjListEntry->setSelected (true); |
533 obj->setSelected (true); |
583 obj->setSelected (true); |
534 } |
584 } |
538 } |
588 } |
539 |
589 |
540 // ============================================================================= |
590 // ============================================================================= |
541 // ----------------------------------------------------------------------------- |
591 // ----------------------------------------------------------------------------- |
542 int ForgeWindow::getSelectedColor() |
592 int ForgeWindow::getSelectedColor() |
543 { int result = -1; |
593 { |
|
594 int result = -1; |
544 |
595 |
545 for (LDObject* obj : selection()) |
596 for (LDObject* obj : selection()) |
546 { if (obj->isColored() == false) |
597 { |
|
598 if (obj->isColored() == false) |
547 continue; // doesn't use color |
599 continue; // doesn't use color |
548 |
600 |
549 if (result != -1 && obj->getColor() != result) |
601 if (result != -1 && obj->getColor() != result) |
550 return -1; // No consensus in object color |
602 return -1; // No consensus in object color |
551 |
603 |
557 } |
609 } |
558 |
610 |
559 // ============================================================================= |
611 // ============================================================================= |
560 // ----------------------------------------------------------------------------- |
612 // ----------------------------------------------------------------------------- |
561 LDObject::Type ForgeWindow::getUniformSelectedType() |
613 LDObject::Type ForgeWindow::getUniformSelectedType() |
562 { LDObject::Type result = LDObject::Unidentified; |
614 { |
|
615 LDObject::Type result = LDObject::Unidentified; |
563 |
616 |
564 for (LDObject* obj : selection()) |
617 for (LDObject* obj : selection()) |
565 { if (result != LDObject::Unidentified && obj->getColor() != result) |
618 { |
|
619 if (result != LDObject::Unidentified && obj->getColor() != result) |
566 return LDObject::Unidentified; |
620 return LDObject::Unidentified; |
567 |
621 |
568 if (result == LDObject::Unidentified) |
622 if (result == LDObject::Unidentified) |
569 result = obj->getType(); |
623 result = obj->getType(); |
570 } |
624 } |
573 } |
627 } |
574 |
628 |
575 // ============================================================================= |
629 // ============================================================================= |
576 // ----------------------------------------------------------------------------- |
630 // ----------------------------------------------------------------------------- |
577 void ForgeWindow::closeEvent (QCloseEvent* ev) |
631 void ForgeWindow::closeEvent (QCloseEvent* ev) |
578 { // Check whether it's safe to close all files. |
632 { |
|
633 // Check whether it's safe to close all files. |
579 if (!safeToCloseAll()) |
634 if (!safeToCloseAll()) |
580 { ev->ignore(); |
635 { |
|
636 ev->ignore(); |
581 return; |
637 return; |
582 } |
638 } |
583 |
639 |
584 // Save the configuration before leaving so that, for instance, grid choice |
640 // Save the configuration before leaving so that, for instance, grid choice |
585 // is preserved across instances. |
641 // is preserved across instances. |
589 } |
645 } |
590 |
646 |
591 // ============================================================================= |
647 // ============================================================================= |
592 // ----------------------------------------------------------------------------- |
648 // ----------------------------------------------------------------------------- |
593 void ForgeWindow::spawnContextMenu (const QPoint pos) |
649 void ForgeWindow::spawnContextMenu (const QPoint pos) |
594 { const bool single = (selection().size() == 1); |
650 { |
|
651 const bool single = (selection().size() == 1); |
595 LDObject* singleObj = (single) ? selection()[0] : null; |
652 LDObject* singleObj = (single) ? selection()[0] : null; |
596 |
653 |
597 QMenu* contextMenu = new QMenu; |
654 QMenu* contextMenu = new QMenu; |
598 |
655 |
599 if (single && singleObj->getType() != LDObject::Empty) |
656 if (single && singleObj->getType() != LDObject::Empty) |
600 { contextMenu->addAction (ui->actionEdit); |
657 { |
|
658 contextMenu->addAction (ui->actionEdit); |
601 contextMenu->addSeparator(); |
659 contextMenu->addSeparator(); |
602 } |
660 } |
603 |
661 |
604 contextMenu->addAction (ui->actionCut); |
662 contextMenu->addAction (ui->actionCut); |
605 contextMenu->addAction (ui->actionCopy); |
663 contextMenu->addAction (ui->actionCopy); |
617 contextMenu->addAction (ui->actionModeSelect); |
675 contextMenu->addAction (ui->actionModeSelect); |
618 contextMenu->addAction (ui->actionModeDraw); |
676 contextMenu->addAction (ui->actionModeDraw); |
619 contextMenu->addAction (ui->actionModeCircle); |
677 contextMenu->addAction (ui->actionModeCircle); |
620 |
678 |
621 if (selection().size() > 0) |
679 if (selection().size() > 0) |
622 { contextMenu->addSeparator(); |
680 { |
|
681 contextMenu->addSeparator(); |
623 contextMenu->addAction (ui->actionSubfileSelection); |
682 contextMenu->addAction (ui->actionSubfileSelection); |
624 } |
683 } |
625 |
684 |
626 if (R()->camera() != GL::EFreeCamera) |
685 if (R()->camera() != GL::EFreeCamera) |
627 { contextMenu->addSeparator(); |
686 { |
|
687 contextMenu->addSeparator(); |
628 contextMenu->addAction (ui->actionSetDrawDepth); |
688 contextMenu->addAction (ui->actionSetDrawDepth); |
629 } |
689 } |
630 |
690 |
631 contextMenu->exec (pos); |
691 contextMenu->exec (pos); |
632 } |
692 } |
633 |
693 |
634 // ============================================================================= |
694 // ============================================================================= |
635 // TODO: what the heh? |
695 // TODO: what the heh? |
636 // ----------------------------------------------------------------------------- |
696 // ----------------------------------------------------------------------------- |
637 void ForgeWindow::deleteObjects (QList<LDObject*> objs) |
697 void ForgeWindow::deleteObjects (QList<LDObject*> objs) |
638 { for (LDObject* obj : objs) |
698 { |
|
699 for (LDObject* obj : objs) |
639 obj->deleteSelf(); |
700 obj->deleteSelf(); |
640 } |
701 } |
641 |
702 |
642 // ============================================================================= |
703 // ============================================================================= |
643 // ----------------------------------------------------------------------------- |
704 // ----------------------------------------------------------------------------- |
644 void ForgeWindow::deleteByColor (const int colnum) |
705 void ForgeWindow::deleteByColor (const int colnum) |
645 { QList<LDObject*> objs; |
706 { |
|
707 QList<LDObject*> objs; |
646 |
708 |
647 for (LDObject* obj : getCurrentDocument()->getObjects()) |
709 for (LDObject* obj : getCurrentDocument()->getObjects()) |
648 { if (!obj->isColored() || obj->getColor() != colnum) |
710 { |
|
711 if (!obj->isColored() || obj->getColor() != colnum) |
649 continue; |
712 continue; |
650 |
713 |
651 objs << obj; |
714 objs << obj; |
652 } |
715 } |
653 |
716 |
655 } |
718 } |
656 |
719 |
657 // ============================================================================= |
720 // ============================================================================= |
658 // ----------------------------------------------------------------------------- |
721 // ----------------------------------------------------------------------------- |
659 void ForgeWindow::updateEditModeActions() |
722 void ForgeWindow::updateEditModeActions() |
660 { const EditMode mode = R()->getEditMode(); |
723 { |
|
724 const EditMode mode = R()->getEditMode(); |
661 ui->actionModeSelect->setChecked (mode == ESelectMode); |
725 ui->actionModeSelect->setChecked (mode == ESelectMode); |
662 ui->actionModeDraw->setChecked (mode == EDrawMode); |
726 ui->actionModeDraw->setChecked (mode == EDrawMode); |
663 ui->actionModeCircle->setChecked (mode == ECircleMode); |
727 ui->actionModeCircle->setChecked (mode == ECircleMode); |
664 } |
728 } |
665 |
729 |
666 // ============================================================================= |
730 // ============================================================================= |
667 // ----------------------------------------------------------------------------- |
731 // ----------------------------------------------------------------------------- |
668 void ForgeWindow::slot_editObject (QListWidgetItem* listitem) |
732 void ForgeWindow::slot_editObject (QListWidgetItem* listitem) |
669 { LDObject* obj = null; |
733 { |
|
734 LDObject* obj = null; |
670 |
735 |
671 for (LDObject* it : getCurrentDocument()->getObjects()) |
736 for (LDObject* it : getCurrentDocument()->getObjects()) |
672 { if (it->qObjListEntry == listitem) |
737 { |
673 { obj = it; |
738 if (it->qObjListEntry == listitem) |
|
739 { |
|
740 obj = it; |
674 break; |
741 break; |
675 } |
742 } |
676 } |
743 } |
677 |
744 |
678 AddObjectDialog::staticDialog (obj->getType(), obj); |
745 AddObjectDialog::staticDialog (obj->getType(), obj); |
680 |
747 |
681 #if 0 |
748 #if 0 |
682 // ============================================================================= |
749 // ============================================================================= |
683 // ----------------------------------------------------------------------------- |
750 // ----------------------------------------------------------------------------- |
684 void ForgeWindow::primitiveLoaderStart (int max) |
751 void ForgeWindow::primitiveLoaderStart (int max) |
685 { m_primLoaderWidget->show(); |
752 { |
|
753 m_primLoaderWidget->show(); |
686 m_primLoaderBar->setRange (0, max); |
754 m_primLoaderBar->setRange (0, max); |
687 m_primLoaderBar->setValue (0); |
755 m_primLoaderBar->setValue (0); |
688 m_primLoaderBar->setFormat ("%p%"); |
756 m_primLoaderBar->setFormat ("%p%"); |
689 } |
757 } |
690 |
758 |
691 // ============================================================================= |
759 // ============================================================================= |
692 // ----------------------------------------------------------------------------- |
760 // ----------------------------------------------------------------------------- |
693 void ForgeWindow::primitiveLoaderUpdate (int prog) |
761 void ForgeWindow::primitiveLoaderUpdate (int prog) |
694 { m_primLoaderBar->setValue (prog); |
762 { |
|
763 m_primLoaderBar->setValue (prog); |
695 } |
764 } |
696 |
765 |
697 // ============================================================================= |
766 // ============================================================================= |
698 // ----------------------------------------------------------------------------- |
767 // ----------------------------------------------------------------------------- |
699 void ForgeWindow::primitiveLoaderEnd() |
768 void ForgeWindow::primitiveLoaderEnd() |
700 { QTimer* hidetimer = new QTimer; |
769 { |
|
770 QTimer* hidetimer = new QTimer; |
701 connect (hidetimer, SIGNAL (timeout()), m_primLoaderWidget, SLOT (hide())); |
771 connect (hidetimer, SIGNAL (timeout()), m_primLoaderWidget, SLOT (hide())); |
702 hidetimer->setSingleShot (true); |
772 hidetimer->setSingleShot (true); |
703 hidetimer->start (1500); |
773 hidetimer->start (1500); |
704 m_primLoaderBar->setFormat (tr ("Done")); |
774 m_primLoaderBar->setFormat (tr ("Done")); |
705 log (tr ("Primitives scanned: %1 primitives listed"), m_primLoaderBar->value()); |
775 log (tr ("Primitives scanned: %1 primitives listed"), m_primLoaderBar->value()); |
707 #endif |
777 #endif |
708 |
778 |
709 // ============================================================================= |
779 // ============================================================================= |
710 // ----------------------------------------------------------------------------- |
780 // ----------------------------------------------------------------------------- |
711 bool ForgeWindow::save (LDDocument* f, bool saveAs) |
781 bool ForgeWindow::save (LDDocument* f, bool saveAs) |
712 { str path = f->getFullPath(); |
782 { |
|
783 str path = f->getFullPath(); |
713 |
784 |
714 if (saveAs || path.isEmpty()) |
785 if (saveAs || path.isEmpty()) |
715 { str name = f->getDefaultName(); |
786 { |
|
787 str name = f->getDefaultName(); |
716 |
788 |
717 if (!f->getFullPath().isEmpty()) |
789 if (!f->getFullPath().isEmpty()) |
718 name = f->getFullPath(); |
790 name = f->getFullPath(); |
719 elif (!f->getName().isEmpty()) |
791 elif (!f->getName().isEmpty()) |
720 name = f->getName(); |
792 name = f->getName(); |
722 name.replace ("\\", "/"); |
794 name.replace ("\\", "/"); |
723 path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), |
795 path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), |
724 name, tr ("LDraw files (*.dat *.ldr)")); |
796 name, tr ("LDraw files (*.dat *.ldr)")); |
725 |
797 |
726 if (path.isEmpty()) |
798 if (path.isEmpty()) |
727 { // User didn't give a file name, abort. |
799 { |
|
800 // User didn't give a file name, abort. |
728 return false; |
801 return false; |
729 } |
802 } |
730 } |
803 } |
731 |
804 |
732 if (f->save (path)) |
805 if (f->save (path)) |
733 { if (f == getCurrentDocument()) |
806 { |
|
807 if (f == getCurrentDocument()) |
734 updateTitle(); |
808 updateTitle(); |
735 |
809 |
736 log ("Saved to %1.", path); |
810 log ("Saved to %1.", path); |
737 |
811 |
738 // Add it to recent files |
812 // Add it to recent files |
757 |
831 |
758 return false; |
832 return false; |
759 } |
833 } |
760 |
834 |
761 void ForgeWindow::addMessage (str msg) |
835 void ForgeWindow::addMessage (str msg) |
762 { m_msglog->addLine (msg); |
836 { |
|
837 m_msglog->addLine (msg); |
763 } |
838 } |
764 |
839 |
765 // ============================================================================ |
840 // ============================================================================ |
766 void ObjectList::contextMenuEvent (QContextMenuEvent* ev) |
841 void ObjectList::contextMenuEvent (QContextMenuEvent* ev) |
767 { g_win->spawnContextMenu (ev->globalPos()); |
842 { |
|
843 g_win->spawnContextMenu (ev->globalPos()); |
768 } |
844 } |
769 |
845 |
770 // ============================================================================= |
846 // ============================================================================= |
771 // ----------------------------------------------------------------------------- |
847 // ----------------------------------------------------------------------------- |
772 QPixmap getIcon (str iconName) |
848 QPixmap getIcon (str iconName) |
773 { return (QPixmap (fmt (":/icons/%1.png", iconName))); |
849 { |
|
850 return (QPixmap (fmt (":/icons/%1.png", iconName))); |
774 } |
851 } |
775 |
852 |
776 // ============================================================================= |
853 // ============================================================================= |
777 bool confirm (str msg) |
854 bool confirm (str msg) |
778 { return confirm (ForgeWindow::tr ("Confirm"), msg); |
855 { |
|
856 return confirm (ForgeWindow::tr ("Confirm"), msg); |
779 } |
857 } |
780 |
858 |
781 bool confirm (str title, str msg) |
859 bool confirm (str title, str msg) |
782 { return QMessageBox::question (g_win, title, msg, |
860 { |
|
861 return QMessageBox::question (g_win, title, msg, |
783 (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes; |
862 (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes; |
784 } |
863 } |
785 |
864 |
786 // ============================================================================= |
865 // ============================================================================= |
787 void critical (str msg) |
866 void critical (str msg) |
788 { QMessageBox::critical (g_win, ForgeWindow::tr ("Error"), msg, |
867 { |
|
868 QMessageBox::critical (g_win, ForgeWindow::tr ("Error"), msg, |
789 (QMessageBox::Close), QMessageBox::Close); |
869 (QMessageBox::Close), QMessageBox::Close); |
790 } |
870 } |
791 |
871 |
792 // ============================================================================= |
872 // ============================================================================= |
793 QIcon makeColorIcon (LDColor* colinfo, const int size) |
873 QIcon makeColorIcon (LDColor* colinfo, const int size) |
794 { // Create an image object and link a painter to it. |
874 { |
|
875 // Create an image object and link a painter to it. |
795 QImage img (size, size, QImage::Format_ARGB32); |
876 QImage img (size, size, QImage::Format_ARGB32); |
796 QPainter paint (&img); |
877 QPainter paint (&img); |
797 QColor col = colinfo->faceColor; |
878 QColor col = colinfo->faceColor; |
798 |
879 |
799 if (colinfo->index == maincolor) |
880 if (colinfo->index == maincolor) |
800 { // Use the user preferences for main color here |
881 { |
|
882 // Use the user preferences for main color here |
801 col = gl_maincolor; |
883 col = gl_maincolor; |
802 col.setAlphaF (gl_maincolor_alpha); |
884 col.setAlphaF (gl_maincolor_alpha); |
803 } |
885 } |
804 |
886 |
805 // Paint the icon border |
887 // Paint the icon border |
813 return QIcon (QPixmap::fromImage (img)); |
895 return QIcon (QPixmap::fromImage (img)); |
814 } |
896 } |
815 |
897 |
816 // ============================================================================= |
898 // ============================================================================= |
817 void makeColorComboBox (QComboBox* box) |
899 void makeColorComboBox (QComboBox* box) |
818 { std::map<int, int> counts; |
900 { |
|
901 std::map<int, int> counts; |
819 |
902 |
820 for (LDObject* obj : getCurrentDocument()->getObjects()) |
903 for (LDObject* obj : getCurrentDocument()->getObjects()) |
821 { if (!obj->isColored()) |
904 { |
|
905 if (!obj->isColored()) |
822 continue; |
906 continue; |
823 |
907 |
824 if (counts.find (obj->getColor()) == counts.end()) |
908 if (counts.find (obj->getColor()) == counts.end()) |
825 counts[obj->getColor()] = 1; |
909 counts[obj->getColor()] = 1; |
826 else |
910 else |
829 |
913 |
830 box->clear(); |
914 box->clear(); |
831 int row = 0; |
915 int row = 0; |
832 |
916 |
833 for (const auto& pair : counts) |
917 for (const auto& pair : counts) |
834 { LDColor* col = getColor (pair.first); |
918 { |
|
919 LDColor* col = getColor (pair.first); |
835 assert (col != null); |
920 assert (col != null); |
836 |
921 |
837 QIcon ico = makeColorIcon (col, 16); |
922 QIcon ico = makeColorIcon (col, 16); |
838 box->addItem (ico, fmt ("[%1] %2 (%3 object%4)", |
923 box->addItem (ico, fmt ("[%1] %2 (%3 object%4)", |
839 pair.first, col->name, pair.second, plural (pair.second))); |
924 pair.first, col->name, pair.second, plural (pair.second))); |
842 ++row; |
927 ++row; |
843 } |
928 } |
844 } |
929 } |
845 |
930 |
846 void ForgeWindow::setStatusBarText (str text) |
931 void ForgeWindow::setStatusBarText (str text) |
847 { statusBar()->showMessage (text); |
932 { |
|
933 statusBar()->showMessage (text); |
848 } |
934 } |
849 |
935 |
850 Ui_LDForgeUI* ForgeWindow::getInterface() const |
936 Ui_LDForgeUI* ForgeWindow::getInterface() const |
851 { return ui; |
937 { |
|
938 return ui; |
852 } |
939 } |
853 |
940 |
854 void ForgeWindow::updateDocumentList() |
941 void ForgeWindow::updateDocumentList() |
855 { ui->fileList->clear(); |
942 { |
|
943 ui->fileList->clear(); |
856 |
944 |
857 for (LDDocument* f : g_loadedFiles) |
945 for (LDDocument* f : g_loadedFiles) |
858 { // Don't list implicit files unless explicitly desired. |
946 { |
|
947 // Don't list implicit files unless explicitly desired. |
859 if (f->isImplicit() && !gui_implicitfiles) |
948 if (f->isImplicit() && !gui_implicitfiles) |
860 continue; |
949 continue; |
861 |
950 |
862 // Add an item to the list for this file and store a pointer to it in |
951 // Add an item to the list for this file and store a pointer to it in |
863 // the file, so we can find files by the list item. |
952 // the file, so we can find files by the list item. |
894 |
985 |
895 // ============================================================================= |
986 // ============================================================================= |
896 // A file is selected from the list of files on the left of the screen. Find out |
987 // A file is selected from the list of files on the left of the screen. Find out |
897 // which file was picked and change to it. |
988 // which file was picked and change to it. |
898 void ForgeWindow::changeCurrentFile() |
989 void ForgeWindow::changeCurrentFile() |
899 { LDDocument* f = null; |
990 { |
|
991 LDDocument* f = null; |
900 QListWidgetItem* item = ui->fileList->currentItem(); |
992 QListWidgetItem* item = ui->fileList->currentItem(); |
901 |
993 |
902 // Find the file pointer of the item that was selected. |
994 // Find the file pointer of the item that was selected. |
903 for (LDDocument* it : g_loadedFiles) |
995 for (LDDocument* it : g_loadedFiles) |
904 { if (it->getListItem() == item) |
996 { |
905 { f = it; |
997 if (it->getListItem() == item) |
|
998 { |
|
999 f = it; |
906 break; |
1000 break; |
907 } |
1001 } |
908 } |
1002 } |
909 |
1003 |
910 // If we picked the same file we're currently on, we don't need to do |
1004 // If we picked the same file we're currently on, we don't need to do |
928 |
1022 |
929 buildObjList(); |
1023 buildObjList(); |
930 } |
1024 } |
931 |
1025 |
932 void ForgeWindow::updateActions() |
1026 void ForgeWindow::updateActions() |
933 { History* his = getCurrentDocument()->getHistory(); |
1027 { |
|
1028 History* his = getCurrentDocument()->getHistory(); |
934 int pos = his->getPosition(); |
1029 int pos = his->getPosition(); |
935 ui->actionUndo->setEnabled (pos != -1); |
1030 ui->actionUndo->setEnabled (pos != -1); |
936 ui->actionRedo->setEnabled (pos < (long) his->getSize() - 1); |
1031 ui->actionRedo->setEnabled (pos < (long) his->getSize() - 1); |
937 ui->actionAxes->setChecked (gl_axes); |
1032 ui->actionAxes->setChecked (gl_axes); |
938 ui->actionBFCView->setChecked (gl_colorbfc); |
1033 ui->actionBFCView->setChecked (gl_colorbfc); |
939 ui->actionDrawAngles->setChecked (gl_drawangles); |
1034 ui->actionDrawAngles->setChecked (gl_drawangles); |
940 } |
1035 } |
941 |
1036 |
942 QImage imageFromScreencap (uchar* data, int w, int h) |
1037 QImage imageFromScreencap (uchar* data, int w, int h) |
943 { // GL and Qt formats have R and B swapped. Also, GL flips Y - correct it as well. |
1038 { |
|
1039 // GL and Qt formats have R and B swapped. Also, GL flips Y - correct it as well. |
944 return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped().mirrored(); |
1040 return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped().mirrored(); |
945 } |
1041 } |
946 |
1042 |
947 // ============================================================================= |
1043 // ============================================================================= |
948 // ----------------------------------------------------------------------------- |
1044 // ----------------------------------------------------------------------------- |
949 LDQuickColor::LDQuickColor (LDColor* color, QToolButton* toolButton) : |
1045 LDQuickColor::LDQuickColor (LDColor* color, QToolButton* toolButton) : |
950 m_Color (color), |
1046 m_Color (color), |
951 m_ToolButton (toolButton) {} |
1047 m_ToolButton (toolButton) {} |
952 |
1048 |
953 LDQuickColor LDQuickColor::getSeparator() |
1049 LDQuickColor LDQuickColor::getSeparator() |
954 { return LDQuickColor (null, null); |
1050 { |
|
1051 return LDQuickColor (null, null); |
955 } |
1052 } |
956 |
1053 |
957 bool LDQuickColor::isSeparator() const |
1054 bool LDQuickColor::isSeparator() const |
958 { return getColor() == null; |
1055 { |
959 } |
1056 return getColor() == null; |
|
1057 } |