1 #include "LDViewMainWindow.h"
2 #include <QtGlobal>
3 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4 #include <QScreen>
5 #else
6 #include <QDesktopWidget>
7 #endif
8 #include "misc.h"
9 #include <QToolButton>
10 #include <TCFoundation/TCLocalStrings.h>
11 #include <QObject>
12 #include <QAction>
13
14 TCStringArray *LDViewMainWindow::recentFiles = NULL;
15
LDViewMainWindow(QApplication * a)16 LDViewMainWindow::LDViewMainWindow(QApplication *a)
17 :QMainWindow(),Ui::LDView(),
18 #ifdef __APPLE__
19 openRecentMenu(NULL),
20 #endif // __APPLE__
21 fileSeparatorIndex(-1),
22 toolbarMaxStep(new QLabel),
23 toolbarCurrentStep(new QLabel),
24 toolbarStepLabel(new QLabel("Step :")),
25 toolbarViewAngle(NULL),
26 toolbarWireframeMenu(new QMenu(this)),
27 edgeMenu(new QMenu(this)),
28 bfcMenu(new QMenu(this)),
29 primitiveMenu(new QMenu(this))
30 {
31 setupUi(this);
32 toolbar->insertWidget(toolbarFirstStep,toolbarStepLabel);
33 toolbar->insertWidget(toolbarFirstStep,toolbarCurrentStep);
34 toolbar->insertWidget(toolbarFirstStep,toolbarMaxStep);
35 if (modelViewer) modelViewer->setMainWindow(this);
36 connect( fileOpenAction, SIGNAL( triggered() ), this, SLOT( fileOpen() ) );
37 connect( fileSaveSettingsAction, SIGNAL( triggered() ), this, SLOT( fileSaveSettings() ) );
38 connect( fileExportAction, SIGNAL( triggered() ), this, SLOT( fileExport() ) );
39 connect( fileExportOptionAction, SIGNAL( triggered() ), this, SLOT( fileExportOption() ) );
40 connect( file3DSExportOptionAction, SIGNAL( triggered() ), this, SLOT( file3DSExportOption() ) );
41 connect( fileJPEGOptionsAction, SIGNAL( triggered() ), this, SLOT( fileJPEGOptions() ) );
42 connect( fileSaveAction, SIGNAL( triggered() ), this, SLOT( fileSave() ) );
43 connect( filePrintAction, SIGNAL( triggered() ), this, SLOT( filePrint() ) );
44 connect( fileExitAction, SIGNAL( triggered() ), this, SLOT( fileExit() ) );
45 connect( helpContentsAction, SIGNAL( triggered() ), this, SLOT( helpContents() ) );
46 connect( helpAboutAction, SIGNAL( triggered() ), this, SLOT( helpAbout() ) );
47 connect( helpAboutQtAction, SIGNAL( triggered() ), this, SLOT( helpAboutQt() ) );
48 connect( editPreferencesAction, SIGNAL( triggered() ), this, SLOT( editPreferences() ) );
49 connect( viewToolBarAction, SIGNAL( toggled(bool) ), this, SLOT( viewToolBar(bool) ) );
50 connect( toolbarWireframeAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarWireframe(bool) ) );
51 connect( toolbarEdgeAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarEdge(bool) ) );
52 connect( toolbarPrimitiveSubstitutionAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarPrimitiveSubstitution(bool) ) );
53 connect( toolbarLightingAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarLighting(bool) ) );
54 connect( toolbarBFCAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarBFC(bool) ) );
55 connect( toolbarAxesAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarAxes(bool) ) );
56 connect( toolbarSeamsAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarSeams(bool) ) );
57 connect( viewStatusBarAction, SIGNAL( toggled(bool) ), this, SLOT( viewStatusBar(bool) ) );
58 connect( viewLatitudeRotationAction, SIGNAL( toggled(bool) ), this, SLOT( latitudeRotation(bool) ) );
59 connect( viewKeepRightSideUpAction, SIGNAL( toggled(bool) ), this, SLOT( keepRightSideUp(bool) ) );
60 connect( viewFullScreenAction, SIGNAL( triggered() ), this, SLOT( viewFullScreen() ) );
61 connect( viewResetViewAction, SIGNAL( triggered() ), this, SLOT( viewResetView() ) );
62 connect( helpOpenGLDriverInfoAction, SIGNAL( triggered() ), this, SLOT( helpOpenGLDriverInfo() ) );
63 connect( fileLDrawDirAction, SIGNAL( triggered() ), this, SLOT( fileLDrawDir() ) );
64 connect( fileExtraDirAction, SIGNAL( triggered() ), this, SLOT( fileExtraDir() ) );
65 connect( fileCheckForUpdatesAction, SIGNAL( triggered() ), this, SLOT( fileCheckForUpdates() ) );
66 connect( fileReloadAction, SIGNAL( triggered() ), this, SLOT( fileReload() ) );
67 connect( viewShowErrorsAction, SIGNAL( triggered() ), this, SLOT( viewShowErrors() ) );
68 connect( pollActionGroup, SIGNAL( triggered(QAction*) ), this, SLOT( pollChanged(QAction*) ) );
69 connect( viewZoomToFitAction, SIGNAL( triggered() ), this, SLOT( viewZoomToFit() ) );
70 connect( viewRightSideUpAction, SIGNAL( triggered() ), this, SLOT( viewRightSideUp() ) );
71 connect( viewCameraLocationAction, SIGNAL( triggered() ), this, SLOT (viewCameraLocation() ) );
72 connect( viewRotationCenterAction, SIGNAL( triggered() ), this, SLOT (viewRotationCenter() ) );
73 connect( viewModeActionGroup, SIGNAL( triggered(QAction*) ), this, SLOT( viewModeChanged(QAction*) ) );
74 connect( frontViewAngleAction, SIGNAL( triggered() ), this, SLOT( frontViewAngle() ) );
75 connect( backViewAngleAction, SIGNAL( triggered() ), this, SLOT( backViewAngle() ) );
76 connect( leftViewAngleAction, SIGNAL( triggered() ), this, SLOT( leftViewAngle() ) );
77 connect( rightViewAngleAction, SIGNAL( triggered() ), this, SLOT( rightViewAngle() ) );
78 connect( topViewAngleAction, SIGNAL( triggered() ), this, SLOT( topViewAngle() ) );
79 connect( bottomViewAngleAction, SIGNAL( triggered() ), this, SLOT( bottomViewAngle() ) );
80 connect( latLongViewAngleAction, SIGNAL( triggered() ), this, SLOT( latLongViewAngle() ) );
81 connect( isoViewAngleAction, SIGNAL( triggered() ), this, SLOT( isoViewAngle() ) );
82 connect( saveDefaultViewAngleAction, SIGNAL( triggered() ), this, SLOT( saveDefaultViewAngle() ) );
83 connect( fileCancelLoadAction, SIGNAL( triggered() ), this, SLOT( fileCancelLoad() ) );
84 connect( showViewInfoAction, SIGNAL( triggered() ), this, SLOT( showViewInfo() ) );
85 connect( showPovCameraAction, SIGNAL( triggered() ), this, SLOT( showPovCamera() ) );
86 connect( showPovAspectRatioAction, SIGNAL( toggled(bool) ), this, SLOT( showPovAspectRatio(bool) ) );
87 connect( toolsPartListAction, SIGNAL( triggered() ), this, SLOT( toolsPartList() ) );
88 connect( toolbarPrevStep, SIGNAL( triggered() ), this, SLOT( prevStep() ) );
89 connect( toolbarNextStep, SIGNAL( triggered() ), this, SLOT( nextStep() ) );
90 connect( toolbarFirstStep, SIGNAL( triggered() ), this, SLOT( firstStep() ) );
91 connect( toolbarLastStep, SIGNAL( triggered() ), this, SLOT( lastStep() ) );
92 connect( stepGoto, SIGNAL( triggered() ), this, SLOT( gotoStep() ) );
93 connect( toolsModelTreeAction, SIGNAL( triggered() ), this, SLOT( toolsModelTree() ) );
94 connect( toolsBoundingBoxAction, SIGNAL( triggered() ), this, SLOT( toolsBoundingBox() ) );
95 connect( toolsMpdModelSelectionAction, SIGNAL( triggered() ), this, SLOT( toolsMpdModelSelection() ) );
96
97 connect(fileMenu, SIGNAL(aboutToShow()), this, SLOT(doFileMenuAboutToShow()));
98 connect(editMenu, SIGNAL(aboutToShow()), this, SLOT(doEditMenuAboutToShow()));
99 connect(viewMenu, SIGNAL(aboutToShow()), this, SLOT(doViewMenuAboutToShow()));
100 connect(toolsMenu,SIGNAL(aboutToShow()), this, SLOT(doToolsMenuAboutToShow()));
101 connect(helpMenu, SIGNAL(aboutToShow()), this, SLOT(doHelpMenuAboutToShow()));
102
103 int cnt,i;
104 QAction *item;
105 for ( cnt = i = 0; ; i++)
106 {
107 item = fileMenu->actions()[i];
108 if (item->isSeparator())
109 {
110 if (++cnt == 2)
111 break;
112 }
113 }
114 fileSeparatorIndex = i;
115 #ifdef __APPLE__
116 /*
117 fileMenu->removeItemAt(fileSeparatorIndex);
118 fileSeparatorIndex = -1;
119 openRecentMenu = new QMenu(this, "openRecentMenu");
120 fileMenu->insertItem("Open Recent", openRecentMenu, -1, 1);
121 */
122 #endif // __APPLE__
123 if (!recentFiles)
124 {
125 recentFiles = new TCStringArray(10);
126 populateRecentFiles();
127 }
128 populateRecentFileMenuItems();
129 setupStandardSizes();
130 #ifdef __APPLE__
131 // Since Preferences is the only item in the edit menu, we need to
132 // delete the edit menu on the Mac, since the item is going to get
133 // magically moved to the LDView menu. The problem is, if we delete
134 // the edit menu, the magic stops working, since it's apparently all
135 // done on the fly. So, we're going to create a new fully-functional
136 // Preferences menu item at the top of the File menu, and THEN delete
137 // the edit menu. This newly created menu item won't be visible to the
138 // user, but it will make the other one continue to function after the
139 // deletion of the edit menu.
140 // fileMenu->insertItem("Preferences", this, SLOT(doPreferences()),
141 // 0, -1, 0);
142 // Remove the (empty without Preferences) edit menu.
143 // menuBar->removeItem(menuBar->idAt(1));
144 #endif //__APPLE__
145 toolbarViewAngle = new QToolButton(toolbar);
146 toolbarViewAngle->setMenu(viewingAnglePopupMenu);
147 toolbarViewAngle->setPopupMode(QToolButton::InstantPopup);
148 toolbarViewAngle->setIcon(QPixmap( ":/images/Icons/toolbar_view.png"));
149 toolbarViewAngle->setEnabled(false);
150 toolbar->insertWidget(editPreferencesAction,toolbarViewAngle);
151 connect( wireframeFogAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarWireframeFog(bool) ) );
152 connect( wireframeRemoveHiddenLinesAction, SIGNAL( toggled(bool) ), this, SLOT( toolbarWireframeRemoveHiddenLines(bool) ) );
153 toolbarWireframeMenu->addAction(wireframeFogAction);
154 toolbarWireframeMenu->addAction(wireframeRemoveHiddenLinesAction);
155 QToolButton *toolbarWireframe =
156 (QToolButton *)toolbar->widgetForAction(toolbarWireframeAction);
157 if (toolbarWireframe != NULL)
158 {
159 toolbarWireframe->setMenu(toolbarWireframeMenu);
160 toolbarWireframe->setPopupMode(QToolButton::MenuButtonPopup);
161 }
162 connect( textureStudAction, SIGNAL( toggled(bool) ), this, SLOT( textureStud(bool) ) );
163 primitiveMenu->addAction(textureStudAction);
164 QToolButton *toolbarPrimitives =
165 (QToolButton *)toolbar->widgetForAction(toolbarPrimitiveSubstitutionAction);
166 if (toolbarPrimitives)
167 {
168 toolbarPrimitives->setMenu(primitiveMenu);
169 toolbarPrimitives->setPopupMode(QToolButton::MenuButtonPopup);
170 }
171 connect( edgeShowEdgeOnlyAction, SIGNAL( toggled(bool) ), this, SLOT( edgeShowEdgeOnly(bool) ) );
172 connect( edgeConditionalLineAction, SIGNAL( toggled(bool) ), this, SLOT( edgeConditionalLine(bool) ) );
173 connect( edgeHighQualityAction, SIGNAL( toggled(bool) ), this, SLOT( edgeHighQuality(bool) ) );
174 connect( edgeAlwaysBlackAction, SIGNAL( toggled(bool) ), this, SLOT( edgeAlwaysBlack(bool) ) );
175 edgeMenu->addAction(edgeShowEdgeOnlyAction);
176 edgeMenu->addAction(edgeConditionalLineAction);
177 edgeMenu->addAction(edgeHighQualityAction);
178 edgeMenu->addAction(edgeAlwaysBlackAction);
179 QToolButton *toolbarEdge =
180 (QToolButton *)toolbar->widgetForAction(toolbarEdgeAction);
181 if (toolbarEdge)
182 {
183 toolbarEdge->setMenu(edgeMenu);
184 toolbarEdge->setPopupMode(QToolButton::MenuButtonPopup);
185 }
186 connect( bfcRedBackFacesAction, SIGNAL( toggled(bool) ), this, SLOT( bfcRedBackFaces(bool) ) );
187 connect( bfcGreenFrontFacesAction, SIGNAL( toggled(bool) ), this, SLOT( bfcGreenFrontFaces(bool) ) );
188 connect( bfcBlueNeutralFacesAction, SIGNAL( toggled(bool) ), this, SLOT( bfcBlueNeutralFaces(bool) ) );
189 bfcMenu->addAction(bfcRedBackFacesAction);
190 bfcMenu->addAction(bfcGreenFrontFacesAction);
191 bfcMenu->addAction(bfcBlueNeutralFacesAction);
192 QToolButton *toolbarBfc =
193 (QToolButton *)toolbar->widgetForAction(toolbarBFCAction);
194 if (toolbarBfc)
195 {
196 toolbarBfc->setMenu(bfcMenu);
197 toolbarBfc->setPopupMode(QToolButton::MenuButtonPopup);
198 }
199 modelViewer->setApplication(a);
200 }
201
standardSizeSelected()202 void LDViewMainWindow::standardSizeSelected()
203 {
204 QAction *action = qobject_cast<QAction *>(sender());
205 QString text;
206 #if QT_VERSION >= 0x60000
207 QRegularExpression sep( "\\s+" );
208 #else
209 QRegExp sep( "\\s+" );
210 #endif
211 text = action->text();
212 if (! text.isNull())
213 {
214 int w,h;
215 bool ok;
216 w = text.section(sep,0,0).toInt(&ok);
217 h = text.section(sep,2,2).toInt(&ok);
218 resize(w + size().width() -
219 modelViewer->getModelViewer()->getWidth(),
220 h + size().height() -
221 modelViewer->getModelViewer()->getHeight());
222 }
223 }
224
setupStandardSizes()225 void LDViewMainWindow::setupStandardSizes()
226 {
227 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
228 QSize workArea = QGuiApplication::primaryScreen()->availableGeometry().size();
229 #else
230 QSize workArea = QApplication::desktop()->availableGeometry(this).size();
231 #endif
232 QSize windowSize = frameSize();
233 LDrawModelViewer::getStandardSizes(workArea.width() - windowSize.width() +
234 modelViewer->getModelViewer()->getWidth(),
235 workArea.height() - windowSize.height() +
236 modelViewer->getModelViewer()->getHeight(),
237 standardSizes);
238 standardSizesPopupMenu->clear();
239 for (size_t i = 0; i < standardSizes.size(); i++)
240 {
241 QString qs;
242 ucstringtoqstring(qs, standardSizes[i].name);
243 QAction *act = standardSizesPopupMenu->addAction(qs);
244 connect( act, SIGNAL( triggered() ), this, SLOT(standardSizeSelected()) );
245 }
246 }
247
pollChanged(QAction * action)248 void LDViewMainWindow::pollChanged(QAction *action)
249 {
250 LDVPollMode newMode = LDVPollNone;
251 if (action == promptPollingAction)
252 {
253 newMode = LDVPollPrompt;
254 }
255 else if (action == autoPollingAction)
256 {
257 newMode = LDVPollAuto;
258 }
259 else if (action == backgroundPollingAction)
260 {
261 newMode = LDVPollBackground;
262 }
263 modelViewer->doPollChanged(newMode);
264 }
265
setPollAction(LDVPollMode mode)266 void LDViewMainWindow::setPollAction(LDVPollMode mode)
267 {
268 QAction *pollAction;
269 switch (mode)
270 {
271 case LDVPollPrompt:
272 pollAction = promptPollingAction;
273 break;
274 case LDVPollAuto:
275 pollAction = autoPollingAction;
276 break;
277 case LDVPollBackground:
278 pollAction = backgroundPollingAction;
279 break;
280 default:
281 pollAction = noPollingAction;
282 break;
283 }
284 pollAction->setChecked(true);
285
286 }
287
setMenuItemsEnabled(QMenu * menu,bool enabled)288 void LDViewMainWindow::setMenuItemsEnabled(QMenu *menu, bool enabled)
289 {
290 int count = menu->actions().count();
291 int i;
292
293 for (i = 0; i < count; i++)
294 {
295 menu->actions()[i]->setEnabled(enabled);
296 }
297 }
298
doFileMenuAboutToShow(void)299 void LDViewMainWindow::doFileMenuAboutToShow(void)
300 {
301 if (modelViewer->isLoading())
302 {
303 setMenuItemsEnabled(fileMenu, false);
304 fileCancelLoadAction->setEnabled(true);
305 }
306 else
307 {
308 setMenuItemsEnabled(fileMenu, true);
309 fileCancelLoadAction->setEnabled(false);
310 if (!modelViewer->getModelViewer() || !modelViewer->getModelViewer()->getMainTREModel())
311 {
312 fileReloadAction->setEnabled(false);
313 fileSaveAction->setEnabled(false);
314 fileExportAction->setEnabled(false);
315 filePrintAction->setEnabled(false);
316 fileCancelLoadAction->setEnabled(false);
317 }
318 }
319 }
320
doEditMenuAboutToShow(void)321 void LDViewMainWindow::doEditMenuAboutToShow(void)
322 {
323 if (modelViewer->isLoading())
324 {
325 setMenuItemsEnabled(editMenu, false);
326 }
327 else
328 {
329 setMenuItemsEnabled(editMenu, true);
330 }
331 }
332
doViewMenuAboutToShow(void)333 void LDViewMainWindow::doViewMenuAboutToShow(void)
334 {
335 if (modelViewer->isLoading())
336 {
337 setMenuItemsEnabled(viewMenu, false);
338 }
339 else
340 {
341 if (!modelViewer->getModelViewer() || !modelViewer->getModelViewer()->getMainTREModel())
342 {
343 setMenuItemsEnabled(viewMenu, false);
344 viewToolBarAction->setEnabled(true);
345 viewStatusBarAction->setEnabled(true);
346 }
347 else
348 {
349 setMenuItemsEnabled(viewMenu, true);
350 viewLatitudeRotationAction->setEnabled( modelViewer->getViewMode() == LDInputHandler::VMExamine);
351 viewKeepRightSideUpAction->setEnabled( modelViewer->getViewMode() == LDInputHandler::VMFlyThrough);
352 }
353 }
354 //setupStandardSizes();
355 }
356
doToolsMenuAboutToShow(void)357 void LDViewMainWindow::doToolsMenuAboutToShow(void)
358 {
359 if (modelViewer->isLoading())
360 {
361 setMenuItemsEnabled(toolsMenu, false);
362 }
363 else
364 {
365 if (!modelViewer->getModelViewer() || !modelViewer->getModelViewer()->getMainTREModel())
366 {
367 setMenuItemsEnabled(toolsMenu, false);
368 }
369 else
370 setMenuItemsEnabled(toolsMenu, true);
371 }
372 }
373
doHelpMenuAboutToShow(void)374 void LDViewMainWindow::doHelpMenuAboutToShow(void)
375 {
376 setMenuItemsEnabled(helpMenu, !modelViewer->isLoading());
377 }
378
truncateFilename(const char * filename)379 char *LDViewMainWindow::truncateFilename(const char *filename)
380 {
381 if (filename)
382 {
383 int len = strlen(filename);
384
385 if (len > 40)
386 {
387 char *retValue = new char[44];
388
389 strncpy(retValue, filename, 10);
390 strcpy(retValue + 10, "...");
391 strcat(retValue, filename + len - 30);
392 return retValue;
393 }
394 else
395 {
396 return copyString(filename);
397 }
398 }
399 else
400 {
401 return NULL;
402 }
403 }
404
405
clearRecentFileMenuItems(void)406 void LDViewMainWindow::clearRecentFileMenuItems(void)
407 {
408 #ifdef __APPLE__
409 if (openRecentMenu)
410 {
411 openRecentMenu->clear();
412 }
413 #else // __APPLE__
414 QAction *item;
415 int index = fileSeparatorIndex + 1;
416 int i;
417 int count = fileMenu->actions().count();
418
419 for (i = index; i < count - 1; i++)
420 {
421 item = fileMenu->actions()[index];
422 fileMenu->removeAction(item);
423 }
424 #endif // __APPLE__
425 }
426
populateRecentFiles(void)427 void LDViewMainWindow::populateRecentFiles(void)
428 {
429 int i;
430 long maxRecentFiles = Preferences::getMaxRecentFiles();
431
432 recentFiles->removeAll();
433 for (i = 1; i <= maxRecentFiles; i++)
434 {
435 char *filename = Preferences::getRecentFile(i);
436
437 if (filename)
438 {
439 recentFiles->addString(filename);
440 delete filename;
441 }
442 else
443 {
444 recentFiles->addString(NULL);
445 }
446 }
447 }
448
populateRecentFileMenuItems(void)449 void LDViewMainWindow::populateRecentFileMenuItems(void)
450 {
451 #ifdef __APPLE__
452 if (!openRecentMenu)
453 {
454 return;
455 }
456 #endif // __APPLE__
457 clearRecentFileMenuItems();
458
459 if (recentFiles->stringAtIndex(0))
460 {
461 int i;
462 long maxRecentFiles = Preferences::getMaxRecentFiles();
463
464 for (i = 0; i < maxRecentFiles; i++)
465 {
466 char *filename = truncateFilename(recentFiles->stringAtIndex(i));
467
468 if (filename)
469 {
470 #ifdef __APPLE__
471 QMenu *menu = openRecentMenu;
472 #else // __APPLE__
473 QMenu *menu = fileMenu;
474 #endif // __APPLE__
475 QAction *act;
476 act = new QAction(filename,this);
477 act->setData(i);
478 menu->insertAction(fileMenu->actions()[fileMenu->actions().count() - 1],
479 act);
480 connect( act, SIGNAL( triggered() ), this, SLOT(doRecentFile()) );
481 delete filename;
482 }
483 }
484 #ifndef __APPLE__
485 fileMenu->insertSeparator(fileMenu->actions()[fileMenu->actions().count() - 1]);
486 #endif // __APPLE__
487 }
488 }
489
recordRecentFiles(void)490 void LDViewMainWindow::recordRecentFiles(void)
491 {
492 int i;
493 long maxRecentFiles = Preferences::getMaxRecentFiles();
494
495 for (i = 1; i <= maxRecentFiles; i++)
496 {
497 char *filename = recentFiles->stringAtIndex(i - 1);
498
499 Preferences::setRecentFile(i, filename);
500 }
501 }
502
doRecentFile()503 void LDViewMainWindow::doRecentFile()
504 {
505 QAction *action = qobject_cast<QAction *>(sender());
506 modelViewer->doRecentFile(action->data().toInt());
507 }
508
509