Download src/Mod/Sandbox/Gui/GLGraphicsView.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 21 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Sandbox/Gui/GLGraphicsView.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Sandbox/Gui/GLGraphicsView.cpp
-
curl -L -o GLGraphicsView.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Sandbox/Gui/GLGraphicsView.cpp
21 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This library is free software; you can redistribute it and/or * | |
| * modify it under the terms of the GNU Library General Public * | |
| * License as published by the Free Software Foundation; either * | |
| * version 2 of the License, or (at your option) any later version. * | |
| * * | |
| * This library is distributed in the hope that it will be useful, * | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| * GNU Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with this library; see the file COPYING.LIB. If not, * | |
| * write to the Free Software Foundation, Inc., 59 Temple Place, * | |
| * Suite 330, Boston, MA 02111-1307, USA * | |
| * * | |
| ***************************************************************************/ | |
| using namespace Gui; | |
| // http://doc.qt.digia.com/qq/qq26-openglcanvas.html | |
| GraphicsView::GraphicsView() | |
| { | |
| } | |
| GraphicsView::~GraphicsView() | |
| { | |
| } | |
| bool GraphicsView::viewportEvent(QEvent* event) | |
| { | |
| if (event->type() == QEvent::Paint || event->type() == QEvent::Resize) { | |
| return QGraphicsView::viewportEvent(event); | |
| } | |
| else if (event->type() == QEvent::MouseMove || | |
| event->type() == QEvent::Wheel || | |
| event->type() == QEvent::MouseButtonDblClick || | |
| event->type() == QEvent::MouseButtonRelease || | |
| event->type() == QEvent::MouseButtonPress) { | |
| QMouseEvent* mouse = static_cast<QMouseEvent*>(event); | |
| QGraphicsItem *item = itemAt(mouse->pos()); | |
| if (!item) { | |
| QGraphicsView::viewportEvent(event); | |
| return false; | |
| } | |
| return QGraphicsView::viewportEvent(event); | |
| } | |
| return QGraphicsView::viewportEvent(event); | |
| } | |
| void GraphicsView::resizeEvent(QResizeEvent *event) | |
| { | |
| if (scene()) | |
| scene()->setSceneRect( | |
| QRect(QPoint(0, 0), event->size())); | |
| QGraphicsView::resizeEvent(event); | |
| } | |
| // ---------------------------------------------------------------------------- | |
| class SceneEventFilter::Private | |
| { | |
| public: | |
| QList<SIM::Coin3D::Quarter::InputDevice *> devices; | |
| GraphicsScene * scene; | |
| QPoint globalmousepos; | |
| SbVec2s windowsize; | |
| void trackWindowSize(QResizeEvent * event) | |
| { | |
| this->windowsize = SbVec2s(event->size().width(), | |
| event->size().height()); | |
| Q_FOREACH(SIM::Coin3D::Quarter::InputDevice * device, this->devices) { | |
| device->setWindowSize(this->windowsize); | |
| } | |
| } | |
| void trackPointerPosition(QMouseEvent * event) | |
| { | |
| assert(this->windowsize[1] != -1); | |
| this->globalmousepos = event->globalPos(); | |
| SbVec2s mousepos(event->pos().x(), this->windowsize[1] - event->pos().y() - 1); | |
| Q_FOREACH(SIM::Coin3D::Quarter::InputDevice * device, this->devices) { | |
| device->setMousePosition(mousepos); | |
| } | |
| } | |
| }; | |
| SceneEventFilter::SceneEventFilter(QObject * parent) | |
| : QObject(parent) | |
| { | |
| PRIVATE(this) = new Private; | |
| PRIVATE(this)->scene = dynamic_cast<GraphicsScene *>(parent); | |
| assert(PRIVATE(this)->scene); | |
| PRIVATE(this)->windowsize = SbVec2s(PRIVATE(this)->scene->width(), | |
| PRIVATE(this)->scene->height()); | |
| PRIVATE(this)->devices += new SIM::Coin3D::Quarter::Mouse; | |
| PRIVATE(this)->devices += new SIM::Coin3D::Quarter::Keyboard; | |
| PRIVATE(this)->devices += new SpaceNavigatorDevice; | |
| } | |
| SceneEventFilter::~SceneEventFilter() | |
| { | |
| qDeleteAll(PRIVATE(this)->devices); | |
| delete PRIVATE(this); | |
| } | |
| /*! | |
| Adds a device for event translation | |
| */ | |
| void | |
| SceneEventFilter::registerInputDevice(SIM::Coin3D::Quarter::InputDevice * device) | |
| { | |
| PRIVATE(this)->devices += device; | |
| } | |
| /*! | |
| Removes a device from event translation | |
| */ | |
| void | |
| SceneEventFilter::unregisterInputDevice(SIM::Coin3D::Quarter::InputDevice * device) | |
| { | |
| int i = PRIVATE(this)->devices.indexOf(device); | |
| if (i != -1) { | |
| PRIVATE(this)->devices.removeAt(i); | |
| } | |
| } | |
| /*! Translates Qt Events into Coin events and passes them on to the | |
| event QuarterWidget for processing. If the event can not be | |
| translated or processed, it is forwarded to Qt and the method | |
| returns false. | |
| */ | |
| bool | |
| SceneEventFilter::eventFilter(QObject *, QEvent * qevent) | |
| { | |
| // Convert the scene event back to a standard event | |
| std::unique_ptr<QEvent> sceneev; | |
| switch (qevent->type()) { | |
| case QEvent::GraphicsSceneMouseMove: | |
| { | |
| QGraphicsSceneMouseEvent* ev = static_cast<QGraphicsSceneMouseEvent*>(qevent); | |
| sceneev.reset(new QMouseEvent(QEvent::MouseMove, ev->pos().toPoint(), | |
| ev->button(), ev->buttons(), ev->modifiers())); | |
| qevent = sceneev.get(); | |
| break; | |
| } | |
| case QEvent::GraphicsSceneMousePress: | |
| { | |
| QGraphicsSceneMouseEvent* ev = static_cast<QGraphicsSceneMouseEvent*>(qevent); | |
| sceneev.reset(new QMouseEvent(QEvent::MouseButtonPress, ev->pos().toPoint(), | |
| ev->button(), ev->buttons(), ev->modifiers())); | |
| qevent = sceneev.get(); | |
| break; | |
| } | |
| case QEvent::GraphicsSceneMouseRelease: | |
| { | |
| QGraphicsSceneMouseEvent* ev = static_cast<QGraphicsSceneMouseEvent*>(qevent); | |
| sceneev.reset(new QMouseEvent(QEvent::MouseButtonRelease, ev->pos().toPoint(), | |
| ev->button(), ev->buttons(), ev->modifiers())); | |
| qevent = sceneev.get(); | |
| break; | |
| } | |
| case QEvent::GraphicsSceneMouseDoubleClick: | |
| { | |
| QGraphicsSceneMouseEvent* ev = static_cast<QGraphicsSceneMouseEvent*>(qevent); | |
| sceneev.reset(new QMouseEvent(QEvent::MouseButtonDblClick, ev->pos().toPoint(), | |
| ev->button(), ev->buttons(), ev->modifiers())); | |
| qevent = sceneev.get(); | |
| break; | |
| } | |
| case QEvent::GraphicsSceneWheel: | |
| { | |
| QGraphicsSceneWheelEvent* ev = static_cast<QGraphicsSceneWheelEvent*>(qevent); | |
| sceneev.reset(new QWheelEvent(ev->pos().toPoint(), ev->delta(), ev->buttons(), | |
| ev->modifiers(), ev->orientation())); | |
| qevent = sceneev.get(); | |
| break; | |
| } | |
| case QEvent::GraphicsSceneResize: | |
| { | |
| QGraphicsSceneResizeEvent* ev = static_cast<QGraphicsSceneResizeEvent*>(qevent); | |
| sceneev.reset(new QResizeEvent(ev->newSize().toSize(), ev->oldSize().toSize())); | |
| qevent = sceneev.get(); | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| // make sure every device has updated screen size and mouse position | |
| // before translating events | |
| switch (qevent->type()) { | |
| case QEvent::MouseMove: | |
| case QEvent::MouseButtonPress: | |
| case QEvent::MouseButtonRelease: | |
| case QEvent::MouseButtonDblClick: | |
| PRIVATE(this)->trackPointerPosition(dynamic_cast<QMouseEvent *>(qevent)); | |
| break; | |
| case QEvent::Resize: | |
| PRIVATE(this)->trackWindowSize(dynamic_cast<QResizeEvent *>(qevent)); | |
| break; | |
| default: | |
| break; | |
| } | |
| // translate QEvent into SoEvent and see if it is handled by scene | |
| // graph | |
| Q_FOREACH(SIM::Coin3D::Quarter::InputDevice * device, PRIVATE(this)->devices) { | |
| const SoEvent * soevent = device->translateEvent(qevent); | |
| if (soevent && PRIVATE(this)->scene->processSoEvent(soevent)) { | |
| //return true; | |
| } | |
| } | |
| return false; | |
| } | |
| /*! | |
| Returns mouse position in global coordinates | |
| */ | |
| const QPoint & | |
| SceneEventFilter::globalMousePosition(void) const | |
| { | |
| return PRIVATE(this)->globalmousepos; | |
| } | |
| // ---------------------------------------------------------------------------- | |
| QDialog *GraphicsScene::createDialog(const QString &windowTitle) const | |
| { | |
| QDialog *dialog = new QDialog(0, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint); | |
| dialog->setWindowOpacity(0.8); | |
| dialog->setWindowTitle(windowTitle); | |
| dialog->setLayout(new QVBoxLayout); | |
| return dialog; | |
| } | |
| GraphicsScene::GraphicsScene() | |
| : m_backgroundColor(0, 170, 255) | |
| , m_lastTime(0) | |
| , m_distance(1.4f) | |
| { | |
| headlight = new SoDirectionalLight(); | |
| headlight->ref(); | |
| sceneNode = new SoSeparator(); | |
| sceneNode->ref(); | |
| this->addEllipse(20,20, 120, 60); | |
| QWidget *controls = createDialog(tr("Controls")); | |
| QCheckBox *wireframe = new QCheckBox(tr("Render as wireframe")); | |
| controls->layout()->addWidget(wireframe); | |
| QCheckBox *normals = new QCheckBox(tr("Display normals vectors")); | |
| controls->layout()->addWidget(normals); | |
| QPushButton *colorButton = new QPushButton(tr("Choose model color")); | |
| controls->layout()->addWidget(colorButton); | |
| QWidget *instructions = createDialog(tr("Instructions")); | |
| instructions->layout()->addWidget(new QLabel(tr("Use mouse wheel to zoom model, and click and drag to rotate model"))); | |
| instructions->layout()->addWidget(new QLabel(tr("Move the sun around to change the light position"))); | |
| QGraphicsProxyWidget* g1 = addWidget(instructions); | |
| g1->setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint); | |
| QGraphicsProxyWidget* g2 = addWidget(controls); | |
| g2->setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint); | |
| controls->setAttribute(Qt::WA_TranslucentBackground); | |
| QPointF pos(10, 10); | |
| Q_FOREACH (QGraphicsItem *item, items()) { | |
| item->setFlag(QGraphicsItem::ItemIsMovable); | |
| item->setCacheMode(QGraphicsItem::DeviceCoordinateCache); | |
| const QRectF rect = item->boundingRect(); | |
| item->setPos(pos.x() - rect.x(), pos.y() - rect.y()); | |
| pos += QPointF(0, 10 + rect.height()); | |
| } | |
| m_time.start(); | |
| sorendermanager = new SoRenderManager; | |
| sorendermanager->setAutoClipping(SoRenderManager::VARIABLE_NEAR_PLANE); | |
| sorendermanager->setBackgroundColor(SbColor4f(0.0f, 0.0f, 0.0f, 0.0f)); | |
| sorendermanager->activate(); | |
| soeventmanager = new SoEventManager; | |
| soeventmanager->setNavigationState(SoEventManager::MIXED_NAVIGATION); | |
| eventfilter = new SceneEventFilter(this); | |
| connect(this, SIGNAL(sceneRectChanged(const QRectF&)), | |
| this, SLOT(onSceneRectChanged(const QRectF&))); | |
| } | |
| GraphicsScene::~GraphicsScene() | |
| { | |
| headlight->unref(); | |
| sceneNode->unref(); | |
| delete sorendermanager; | |
| delete soeventmanager; | |
| delete eventfilter; | |
| } | |
| void GraphicsScene::viewAll() | |
| { | |
| SoCamera* cam = sorendermanager->getCamera(); | |
| if (cam) | |
| cam->viewAll(sceneNode, sorendermanager->getViewportRegion()); | |
| } | |
| SceneEventFilter * | |
| GraphicsScene::getEventFilter(void) const | |
| { | |
| return eventfilter; | |
| } | |
| bool | |
| GraphicsScene::processSoEvent(const SoEvent * event) | |
| { | |
| if (event) { | |
| return soeventmanager && soeventmanager->processEvent(event); | |
| } | |
| return false; | |
| } | |
| void | |
| GraphicsScene::addStateMachine(SoScXMLStateMachine * statemachine) | |
| { | |
| SoEventManager * em = this->getSoEventManager(); | |
| em->addSoScXMLStateMachine(statemachine); | |
| statemachine->setSceneGraphRoot(this->getSoRenderManager()->getSceneGraph()); | |
| statemachine->setActiveCamera(this->getSoRenderManager()->getCamera()); | |
| } | |
| void | |
| GraphicsScene::removeStateMachine(SoScXMLStateMachine * statemachine) | |
| { | |
| SoEventManager * em = this->getSoEventManager(); | |
| statemachine->setSceneGraphRoot(NULL); | |
| statemachine->setActiveCamera(NULL); | |
| em->removeSoScXMLStateMachine(statemachine); | |
| } | |
| void | |
| GraphicsScene::setNavigationModeFile(const QUrl & url) | |
| { | |
| QString filename; | |
| if (url.scheme()== QLatin1String("coin")) { | |
| filename = url.path(); | |
| //FIXME: This conditional needs to be implemented when the | |
| //CoinResources systems if working | |
| //Workaround for differences between url scheme, and Coin internal | |
| //scheme in Coin 3.0. | |
| if (filename[0] == QLatin1Char('/')) { | |
| filename.remove(0,1); | |
| } | |
| filename = url.scheme() + QLatin1Char(':') + filename; | |
| } | |
| else if (url.scheme() == QLatin1String("file")) | |
| filename = url.toLocalFile(); | |
| else if (url.isEmpty()) { | |
| return; | |
| } | |
| else { | |
| return; | |
| } | |
| QByteArray filenametmp = filename.toLocal8Bit(); | |
| ScXMLStateMachine * stateMachine = NULL; | |
| if (filenametmp.startsWith("coin:")){ | |
| stateMachine = ScXML::readFile(filenametmp.data()); | |
| } | |
| else { | |
| //Use Qt to read the file in case it is a Qt resource | |
| QFile file(QString::fromLatin1(filenametmp)); | |
| if (file.open(QIODevice::ReadOnly)) { | |
| QByteArray fileContents = file.readAll(); | |
| stateMachine = ScXML::readBuffer(SbByteBuffer(fileContents.size(), fileContents.constData())); | |
| file.close(); | |
| } | |
| } | |
| if (stateMachine && stateMachine->isOfType(SoScXMLStateMachine::getClassTypeId())) { | |
| SoScXMLStateMachine * newsm = static_cast<SoScXMLStateMachine *>(stateMachine); | |
| this->addStateMachine(newsm); | |
| newsm->initialize(); | |
| } | |
| else { | |
| if (stateMachine) | |
| delete stateMachine; | |
| return; | |
| } | |
| } | |
| SoNode* GraphicsScene::getSceneGraph() const | |
| { | |
| return sceneNode; | |
| } | |
| SoCamera * | |
| GraphicsScene::searchForCamera(SoNode * root) | |
| { | |
| SoSearchAction sa; | |
| sa.setInterest(SoSearchAction::FIRST); | |
| sa.setType(SoCamera::getClassTypeId()); | |
| sa.apply(root); | |
| if (sa.getPath()) { | |
| SoNode * node = sa.getPath()->getTail(); | |
| if (node && node->isOfType(SoCamera::getClassTypeId())) { | |
| return (SoCamera *) node; | |
| } | |
| } | |
| return NULL; | |
| } | |
| void GraphicsScene::setSceneGraph(SoNode * node) | |
| { | |
| if (node == sceneNode) { | |
| return; | |
| } | |
| if (sceneNode) { | |
| sceneNode->unref(); | |
| sceneNode = NULL; | |
| } | |
| SoCamera * camera = NULL; | |
| SoSeparator * superscene = NULL; | |
| bool viewall = false; | |
| if (node) { | |
| sceneNode = node; | |
| sceneNode->ref(); | |
| superscene = new SoSeparator; | |
| superscene->addChild(headlight); | |
| // if the scene does not contain a camera, add one | |
| if (!(camera = searchForCamera(node))) { | |
| camera = new SoOrthographicCamera; | |
| superscene->addChild(camera); | |
| viewall = true; | |
| } | |
| superscene->addChild(node); | |
| } | |
| soeventmanager->setCamera(camera); | |
| sorendermanager->setCamera(camera); | |
| soeventmanager->setSceneGraph(superscene); | |
| sorendermanager->setSceneGraph(superscene); | |
| if (viewall) { | |
| this->viewAll(); | |
| } | |
| if (superscene) { | |
| superscene->touch(); | |
| } | |
| } | |
| SoRenderManager * | |
| GraphicsScene::getSoRenderManager(void) const | |
| { | |
| return sorendermanager; | |
| } | |
| SoEventManager * | |
| GraphicsScene::getSoEventManager(void) const | |
| { | |
| return soeventmanager; | |
| } | |
| void GraphicsScene::onSceneRectChanged(const QRectF & rect) | |
| { | |
| SbViewportRegion vp(rect.width(), rect.height()); | |
| sorendermanager->setViewportRegion(vp); | |
| soeventmanager->setViewportRegion(vp); | |
| } | |
| void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) | |
| { | |
| if (painter->paintEngine()->type() != QPaintEngine::OpenGL && painter->paintEngine()->type() != QPaintEngine::OpenGL2) { | |
| qWarning("GraphicsScene: drawBackground needs a QGLWidget to be set as viewport on the graphics view"); | |
| return; | |
| } | |
| const int delta = m_time.elapsed() - m_lastTime; | |
| m_lastTime += delta; | |
| sorendermanager->render(true/*PRIVATE(this)->clearwindow*/, | |
| false/*PRIVATE(this)->clearzbuffer*/); | |
| painter->save(); | |
| painter->fillRect(40,40,40,60,Qt::lightGray); | |
| painter->drawText(50,50, QStringLiteral("Done with QPainter")); | |
| painter->restore(); | |
| QTimer::singleShot(20, this, SLOT(update())); | |
| } | |
| void GraphicsScene::setBackgroundColor(const QColor& color) | |
| { | |
| if (color.isValid()) { | |
| m_backgroundColor = color; | |
| update(); | |
| SbColor4f bgcolor(SbClamp(color.red() / 255.0, 0.0, 1.0), | |
| SbClamp(color.green() / 255.0, 0.0, 1.0), | |
| SbClamp(color.blue() / 255.0, 0.0, 1.0), | |
| SbClamp(color.alpha() / 255.0, 0.0, 1.0)); | |
| sorendermanager->setBackgroundColor(bgcolor); | |
| sorendermanager->scheduleRedraw(); | |
| } | |
| } | |
| void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) | |
| { | |
| QGraphicsScene::mouseMoveEvent(event); | |
| if (event->isAccepted()) | |
| return; | |
| if (event->buttons() & Qt::LeftButton) { | |
| event->accept(); | |
| update(); | |
| } | |
| } | |
| void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) | |
| { | |
| QGraphicsScene::mousePressEvent(event); | |
| if (event->isAccepted()) | |
| return; | |
| m_mouseEventTime = m_time.elapsed(); | |
| event->accept(); | |
| } | |
| void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) | |
| { | |
| QGraphicsScene::mouseReleaseEvent(event); | |
| if (event->isAccepted()) | |
| return; | |
| event->accept(); | |
| update(); | |
| } | |
| void GraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *event) | |
| { | |
| QGraphicsScene::wheelEvent(event); | |
| if (event->isAccepted()) | |
| return; | |
| event->accept(); | |
| update(); | |
| } | |
| // ---------------------------------------------------------------------------- | |
| GraphicsView3D::GraphicsView3D(Gui::Document* doc, QWidget* parent) | |
| : Gui::MDIView(doc, parent), m_scene(new GraphicsScene()), m_view(new GraphicsView) | |
| { | |
| m_view->installEventFilter(m_scene->getEventFilter()); | |
| m_view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); | |
| m_view->setScene(m_scene); | |
| m_scene->setNavigationModeFile(QUrl(QStringLiteral("coin:///scxml/navigation/examiner.xml"))); | |
| std::vector<ViewProvider*> v = doc->getViewProvidersOfType(ViewProvider::getClassTypeId()); | |
| SoSeparator* root = new SoSeparator(); | |
| for (std::vector<ViewProvider*>::iterator it = v.begin(); it != v.end(); ++it) | |
| root->addChild((*it)->getRoot()); | |
| m_scene->setSceneGraph(root); | |
| setCentralWidget(m_view); | |
| m_scene->viewAll(); | |
| // attach parameter Observer | |
| hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); | |
| hGrp->Attach(this); | |
| OnChange(*hGrp,"BackgroundColor"); | |
| } | |
| GraphicsView3D::~GraphicsView3D() | |
| { | |
| hGrp->Detach(this); | |
| delete m_view; | |
| delete m_scene; | |
| } | |
| void GraphicsView3D::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason) | |
| { | |
| const ParameterGrp& rGrp = static_cast<ParameterGrp&>(rCaller); | |
| if (strcmp(Reason, "BackgroundColor") == 0) | |
| { | |
| unsigned long col1 = rGrp.GetUnsigned("BackgroundColor",3940932863UL); | |
| float r1,g1,b1; | |
| r1 = ((col1 >> 24) & 0xff) / 255.0; g1 = ((col1 >> 16) & 0xff) / 255.0; b1 = ((col1 >> 8) & 0xff) / 255.0; | |
| m_scene->setBackgroundColor(QColor::fromRgbF(r1, g1, b1)); | |
| } | |
| } | |