• Shawn Rutledge's avatar
    FileDialog: several logic corrections in handling the enter key · 67609e43
    Shawn Rutledge authored
    
    A "save as" dialog does not need to validate existence of the file.
    When the user presses enter in the text field at the top, and the
    text field contains a path to a directory, it usually means enter
    the directory; but if the dialog is for choosing a directory, then
    pressing enter will mean enter the directory if the dialog is not already
    viewing that one, or else accept the current directory as the choice if
    the table view does not have focus on some other row.
    When the user presses enter in table view, go down into a directory
    only if a directory is selected; otherwise accept the current selection.
    When the user clicks a row in the table, copy the path of that row
    into the text field so that it is possible to edit the path before
    pressing Enter or OK (behavior similar to a native dialog that has
    an editable path, such as GTK).
    
    Task-number: QTBUG-39435
    Change-Id: Ibd5e988624c5b1072a12239d681cbdc812e0a697
    Reviewed-by: default avatarLiang Qi <liang.qi@theqtcompany.com>
    67609e43
canvas3d.cpp 24.95 KiB
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCanvas3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
** $QT_END_LICENSE$
****************************************************************************/
#include "canvas3d_p.h"
#include "context3d_p.h"
#include "canvas3dcommon_p.h"
#include "canvasrendernode_p.h"
#include "teximage3d_p.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlContext>
#include <QtCore/QElapsedTimer>
QT_BEGIN_NAMESPACE
QT_CANVAS3D_BEGIN_NAMESPACE
/*!
 * \qmltype Canvas3D
 * \since QtCanvas3D 1.0
 * \ingroup qtcanvas3d-qml-types
 * \brief Canvas that provides a 3D rendering context.
 * The Canvas3D is a QML element that, when placed in your Qt Quick 2 scene, allows you to
 * get a 3D rendering context and call 3D rendering API calls through that context object.
 * Use of the rendering API requires knowledge of OpenGL like rendering APIs.
 * There are two functions that are called by the Canvas3D implementation:
 * \list
 * \li initGL is emitted before the first frame is rendered, and usually during that you get
 * the 3D context and initialize resources to be used later on during the rendering cycle.
 * \li renderGL is emitted for each frame to be rendered, and usually during that you
 * submit 3D rendering calls to draw whatever 3D content you want to be displayed.
 * \endlist
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
* * \sa Context3D, {QML Canvas 3D QML Types} */ /*! * \internal */ Canvas::Canvas(QQuickItem *parent): QQuickItem(parent), m_renderNodeReady(false), m_logAllCalls(false), m_logAllErrors(false), m_mainThread(QThread::currentThread()), m_contextThread(0), m_context3D(0), m_isFirstRender(true), m_glContext(0), m_glContextQt(0), m_contextWindow(0), m_fps(0), m_maxSamples(0), m_devicePixelRatio(1.0f), m_isOpenGLES2(false), m_isSoftwareRendered(false), m_isContextAttribsSet(false), m_antialiasFbo(0), m_renderFbo(0), m_displayFbo(0), m_offscreenSurface(0) { if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__; connect(this, &QQuickItem::windowChanged, this, &Canvas::handleWindowChanged); connect(this, &Canvas::needRender, this, &Canvas::renderNext, Qt::QueuedConnection); setAntialiasing(false); // Set contents to false in case we are in qml designer to make component look nice m_runningInDesigner = QGuiApplication::applicationDisplayName() == "Qml2Puppet"; setFlag(ItemHasContents, !m_runningInDesigner); #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) m_isSoftwareRendered = true; #endif } /*! * \qmlsignal void Canvas::initGL() * Emitted once when Canvas3D is ready and OpenGL state initialization can be done by the client. */ /*! * \qmlsignal void Canvas::renderGL() * Emitted each time a new frame should be drawn to Canvas3D. Driven by the QML scenegraph loop. */ /*! * \internal */ Canvas::~Canvas() { if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__; shutDown(); } /*! * \internal */ void Canvas::shutDown() { if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
if (!m_glContext) return; disconnect(m_contextWindow, 0, this, 0); disconnect(this, 0, this, 0); m_glContext->makeCurrent(m_offscreenSurface); delete m_renderFbo; delete m_displayFbo; delete m_antialiasFbo; delete m_context3D; m_glContext->doneCurrent(); if (m_logAllCalls) qDebug() << m_contextThread << m_mainThread; if (m_contextThread && m_contextThread != m_mainThread) { m_glContext->deleteLater(); m_offscreenSurface->deleteLater(); } else { delete m_glContext; delete m_offscreenSurface; } m_glContext = 0; m_glContextQt = 0; } /*! * \qmlproperty bool Canvas3D::logAllCalls * Specifies if all Canvas3D method calls (including internal ones) are logged to the console. * Defaults to \c{false}. */ void Canvas::setLogAllCalls(bool logCalls) { if (m_logAllCalls != logCalls) { m_logAllCalls = logCalls; emit logAllCallsChanged(logCalls); } } bool Canvas::logAllCalls() const { return m_logAllCalls; } /*! * \qmlproperty bool Canvas3D::logAllErrors * Specifies if all GL errors are checked and logged to the console. Defaults to \c{false}. * WARNING! Enabling this flag will have severe negative performance impact due to use of * \c{glGetError()} after each function call, so only enable it while debugging an issue during * development. */ void Canvas::setLogAllErrors(bool logErrors) { if (m_logAllErrors != logErrors) { m_logAllErrors = logErrors; emit logAllErrorsChanged(logErrors); } } bool Canvas::logAllErrors() const { return m_logAllErrors; } /*! * \qmlsignal Canvas3D::needRender() * This signal, if emitted, causes a re-rendering cycle to happen. Usually this is needed * if a value that affects the look of the 3D scene has changed, but no other mechanism * triggers the re-render cycle.
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
*/ /*! * \qmlsignal Canvas3D::textureReady(int id, size size, float devicePixelRatio) * Emitted when a new texture is ready to inform the render node. */ /*! * \qmlproperty float Canvas3D::devicePixelRatio * Specifies the ratio between logical pixels (used by the Qt Quick) and actual physical * on-screen pixels (used by the 3D rendering). */ float Canvas::devicePixelRatio() { if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__; QQuickWindow *win = window(); if (win) return win->devicePixelRatio(); else return 1.0f; } /*! * \qmlmethod Context3D Canvas3D::getContext(string type) * Returns the 3D rendering context that allows 3D rendering calls to be made. * The \a type parameter is ignored for now, but a string is expected to be given. */ /*! * \internal */ QJSValue Canvas::getContext(const QString &type) { QVariantMap map; return getContext(type, map); } /*! * \qmlmethod Context3D Canvas3D::getContext(string type, ContextAttributes options) * Returns the 3D rendering context that allows 3D rendering calls to be made. * The \a type parameter is ignored for now, but a string is expected to be given. * The \a options parameter is only parsed when the first call to getContext() is * made and is ignored in subsequent calls if given. If the first call is made without * giving the \a options parameter, then the context and render target is initialized with * default configuration. * * \sa ContextAttributes, Context3D */ /*! * \internal */ QJSValue Canvas::getContext(const QString &type, const QVariantMap &options) { Q_UNUSED(type); if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "(" << type << ", " << options << ")"; if (!m_isContextAttribsSet) { // Accept passed attributes only from first call and ignore for subsequent calls m_isContextAttribsSet = true; m_contextAttribs.setFrom(options); if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Attribs:" << m_contextAttribs; // If we can't do antialiasing, ensure we don't even try to enable it if (m_maxSamples == 0 || m_isSoftwareRendered) m_contextAttribs.setAntialias(false);
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
// Reflect the fact that creation of stencil attachment // causes the creation of depth attachment as well if (m_contextAttribs.stencil()) m_contextAttribs.setDepth(true); // Ensure ignored attributes are left to their default state m_contextAttribs.setAlpha(false); m_contextAttribs.setPremultipliedAlpha(false); m_contextAttribs.setPreserveDrawingBuffer(false); m_contextAttribs.setPreferLowPowerToHighPerformance(false); m_contextAttribs.setFailIfMajorPerformanceCaveat(false); } if (!m_context3D) { // Create the context using current context attributes updateWindowParameters(); QOpenGLFramebufferObjectFormat format; QOpenGLFramebufferObjectFormat antialiasFboFormat; // Initialize the swap buffer chain if (m_contextAttribs.depth() && m_contextAttribs.stencil() && !m_contextAttribs.antialias()) format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); else if (m_contextAttribs.depth() && !m_contextAttribs.antialias()) format.setAttachment(QOpenGLFramebufferObject::Depth); else if (m_contextAttribs.stencil() && !m_contextAttribs.antialias()) format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); else format.setAttachment(QOpenGLFramebufferObject::NoAttachment); if (m_contextAttribs.antialias()) { antialiasFboFormat.setSamples(m_maxSamples); if (antialiasFboFormat.samples() != m_maxSamples) { qDebug() << "Failed to use " << m_maxSamples << " will use " << antialiasFboFormat.samples(); } if (m_contextAttribs.depth() && m_contextAttribs.stencil()) antialiasFboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); else if (m_contextAttribs.depth()) antialiasFboFormat.setAttachment(QOpenGLFramebufferObject::Depth); else antialiasFboFormat.setAttachment(QOpenGLFramebufferObject::NoAttachment); } QSurfaceFormat surfaceFormat = m_glContextQt->format(); if (!m_isOpenGLES2) { surfaceFormat.setSwapBehavior(QSurfaceFormat::SingleBuffer); surfaceFormat.setSwapInterval(0); } if (m_contextAttribs.alpha()) surfaceFormat.setAlphaBufferSize(8); else surfaceFormat.setAlphaBufferSize(0); if (m_contextAttribs.depth()) surfaceFormat.setDepthBufferSize(24); if (m_contextAttribs.stencil()) surfaceFormat.setStencilBufferSize(8); else surfaceFormat.setStencilBufferSize(-1); if (m_contextAttribs.antialias()) surfaceFormat.setSamples(antialiasFboFormat.samples()); if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Creating QOpenGLContext with surfaceFormat :"