55 #include "guiutilities.h" |
55 #include "guiutilities.h" |
56 #include "glCompiler.h" |
56 #include "glCompiler.h" |
57 #include "documentmanager.h" |
57 #include "documentmanager.h" |
58 #include "ldobjectiterator.h" |
58 #include "ldobjectiterator.h" |
59 |
59 |
60 ConfigOption (bool ColorizeObjectsList = true) |
60 ConfigOption(bool ColorizeObjectsList = true) |
61 ConfigOption (QString QuickColorToolbar = "4:25:14:27:2:3:11:1:22:|:0:72:71:15") |
61 ConfigOption(QString QuickColorToolbar = "4:25:14:27:2:3:11:1:22:|:0:72:71:15") |
62 ConfigOption (bool ListImplicitFiles = false) |
62 ConfigOption(bool ListImplicitFiles = false) |
63 ConfigOption (QStringList HiddenToolbars) |
63 ConfigOption(QStringList HiddenToolbars) |
64 |
64 |
65 // --------------------------------------------------------------------------------------------------------------------- |
65 // --------------------------------------------------------------------------------------------------------------------- |
66 // |
66 // |
67 MainWindow::MainWindow (QWidget* parent, Qt::WindowFlags flags) : |
67 MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) : |
68 QMainWindow (parent, flags), |
68 QMainWindow(parent, flags), |
69 m_guiUtilities (new GuiUtilities (this)), |
69 m_guiUtilities(new GuiUtilities(this)), |
70 ui (*new Ui_MainWindow), |
70 ui(*new Ui_MainWindow), |
71 m_externalPrograms (nullptr), |
71 m_externalPrograms(nullptr), |
72 m_settings (makeSettings (this)), |
72 m_settings(makeSettings(this)), |
73 m_documents (new DocumentManager (this)), |
73 m_documents(new DocumentManager(this)), |
74 m_currentDocument (nullptr), |
74 m_currentDocument(nullptr), |
75 m_isSelectionLocked (false) |
75 m_isSelectionLocked(false) |
76 { |
76 { |
77 g_win = this; |
77 g_win = this; |
78 ui.setupUi (this); |
78 ui.setupUi(this); |
79 m_updatingTabs = false; |
79 m_updatingTabs = false; |
80 m_renderer = new GLRenderer (this); |
80 m_renderer = new GLRenderer(this); |
81 m_tabs = new QTabBar; |
81 m_tabs = new QTabBar; |
82 m_tabs->setTabsClosable (true); |
82 m_tabs->setTabsClosable(true); |
83 ui.verticalLayout->insertWidget (0, m_tabs); |
83 ui.verticalLayout->insertWidget(0, m_tabs); |
84 |
84 |
85 createBlankDocument(); |
85 createBlankDocument(); |
86 m_renderer->setDocument (m_currentDocument); |
86 m_renderer->setDocument(m_currentDocument); |
87 |
87 |
88 // Stuff the renderer into its frame |
88 // Stuff the renderer into its frame |
89 QVBoxLayout* rendererLayout = new QVBoxLayout (ui.rendererFrame); |
89 QVBoxLayout* rendererLayout = new QVBoxLayout(ui.rendererFrame); |
90 rendererLayout->addWidget (renderer()); |
90 rendererLayout->addWidget(renderer()); |
91 |
91 |
92 connect (ui.objectList, SIGNAL (itemSelectionChanged()), this, SLOT (selectionChanged())); |
92 connect(ui.objectList, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); |
93 connect (ui.objectList, SIGNAL (itemDoubleClicked (QListWidgetItem*)), this, SLOT (objectListDoubleClicked (QListWidgetItem*))); |
93 connect(ui.objectList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(objectListDoubleClicked(QListWidgetItem*))); |
94 connect (m_tabs, SIGNAL (currentChanged(int)), this, SLOT (tabSelected())); |
94 connect(m_tabs, SIGNAL(currentChanged(int)), this, SLOT(tabSelected())); |
95 connect (m_tabs, SIGNAL (tabCloseRequested (int)), this, SLOT (closeTab (int))); |
95 connect(m_tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); |
96 |
96 |
97 if (ActivePrimitiveScanner()) |
97 if (ActivePrimitiveScanner()) |
98 connect (ActivePrimitiveScanner(), SIGNAL (workDone()), this, SLOT (updatePrimitives())); |
98 connect(ActivePrimitiveScanner(), SIGNAL(workDone()), this, SLOT(updatePrimitives())); |
99 else |
99 else |
100 updatePrimitives(); |
100 updatePrimitives(); |
101 |
101 |
102 m_quickColors = LoadQuickColorList(); |
102 m_quickColors = LoadQuickColorList(); |
103 setStatusBar (new QStatusBar); |
103 setStatusBar(new QStatusBar); |
104 updateActions(); |
104 updateActions(); |
105 |
105 |
106 // Connect all actions and save default sequences |
106 // Connect all actions and save default sequences |
107 applyToActions ([&](QAction* act) |
107 applyToActions([&](QAction* act) |
108 { |
108 { |
109 connect (act, SIGNAL (triggered()), this, SLOT (actionTriggered())); |
109 connect(act, SIGNAL(triggered()), this, SLOT(actionTriggered())); |
110 m_defaultShortcuts[act] = act->shortcut(); |
110 m_defaultShortcuts[act] = act->shortcut(); |
111 }); |
111 }); |
112 |
112 |
113 updateGridToolBar(); |
113 updateGridToolBar(); |
114 updateEditModeActions(); |
114 updateEditModeActions(); |
115 updateRecentFilesMenu(); |
115 updateRecentFilesMenu(); |
116 updateColorToolbar(); |
116 updateColorToolbar(); |
117 updateTitle(); |
117 updateTitle(); |
118 loadShortcuts(); |
118 loadShortcuts(); |
119 setMinimumSize (300, 200); |
119 setMinimumSize(300, 200); |
120 connect (qApp, SIGNAL (aboutToQuit()), this, SLOT (doLastSecondCleanup())); |
120 connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(doLastSecondCleanup())); |
121 connect (ui.ringToolHiRes, SIGNAL (clicked (bool)), this, SLOT (ringToolHiResClicked (bool))); |
121 connect(ui.ringToolHiRes, SIGNAL(clicked(bool)), this, SLOT(ringToolHiResClicked(bool))); |
122 connect (ui.ringToolSegments, SIGNAL (valueChanged (int)), |
122 connect(ui.ringToolSegments, SIGNAL(valueChanged(int)), |
123 this, SLOT (circleToolSegmentsChanged())); |
123 this, SLOT(circleToolSegmentsChanged())); |
124 circleToolSegmentsChanged(); // invoke it manually for initial label text |
124 circleToolSegmentsChanged(); // invoke it manually for initial label text |
125 |
125 |
126 // Examine the toolsets and make a dictionary of tools |
126 // Examine the toolsets and make a dictionary of tools |
127 m_toolsets = Toolset::createToolsets (this); |
127 m_toolsets = Toolset::createToolsets(this); |
128 |
128 |
129 QStringList ignore; |
129 QStringList ignore; |
130 for (int i = 0; i < Toolset::staticMetaObject.methodCount(); ++i) |
130 for (int i = 0; i < Toolset::staticMetaObject.methodCount(); ++i) |
131 { |
131 { |
132 QMetaMethod method = Toolset::staticMetaObject.method (i); |
132 QMetaMethod method = Toolset::staticMetaObject.method(i); |
133 ignore.append (QString::fromUtf8 (method.name())); |
133 ignore.append(QString::fromUtf8(method.name())); |
134 } |
134 } |
135 |
135 |
136 for (Toolset* toolset : m_toolsets) |
136 for (Toolset* toolset : m_toolsets) |
137 { |
137 { |
138 const QMetaObject* meta = toolset->metaObject(); |
138 const QMetaObject* meta = toolset->metaObject(); |
139 |
139 |
140 if (qobject_cast<ExtProgramToolset*> (toolset)) |
140 if (qobject_cast<ExtProgramToolset*>(toolset)) |
141 m_externalPrograms = static_cast<ExtProgramToolset*> (toolset); |
141 m_externalPrograms = static_cast<ExtProgramToolset*>(toolset); |
142 |
142 |
143 for (int i = 0; i < meta->methodCount(); ++i) |
143 for (int i = 0; i < meta->methodCount(); ++i) |
144 { |
144 { |
145 ToolInfo info; |
145 ToolInfo info; |
146 info.method = meta->method (i); |
146 info.method = meta->method(i); |
147 info.object = toolset; |
147 info.object = toolset; |
148 QString methodName = QString::fromUtf8 (info.method.name()); |
148 QString methodName = QString::fromUtf8(info.method.name()); |
149 |
149 |
150 if (ignore.contains (methodName)) |
150 if (ignore.contains(methodName)) |
151 continue; // The method was inherited from base classes |
151 continue; // The method was inherited from base classes |
152 |
152 |
153 QString actionName = "action" + methodName.left (1).toUpper() + methodName.mid (1); |
153 QString actionName = "action" + methodName.left(1).toUpper() + methodName.mid(1); |
154 QAction* action = findChild<QAction*> (actionName); |
154 QAction* action = findChild<QAction*>(actionName); |
155 |
155 |
156 if (action == nullptr) |
156 if (action == nullptr) |
157 print ("No action for %1::%2 (looked for %3)\n", meta->className(), methodName, actionName); |
157 print("No action for %1::%2(looked for %3)\n", meta->className(), methodName, actionName); |
158 else |
158 else |
159 m_toolmap[action] = info; |
159 m_toolmap[action] = info; |
160 } |
160 } |
161 } |
161 } |
162 |
162 |
163 for (QVariant const& toolbarname : config.hiddenToolbars()) |
163 for (QVariant const& toolbarname : config.hiddenToolbars()) |
164 { |
164 { |
165 QToolBar* toolbar = findChild<QToolBar*> (toolbarname.toString()); |
165 QToolBar* toolbar = findChild<QToolBar*>(toolbarname.toString()); |
166 |
166 |
167 if (toolbar) |
167 if (toolbar) |
168 toolbar->hide(); |
168 toolbar->hide(); |
169 } |
169 } |
170 |
170 |
171 // If this is the first start, get the user to configuration. Especially point |
171 // If this is the first start, get the user to configuration. Especially point |
172 // them to the profile tab, it's the most important form to fill in. |
172 // them to the profile tab, it's the most important form to fill in. |
173 if (config.firstStart()) |
173 if (config.firstStart()) |
174 { |
174 { |
175 ConfigDialog* dialog = new ConfigDialog (this, ConfigDialog::ProfileTab); |
175 ConfigDialog* dialog = new ConfigDialog(this, ConfigDialog::ProfileTab); |
176 dialog->show(); |
176 dialog->show(); |
177 config.setFirstStart (false); |
177 config.setFirstStart(false); |
178 } |
178 } |
179 } |
179 } |
180 |
180 |
181 MainWindow::~MainWindow() |
181 MainWindow::~MainWindow() |
182 { |
182 { |
305 // |
305 // |
306 void MainWindow::updateGridToolBar() |
306 void MainWindow::updateGridToolBar() |
307 { |
307 { |
308 // Ensure that the current grid - and only the current grid - is selected. |
308 // Ensure that the current grid - and only the current grid - is selected. |
309 int grid = config.grid(); |
309 int grid = config.grid(); |
310 ui.actionGridCoarse->setChecked (grid == Grid::Coarse); |
310 ui.actionGridCoarse->setChecked(grid == Grid::Coarse); |
311 ui.actionGridMedium->setChecked (grid == Grid::Medium); |
311 ui.actionGridMedium->setChecked(grid == Grid::Medium); |
312 ui.actionGridFine->setChecked (grid == Grid::Fine); |
312 ui.actionGridFine->setChecked(grid == Grid::Fine); |
313 |
313 |
314 // Recompile all Bézier curves, the changing grid affects their precision. |
314 // Recompile all Bézier curves, the changing grid affects their precision. |
315 for (LDObjectIterator<LDBezierCurve> it (m_currentDocument); it.isValid(); ++it) |
315 for (LDObjectIterator<LDBezierCurve> it(m_currentDocument); it.isValid(); ++it) |
316 renderer()->compileObject (it); |
316 renderer()->compileObject(it); |
317 } |
317 } |
318 |
318 |
319 // --------------------------------------------------------------------------------------------------------------------- |
319 // --------------------------------------------------------------------------------------------------------------------- |
320 // |
320 // |
321 void MainWindow::updateTitle() |
321 void MainWindow::updateTitle() |
322 { |
322 { |
323 QString title = format (APPNAME " " VERSION_STRING); |
323 QString title = format(APPNAME " " VERSION_STRING); |
324 |
324 |
325 // Append our current file if we have one |
325 // Append our current file if we have one |
326 if (m_currentDocument) |
326 if (m_currentDocument) |
327 { |
327 { |
328 title += ": "; |
328 title += ": "; |
329 title += m_currentDocument->getDisplayName(); |
329 title += m_currentDocument->getDisplayName(); |
330 |
330 |
331 if (m_currentDocument->getObjectCount() > 0 and |
331 if (m_currentDocument->getObjectCount() > 0 and |
332 m_currentDocument->getObject (0)->type() == OBJ_Comment) |
332 m_currentDocument->getObject(0)->type() == OBJ_Comment) |
333 { |
333 { |
334 // Append title |
334 // Append title |
335 LDComment* comm = static_cast <LDComment*> (m_currentDocument->getObject (0)); |
335 LDComment* comm = static_cast <LDComment*>(m_currentDocument->getObject(0)); |
336 title += format (": %1", comm->text()); |
336 title += format(": %1", comm->text()); |
337 } |
337 } |
338 |
338 |
339 if (m_currentDocument->hasUnsavedChanges()) |
339 if (m_currentDocument->hasUnsavedChanges()) |
340 title += '*'; |
340 title += '*'; |
341 } |
341 } |
462 descr = obj->typeName(); |
462 descr = obj->typeName(); |
463 break; |
463 break; |
464 } |
464 } |
465 } |
465 } |
466 |
466 |
467 QListWidgetItem* item = new QListWidgetItem (descr); |
467 QListWidgetItem* item = new QListWidgetItem(descr); |
468 item->setIcon (GetIcon (obj->typeName())); |
468 item->setIcon(GetIcon(obj->typeName())); |
469 |
469 |
470 // Use italic font if hidden |
470 // Use italic font if hidden |
471 if (obj->isHidden()) |
471 if (obj->isHidden()) |
472 { |
472 { |
473 QFont font = item->font(); |
473 QFont font = item->font(); |
474 font.setItalic (true); |
474 font.setItalic(true); |
475 item->setFont (font); |
475 item->setFont(font); |
476 } |
476 } |
477 |
477 |
478 // Color gibberish orange on red so it stands out. |
478 // Color gibberish orange on red so it stands out. |
479 if (obj->type() == OBJ_Error) |
479 if (obj->type() == OBJ_Error) |
480 { |
480 { |
481 item->setBackground (QColor ("#AA0000")); |
481 item->setBackground(QColor("#AA0000")); |
482 item->setForeground (QColor ("#FFAA00")); |
482 item->setForeground(QColor("#FFAA00")); |
483 } |
483 } |
484 else if (config.colorizeObjectsList() |
484 else if (config.colorizeObjectsList() |
485 and obj->isColored() |
485 and obj->isColored() |
486 and obj->color().isValid() |
486 and obj->color().isValid() |
487 and obj->color() != MainColor |
487 and obj->color() != MainColor |
488 and obj->color() != EdgeColor) |
488 and obj->color() != EdgeColor) |
489 { |
489 { |
490 // If the object isn't in the main or edge color, draw this list entry in that color. |
490 // If the object isn't in the main or edge color, draw this list entry in that color. |
491 item->setForeground (obj->color().faceColor()); |
491 item->setForeground(obj->color().faceColor()); |
492 } |
492 } |
493 |
493 |
494 m_objectsInList.insert (obj, item); |
494 m_objectsInList.insert(obj, item); |
495 ui.objectList->insertItem (ui.objectList->count(), item); |
495 ui.objectList->insertItem(ui.objectList->count(), item); |
496 } |
496 } |
497 |
497 |
498 m_isSelectionLocked = false; |
498 m_isSelectionLocked = false; |
499 updateSelection(); |
499 updateSelection(); |
500 scrollToSelection(); |
500 scrollToSelection(); |
739 |
739 |
740 QMenu* contextMenu = new QMenu; |
740 QMenu* contextMenu = new QMenu; |
741 |
741 |
742 if (single and singleObj->type() != OBJ_Empty) |
742 if (single and singleObj->type() != OBJ_Empty) |
743 { |
743 { |
744 contextMenu->addAction (ui.actionEdit); |
744 contextMenu->addAction(ui.actionEdit); |
745 contextMenu->addSeparator(); |
745 contextMenu->addSeparator(); |
746 } |
746 } |
747 |
747 |
748 contextMenu->addAction (ui.actionCut); |
748 contextMenu->addAction(ui.actionCut); |
749 contextMenu->addAction (ui.actionCopy); |
749 contextMenu->addAction(ui.actionCopy); |
750 contextMenu->addAction (ui.actionPaste); |
750 contextMenu->addAction(ui.actionPaste); |
751 contextMenu->addAction (ui.actionRemove); |
751 contextMenu->addAction(ui.actionRemove); |
752 contextMenu->addSeparator(); |
752 contextMenu->addSeparator(); |
753 contextMenu->addAction (ui.actionSetColor); |
753 contextMenu->addAction(ui.actionSetColor); |
754 |
754 |
755 if (single) |
755 if (single) |
756 contextMenu->addAction (ui.actionEditRaw); |
756 contextMenu->addAction(ui.actionEditRaw); |
757 |
757 |
758 contextMenu->addAction (ui.actionMakeBorders); |
758 contextMenu->addAction(ui.actionMakeBorders); |
759 contextMenu->addAction (ui.actionSetOverlay); |
759 contextMenu->addAction(ui.actionSetOverlay); |
760 contextMenu->addAction (ui.actionClearOverlay); |
760 contextMenu->addAction(ui.actionClearOverlay); |
761 |
761 |
762 if (hasSubfiles) |
762 if (hasSubfiles) |
763 { |
763 { |
764 contextMenu->addSeparator(); |
764 contextMenu->addSeparator(); |
765 contextMenu->addAction (ui.actionOpenSubfiles); |
765 contextMenu->addAction(ui.actionOpenSubfiles); |
766 } |
766 } |
767 |
767 |
768 contextMenu->addSeparator(); |
768 contextMenu->addSeparator(); |
769 contextMenu->addAction (ui.actionModeSelect); |
769 contextMenu->addAction(ui.actionModeSelect); |
770 contextMenu->addAction (ui.actionModeDraw); |
770 contextMenu->addAction(ui.actionModeDraw); |
771 contextMenu->addAction (ui.actionModeCircle); |
771 contextMenu->addAction(ui.actionModeCircle); |
772 |
772 |
773 if (not selectedObjects().isEmpty()) |
773 if (not selectedObjects().isEmpty()) |
774 { |
774 { |
775 contextMenu->addSeparator(); |
775 contextMenu->addSeparator(); |
776 contextMenu->addAction (ui.actionSubfileSelection); |
776 contextMenu->addAction(ui.actionSubfileSelection); |
777 } |
777 } |
778 |
778 |
779 if (renderer()->camera() != EFreeCamera) |
779 if (renderer()->camera() != EFreeCamera) |
780 { |
780 { |
781 contextMenu->addSeparator(); |
781 contextMenu->addSeparator(); |
782 contextMenu->addAction (ui.actionSetDrawDepth); |
782 contextMenu->addAction(ui.actionSetDrawDepth); |
783 } |
783 } |
784 |
784 |
785 contextMenu->exec (pos); |
785 contextMenu->exec(pos); |
786 } |
786 } |
787 |
787 |
788 // --------------------------------------------------------------------------------------------------------------------- |
788 // --------------------------------------------------------------------------------------------------------------------- |
789 // |
789 // |
790 void MainWindow::deleteByColor (LDColor color) |
790 void MainWindow::deleteByColor(LDColor color) |
791 { |
791 { |
792 LDObjectList objs; |
792 LDObjectList objs; |
793 |
793 |
794 for (LDObject* obj : m_currentDocument->objects()) |
794 for (LDObject* obj : m_currentDocument->objects()) |
795 { |
795 { |
806 // --------------------------------------------------------------------------------------------------------------------- |
806 // --------------------------------------------------------------------------------------------------------------------- |
807 // |
807 // |
808 void MainWindow::updateEditModeActions() |
808 void MainWindow::updateEditModeActions() |
809 { |
809 { |
810 const EditModeType mode = renderer()->currentEditModeType(); |
810 const EditModeType mode = renderer()->currentEditModeType(); |
811 ui.actionModeSelect->setChecked (mode == EditModeType::Select); |
811 ui.actionModeSelect->setChecked(mode == EditModeType::Select); |
812 ui.actionModeDraw->setChecked (mode == EditModeType::Draw); |
812 ui.actionModeDraw->setChecked(mode == EditModeType::Draw); |
813 ui.actionModeRectangle->setChecked (mode == EditModeType::Rectangle); |
813 ui.actionModeRectangle->setChecked(mode == EditModeType::Rectangle); |
814 ui.actionModeCircle->setChecked (mode == EditModeType::Circle); |
814 ui.actionModeCircle->setChecked(mode == EditModeType::Circle); |
815 ui.actionModeMagicWand->setChecked (mode == EditModeType::MagicWand); |
815 ui.actionModeMagicWand->setChecked(mode == EditModeType::MagicWand); |
816 ui.actionModeLinePath->setChecked (mode == EditModeType::LinePath); |
816 ui.actionModeLinePath->setChecked(mode == EditModeType::LinePath); |
817 ui.actionModeCurve->setChecked (mode == EditModeType::Curve); |
817 ui.actionModeCurve->setChecked(mode == EditModeType::Curve); |
818 } |
818 } |
819 |
819 |
820 // --------------------------------------------------------------------------------------------------------------------- |
820 // --------------------------------------------------------------------------------------------------------------------- |
821 // |
821 // |
822 void MainWindow::objectListDoubleClicked (QListWidgetItem* listitem) |
822 void MainWindow::objectListDoubleClicked(QListWidgetItem* listitem) |
823 { |
823 { |
824 LDObject* object = m_objectsInList.reverseLookup (listitem); |
824 LDObject* object = m_objectsInList.reverseLookup(listitem); |
825 AddObjectDialog::staticDialog (object->type(), object); |
825 AddObjectDialog::staticDialog(object->type(), object); |
826 } |
826 } |
827 |
827 |
828 // --------------------------------------------------------------------------------------------------------------------- |
828 // --------------------------------------------------------------------------------------------------------------------- |
829 // |
829 // |
830 bool MainWindow::save (LDDocument* doc, bool saveAs) |
830 bool MainWindow::save(LDDocument* doc, bool saveAs) |
831 { |
831 { |
832 if (doc->isCache()) |
832 if (doc->isCache()) |
833 return false; |
833 return false; |
834 |
834 |
835 QString path = doc->fullPath(); |
835 QString path = doc->fullPath(); |
842 if (not doc->fullPath().isEmpty()) |
842 if (not doc->fullPath().isEmpty()) |
843 name = doc->fullPath(); |
843 name = doc->fullPath(); |
844 else if (not doc->name().isEmpty()) |
844 else if (not doc->name().isEmpty()) |
845 name = doc->name(); |
845 name = doc->name(); |
846 |
846 |
847 name.replace ("\\", "/"); |
847 name.replace("\\", "/"); |
848 path = QFileDialog::getSaveFileName (this, tr ("Save As"), |
848 path = QFileDialog::getSaveFileName(this, tr("Save As"), |
849 name, tr ("LDraw files (*.dat *.ldr)")); |
849 name, tr("LDraw files(*.dat *.ldr)")); |
850 |
850 |
851 if (path.isEmpty()) |
851 if (path.isEmpty()) |
852 { |
852 { |
853 // User didn't give a file name, abort. |
853 // User didn't give a file name, abort. |
854 return false; |
854 return false; |
855 } |
855 } |
856 } |
856 } |
857 |
857 |
858 if (doc->save (path, &savesize)) |
858 if (doc->save(path, &savesize)) |
859 { |
859 { |
860 if (doc == m_currentDocument) |
860 if (doc == m_currentDocument) |
861 updateTitle(); |
861 updateTitle(); |
862 |
862 |
863 print ("Saved to %1 (%2)", path, MakePrettyFileSize (savesize)); |
863 print("Saved to %1(%2)", path, MakePrettyFileSize(savesize)); |
864 |
864 |
865 // Add it to recent files |
865 // Add it to recent files |
866 m_documents->addRecentFile (path); |
866 m_documents->addRecentFile(path); |
867 return true; |
867 return true; |
868 } |
868 } |
869 |
869 |
870 QString message = format (tr ("Failed to save to %1: %2"), path, strerror (errno)); |
870 QString message = format(tr("Failed to save to %1: %2"), path, strerror(errno)); |
871 |
871 |
872 // Tell the user the save failed, and give the option for saving as with it. |
872 // Tell the user the save failed, and give the option for saving as with it. |
873 QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, this); |
873 QMessageBox dlg(QMessageBox::Critical, tr("Save Failure"), message, QMessageBox::Close, this); |
874 |
874 |
875 // Add a save-as button |
875 // Add a save-as button |
876 QPushButton* saveAsBtn = new QPushButton (tr ("Save As")); |
876 QPushButton* saveAsBtn = new QPushButton(tr("Save As")); |
877 saveAsBtn->setIcon (GetIcon ("file-save-as")); |
877 saveAsBtn->setIcon(GetIcon("file-save-as")); |
878 dlg.addButton (saveAsBtn, QMessageBox::ActionRole); |
878 dlg.addButton(saveAsBtn, QMessageBox::ActionRole); |
879 dlg.setDefaultButton (QMessageBox::Close); |
879 dlg.setDefaultButton(QMessageBox::Close); |
880 dlg.exec(); |
880 dlg.exec(); |
881 |
881 |
882 if (dlg.clickedButton() == saveAsBtn) |
882 if (dlg.clickedButton() == saveAsBtn) |
883 return save (doc, true); // yay recursion! |
883 return save(doc, true); // yay recursion! |
884 |
884 |
885 return false; |
885 return false; |
886 } |
886 } |
887 |
887 |
888 // Adds a message to the renderer's message manager. |
888 // Adds a message to the renderer's message manager. |
889 void MainWindow::addMessage (QString msg) |
889 void MainWindow::addMessage(QString msg) |
890 { |
890 { |
891 m_renderer->messageLog()->addLine (msg); |
891 m_renderer->messageLog()->addLine(msg); |
892 } |
892 } |
893 |
893 |
894 // ============================================================================ |
894 // ============================================================================ |
895 void ObjectList::contextMenuEvent (QContextMenuEvent* ev) |
895 void ObjectList::contextMenuEvent(QContextMenuEvent* ev) |
896 { |
896 { |
897 g_win->spawnContextMenu (ev->globalPos()); |
897 g_win->spawnContextMenu(ev->globalPos()); |
898 } |
898 } |
899 |
899 |
900 // --------------------------------------------------------------------------------------------------------------------- |
900 // --------------------------------------------------------------------------------------------------------------------- |
901 // |
901 // |
902 QPixmap GetIcon (QString iconName) |
902 QPixmap GetIcon(QString iconName) |
903 { |
903 { |
904 return (QPixmap (format (":/icons/%1.png", iconName))); |
904 return (QPixmap(format(":/icons/%1.png", iconName))); |
905 } |
905 } |
906 |
906 |
907 // --------------------------------------------------------------------------------------------------------------------- |
907 // --------------------------------------------------------------------------------------------------------------------- |
908 // |
908 // |
909 bool Confirm (const QString& message) |
909 bool Confirm(const QString& message) |
910 { |
910 { |
911 return Confirm (MainWindow::tr ("Confirm"), message); |
911 return Confirm(MainWindow::tr("Confirm"), message); |
912 } |
912 } |
913 |
913 |
914 // --------------------------------------------------------------------------------------------------------------------- |
914 // --------------------------------------------------------------------------------------------------------------------- |
915 // |
915 // |
916 bool Confirm (const QString& title, const QString& message) |
916 bool Confirm(const QString& title, const QString& message) |
917 { |
917 { |
918 return QMessageBox::question (g_win, title, message, |
918 return QMessageBox::question(g_win, title, message, |
919 (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes; |
919 (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes; |
920 } |
920 } |
921 |
921 |
922 // --------------------------------------------------------------------------------------------------------------------- |
922 // --------------------------------------------------------------------------------------------------------------------- |
923 // |
923 // |
924 void Critical (const QString& message) |
924 void Critical(const QString& message) |
925 { |
925 { |
926 QMessageBox::critical (g_win, MainWindow::tr ("Error"), message, |
926 QMessageBox::critical(g_win, MainWindow::tr("Error"), message, |
927 (QMessageBox::Close), QMessageBox::Close); |
927 (QMessageBox::Close), QMessageBox::Close); |
928 } |
928 } |
929 |
929 |
930 // --------------------------------------------------------------------------------------------------------------------- |
930 // --------------------------------------------------------------------------------------------------------------------- |
931 // |
931 // |
932 void MainWindow::updateDocumentList() |
932 void MainWindow::updateDocumentList() |
933 { |
933 { |
934 m_updatingTabs = true; |
934 m_updatingTabs = true; |
935 |
935 |
936 while (m_tabs->count() > 0) |
936 while (m_tabs->count() > 0) |
937 m_tabs->removeTab (0); |
937 m_tabs->removeTab(0); |
938 |
938 |
939 for (LDDocument* document : m_documents->allDocuments()) |
939 for (LDDocument* document : m_documents->allDocuments()) |
940 { |
940 { |
941 if (not document->isCache()) |
941 if (not document->isCache()) |
942 { |
942 { |
943 // Add an item to the list for this file and store the tab index |
943 // Add an item to the list for this file and store the tab index |
944 // in the document so we can find documents by tab index. |
944 // in the document so we can find documents by tab index. |
945 document->setTabIndex (m_tabs->addTab ("")); |
945 document->setTabIndex(m_tabs->addTab("")); |
946 updateDocumentListItem (document); |
946 updateDocumentListItem(document); |
947 } |
947 } |
948 } |
948 } |
949 |
949 |
950 m_updatingTabs = false; |
950 m_updatingTabs = false; |
951 } |
951 } |
952 |
952 |
953 // --------------------------------------------------------------------------------------------------------------------- |
953 // --------------------------------------------------------------------------------------------------------------------- |
954 // |
954 // |
955 // Update the given document's tab. If no such tab exists, the document list is rebuilt. |
955 // Update the given document's tab. If no such tab exists, the document list is rebuilt. |
956 // |
956 // |
957 void MainWindow::updateDocumentListItem (LDDocument* doc) |
957 void MainWindow::updateDocumentListItem(LDDocument* doc) |
958 { |
958 { |
959 bool oldUpdatingTabs = m_updatingTabs; |
959 bool oldUpdatingTabs = m_updatingTabs; |
960 m_updatingTabs = true; |
960 m_updatingTabs = true; |
961 |
961 |
962 if (doc->tabIndex() == -1) |
962 if (doc->tabIndex() == -1) |
1155 return ui.ringToolSegments->value(); |
1155 return ui.ringToolSegments->value(); |
1156 } |
1156 } |
1157 |
1157 |
1158 // --------------------------------------------------------------------------------------------------------------------- |
1158 // --------------------------------------------------------------------------------------------------------------------- |
1159 // |
1159 // |
1160 void MainWindow::ringToolHiResClicked (bool checked) |
1160 void MainWindow::ringToolHiResClicked(bool checked) |
1161 { |
1161 { |
1162 if (checked) |
1162 if (checked) |
1163 { |
1163 { |
1164 ui.ringToolSegments->setMaximum (HighResolution); |
1164 ui.ringToolSegments->setMaximum(HighResolution); |
1165 ui.ringToolSegments->setValue (ui.ringToolSegments->value() * 3); |
1165 ui.ringToolSegments->setValue(ui.ringToolSegments->value() * 3); |
1166 } |
1166 } |
1167 else |
1167 else |
1168 { |
1168 { |
1169 ui.ringToolSegments->setValue (ui.ringToolSegments->value() / 3); |
1169 ui.ringToolSegments->setValue(ui.ringToolSegments->value() / 3); |
1170 ui.ringToolSegments->setMaximum (LowResolution); |
1170 ui.ringToolSegments->setMaximum(LowResolution); |
1171 } |
1171 } |
1172 } |
1172 } |
1173 |
1173 |
1174 // --------------------------------------------------------------------------------------------------------------------- |
1174 // --------------------------------------------------------------------------------------------------------------------- |
1175 // |
1175 // |
1176 void MainWindow::circleToolSegmentsChanged() |
1176 void MainWindow::circleToolSegmentsChanged() |
1177 { |
1177 { |
1178 int numerator (ui.ringToolSegments->value()); |
1178 int numerator(ui.ringToolSegments->value()); |
1179 int denominator (ui.ringToolHiRes->isChecked() ? HighResolution : LowResolution); |
1179 int denominator(ui.ringToolHiRes->isChecked() ? HighResolution : LowResolution); |
1180 Simplify (numerator, denominator); |
1180 Simplify(numerator, denominator); |
1181 ui.ringToolSegmentsLabel->setText (format ("%1 / %2", numerator, denominator)); |
1181 ui.ringToolSegmentsLabel->setText(format("%1 / %2", numerator, denominator)); |
1182 } |
1182 } |
1183 |
1183 |
1184 // --------------------------------------------------------------------------------------------------------------------- |
1184 // --------------------------------------------------------------------------------------------------------------------- |
1185 // |
1185 // |
1186 // Accessor to the settings object |
1186 // Accessor to the settings object |
1187 // |
1187 // |
1188 QSettings* makeSettings (QObject* parent) |
1188 QSettings* makeSettings(QObject* parent) |
1189 { |
1189 { |
1190 QString path = qApp->applicationDirPath() + "/" UNIXNAME ".ini"; |
1190 QString path = qApp->applicationDirPath() + "/" UNIXNAME ".ini"; |
1191 return new QSettings (path, QSettings::IniFormat, parent); |
1191 return new QSettings(path, QSettings::IniFormat, parent); |
1192 } |
1192 } |
1193 |
1193 |
1194 // --------------------------------------------------------------------------------------------------------------------- |
1194 // --------------------------------------------------------------------------------------------------------------------- |
1195 // |
1195 // |
1196 void MainWindow::syncSettings() |
1196 void MainWindow::syncSettings() |
1198 m_settings->sync(); |
1198 m_settings->sync(); |
1199 } |
1199 } |
1200 |
1200 |
1201 // --------------------------------------------------------------------------------------------------------------------- |
1201 // --------------------------------------------------------------------------------------------------------------------- |
1202 // |
1202 // |
1203 QVariant MainWindow::getConfigValue (QString name) |
1203 QVariant MainWindow::getConfigValue(QString name) |
1204 { |
1204 { |
1205 QVariant value = m_settings->value (name, config.defaultValueByName (name)); |
1205 QVariant value = m_settings->value(name, config.defaultValueByName(name)); |
1206 return value; |
1206 return value; |
1207 } |
1207 } |
1208 |
1208 |
1209 // --------------------------------------------------------------------------------------------------------------------- |
1209 // --------------------------------------------------------------------------------------------------------------------- |
1210 // |
1210 // |
1211 void MainWindow::createBlankDocument() |
1211 void MainWindow::createBlankDocument() |
1212 { |
1212 { |
1213 // Create a new anonymous file and set it to our current |
1213 // Create a new anonymous file and set it to our current |
1214 LDDocument* f = newDocument(); |
1214 LDDocument* f = newDocument(); |
1215 f->setName (""); |
1215 f->setName(""); |
1216 changeDocument (f); |
1216 changeDocument(f); |
1217 closeInitialDocument(); |
1217 closeInitialDocument(); |
1218 doFullRefresh(); |
1218 doFullRefresh(); |
1219 updateActions(); |
1219 updateActions(); |
1220 } |
1220 } |
1221 |
1221 |
1222 // --------------------------------------------------------------------------------------------------------------------- |
1222 // --------------------------------------------------------------------------------------------------------------------- |
1223 // |
1223 // |
1224 LDDocument* MainWindow::newDocument (bool cache) |
1224 LDDocument* MainWindow::newDocument(bool cache) |
1225 { |
1225 { |
1226 LDDocument* document = m_documents->createNew(); |
1226 LDDocument* document = m_documents->createNew(); |
1227 connect (document->history(), SIGNAL (undone()), this, SLOT (historyTraversed())); |
1227 connect(document->history(), SIGNAL(undone()), this, SLOT(historyTraversed())); |
1228 connect (document->history(), SIGNAL (redone()), this, SLOT (historyTraversed())); |
1228 connect(document->history(), SIGNAL(redone()), this, SLOT(historyTraversed())); |
1229 connect (document->history(), SIGNAL (stepAdded()), this, SLOT (updateActions())); |
1229 connect(document->history(), SIGNAL(stepAdded()), this, SLOT(updateActions())); |
1230 |
1230 |
1231 if (not cache) |
1231 if (not cache) |
1232 document->openForEditing(); |
1232 document->openForEditing(); |
1233 |
1233 |
1234 return document; |
1234 return document; |
1341 LDColor ColorToolbarItem::color() const |
1341 LDColor ColorToolbarItem::color() const |
1342 { |
1342 { |
1343 return m_color; |
1343 return m_color; |
1344 } |
1344 } |
1345 |
1345 |
1346 void ColorToolbarItem::setColor (LDColor color) |
1346 void ColorToolbarItem::setColor(LDColor color) |
1347 { |
1347 { |
1348 m_color = color; |
1348 m_color = color; |
1349 } |
1349 } |
1350 |
1350 |
1351 QToolButton* ColorToolbarItem::toolButton() const |
1351 QToolButton* ColorToolbarItem::toolButton() const |
1352 { |
1352 { |
1353 return m_toolButton; |
1353 return m_toolButton; |
1354 } |
1354 } |
1355 |
1355 |
1356 void ColorToolbarItem::setToolButton (QToolButton* value) |
1356 void ColorToolbarItem::setToolButton(QToolButton* value) |
1357 { |
1357 { |
1358 m_toolButton = value; |
1358 m_toolButton = value; |
1359 } |
1359 } |
1360 |
1360 |
1361 // --------------------------------------------------------------------------------------------------------------------- |
1361 // --------------------------------------------------------------------------------------------------------------------- |
1362 // |
1362 // |
1363 void populatePrimitivesTree (QTreeWidget* tw, QString const& selectByDefault) |
1363 void populatePrimitivesTree(QTreeWidget* tw, QString const& selectByDefault) |
1364 { |
1364 { |
1365 tw->clear(); |
1365 tw->clear(); |
1366 |
1366 |
1367 for (PrimitiveCategory* cat : g_PrimitiveCategories) |
1367 for (PrimitiveCategory* cat : g_PrimitiveCategories) |
1368 { |
1368 { |
1369 PrimitiveTreeItem* parentItem = new PrimitiveTreeItem (tw, nullptr); |
1369 PrimitiveTreeItem* parentItem = new PrimitiveTreeItem(tw, nullptr); |
1370 parentItem->setText (0, cat->name()); |
1370 parentItem->setText(0, cat->name()); |
1371 QList<QTreeWidgetItem*> subfileItems; |
1371 QList<QTreeWidgetItem*> subfileItems; |
1372 |
1372 |
1373 for (Primitive& prim : cat->prims) |
1373 for (Primitive& prim : cat->prims) |
1374 { |
1374 { |
1375 PrimitiveTreeItem* item = new PrimitiveTreeItem (parentItem, &prim); |
1375 PrimitiveTreeItem* item = new PrimitiveTreeItem(parentItem, &prim); |
1376 item->setText (0, format ("%1 - %2", prim.name, prim.title)); |
1376 item->setText(0, format("%1 - %2", prim.name, prim.title)); |
1377 subfileItems << item; |
1377 subfileItems << item; |
1378 |
1378 |
1379 // If this primitive is the one the current object points to, |
1379 // If this primitive is the one the current object points to, |
1380 // select it by default |
1380 // select it by default |
1381 if (selectByDefault == prim.name) |
1381 if (selectByDefault == prim.name) |
1382 tw->setCurrentItem (item); |
1382 tw->setCurrentItem(item); |
1383 } |
1383 } |
1384 |
1384 |
1385 tw->addTopLevelItem (parentItem); |
1385 tw->addTopLevelItem(parentItem); |
1386 } |
1386 } |
1387 } |
1387 } |
1388 |
1388 |
1389 PrimitiveTreeItem::PrimitiveTreeItem (QTreeWidgetItem* parent, Primitive* info) : |
1389 PrimitiveTreeItem::PrimitiveTreeItem(QTreeWidgetItem* parent, Primitive* info) : |
1390 QTreeWidgetItem (parent), |
1390 QTreeWidgetItem(parent), |
1391 m_primitive (info) {} |
1391 m_primitive(info) {} |
1392 |
1392 |
1393 PrimitiveTreeItem::PrimitiveTreeItem (QTreeWidget* parent, Primitive* info) : |
1393 PrimitiveTreeItem::PrimitiveTreeItem(QTreeWidget* parent, Primitive* info) : |
1394 QTreeWidgetItem (parent), |
1394 QTreeWidgetItem(parent), |
1395 m_primitive (info) {} |
1395 m_primitive(info) {} |
1396 |
1396 |
1397 Primitive* PrimitiveTreeItem::primitive() const |
1397 Primitive* PrimitiveTreeItem::primitive() const |
1398 { |
1398 { |
1399 return m_primitive; |
1399 return m_primitive; |
1400 } |
1400 } |