// Copyright (c) 2008 GeometryFactory Sarl (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // You can redistribute it and/or modify it under the terms of the GNU // General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0+ // // // Author(s) : Andreas Fabri // Laurent Rineau #ifdef CGAL_HEADER_ONLY #define CGAL_INLINE_FUNCTION inline #include #else #define CGAL_INLINE_FUNCTION #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // needed to get CGAL_VERSION_STR #include #include namespace CGAL { namespace Qt { CGAL_INLINE_FUNCTION DemosMainWindow::DemosMainWindow(QWidget * parent, ::Qt::WindowFlags flags) : QMainWindow(parent, flags), maxNumRecentFiles(10), recentFileActs(maxNumRecentFiles) { // prepare the QLabel xycoord for inclusion in the statusBar() xycoord = new QLabel(" -0.00000 , -0.00000 ", this); xycoord->setAlignment(::Qt::AlignHCenter); xycoord->setMinimumSize(xycoord->sizeHint()); xycoord->clear(); actionUse_OpenGL = new QAction(this); actionUse_OpenGL->setObjectName("actionUse_OpenGL"); actionUse_OpenGL->setCheckable(true); actionUse_OpenGL->setText(tr("Use &OpenGL")); actionUse_OpenGL->setStatusTip(tr("Make Qt use OpenGL to display the graphical items, instead of its native painting system.")); actionUse_OpenGL->setShortcut(tr("Ctrl+G")); actionUse_Antialiasing = new QAction(this); actionUse_Antialiasing->setObjectName("actionUse_Antialiasing"); actionUse_Antialiasing->setCheckable(true); actionUse_Antialiasing->setText(tr("Use &anti-aliasing")); actionUse_Antialiasing->setStatusTip(tr("Make Qt use anti-aliasing when displaying the graphical items.")); actionUse_Antialiasing->setShortcut(tr("Ctrl+A")); actionAboutCGAL = new QAction(this); actionAboutCGAL->setObjectName("actionAboutCGAL"); actionAboutCGAL->setText(tr("About &CGAL...")); actionAbout = new QAction(this); actionAbout->setObjectName("actionAbout"); actionAbout->setText(tr("&About...")); setAcceptDrops(true); } CGAL_INLINE_FUNCTION DemosMainWindow::~DemosMainWindow() { } CGAL_INLINE_FUNCTION void DemosMainWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("text/uri-list")) event->acceptProposedAction(); } CGAL_INLINE_FUNCTION void DemosMainWindow::dropEvent(QDropEvent *event) { Q_FOREACH(QUrl url, event->mimeData()->urls()) { QString filename = url.toLocalFile(); this->open(filename); } event->acceptProposedAction(); } CGAL_INLINE_FUNCTION void DemosMainWindow::addNavigation(QGraphicsView* graphicsView) { navigation = new CGAL::Qt::GraphicsViewNavigation(); graphicsView->viewport()->installEventFilter(navigation); graphicsView->installEventFilter(navigation); QObject::connect(navigation, SIGNAL(mouseCoordinates(QString)), xycoord, SLOT(setText(QString))); view = graphicsView; } CGAL_INLINE_FUNCTION void DemosMainWindow::setupStatusBar() { this->statusBar()->addWidget(new QLabel(this), 1); this->statusBar()->addWidget(xycoord, 0); } CGAL_INLINE_FUNCTION void DemosMainWindow::setupOptionsMenu(QMenu* menuOptions) { // search for the Options menu if(!menuOptions) { menuOptions = getMenu("menuOptions", tr("&Options")); } // if not found, then create it if(!menuOptions) { menuOptions = new QMenu(this->menuBar()); menuOptions->setTitle(tr("&Options")); this->menuBar()->addAction(menuOptions->menuAction()); menuOptions->setObjectName("menuOptions"); } if(!menuOptions->isEmpty()) { menuOptions->addSeparator(); } menuOptions->addAction(actionUse_OpenGL); menuOptions->addAction(actionUse_Antialiasing); connect(actionUse_Antialiasing, SIGNAL(toggled(bool)), this, SLOT(setUseAntialiasing(bool))); connect(actionUse_OpenGL, SIGNAL(toggled(bool)), this, SLOT(setUseOpenGL(bool))); actionUse_Antialiasing->setChecked(true); } CGAL_INLINE_FUNCTION void DemosMainWindow::setupExportSVG(QAction* action, QGraphicsView* view) { this->view = view; connect(action, SIGNAL(triggered(bool)), this, SLOT(exportSVG())); } CGAL_INLINE_FUNCTION void DemosMainWindow::exportSVG() { QString fileName = QFileDialog::getSaveFileName(this, tr("Export to SVG"), ".", tr("SVG (*.svg)\n")); QSvgGenerator svg; svg.setFileName(fileName); svg.setSize(this->view->size()); svg.setViewBox(this->view->sceneRect()); svg.setTitle(tr("%1 drawing").arg(qApp->applicationName())); svg.setDescription(tr("Generated using %1").arg(qApp->applicationName())); QPainter painter; painter.begin(&svg); this->view->render(&painter); painter.end(); } CGAL_INLINE_FUNCTION void DemosMainWindow::setUseAntialiasing(bool checked) { view->setRenderHint(QPainter::Antialiasing, checked); view->setRenderHint(QPainter::HighQualityAntialiasing, checked); statusBar()->showMessage(tr("Antialiasing %1activated").arg(checked?"":"de-"), 1000); } CGAL_INLINE_FUNCTION void DemosMainWindow::setUseOpenGL(bool checked) { if(checked) { QGLWidget* new_viewport = new QGLWidget; // Setup the format to allow antialiasing with OpenGL: // one need to activate the SampleBuffers, if the graphic driver allows // this. QGLFormat glformat = new_viewport->format(); glformat.setOption(QGL::SampleBuffers); new_viewport->setFormat(glformat); view->setViewport(new_viewport); } else { view->setViewport(new QWidget); } statusBar()->showMessage(tr("OpenGL %1activated").arg(checked?"":"de-"), 1000); view->viewport()->installEventFilter(navigation); view->setFocus(); } CGAL_INLINE_FUNCTION QMenu* DemosMainWindow::getMenu(QString objectName, QString title) { QMenu* menu = NULL; QString title2 = title; title2.remove('&'); // search if a menu has objectName()==objectName menu = this->findChild(objectName); // then search if a menu has title()==title if(menu) { return menu; } else { Q_FOREACH(menu, this->findChildren()) { if(menu->title() == title || menu->title() == title2) { return menu; } } } return NULL; } CGAL_INLINE_FUNCTION void DemosMainWindow::popupAboutBox(QString title, QString html_resource_name) { QFile about_CGAL(html_resource_name); about_CGAL.open(QIODevice::ReadOnly); QString about_CGAL_txt = QTextStream(&about_CGAL).readAll(); #ifdef CGAL_VERSION_STR QString cgal_version(CGAL_VERSION_STR); # ifdef CGAL_FAKE_PUBLIC_RELEASE cgal_version.replace(QRegExp("-Ic?.*"), ""); # endif about_CGAL_txt.replace("", QString(" (version %1)") .arg(cgal_version)); #endif QMessageBox mb(QMessageBox::NoIcon, title, about_CGAL_txt, QMessageBox::Ok, this); QLabel* mb_label = mb.findChild("qt_msgbox_label"); if(mb_label) { mb_label->setTextInteractionFlags(mb_label->textInteractionFlags() | ::Qt::LinksAccessibleByMouse | ::Qt::LinksAccessibleByKeyboard); } else { std::cerr << "Cannot find child \"qt_msgbox_label\" in QMessageBox\n" << " with Qt version " << QT_VERSION_STR << "!\n"; } mb.exec(); } CGAL_INLINE_FUNCTION QMenu* DemosMainWindow::getHelpMenu() { QMenu* menuHelp = getMenu("menuHelp", tr("&Help")); if(!menuHelp) { menuHelp = new QMenu(this->menuBar()); menuHelp->setTitle(tr("&Help")); this->menuBar()->addAction(menuHelp->menuAction()); menuHelp->setObjectName("menuHelp"); } return menuHelp; } CGAL_INLINE_FUNCTION void DemosMainWindow::addAboutCGAL(QMenu* menuHelp) { if(!menuHelp) { menuHelp = getHelpMenu(); } menuHelp->addAction(actionAboutCGAL); connect(actionAboutCGAL, SIGNAL(triggered()), this, SLOT(popupAboutCGAL())); } CGAL_INLINE_FUNCTION void DemosMainWindow::addAboutDemo(QString htmlResourceName, QMenu* menuHelp) { if(!menuHelp) { menuHelp = getHelpMenu(); } menuHelp->addAction(actionAbout); aboutHtmlResource = htmlResourceName; connect(actionAbout, SIGNAL(triggered()), this, SLOT(popupAboutDemo())); } CGAL_INLINE_FUNCTION void DemosMainWindow::popupAboutCGAL() { popupAboutBox(tr("About CGAL..."), ":/cgal/help/about_CGAL.html"); } CGAL_INLINE_FUNCTION void DemosMainWindow::popupAboutDemo() { popupAboutBox(tr("About the demo..."), aboutHtmlResource); } CGAL_INLINE_FUNCTION void DemosMainWindow::setMaxNumberOfRecentFiles(const unsigned int i) { maxNumRecentFiles = i; recentFileActs.resize(maxNumRecentFiles); } CGAL_INLINE_FUNCTION unsigned int DemosMainWindow::maxNumberOfRecentFiles() const { return maxNumRecentFiles; } CGAL_INLINE_FUNCTION void DemosMainWindow::openRecentFile_aux() { QAction *action = qobject_cast(sender()); if (action) Q_EMIT openRecentFile(action->data().toString()); } CGAL_INLINE_FUNCTION void DemosMainWindow::addToRecentFiles(QString fileName) { QSettings settings; QStringList files = settings.value("recentFileList").toStringList(); files.removeAll(fileName); files.prepend(fileName); while (files.size() > (int)maxNumberOfRecentFiles()) files.removeLast(); settings.setValue("recentFileList", files); updateRecentFileActions(); } CGAL_INLINE_FUNCTION void DemosMainWindow::addRecentFiles(QMenu* menu, QAction* insertBeforeAction) { if(!insertBeforeAction) { recentFilesSeparator = menu->addSeparator(); } for (unsigned int i = 0; i < maxNumberOfRecentFiles(); ++i) { recentFileActs[i] = new QAction(this); recentFileActs[i]->setVisible(false); connect(recentFileActs[i], SIGNAL(triggered()), this, SLOT(openRecentFile_aux())); if(insertBeforeAction) menu->insertAction(insertBeforeAction, recentFileActs[i]); else menu->addAction(recentFileActs[i]); } if(insertBeforeAction) { recentFilesSeparator = menu->insertSeparator(insertBeforeAction); } recentFilesSeparator->setVisible(false); updateRecentFileActions(); } CGAL_INLINE_FUNCTION void DemosMainWindow::updateRecentFileActions() { QSettings settings; QStringList files = settings.value("recentFileList").toStringList(); int numRecentFiles = qMin(files.size(), (int)this->maxNumberOfRecentFiles()); for (int i = 0; i < numRecentFiles; ++i) { QString strippedName = QFileInfo(files[i]).fileName(); QString text = tr("&%1 %2").arg(i).arg(strippedName); recentFileActs[i]->setText(text); recentFileActs[i]->setData(files[i]); recentFileActs[i]->setVisible(true); } for (unsigned int j = numRecentFiles; j < maxNumberOfRecentFiles(); ++j) recentFileActs[j]->setVisible(false); recentFilesSeparator->setVisible(numRecentFiles > 0); } CGAL_INLINE_FUNCTION void DemosMainWindow::writeState(QString groupname) { QSettings settings; settings.beginGroup(groupname); settings.setValue("size", size()); settings.setValue("pos", pos()); settings.setValue("state", saveState()); settings.endGroup(); } CGAL_INLINE_FUNCTION void DemosMainWindow::readState(QString groupname, Options /*what_to_save*/) { QSettings settings; settings.beginGroup(groupname); resize(settings.value("size", this->size()).toSize()); QDesktopWidget* desktop = qApp->desktop(); QPoint pos = settings.value("pos", this->pos()).toPoint(); if(desktop->availableGeometry(pos).contains(pos)) { move(pos); } QByteArray mainWindowState = settings.value("state").toByteArray(); if(!mainWindowState.isNull()) { this->restoreState(mainWindowState); } settings.endGroup(); } } // namespace Qt } // namespace CGAL