1 #include <QFileDialog>
2 #include <QProgressBar>
3 #include <QTextBrowser>
4 #include <QTextStream>
5 #include <QApplication>
6 #include <QStatusBar>
7 #include <QPainter>
8 #include <QMessageBox>
9 #include <QDateTime>
10 #include <QClipboard>
11 #include <QProcess>
12 #include <QProgressDialog>
13 #include <QTimer>
14 #include <QtGlobal>
15 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
16 #include <QScreen>
17 #else
18 #include <QDesktopWidget>
19 #endif
20 #include <QInputDialog>
21 #include <QPrintDialog>
22 #include <QDesktopServices>
23 #include <QPrinter>
24 #include <QFileInfo>
25 #ifdef __APPLE__
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <CoreServices/CoreServices.h>
28 #include <ApplicationServices/ApplicationServices.h>
29 #endif // __APPLE__
30 #include "misc.h"
31
32 #include <TCFoundation/TCAutoreleasePool.h>
33 #include <TCFoundation/mystring.h>
34 #include <TCFoundation/TCStringArray.h>
35 #include <TCFoundation/TCAlertManager.h>
36 #include <TCFoundation/TCProgressAlert.h>
37 #include <TCFoundation/TCMacros.h>
38 #include <TCFoundation/TCLocalStrings.h>
39 #include <TCFoundation/TCWebClient.h>
40 #include <LDLoader/LDLError.h>
41 #include <LDLoader/LDLModel.h>
42 #include <LDLib/LDrawModelViewer.h>
43 #include <LDLib/LDInputHandler.h>
44 //#include <LDLib/ModelMacros.h>
45 #include <TRE/TREMainModel.h>
46 #include <TRE/TREGLExtensions.h>
47 #include "About.h"
48 #include "Help.h"
49 #include "LDViewMainWindow.h"
50 #include "LDViewErrors.h"
51 #include "LDViewModelTree.h"
52 #include "LDViewExtraDir.h"
53 #include "LDViewExportOption.h"
54 #include "LDViewSnapshotSettings.h"
55 #include "LDViewPartList.h"
56 #include <TCFoundation/TCUserDefaults.h>
57 #include "LDLib/LDUserDefaultsKeys.h"
58 #include <LDLib/LDPartsList.h>
59 #include <assert.h>
60
61 #include "ModelViewerWidget.h"
62 #include "AlertHandler.h"
63 #include <LDLib/LDConsoleAlertHandler.h>
64
65 #define POLL_INTERVAL 500
66
67 #define PNG_IMAGE_TYPE_INDEX 1
68 #define BMP_IMAGE_TYPE_INDEX 2
69 #define JPG_IMAGE_TYPE_INDEX 3
70 #define WIN_WIDTH 640
71 #define WIN_HEIGHT 480
72
73
ModelViewerWidget(QWidget * parent)74 ModelViewerWidget::ModelViewerWidget(QWidget *parent)
75 #if (QT_VERSION >= 0x50400) && defined(QOPENGLWIDGET)
76 :QOpenGLWidget(parent),
77 #else
78 :QGLWidget(parent),
79 #endif
80 modeltree(new LDViewModelTree(parent,preferences,this)),
81 cameralocation(new CameraLocation(parent, this)),
82 rotationcenter(new RotationCenter(parent, this)),
83 boundingbox(new BoundingBox(parent, this)),
84 mpdmodel(new MpdModel(parent,this)),
85 modelViewer(new LDrawModelViewer(100, 100)),
86 snapshotTaker(NULL),
87 lastX(-1),
88 lastY(-1),
89 originalZoomY(-1),
90 rotationSpeed(0.0f),
91 viewMode(LDInputHandler::VMExamine),
92 spinButton(1),
93 zoomButton(2),
94 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
95 fbo(NULL),
96 #endif
97 preferences(NULL),
98 extradir(NULL),
99 snapshotsettings(NULL),
100 jpegoptions(NULL),
101 extensionsPanel(NULL),
102 latitudelongitude(new LatitudeLongitude(parent, this)),
103 aboutPanel(NULL),
104 helpContents(NULL),
105 mainWindow(NULL),
106 statusBar(NULL),
107 progressBar(NULL),
108 progressLabel(NULL),
109 progressLatlong(NULL),
110 progressMode(NULL),
111 loading(false),
112 saving(false),
113 printing(false),
114 cancelLoad(false),
115 app(NULL),
116 painting(false),
117 fps(-1.0),
118 numFramesSinceReference(0),
119 paintTimer(0),
120 pollTimer(0),
121 loadTimer(0),
122 libraryUpdateTimer(0),
123 saveDialog(NULL),
124 errors(new LDViewErrors(this, preferences)),
125 lastFileSize(0),
126 fileInfo(NULL),
127 lockCount(0),
128 fullscreen(0),
129 #ifdef __APPLE__
130 // openRecentMenu(NULL),
131 #endif // __APPLE__
132 alertHandler(new AlertHandler(this)),
133 #if !defined(_NO_BOOST) || defined(USE_CPP11)
134 libraryUpdater(NULL),
135 #endif
136 libraryUpdateProgressReady(false),
137 libraryUpdateWindow(NULL),
138 lightingSelection(0),
139 commandLineSnapshotSave(false)
140 {
141 int i;
142
143 inputHandler = modelViewer->getInputHandler();
144 LDLModel::setFileCaseCallback(staticFileCaseCallback);
145 QImage studImage(":/images/images/StudLogo.png");
146
147 TREMainModel::setRawStudTextureData(studImage.bits(),
148 #if QT_VERSION < 0x40600
149 studImage.numBytes());
150 #else
151 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
152 studImage.byteCount());
153 #else
154 studImage.sizeInBytes());
155 #endif
156 #endif
157
158 for (i = 0; i < MAX_MOUSE_BUTTONS; i++)
159 {
160 mouseButtonsDown[i] = false;
161 }
162 preferences = new Preferences(parent,this);
163 extradir = new ExtraDir(parent,this);
164 snapshotsettings = new SnapshotSettings(parent,this);
165 jpegoptions = new JpegOptions(parent,this);
166 preferences->doApply();
167 setViewMode(Preferences::getViewMode(),
168 examineLatLong = Preferences::getLatLongMode(),
169 keepRightSide = Preferences::getKeepRightSideUp());
170 setFocusPolicy(Qt::StrongFocus);
171 setupUserAgent();
172 }
173
~ModelViewerWidget(void)174 ModelViewerWidget::~ModelViewerWidget(void)
175 {
176 TCObject::release(snapshotTaker);
177 TCObject::release(modelViewer);
178 delete preferences;
179 delete extensionsPanel;
180 delete errors;
181 TCObject::release(alertHandler);
182 alertHandler = NULL;
183 }
184
setupUserAgent(void)185 void ModelViewerWidget::setupUserAgent(void)
186 {
187 // If uname below doesn't work, just use the generic "QT" instead.
188 QString osName = "QT-";
189 QString userAgent;
190 // If we can't parse the version out of the AboutPanel, use 3.2. Note: this
191 // should be updated in future versions, but the extraction from the
192 // AboutPanel hopefully won't fail.
193 QString ldviewVersion = "4.3";
194 bool foundVersion = false;
195 QString fullVersion;
196
197 int spot;
198 osName +=
199 #if defined (Q_OS_LINUX)
200 "Linux"
201 #elif defined (Q_OS_AIX)
202 "AIX"
203 #elif defined (Q_OS_NETBSD)
204 "NetBSD"
205 #elif defined (Q_OS_FREEBSD)
206 "FreeBSD"
207 #elif defined (Q_OS_SOLARIS)
208 "Solaris"
209 #elif defined (Q_OS_WIN32)
210 "Windows"
211 #elif defined (Q_OS_WIN64)
212 "Windows"
213 #elif defined (Q_OS_HPUX)
214 "HP/UX"
215 #elif defined (Q_OS_CYGWIN)
216 "Cygwin"
217 #elif defined (Q_OS_IRIX)
218 "Irix"
219 #elif defined (Q_OS_OSF)
220 "Osf"
221 #else
222 "unknown"
223 #endif
224 ;
225 // We're going to grab the version label from the about panel, so make sure
226 // it's created first.
227 createAboutPanel();
228 fullVersion = aboutPanel->getText();
229 // The version will always begin with a number.
230 if ((spot = fullVersion.indexOf(
231 #if QT_VERSION >= 0x60000
232 QRegularExpression("[0-9]")
233 #else
234 QRegExp("[0-9]")
235 #endif
236 )) != -1)
237 {
238 fullVersion = fullVersion.right(fullVersion.length() - spot);
239 // The first thing after the version is an open parenthesis. Look
240 // for that.
241 if ((spot = fullVersion.indexOf("(")) != -1)
242 {
243 fullVersion = fullVersion.left(spot);
244 ldviewVersion = fullVersion.trimmed();
245 foundVersion = true;
246 }
247 }
248 // Even though we have a default value for the version, we REALLY want to
249 // extract it from the about panel. Assert if the above extraction wasn't
250 // successful.
251 assert(foundVersion);
252 userAgent=QString("LDView/%1 (%2; ldview@gmail.com; "
253 "https://github.com/tcobbs/ldview)").arg(ldviewVersion).arg(osName);
254 TCWebClient::setUserAgent(userAgent.toLatin1().constData());
255 }
256
setApplication(QApplication * value)257 void ModelViewerWidget::setApplication(QApplication *value)
258 {
259 char *arg0;
260
261 app = value;
262 arg0 = copyString(QCoreApplication::arguments().at(0).toUtf8().constData());
263 if (strrchr(arg0, '/'))
264 {
265 *strrchr(arg0, '/') = 0;
266 }
267 modelViewer->setProgramPath(arg0);
268 delete arg0;
269 QString arg1;
270 if (QCoreApplication::arguments().size()>1 && QString::compare (QCoreApplication::arguments().at(1), "-specialcharacters")==0)
271 {
272 QMessageBox::information(this, "Special Characters",
273 QString::fromWCharArray(TCLocalStrings::get(L"SpecialCharacters")),
274 QMessageBox::Ok, QMessageBox::NoButton);
275 }
276 QString fontFilePath = findPackageFile("SansSerif.fnt");
277 QFile fontFile (fontFilePath);
278 if (fontFile.exists())
279 {
280 int len = fontFile.size();
281 if (len > 0)
282 {
283 char *buffer = (char*)malloc(len);
284 if ( fontFile.open( QIODevice::ReadOnly ) )
285 {
286 QDataStream stream( &fontFile );
287 stream.readRawData(buffer,len);
288 modelViewer->setFontData((TCByte*)buffer,len);
289 }
290 }
291 }
292 QImage fontImage2x(":/images/images/SanSerif@2x.png");
293 #if QT_VERSION < 0x40600
294 long len = fontImage2x.numBytes();
295 #else
296 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
297 long len = fontImage2x.byteCount();
298 #else
299 long len = fontImage2x.sizeInBytes();
300 #endif
301 #endif
302 modelViewer->setRawFont2xData(fontImage2x.bits(),len);
303
304 bool shouldExit = false;
305 // Let LDSnapshotTaker perform an export if requested, but don't try to use
306 // it to save snapshots, because that doesn't work.
307 if (LDSnapshotTaker::doCommandLine(false, true))
308 {
309 shouldExit = true;
310 }
311 const TCStringArray *commandLine = TCUserDefaults::getProcessedCommandLine();
312 const char *commandLineFilename = NULL;
313
314 TCUserDefaults::removeValue(HFOV_KEY, false);
315 TCUserDefaults::removeValue(CAMERA_GLOBE_KEY, false);
316 if (commandLine)
317 {
318 int i;
319 int count = commandLine->getCount();
320 for (i = 0; i < count && !commandLineFilename; i++)
321 {
322 const char *arg = commandLine->stringAtIndex(i);
323
324 if (arg[0] != '-')
325 commandLineFilename = arg;
326 if (stringHasCaseInsensitivePrefix(arg, "-ca"))
327 {
328 float value;
329
330 if (sscanf(arg + 3, "%f", &value) == 1)
331 {
332 TCUserDefaults::setFloatForKey(value, HFOV_KEY, false);
333 }
334 }
335 else if (stringHasCaseInsensitivePrefix(arg, "-cg"))
336 {
337 TCUserDefaults::setStringForKey(arg + 3, CAMERA_GLOBE_KEY,false);
338 }
339 }
340 }
341 char *snapshotFilename =
342 TCUserDefaults::stringForKey(SAVE_SNAPSHOT_KEY);
343 commandLineSnapshotSave = (snapshotFilename ? true : false);
344 QString current = QDir::currentPath();
345 if (commandLineFilename && verifyLDrawDir())
346 {
347 QUrl qurl(commandLineFilename);
348 if (qurl.scheme()=="file")
349 {
350 commandLineFilename=copyString(QUrl::fromPercentEncoding(qurl.toLocalFile().toUtf8().constData()).toUtf8().constData());
351 }
352 QFileInfo fi(commandLineFilename);
353 commandLineFilename = copyString(fi.absoluteFilePath().toUtf8().constData());
354 // loadModel(commandLineFilename);
355 if (chDirFromFilename(commandLineFilename))
356 {
357 modelViewer->setFilename(commandLineFilename);
358 // modelViewer->loadModel();
359 if (modelViewer->loadModel())
360 {
361 getFileInfo(commandLineFilename, lastWriteTime, lastFileSize);
362 if (lastWriteTime.isValid())
363 {
364 startPollTimer();
365 }
366 setLastOpenFile(commandLineFilename);
367 mainWindow->populateRecentFileMenuItems();
368 mainWindow->setupStandardSizes();
369 mainWindow->fileSaveSetEnabled(true);
370 mainWindow->fileReloadSetEnabled(true);
371 mainWindow->toolbarViewAngleSetEnabled(true);
372 startPaintTimer();
373 updateStep();
374 }
375 }
376 }
377 if (snapshotFilename)
378 {
379 if (snapshotFilename)
380 {
381 LDConsoleAlertHandler *consoleAlertHandler = LDSnapshotTaker::getConsoleAlertHandler();
382 QDir::setCurrent(current);
383 QFileInfo fi(snapshotFilename);
384 QString s(snapshotFilename);
385 char *s2=copyString(fi.absoluteFilePath().toUtf8().constData());
386
387 QString ext = s.toLower().right(4);
388 if (ext == ".png")
389 {
390 saveImageType = PNG_IMAGE_TYPE_INDEX;
391 }
392 else if (ext == ".bmp")
393 {
394 saveImageType = BMP_IMAGE_TYPE_INDEX;
395 }
396 else
397 {
398 saveImageType = JPG_IMAGE_TYPE_INDEX;
399 }
400 saveImage(s2,
401 TCUserDefaults::longForKey(SAVE_ACTUAL_SIZE_KEY, 1, false) ?
402 TCUserDefaults::longForKey(WINDOW_WIDTH_KEY, WIN_WIDTH, false) :
403 TCUserDefaults::longForKey(SAVE_WIDTH_KEY, 1024, false),
404 TCUserDefaults::longForKey(SAVE_ACTUAL_SIZE_KEY, 1, false) ?
405 TCUserDefaults::longForKey(WINDOW_HEIGHT_KEY, WIN_HEIGHT, false) :
406 TCUserDefaults::longForKey(SAVE_HEIGHT_KEY, 768, false), true);
407 TCObject::release(consoleAlertHandler);
408 }
409 shouldExit = true;
410 }
411 if (shouldExit)
412 {
413 exit(0);
414 }
415 }
416
initializeGL(void)417 void ModelViewerWidget::initializeGL(void)
418 {
419 lock();
420 TREGLExtensions::setup();
421 preferences->doCancel();
422 doViewStatusBar(preferences->getStatusBar());
423 doViewToolBar(preferences->getToolBar());
424 if (saving || printing)
425 {
426 modelViewer->setup();
427 modelViewer->openGlWillEnd();
428 // modelViewer->recompile();
429 }
430 unlock();
431 }
432
resizeGL(int width,int height)433 void ModelViewerWidget::resizeGL(int width, int height)
434 {
435 lock();
436 if (!loading && !saving && !printing)
437 {
438 QSize mainWindowSize = mainWindow->size();
439
440 modelViewer->setWidth(mwidth=width);
441 modelViewer->setHeight(mheight=height);
442 glViewport(0, 0, width, height);
443 preferences->setWindowSize(mainWindowSize.width(),
444 mainWindowSize.height());
445 }
446 unlock();
447 }
448
swap_Buffers(void)449 void ModelViewerWidget::swap_Buffers(void)
450 {
451 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_FASTEST);
452 glDisable(GL_MULTISAMPLE_ARB);
453 glDrawBuffer(GL_FRONT);
454 // drawFPS();
455 glDrawBuffer(GL_BACK);
456 glFlush();
457 glEnable(GL_MULTISAMPLE_ARB);
458 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
459 }
460
paintGL(void)461 void ModelViewerWidget::paintGL(void)
462 {
463 lock();
464 if (!isFboActive() && !painting && (saving || printing || !loading))
465 {
466 painting = true;
467 glEnable(GL_DEPTH_TEST);
468 if (saving || printing)
469 {
470 if (!TREGLExtensions::haveFramebufferObjectExtension())
471 {
472 glDrawBuffer(GL_BACK);
473 glReadBuffer(GL_BACK);
474 }
475 if (saving) {
476 saveImageResult = snapshotTaker->saveImage(saveImageFilename,
477 saveImageWidth, saveImageHeight, saveImageZoomToFit);
478 }
479 if (printing) {
480 }
481 }
482 else
483 {
484 makeCurrent();
485 //updateSpinRate();
486 redrawRequested = false;
487 modelViewer->update();
488 //updateFPS();
489 //if ((fEq(rotationSpeed, 0.0f) && fEq(modelViewer->getZoomSpeed(), 0.0f)
490 // && fEq(modelViewer->getCameraXRotate(), 0.0f)
491 // && fEq(modelViewer->getCameraYRotate(), 0.0f)
492 // && fEq(modelViewer->getCameraZRotate(), 0.0f)
493 // && fEq(modelViewer->getCameraMotion().length(), 0.0f))
494 // || modelViewer->getPaused())
495 if (!redrawRequested)
496 {
497 killPaintTimer();
498 fps = -1.0f;
499 }
500 else
501 {
502 startPaintTimer();
503 }
504 updateFPS();
505 updateLatlong();
506 //swap_Buffers();
507 }
508 painting = false;
509 }
510 unlock();
511 }
512
lock(void)513 void ModelViewerWidget::lock(void)
514 {
515 if (lockCount == 0)
516 {
517 //app->lock();
518 }
519 lockCount++;
520 }
521
unlock(void)522 void ModelViewerWidget::unlock(void)
523 {
524 lockCount--;
525 if (lockCount == 0)
526 {
527 //app->unlock();
528 }
529 }
530
setLibraryUpdateProgress(float progress)531 void ModelViewerWidget::setLibraryUpdateProgress(float progress)
532 {
533 libraryUpdateWindow->setValue((int)(progress * 100));
534 }
535
timerEvent(QTimerEvent * event)536 void ModelViewerWidget::timerEvent(QTimerEvent* event)
537 {
538 lock();
539 if (event->timerId() == paintTimer)
540 {
541 if (!loading)
542 {
543 #if (QT_VERSION >= 0x50400) && defined(QOPENGLWIDGET)
544 update();
545 #else
546 updateGL();
547 #endif
548 }
549 TCAutoreleasePool::processReleases();
550 }
551 else if (event->timerId() == pollTimer)
552 {
553 if (!loading)
554 {
555 checkFileForUpdates();
556 }
557 }
558 else if (event->timerId() == loadTimer)
559 {
560 killLoadTimer();
561 finishLoadModel();
562 }
563 else if (event->timerId() == libraryUpdateTimer)
564 {
565 if (libraryUpdateFinishNotified)
566 {
567 killTimer(libraryUpdateTimer);
568 libraryUpdateTimer = 0;
569 doLibraryUpdateFinished(libraryUpdateFinishCode);
570 }
571 else if (!libraryUpdateCanceled)
572 {
573 lock();
574 if (libraryUpdateProgressReady)
575 {
576 libraryUpdateProgressReady = false;
577 libraryUpdateWindow->setLabelText(libraryUpdateProgressMessage);
578 libraryUpdateProgressMessage = "";
579 setLibraryUpdateProgress(libraryUpdateProgressValue);
580 }
581 unlock();
582 }
583 }
584 unlock();
585 }
586
paintEvent(QPaintEvent * event)587 void ModelViewerWidget::paintEvent(QPaintEvent *event)
588 {
589 lock();
590 if (loading && !saving && !printing)
591 {
592 int r, g, b;
593
594 preferences->getBackgroundColor(r, g, b);
595
596 // former Qt bug 79310 caused problem with the next 2 lines
597
598 QPainter painter(this);
599 painter.fillRect(event->rect(), QColor(r, g, b));
600 }
601 else if (!saving && !printing)
602 {
603 #if (QT_VERSION >= 0x50400) && defined(QOPENGLWIDGET)
604 QOpenGLWidget::paintEvent(event);
605 #else
606 QGLWidget::paintEvent(event);
607 #endif
608 }
609 unlock();
610 }
611
preLoad(void)612 void ModelViewerWidget::preLoad(void)
613 {
614 clearErrors();
615 makeCurrent();
616 modelViewer->clearBackground();
617 #if (QT_VERSION >= 0x50400) && defined(QOPENGLWIDGET)
618 update();
619 #else
620 glDraw();
621 #endif
622 }
623
postLoad(void)624 void ModelViewerWidget::postLoad(void)
625 {
626 makeCurrent();
627 resizeGL(width(), height());
628 startPaintTimer();
629 mainWindow->fileSaveSetEnabled(true);
630 mainWindow->fileReloadSetEnabled(true);
631 mainWindow->toolbarViewAngleSetEnabled(true);
632 updateStep();
633 }
634
doFileReload(void)635 void ModelViewerWidget::doFileReload(void)
636 {
637 lock();
638 if (loading)
639 {
640 if (app)
641 {
642 app->beep();
643 }
644 return;
645 }
646 preLoad();
647 modelViewer->reload();
648 postLoad();
649 unlock();
650 }
doFilePrint(void)651 void ModelViewerWidget::doFilePrint(void)
652 {
653 QPrinter *printer;
654 printer = new QPrinter(QPrinter::HighResolution);
655 // printer->setOptionEnabled(QPrinter::PrintSelection,false);
656 // printer->setOptionEnabled(QPrinter::PrintPageRange,false);
657 printer->setColorMode(QPrinter::Color);
658 // printer->setFullPage(true);
659 #if QT_VERSION >= 0x40400
660 #if QT_VERSION >= 0x50300
661 printer->setPageMargins(QMarginsF(
662 TCUserDefaults::longForKey(LEFT_MARGIN_KEY, 500, false) / 1000.0f,
663 TCUserDefaults::longForKey(TOP_MARGIN_KEY, 500, false) / 1000.0f,
664 TCUserDefaults::longForKey(RIGHT_MARGIN_KEY, 500, false) / 1000.0f,
665 (qreal)(TCUserDefaults::longForKey(BOTTOM_MARGIN_KEY, 500, false) / 1000.0f)),
666 QPageLayout::Inch);
667 printer->setPageOrientation((QPageLayout::Orientation)TCUserDefaults::longForKey(ORIENTATION_KEY,0,false));
668 printer->setPageSize(QPageSize((QPageSize::PageSizeId)TCUserDefaults::longForKey(PAPER_SIZE_KEY,0,false)));
669 #else
670 printer->setPageMargins(
671 TCUserDefaults::longForKey(LEFT_MARGIN_KEY, 500, false) / 1000.0f,
672 TCUserDefaults::longForKey(TOP_MARGIN_KEY, 500, false) / 1000.0f,
673 TCUserDefaults::longForKey(RIGHT_MARGIN_KEY, 500, false) / 1000.0f,
674 (qreal)(TCUserDefaults::longForKey(BOTTOM_MARGIN_KEY, 500, false) / 1000.0f),
675 QPrinter::Inch);
676 printer->setOrientation((QPrinter::Orientation)TCUserDefaults::longForKey(ORIENTATION_KEY,0,false));
677 printer->setPaperSize((QPrinter::PaperSize)TCUserDefaults::longForKey(PAPER_SIZE_KEY,0,false));
678 #endif
679 #endif
680 QPrintDialog *printdialog = new QPrintDialog(printer);
681 if (printdialog)
682 {
683 #if QT_VERSION >= 0x60000
684 printdialog->setOption(QAbstractPrintDialog::PrintToFile);
685 printdialog->setOption(QAbstractPrintDialog::PrintShowPageSize);
686 #else
687 printdialog->setEnabledOptions(
688 QAbstractPrintDialog::PrintToFile
689 #if QT_VERSION >= 0x40400
690 | QAbstractPrintDialog::PrintShowPageSize
691 #endif
692 );
693 #endif
694 printdialog->setMinMax(1,1);
695 if (printdialog->exec() != QDialog::Accepted) return;
696
697 #if QT_VERSION >= 0x40400
698 qreal *left = new qreal,
699 *right = new qreal,
700 *top = new qreal,
701 *bottom= new qreal;
702 #if QT_VERSION >= 0x50300
703 TCUserDefaults::setLongForKey((long)printer->pageLayout().pageSize().id(),PAPER_SIZE_KEY,false);
704 TCUserDefaults::setLongForKey((long)printer->pageLayout().orientation(), ORIENTATION_KEY, false);
705 QMarginsF margins = printer->pageLayout().margins(QPageLayout::Inch);
706 *left = margins.left();
707 *right= margins.right();
708 *top = margins.top();
709 *bottom=margins.bottom();
710 #else
711 TCUserDefaults::setLongForKey((long)printer->paperSize(),PAPER_SIZE_KEY,false);
712 TCUserDefaults::setLongForKey((long)printer->orientation(), ORIENTATION_KEY, false);
713 printer->getPageMargins(left,top,right,bottom,QPrinter::Inch);
714 #endif
715
716 TCUserDefaults::setLongForKey((long)(*left*1000),LEFT_MARGIN_KEY,false);
717 TCUserDefaults::setLongForKey((long)(*right*1000),RIGHT_MARGIN_KEY,false);
718 TCUserDefaults::setLongForKey((long)(*top*1000),TOP_MARGIN_KEY,false);
719 TCUserDefaults::setLongForKey((long)(*bottom*1000),BOTTOM_MARGIN_KEY,false);
720 #endif
721 QPainter p;
722 if (!p.begin(printer))
723 return;
724 // QPaintDeviceMetrics metrics (p.device());
725 int dpix = p.device()->logicalDpiX(),
726 dpiy = p.device()->logicalDpiY(),
727 marginx = (int) (2/2.54)*dpix,
728 marginy = (int) (2/2.54)*dpiy,
729 pwidth = p.device()->width()-2*marginx,
730 pheight = p.device()->height()-2*marginy,
731 bytesPerLine;
732 long y, x;
733 // printf("%ix%i %ix%i DPI\n",pwidth,pheight,dpix,dpiy);
734 int r, g, b;
735 preferences->getBackgroundColor(r, g, b);
736 modelViewer->setBackgroundRGB(255,255,255);
737 if (dpix != dpiy)
738 modelViewer->setPixelAspectRatio((float)dpix / dpiy);
739 saveImageType = BMP_IMAGE_TYPE_INDEX;
740 TCByte *buffer = grabImage(pwidth,pheight,NULL,true);
741 QImage *image = new QImage(pwidth,pheight,QImage::Format_RGB32);
742 bytesPerLine = roundUp(pwidth * 3, 4);
743 for(y = 0 ; y < pheight; y++)
744 for(x = 0 ; x < pwidth; x++)
745 {
746 image->setPixel(x,pheight-y-1,qRgb(buffer[x*3 + y*bytesPerLine],
747 buffer[x*3 + y*bytesPerLine + 1],
748 buffer[x*3 + y*bytesPerLine + 2]));
749 }
750 p.drawImage(marginx,marginy,*image);
751 delete image;
752 delete buffer;
753 modelViewer->setBackgroundRGB(r, g, b);
754 modelViewer->setPixelAspectRatio(1.0f);
755 }
756 delete printer;
757 endLoad();
758 makeCurrent();
759 }
760
chDirFromFilename(const char * filename)761 bool ModelViewerWidget::chDirFromFilename(const char *filename)
762 {
763 const char *fileSpot = strrchr(filename, '/');
764 bool retValue = false;
765
766 if (fileSpot)
767 {
768 int len = fileSpot - filename;
769 char *path = new char[len + 1];
770
771 strncpy(path, filename, len);
772 path[len] = 0;
773 retValue = QDir::setCurrent(path);
774 if (retValue)
775 {
776 Preferences::setLastOpenPath(path);
777 }
778 delete path;
779 }
780 return retValue;
781 }
782
finishLoadModel(void)783 void ModelViewerWidget::finishLoadModel(void)
784 {
785 char *filename = modelViewer->getFilename();
786
787 preLoad();
788 if (modelViewer->loadModel())
789 {
790 getFileInfo(filename, lastWriteTime, lastFileSize);
791 if (lastWriteTime.isValid())
792 {
793 startPollTimer();
794 }
795 setLastOpenFile(filename);
796 mainWindow->populateRecentFileMenuItems();
797 mainWindow->setupStandardSizes();
798 }
799 postLoad();
800 }
801
loadModel(const char * filename)802 void ModelViewerWidget::loadModel(const char *filename)
803 {
804 if (chDirFromFilename(filename))
805 {
806 killPollTimer();
807 modelViewer->setFilename(filename);
808 // I'm getting occasional crashes, so schedule load to happen RSN.
809 startLoadTimer();
810 }
811 else
812 {
813 QString message;
814
815 #if QT_VERSION < QT_VERSION_CHECK(5,5,0)
816 message.sprintf("The directory containing the file %s could not be found.",
817 filename);
818 #else
819 message = QString::asprintf("The directory containing the file %s could not be found.",
820 filename);
821 #endif
822 QMessageBox::warning(this, "Can't find directory", message, QMessageBox::Ok,
823 QMessageBox::NoButton);
824 }
825 }
826
doFileOpen(void)827 void ModelViewerWidget::doFileOpen(void)
828 {
829 lock();
830 if (loading)
831 {
832 if (app)
833 {
834 app->beep();
835 }
836 return;
837 }
838 if (verifyLDrawDir())
839 {
840 char *initialDir = Preferences::getLastOpenPath();
841
842 QDir::setCurrent(initialDir);
843 delete initialDir;
844 QString selectedfile = QFileDialog::getOpenFileName(this,"Choose a Model",".",
845 "All LDraw Files (*.ldr *.dat *.mpd);;"
846 "LDraw Models (*.ldr *.dat);;Multi-part Models (*.mpd);;All Files (*)");
847 if(!selectedfile.isEmpty())
848 {
849 QString filename = selectedfile.replace("\\","/");
850 QDir dir(filename);
851 QDir::setCurrent(dir.path().replace("\\","/"));
852 Preferences::setLastOpenPath(dir.path().replace("\\","/").toUtf8().constData());
853 loadModel(filename.toUtf8().constData());
854 }
855 }
856 unlock();
857 }
858
setLastOpenFile(const char * filename)859 void ModelViewerWidget::setLastOpenFile(const char *filename)
860 {
861 if (mainWindow->recentFiles)
862 {
863 int index = mainWindow->recentFiles->indexOfString(filename);
864
865 mainWindow->recentFiles->insertString(filename);
866 if (index >= 0)
867 {
868 // Insert before removal. Since the one being removed could have the same
869 // pointer value as the string in the array, we could otherwise access a
870 // pointer after it had been deleted.
871 mainWindow->recentFiles->removeStringAtIndex(index + 1);
872 }
873 mainWindow->recordRecentFiles();
874 }
875 }
876
877 // Note: static method.
convertMouseButton(int button)878 LDInputHandler::MouseButton ModelViewerWidget::convertMouseButton(int button)
879 {
880 switch (button)
881 {
882 case 1:
883 return LDInputHandler::MBLeft;
884 case 2:
885 return LDInputHandler::MBRight;
886 case 3:
887 return LDInputHandler::MBMiddle;
888 default:
889 // Don't even try to handle if the button number it too high.
890 return LDInputHandler::MBUnknown;
891 }
892 }
893
mousePressEvent(QMouseEvent * event)894 void ModelViewerWidget::mousePressEvent(QMouseEvent *event)
895 {
896 lock();
897 if (loading)
898 {
899 unlock();
900 return;
901 }
902 if (!inputHandler->mouseDown(convertKeyModifiers(event->modifiers()),
903 convertMouseButton(event->button()),
904 #if QT_VERSION >= 0x60000
905 event->globalPosition().x(),event->globalPosition().y()
906 #else
907 event->globalX(),event->globalY()
908 #endif
909 ))
910 {
911 event->ignore();
912 }
913 unlock();
914 }
915
mouseReleaseEvent(QMouseEvent * event)916 void ModelViewerWidget::mouseReleaseEvent(QMouseEvent *event)
917 {
918 lock();
919 if (loading)
920 {
921 unlock();
922 return;
923 }
924 if (!inputHandler->mouseUp(convertKeyModifiers(event->modifiers()),
925 convertMouseButton(event->button()),
926 #if QT_VERSION >= 0x60000
927 event->globalPosition().x(),event->globalPosition().y()
928 #else
929 event->globalX(), event->globalY()
930 #endif
931 ))
932 {
933 event->ignore();
934 }
935 unlock();
936 }
937
wheelEvent(QWheelEvent * event)938 void ModelViewerWidget::wheelEvent(QWheelEvent *event)
939 {
940 lock();
941 if (loading)
942 {
943 unlock();
944 return;
945 }
946 if (!inputHandler->mouseWheel(convertKeyModifiers(event->modifiers()),
947 #if QT_VERSION >= 0x50000
948 (TCFloat)event->angleDelta().y() * 0.5f))
949 #else
950 (TCFloat)event->delta() * 0.5f))
951 #endif
952 {
953 event->ignore();
954 }
955 unlock();
956 }
957
mouseMoveEvent(QMouseEvent * event)958 void ModelViewerWidget::mouseMoveEvent(QMouseEvent *event)
959 {
960 lock();
961 if (loading)
962 {
963 unlock();
964 return;
965 }
966 if (!inputHandler->mouseMove(convertKeyModifiers(event->modifiers()),
967 #if QT_VERSION >= 0x60000
968 event->globalPosition().x(),event->globalPosition().y()
969 #else
970 event->globalX(), event->globalY()
971 #endif
972 ))
973 {
974 event->ignore();
975 }
976 unlock();
977 }
978
showPreferences(void)979 void ModelViewerWidget::showPreferences(void)
980 {
981 preferences->show();
982 }
983
showFileExtraDir(void)984 void ModelViewerWidget::showFileExtraDir(void)
985 {
986 extradir->show();
987 }
988
doLibraryUpdateFinished(int finishType)989 void ModelViewerWidget::doLibraryUpdateFinished(int finishType)
990 {
991 #if !defined(_NO_BOOST) || defined(USE_CPP11)
992 if (libraryUpdater)
993 {
994 QString statusText;
995
996 libraryUpdateWindow->setCancelButtonText(QString::fromWCharArray(TCLocalStrings::get(L"OK")));
997 setLibraryUpdateProgress(1.0f);
998 if (libraryUpdater->getError() && ucstrlen(libraryUpdater->getError()))
999 {
1000 QString qError;
1001
1002 statusText = QString::fromWCharArray(TCLocalStrings::get(L"LibraryUpdateError"));
1003 statusText += ":\n";
1004 ucstringtoqstring(qError, libraryUpdater->getError());
1005 statusText += qError;
1006 }
1007 switch (finishType)
1008 {
1009 case LIBRARY_UPDATE_FINISHED:
1010 libraryUpdateFinished = true;
1011 statusText = QString::fromWCharArray(TCLocalStrings::get(L"LibraryUpdateComplete"));
1012 break;
1013 case LIBRARY_UPDATE_CANCELED:
1014 statusText = QString::fromWCharArray(TCLocalStrings::get(L"LibraryUpdateCanceled"));
1015 break;
1016 case LIBRARY_UPDATE_NONE:
1017 statusText = QString::fromWCharArray(TCLocalStrings::get(L"LibraryUpdateUnnecessary"));
1018 break;
1019 }
1020 debugPrintf("About to release library updater.\n");
1021 libraryUpdater->release();
1022 debugPrintf("Released library updater.\n");
1023 libraryUpdater = NULL;
1024 if (statusText.length())
1025 {
1026 libraryUpdateWindow->setLabelText(statusText);
1027 }
1028 }
1029 #endif // _NO_BOOST
1030 }
1031
showLibraryUpdateWindow(bool initialInstall)1032 void ModelViewerWidget::showLibraryUpdateWindow(bool initialInstall)
1033 {
1034 #if !defined(_NO_BOOST) || defined(USE_CPP11)
1035 if (!libraryUpdateWindow)
1036 {
1037 createLibraryUpdateWindow();
1038 }
1039 libraryUpdateWindow->setCancelButtonText(QString::fromWCharArray(TCLocalStrings::get(L"Cancel")));
1040 libraryUpdateWindow->reset();
1041 libraryUpdateWindow->show();
1042 if (initialInstall)
1043 {
1044 libraryUpdateWindow->setModal(true);
1045 }
1046 else
1047 {
1048 libraryUpdateWindow->setModal(false);
1049 connect(libraryUpdateWindow, SIGNAL(canceled()), this,
1050 SLOT(doLibraryUpdateCanceled()));
1051 }
1052 #endif // _NO_BOOST
1053 }
1054
createLibraryUpdateWindow(void)1055 void ModelViewerWidget::createLibraryUpdateWindow(void)
1056 {
1057 if (!libraryUpdateWindow)
1058 {
1059 libraryUpdateWindow = new QProgressDialog(
1060 QString::fromWCharArray(TCLocalStrings::get(L"CheckingForUpdates")),
1061 QString::fromWCharArray(TCLocalStrings::get(L"Cancel")),
1062 0,100,mainWindow);
1063 libraryUpdateWindow->setMinimumDuration(0);
1064 libraryUpdateWindow->setAutoReset(false);
1065 }
1066 }
1067
installLDraw(void)1068 bool ModelViewerWidget::installLDraw(void)
1069 {
1070 #if !defined(_NO_BOOST) || defined(USE_CPP11)
1071 // Don't lock here unless you're REALLY careful. In particular, you
1072 // DEFINITELY have to unlock prior to doing the event processing.
1073 if (libraryUpdater)
1074 {
1075 return false;
1076 }
1077 else
1078 {
1079 char *ldrawParentDir = getLDrawDir();
1080 char *ldrawDir = copyString(ldrawParentDir, 255);
1081 QDir originalDir = QDir::current();
1082 bool progressDialogClosed = false;
1083
1084 libraryUpdateFinished = false;
1085 strcat(ldrawDir, "/ldraw");
1086
1087 QDir dir(ldrawDir);
1088 if (!dir.exists())
1089 {
1090 dir.mkdir(ldrawDir);
1091 }
1092 libraryUpdater = new LDLibraryUpdater;
1093 libraryUpdateCanceled = false;
1094 libraryUpdateFinishNotified = false;
1095 libraryUpdateFinished = false;
1096 progressDialogClosed = false;
1097 libraryUpdater->setLibraryUpdateKey(LAST_LIBRARY_UPDATE_KEY);
1098 libraryUpdater->setLdrawDir(ldrawDir);
1099 libraryUpdater->installLDraw();
1100 showLibraryUpdateWindow(true);
1101 if (!libraryUpdateTimer)
1102 {
1103 libraryUpdateTimer = startTimer(50);
1104 }
1105 while (libraryUpdater || !progressDialogClosed)
1106 {
1107 // We want the update window to be modal, so process events in a
1108 // tight modal loop. (See modal section in QProgressDialog
1109 // documentation.)
1110 qApp->processEvents();
1111 if (!progressDialogClosed && libraryUpdateWindow->wasCanceled())
1112 {
1113 progressDialogClosed = true;
1114 // When the install finishes for real, we change the button
1115 // title from "Cancel" to "OK". However, it still acts like
1116 // a cancel. So check to se if the update really finished, and
1117 // if it didn't, then note that the user canceled.
1118 if (!libraryUpdateFinished)
1119 {
1120 libraryUpdateCanceled = true;
1121 doLibraryUpdateFinished(LIBRARY_UPDATE_CANCELED);
1122 //libraryUpdateCanceled = false;
1123 }
1124 break;
1125 }
1126 if (libraryUpdateFinishNotified)
1127 {
1128 doLibraryUpdateFinished(libraryUpdateFinishCode);
1129 }
1130 // Sleep for 50ms. Unlike the QProgressDialog example, we aren't
1131 // doing anything inside this loop other than processing the
1132 // events. All the work is happening in other threads. So sleep
1133 // for a short time in order to avoid monopolizing the CPU. Keep in
1134 // mind that while 50ms is essentially unnoticable to a user, it's
1135 // quite a long time to the computer.
1136 #ifdef WIN32
1137 Sleep(50);
1138 #else // WIN32
1139 usleep(50000);
1140 #endif // WIN32
1141 }
1142 if (libraryUpdateFinished)
1143 {
1144 LDLModel::setLDrawDir(ldrawDir);
1145 preferences->setLDrawDir(ldrawDir);
1146 }
1147 delete ldrawDir;
1148 return libraryUpdateFinished;
1149 }
1150 #endif // _NO_BOOST
1151 }
1152
checkForLibraryUpdates(void)1153 void ModelViewerWidget::checkForLibraryUpdates(void)
1154 {
1155 #if !defined(_NO_BOOST) || defined(USE_CPP11)
1156 if (libraryUpdater)
1157 {
1158 showLibraryUpdateWindow(false);
1159 }
1160 else
1161 {
1162 libraryUpdater = new LDLibraryUpdater;
1163 char *ldrawDir = getLDrawDir();
1164 wchar_t *updateCheckError = NULL;
1165
1166 libraryUpdateCanceled = false;
1167 libraryUpdateFinishNotified = false;
1168 libraryUpdateFinished = false;
1169 libraryUpdater->setLibraryUpdateKey(LAST_LIBRARY_UPDATE_KEY);
1170 libraryUpdater->setLdrawDir(ldrawDir);
1171 delete ldrawDir;
1172 if (libraryUpdater->canCheckForUpdates(updateCheckError))
1173 {
1174 showLibraryUpdateWindow(false);
1175 if (!libraryUpdateTimer)
1176 {
1177 libraryUpdateTimer = startTimer(50);
1178 }
1179 libraryUpdater->checkForUpdates();
1180 }
1181 else
1182 {
1183 QString qs;
1184 wcstoqstring(qs, updateCheckError);
1185 QMessageBox::warning(this,"LDView", qs,
1186 QMessageBox::Ok, QMessageBox::NoButton);
1187 delete updateCheckError;
1188 }
1189 }
1190 #endif // _NO_BOOST
1191 }
1192
setMainWindow(LDViewMainWindow * value)1193 void ModelViewerWidget::setMainWindow(LDViewMainWindow *value)
1194 {
1195 int width, height;
1196
1197 lock();
1198 mainWindow = value;
1199 width = preferences->getWindowWidth();
1200 height = preferences->getWindowHeight();
1201 mainWindow->resize(width, height);
1202 /*
1203 windowSize = mainWindow->size();
1204 mainWindow->resize(width - 320 + windowSize.width(),
1205 height - 240 + windowSize.height());
1206 */
1207 statusBar = mainWindow->statusBar();
1208 // toolBar = new QToolBar;
1209 reflectSettings();
1210 mainWindow->fileSaveSetEnabled(false);
1211 mainWindow->fileReloadSetEnabled(false);
1212 progressBar = new QProgressBar(statusBar);
1213 progressLabel = new QLabel(statusBar);
1214 progressLatlong = new QLabel(statusBar);
1215 progressMode = new QLabel(statusBar);
1216 progressBar->setTextVisible(false);
1217 statusBar->addWidget(progressBar);
1218 statusBar->addWidget(progressLabel, 1);
1219 statusBar->addWidget(progressLatlong);
1220 statusBar->addWidget(progressMode);
1221 mainWindow->setStatusbarOn(preferences->getStatusBar());
1222 mainWindow->setToolbarOn(preferences->getToolBar());
1223 mainWindow->setPollAction(Preferences::getPollMode());
1224 if (viewMode == LDInputHandler::VMExamine)
1225 {
1226 mainWindow->setExamineModeOn(true);
1227 progressMode->setText(QString::fromWCharArray(TCLocalStrings::get(L"ExamineMode")));
1228 }
1229 else if (viewMode == LDInputHandler::VMFlyThrough)
1230 {
1231 mainWindow->setFlythroughModeOn(true);
1232 progressMode->setText(QString::fromWCharArray(TCLocalStrings::get(L"FlyThroughMode")));
1233 }
1234 else if (viewMode == LDInputHandler::VMWalk)
1235 {
1236 mainWindow->setWalkModeOn(true);
1237 progressMode->setText(QString::fromWCharArray(TCLocalStrings::get(L"WalkMode")));
1238 }
1239 mainWindow->setViewLatitudeRotationOn(Preferences::getLatLongMode());
1240 mainWindow->setKeepRightSideUpOn(keepRightSide = Preferences::getKeepRightSideUp());
1241 mainWindow->setShowPovAspectRatioOn(
1242 Preferences::getPovAspectRatio());
1243 saveAlpha = TCUserDefaults::longForKey(SAVE_ALPHA_KEY, 0, false) != 0;
1244 updateStep();
1245 unlock();
1246 }
1247
doRecentFile(int index)1248 void ModelViewerWidget::doRecentFile(int index)
1249 {
1250 lock();
1251 if (loading)
1252 {
1253 if (app)
1254 {
1255 app->beep();
1256 }
1257 return;
1258 }
1259 if (verifyLDrawDir())
1260 {
1261 char *filename = mainWindow->recentFiles->stringAtIndex(index);
1262
1263 if (filename)
1264 {
1265 QFile file (filename);
1266 if(!file.exists())
1267 {
1268 QString message;
1269 message = QString::fromWCharArray(TCLocalStrings::get(L"ErrorLoadingModel"));
1270 message.replace(QString("%s"),QString(filename));
1271 QMessageBox::warning(this, "LDView", message,
1272 QMessageBox::Ok, QMessageBox::NoButton);
1273
1274 }
1275 else
1276 loadModel(filename);
1277 }
1278 }
1279 unlock();
1280 }
1281
setupProgress(void)1282 void ModelViewerWidget::setupProgress(void)
1283 {
1284 clearErrors();
1285 lastProgressTime.start();
1286 loading = true;
1287 cancelLoad = false;
1288 }
1289
endLoad(void)1290 void ModelViewerWidget::endLoad(void)
1291 {
1292 progressBar->setValue(0);
1293 progressLabel->setText("");
1294 loading = false;
1295 }
1296
progressCallback(const QString & message,float progress,bool)1297 int ModelViewerWidget::progressCallback(const QString &message, float progress,
1298 bool /*showErrors*/)
1299 {
1300 if (progress == 2.0f)
1301 {
1302 showErrorsIfNeeded(true);
1303 endLoad();
1304 makeCurrent();
1305 return 1;
1306 }
1307 if (!loading)
1308 {
1309 setupProgress();
1310 }
1311 if (message.length())
1312 {
1313 progressLabel->setText(message);
1314 }
1315 if (progress >= 0.0f)
1316 {
1317 progressBar->setValue((int)(progress * 100));
1318 }
1319 if (lastProgressTime.elapsed() >= 100 || progress == 1.0f)
1320 {
1321 app->processEvents();
1322 lastProgressTime.start();
1323 makeCurrent();
1324 }
1325 if (cancelLoad)
1326 {
1327 endLoad();
1328 makeCurrent();
1329 return 0;
1330 }
1331 return 1;
1332 }
1333
doViewStatusBar(bool flag)1334 void ModelViewerWidget::doViewStatusBar(bool flag)
1335 {
1336 lock();
1337 if (flag)
1338 {
1339 if (statusBar) statusBar->show();
1340 }
1341 else
1342 {
1343 if (statusBar) statusBar->hide();
1344 }
1345 preferences->setStatusBar(flag);
1346 unlock();
1347 mainWindow->setupStandardSizes();
1348 }
1349
doViewToolBar(bool flag)1350 void ModelViewerWidget::doViewToolBar(bool flag)
1351 {
1352 lock();
1353 mainWindow->showToolbar(flag);
1354 preferences->setToolBar(flag);
1355 unlock();
1356 mainWindow->setupStandardSizes();
1357 }
1358
doViewFullScreen(void)1359 void ModelViewerWidget::doViewFullScreen(void)
1360 {
1361 static QPoint pos;
1362 static QSize size;
1363 if (!fullscreen)
1364 {
1365 pos=mainWindow->pos();
1366 size=mainWindow->size();
1367 statusBar->hide();
1368 //mainWindow->setMainGroupBoxMargin( 0 );
1369 mainWindow->showToolbar(false);
1370 mainWindow->showMenubar(false);
1371 mainWindow->showFullScreen();
1372 fullscreen=1;
1373 } else
1374 {
1375 //mainWindow->setMainGroupBoxMargin( 2 );
1376 mainWindow->showNormal();
1377 mainWindow->resize(size);
1378 mainWindow->move(pos);
1379 mainWindow->showMenubar(true);
1380 if(preferences->getStatusBar()) {statusBar->show();}
1381 if(preferences->getToolBar()) {mainWindow->showToolbar(true);}
1382 fullscreen=0;
1383 }
1384 }
1385
doViewReset(void)1386 void ModelViewerWidget::doViewReset(void)
1387 {
1388 lock();
1389 if (loading)
1390 {
1391 if (app)
1392 {
1393 app->beep();
1394 }
1395 return;
1396 }
1397 rotationSpeed = 0.0f;
1398 modelViewer->setRotationSpeed(0.0f);
1399 modelViewer->setZoomSpeed(0.0f);
1400 modelViewer->resetView();
1401 startPaintTimer();
1402 unlock();
1403 }
1404
switchExamineLatLong(bool b)1405 void ModelViewerWidget::switchExamineLatLong(bool b)
1406 {
1407 lock();
1408 if (examineLatLong != b)
1409 {
1410 preferences->setLatLongMode (examineLatLong = b);
1411 setViewMode (viewMode, examineLatLong, keepRightSide);
1412 if (b && Preferences::getViewMode() == LDInputHandler::VMExamine)
1413 progressLatlong->setHidden(false);
1414 else
1415 progressLatlong->setHidden(true);
1416 }
1417 unlock();
1418 }
1419
keepRightSideUp(bool b)1420 void ModelViewerWidget::keepRightSideUp(bool b)
1421 {
1422 lock();
1423 if (keepRightSide != b)
1424 {
1425 preferences->setKeepRightSideUp(keepRightSide = b);
1426 modelViewer->setKeepRightSideUp(b);
1427 }
1428 unlock();
1429 }
1430
doHelpOpenGLDriverInfo(void)1431 void ModelViewerWidget::doHelpOpenGLDriverInfo(void)
1432 {
1433 lock();
1434 if (loading)
1435 {
1436 if (app)
1437 {
1438 app->beep();
1439 }
1440 return;
1441 }
1442 if (!extensionsPanel)
1443 {
1444 QLabel *extensionsCountLabel;
1445 QString countString;
1446 int extensionCount;
1447 UCSTR temp = LDrawModelViewer::getOpenGLDriverInfo(extensionCount);
1448
1449 extensionsPanel = new OpenGLExtensions(mainWindow);
1450 ucstringtoqstring(openGLDriverInfo, temp);
1451 extensionsPanel->setText(openGLDriverInfo);
1452 extensionsCountLabel = new QLabel(extensionsPanel->statusBar());
1453 countString = QString::number(extensionCount);
1454 countString += QString::fromWCharArray((TCLocalStrings::get(L"OpenGlnExtensionsSuffix")));
1455 extensionsCountLabel->setText(countString);
1456 extensionsPanel->statusBar()->addWidget(extensionsCountLabel, 1);
1457 }
1458 extensionsPanel->show();
1459 extensionsPanel->raise();
1460 // extensionsPanel->setActiveWindow();
1461 unlock();
1462 }
1463
doHelpContents(void)1464 void ModelViewerWidget::doHelpContents(void)
1465 {
1466 if (loading)
1467 {
1468 if (app)
1469 {
1470 app->beep();
1471 }
1472 return;
1473 }
1474 QString helpFilename = findPackageFile(TCLocalStrings::get("HelpHtml"));
1475 QString qUrl = QString("file://") + helpFilename;
1476 #ifdef __APPLE__
1477 helpFilename += "#MacNotes";
1478 CFURLRef url = NULL;
1479 CFStringRef urlString;
1480 bool macSuccess = false;
1481
1482 urlString = CFStringCreateWithCString(NULL, qUrl.toUtf8(),
1483 kCFStringEncodingUTF8);
1484 if (urlString && (url = CFURLCreateWithString(NULL, urlString, NULL)) !=
1485 NULL)
1486 {
1487 if (LSOpenCFURLRef(url, NULL) == 0)
1488 {
1489 macSuccess = true;
1490 }
1491 }
1492 if (urlString)
1493 {
1494 CFRelease(urlString);
1495 }
1496 if (url)
1497 {
1498 CFRelease(url);
1499 }
1500 if (macSuccess)
1501 {
1502 return;
1503 }
1504 FSRef fsRef;
1505 Boolean isDirectory;
1506 /*
1507 if (FSPathMakeRef((const UInt8 *)(const char *)helpFilename, &fsRef,
1508 &isDirectory) == 0 && !isDirectory)
1509 {
1510 if (LSOpenFSRef(&fsRef, NULL) == 0)
1511 {
1512 return;
1513 }
1514 }
1515 */
1516 #endif // __APPLE__
1517 QFile file(helpFilename);
1518 if (!file.exists())
1519 {
1520 return;
1521 }
1522 if(!helpContents)
1523 {
1524 helpContents = new Help(mainWindow);
1525 if ( file.open( QIODevice::ReadOnly ) ) {
1526 QTextStream stream( &file );
1527 helpContents->setText(
1528 stream.readAll().replace(
1529 #if QT_VERSION >= 0x60000
1530 QRegularExpression("(BGCOLOR|COLOR|TEXT|LINK)="),
1531 #else
1532 QRegExp("(BGCOLOR|COLOR|TEXT|LINK)="),
1533 #endif
1534 "i=") );
1535 }
1536 }
1537 if (!QDesktopServices::openUrl(helpFilename))
1538 helpContents->show();
1539 }
1540
doHelpAbout(void)1541 void ModelViewerWidget::doHelpAbout(void)
1542 {
1543 lock();
1544 if (loading)
1545 {
1546 if (app)
1547 {
1548 app->beep();
1549 }
1550 return;
1551 }
1552 createAboutPanel();
1553 aboutPanel->show();
1554 unlock();
1555 }
1556
createAboutPanel(void)1557 void ModelViewerWidget::createAboutPanel(void)
1558 {
1559 if (!aboutPanel)
1560 {
1561 aboutPanel = new About;
1562 aboutPanel->resize(10, 10);
1563 QString text = aboutPanel->getText();
1564 text.replace( "__DATE__",__DATE__);
1565 aboutPanel->setText(text);
1566 }
1567 }
1568
doHelpAboutQt(void)1569 void ModelViewerWidget::doHelpAboutQt(void)
1570 {
1571 lock();
1572 QMessageBox::aboutQt(this,"");
1573 unlock();
1574 }
1575
doAboutOK(void)1576 void ModelViewerWidget::doAboutOK(void)
1577 {
1578 lock();
1579 aboutPanel->hide();
1580 unlock();
1581 }
1582
doLibraryUpdateCanceled(void)1583 void ModelViewerWidget::doLibraryUpdateCanceled(void)
1584 {
1585 libraryUpdateCanceled = true;
1586 }
1587
doWireframe(bool value)1588 void ModelViewerWidget::doWireframe(bool value)
1589 {
1590 preferences->setDrawWireframe(value);
1591 doApply();
1592 }
1593
doWireframeFog(bool value)1594 void ModelViewerWidget::doWireframeFog(bool value)
1595 {
1596 preferences->setUseWireframeFog(value);
1597 doApply();
1598 }
1599
doWireframeRemoveHiddenLines(bool value)1600 void ModelViewerWidget::doWireframeRemoveHiddenLines(bool value)
1601 {
1602 preferences->setRemoveHiddenLines(value);
1603 doApply();
1604 }
1605
doTextureStud(bool value)1606 void ModelViewerWidget::doTextureStud(bool value)
1607 {
1608 preferences->setTextureStud(value);
1609 doApply();
1610 }
1611
doShowEdgeOnly(bool value)1612 void ModelViewerWidget::doShowEdgeOnly(bool value)
1613 {
1614 preferences->setEdgeOnly(value);
1615 doApply();
1616 }
1617
doConditionalLine(bool value)1618 void ModelViewerWidget::doConditionalLine(bool value)
1619 {
1620 preferences->setConditionalLine(value);
1621 doApply();
1622 }
1623
doHighQuality(bool value)1624 void ModelViewerWidget::doHighQuality(bool value)
1625 {
1626 preferences->setHighQuality(value);
1627 doApply();
1628 }
1629
doAlwaysBlack(bool value)1630 void ModelViewerWidget::doAlwaysBlack(bool value)
1631 {
1632 preferences->setAlwaysBlack(value);
1633 doApply();
1634 }
1635
doRedBackFaces(bool value)1636 void ModelViewerWidget::doRedBackFaces(bool value)
1637 {
1638 preferences->setRedBackFaces(value);
1639 doApply();
1640 }
1641
doGreenFrontFaces(bool value)1642 void ModelViewerWidget::doGreenFrontFaces(bool value)
1643 {
1644 preferences->setGreenFrontFaces(value);
1645 doApply();
1646 }
1647
doBlueNeutralFaces(bool value)1648 void ModelViewerWidget::doBlueNeutralFaces(bool value)
1649 {
1650 preferences->setBlueNeutralFaces(value);
1651 doApply();
1652 }
1653
doEdge(bool value)1654 void ModelViewerWidget::doEdge(bool value)
1655 {
1656 preferences->setShowsHighlightLines(value);
1657 doApply();
1658 }
1659
doLighting(bool value)1660 void ModelViewerWidget::doLighting(bool value)
1661 {
1662 preferences->setUseLighting(value);
1663 doApply();
1664 }
1665
doBFC(bool value)1666 void ModelViewerWidget::doBFC(bool value)
1667 {
1668 preferences->setUseBFC(value);
1669 doApply();
1670 }
1671
doAxes(bool value)1672 void ModelViewerWidget::doAxes(bool value)
1673 {
1674 preferences->setShowAxes(value);
1675 doApply();
1676 }
1677
doPrimitiveSubstitution(bool value)1678 void ModelViewerWidget::doPrimitiveSubstitution(bool value)
1679 {
1680 preferences->setAllowPrimitiveSubstitution(value);
1681 doApply();
1682 }
1683
doSeams(bool value)1684 void ModelViewerWidget::doSeams(bool value)
1685 {
1686 preferences->setUseSeams(value);
1687 doApply();
1688 }
1689
reflectSettings(void)1690 void ModelViewerWidget::reflectSettings(void)
1691 {
1692 if (mainWindow && preferences)
1693 {
1694 mainWindow->setToolbarWireframeOn(preferences->getDrawWireframe());
1695 mainWindow->setToolbarWireframeFogOn(preferences->getUseWireframeFog());
1696 mainWindow->setToolbarWireframeRemoveHiddenLinesOn(preferences->getRemoveHiddenLines());
1697 mainWindow->setToolbarTextureStudOn(preferences->getTextureStud());
1698 mainWindow->setToolbarEdgeShowEdgeOnlyOn(preferences->getEdgeOnly());
1699 mainWindow->setToolbarEdgeConditionalLineOn(preferences->getConditionalLine());
1700 mainWindow->setToolbarEdgeHighQualityOn(preferences->getHighQuality());
1701 mainWindow->setToolbarEdgeAlwaysBlackOn(preferences->getAlwaysBlack());
1702 mainWindow->setToolbarBfcRedBackFacesOn(preferences->getRedBackFaces());
1703 mainWindow->setToolbarBfcGreenFrontFacesOn(preferences->getGreenFrontFaces());
1704 mainWindow->setToolbarBfcBlueNeutralFacesOn(preferences->getBlueNeutralFaces());
1705 mainWindow->setToolbarEdgeOn(preferences->getShowsHighlightLines());
1706 mainWindow->setToolbarLightingOn(preferences->getUseLighting());
1707 mainWindow->setToolbarBFCOn(preferences->getUseBFC());
1708 mainWindow->setToolbarAxesOn(preferences->getShowAxes());
1709 mainWindow->setToolbarSeamsOn(preferences->getUseSeams());
1710 mainWindow->setToolbarPrimitiveSubstitutionOn(preferences->getAllowPrimitiveSubstitution());
1711 }
1712 }
1713
updateFPS(void)1714 void ModelViewerWidget::updateFPS(void)
1715 {
1716 numFramesSinceReference++;
1717 if (fps == -1.0f)
1718 {
1719 referenceFrameTime.start();
1720 numFramesSinceReference = 0;
1721 fps = 0.0f;
1722 }
1723 else
1724 {
1725 long elapsed = referenceFrameTime.elapsed();
1726
1727 if (elapsed >= 250)
1728 {
1729 fps = 1000.0f / (float)elapsed * numFramesSinceReference;
1730 referenceFrameTime.start();
1731 numFramesSinceReference = 0;
1732 }
1733 }
1734 drawFPS();
1735 }
1736
drawFPS(void)1737 void ModelViewerWidget::drawFPS(void)
1738 {
1739 if (showFPS && modelViewer->getMainTREModel())
1740 {
1741 if (statusBar->isHidden())
1742 {
1743 modelViewer->drawFPS(fps);
1744 }
1745 else
1746 {
1747 QString fpsString;
1748
1749 if (fps > 0.0f)
1750 {
1751 #if QT_VERSION < QT_VERSION_CHECK(5,5,0)
1752 fpsString.sprintf(TCLocalStrings::get("FPSFormat"), fps);
1753 #else
1754 fpsString = QString::asprintf(TCLocalStrings::get("FPSFormat"), fps);
1755 #endif
1756 }
1757 else
1758 {
1759 fpsString = QString::fromWCharArray(TCLocalStrings::get(L"FPSSpinPrompt"));
1760 }
1761 progressLabel->setText(fpsString);
1762 }
1763 }
1764 }
1765
updateLatlong(void)1766 void ModelViewerWidget::updateLatlong(void)
1767 {
1768 if (modelViewer &&
1769 modelViewer->getViewMode() == LDrawModelViewer::VMExamine &&
1770 modelViewer->getExamineMode() == LDrawModelViewer::EMLatLong)
1771 {
1772 int lat = (int)(modelViewer->getExamineLatitude()+.5);
1773 int lon = (int)(modelViewer->getExamineLongitude()+.5);
1774 if (lon == -180) lon = 180;
1775 QString latlongstring;
1776 #if QT_VERSION < QT_VERSION_CHECK(5,5,0)
1777 latlongstring.sprintf(TCLocalStrings::get("LatLonFormat"),lat,lon);
1778 #else
1779 latlongstring = QString::asprintf(TCLocalStrings::get("LatLonFormat"),lat,lon);
1780 #endif
1781 progressLatlong->setText(latlongstring);
1782 }
1783 else progressLatlong->setText("");
1784
1785 }
1786
startPaintTimer(void)1787 void ModelViewerWidget::startPaintTimer(void)
1788 {
1789 if (!paintTimer)
1790 {
1791 paintTimer = startTimer(0);
1792 }
1793 }
1794
killPaintTimer(void)1795 void ModelViewerWidget::killPaintTimer(void)
1796 {
1797 if (paintTimer)
1798 {
1799 killTimer(paintTimer);
1800 paintTimer = 0;
1801 }
1802 }
1803
startPollTimer(bool immediate)1804 void ModelViewerWidget::startPollTimer(bool immediate)
1805 {
1806 if (!pollTimer && Preferences::getPollMode() != LDVPollNone)
1807 {
1808 pollTimer = startTimer(POLL_INTERVAL);
1809 if (!loading && immediate)
1810 {
1811 checkFileForUpdates();
1812 }
1813 }
1814 }
1815
killPollTimer(void)1816 void ModelViewerWidget::killPollTimer(void)
1817 {
1818 if (pollTimer)
1819 {
1820 killTimer(pollTimer);
1821 pollTimer = 0;
1822 }
1823 }
1824
startLoadTimer(void)1825 void ModelViewerWidget::startLoadTimer(void)
1826 {
1827 if (!loadTimer)
1828 {
1829 loadTimer = startTimer(0);
1830 }
1831 }
1832
killLoadTimer(void)1833 void ModelViewerWidget::killLoadTimer(void)
1834 {
1835 if (loadTimer)
1836 {
1837 killTimer(loadTimer);
1838 loadTimer = 0;
1839 }
1840 }
1841
doApply(void)1842 void ModelViewerWidget::doApply(void)
1843 {
1844 lock();
1845 startPaintTimer();
1846 unlock();
1847 }
1848
verifyLDrawDir(char * value)1849 bool ModelViewerWidget::verifyLDrawDir(char *value)
1850 {
1851 QString currentDir = QDir::currentPath();
1852 bool found = false;
1853 char buf[128];
1854
1855 if (QDir::setCurrent(value))
1856 {
1857 strcpy(buf, "parts");
1858 if (staticFileCaseCallback(buf) && QDir::current().cd(buf))
1859 {
1860 QDir::setCurrent(value);
1861 strcpy(buf, "p");
1862 if (staticFileCaseCallback(buf) && QDir::current().cd(buf))
1863 {
1864 LDLModel::setLDrawDir(value);
1865 found = true;
1866 }
1867 }
1868 QDir::setCurrent(currentDir);
1869 }
1870 return found;
1871 }
1872
verifyLDrawDir(bool forceChoose)1873 bool ModelViewerWidget::verifyLDrawDir(bool forceChoose)
1874 {
1875 char *lDrawDir = getLDrawDir();
1876 bool found = false;
1877
1878 if (!forceChoose &&
1879 (!TCUserDefaults::longForKey(VERIFY_LDRAW_DIR_KEY, 1, false) ||
1880 verifyLDrawDir(lDrawDir)))
1881 {
1882 delete lDrawDir;
1883 found = true;
1884 }
1885 else
1886 {
1887 if (commandLineSnapshotSave) return true;
1888 bool ans = true;
1889 if (!verifyLDrawDir(lDrawDir))
1890 {
1891 ans = (QMessageBox::question(this, "LDView",
1892 QString::fromWCharArray(TCLocalStrings::get(L"LDrawDirExistsPrompt")), QMessageBox::Yes,
1893 QMessageBox::No | QMessageBox::Default) == QMessageBox::Yes);
1894 }
1895 delete lDrawDir;
1896 if (ans)
1897 {
1898 while (!found)
1899 {
1900 if (promptForLDrawDir())
1901 {
1902 lDrawDir = getLDrawDir();
1903 if (verifyLDrawDir(lDrawDir))
1904 {
1905 found = true;
1906 }
1907 else
1908 {
1909 QMessageBox::warning(this,
1910 QString::fromWCharArray(TCLocalStrings::get(L"InvalidDir")),
1911 QString::fromWCharArray(TCLocalStrings::get(L"LDrawNotInDir")),
1912 QMessageBox::Ok, QMessageBox::NoButton);
1913 }
1914 delete lDrawDir;
1915 }
1916 else
1917 {
1918 break;
1919 }
1920 }
1921 }
1922 else
1923 {
1924 if (QMessageBox::warning(this,
1925 "LDView", QString::fromWCharArray(TCLocalStrings::get(L"WillDownloadLDraw")),
1926 QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok)
1927 {
1928 LDLModel::setLDrawDir("/");
1929 if (promptForLDrawDir(
1930 QString::fromWCharArray(TCLocalStrings::get(L"LDrawInstallDirPrompt"))))
1931 {
1932 if (installLDraw())
1933 {
1934 found = true;
1935 }
1936 }
1937 }
1938 }
1939 }
1940 return found;
1941 }
1942
getLDrawDir(void)1943 char *ModelViewerWidget::getLDrawDir(void)
1944 {
1945 char *lDrawDir = Preferences::getLDrawDir();
1946
1947 if (!lDrawDir)
1948 {
1949 lDrawDir = copyString(getenv("LDRAWDIR"));
1950 if (!lDrawDir)
1951 {
1952 lDrawDir = copyString("/usr/local/share/ldraw");
1953 }
1954 }
1955 stripTrailingPathSeparators(lDrawDir);
1956 return lDrawDir;
1957 }
1958
promptForLDrawDir(QString prompt)1959 bool ModelViewerWidget::promptForLDrawDir(QString prompt)
1960 {
1961 char *initialDir = getLDrawDir();
1962 bool retValue = false;
1963
1964 if (prompt.isEmpty())
1965 {
1966 prompt = QString::fromWCharArray(TCLocalStrings::get(L"LDrawDirPrompt"));
1967 }
1968 QDir::setCurrent(initialDir);
1969 QString selectedfile=QFileDialog::getExistingDirectory(this,prompt,".");
1970 if (!selectedfile.isEmpty())
1971 {
1972 Preferences::setLDrawDir(selectedfile.toUtf8().constData());
1973 retValue = true;
1974 }
1975 return retValue;
1976 }
1977
doFileLDrawDir(void)1978 void ModelViewerWidget::doFileLDrawDir(void)
1979 {
1980 char *oldDir;
1981
1982 lock();
1983 if (loading)
1984 {
1985 if (app)
1986 {
1987 app->beep();
1988 }
1989 return;
1990 }
1991 oldDir = getLDrawDir();
1992 if (!verifyLDrawDir(true))
1993 {
1994 if (oldDir)
1995 {
1996 Preferences::setLDrawDir(oldDir);
1997 }
1998 }
1999 delete oldDir;
2000 unlock();
2001 }
2002
doFileCancelLoad(void)2003 void ModelViewerWidget::doFileCancelLoad(void)
2004 {
2005 lock();
2006 cancelLoad = true;
2007 unlock();
2008 }
2009
errorCallback(LDLError * error)2010 int ModelViewerWidget::errorCallback(LDLError* error)
2011 {
2012 if (!errors)
2013 {
2014 errors = new LDViewErrors(mainWindow, preferences);
2015 }
2016 errors->addError(error);
2017 return 1;
2018 }
2019
clearErrors(void)2020 void ModelViewerWidget::clearErrors(void)
2021 {
2022 if (errors)
2023 {
2024 errors->clear();
2025 }
2026 }
2027
showErrorsIfNeeded(bool onlyIfNeeded)2028 void ModelViewerWidget::showErrorsIfNeeded(bool onlyIfNeeded)
2029 {
2030 if (errors)
2031 {
2032 int errorCount = errors->populateListView();
2033
2034 if (!onlyIfNeeded || (errorCount && preferences->getShowErrors()))
2035 {
2036 errors->show();
2037 }
2038 }
2039 }
2040
doViewErrors(void)2041 void ModelViewerWidget::doViewErrors(void)
2042 {
2043 lock();
2044 if (loading)
2045 {
2046 if (app)
2047 {
2048 app->beep();
2049 }
2050 return;
2051 }
2052 if (!errors)
2053 {
2054 errors = new LDViewErrors(mainWindow, preferences);
2055 }
2056 showErrorsIfNeeded(false);
2057 unlock();
2058 }
2059
getFileTime(const char * filename,QDateTime & value)2060 void ModelViewerWidget::getFileTime(const char *filename, QDateTime &value)
2061 {
2062 if (filename)
2063 {
2064 if (!fileInfo)
2065 {
2066 fileInfo = new QFileInfo;
2067 }
2068 fileInfo->setFile(filename);
2069
2070 value = QDateTime(fileInfo->lastModified());
2071 }
2072 else
2073 {
2074 value = QDateTime();
2075 }
2076 }
2077
getFileInfo(const char * filename,QDateTime & value,qint64 & size)2078 void ModelViewerWidget::getFileInfo(const char *filename, QDateTime &value, qint64 &size)
2079 {
2080 if (filename)
2081 {
2082 if (!fileInfo)
2083 {
2084 fileInfo = new QFileInfo;
2085 }
2086 fileInfo->setFile(filename);
2087
2088 value = QDateTime(fileInfo->lastModified());
2089 size = fileInfo->size();
2090 }
2091 else
2092 {
2093 value = QDateTime();
2094 size = 0;
2095 }
2096 }
2097
checkFileForUpdates(void)2098 void ModelViewerWidget::checkFileForUpdates(void)
2099 {
2100 if (pollTimer && modelViewer)
2101 {
2102 char *filename = modelViewer->getFilename();
2103
2104 killPollTimer();
2105 if (filename)
2106 {
2107 QDateTime newWriteTime;
2108 qint64 newFileSize;
2109
2110 getFileInfo(filename, newWriteTime, newFileSize);
2111 if (newWriteTime != lastWriteTime)
2112 {
2113 bool update = true;
2114
2115 if(newFileSize != lastFileSize)
2116 {
2117 startPollTimer();
2118 lastFileSize = newFileSize;
2119 return;
2120 }
2121 lastFileSize = 0;
2122 lastWriteTime = QDateTime(newWriteTime);
2123 if (Preferences::getPollMode() == LDVPollPrompt)
2124 {
2125 if (QMessageBox::information(this, QString::fromWCharArray(TCLocalStrings::get(L"PollFileUpdate")),
2126 QString::fromWCharArray(TCLocalStrings::get(L"PollReloadCheck")),
2127 QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
2128 {
2129 update = false;
2130 }
2131 }
2132 if (update)
2133 {
2134 doFileReload();
2135 }
2136 }
2137 }
2138 startPollTimer();
2139 }
2140 }
2141
windowActivationChange(bool oldActive)2142 void ModelViewerWidget::windowActivationChange(bool oldActive)
2143 {
2144 lock();
2145 if (isActiveWindow())
2146 {
2147 startPollTimer(true);
2148 }
2149 else
2150 {
2151 if (Preferences::getPollMode() != LDVPollBackground)
2152 {
2153 killPollTimer();
2154 }
2155 }
2156 unlock();
2157 #if QT_VERSION < 0x50000
2158 QGLWidget::windowActivationChange(oldActive);
2159 #endif
2160 }
2161
doPollChanged(LDVPollMode newMode)2162 void ModelViewerWidget::doPollChanged(LDVPollMode newMode)
2163 {
2164 lock();
2165 Preferences::setPollMode(newMode);
2166 killPollTimer();
2167 startPollTimer(true);
2168 unlock();
2169 }
2170
setViewMode(LDInputHandler::ViewMode value,bool examine,bool keep,bool)2171 void ModelViewerWidget::setViewMode(LDInputHandler::ViewMode value,
2172 bool examine, bool keep, bool /*saveSettings*/)
2173 {
2174 viewMode = value;
2175 if (viewMode == LDInputHandler::VMExamine)
2176 {
2177 LDrawModelViewer::ExamineMode examineMode = ( examine ?
2178 LDrawModelViewer::EMLatLong : LDrawModelViewer::EMFree );
2179 inputHandler->setViewMode(LDInputHandler::VMExamine);
2180 modelViewer->setConstrainZoom(true);
2181 if (progressMode)
2182 {
2183 progressMode->setText(QString::fromWCharArray(TCLocalStrings::get(L"ExamineMode")));
2184 }
2185 if (progressLatlong)
2186 {
2187 progressLatlong->setHidden(!examine);
2188 }
2189 modelViewer->setExamineMode(examineMode);
2190 }
2191 else if (viewMode == LDInputHandler::VMFlyThrough)
2192 {
2193 inputHandler->setViewMode(LDInputHandler::VMFlyThrough);
2194 modelViewer->setConstrainZoom(false);
2195 modelViewer->setKeepRightSideUp(keep);
2196 if (progressMode)
2197 {
2198 progressMode->setText(QString::fromWCharArray(TCLocalStrings::get(L"FlyThroughMode")));
2199 }
2200 if (progressLatlong) progressLatlong->setHidden(true);
2201 }
2202 else if (viewMode == LDInputHandler::VMWalk)
2203 {
2204 inputHandler->setViewMode(LDInputHandler::VMWalk);
2205 modelViewer->setKeepRightSideUp(true);
2206 if (progressMode)
2207 {
2208 progressMode->setText(QString::fromWCharArray(TCLocalStrings::get(L"WalkMode")));
2209 }
2210 }
2211 Preferences::setViewMode(viewMode);
2212 }
2213
doViewModeChanged(LDInputHandler::ViewMode newMode)2214 void ModelViewerWidget::doViewModeChanged(LDInputHandler::ViewMode newMode)
2215 {
2216 lock();
2217 setViewMode(newMode,examineLatLong, keepRightSide);
2218 unlock();
2219 }
2220
doZoomToFit(void)2221 void ModelViewerWidget::doZoomToFit(void)
2222 {
2223 lock();
2224 if (loading)
2225 {
2226 if (app)
2227 {
2228 app->beep();
2229 }
2230 return;
2231 }
2232 modelViewer->zoomToFit();
2233 startPaintTimer();
2234 unlock();
2235 }
2236
doRightSideUp(void)2237 void ModelViewerWidget::doRightSideUp(void)
2238 {
2239 lock();
2240 if (loading)
2241 {
2242 if (app)
2243 {
2244 app->beep();
2245 }
2246 return;
2247 }
2248 modelViewer->rightSideUp();
2249 startPaintTimer();
2250 unlock();
2251 }
2252
doCameraLocation(void)2253 void ModelViewerWidget::doCameraLocation(void)
2254 {
2255 cameralocation->show();
2256 }
2257
doRotationCenter(void)2258 void ModelViewerWidget::doRotationCenter(void)
2259 {
2260 rotationcenter->show();
2261 }
2262
staticImageProgressCallback(const wchar_t * message,float progress,void * userData)2263 bool ModelViewerWidget::staticImageProgressCallback(const wchar_t* message,
2264 float progress, void* userData)
2265 {
2266 QString qs="";
2267 if (message) wcstoqstring(qs,message);
2268 return ((ModelViewerWidget*)userData)->progressCallback(qs, progress, true);
2269 }
2270
writeImage(char * filename,int width,int height,TCByte * buffer,const char * formatName,bool saveAlpha)2271 bool ModelViewerWidget::writeImage(char *filename, int width, int height,
2272 TCByte *buffer, const char *formatName,
2273 bool saveAlpha)
2274 {
2275 TCImage *image = new TCImage;
2276 bool retValue;
2277 char comment[1024];
2278
2279 if (saveAlpha)
2280 {
2281 image->setDataFormat(TCRgba8);
2282 }
2283 image->setSize(width, height);
2284 image->setLineAlignment(4);
2285 image->setImageData((TCByte*)buffer);
2286 image->setFormatName(formatName);
2287 image->setFlipped(true);
2288 if (strcasecmp(formatName, "PNG") == 0)
2289 {
2290 strcpy(comment, "Software:!:!:LDView");
2291 }
2292 else
2293 {
2294 strcpy(comment, "Created by LDView");
2295 }
2296 image->setComment(comment);
2297 if (TCUserDefaults::longForKey(AUTO_CROP_KEY, 0, false))
2298 {
2299 image->autoCrop((TCByte)modelViewer->getBackgroundR(),
2300 (TCByte)modelViewer->getBackgroundG(),
2301 (TCByte)modelViewer->getBackgroundB());
2302 }
2303 retValue = image->saveFile(filename, staticImageProgressCallback, this);
2304 image->release();
2305 return retValue;
2306 }
2307
roundUp(int value,int nearest)2308 int ModelViewerWidget::roundUp(int value, int nearest)
2309 {
2310 return (value + nearest - 1) / nearest * nearest;
2311 }
2312
setupSnapshotBackBuffer(int imageWidth,int imageHeight)2313 void ModelViewerWidget::setupSnapshotBackBuffer(int imageWidth, int imageHeight)
2314 {
2315 modelViewer->setSlowClear(true);
2316 modelViewer->setWidth(imageWidth);
2317 modelViewer->setHeight(imageHeight);
2318 modelViewer->setup();
2319 glReadBuffer(GL_BACK);
2320 }
2321
grabImage(int & imageWidth,int & imageHeight,bool fromCommandLine)2322 bool ModelViewerWidget::grabImage(
2323 int &imageWidth,
2324 int &imageHeight,
2325 bool fromCommandLine /*= false*/)
2326 {
2327 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
2328 if (fbo == NULL)
2329 {
2330 QOpenGLFramebufferObjectFormat fboFormat;
2331 GLsizei fboSize = 1024;
2332 fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
2333 fbo = new QOpenGLFramebufferObject(fboSize, fboSize, fboFormat);
2334 saving = true;
2335 if (fbo->isValid() && fbo->bind())
2336 {
2337 snapshotTaker->setUseFBO(false);
2338 glViewport(0, 0, fboSize, fboSize);
2339 if (modelViewer->getMainTREModel() == NULL && !modelViewer->getNeedsReload())
2340 {
2341 modelViewer->loadModel(true);
2342 }
2343 inputHandler->stopRotation();
2344 bool retValue = snapshotTaker->saveImage(saveImageFilename, imageWidth, imageHeight, saveImageZoomToFit);
2345 fbo->release();
2346 delete fbo;
2347 fbo = NULL;
2348 saving = false;
2349 return retValue;
2350 }
2351 else
2352 {
2353 delete fbo;
2354 fbo = NULL;
2355 saving = false;
2356 }
2357 }
2358 #endif
2359 if (!fromCommandLine)
2360 {
2361 saving = true;
2362 makeCurrent();
2363 if (modelViewer->getMainTREModel() == NULL && !modelViewer->getNeedsReload())
2364 {
2365 modelViewer->loadModel(true);
2366 }
2367 bool retValue = snapshotTaker->saveImage(saveImageFilename, imageWidth, imageHeight, saveImageZoomToFit);
2368 saving = false;
2369 return retValue;
2370 }
2371 int newWidth = 800;
2372 int newHeight = 600;
2373 int origWidth = mwidth;
2374 int origHeight = mheight;
2375 int numXTiles, numYTiles;
2376 bool origSlowClear = modelViewer->getSlowClear();
2377 int origMemoryUsage = modelViewer->getMemoryUsage();
2378
2379 saving = true;
2380 modelViewer->setMemoryUsage(0);
2381 if (snapshotTaker->getUseFBO())
2382 {
2383 newWidth = snapshotTaker->getFBOSize();
2384 newHeight = snapshotTaker->getFBOSize();
2385 }
2386 snapshotTaker->calcTiling(imageWidth, imageHeight, newWidth, newHeight,
2387 numXTiles, numYTiles);
2388 if (!snapshotTaker->getUseFBO())
2389 {
2390 setupSnapshotBackBuffer(newWidth, newHeight);
2391 }
2392 imageWidth = newWidth * numXTiles;
2393 imageHeight = newHeight * numYTiles;
2394 saveImageWidth = imageWidth;
2395 saveImageHeight = imageHeight;
2396 if (snapshotTaker->getUseFBO())
2397 {
2398 makeCurrent();
2399 if (fromCommandLine)
2400 {
2401 saveImageResult = snapshotTaker->saveImage();
2402 }
2403 else
2404 {
2405 saveImageResult = snapshotTaker->saveImage(saveImageFilename,
2406 saveImageWidth, saveImageHeight, saveImageZoomToFit);
2407 }
2408 }
2409 else
2410 {
2411 #if (QT_VERSION >= 0x50400) && defined(QOPENGLWIDGET)
2412 // Code to be added for renderPixmap functionality
2413 // Without this code saved snapshot image is corrupted/garbage
2414 #else
2415 renderPixmap(newWidth, newHeight);
2416 #endif
2417 }
2418 makeCurrent();
2419 TREGLExtensions::setup();
2420 if (!snapshotTaker->getUseFBO())
2421 {
2422 modelViewer->openGlWillEnd();
2423 }
2424 saving = false;
2425 mwidth = origWidth;
2426 mheight = origHeight;
2427 modelViewer->setWidth(mwidth);
2428 modelViewer->setHeight(mheight);
2429 modelViewer->setMemoryUsage(origMemoryUsage);
2430 modelViewer->setSlowClear(origSlowClear);
2431 modelViewer->setup();
2432 doApply();
2433 return saveImageResult;
2434 }
2435
2436
2437
grabImage(int & imageWidth,int & imageHeight,TCByte * buffer,bool,bool *)2438 TCByte *ModelViewerWidget::grabImage(
2439 int &imageWidth,
2440 int &imageHeight,
2441 TCByte *buffer, bool /*zoomToFit*/,
2442 bool * /*saveAlpha*/)
2443 {
2444 int newWidth = 800;
2445 int newHeight = 600;
2446 int origWidth = mwidth;
2447 int origHeight = mheight;
2448 int numXTiles, numYTiles;
2449 bool origSlowClear = modelViewer->getSlowClear();
2450 int origMemoryUsage = modelViewer->getMemoryUsage();
2451 bool sa=false;
2452 TCByte *bufferReturn = NULL;
2453 if (!snapshotTaker)
2454 {
2455 snapshotTaker = new LDSnapshotTaker(modelViewer);
2456 }
2457 if (TREGLExtensions::haveFramebufferObjectExtension())
2458 {
2459 snapshotTaker->setUseFBO(true);
2460 }
2461 snapshotTaker->setImageType(getSaveImageType());
2462 snapshotTaker->setTrySaveAlpha(saveAlpha =
2463 TCUserDefaults::longForKey(SAVE_ALPHA_KEY, 0, false) != 0);
2464 snapshotTaker->setAutoCrop(
2465 TCUserDefaults::boolForKey(AUTO_CROP_KEY, false, false));
2466
2467 printing = true;
2468 modelViewer->setMemoryUsage(0);
2469 if (snapshotTaker->getUseFBO())
2470 {
2471 newWidth = snapshotTaker->getFBOSize();
2472 newHeight = snapshotTaker->getFBOSize();
2473 }
2474 snapshotTaker->calcTiling(imageWidth, imageHeight, newWidth, newHeight,
2475 numXTiles, numYTiles);
2476 if (!snapshotTaker->getUseFBO())
2477 {
2478 setupSnapshotBackBuffer(newWidth, newHeight);
2479 }
2480 imageWidth = newWidth * numXTiles;
2481 imageHeight = newHeight * numYTiles;
2482 saveImageWidth = imageWidth;
2483 saveImageHeight = imageHeight;
2484 if (snapshotTaker->getUseFBO())
2485 {
2486 makeCurrent();
2487 bufferReturn = snapshotTaker->grabImage(saveImageWidth, saveImageHeight, saveImageZoomToFit,buffer,&sa);
2488 }
2489 makeCurrent();
2490 TREGLExtensions::setup();
2491 if (!snapshotTaker->getUseFBO())
2492 {
2493 modelViewer->openGlWillEnd();
2494 }
2495 printing = false;
2496 mwidth = origWidth;
2497 mheight = origHeight;
2498 modelViewer->setWidth(mwidth);
2499 modelViewer->setHeight(mheight);
2500 modelViewer->setMemoryUsage(origMemoryUsage);
2501 modelViewer->setSlowClear(origSlowClear);
2502 modelViewer->setup();
2503 doApply();
2504 return bufferReturn;
2505 }
2506
calcSaveFilename(char * saveFilename,int)2507 bool ModelViewerWidget::calcSaveFilename(char* saveFilename, int /*len*/)
2508 {
2509 char* filename = modelViewer->getFilename();
2510 saveDigits = TCUserDefaults::longForKey(SAVE_DIGITS_KEY, 1, false);
2511 if (filename)
2512 {
2513 char baseFilename[1024];
2514
2515 if (strrchr(filename, '/'))
2516 {
2517 filename = strrchr(filename, '/') + 1;
2518 }
2519 if (strrchr(filename, '\\'))
2520 {
2521 filename = strrchr(filename, '\\') + 1;
2522 }
2523 strcpy(baseFilename, filename);
2524 if (strchr(baseFilename, '.'))
2525 {
2526 *strchr(baseFilename, '.') = 0;
2527 }
2528 if (curSaveOp == LDPreferences::SOExport)
2529 {
2530 sprintf(saveFilename, "%s.%s", baseFilename,
2531 modelViewer->getExporter(
2532 (LDrawModelViewer::ExportType)exportType)->
2533 getExtension().c_str());
2534 return true;
2535 }
2536 else
2537 {
2538 char format[32] = "%s.%s";
2539 const char *extension = NULL;
2540 int max;
2541 if (TCUserDefaults::longForKey(SAVE_SERIES_KEY, 1, false) != 0)
2542 {
2543 max = (int)(pow(10.0, saveDigits + 0.1));
2544 sprintf(format, "%%s%%0%dd.%%s", saveDigits);
2545 }
2546 else max = 2;
2547 int i;
2548 for (i = 1; i < max; i++)
2549 {
2550 if (saveImageType == PNG_IMAGE_TYPE_INDEX)
2551 {
2552 extension = "png";
2553 }
2554 else if (saveImageType == BMP_IMAGE_TYPE_INDEX)
2555 {
2556 extension = "bmp";
2557 }
2558 else if (saveImageType == JPG_IMAGE_TYPE_INDEX)
2559 {
2560 extension = "jpg";
2561 }
2562 if (TCUserDefaults::longForKey(SAVE_SERIES_KEY, 1, false) != 0)
2563 {
2564 sprintf(saveFilename, format, baseFilename, i , extension);
2565 }
2566 else
2567 {
2568 sprintf(saveFilename, format, baseFilename, extension);
2569 }
2570 if (TCUserDefaults::boolForKey(SAVE_STEPS_KEY, false, false))
2571 {
2572 QString suffix = TCUserDefaults::stringForKey(SAVE_STEPS_SUFFIX_KEY,
2573 TCLocalStrings::get("DefaultStepSuffix"), false);
2574 std::string temp = LDSnapshotTaker::addStepSuffix(saveFilename,
2575 suffix.toUtf8().constData(), 1, modelViewer->getNumSteps());
2576 strcpy(saveFilename, temp.c_str());
2577
2578 }
2579 if (!fileExists(saveFilename))
2580 {
2581 return true;
2582 }
2583 }
2584 return true;
2585 }
2586 }
2587 return false;
2588 }
2589
getSaveFilename(char * saveFilename,int len)2590 bool ModelViewerWidget::getSaveFilename(char* saveFilename, int len)
2591 {
2592 QString initialDir = preferences->getSaveDir(curSaveOp,
2593 modelViewer->getFilename());
2594 LDrawModelViewer::ExportType origExportType = modelViewer->getExportType();
2595 QStringList exportFilters;
2596 // QStringList::const_iterator exportFilterIt;
2597
2598 QDir::setCurrent(initialDir);
2599 saveImageType = TCUserDefaults::longForKey(SAVE_IMAGE_TYPE_KEY, 1, false);
2600 exportType = TCUserDefaults::longForKey(SAVE_EXPORT_TYPE_KEY,
2601 LDrawModelViewer::ETPov, false);
2602 if (!calcSaveFilename(saveFilename, len))
2603 {
2604 saveFilename[0] = 0;
2605 }
2606 switch (curSaveOp)
2607 {
2608 case LDPreferences::SOExport:
2609 origExportType = modelViewer->getExportType();
2610 for (int i = LDrawModelViewer::ETFirst; i <= LDrawModelViewer::ETLast;
2611 i++)
2612 {
2613 const LDExporter *exporter = modelViewer->getExporter(
2614 (LDrawModelViewer::ExportType)i);
2615
2616 if (exporter != NULL)
2617 {
2618 ucstring ucFileType = exporter->getTypeDescription();
2619 QString qFileType;
2620
2621 ucstringtoqstring(qFileType, ucFileType);
2622 qFileType += " (*.";
2623 qFileType += exporter->getExtension().c_str();
2624 qFileType += ")";
2625 exportFilters << qFileType;
2626 }
2627 }
2628 modelViewer->getExporter(origExportType);
2629 saveDialog = new QFileDialog(this,QString::fromWCharArray(TCLocalStrings::get(L"ExportModel")),".");
2630 saveDialog->setWindowIcon(QPixmap( ":/images/images/LDViewIcon16.png"));
2631 #if QT_VERSION < 0x40400
2632 saveDialog->setFilters(exportFilters);
2633 saveDialog->selectFilter(saveDialog->filters().at(exportType - LDrawModelViewer::ETFirst));
2634 #else
2635 saveDialog->setNameFilters(exportFilters);
2636 saveDialog->selectNameFilter(exportFilters.at(exportType - LDrawModelViewer::ETFirst));
2637 #endif
2638 saveDialog->setFileMode(QFileDialog::AnyFile);
2639 saveDialog->setAcceptMode(QFileDialog::AcceptSave);
2640 saveDialog->setLabelText(QFileDialog::Accept,"Export");
2641
2642 break;
2643 case LDPreferences::SOSnapshot:
2644 default:
2645 saveDialog = new QFileDialog(this,QString::fromWCharArray(TCLocalStrings::get(L"SaveSnapshot")),".",
2646 "Portable Network Graphics (*.png);;Windows Bitmap (*.bmp);;Jpeg (*.jpg)");
2647 #if QT_VERSION < 0x40400
2648 saveDialog->selectFilter(saveDialog->filters().at(saveImageType-1));
2649 #else
2650 saveDialog->selectNameFilter(saveDialog->nameFilters().at(saveImageType-1));
2651 #endif
2652 saveDialog->setWindowIcon(QPixmap( ":/images/images/LDViewIcon16.png"));
2653 saveDialog->setFileMode(QFileDialog::AnyFile);
2654 saveDialog->setAcceptMode(QFileDialog::AcceptSave);
2655 saveDialog->setLabelText(QFileDialog::Accept,"Save");
2656 break;
2657 }
2658 saveDialog->selectFile(saveFilename);
2659 if (saveDialog->exec() == QDialog::Accepted)
2660 {
2661 QString selectedfile="";
2662 if (!saveDialog->selectedFiles().isEmpty())
2663 {
2664 selectedfile = saveDialog->selectedFiles()[0];
2665 }
2666 QString filename = selectedfile, dir = saveDialog->directory().path();
2667 switch (curSaveOp)
2668 {
2669 case LDPreferences::SOExport:
2670 TCUserDefaults::setPathForKey(dir.toUtf8().constData(), LAST_EXPORT_DIR_KEY, false);
2671 break;
2672 case LDPreferences::SOSnapshot:
2673 default:
2674 TCUserDefaults::setPathForKey(dir.toUtf8().constData(), LAST_SNAPSHOT_DIR_KEY, false);
2675 break;
2676 }
2677 QDir::setCurrent(dir);
2678 strncpy(saveFilename,filename.toUtf8().constData(),len);
2679 #if QT_VERSION < 0x40400
2680 QString filter = saveDialog->selectedFilter();
2681 #else
2682 QString filter = saveDialog->selectedNameFilter();
2683 #endif
2684 if (filter.indexOf(".png") != -1)
2685 {
2686 saveImageType = PNG_IMAGE_TYPE_INDEX;
2687 }
2688 if (filter.indexOf(".jpg") != -1)
2689 {
2690 saveImageType = JPG_IMAGE_TYPE_INDEX;
2691 }
2692 if (filter.indexOf(".bmp") != -1)
2693 {
2694 saveImageType = BMP_IMAGE_TYPE_INDEX;
2695 }
2696 if (filter.indexOf(".pov") != -1)
2697 {
2698 exportType = LDrawModelViewer::ETPov;
2699 }
2700 if (filter.indexOf(".stl") != -1)
2701 {
2702 exportType = LDrawModelViewer::ETStl;
2703 }
2704 #ifdef EXPORT_3DS
2705 if (filter.indexOf(".3ds") != -1)
2706 {
2707 exportType = LDrawModelViewer::ET3ds;
2708 }
2709 #endif
2710
2711 TCUserDefaults::setLongForKey(saveImageType, SAVE_IMAGE_TYPE_KEY,
2712 false);
2713 TCUserDefaults::setLongForKey(exportType, SAVE_EXPORT_TYPE_KEY, false);
2714 if(strlen(saveFilename)>5 && saveFilename[strlen(saveFilename)-4]!='.')
2715 {
2716 if (saveImageType == PNG_IMAGE_TYPE_INDEX)
2717 {
2718 strcat(saveFilename, ".png");
2719 }
2720 else if (saveImageType == BMP_IMAGE_TYPE_INDEX)
2721 {
2722 strcat(saveFilename, ".bmp");
2723 }
2724 else if (saveImageType == JPG_IMAGE_TYPE_INDEX)
2725 {
2726 strcat(saveFilename, ".jpg");
2727 }
2728 }
2729 delete saveDialog;
2730 return true;
2731 }
2732 delete saveDialog;
2733 return false;
2734 }
2735
writeBmp(char * filename,int width,int height,TCByte * buffer)2736 bool ModelViewerWidget::writeBmp(char *filename, int width, int height,
2737 TCByte *buffer)
2738 {
2739 return writeImage(filename, width, height, buffer, "BMP");
2740 }
2741
writePng(char * filename,int width,int height,TCByte * buffer,bool saveAlpha)2742 bool ModelViewerWidget::writePng(char *filename, int width, int height,
2743 TCByte *buffer, bool saveAlpha)
2744 {
2745 return writeImage(filename, width, height, buffer, "PNG", saveAlpha);
2746 }
2747
getSaveImageType(void)2748 LDSnapshotTaker::ImageType ModelViewerWidget::getSaveImageType(void)
2749 {
2750 switch (saveImageType)
2751 {
2752 case PNG_IMAGE_TYPE_INDEX:
2753 return LDSnapshotTaker::ITPng;
2754 case BMP_IMAGE_TYPE_INDEX:
2755 return LDSnapshotTaker::ITBmp;
2756 case JPG_IMAGE_TYPE_INDEX:
2757 return LDSnapshotTaker::ITJpg;
2758 default:
2759 return LDSnapshotTaker::ITPng;
2760 }
2761 }
2762
saveImage(char * filename,int imageWidth,int imageHeight,bool fromCommandLine)2763 bool ModelViewerWidget::saveImage(
2764 char *filename,
2765 int imageWidth,
2766 int imageHeight,
2767 bool fromCommandLine /*= false*/)
2768 {
2769 bool retValue = false;
2770
2771 if (!snapshotTaker)
2772 {
2773 if (fromCommandLine)
2774 {
2775 //
2776 // The command line snapshot will be blank if LDSnapshotTaker has no argument
2777 //
2778 snapshotTaker = new LDSnapshotTaker(modelViewer);
2779 }
2780 else
2781 {
2782 snapshotTaker = new LDSnapshotTaker(modelViewer);
2783 }
2784 }
2785 if (TREGLExtensions::haveFramebufferObjectExtension())
2786 {
2787 snapshotTaker->setUseFBO(true);
2788 }
2789 snapshotTaker->setImageType(getSaveImageType());
2790 snapshotTaker->setTrySaveAlpha(saveAlpha =
2791 TCUserDefaults::longForKey(SAVE_ALPHA_KEY, 0, false) != 0);
2792 snapshotTaker->setAutoCrop(
2793 TCUserDefaults::boolForKey(AUTO_CROP_KEY, false, false));
2794 saveImageFilename = filename;
2795 //snapshotTaker->setProductVersion(
2796 // ((LDViewWindow *)parentWindow)->getProductVersion());
2797 saveImageZoomToFit = TCUserDefaults::longForKey(SAVE_ZOOM_TO_FIT_KEY, 1,
2798 false);
2799 retValue = grabImage(imageWidth, imageHeight, fromCommandLine);
2800 return retValue;
2801 }
2802
fileExists(const char * filename)2803 bool ModelViewerWidget::fileExists(const char* filename)
2804 {
2805 FILE* file = fopen(filename, "r");
2806
2807 if (file)
2808 {
2809 fclose(file);
2810 return true;
2811 }
2812 else
2813 {
2814 return false;
2815 }
2816 }
2817
shouldOverwriteFile(char * filename)2818 bool ModelViewerWidget::shouldOverwriteFile(char* filename)
2819 {
2820 char buf[256];
2821
2822 sprintf(buf, TCLocalStrings::get("OverwritePrompt"),
2823 filename);
2824 switch( QMessageBox::warning( this, "LDView",
2825 buf,
2826 QMessageBox::Yes | QMessageBox::Default,
2827 QMessageBox::No | QMessageBox::Escape )) {
2828 case QMessageBox::Yes:
2829 return true;
2830 break;
2831 }
2832 return false;
2833 }
2834
fileExport()2835 void ModelViewerWidget::fileExport()
2836 {
2837 curSaveOp = LDPreferences::SOExport;
2838 char saveFilename[1024] = "";
2839 if (getSaveFilename(saveFilename, 1024)&&
2840 (!fileExists(saveFilename)||shouldOverwriteFile(saveFilename)))
2841 {
2842 modelViewer->setExportType((LDrawModelViewer::ExportType)exportType);
2843 modelViewer->exportCurModel(saveFilename);
2844 }
2845 }
2846
fileExportOption()2847 void ModelViewerWidget::fileExportOption()
2848 {
2849 LDViewExportOption exportOption(mainWindow,modelViewer);
2850
2851 if (exportOption.exec() == QDialog::Rejected)
2852 {
2853 modelViewer->getExporter((LDrawModelViewer::ExportType)0, true);
2854 }
2855 }
2856
file3DSExportOption()2857 void ModelViewerWidget::file3DSExportOption()
2858 {
2859 #ifdef EXPORT_3DS
2860 LDViewExportOption dsExportOption(mainWindow,modelViewer,LDrawModelViewer::ET3ds);
2861 dsExportOption.setWindowTitle("3DS Export Options");
2862 if (dsExportOption.exec() == QDialog::Rejected)
2863 {
2864 modelViewer->getExporter((LDrawModelViewer::ExportType)0, true);
2865 }
2866 #endif
2867 }
2868
doFileSave(void)2869 bool ModelViewerWidget::doFileSave(void)
2870 {
2871 char saveFilename[1024] = "";
2872
2873 return doFileSave(saveFilename);
2874 }
2875
doFileSave(char * saveFilename)2876 bool ModelViewerWidget::doFileSave(char *saveFilename)
2877 {
2878 curSaveOp = LDPreferences::SOSnapshot;
2879 if (getSaveFilename(saveFilename, 1024))
2880 {
2881 if(fileExists(saveFilename)&&!shouldOverwriteFile(saveFilename))
2882 {
2883 return false;
2884 }
2885 return saveImage(saveFilename, TCUserDefaults::longForKey(SAVE_ACTUAL_SIZE_KEY, 1, false) ? TCUserDefaults::longForKey(SAVE_WIDTH_KEY, 1024, false) : modelViewer->getWidth(),
2886 TCUserDefaults::longForKey(SAVE_ACTUAL_SIZE_KEY, 1, false) ? TCUserDefaults::longForKey(SAVE_HEIGHT_KEY, 768, false) : modelViewer->getHeight());
2887 }
2888 else
2889 {
2890 return false;
2891 }
2892 }
2893
doFileSaveSettings(void)2894 void ModelViewerWidget::doFileSaveSettings(void)
2895 {
2896 snapshotsettings->show();
2897 }
2898
doFileJPEGOptions(void)2899 void ModelViewerWidget::doFileJPEGOptions(void)
2900 {
2901 jpegoptions->show();
2902 }
2903
doFrontViewAngle(void)2904 void ModelViewerWidget::doFrontViewAngle(void)
2905 {
2906 lock();
2907 if (loading)
2908 {
2909 if (app)
2910 {
2911 app->beep();
2912 }
2913 return;
2914 }
2915 rotationSpeed = 0.0f;
2916 modelViewer->setRotationSpeed(0.0f);
2917 modelViewer->setZoomSpeed(0.0f);
2918 modelViewer->resetView(LDVAngleFront);
2919 startPaintTimer();
2920 unlock();
2921 }
2922
doBackViewAngle(void)2923 void ModelViewerWidget::doBackViewAngle(void)
2924 {
2925 lock();
2926 if (loading)
2927 {
2928 if (app)
2929 {
2930 app->beep();
2931 }
2932 return;
2933 }
2934 rotationSpeed = 0.0f;
2935 modelViewer->setRotationSpeed(0.0f);
2936 modelViewer->setZoomSpeed(0.0f);
2937 modelViewer->resetView(LDVAngleBack);
2938 startPaintTimer();
2939 unlock();
2940 }
2941
doLeftViewAngle(void)2942 void ModelViewerWidget::doLeftViewAngle(void)
2943 {
2944 lock();
2945 if (loading)
2946 {
2947 if (app)
2948 {
2949 app->beep();
2950 }
2951 return;
2952 }
2953 rotationSpeed = 0.0f;
2954 modelViewer->setRotationSpeed(0.0f);
2955 modelViewer->setZoomSpeed(0.0f);
2956 modelViewer->resetView(LDVAngleLeft);
2957 startPaintTimer();
2958 unlock();
2959 }
2960
doRightViewAngle(void)2961 void ModelViewerWidget::doRightViewAngle(void)
2962 {
2963 lock();
2964 if (loading)
2965 {
2966 if (app)
2967 {
2968 app->beep();
2969 }
2970 return;
2971 }
2972 rotationSpeed = 0.0f;
2973 modelViewer->setRotationSpeed(0.0f);
2974 modelViewer->setZoomSpeed(0.0f);
2975 modelViewer->resetView(LDVAngleRight);
2976 startPaintTimer();
2977 unlock();
2978 }
2979
doTopViewAngle(void)2980 void ModelViewerWidget::doTopViewAngle(void)
2981 {
2982 lock();
2983 if (loading)
2984 {
2985 if (app)
2986 {
2987 app->beep();
2988 }
2989 return;
2990 }
2991 rotationSpeed = 0.0f;
2992 modelViewer->setRotationSpeed(0.0f);
2993 modelViewer->setZoomSpeed(0.0f);
2994 modelViewer->resetView(LDVAngleTop);
2995 startPaintTimer();
2996 unlock();
2997 }
2998
doBottomViewAngle(void)2999 void ModelViewerWidget::doBottomViewAngle(void)
3000 {
3001 lock();
3002 if (loading)
3003 {
3004 if (app)
3005 {
3006 app->beep();
3007 }
3008 return;
3009 }
3010 rotationSpeed = 0.0f;
3011 modelViewer->setRotationSpeed(0.0f);
3012 modelViewer->setZoomSpeed(0.0f);
3013 modelViewer->resetView(LDVAngleBottom);
3014 startPaintTimer();
3015 unlock();
3016 }
3017
doLatLongViewAngle(void)3018 void ModelViewerWidget::doLatLongViewAngle(void)
3019 {
3020 lock();
3021 if (loading)
3022 {
3023 if (app)
3024 {
3025 app->beep();
3026 }
3027 return;
3028 }
3029 latitudelongitude->exec();
3030 unlock();
3031 }
3032
doIsoViewAngle(void)3033 void ModelViewerWidget::doIsoViewAngle(void)
3034 {
3035 lock();
3036 if (loading)
3037 {
3038 if (app)
3039 {
3040 app->beep();
3041 }
3042 return;
3043 }
3044 rotationSpeed = 0.0f;
3045 modelViewer->setRotationSpeed(0.0f);
3046 modelViewer->setZoomSpeed(0.0f);
3047 modelViewer->resetView(LDVAngleIso);
3048 startPaintTimer();
3049 unlock();
3050 }
3051
doSaveDefaultViewAngle(void)3052 void ModelViewerWidget::doSaveDefaultViewAngle(void)
3053 {
3054 preferences->doSaveDefaultViewAngle();
3055 }
3056
cleanupFloats(TCFloat * array,int count)3057 void ModelViewerWidget::cleanupFloats(TCFloat *array, int count)
3058 {
3059 int i;
3060
3061 for (i = 0; i < count; i++)
3062 {
3063 if (fabs(array[i]) < 1e-6)
3064 {
3065 array[i] = 0.0f;
3066 }
3067 }
3068 }
3069
doShowViewInfo(void)3070 void ModelViewerWidget::doShowViewInfo(void)
3071 {
3072 QString qmessage,qcl;
3073 if (modelViewer)
3074 {
3075 ucstring message, commandLine;
3076 if (modelViewer->getViewInfo(message, commandLine))
3077 {
3078 ucstringtoqstring(qmessage,message);
3079 ucstringtoqstring(qcl,commandLine);
3080 if(QMessageBox::information(this,
3081 QString::fromWCharArray(TCLocalStrings::get(L"ViewInfoTitle")),
3082 qmessage, QMessageBox::Ok,
3083 QMessageBox::Cancel)==QMessageBox::Ok)
3084 {
3085 QApplication::clipboard()->setText(qcl);
3086 }
3087 }
3088 }
3089 }
3090
doShowPovCamera(void)3091 void ModelViewerWidget::doShowPovCamera(void)
3092 {
3093 if (modelViewer)
3094 {
3095 UCSTR userMessage;
3096 char *povCamera;
3097 modelViewer->getPovCameraInfo(userMessage, povCamera);
3098 if (userMessage && povCamera)
3099 {
3100 QString quserMessage;
3101
3102 ucstringtoqstring(quserMessage, userMessage);
3103 if (QMessageBox::information(this,
3104 QString::fromWCharArray(TCLocalStrings::get(L"PovCameraTitle")), quserMessage,
3105 QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok)
3106 {
3107 QApplication::clipboard()->setText(QString(povCamera));
3108 };
3109 }
3110 delete userMessage;
3111 delete povCamera;
3112 }
3113 }
doShowPovAspectRatio(bool flag)3114 void ModelViewerWidget::doShowPovAspectRatio(bool flag)
3115 {
3116 modelViewer->setPovCameraAspect(flag, true);
3117 }
3118
doPartList(LDHtmlInventory * htmlInventory,LDPartsList * partsList,const char * filename)3119 void ModelViewerWidget::doPartList(
3120 LDHtmlInventory *htmlInventory,
3121 LDPartsList *partsList,
3122 const char *filename)
3123 {
3124 if (htmlInventory->generateHtml(filename, partsList,
3125 modelViewer->getFilename()))
3126 {
3127 if (htmlInventory->isSnapshotNeeded())
3128 {
3129 char *snapshotPath = copyString(htmlInventory->getSnapshotPath());
3130 bool saveZoomToFit = modelViewer->getForceZoomToFit();
3131 bool saveActualSize = TCUserDefaults::longForKey(SAVE_ACTUAL_SIZE_KEY, 1, false);
3132 int saveWidth = TCUserDefaults::longForKey(SAVE_WIDTH_KEY, 1024, false);
3133 int saveHeight = TCUserDefaults::longForKey(SAVE_HEIGHT_KEY, 768, false);
3134 bool origSteps = TCUserDefaults::boolForKey(SAVE_STEPS_KEY, false,
3135 false);
3136 int origStep = modelViewer->getStep();
3137
3138 TCUserDefaults::setBoolForKey(false, SAVE_STEPS_KEY, false);
3139 modelViewer->setStep(modelViewer->getNumSteps());
3140 htmlInventory->prepForSnapshot(modelViewer);
3141 modelViewer->setForceZoomToFit(true);
3142 TCUserDefaults::setLongForKey(false, SAVE_ACTUAL_SIZE_KEY, false);
3143 TCUserDefaults::setLongForKey(800, SAVE_WIDTH_KEY, false);
3144 TCUserDefaults::setLongForKey(600, SAVE_HEIGHT_KEY, false);
3145
3146 // By saying it's from the command line, none of the above settings
3147 // will be written to TCUserDefaults. I know it's not really from
3148 // the command line, but it produces the behavior we want.
3149 saveImageType = PNG_IMAGE_TYPE_INDEX;
3150 saveImage(snapshotPath, 800, 600);
3151 delete snapshotPath;
3152 htmlInventory->restoreAfterSnapshot(modelViewer);
3153 modelViewer->setForceZoomToFit(saveZoomToFit);
3154 TCUserDefaults::setLongForKey(saveActualSize, SAVE_ACTUAL_SIZE_KEY, false);
3155 TCUserDefaults::setLongForKey(saveWidth, SAVE_WIDTH_KEY, false);
3156 TCUserDefaults::setLongForKey(saveHeight, SAVE_HEIGHT_KEY, false);
3157 modelViewer->setStep(origStep);
3158 TCUserDefaults::setBoolForKey(origSteps, SAVE_STEPS_KEY, false);
3159 doApply();
3160 }
3161 }
3162 else
3163 {
3164 QMessageBox::warning(this,"LDView",
3165 QString::fromWCharArray(TCLocalStrings::get(L"PLGenerateError")),
3166 QMessageBox::Ok, QMessageBox::NoButton);
3167 }
3168 }
doPartList(void)3169 void ModelViewerWidget::doPartList(void)
3170 {
3171 if (modelViewer)
3172 {
3173 LDPartsList *partsList = modelViewer->getPartsList();
3174 if (partsList)
3175 {
3176 LDHtmlInventory *htmlInventory = new LDHtmlInventory;
3177 PartList *partlist = new PartList(mainWindow, this, htmlInventory);
3178 if (partlist->exec() == QDialog::Accepted)
3179 {
3180 QString initialDir = preferences->getSaveDir(LDPreferences::SOPartsList,
3181 modelViewer->getFilename());
3182 QDir::setCurrent(initialDir);
3183
3184 bool done = false;
3185 char *cFilename = modelViewer->getFilename();
3186 QString filename;
3187
3188 if (cFilename)
3189 {
3190 filename = cFilename;
3191 }
3192 else
3193 {
3194 consolePrintf("No filename from modelViewer.\n");
3195 }
3196 int findSpot = filename.lastIndexOf((
3197 #if QT_VERSION >= 0x60000
3198 QRegularExpression("/\\")
3199 #else
3200 QRegExp("/\\")
3201 #endif
3202 ));
3203 if (findSpot >= 0 && findSpot < (int)filename.length())
3204 filename=filename.mid(findSpot+1);
3205 findSpot = filename.lastIndexOf(('.'));
3206 if (findSpot >= 0 && findSpot < (int)filename.length())
3207 filename=filename.left(findSpot);
3208 filename += ".html";
3209 findSpot = filename.lastIndexOf(('/'));
3210 if (findSpot >= 0 && findSpot < (int)filename.length())
3211 filename = filename.mid(findSpot + 1);
3212 QString startWith = QString(htmlInventory->getLastSavePath()) +
3213 QString("/") + filename;
3214 QString filter = QString(TCLocalStrings::get("HtmlFileType")) +
3215 " (*.html)";
3216 while (!done)
3217 {
3218 QString htmlFilename = QFileDialog::getSaveFileName(this,
3219 QString::fromWCharArray(TCLocalStrings::get(L"GeneratePartsList")),
3220 initialDir + "/" + filename,
3221 filter);
3222 if (htmlFilename.isEmpty())
3223 {
3224 done = true;
3225 }
3226 else
3227 {
3228 if (fileExists(htmlFilename.toUtf8().constData()))
3229 {
3230 QString prompt =
3231 QString::fromWCharArray(TCLocalStrings::get(L"OverwritePrompt"));
3232
3233 prompt.replace("%s", htmlFilename);
3234 if (QMessageBox::warning(this, "LDView", prompt,
3235 QMessageBox::Yes, QMessageBox::No) ==
3236 QMessageBox::No)
3237 {
3238 continue;
3239 }
3240 }
3241 doPartList(htmlInventory, partsList,
3242 htmlFilename.toUtf8().constData());
3243 done = true;
3244 }
3245 }
3246 }
3247 htmlInventory->release();
3248 partsList->release();
3249 }
3250 }
3251 }
3252
doModelTree()3253 void ModelViewerWidget::doModelTree()
3254 {
3255 modeltree->show();
3256 }
3257
doBoundingBox()3258 void ModelViewerWidget::doBoundingBox()
3259 {
3260 boundingbox->show();
3261 }
3262
doMpdModel()3263 void ModelViewerWidget::doMpdModel()
3264 {
3265 mpdmodel->show();
3266 }
3267
3268 // Note: static method
convertKeyCode(int osKey)3269 LDInputHandler::KeyCode ModelViewerWidget::convertKeyCode(int osKey)
3270 {
3271 if (osKey >= Qt::Key_A && osKey <= Qt::Key_Z)
3272 {
3273 return (LDInputHandler::KeyCode)(osKey - Qt::Key_A +
3274 LDInputHandler::KCA);
3275 }
3276 else
3277 {
3278 switch (osKey)
3279 {
3280 case Qt::Key_Up:
3281 return LDInputHandler::KCUp;
3282 case Qt::Key_Down:
3283 return LDInputHandler::KCDown;
3284 case Qt::Key_Left:
3285 return LDInputHandler::KCLeft;
3286 case Qt::Key_Right:
3287 return LDInputHandler::KCRight;
3288 case Qt::Key_Space:
3289 return LDInputHandler::KCSpace;
3290 case Qt::Key_PageUp:
3291 return LDInputHandler::KCPageUp;
3292 case Qt::Key_PageDown:
3293 return LDInputHandler::KCPageDown;
3294 case Qt::Key_Home:
3295 return LDInputHandler::KCHome;
3296 case Qt::Key_End:
3297 return LDInputHandler::KCEnd;
3298 case Qt::Key_Insert:
3299 return LDInputHandler::KCInsert;
3300 case Qt::Key_Delete:
3301 return LDInputHandler::KCDelete;
3302 case Qt::Key_Escape:
3303 return LDInputHandler::KCEscape;
3304 default:
3305 return LDInputHandler::KCUnknown;
3306 }
3307 }
3308 }
3309
keyPressEvent(QKeyEvent * event)3310 void ModelViewerWidget::keyPressEvent(QKeyEvent *event)
3311 {
3312 lock();
3313 if (inputHandler->keyDown(convertKeyModifiers(event->modifiers()),
3314 convertKeyCode(event->key())))
3315 {
3316 event->accept();
3317 }
3318 else
3319 {
3320 event->ignore();
3321 }
3322 if((event->modifiers() & Qt::AltModifier) &&
3323 (event->key() >= Qt::Key_0) &&
3324 (event->key() <= Qt::Key_9) && preferences)
3325 {
3326 int i = event->key()-Qt::Key_0;
3327 preferences->performHotKey(i);
3328 }
3329 if(event->key() == Qt::Key_F10 && fullscreen)
3330 {
3331 doViewFullScreen();
3332 }
3333 unlock();
3334 #if (QT_VERSION >= 0x50400) && defined(QOPENGLWIDGET)
3335 QOpenGLWidget::keyPressEvent(event);
3336 #else
3337 QGLWidget::keyPressEvent(event);
3338 #endif
3339 }
3340
keyReleaseEvent(QKeyEvent * event)3341 void ModelViewerWidget::keyReleaseEvent(QKeyEvent *event)
3342 {
3343 lock();
3344 if (inputHandler->keyUp(convertKeyModifiers(event->modifiers()),
3345 convertKeyCode(event->key())))
3346 {
3347 event->accept();
3348 }
3349 else
3350 {
3351 event->ignore();
3352 }
3353 unlock();
3354 #if (QT_VERSION >= 0x50400) && defined(QOPENGLWIDGET)
3355 QOpenGLWidget::keyReleaseEvent(event);
3356 #else
3357 QGLWidget::keyReleaseEvent(event);
3358 #endif
3359 }
3360
ldlErrorCallback(LDLError * error)3361 void ModelViewerWidget::ldlErrorCallback(LDLError *error)
3362 {
3363 if (error)
3364 {
3365 if (!errorCallback(error))
3366 {
3367 error->cancelLoad();
3368 }
3369 }
3370 }
3371
modelViewerAlertCallback(TCAlert * alert)3372 void ModelViewerWidget::modelViewerAlertCallback(TCAlert *alert)
3373 {
3374 if (alert)
3375 {
3376 QMessageBox::warning(this,"LDView",alert->getMessage(),
3377 QMessageBox::Ok, QMessageBox::NoButton);
3378 }
3379 }
3380
snapshotTakerAlertCallback(TCAlert * alert)3381 void ModelViewerWidget::snapshotTakerAlertCallback(TCAlert *alert)
3382 {
3383 if (alert->getSender() == snapshotTaker)
3384 {
3385 if (strcmp(alert->getMessage(), "MakeCurrent") == 0)
3386 {
3387 if (isFboActive())
3388 {
3389 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
3390 if (!fbo->isBound())
3391 {
3392 fbo->bind();
3393 }
3394 #endif
3395 }
3396 else
3397 {
3398 makeCurrent();
3399 }
3400 //glEnable(GL_DEPTH_TEST);
3401 }
3402 }
3403 }
3404
redrawAlertCallback(TCAlert *)3405 void ModelViewerWidget::redrawAlertCallback(TCAlert * /*alert*/)
3406 {
3407 lock();
3408 startPaintTimer();
3409 redrawRequested = true;
3410 unlock();
3411 }
3412
captureAlertCallback(TCAlert *)3413 void ModelViewerWidget::captureAlertCallback(TCAlert * /*alert*/)
3414 {
3415 }
3416
releaseAlertCallback(TCAlert *)3417 void ModelViewerWidget::releaseAlertCallback(TCAlert * /*alert*/)
3418 {
3419 }
3420
lightVectorChangedAlertCallback(TCAlert *)3421 void ModelViewerWidget::lightVectorChangedAlertCallback(TCAlert * /*alert*/)
3422 {
3423 if (preferences)
3424 {
3425 preferences->checkLightVector();
3426 }
3427 }
3428
libraryUpdateProgress(TCProgressAlert * alert)3429 void ModelViewerWidget::libraryUpdateProgress(TCProgressAlert *alert)
3430 {
3431 // NOTE: this gets called from inside one of the library update threads. It
3432 // does NOT happen in the app's main thread.
3433
3434
3435 // Are we allowed to update widgets from outside the main thread? NOPE!
3436 lock();
3437 //debugPrintf("Updater progress (%s): %f\n", alert->getMessage(),
3438 // alert->getProgress());
3439 libraryUpdateProgressMessage = QString::fromWCharArray(alert->getWMessage());
3440 libraryUpdateProgressValue = alert->getProgress();
3441 libraryUpdateProgressReady = true;
3442 unlock();
3443 if (alert->getProgress() == 1.0f)
3444 {
3445 // Progress of 1.0 means the library updater is done.
3446 if (alert->getExtraInfo())
3447 {
3448 // We can't call doLibraryUpdateFinished directly, because we're
3449 // executing from the library update thread. The
3450 // doLibraryUpdateFinished function waits for the library update
3451 // thread to complete. That will never happen if it's executing
3452 // inside the library update thread. So we record the finish code,
3453 // tell ourselves we have done so, and the doLibraryUpdateTimer()
3454 // slot will take care of the rest when running in non-modal mode,
3455 // and the modal loop will take care of things when running in
3456 // modal mode (during initial library install).
3457 if (strcmp((*(alert->getExtraInfo()))[0], "None") == 0)
3458 {
3459 libraryUpdateFinishCode = LIBRARY_UPDATE_NONE;
3460 }
3461 else
3462 {
3463 libraryUpdateFinishCode = LIBRARY_UPDATE_FINISHED;
3464 }
3465 }
3466 else
3467 {
3468 libraryUpdateFinishCode = LIBRARY_UPDATE_CANCELED;
3469 }
3470 // Just as a note, while I believe that assignment of an int is an
3471 // atomic operation (and therefore doesn't require thread checking),
3472 // I'm not 100% sure of this. So set the code first, and then once
3473 // it's definitely set, set the notification. I really couldn't care
3474 // less if the notification setting is atomic, since I'm only doing a
3475 // boolean compare on it.
3476 libraryUpdateFinishNotified = true;
3477 }
3478 else if (alert->getProgress() == 2.0f)
3479 {
3480 // Progress of 2.0 means the library updater encountered an
3481 // error.
3482 libraryUpdateFinishCode = LIBRARY_UPDATE_ERROR;
3483 libraryUpdateFinishNotified = true;
3484 }
3485 if (libraryUpdateCanceled)
3486 {
3487 alert->abort();
3488 }
3489 }
3490
progressAlertCallback(TCProgressAlert * alert)3491 void ModelViewerWidget::progressAlertCallback(TCProgressAlert *alert)
3492 {
3493 if (alert && !saving)
3494 {
3495 if (strcmp(alert->getSource(), "LDLibraryUpdater") == 0)
3496 {
3497 libraryUpdateProgress(alert);
3498 }
3499 else
3500 {
3501 bool showErrors = true;
3502 QString message;
3503
3504 if (strcmp(alert->getSource(), "TCImage") == 0)
3505 {
3506 showErrors = false;
3507 }
3508 wcstoqstring(message, alert->getWMessage());
3509 if (!progressCallback(message, alert->getProgress(),
3510 showErrors))
3511 {
3512 alert->abort();
3513 }
3514 }
3515 }
3516 }
3517
staticFileCaseLevel(QDir & dir,char * filename)3518 bool ModelViewerWidget::staticFileCaseLevel(QDir &dir, char *filename)
3519 {
3520 int i;
3521 int len = strlen(filename);
3522 QString wildcard;
3523 QStringList files;
3524
3525 if (!dir.isReadable())
3526 {
3527 return false;
3528 }
3529 for (i = 0; i < len; i++)
3530 {
3531 QChar letter = filename[i];
3532
3533 if (letter.isLetter())
3534 {
3535 wildcard.append('[');
3536 wildcard.append(letter.toLower());
3537 wildcard.append(letter.toUpper());
3538 wildcard.append(']');
3539 }
3540 else
3541 {
3542 wildcard.append(letter);
3543 }
3544 }
3545 dir.setNameFilters(QStringList(wildcard));
3546 files = dir.entryList();
3547 if (files.count())
3548 {
3549 QString file = files[0];
3550
3551 if (file.length() == (int)strlen(filename))
3552 {
3553 // This should never be false, but just want to be sure.
3554 strcpy(filename, file.toUtf8().constData());
3555 return true;
3556 }
3557 }
3558 return false;
3559 }
3560
staticFileCaseCallback(char * filename)3561 bool ModelViewerWidget::staticFileCaseCallback(char *filename)
3562 {
3563 char *shortName;
3564 QDir dir;
3565 char *firstSlashSpot;
3566
3567 dir.setFilter(QDir::AllEntries | QDir::Readable | QDir::Hidden | QDir::System);
3568 replaceStringCharacter(filename, '\\', '/');
3569 firstSlashSpot = strchr(filename, '/');
3570 if (firstSlashSpot)
3571 {
3572 char *lastSlashSpot = strrchr(filename, '/');
3573 int dirLen;
3574 char *dirName;
3575
3576 while (firstSlashSpot != lastSlashSpot)
3577 {
3578 char *nextSlashSpot = strchr(firstSlashSpot + 1, '/');
3579
3580 dirLen = firstSlashSpot - filename + 1;
3581 dirName = new char[dirLen + 1];
3582 *nextSlashSpot = 0;
3583 strncpy(dirName, filename, dirLen);
3584 dirName[dirLen] = 0;
3585 if (dirLen)
3586 {
3587 dir.setPath(dirName);
3588 delete dirName;
3589 if (!staticFileCaseLevel(dir, firstSlashSpot + 1))
3590 {
3591 return false;
3592 }
3593 }
3594 firstSlashSpot = nextSlashSpot;
3595 *firstSlashSpot = '/';
3596 }
3597 dirLen = lastSlashSpot - filename;
3598 dirName = new char[dirLen + 1];
3599 strncpy(dirName, filename, dirLen);
3600 dirName[dirLen] = 0;
3601 dir.setPath(dirName);
3602 shortName = lastSlashSpot + 1;
3603 delete dirName;
3604 }
3605 else
3606 {
3607 shortName = filename;
3608 }
3609 return staticFileCaseLevel(dir, shortName);
3610 }
3611
canSaveAlpha(void)3612 bool ModelViewerWidget::canSaveAlpha(void)
3613 {
3614 if (saveAlpha && (saveImageType == PNG_IMAGE_TYPE_INDEX))
3615 {
3616 GLint alphaBits;
3617
3618 glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
3619 return alphaBits > 0;
3620 }
3621 return false;
3622 }
3623
renderOffscreenImage(void)3624 void ModelViewerWidget::renderOffscreenImage(void)
3625 {
3626 modelViewer->update();
3627 repaint();
3628 // offscreen = renderPixmap();
3629 if(canSaveAlpha())
3630 {
3631 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
3632 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
3633 glEnable(GL_DEPTH_TEST);
3634 glDisable(GL_LIGHTING);
3635 glDisable(GL_POLYGON_OFFSET_FILL);
3636 glDepthFunc(GL_GREATER);
3637 glDepthRange(0.0f, 1.0f);
3638 glBegin(GL_QUADS);
3639 treGlVertex3f(0.0f, 0.0f, -1.0f);
3640 treGlVertex3f((TCFloat)mwidth, 0.0f, -1.0f);
3641 treGlVertex3f((TCFloat)mwidth, (TCFloat)mheight, -1.0f);
3642 treGlVertex3f(0.0f, (TCFloat)mheight, -1.0f);
3643 glEnd();
3644 glColor4ub(0, 0, 0, 129);
3645 glBlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA);
3646 glEnable(GL_BLEND);
3647 glDisable(GL_DEPTH_TEST);
3648 glEnable(GL_ALPHA_TEST);
3649 glAlphaFunc(GL_LESS, 1.0);
3650 glBegin(GL_QUADS);
3651 treGlVertex3f(0.0f, 0.0f, -1.0f);
3652 treGlVertex3f((TCFloat)mwidth, 0.0f, -1.0f);
3653 treGlVertex3f((TCFloat)mwidth, (TCFloat)mheight, -1.0f);
3654 treGlVertex3f(0.0f, (TCFloat)mheight, -1.0f);
3655 glEnd();
3656 glPopAttrib();
3657 }
3658 }
3659
calcTiling(int desiredWidth,int desiredHeight,int & bitmapWidth,int & bitmapHeight,int & numXTiles,int & numYTiles)3660 void ModelViewerWidget::calcTiling(int desiredWidth, int desiredHeight,
3661 int &bitmapWidth, int &bitmapHeight,
3662 int &numXTiles, int &numYTiles)
3663 {
3664 if (desiredWidth > bitmapWidth)
3665 {
3666 numXTiles = (desiredWidth + bitmapWidth - 1) / bitmapWidth;
3667 }
3668 else
3669 {
3670 numXTiles = 1;
3671 }
3672 bitmapWidth = desiredWidth / numXTiles;
3673 if (desiredHeight > bitmapHeight)
3674 {
3675 numYTiles = (desiredHeight + bitmapHeight - 1) / bitmapHeight;
3676 }
3677 else
3678 {
3679 numYTiles = 1;
3680 }
3681 bitmapHeight = desiredHeight / numYTiles;
3682 }
3683
userDefaultChangedAlertCallback(TCAlert * alert)3684 void ModelViewerWidget::userDefaultChangedAlertCallback(TCAlert *alert)
3685 {
3686 if (preferences)
3687 {
3688 preferences->userDefaultChangedAlertCallback(alert);
3689 }
3690 }
3691
doPreferences(void)3692 void ModelViewerWidget::doPreferences(void)
3693 {
3694 showPreferences();
3695 }
3696
findPackageFile(const QString & filename)3697 QString ModelViewerWidget::findPackageFile(const QString &filename)
3698 {
3699 QString dir = QDir::currentPath();
3700 QFile file(filename);
3701 QString retValue;
3702
3703 // if (!file.exists())
3704 // QDir::setCurrent("..");
3705 if (!file.exists())
3706 QDir::setCurrent("Textures");
3707 if (!file.exists())
3708 QDir::setCurrent("/usr/share/ldview");
3709 if (!file.exists())
3710 QDir::setCurrent("/usr/local/share/ldview");
3711 if (!file.exists())
3712 QDir::setCurrent("/usr/local/etc");
3713 if (!file.exists())
3714 QDir::setCurrent("/usr/local/lib");
3715 if (!file.exists())
3716 QDir::setCurrent(QDir( QCoreApplication::applicationDirPath() + "/../share/ldview").absolutePath());
3717 if (!file.exists())
3718 {
3719 const char *argv0 = TCUserDefaults::getArgv0();
3720
3721 QDir::setCurrent(dir);
3722 if (argv0)
3723 {
3724 char *path = copyString(argv0, filename.length() + 5);
3725
3726 if (strrchr(path, '/'))
3727 {
3728 *strrchr(path, '/') = 0;
3729 }
3730 QDir::setCurrent(path);
3731 }
3732 }
3733 if (file.exists())
3734 {
3735 QString newDir = QDir::currentPath();
3736 retValue = newDir + "/" + file.fileName();
3737 }
3738 QDir::setCurrent(dir);
3739 return retValue;
3740 }
3741
3742 // Note: static method.
convertKeyModifiers(Qt::KeyboardModifiers osModifiers)3743 TCULong ModelViewerWidget::convertKeyModifiers(Qt::KeyboardModifiers osModifiers)
3744 {
3745 TCULong retValue = 0;
3746 if (osModifiers & Qt::ShiftModifier)
3747 {
3748 retValue |= LDInputHandler::MKShift;
3749 }
3750 if (osModifiers & Qt::ControlModifier)
3751 {
3752 retValue |= LDInputHandler::MKControl;
3753 }
3754 return retValue;
3755 }
3756
nextStep()3757 void ModelViewerWidget::nextStep()
3758 {
3759 if (modelViewer->getStep()>=modelViewer->getNumSteps())
3760 return;
3761 modelViewer->setStep(modelViewer->getStep()+1);
3762 updateStep();
3763 doApply();
3764 }
3765
prevStep()3766 void ModelViewerWidget::prevStep()
3767 {
3768 if (modelViewer->getStep()<=1)
3769 return;
3770 modelViewer->setStep(modelViewer->getStep()-1);
3771 updateStep();
3772 doApply();
3773 }
3774
firstStep()3775 void ModelViewerWidget::firstStep()
3776 {
3777 modelViewer->setStep(1);
3778 updateStep();
3779 doApply();
3780 }
3781
lastStep()3782 void ModelViewerWidget::lastStep()
3783 {
3784 modelViewer->setStep(modelViewer->getNumSteps());
3785 updateStep();
3786 doApply();
3787 }
3788
3789
updateStep()3790 void ModelViewerWidget::updateStep()
3791 {
3792 int step = modelViewer->getStep();
3793 QString max = QString::number(modelViewer->getNumSteps());
3794 mainWindow->toolbarFirstStepSetEnabled(step>1);
3795 mainWindow->toolbarPrevStepSetEnabled(step>1);
3796 mainWindow->toolbarNextStepSetEnabled(modelViewer->getNumSteps()>step);
3797 mainWindow->toolbarLastStepSetEnabled(modelViewer->getNumSteps()>step);
3798 mainWindow->setStepGotoEnabled(modelViewer->getNumSteps()>0);
3799 mainWindow->toolbarMaxStepSetText(" / "+max);
3800 mainWindow->toolbarCurrentStepSetText(QString::number(step));
3801 }
3802
gotoStep()3803 void ModelViewerWidget::gotoStep()
3804 {
3805 bool ok;
3806 int step =
3807 #if QT_VERSION < 0x40500
3808 QInputDialog::getInteger(
3809 #else
3810 QInputDialog::getInt(
3811 #endif
3812 this,"Step","Go to Step:",
3813 modelViewer->getStep(), 1, modelViewer->getNumSteps(), 1, &ok );
3814 if (ok)
3815 {
3816 modelViewer->setStep(step);
3817 updateStep();
3818 doApply();
3819 }
3820 }
3821
3822