forked from qt-creator/qt-creator
Merge "Merge remote-tracking branch 'origin/4.11'"
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -55,6 +55,7 @@ CMakeLists.txt.user*
|
||||
/src/plugins/**/*.json
|
||||
/src/plugins/coreplugin/ide_version.h
|
||||
/src/libs/qt-breakpad/bin
|
||||
/.cmake/
|
||||
app_version.h
|
||||
phony.c
|
||||
|
||||
|
@@ -491,16 +491,18 @@ function(add_qtc_library name)
|
||||
|
||||
install(TARGETS ${name}
|
||||
EXPORT ${IDE_CASED_ID}
|
||||
RUNTIME DESTINATION "${_DESTINATION}"
|
||||
RUNTIME DESTINATION "${_DESTINATION}" OPTIONAL
|
||||
LIBRARY
|
||||
DESTINATION "${IDE_LIBRARY_PATH}"
|
||||
${NAMELINK_OPTION}
|
||||
OPTIONAL
|
||||
OBJECTS
|
||||
DESTINATION "${IDE_LIBRARY_PATH}"
|
||||
COMPONENT Devel EXCLUDE_FROM_ALL
|
||||
ARCHIVE
|
||||
DESTINATION "${IDE_LIBRARY_PATH}"
|
||||
COMPONENT Devel EXCLUDE_FROM_ALL
|
||||
OPTIONAL
|
||||
)
|
||||
|
||||
if (NAMELINK_OPTION)
|
||||
@@ -509,6 +511,7 @@ function(add_qtc_library name)
|
||||
DESTINATION "${IDE_LIBRARY_PATH}"
|
||||
NAMELINK_ONLY
|
||||
COMPONENT Devel EXCLUDE_FROM_ALL
|
||||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -703,11 +706,12 @@ function(add_qtc_plugin target_name)
|
||||
if (NOT _arg_SKIP_INSTALL)
|
||||
install(TARGETS ${target_name}
|
||||
EXPORT ${IDE_CASED_ID}
|
||||
RUNTIME DESTINATION "${plugin_dir}"
|
||||
LIBRARY DESTINATION "${plugin_dir}"
|
||||
RUNTIME DESTINATION "${plugin_dir}" OPTIONAL
|
||||
LIBRARY DESTINATION "${plugin_dir}" OPTIONAL
|
||||
ARCHIVE
|
||||
DESTINATION "${plugin_dir}"
|
||||
COMPONENT Devel EXCLUDE_FROM_ALL
|
||||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -857,7 +861,7 @@ function(add_qtc_executable name)
|
||||
enable_pch(${name})
|
||||
|
||||
if (NOT _arg_SKIP_INSTALL)
|
||||
install(TARGETS ${name} DESTINATION "${_DESTINATION}")
|
||||
install(TARGETS ${name} DESTINATION "${_DESTINATION}" OPTIONAL)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
@@ -61,10 +61,6 @@
|
||||
switch to the nfs-kernel-server, or create a symlink so that the
|
||||
settings are stored locally.
|
||||
|
||||
\li Qt 4.7.4 is known to contain a bug exposed by g++ 4.6 which triggers
|
||||
a crash in \QC. For more information, see
|
||||
\l{https://bugreports.qt.io/browse/QTBUG-21265}{QTBUG-21265}
|
||||
|
||||
\li The Okteta KDE custom widget plugin might be installed as part of
|
||||
some Linux distributions. It can cause Qt Designer to crash. For
|
||||
more information, see:
|
||||
|
@@ -111,7 +111,6 @@
|
||||
\li \l {Editing PathView Properties}
|
||||
\li \l {Browsing ISO 7000 Icons}
|
||||
\li \l {Qt Quick UI Forms}
|
||||
\li \l {Exporting Designs from Graphics Software}
|
||||
\li \l {Using QML Modules with Plugins}
|
||||
\li \l {Converting UI Projects to Applications}
|
||||
\endlist
|
||||
|
@@ -157,12 +157,6 @@
|
||||
QML language and you can edit them in the Design mode.
|
||||
|
||||
\if defined(qtcreator)
|
||||
\li \l {Exporting Designs from Graphics Software}
|
||||
|
||||
You can export designs from graphics software, such as Adobe
|
||||
Photoshop and GIMP, to QML files. You can then edit QML files in
|
||||
\QC.
|
||||
|
||||
\li \l {Using QML Modules with Plugins}
|
||||
|
||||
QML modules may use plugins to expose components defined in C++ to
|
||||
|
@@ -1,171 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
**
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// **********************************************************************
|
||||
// NOTE: the sections are not ordered by their logical order to avoid
|
||||
// reshuffling the file each time the index order changes (i.e., often).
|
||||
// Run the fixnavi.pl script to adjust the links to the index order.
|
||||
// **********************************************************************
|
||||
|
||||
/*!
|
||||
|
||||
\contentspage index.html
|
||||
\previouspage creator-quick-ui-forms.html
|
||||
\page quick-export-to-qml.html
|
||||
\nextpage creator-qml-modules-with-plugins.html
|
||||
|
||||
\title Exporting Designs from Graphics Software
|
||||
|
||||
You can export designs from graphics software, such as Adobe Photoshop and
|
||||
GIMP, to QML files.
|
||||
|
||||
\section1 Exporting from Adobe Photoshop to QML
|
||||
|
||||
You can use a QML Asset Exporter to export designs from Adobe Photoshop
|
||||
to .ui.qml files. The QML Asset Exporter provides templates that are
|
||||
based on the \l{http://www.pngexpress.com}{PNG EXPRESS} plugin for
|
||||
Photoshop. They enable you to export PSD files to QML format, so that each
|
||||
PSD file is converted into an .ui.qml file.
|
||||
|
||||
The filename of the generated document is based on the name of the PSD file.
|
||||
Tagged image and text objects are exported with absolute positioning. Text
|
||||
objects are exported with font and alignment information.
|
||||
|
||||
For more information, see the
|
||||
\l {https://github.com/Pelagicore/QmlAssetExporter}{QML Asset Exporter}
|
||||
documentation.
|
||||
|
||||
\section1 Exporting from GIMP to QML
|
||||
|
||||
\image qml-export-gimp.png
|
||||
|
||||
Each scene is converted into a single QML file with an
|
||||
\l [QML]{Image} or a \l [QML]{Text} item for each layer and saved on the
|
||||
development PC. Each layer is exported as an item.
|
||||
|
||||
You can open the QML file in \QC for editing. By default, the export scripts
|
||||
generate Qt Quick 1 files. To edit the files in the Design mode, change the import
|
||||
statements in the export scripts to import Qt Quick 2. Or, you can change
|
||||
the import statement in each file after generating the files.
|
||||
|
||||
\section2 Conversion Rules
|
||||
|
||||
The following rules apply to the conversions:
|
||||
|
||||
\list
|
||||
|
||||
\li Layer names are used as item names. Spaces and hash marks (#) are
|
||||
replaced with underscore characters to create valid ids for the
|
||||
items.
|
||||
|
||||
\li Layer styles, such as drop shadows, are converted to images.
|
||||
|
||||
\li Offset, size, ordering and opacity are preserved.
|
||||
|
||||
\li Text layers are converted to \l [QML]{Text} items, unless you
|
||||
specify that they be converted to \l [QML]{Image} items.
|
||||
|
||||
\li Hidden layers can be exported, and their visibility is set to
|
||||
hidden.
|
||||
|
||||
\li PNG images are copied to the images subirectory.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Preparing Files for Conversion
|
||||
|
||||
To create QML files that are easy to use, prepare the
|
||||
GIMP designs for exporting, as follows:
|
||||
|
||||
\list
|
||||
|
||||
\li To minimize the number of items, minimize the number of layers,
|
||||
because each layer or is
|
||||
exported as a \l [QML]{Text} or \l [QML]{Image} item.
|
||||
|
||||
\li To determine that some layers are not exported, hide them, and
|
||||
deselect the \uicontrol {Export hidden} check box during exporting.
|
||||
|
||||
\li To make it easier to find the layers after
|
||||
exporting them, use descriptive names for them.
|
||||
|
||||
\li To make sure that image dimensions are preserved during export,
|
||||
create at least one fully filled layer (which can be hidden), such
|
||||
as a background layer. If the export script does not find a fully
|
||||
filled layer, it resizes all images to the size of the canvas.
|
||||
|
||||
\li To prevent errors during export, make sure that the layers are not
|
||||
locked. Locked layers cannot be exported.
|
||||
|
||||
\li To avoid unexpected results, do not use Blending Mode effects. They
|
||||
are not exported.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Running the Export Script
|
||||
|
||||
The script has been tested to work on GIMP 2. You can download GIMP 2 from
|
||||
\l{http://www.gimp.org/downloads/}{GIMP Downloads}.
|
||||
|
||||
\list 1
|
||||
|
||||
\li Clone the repository that contains the export script,
|
||||
\e qmlexporter.py, from
|
||||
\l{https://codereview.qt-project.org/#/admin/projects/qt-labs/gimp-qmlexporter}
|
||||
{Qt Code Review}.
|
||||
|
||||
\note Read the INSTALL.txt in the repository for latest information
|
||||
about the script.
|
||||
|
||||
\li Copy the export script to the plug-ins directory in the GIMP
|
||||
installation directory.
|
||||
|
||||
\li Check the properties of the file to make sure that it is executable.
|
||||
|
||||
On Linux, run the following command: \c {chmod u+rx}
|
||||
|
||||
\li To generate QML files that you can edit in the Design mode, edit the
|
||||
import statement in \e qmlexporter.py. For example:
|
||||
|
||||
\code
|
||||
f.write('import QtQuick 2.5\n')
|
||||
\endcode
|
||||
|
||||
\li Restart GIMP to have the export command added to the \uicontrol File menu.
|
||||
|
||||
\li Choose \uicontrol {File > Export to QML} to export the design to a QML
|
||||
file.
|
||||
|
||||
\li In the \uicontrol {Export Layers to a QML Document} dialog, enter a name
|
||||
and location for the QML file, and click \uicontrol Export.
|
||||
|
||||
\endlist
|
||||
|
||||
The QML file is saved to the location that you specified. In \QC, choose
|
||||
\uicontrol {File > Open File or Project} to open the QML file.
|
||||
|
||||
\note Existing files are replaced without warning.
|
||||
|
||||
*/
|
@@ -31,7 +31,7 @@
|
||||
|
||||
/*!
|
||||
\contentspage index.html
|
||||
\previouspage quick-export-to-qml.html
|
||||
\previouspage creator-quick-ui-forms.html
|
||||
\page creator-qml-modules-with-plugins.html
|
||||
\nextpage quick-converting-ui-projects.html
|
||||
|
||||
|
@@ -25,7 +25,7 @@
|
||||
|
||||
/*!
|
||||
\contentspage index.html
|
||||
\previouspage qmldesigner-pathview-editor.html
|
||||
\previouspage quick-states.html
|
||||
\page qmldesigner-connections.html
|
||||
\nextpage quick-signals.html
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
/*!
|
||||
\contentspage {Qt Creator}
|
||||
\if defined(qtdesignstudio)
|
||||
\previouspage creator-quick-ui-forms.html
|
||||
\previouspage studio-3d-camera.html
|
||||
\else
|
||||
\previouspage creator-building-running.html
|
||||
\endif
|
||||
|
@@ -26,15 +26,13 @@
|
||||
/*!
|
||||
\contentspage index.html
|
||||
\page qmldesigner-pathview-editor.html
|
||||
\if defined(qtdesignstudio)
|
||||
\previouspage studio-fonts.html
|
||||
\nextpage creator-quick-ui-forms.html
|
||||
\else
|
||||
\previouspage quick-states.html
|
||||
\if defined(qtdesignstudio)
|
||||
\nextpage studio-3d.html
|
||||
\else
|
||||
\nextpage qtquick-iso-icon-browser.html
|
||||
\endif
|
||||
|
||||
|
||||
\title Editing PathView Properties
|
||||
|
||||
A \l{PathView}{Path View} lays out data provided by data models on a
|
||||
|
@@ -27,7 +27,11 @@
|
||||
\contentspage {Qt Creator Manual}
|
||||
\page qtquick-properties.html
|
||||
\previouspage qtquick-navigator.html
|
||||
\if defined(qtdesignstudio)
|
||||
\nextpage studio-fonts.html
|
||||
\else
|
||||
\nextpage studio-timeline.html
|
||||
\endif
|
||||
|
||||
\title Specifying Item Properties
|
||||
|
||||
|
@@ -28,11 +28,10 @@
|
||||
\page quick-states.html
|
||||
\if defined(qtdesignstudio)
|
||||
\previouspage quick-property-bindings.html
|
||||
\nextpage studio-fonts.html
|
||||
\else
|
||||
\previouspage quick-connections-backend.html
|
||||
\nextpage qmldesigner-pathview-editor.html
|
||||
\endif
|
||||
\nextpage qmldesigner-pathview-editor.html
|
||||
|
||||
\title Adding States
|
||||
|
||||
|
@@ -25,7 +25,11 @@
|
||||
|
||||
/*!
|
||||
\contentspage {Qt Design Studio Manual}
|
||||
\if defined(qtdesignstudio)
|
||||
\previouspage studio-adding-dynamics.html
|
||||
\else
|
||||
\previouspage qtquick-properties.html
|
||||
\endif
|
||||
\page studio-timeline.html
|
||||
\nextpage qmldesigner-connections.html
|
||||
|
||||
|
@@ -38,7 +38,7 @@
|
||||
\nextpage creator-live-preview.html
|
||||
\else
|
||||
\previouspage qtquick-iso-icon-browser.html
|
||||
\nextpage quick-export-to-qml.html
|
||||
\nextpage creator-qml-modules-with-plugins.html
|
||||
\endif
|
||||
|
||||
\title Qt Quick UI Forms
|
||||
|
@@ -144,7 +144,7 @@ def kindName(d, value):
|
||||
e = value.integer()
|
||||
if e:
|
||||
kindType = d.lookupType("CPlusPlus::Kind")
|
||||
return kindType.typeData().enumDisplay(e, value.address())[11:]
|
||||
return kindType.typeData().enumDisplay(e, value.address(), '%d')[11:]
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "change3dviewcommand.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
Change3DViewCommand::Change3DViewCommand() = default;
|
||||
|
||||
Change3DViewCommand::Change3DViewCommand(const QVector<InformationContainer> &informationVector)
|
||||
: m_informationVector(informationVector)
|
||||
{
|
||||
}
|
||||
|
||||
QVector<InformationContainer> Change3DViewCommand::informationVector() const
|
||||
{
|
||||
return m_informationVector;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const Change3DViewCommand &command)
|
||||
{
|
||||
out << command.informationVector();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &in, Change3DViewCommand &command)
|
||||
{
|
||||
in >> command.m_informationVector;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
QDebug operator <<(QDebug debug, const Change3DViewCommand &command)
|
||||
{
|
||||
return debug.nospace() << "Change3DViewCommand(auxiliaryChanges: " << command.m_informationVector << ")";
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
57
share/qtcreator/qml/qmlpuppet/commands/change3dviewcommand.h
Normal file
57
share/qtcreator/qml/qmlpuppet/commands/change3dviewcommand.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QVector>
|
||||
|
||||
#include "informationcontainer.h"
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class Change3DViewCommand
|
||||
{
|
||||
friend QDataStream &operator>>(QDataStream &in, Change3DViewCommand &command);
|
||||
friend QDebug operator <<(QDebug debug, const Change3DViewCommand &command);
|
||||
|
||||
public:
|
||||
Change3DViewCommand();
|
||||
explicit Change3DViewCommand(const QVector<InformationContainer> &auxiliaryChangeVector);
|
||||
|
||||
QVector<InformationContainer> informationVector() const;
|
||||
|
||||
private:
|
||||
QVector<InformationContainer> m_informationVector;
|
||||
};
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const Change3DViewCommand &command);
|
||||
QDataStream &operator>>(QDataStream &in, Change3DViewCommand &command);
|
||||
|
||||
QDebug operator <<(QDebug debug, const Change3DViewCommand &command);
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
Q_DECLARE_METATYPE(QmlDesigner::Change3DViewCommand)
|
@@ -28,6 +28,7 @@ HEADERS += $$PWD/removesharedmemorycommand.h
|
||||
HEADERS += $$PWD/puppetalivecommand.h
|
||||
HEADERS += $$PWD/changeselectioncommand.h
|
||||
HEADERS += $$PWD/drop3dlibraryitemcommand.h
|
||||
HEADERS += $$PWD/change3dviewcommand.h
|
||||
|
||||
SOURCES += $$PWD/synchronizecommand.cpp
|
||||
SOURCES += $$PWD/debugoutputcommand.cpp
|
||||
@@ -57,3 +58,4 @@ SOURCES += $$PWD/removesharedmemorycommand.cpp
|
||||
SOURCES += $$PWD/puppetalivecommand.cpp
|
||||
SOURCES += $$PWD/changeselectioncommand.cpp
|
||||
SOURCES += $$PWD/drop3dlibraryitemcommand.cpp
|
||||
SOURCES += $$PWD/change3dviewcommand.cpp
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include "instancecontainer.h"
|
||||
#include "createinstancescommand.h"
|
||||
#include "createscenecommand.h"
|
||||
#include "change3dviewcommand.h"
|
||||
#include "changevaluescommand.h"
|
||||
#include "changebindingscommand.h"
|
||||
#include "changeauxiliarycommand.h"
|
||||
@@ -360,6 +361,11 @@ void NodeInstanceClientProxy::createScene(const CreateSceneCommand &command)
|
||||
nodeInstanceServer()->createScene(command);
|
||||
}
|
||||
|
||||
void NodeInstanceClientProxy::change3DView(const Change3DViewCommand &command)
|
||||
{
|
||||
nodeInstanceServer()->change3DView(command);
|
||||
}
|
||||
|
||||
void NodeInstanceClientProxy::clearScene(const ClearSceneCommand &command)
|
||||
{
|
||||
nodeInstanceServer()->clearScene(command);
|
||||
@@ -447,6 +453,7 @@ void NodeInstanceClientProxy::changeSelection(const ChangeSelectionCommand &comm
|
||||
void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
|
||||
{
|
||||
static const int createInstancesCommandType = QMetaType::type("CreateInstancesCommand");
|
||||
static const int change3DViewCommandType = QMetaType::type("Change3DViewCommand");
|
||||
static const int changeFileUrlCommandType = QMetaType::type("ChangeFileUrlCommand");
|
||||
static const int createSceneCommandType = QMetaType::type("CreateSceneCommand");
|
||||
static const int clearSceneCommandType = QMetaType::type("ClearSceneCommand");
|
||||
@@ -470,6 +477,8 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
|
||||
|
||||
if (commandType == createInstancesCommandType)
|
||||
createInstances(command.value<CreateInstancesCommand>());
|
||||
else if (commandType == change3DViewCommandType)
|
||||
change3DView(command.value<Change3DViewCommand>());
|
||||
else if (commandType == changeFileUrlCommandType)
|
||||
changeFileUrl(command.value<ChangeFileUrlCommand>());
|
||||
else if (commandType == createSceneCommandType)
|
||||
|
@@ -45,6 +45,7 @@ class CreateSceneCommand;
|
||||
class CreateInstancesCommand;
|
||||
class ClearSceneCommand;
|
||||
class ReparentInstancesCommand;
|
||||
class Change3DViewCommand;
|
||||
class ChangeFileUrlCommand;
|
||||
class ChangeValuesCommand;
|
||||
class ChangeAuxiliaryCommand;
|
||||
@@ -95,6 +96,7 @@ protected:
|
||||
void changeFileUrl(const ChangeFileUrlCommand &command);
|
||||
void createScene(const CreateSceneCommand &command);
|
||||
void clearScene(const ClearSceneCommand &command);
|
||||
void change3DView(const Change3DViewCommand &command);
|
||||
void removeInstances(const RemoveInstancesCommand &command);
|
||||
void removeProperties(const RemovePropertiesCommand &command);
|
||||
void changePropertyBindings(const ChangeBindingsCommand &command);
|
||||
|
@@ -52,7 +52,11 @@ enum InformationName
|
||||
HasBindingForProperty,
|
||||
ContentTransform,
|
||||
ContentItemTransform,
|
||||
ContentItemBoundingRect
|
||||
ContentItemBoundingRect,
|
||||
MoveView,
|
||||
ShowView,
|
||||
ResizeView,
|
||||
HideView
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "instancecontainer.h"
|
||||
#include "createinstancescommand.h"
|
||||
#include "createscenecommand.h"
|
||||
#include "change3dviewcommand.h"
|
||||
#include "changevaluescommand.h"
|
||||
#include "changebindingscommand.h"
|
||||
#include "changeauxiliarycommand.h"
|
||||
@@ -90,6 +91,9 @@ void NodeInstanceServerInterface::registerCommands()
|
||||
qRegisterMetaType<CreateSceneCommand>("CreateSceneCommand");
|
||||
qRegisterMetaTypeStreamOperators<CreateSceneCommand>("CreateSceneCommand");
|
||||
|
||||
qRegisterMetaType<Change3DViewCommand>("Change3DViewCommand");
|
||||
qRegisterMetaTypeStreamOperators<Change3DViewCommand>("Change3DViewCommand");
|
||||
|
||||
qRegisterMetaType<ChangeBindingsCommand>("ChangeBindingsCommand");
|
||||
qRegisterMetaTypeStreamOperators<ChangeBindingsCommand>("ChangeBindingsCommand");
|
||||
|
||||
|
@@ -33,6 +33,7 @@ class PropertyAbstractContainer;
|
||||
class PropertyBindingContainer;
|
||||
class PropertyValueContainer;
|
||||
|
||||
class Change3DViewCommand;
|
||||
class ChangeFileUrlCommand;
|
||||
class ChangeValuesCommand;
|
||||
class ChangeBindingsCommand;
|
||||
@@ -66,6 +67,7 @@ public:
|
||||
virtual void changeFileUrl(const ChangeFileUrlCommand &command) = 0;
|
||||
virtual void createScene(const CreateSceneCommand &command) = 0;
|
||||
virtual void clearScene(const ClearSceneCommand &command) = 0;
|
||||
virtual void change3DView(const Change3DViewCommand &command) = 0;
|
||||
virtual void removeInstances(const RemoveInstancesCommand &command) = 0;
|
||||
virtual void removeProperties(const RemovePropertiesCommand &command) = 0;
|
||||
virtual void changePropertyBindings(const ChangeBindingsCommand &command) = 0;
|
||||
|
@@ -33,15 +33,18 @@ Node {
|
||||
property View3D view3D
|
||||
property Node target: parent
|
||||
property bool autoScale: true
|
||||
property Camera camera: view3D.camera
|
||||
|
||||
// Read-only
|
||||
property real relativeScale: 1
|
||||
|
||||
onSceneTransformChanged: updateScale()
|
||||
onAutoScaleChanged: updateScale()
|
||||
// Trigger delayed update on camera change to ensure camera values are correct
|
||||
onCameraChanged: _generalHelper.requestOverlayUpdate();
|
||||
|
||||
Connections {
|
||||
target: view3D.camera
|
||||
target: camera
|
||||
onSceneTransformChanged: updateScale()
|
||||
}
|
||||
|
||||
@@ -66,16 +69,22 @@ Node {
|
||||
// "anchor" distance. Map the two positions back to the target node, and measure the
|
||||
// distance between them now, in the 3D scene. The difference of the two distances,
|
||||
// view and scene, will tell us what the distance independent scale should be.
|
||||
var posInView1 = view3D.mapFrom3DScene(scenePosition);
|
||||
|
||||
// Need to recreate vector as we need to adjust it and we can't do that on reference of
|
||||
// scenePosition, which is read-only property
|
||||
var scenePos = Qt.vector3d(scenePosition.x, scenePosition.y, scenePosition.z);
|
||||
if (orientation === Node.RightHanded)
|
||||
scenePos.z = -scenePos.z;
|
||||
|
||||
var posInView1 = view3D.mapFrom3DScene(scenePos);
|
||||
var posInView2 = Qt.vector3d(posInView1.x + 100, posInView1.y, posInView1.z);
|
||||
|
||||
var rayPos1 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 0));
|
||||
var rayPos2 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 10));
|
||||
|
||||
var planeNormal = view3D.camera.forward;
|
||||
var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, scenePosition,
|
||||
planeNormal);
|
||||
relativeScale = scenePosition.minus(rayHitPos).length() / 100;
|
||||
var planeNormal = camera.forward;
|
||||
var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, scenePos, planeNormal);
|
||||
relativeScale = scenePos.minus(rayHitPos).length() / 100;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -120,8 +120,8 @@ View3D {
|
||||
onPressed: {
|
||||
pick(mouse);
|
||||
if (pickObj) {
|
||||
axisHelperView.editCameraCtrl.fitObject(axisHelperView.selectedNode,
|
||||
pickObj.cameraRotation);
|
||||
axisHelperView.editCameraCtrl.focusObject(axisHelperView.selectedNode,
|
||||
pickObj.cameraRotation, false);
|
||||
} else {
|
||||
mouse.accepted = false;
|
||||
}
|
||||
|
@@ -41,8 +41,7 @@ IconGizmo {
|
||||
materials: [
|
||||
DefaultMaterial {
|
||||
id: defaultMaterial
|
||||
emissiveColor: cameraGizmo.targetNode === cameraGizmo.selectedNode ? "#FF0000"
|
||||
: "#555555"
|
||||
emissiveColor: cameraGizmo.selected ? "#FF0000" : "#555555"
|
||||
lighting: DefaultMaterial.NoLighting
|
||||
cullingMode: Material.DisableCulling
|
||||
}
|
||||
|
@@ -29,7 +29,6 @@ import MouseArea3D 1.0
|
||||
|
||||
Model {
|
||||
id: rootModel
|
||||
rotationOrder: Node.XYZr
|
||||
|
||||
property View3D view3D
|
||||
property alias color: material.emissiveColor
|
||||
@@ -59,6 +58,8 @@ Model {
|
||||
|
||||
var maskedPosition = Qt.vector3d(scenePos.x, 0, 0);
|
||||
_pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition);
|
||||
if (targetNode.orientation === Node.RightHanded)
|
||||
_pointerPosPressed.z = -_pointerPosPressed.z;
|
||||
var sp = targetNode.scenePosition;
|
||||
_targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z);
|
||||
pressed(mouseArea);
|
||||
@@ -68,9 +69,9 @@ Model {
|
||||
{
|
||||
var maskedPosition = Qt.vector3d(scenePos.x, 0, 0);
|
||||
var scenePointerPos = mouseArea.mapPositionToScene(maskedPosition);
|
||||
return Qt.vector3d(scenePointerPos.x - _pointerPosPressed.x,
|
||||
scenePointerPos.y - _pointerPosPressed.y,
|
||||
scenePointerPos.z - _pointerPosPressed.z);
|
||||
if (targetNode.orientation === Node.RightHanded)
|
||||
scenePointerPos.z = -scenePointerPos.z;
|
||||
return scenePointerPos.minus(_pointerPosPressed);
|
||||
}
|
||||
|
||||
function handleDragged(mouseArea, scenePos)
|
||||
|
@@ -45,11 +45,11 @@ Item {
|
||||
property real _defaultCameraLookAtDistance: 0
|
||||
property Camera _prevCamera: null
|
||||
|
||||
function fitObject(targetObject, rotation)
|
||||
function focusObject(targetObject, rotation, updateZoom)
|
||||
{
|
||||
camera.rotation = rotation;
|
||||
var newLookAtAndZoom = _generalHelper.fitObjectToCamera(
|
||||
camera, _defaultCameraLookAtDistance, targetObject, view3d);
|
||||
var newLookAtAndZoom = _generalHelper.focusObjectToCamera(
|
||||
camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor, updateZoom);
|
||||
_lookAtPoint = newLookAtAndZoom.toVector3d();
|
||||
_zoomFactor = newLookAtAndZoom.w;
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick.Window 2.12
|
||||
import QtQuick3D 1.0
|
||||
import QtQuick.Controls 2.0
|
||||
import QtGraphicalEffects 1.0
|
||||
@@ -33,36 +33,95 @@ Window {
|
||||
id: viewWindow
|
||||
width: 1024
|
||||
height: 768
|
||||
visible: true
|
||||
visible: false
|
||||
title: "3D"
|
||||
flags: Qt.WindowStaysOnTopHint | Qt.Window | Qt.WindowTitleHint | Qt.WindowCloseButtonHint
|
||||
flags: Qt.Widget | Qt.SplashScreen
|
||||
|
||||
onActiveChanged: {
|
||||
if (viewWindow.active)
|
||||
cameraControl.forceActiveFocus()
|
||||
}
|
||||
|
||||
property alias scene: editView.importScene
|
||||
property alias showEditLight: btnEditViewLight.toggled
|
||||
property alias usePerspective: btnPerspective.toggled
|
||||
|
||||
property Node selectedNode: null
|
||||
property Node selectedNode: null // This is non-null only in single selection case
|
||||
property var selectedNodes: [] // All selected nodes
|
||||
|
||||
property var lightGizmos: []
|
||||
property var cameraGizmos: []
|
||||
property var selectionBoxes: []
|
||||
property rect viewPortRect: Qt.rect(0, 0, 1000, 1000)
|
||||
|
||||
signal objectClicked(var object)
|
||||
signal selectionChanged(var selectedNodes)
|
||||
signal commitObjectProperty(var object, var propName)
|
||||
signal changeObjectProperty(var object, var propName)
|
||||
|
||||
function selectObject(object) {
|
||||
selectedNode = object;
|
||||
function ensureSelectionBoxes(count) {
|
||||
var needMore = count - selectionBoxes.length
|
||||
if (needMore > 0) {
|
||||
var component = Qt.createComponent("SelectionBox.qml");
|
||||
if (component.status === Component.Ready) {
|
||||
for (var i = 0; i < needMore; ++i) {
|
||||
var geometryName = _generalHelper.generateUniqueName("SelectionBoxGeometry");
|
||||
var box = component.createObject(mainSceneHelpers, {"view3D": editView,
|
||||
"geometryName": geometryName});
|
||||
selectionBoxes[selectionBoxes.length] = box;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleObjectClicked(object) {
|
||||
function selectObjects(objects) {
|
||||
// Create selection boxes as necessary. One more box than is actually needed is created, so
|
||||
// that we always have a previously created box to use for new selection.
|
||||
// This fixes an occasional visual glitch when creating a new box.
|
||||
ensureSelectionBoxes(objects.length + 1)
|
||||
|
||||
var i;
|
||||
for (i = 0; i < objects.length; ++i)
|
||||
selectionBoxes[i].targetNode = objects[i];
|
||||
for (i = objects.length; i < selectionBoxes.length; ++i)
|
||||
selectionBoxes[i].targetNode = null;
|
||||
|
||||
selectedNodes = objects;
|
||||
if (objects.length === 0 || objects.length > 1)
|
||||
selectedNode = null;
|
||||
else
|
||||
selectedNode = objects[0];
|
||||
}
|
||||
|
||||
function handleObjectClicked(object, multi) {
|
||||
var theObject = object;
|
||||
if (btnSelectGroup.selected) {
|
||||
while (theObject && theObject.parent !== scene)
|
||||
theObject = theObject.parent;
|
||||
}
|
||||
selectObject(theObject);
|
||||
objectClicked(theObject);
|
||||
// Object selection logic:
|
||||
// Regular click: Clear any multiselection, single-selects the clicked object
|
||||
// Ctrl-click: No objects selected: Act as single select
|
||||
// One or more objects selected: Multiselect
|
||||
// Null object always clears entire selection
|
||||
var newSelection = [];
|
||||
if (object !== null) {
|
||||
if (multi && selectedNodes.length > 0) {
|
||||
var deselect = false;
|
||||
for (var i = 0; i < selectedNodes.length; ++i) {
|
||||
// Multiselecting already selected object clears that object from selection
|
||||
if (selectedNodes[i] !== object)
|
||||
newSelection[newSelection.length] = selectedNodes[i];
|
||||
else
|
||||
deselect = true;
|
||||
}
|
||||
if (!deselect)
|
||||
newSelection[newSelection.length] = object;
|
||||
} else {
|
||||
newSelection[0] = theObject;
|
||||
}
|
||||
}
|
||||
selectObjects(newSelection);
|
||||
selectionChanged(newSelection);
|
||||
}
|
||||
|
||||
function addLightGizmo(obj)
|
||||
@@ -71,10 +130,10 @@ Window {
|
||||
if (component.status === Component.Ready) {
|
||||
var gizmo = component.createObject(overlayScene,
|
||||
{"view3D": overlayView, "targetNode": obj,
|
||||
"selectedNode": selectedNode});
|
||||
"selectedNodes": selectedNodes});
|
||||
lightGizmos[lightGizmos.length] = gizmo;
|
||||
gizmo.clicked.connect(handleObjectClicked);
|
||||
gizmo.selectedNode = Qt.binding(function() {return selectedNode;});
|
||||
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,17 +145,20 @@ Window {
|
||||
var gizmo = component.createObject(
|
||||
overlayScene,
|
||||
{"view3D": overlayView, "targetNode": obj, "geometryName": geometryName,
|
||||
"viewPortRect": viewPortRect, "selectedNode": selectedNode});
|
||||
"viewPortRect": viewPortRect, "selectedNodes": selectedNodes});
|
||||
cameraGizmos[cameraGizmos.length] = gizmo;
|
||||
gizmo.clicked.connect(handleObjectClicked);
|
||||
gizmo.viewPortRect = Qt.binding(function() {return viewPortRect;});
|
||||
gizmo.selectedNode = Qt.binding(function() {return selectedNode;});
|
||||
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
||||
}
|
||||
}
|
||||
|
||||
// Work-around the fact that the projection matrix for the camera is not calculated until
|
||||
// the first frame is rendered, so any initial calls to mapFrom3DScene() will fail.
|
||||
Component.onCompleted: _generalHelper.requestOverlayUpdate();
|
||||
Component.onCompleted: {
|
||||
selectObjects([]);
|
||||
_generalHelper.requestOverlayUpdate();
|
||||
}
|
||||
|
||||
onWidthChanged: _generalHelper.requestOverlayUpdate();
|
||||
onHeightChanged: _generalHelper.requestOverlayUpdate();
|
||||
@@ -126,8 +188,6 @@ Window {
|
||||
scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
|
||||
highlightOnHover: true
|
||||
targetNode: viewWindow.selectedNode
|
||||
position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition
|
||||
: Qt.vector3d(0, 0, 0)
|
||||
globalOrientation: btnLocalGlobal.toggled
|
||||
visible: selectedNode && btnMove.selected
|
||||
view3D: overlayView
|
||||
@@ -141,8 +201,6 @@ Window {
|
||||
scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
|
||||
highlightOnHover: true
|
||||
targetNode: viewWindow.selectedNode
|
||||
position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition
|
||||
: Qt.vector3d(0, 0, 0)
|
||||
globalOrientation: false
|
||||
visible: selectedNode && btnScale.selected
|
||||
view3D: overlayView
|
||||
@@ -156,8 +214,6 @@ Window {
|
||||
scale: autoScale.getScale(Qt.vector3d(7, 7, 7))
|
||||
highlightOnHover: true
|
||||
targetNode: viewWindow.selectedNode
|
||||
position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition
|
||||
: Qt.vector3d(0, 0, 0)
|
||||
globalOrientation: btnLocalGlobal.toggled
|
||||
visible: selectedNode && btnRotate.selected
|
||||
view3D: overlayView
|
||||
@@ -170,6 +226,7 @@ Window {
|
||||
id: autoScale
|
||||
view3D: overlayView
|
||||
position: moveGizmo.scenePosition
|
||||
orientation: moveGizmo.orientation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,11 +239,15 @@ Window {
|
||||
GradientStop { position: 0.0; color: "#999999" }
|
||||
}
|
||||
|
||||
TapHandler { // check tapping/clicking an object in the scene
|
||||
onTapped: {
|
||||
var pickResult = editView.pick(eventPoint.scenePosition.x,
|
||||
eventPoint.scenePosition.y);
|
||||
handleObjectClicked(pickResult.objectHit);
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: {
|
||||
var pickResult = editView.pick(mouse.x, mouse.y);
|
||||
handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit),
|
||||
mouse.modifiers & Qt.ControlModifier);
|
||||
if (!pickResult.objectHit)
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,12 +269,6 @@ Window {
|
||||
step: 50
|
||||
}
|
||||
|
||||
SelectionBox {
|
||||
id: selectionBox
|
||||
view3D: editView
|
||||
targetNode: viewWindow.selectedNode
|
||||
}
|
||||
|
||||
PointLight {
|
||||
id: editLight
|
||||
visible: showEditLight
|
||||
@@ -382,8 +437,9 @@ Window {
|
||||
|
||||
onSelectedChanged: {
|
||||
if (selected) {
|
||||
var targetNode = viewWindow.selectedNode ? selectionBox.model : null;
|
||||
cameraControl.fitObject(targetNode, editView.camera.rotation);
|
||||
var targetNode = viewWindow.selectedNodes.length > 0
|
||||
? selectionBoxes[0].model : null;
|
||||
cameraControl.focusObject(targetNode, editView.camera.rotation, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,7 +452,7 @@ Window {
|
||||
width: 100
|
||||
height: width
|
||||
editCameraCtrl: cameraControl
|
||||
selectedNode : viewWindow.selectedNode ? selectionBox.model : null
|
||||
selectedNode : viewWindow.selectedNodes.length ? selectionBoxes[0].model : null
|
||||
}
|
||||
|
||||
Rectangle { // top controls bar
|
||||
|
@@ -33,13 +33,20 @@ Node {
|
||||
property View3D view3D
|
||||
property bool highlightOnHover: true
|
||||
property Node targetNode: null
|
||||
property Node selectedNode: null
|
||||
property var selectedNodes: null
|
||||
readonly property bool selected: {
|
||||
for (var i = 0; i < selectedNodes.length; ++i) {
|
||||
if (selectedNodes[i] === targetNode)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
property alias iconSource: iconImage.source
|
||||
property alias overlayColor: colorOverlay.color
|
||||
|
||||
signal positionCommit()
|
||||
signal clicked(Node node)
|
||||
signal clicked(Node node, bool multi)
|
||||
|
||||
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
|
||||
rotation: targetNode ? targetNode.sceneRotation : Qt.vector3d(0, 0, 0)
|
||||
@@ -60,21 +67,26 @@ Node {
|
||||
y: -height / 2
|
||||
color: "transparent"
|
||||
border.color: "#7777ff"
|
||||
border.width: iconGizmo.selectedNode !== iconGizmo.targetNode
|
||||
border.width: !iconGizmo.selected
|
||||
&& iconGizmo.highlightOnHover && iconMouseArea.containsMouse ? 2 : 0
|
||||
radius: 5
|
||||
opacity: iconGizmo.selectedNode === iconGizmo.targetNode ? 0.2 : 1
|
||||
opacity: iconGizmo.selected ? 0.2 : 1
|
||||
Image {
|
||||
id: iconImage
|
||||
fillMode: Image.Pad
|
||||
MouseArea {
|
||||
id: iconMouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: iconGizmo.clicked(iconGizmo.targetNode)
|
||||
hoverEnabled: iconGizmo.highlightOnHover
|
||||
&& iconGizmo.selectedNode !== iconGizmo.targetNode
|
||||
acceptedButtons: iconGizmo.selectedNode !== iconGizmo.targetNode
|
||||
? Qt.LeftButton : Qt.NoButton
|
||||
onPressed: {
|
||||
if (iconGizmo.selected && !(mouse.modifiers & Qt.ControlModifier)) {
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: iconGizmo.clicked(iconGizmo.targetNode,
|
||||
mouse.modifiers & Qt.ControlModifier)
|
||||
hoverEnabled: iconGizmo.highlightOnHover && !iconGizmo.selected
|
||||
acceptedButtons: Qt.LeftButton
|
||||
}
|
||||
}
|
||||
ColorOverlay {
|
||||
|
@@ -37,12 +37,17 @@ Node {
|
||||
readonly property bool dragging: arrowX.dragging || arrowY.dragging || arrowZ.dragging
|
||||
|| planeX.dragging || planeY.dragging || planeZ.dragging
|
||||
|| centerBall.dragging
|
||||
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
|
||||
orientation: targetNode ? targetNode.orientation : Node.LeftHanded
|
||||
|
||||
signal positionCommit()
|
||||
signal positionMove()
|
||||
|
||||
Node {
|
||||
rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation
|
||||
rotation: globalOrientation || !moveGizmo.targetNode ? Qt.vector3d(0, 0, 0)
|
||||
: moveGizmo.targetNode.sceneRotation
|
||||
rotationOrder: moveGizmo.targetNode ? moveGizmo.targetNode.rotationOrder : Node.YXZ
|
||||
orientation: moveGizmo.orientation
|
||||
|
||||
Arrow {
|
||||
id: arrowX
|
||||
|
@@ -55,9 +55,13 @@ Item {
|
||||
function updateOverlay()
|
||||
{
|
||||
var scenePos = targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0);
|
||||
// Need separate variable as scenePos is reference to read-only property
|
||||
var scenePosZ = scenePos.z
|
||||
if (targetNode && targetNode.orientation === Node.RightHanded)
|
||||
scenePosZ = -scenePosZ;
|
||||
var scenePosWithOffset = Qt.vector3d(scenePos.x + offset.x,
|
||||
scenePos.y + offset.y,
|
||||
scenePos.z + offset.z);
|
||||
scenePosZ + offset.z);
|
||||
var viewPos = targetView ? targetView.mapFrom3DScene(scenePosWithOffset)
|
||||
: Qt.vector3d(0, 0, 0);
|
||||
root.x = viewPos.x;
|
||||
|
@@ -63,6 +63,8 @@ Model {
|
||||
return;
|
||||
|
||||
_pointerPosPressed = mouseArea.mapPositionToScene(scenePos);
|
||||
if (targetNode.orientation === Node.RightHanded)
|
||||
_pointerPosPressed.z = -_pointerPosPressed.z;
|
||||
var sp = targetNode.scenePosition;
|
||||
_targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z);
|
||||
pressed(mouseArea);
|
||||
@@ -71,9 +73,9 @@ Model {
|
||||
function calcRelativeDistance(mouseArea, scenePos)
|
||||
{
|
||||
var scenePointerPos = mouseArea.mapPositionToScene(scenePos);
|
||||
return Qt.vector3d(scenePointerPos.x - _pointerPosPressed.x,
|
||||
scenePointerPos.y - _pointerPosPressed.y,
|
||||
scenePointerPos.z - _pointerPosPressed.z);
|
||||
if (targetNode.orientation === Node.RightHanded)
|
||||
scenePointerPos.z = -scenePointerPos.z;
|
||||
return scenePointerPos.minus(_pointerPosPressed);
|
||||
}
|
||||
|
||||
function handleDragged(mouseArea, scenePos)
|
||||
|
@@ -39,6 +39,9 @@ Node {
|
||||
property real currentAngle
|
||||
property point currentMousePos
|
||||
|
||||
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
|
||||
orientation: targetNode ? targetNode.orientation : Node.LeftHanded
|
||||
|
||||
signal rotateCommit()
|
||||
signal rotateChange()
|
||||
|
||||
@@ -69,7 +72,11 @@ Node {
|
||||
}
|
||||
|
||||
Node {
|
||||
rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation
|
||||
id: rotNode
|
||||
rotation: globalOrientation || !rotateGizmo.targetNode ? Qt.vector3d(0, 0, 0)
|
||||
: rotateGizmo.targetNode.sceneRotation
|
||||
rotationOrder: rotateGizmo.targetNode ? rotateGizmo.targetNode.rotationOrder : Node.YXZ
|
||||
orientation: rotateGizmo.orientation
|
||||
|
||||
RotateRing {
|
||||
id: rotRingX
|
||||
@@ -166,7 +173,14 @@ Node {
|
||||
if (!rotateGizmo.targetNode)
|
||||
return;
|
||||
|
||||
_targetPosOnScreen = view3D.mapFrom3DScene(rotateGizmo.targetNode.scenePosition);
|
||||
// Need to recreate vector as we need to adjust it and we can't do that on reference of
|
||||
// scenePosition, which is read-only property
|
||||
var scenePos = Qt.vector3d(rotateGizmo.targetNode.scenePosition.x,
|
||||
rotateGizmo.targetNode.scenePosition.y,
|
||||
rotateGizmo.targetNode.scenePosition.z);
|
||||
if (rotateGizmo.targetNode && rotateGizmo.targetNode.orientation === Node.RightHanded)
|
||||
scenePos.z = -scenePos.z
|
||||
_targetPosOnScreen = view3D.mapFrom3DScene(scenePos);
|
||||
_targetPosOnScreen.z = 0;
|
||||
_pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0);
|
||||
|
||||
|
@@ -77,7 +77,15 @@ Model {
|
||||
if (!targetNode)
|
||||
return;
|
||||
|
||||
_targetPosOnScreen = view3D.mapFrom3DScene(targetNode.scenePosition);
|
||||
// Need to recreate vector as we need to adjust it and we can't do that on reference of
|
||||
// scenePosition, which is read-only property
|
||||
var scenePos = Qt.vector3d(targetNode.scenePosition.x,
|
||||
targetNode.scenePosition.y,
|
||||
targetNode.scenePosition.z);
|
||||
if (targetNode && targetNode.orientation === Node.RightHanded)
|
||||
scenePos.z = -scenePos.z
|
||||
|
||||
_targetPosOnScreen = view3D.mapFrom3DScene(scenePos);
|
||||
_targetPosOnScreen.z = 0;
|
||||
_pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0);
|
||||
_trackBall = angle < 0.1;
|
||||
|
@@ -38,11 +38,16 @@ Node {
|
||||
|| planeX.dragging || planeY.dragging || planeZ.dragging
|
||||
|| centerMouseArea.dragging
|
||||
|
||||
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
|
||||
orientation: targetNode ? targetNode.orientation : Node.LeftHanded
|
||||
|
||||
signal scaleCommit()
|
||||
signal scaleChange()
|
||||
|
||||
Node {
|
||||
rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation
|
||||
rotationOrder: scaleGizmo.targetNode ? scaleGizmo.targetNode.rotationOrder : Node.YXZ
|
||||
orientation: scaleGizmo.orientation
|
||||
|
||||
ScaleRod {
|
||||
id: scaleRodX
|
||||
|
@@ -33,6 +33,7 @@ Node {
|
||||
property View3D view3D
|
||||
property Node targetNode: null
|
||||
property alias model: selectionBoxModel
|
||||
property alias geometryName: selectionBoxGeometry.name
|
||||
|
||||
SelectionBoxGeometry {
|
||||
id: selectionBoxGeometry
|
||||
|
@@ -139,8 +139,9 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de
|
||||
}
|
||||
|
||||
// Return value contains new lookAt point (xyz) and zoom factor (w)
|
||||
QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort)
|
||||
QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
|
||||
float oldZoom, bool updateZoom)
|
||||
{
|
||||
if (!camera)
|
||||
return QVector4D(0.f, 0.f, 0.f, 1.f);
|
||||
@@ -148,7 +149,8 @@ QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float default
|
||||
QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D();
|
||||
|
||||
// Get object bounds
|
||||
qreal maxExtent = 200.;
|
||||
const qreal defaultExtent = 200.;
|
||||
qreal maxExtent = defaultExtent;
|
||||
if (auto modelNode = qobject_cast<QQuick3DModel *>(targetObject)) {
|
||||
auto targetPriv = QQuick3DObjectPrivate::get(targetObject);
|
||||
if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) {
|
||||
@@ -172,6 +174,9 @@ QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float default
|
||||
maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z()));
|
||||
maxExtent *= maxScale;
|
||||
|
||||
if (maxExtent < 0.0001)
|
||||
maxExtent = defaultExtent;
|
||||
|
||||
// Adjust lookAt to look directly at the center of the object bounds
|
||||
lookAt = renderModel->globalTransform.map(center);
|
||||
lookAt.setZ(-lookAt.z()); // Render node transforms have inverted z
|
||||
@@ -189,11 +194,10 @@ QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float default
|
||||
|
||||
camera->setPosition(lookAt + newLookVector);
|
||||
|
||||
// Emprically determined algorithm for nice zoom
|
||||
float newZoomFactor = qBound(.0001f, float(maxExtent / 700.), 10000.f);
|
||||
float newZoomFactor = updateZoom ? qBound(.0001f, float(maxExtent / 700.), 10000.f) : oldZoom;
|
||||
float cameraZoomFactor = zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false);
|
||||
|
||||
return QVector4D(lookAt,
|
||||
zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false));
|
||||
return QVector4D(lookAt, cameraZoomFactor);
|
||||
}
|
||||
|
||||
void GeneralHelper::delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
@@ -204,6 +208,20 @@ void GeneralHelper::delayedPropertySet(QObject *obj, int delay, const QString &p
|
||||
});
|
||||
}
|
||||
|
||||
QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode)
|
||||
{
|
||||
if (pickNode) {
|
||||
// Check if the picked node actually specifies another node as the pick target
|
||||
QVariant componentVar = pickNode->property("_pickTarget");
|
||||
if (componentVar.isValid()) {
|
||||
auto componentNode = componentVar.value<QQuick3DNode *>();
|
||||
if (componentNode)
|
||||
return componentNode;
|
||||
}
|
||||
}
|
||||
return pickNode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -62,10 +62,13 @@ public:
|
||||
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
|
||||
float defaultLookAtDistance, const QVector3D &lookAt,
|
||||
float zoomFactor, bool relative);
|
||||
Q_INVOKABLE QVector4D fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort);
|
||||
Q_INVOKABLE QVector4D focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
|
||||
float oldZoom, bool updateZoom = true);
|
||||
Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
const QVariant& value);
|
||||
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
|
||||
|
||||
|
||||
signals:
|
||||
void overlayUpdateNeeded();
|
||||
|
@@ -322,11 +322,11 @@ QVector3D MouseArea3D::getNewScale(QQuick3DNode *node, const QVector3D &startSca
|
||||
scaleVec *= magnitude;
|
||||
|
||||
// Zero axes on scale vector indicate directions we don't want scaling to affect
|
||||
if (qFuzzyIsNull(scaleVec.x()))
|
||||
if (scaleDirVector.x() < 0.0001f)
|
||||
scaleVec.setX(1.f);
|
||||
if (qFuzzyIsNull(scaleVec.y()))
|
||||
if (scaleDirVector.y() < 0.0001f)
|
||||
scaleVec.setY(1.f);
|
||||
if (qFuzzyIsNull(scaleVec.z()))
|
||||
if (scaleDirVector.z() < 0.0001f)
|
||||
scaleVec.setZ(1.f);
|
||||
scaleVec *= startScale;
|
||||
|
||||
@@ -344,11 +344,17 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
|
||||
QQuick3DNode *node, const QVector3D &pressPos, const QVector3D ¤tPos,
|
||||
const QVector3D &nodePos, qreal prevAngle, bool trackBall)
|
||||
{
|
||||
const QVector3D cameraToNodeDir = getCameraToNodeDir(node);
|
||||
// Get camera to node direction in node orientation
|
||||
QVector3D cameraToNodeDir = getCameraToNodeDir(node);
|
||||
if (trackBall) {
|
||||
// Only the distance in plane direction is relevant in trackball drag
|
||||
QVector3D dragDir = QVector3D::crossProduct(getNormal(), cameraToNodeDir).normalized();
|
||||
QVector3D screenDragDir = m_view3D->mapFrom3DScene(node->scenePosition() + dragDir);
|
||||
QVector3D scenePos = node->scenePosition();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded) {
|
||||
scenePos.setZ(-scenePos.z());
|
||||
dragDir = -dragDir;
|
||||
}
|
||||
QVector3D screenDragDir = m_view3D->mapFrom3DScene(scenePos + dragDir);
|
||||
screenDragDir.setZ(0);
|
||||
dragDir = (screenDragDir - nodePos).normalized();
|
||||
const QVector3D pressToCurrent = (currentPos - pressPos);
|
||||
@@ -361,7 +367,9 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
|
||||
qreal angle = qAcos(qreal(QVector3D::dotProduct(nodeToPress, nodeToCurrent)));
|
||||
|
||||
// Determine drag direction left/right
|
||||
const QVector3D dragNormal = QVector3D::crossProduct(nodeToPress, nodeToCurrent).normalized();
|
||||
QVector3D dragNormal = QVector3D::crossProduct(nodeToPress, nodeToCurrent).normalized();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded)
|
||||
dragNormal = -dragNormal;
|
||||
angle *= QVector3D::dotProduct(QVector3D(0.f, 0.f, 1.f), dragNormal) < 0 ? -1.0 : 1.0;
|
||||
|
||||
// Determine drag ring orientation relative to camera
|
||||
@@ -392,7 +400,10 @@ void QmlDesigner::Internal::MouseArea3D::applyRotationAngleToNode(
|
||||
{
|
||||
if (!qFuzzyIsNull(angle)) {
|
||||
node->setRotation(startRotation);
|
||||
node->rotate(qRadiansToDegrees(angle), getNormal(), QQuick3DNode::SceneSpace);
|
||||
QVector3D normal = getNormal();
|
||||
if (orientation() != node->orientation())
|
||||
normal.setZ(-normal.z());
|
||||
node->rotate(qRadiansToDegrees(angle), normal, QQuick3DNode::SceneSpace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,6 +418,10 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo
|
||||
const float *dataPtr(sceneTransform().data());
|
||||
QVector3D xAxis = QVector3D(-dataPtr[0], -dataPtr[1], -dataPtr[2]).normalized();
|
||||
QVector3D yAxis = QVector3D(-dataPtr[4], -dataPtr[5], -dataPtr[6]).normalized();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded) {
|
||||
xAxis = QVector3D(-xAxis.x(), -xAxis.y(), xAxis.z());
|
||||
yAxis = QVector3D(-yAxis.x(), -yAxis.y(), yAxis.z());
|
||||
}
|
||||
|
||||
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
|
||||
|
||||
@@ -596,11 +611,14 @@ QVector3D MouseArea3D::getCameraToNodeDir(QQuick3DNode *node) const
|
||||
{
|
||||
QVector3D dir;
|
||||
if (qobject_cast<QQuick3DOrthographicCamera *>(m_view3D->camera())) {
|
||||
dir = m_view3D->camera()->cameraNode()->getDirection();
|
||||
// Camera direction has x and y flipped
|
||||
dir = QVector3D(-dir.x(), -dir.y(), dir.z());
|
||||
dir = -m_view3D->camera()->cameraNode()->getDirection();
|
||||
dir.setZ(-dir.z());
|
||||
} else {
|
||||
dir = (node->scenePosition() - m_view3D->camera()->scenePosition()).normalized();
|
||||
QVector3D camPos = m_view3D->camera()->scenePosition();
|
||||
QVector3D nodePos = node->scenePosition();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded)
|
||||
nodePos.setZ(-nodePos.z());
|
||||
dir = (node->scenePosition() - camPos).normalized();
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
@@ -41,6 +41,11 @@
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
|
||||
static const float floatMin = std::numeric_limits<float>::lowest();
|
||||
static const float floatMax = std::numeric_limits<float>::max();
|
||||
static const QVector3D maxVec = QVector3D(floatMax, floatMax, floatMax);
|
||||
static const QVector3D minVec = QVector3D(floatMin, floatMin, floatMin);
|
||||
|
||||
SelectionBoxGeometry::SelectionBoxGeometry()
|
||||
: QQuick3DGeometry()
|
||||
{
|
||||
@@ -133,11 +138,8 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
|
||||
QByteArray vertexData;
|
||||
QByteArray indexData;
|
||||
|
||||
static const float floatMin = std::numeric_limits<float>::lowest();
|
||||
static const float floatMax = std::numeric_limits<float>::max();
|
||||
|
||||
QVector3D minBounds = QVector3D(floatMax, floatMax, floatMax);
|
||||
QVector3D maxBounds = QVector3D(floatMin, floatMin, floatMin);
|
||||
QVector3D minBounds = maxVec;
|
||||
QVector3D maxBounds = minVec;
|
||||
|
||||
if (m_targetNode) {
|
||||
auto rootPriv = QQuick3DObjectPrivate::get(m_rootNode);
|
||||
@@ -154,10 +156,20 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
|
||||
rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty);
|
||||
rootRN->calculateGlobalVariables();
|
||||
}
|
||||
getBounds(m_targetNode, vertexData, indexData, minBounds, maxBounds, QMatrix4x4());
|
||||
getBounds(m_targetNode, vertexData, indexData, minBounds, maxBounds);
|
||||
appendVertexData(QMatrix4x4(), vertexData, indexData, minBounds, maxBounds);
|
||||
|
||||
// Track changes in ancestors, as they can move node without affecting node properties
|
||||
auto parentNode = m_targetNode->parentNode();
|
||||
while (parentNode) {
|
||||
trackNodeChanges(parentNode);
|
||||
parentNode = parentNode->parentNode();
|
||||
}
|
||||
} else {
|
||||
// Fill some dummy data so geometry won't get rejected
|
||||
appendVertexData(vertexData, indexData, minBounds, maxBounds);
|
||||
minBounds = {};
|
||||
maxBounds = {};
|
||||
appendVertexData(QMatrix4x4(), vertexData, indexData, minBounds, maxBounds);
|
||||
}
|
||||
|
||||
geometry->addAttribute(QSSGRenderGeometry::Attribute::PositionSemantic, 0,
|
||||
@@ -182,62 +194,73 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
|
||||
return node;
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::getBounds(QQuick3DNode *node, QByteArray &vertexData,
|
||||
QByteArray &indexData, QVector3D &minBounds,
|
||||
QVector3D &maxBounds, const QMatrix4x4 &transform)
|
||||
void SelectionBoxGeometry::getBounds(
|
||||
QQuick3DNode *node, QByteArray &vertexData, QByteArray &indexData,
|
||||
QVector3D &minBounds, QVector3D &maxBounds)
|
||||
{
|
||||
QMatrix4x4 fullTransform;
|
||||
QMatrix4x4 localTransform;
|
||||
auto nodePriv = QQuick3DObjectPrivate::get(node);
|
||||
auto renderNode = static_cast<QSSGRenderNode *>(nodePriv->spatialNode);
|
||||
|
||||
// All transforms are relative to targetNode transform, so its local transform is ignored
|
||||
if (node != m_targetNode) {
|
||||
if (renderNode) {
|
||||
if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty))
|
||||
renderNode->calculateLocalTransform();
|
||||
fullTransform = transform * renderNode->localTransform;
|
||||
localTransform = renderNode->localTransform;
|
||||
}
|
||||
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::scaleChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::rotationChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::positionChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::pivotChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::orientationChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::rotationOrderChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
trackNodeChanges(node);
|
||||
}
|
||||
|
||||
QVector3D localMinBounds = maxVec;
|
||||
QVector3D localMaxBounds = minVec;
|
||||
|
||||
// Find bounds for children
|
||||
QVector<QVector3D> minBoundsVec;
|
||||
QVector<QVector3D> maxBoundsVec;
|
||||
|
||||
// Check for children
|
||||
const auto children = node->childItems();
|
||||
for (const auto child : children) {
|
||||
if (auto childNode = qobject_cast<QQuick3DNode *>(child)) {
|
||||
QVector3D newMinBounds = minBounds;
|
||||
QVector3D newMaxBounds = maxBounds;
|
||||
getBounds(childNode, vertexData, indexData, newMinBounds, newMaxBounds, fullTransform);
|
||||
getBounds(childNode, vertexData, indexData, newMinBounds, newMaxBounds);
|
||||
minBoundsVec << newMinBounds;
|
||||
maxBoundsVec << newMaxBounds;
|
||||
}
|
||||
}
|
||||
|
||||
auto combineMinBounds = [](QVector3D &target, const QVector3D &source) {
|
||||
target.setX(qMin(source.x(), target.x()));
|
||||
target.setY(qMin(source.y(), target.y()));
|
||||
target.setZ(qMin(source.z(), target.z()));
|
||||
};
|
||||
auto combineMaxBounds = [](QVector3D &target, const QVector3D &source) {
|
||||
target.setX(qMax(source.x(), target.x()));
|
||||
target.setY(qMax(source.y(), target.y()));
|
||||
target.setZ(qMax(source.z(), target.z()));
|
||||
};
|
||||
auto transformCorner = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget,
|
||||
const QVector3D &corner) {
|
||||
QVector3D mappedCorner = m.map(corner);
|
||||
combineMinBounds(minTarget, mappedCorner);
|
||||
combineMaxBounds(maxTarget, mappedCorner);
|
||||
};
|
||||
auto transformCorners = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget,
|
||||
const QVector3D &minCorner, const QVector3D &maxCorner) {
|
||||
transformCorner(m, minTarget, maxTarget, minCorner);
|
||||
transformCorner(m, minTarget, maxTarget, maxCorner);
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), minCorner.y(), maxCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), minCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), minCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), maxCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), maxCorner.y(), minCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), maxCorner.z()));
|
||||
};
|
||||
|
||||
// Combine all child bounds
|
||||
for (const auto &newBounds : qAsConst(minBoundsVec)) {
|
||||
minBounds.setX(qMin(newBounds.x(), minBounds.x()));
|
||||
minBounds.setY(qMin(newBounds.y(), minBounds.y()));
|
||||
minBounds.setZ(qMin(newBounds.z(), minBounds.z()));
|
||||
}
|
||||
for (const auto &newBounds : qAsConst(maxBoundsVec)) {
|
||||
maxBounds.setX(qMax(newBounds.x(), maxBounds.x()));
|
||||
maxBounds.setY(qMax(newBounds.y(), maxBounds.y()));
|
||||
maxBounds.setZ(qMax(newBounds.z(), maxBounds.z()));
|
||||
}
|
||||
for (const auto &newBounds : qAsConst(minBoundsVec))
|
||||
combineMinBounds(localMinBounds, newBounds);
|
||||
for (const auto &newBounds : qAsConst(maxBoundsVec))
|
||||
combineMaxBounds(localMaxBounds, newBounds);
|
||||
|
||||
if (auto modelNode = qobject_cast<QQuick3DModel *>(node)) {
|
||||
if (auto renderModel = static_cast<QSSGRenderModel *>(renderNode)) {
|
||||
@@ -253,47 +276,38 @@ void SelectionBoxGeometry::getBounds(QQuick3DNode *node, QByteArray &vertexData,
|
||||
QVector3D localMin = center - extents;
|
||||
QVector3D localMax = center + extents;
|
||||
|
||||
// Transform all corners of the local bounding box to find final extent in
|
||||
// in parent space
|
||||
|
||||
auto checkCorner = [&minBounds, &maxBounds, &fullTransform]
|
||||
(const QVector3D &corner) {
|
||||
QVector3D mappedCorner = fullTransform.map(corner);
|
||||
minBounds.setX(qMin(mappedCorner.x(), minBounds.x()));
|
||||
minBounds.setY(qMin(mappedCorner.y(), minBounds.y()));
|
||||
minBounds.setZ(qMin(mappedCorner.z(), minBounds.z()));
|
||||
maxBounds.setX(qMax(mappedCorner.x(), maxBounds.x()));
|
||||
maxBounds.setY(qMax(mappedCorner.y(), maxBounds.y()));
|
||||
maxBounds.setZ(qMax(mappedCorner.z(), maxBounds.z()));
|
||||
};
|
||||
|
||||
checkCorner(localMin);
|
||||
checkCorner(localMax);
|
||||
checkCorner(QVector3D(localMin.x(), localMin.y(), localMax.z()));
|
||||
checkCorner(QVector3D(localMin.x(), localMax.y(), localMin.z()));
|
||||
checkCorner(QVector3D(localMax.x(), localMin.y(), localMin.z()));
|
||||
checkCorner(QVector3D(localMin.x(), localMax.y(), localMax.z()));
|
||||
checkCorner(QVector3D(localMax.x(), localMax.y(), localMin.z()));
|
||||
checkCorner(QVector3D(localMax.x(), localMin.y(), localMax.z()));
|
||||
combineMinBounds(localMinBounds, localMin);
|
||||
combineMaxBounds(localMaxBounds, localMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
combineMinBounds(localMinBounds, {});
|
||||
combineMaxBounds(localMaxBounds, {});
|
||||
}
|
||||
|
||||
// Target node and immediate children get selection boxes
|
||||
if (transform.isIdentity()) {
|
||||
// Adjust bounds to reduce targetNode pixels obscuring the selection box
|
||||
QVector3D extents = (maxBounds - minBounds) / 1000.f;
|
||||
QVector3D minAdjBounds = minBounds - extents;
|
||||
QVector3D maxAdjBounds = maxBounds + extents;
|
||||
|
||||
appendVertexData(vertexData, indexData, minAdjBounds, maxAdjBounds);
|
||||
if (localMaxBounds == minVec) {
|
||||
localMinBounds = {};
|
||||
localMaxBounds = {};
|
||||
}
|
||||
|
||||
// Transform local space bounding box to parent space
|
||||
transformCorners(localTransform, minBounds, maxBounds, localMinBounds, localMaxBounds);
|
||||
|
||||
// Immediate child boxes
|
||||
if (node->parentNode() == m_targetNode)
|
||||
appendVertexData(localTransform, vertexData, indexData, localMinBounds, localMaxBounds);
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &indexData,
|
||||
const QVector3D &minBounds, const QVector3D &maxBounds)
|
||||
void SelectionBoxGeometry::appendVertexData(const QMatrix4x4 &m, QByteArray &vertexData,
|
||||
QByteArray &indexData, const QVector3D &minBounds,
|
||||
const QVector3D &maxBounds)
|
||||
{
|
||||
// Adjust bounds to reduce targetNode pixels obscuring the selection box
|
||||
QVector3D extents = (maxBounds - minBounds) / 1000.f;
|
||||
QVector3D minAdjBounds = minBounds - extents;
|
||||
QVector3D maxAdjBounds = maxBounds + extents;
|
||||
|
||||
int initialVertexSize = vertexData.size();
|
||||
int initialIndexSize = indexData.size();
|
||||
const int vertexSize = int(sizeof(float)) * 8 * 3; // 8 vertices, 3 floats/vert
|
||||
@@ -305,14 +319,20 @@ void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &
|
||||
auto dataPtr = reinterpret_cast<float *>(vertexData.data() + initialVertexSize);
|
||||
auto indexPtr = reinterpret_cast<quint16 *>(indexData.data() + initialIndexSize);
|
||||
|
||||
*dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z();
|
||||
*dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z();
|
||||
*dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z();
|
||||
*dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z();
|
||||
*dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z();
|
||||
*dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z();
|
||||
*dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z();
|
||||
*dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z();
|
||||
QVector3D corners[8];
|
||||
corners[0] = QVector3D(maxAdjBounds.x(), maxAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[1] = QVector3D(minAdjBounds.x(), maxAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[2] = QVector3D(minAdjBounds.x(), minAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[3] = QVector3D(maxAdjBounds.x(), minAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[4] = QVector3D(maxAdjBounds.x(), maxAdjBounds.y(), minAdjBounds.z());
|
||||
corners[5] = QVector3D(minAdjBounds.x(), maxAdjBounds.y(), minAdjBounds.z());
|
||||
corners[6] = QVector3D(minAdjBounds.x(), minAdjBounds.y(), minAdjBounds.z());
|
||||
corners[7] = QVector3D(maxAdjBounds.x(), minAdjBounds.y(), minAdjBounds.z());
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
corners[i] = m.map(corners[i]);
|
||||
*dataPtr++ = corners[i].x(); *dataPtr++ = corners[i].y(); *dataPtr++ = corners[i].z();
|
||||
}
|
||||
|
||||
*indexPtr++ = 0 + indexAdd; *indexPtr++ = 1 + indexAdd;
|
||||
*indexPtr++ = 1 + indexAdd; *indexPtr++ = 2 + indexAdd;
|
||||
@@ -330,6 +350,22 @@ void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &
|
||||
*indexPtr++ = 7 + indexAdd; *indexPtr++ = 4 + indexAdd;
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::trackNodeChanges(QQuick3DNode *node)
|
||||
{
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::sceneScaleChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::sceneRotationChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::scenePositionChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::pivotChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::orientationChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::rotationOrderChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -69,10 +69,11 @@ protected:
|
||||
QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override;
|
||||
|
||||
private:
|
||||
void getBounds(QQuick3DNode *node, QByteArray &vertexData, QByteArray &indexData,
|
||||
QVector3D &minBounds, QVector3D &maxBounds, const QMatrix4x4 &transform);
|
||||
void appendVertexData(QByteArray &vertexData, QByteArray &indexData,
|
||||
void getBounds(QQuick3DNode *node, QByteArray &vertexData,
|
||||
QByteArray &indexData, QVector3D &minBounds, QVector3D &maxBounds);
|
||||
void appendVertexData(const QMatrix4x4 &m, QByteArray &vertexData, QByteArray &indexData,
|
||||
const QVector3D &minBounds, const QVector3D &maxBounds);
|
||||
void trackNodeChanges(QQuick3DNode *node);
|
||||
|
||||
QQuick3DNode *m_targetNode = nullptr;
|
||||
QQuick3DViewport *m_view3D = nullptr;
|
||||
|
@@ -332,6 +332,10 @@ void NodeInstanceServer::clearScene(const ClearSceneCommand &/*command*/)
|
||||
m_fileUrl.clear();
|
||||
}
|
||||
|
||||
void NodeInstanceServer::change3DView(const Change3DViewCommand &/*command*/)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeInstanceServer::changeSelection(const ChangeSelectionCommand & /*command*/)
|
||||
{
|
||||
}
|
||||
|
@@ -101,6 +101,7 @@ public:
|
||||
void changeIds(const ChangeIdsCommand &command) override;
|
||||
void createScene(const CreateSceneCommand &command) override;
|
||||
void clearScene(const ClearSceneCommand &command) override;
|
||||
void change3DView(const Change3DViewCommand &command) override;
|
||||
void removeInstances(const RemoveInstancesCommand &command) override;
|
||||
void removeProperties(const RemovePropertiesCommand &command) override;
|
||||
void reparentInstances(const ReparentInstancesCommand &command) override;
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "changefileurlcommand.h"
|
||||
#include "clearscenecommand.h"
|
||||
#include "reparentinstancescommand.h"
|
||||
#include "change3dviewcommand.h"
|
||||
#include "changevaluescommand.h"
|
||||
#include "changebindingscommand.h"
|
||||
#include "changeidscommand.h"
|
||||
@@ -57,7 +58,6 @@
|
||||
#include "createscenecommand.h"
|
||||
#include "tokencommand.h"
|
||||
#include "removesharedmemorycommand.h"
|
||||
#include "changeselectioncommand.h"
|
||||
#include "objectnodeinstance.h"
|
||||
#include <drop3dlibraryitemcommand.h>
|
||||
|
||||
@@ -124,13 +124,18 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
||||
}
|
||||
|
||||
window->installEventFilter(this);
|
||||
QObject::connect(window, SIGNAL(objectClicked(QVariant)), this, SLOT(objectClicked(QVariant)));
|
||||
QObject::connect(window, SIGNAL(selectionChanged(QVariant)),
|
||||
this, SLOT(handleSelectionChanged(QVariant)));
|
||||
QObject::connect(window, SIGNAL(commitObjectProperty(QVariant, QVariant)),
|
||||
this, SLOT(handleObjectPropertyCommit(QVariant, QVariant)));
|
||||
QObject::connect(window, SIGNAL(changeObjectProperty(QVariant, QVariant)),
|
||||
this, SLOT(handleObjectPropertyChange(QVariant, QVariant)));
|
||||
QObject::connect(window, SIGNAL(activeChanged()),
|
||||
this, SLOT(handleActiveChanged()));
|
||||
QObject::connect(&m_propertyChangeTimer, &QTimer::timeout,
|
||||
this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout);
|
||||
QObject::connect(&m_selectionChangeTimer, &QTimer::timeout,
|
||||
this, &Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout);
|
||||
|
||||
//For macOS we have to use the 4.1 core profile
|
||||
QSurfaceFormat surfaceFormat = window->requestedFormat();
|
||||
@@ -145,14 +150,21 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
||||
return window;
|
||||
}
|
||||
|
||||
// an object is clicked in the 3D edit view. Null object indicates selection clearing.
|
||||
void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object)
|
||||
// The selection has changed in the 3D edit view. Empty list indicates selection is cleared.
|
||||
void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs)
|
||||
{
|
||||
auto obj = object.value<QObject *>();
|
||||
ServerNodeInstance instance;
|
||||
if (obj)
|
||||
instance = instanceForObject(obj);
|
||||
selectInstance(instance);
|
||||
QList<ServerNodeInstance> instanceList;
|
||||
const QVariantList varObjs = objs.value<QVariantList>();
|
||||
for (const auto &object : varObjs) {
|
||||
auto obj = object.value<QObject *>();
|
||||
if (obj) {
|
||||
ServerNodeInstance instance = instanceForObject(obj);
|
||||
instanceList << instance;
|
||||
}
|
||||
}
|
||||
selectInstances(instanceList);
|
||||
// Hold selection changes reflected back from designer for a bit
|
||||
m_selectionChangeTimer.start(500);
|
||||
}
|
||||
|
||||
QVector<Qt5InformationNodeInstanceServer::InstancePropertyValueTriple>
|
||||
@@ -219,6 +231,65 @@ void Qt5InformationNodeInstanceServer::modifyVariantValue(
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::showEditView(const QPoint &pos, const QSize &size)
|
||||
{
|
||||
m_blockViewActivate = false;
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window) {
|
||||
activateEditView();
|
||||
window->setPosition(pos);
|
||||
window->resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::hideEditView()
|
||||
{
|
||||
m_blockViewActivate = true;
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window)
|
||||
window->hide();
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::activateEditView()
|
||||
{
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window) {
|
||||
Qt::WindowFlags flags = window->flags();
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
window->setFlags(Qt::Popup);
|
||||
window->show();
|
||||
window->setFlags(flags);
|
||||
#else
|
||||
window->raise();
|
||||
window->setFlags(flags | Qt::WindowStaysOnTopHint);
|
||||
window->show();
|
||||
|
||||
window->requestActivate();
|
||||
window->raise();
|
||||
window->setFlags(flags);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::moveEditView(const QPoint &pos)
|
||||
{
|
||||
auto window = qobject_cast<QWindow*>(m_editView3D);
|
||||
if (window) {
|
||||
activateEditView();
|
||||
window->setPosition(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::resizeEditView(const QSize &size)
|
||||
{
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window) {
|
||||
activateEditView();
|
||||
window->resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleObjectPropertyCommit(const QVariant &object,
|
||||
const QVariant &propName)
|
||||
{
|
||||
@@ -253,10 +324,19 @@ void Qt5InformationNodeInstanceServer::updateViewPortRect()
|
||||
viewPortProperty.write(viewPortrect);
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleActiveChanged()
|
||||
{
|
||||
if (m_blockViewActivate)
|
||||
return;
|
||||
|
||||
activateEditView();
|
||||
}
|
||||
|
||||
Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
|
||||
Qt5NodeInstanceServer(nodeInstanceClient)
|
||||
{
|
||||
m_propertyChangeTimer.setInterval(100);
|
||||
m_selectionChangeTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::sendTokenBack()
|
||||
@@ -315,9 +395,9 @@ bool Qt5InformationNodeInstanceServer::isDirtyRecursiveForParentInstances(QQuick
|
||||
}
|
||||
|
||||
/* This method allows changing the selection from the puppet */
|
||||
void Qt5InformationNodeInstanceServer::selectInstance(const ServerNodeInstance &instance)
|
||||
void Qt5InformationNodeInstanceServer::selectInstances(const QList<ServerNodeInstance> &instanceList)
|
||||
{
|
||||
nodeInstanceClient()->selectionChanged(createChangeSelectionCommand({instance}));
|
||||
nodeInstanceClient()->selectionChanged(createChangeSelectionCommand(instanceList));
|
||||
}
|
||||
|
||||
/* This method allows changing property values from the puppet
|
||||
@@ -335,6 +415,11 @@ void Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout()
|
||||
ValuesModifiedCommand::TransactionOption::None);
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout()
|
||||
{
|
||||
changeSelection(m_pendingSelectionChangeCommand);
|
||||
}
|
||||
|
||||
QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport(
|
||||
const QList<ServerNodeInstance> &instanceList) const
|
||||
{
|
||||
@@ -389,26 +474,25 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
|
||||
{
|
||||
ServerNodeInstance root = rootNodeInstance();
|
||||
|
||||
QObject *node = nullptr;
|
||||
bool showCustomLight = false;
|
||||
|
||||
if (root.isSubclassOf("QQuick3DNode")) {
|
||||
node = root.internalObject();
|
||||
m_rootNode = root.internalObject();
|
||||
showCustomLight = true; // Pure node scene we should add a custom light
|
||||
} else {
|
||||
node = findRootNodeOf3DViewport(instanceList);
|
||||
m_rootNode = findRootNodeOf3DViewport(instanceList);
|
||||
}
|
||||
|
||||
if (node) { // If we found a scene we create the edit view
|
||||
if (m_rootNode) { // If we found a scene we create the edit view
|
||||
m_editView3D = createEditView3D(engine());
|
||||
|
||||
if (!m_editView3D)
|
||||
return;
|
||||
|
||||
QQmlProperty sceneProperty(m_editView3D, "scene", context());
|
||||
node->setParent(m_editView3D);
|
||||
sceneProperty.write(objectToVariant(node));
|
||||
QQmlProperty parentProperty(node, "parent", context());
|
||||
m_rootNode->setParent(m_editView3D);
|
||||
sceneProperty.write(objectToVariant(m_rootNode));
|
||||
QQmlProperty parentProperty(m_rootNode, "parent", context());
|
||||
parentProperty.write(objectToVariant(m_editView3D));
|
||||
QQmlProperty showLightProperty(m_editView3D, "showLight", context());
|
||||
showLightProperty.write(showCustomLight);
|
||||
@@ -610,18 +694,41 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
||||
if (!m_editView3D)
|
||||
return;
|
||||
|
||||
if (m_selectionChangeTimer.isActive()) {
|
||||
// If selection was recently changed by puppet, hold updating the selection for a bit to
|
||||
// avoid selection flicker, especially in multiselect cases.
|
||||
m_pendingSelectionChangeCommand = command;
|
||||
// Add additional time in case more commands are still coming through
|
||||
m_selectionChangeTimer.start(500);
|
||||
return;
|
||||
}
|
||||
|
||||
const QVector<qint32> instanceIds = command.instanceIds();
|
||||
QVariantList selectedObjs;
|
||||
for (qint32 id : instanceIds) {
|
||||
if (hasInstanceForId(id)) {
|
||||
ServerNodeInstance instance = instanceForId(id);
|
||||
QObject *object = nullptr;
|
||||
if (instance.isSubclassOf("QQuick3DNode"))
|
||||
object = instance.internalObject();
|
||||
QMetaObject::invokeMethod(m_editView3D, "selectObject", Q_ARG(QVariant,
|
||||
objectToVariant(object)));
|
||||
return; // TODO: support multi-selection
|
||||
if (object && object != m_rootNode)
|
||||
selectedObjs << objectToVariant(object);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the
|
||||
// case when the first selection processed is a multiselection, we wait a bit as
|
||||
// using the new boxes immediately leads to visual glitches.
|
||||
int boxCount = m_editView3D->property("selectionBoxes").value<QVariantList>().size();
|
||||
if (boxCount < selectedObjs.size()) {
|
||||
QMetaObject::invokeMethod(m_editView3D, "ensureSelectionBoxes",
|
||||
Q_ARG(QVariant, QVariant::fromValue(selectedObjs.size())));
|
||||
m_pendingSelectionChangeCommand = command;
|
||||
m_selectionChangeTimer.start(100);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(m_editView3D, "selectObjects",
|
||||
Q_ARG(QVariant, QVariant::fromValue(selectedObjs)));
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCommand &command)
|
||||
@@ -641,4 +748,18 @@ void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCo
|
||||
startRenderTimer();
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::change3DView(const Change3DViewCommand &command)
|
||||
{
|
||||
for (const InformationContainer &container : command.informationVector()) {
|
||||
if (container.name() == InformationName::ShowView)
|
||||
showEditView(container.information().toPoint(), container.secondInformation().toSize());
|
||||
else if (container.name() == InformationName::HideView)
|
||||
hideEditView();
|
||||
else if (container.name() == InformationName::MoveView)
|
||||
moveEditView(container.information().toPoint());
|
||||
else if (container.name() == InformationName::ResizeView)
|
||||
resizeEditView(container.secondInformation().toSize());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "qt5nodeinstanceserver.h"
|
||||
#include "tokencommand.h"
|
||||
#include "valueschangedcommand.h"
|
||||
#include "changeselectioncommand.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
@@ -42,6 +43,7 @@ public:
|
||||
|
||||
void reparentInstances(const ReparentInstancesCommand &command) override;
|
||||
void clearScene(const ClearSceneCommand &command) override;
|
||||
void change3DView(const Change3DViewCommand &command) override;
|
||||
void createScene(const CreateSceneCommand &command) override;
|
||||
void completeComponent(const CompleteComponentCommand &command) override;
|
||||
void token(const TokenCommand &command) override;
|
||||
@@ -50,10 +52,11 @@ public:
|
||||
void changePropertyValues(const ChangeValuesCommand &command) override;
|
||||
|
||||
private slots:
|
||||
void objectClicked(const QVariant &object);
|
||||
void handleSelectionChanged(const QVariant &objs);
|
||||
void handleObjectPropertyCommit(const QVariant &object, const QVariant &propName);
|
||||
void handleObjectPropertyChange(const QVariant &object, const QVariant &propName);
|
||||
void updateViewPortRect();
|
||||
void handleActiveChanged();
|
||||
|
||||
protected:
|
||||
void collectItemChangesAndSendChangeCommands() override;
|
||||
@@ -62,11 +65,12 @@ protected:
|
||||
void sendTokenBack();
|
||||
bool isDirtyRecursiveForNonInstanceItems(QQuickItem *item) const;
|
||||
bool isDirtyRecursiveForParentInstances(QQuickItem *item) const;
|
||||
void selectInstance(const ServerNodeInstance &instance);
|
||||
void selectInstances(const QList<ServerNodeInstance> &instanceList);
|
||||
void modifyProperties(const QVector<InstancePropertyValueTriple> &properties);
|
||||
|
||||
private:
|
||||
void handleObjectPropertyChangeTimeout();
|
||||
void handleSelectionChangeTimeout();
|
||||
QObject *createEditView3D(QQmlEngine *engine);
|
||||
void setup3DEditView(const QList<ServerNodeInstance> &instanceList);
|
||||
QObject *findRootNodeOf3DViewport(const QList<ServerNodeInstance> &instanceList) const;
|
||||
@@ -80,14 +84,24 @@ private:
|
||||
const PropertyName &propertyName,
|
||||
ValuesModifiedCommand::TransactionOption option);
|
||||
|
||||
void showEditView(const QPoint &pos, const QSize &size);
|
||||
void hideEditView();
|
||||
void activateEditView();
|
||||
void moveEditView(const QPoint &pos);
|
||||
void resizeEditView(const QSize &size);
|
||||
|
||||
QObject *m_editView3D = nullptr;
|
||||
QSet<ServerNodeInstance> m_parentChangedSet;
|
||||
QList<ServerNodeInstance> m_completedComponentList;
|
||||
QList<TokenCommand> m_tokenList;
|
||||
QTimer m_propertyChangeTimer;
|
||||
QTimer m_selectionChangeTimer;
|
||||
QVariant m_changedNode;
|
||||
PropertyName m_changedProperty;
|
||||
ServerNodeInstance m_viewPortInstance;
|
||||
bool m_blockViewActivate = false;
|
||||
QObject *m_rootNode = nullptr;
|
||||
ChangeSelectionCommand m_pendingSelectionChangeCommand;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -37,6 +37,7 @@
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
#include <private/qquick3dnode_p.h>
|
||||
#include <private/qquick3dmodel_p.h>
|
||||
#include <private/qquick3dnode_p_p.h>
|
||||
#endif
|
||||
|
||||
@@ -73,7 +74,7 @@ QQuick3DNode *Quick3DNodeInstance::quick3DNode() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildren)
|
||||
void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildInstances)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
auto node = quick3DNode();
|
||||
@@ -90,22 +91,42 @@ void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyT
|
||||
|
||||
}
|
||||
if (!parentHidden) {
|
||||
if (applyToChildren) {
|
||||
auto getQuick3DInstance = [this](QQuick3DObject *obj) -> Quick3DNodeInstance * {
|
||||
if (nodeInstanceServer()->hasInstanceForObject(obj)) {
|
||||
ServerNodeInstance instance = nodeInstanceServer()->instanceForObject(obj);
|
||||
if (instance.isValid() && qobject_cast<QQuick3DNode *>(instance.internalObject()))
|
||||
return static_cast<Quick3DNodeInstance *>(instance.internalInstance().data());
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
const auto childItems = node->childItems();
|
||||
for (auto childItem : childItems) {
|
||||
if (auto quick3dInstance = getQuick3DInstance(childItem)) {
|
||||
auto getQuick3DInstance = [this](QQuick3DObject *obj) -> Quick3DNodeInstance * {
|
||||
if (nodeInstanceServer()->hasInstanceForObject(obj)) {
|
||||
ServerNodeInstance instance = nodeInstanceServer()->instanceForObject(obj);
|
||||
if (instance.isValid() && qobject_cast<QQuick3DNode *>(instance.internalObject()))
|
||||
return static_cast<Quick3DNodeInstance *>(instance.internalInstance().data());
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
const auto childItems = node->childItems();
|
||||
for (auto childItem : childItems) {
|
||||
if (auto quick3dInstance = getQuick3DInstance(childItem)) {
|
||||
if (applyToChildInstances) {
|
||||
// Don't override explicit block in children
|
||||
if (!QQuick3DNodePrivate::get(quick3dInstance->quick3DNode())->m_isHiddenInEditor)
|
||||
quick3dInstance->setPickable(enable, false, true);
|
||||
}
|
||||
} else {
|
||||
// Children of components do not have instances, but will still need to be
|
||||
// pickable. These need to be set even if applyToChildInstances is false.
|
||||
std::function<void(QQuick3DNode *)> checkChildren;
|
||||
checkChildren = [&](QQuick3DNode *checkNode) {
|
||||
const auto childItems = checkNode->childItems();
|
||||
for (auto child : childItems) {
|
||||
if (auto childNode = qobject_cast<QQuick3DNode *>(child))
|
||||
checkChildren(childNode);
|
||||
}
|
||||
if (auto checkModel = qobject_cast<QQuick3DModel *>(checkNode)) {
|
||||
QVariant value;
|
||||
if (enable)
|
||||
value = QVariant::fromValue(node);
|
||||
// Specify the actual pick target with dynamic property
|
||||
checkModel->setProperty("_pickTarget", value);
|
||||
checkModel->setPickable(enable);
|
||||
}
|
||||
};
|
||||
checkChildren(node);
|
||||
}
|
||||
}
|
||||
if (nodeType == QQuick3DObject::Model)
|
||||
@@ -115,7 +136,7 @@ void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyT
|
||||
#else
|
||||
Q_UNUSED(enable)
|
||||
Q_UNUSED(checkParent)
|
||||
Q_UNUSED(applyToChildren)
|
||||
Q_UNUSED(applyToChildInstances)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -53,7 +53,7 @@ protected:
|
||||
private:
|
||||
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
||||
QQuick3DNode *quick3DNode() const;
|
||||
void setPickable(bool enable, bool checkParent, bool applyToChildren);
|
||||
void setPickable(bool enable, bool checkParent, bool applyToChildInstances);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -615,6 +615,8 @@ Rectangle {
|
||||
anchors.right: parent.right
|
||||
AdvancedSection {
|
||||
}
|
||||
LayerSection {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,319 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
import QtQuick 2.0
|
||||
import HelperWidgets 2.0
|
||||
import QtQuick.Layouts 1.0
|
||||
|
||||
Section {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
caption: qsTr("Layer")
|
||||
|
||||
SectionLayout {
|
||||
columns: 2
|
||||
|
||||
Label {
|
||||
text: qsTr("Effect")
|
||||
tooltip: qsTr("Sets the effect that is applied to this layer.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
ItemFilterComboBox {
|
||||
typeFilter: "QtQuick.Item"
|
||||
validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
|
||||
backendValue: backendValues.layer_effect
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Enabled")
|
||||
tooltip: qsTr("Sets whether the item is layered or not.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
CheckBox {
|
||||
text: backendValues.layer_enabled.valueToString
|
||||
backendValue: backendValues.layer_enabled
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Format")
|
||||
tooltip: qsTr("Defines the internal OpenGL format of the texture.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
ComboBox {
|
||||
scope: "ShaderEffectSource"
|
||||
model: ["Alpha", "RGB", "RGBA"]
|
||||
backendValue: backendValues.layer_format
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Mipmap")
|
||||
tooltip: qsTr("Enables the generation of mipmaps for the texture.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
CheckBox {
|
||||
text: backendValues.layer_mipmap.valueToString
|
||||
backendValue: backendValues.layer_mipmap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Sampler name")
|
||||
tooltip: qsTr("Sets the name of the effect's source texture property.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
LineEdit {
|
||||
backendValue: backendValues.layer_samplerName
|
||||
text: backendValues.layer_samplerName.valueToString
|
||||
Layout.fillWidth: true
|
||||
showTranslateCheckBox: false
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Samples")
|
||||
tooltip: qsTr("Allows requesting multisampled rendering in the layer.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
ComboBox {
|
||||
id: samplesComboBox
|
||||
model: [2, 4, 8, 16]
|
||||
backendValue: backendValues.layer_samples
|
||||
manualMapping: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
onValueFromBackendChanged: {
|
||||
if (!samplesComboBox.__isCompleted)
|
||||
return
|
||||
|
||||
samplesComboBox.syncIndexToBackendValue()
|
||||
}
|
||||
onCompressedActivated: {
|
||||
if (!samplesComboBox.__isCompleted)
|
||||
return
|
||||
|
||||
if (samplesComboBox.block)
|
||||
return
|
||||
|
||||
backendValues.layer_samples.value = samplesComboBox.model[samplesComboBox.currentIndex]
|
||||
}
|
||||
Component.onCompleted: samplesComboBox.syncIndexToBackendValue()
|
||||
|
||||
function syncIndexToBackendValue() {
|
||||
samplesComboBox.block = true
|
||||
samplesComboBox.currentIndex = samplesComboBox.model.indexOf(backendValues.layer_samples.value)
|
||||
samplesComboBox.block = false
|
||||
}
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Smooth")
|
||||
tooltip: qsTr("Sets whether the layer is smoothly transformed.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
CheckBox {
|
||||
text: backendValues.layer_smooth.valueToString
|
||||
backendValue: backendValues.layer_smooth
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Label {
|
||||
text: qsTr("Source rectangle")
|
||||
tooltip: qsTr("TODO.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
Label {
|
||||
text: "X"
|
||||
width: 12
|
||||
}
|
||||
SpinBox {
|
||||
backendValue: backendValues.layer_sourceRect_x
|
||||
maximumValue: 0xffff
|
||||
minimumValue: -0xffff
|
||||
decimals: 0
|
||||
realDragRange: 5000
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 4
|
||||
height: 4
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Y"
|
||||
width: 12
|
||||
}
|
||||
SpinBox {
|
||||
backendValue: backendValues.layer_sourceRect_y
|
||||
maximumValue: 0xffff
|
||||
minimumValue: -0xffff
|
||||
decimals: 0
|
||||
realDragRange: 5000
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 4
|
||||
height: 4
|
||||
}
|
||||
SecondColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Label {
|
||||
text: "W"
|
||||
width: 12
|
||||
}
|
||||
SpinBox {
|
||||
backendValue: backendValues.layer_sourceRect_width
|
||||
maximumValue: 0xffff
|
||||
minimumValue: 0
|
||||
decimals: 0
|
||||
realDragRange: 5000
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 4
|
||||
height: 4
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "H"
|
||||
width: 12
|
||||
}
|
||||
SpinBox {
|
||||
backendValue: backendValues.layer_sourceRect_height
|
||||
maximumValue: 0xffff
|
||||
minimumValue: 0
|
||||
decimals: 0
|
||||
realDragRange: 5000
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Label {
|
||||
text: qsTr("Texture mirroring")
|
||||
tooltip: qsTr("Defines how the generated OpenGL texture should be mirrored.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
ComboBox {
|
||||
scope: "ShaderEffectSource"
|
||||
model: ["NoMirroring", "MirrorHorizontally", "MirrorVertically"]
|
||||
backendValue: backendValues.layer_textureMirroring
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Texture size")
|
||||
tooltip: qsTr("Sets the requested pixel size of the layers texture.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
Label {
|
||||
text: "W"
|
||||
width: 12
|
||||
}
|
||||
SpinBox {
|
||||
backendValue: backendValues.layer_textureSize_width
|
||||
minimumValue: 0
|
||||
maximumValue: 2000
|
||||
decimals: 0
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 4
|
||||
height: 4
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "H"
|
||||
width: 12
|
||||
}
|
||||
SpinBox {
|
||||
backendValue: backendValues.layer_textureSize_height
|
||||
minimumValue: 0
|
||||
maximumValue: 2000
|
||||
decimals: 0
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Wrap mode")
|
||||
tooltip: qsTr("Defines the OpenGL wrap modes associated with the texture.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
ComboBox {
|
||||
scope: "ShaderEffectSource"
|
||||
model: ["ClampToEdge", "RepeatHorizontally", "RepeatVertically", "Repeat"]
|
||||
backendValue: backendValues.layer_wrapMode
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandingSpacer {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,213 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import StudioControls 1.0 as StudioControls
|
||||
import StudioTheme 1.0 as StudioTheme
|
||||
|
||||
Rectangle {
|
||||
id: editableListView
|
||||
|
||||
property variant backendValue
|
||||
|
||||
ExtendedFunctionLogic {
|
||||
id: extFuncLogic
|
||||
backendValue: editableListView.backendValue
|
||||
}
|
||||
|
||||
property var model
|
||||
onModelChanged: myRepeater.updateModel()
|
||||
|
||||
signal add(string value)
|
||||
signal remove(int idx)
|
||||
signal replace(int idx, string value)
|
||||
|
||||
property alias actionIndicator: actionIndicator
|
||||
|
||||
property alias actionIndicatorVisible: actionIndicator.visible
|
||||
property real __actionIndicatorWidth: StudioTheme.Values.squareComponentWidth
|
||||
property real __actionIndicatorHeight: StudioTheme.Values.height
|
||||
|
||||
color: "transparent"
|
||||
border.color: StudioTheme.Values.themeControlOutline
|
||||
border.width: StudioTheme.Values.border
|
||||
|
||||
property int numVisibleItems: myRepeater.count
|
||||
|
||||
Layout.preferredWidth: StudioTheme.Values.height * 10
|
||||
Layout.preferredHeight: myColumn.height
|
||||
|
||||
Component {
|
||||
id: myDelegate
|
||||
ListViewComboBox {
|
||||
id: itemFilterComboBox
|
||||
|
||||
property int myIndex: index
|
||||
property bool empty: itemFilterComboBox.initialModelData === ""
|
||||
|
||||
validator: RegExpValidator { regExp: /(^[a-z_]\w*|^[A-Z]\w*\.{1}([a-z_]\w*\.?)+)/ }
|
||||
|
||||
actionIndicatorVisible: false
|
||||
typeFilter: "QtQuick3D.Material"
|
||||
editText: modelData
|
||||
initialModelData: modelData
|
||||
|
||||
width: editableListView.width
|
||||
|
||||
onFocusChanged: {
|
||||
if (itemFilterComboBox.focus) {
|
||||
myColumn.currentIndex = index
|
||||
}
|
||||
|
||||
if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") {
|
||||
myRepeater.dirty = false
|
||||
editableListView.add(itemFilterComboBox.editText)
|
||||
}
|
||||
}
|
||||
|
||||
onCompressedActivated: {
|
||||
if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") {
|
||||
myRepeater.dirty = false
|
||||
editableListView.add(itemFilterComboBox.editText)
|
||||
} else {
|
||||
editableListView.replace(myIndex, itemFilterComboBox.editText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: highlightRect
|
||||
color: "transparent"
|
||||
border.width: StudioTheme.Values.border
|
||||
border.color: StudioTheme.Values.themeInteraction
|
||||
x: myColumn.currentItem ? myColumn.currentItem.x : 0
|
||||
y: myColumn.currentItem ? myColumn.currentItem.y : 0
|
||||
z: 10
|
||||
width: myColumn.currentItem ? myColumn.currentItem.width : 0
|
||||
height: myColumn.currentItem ? myColumn.currentItem.height : 0
|
||||
}
|
||||
|
||||
Column {
|
||||
id: myColumn
|
||||
|
||||
property int currentIndex: -1
|
||||
property Item currentItem
|
||||
|
||||
spacing: -1
|
||||
|
||||
onCurrentIndexChanged: myColumn.currentItem = myRepeater.itemAt(myColumn.currentIndex)
|
||||
|
||||
Repeater {
|
||||
id: myRepeater
|
||||
|
||||
property bool dirty: false
|
||||
property var localModel: []
|
||||
|
||||
delegate: myDelegate
|
||||
|
||||
onItemAdded: function(index, item) {
|
||||
if (index === myColumn.currentIndex)
|
||||
myColumn.currentItem = item
|
||||
}
|
||||
|
||||
function updateModel() {
|
||||
var lastIndex = myColumn.currentIndex
|
||||
myColumn.currentIndex = -1
|
||||
myRepeater.localModel = []
|
||||
|
||||
editableListView.model.forEach(function(item) {
|
||||
myRepeater.localModel.push(item)
|
||||
});
|
||||
|
||||
// if list view is still dirty, then last state had an unfinished/empty ComboBox
|
||||
if (myRepeater.dirty)
|
||||
myRepeater.localModel.push("")
|
||||
|
||||
myRepeater.model = myRepeater.localModel // trigger on change handler
|
||||
|
||||
if (lastIndex < 0 && myRepeater.localModel.length > 0)
|
||||
myColumn.currentIndex = 0
|
||||
else if (myRepeater.localModel.length > lastIndex)
|
||||
myColumn.currentIndex = lastIndex
|
||||
else
|
||||
myColumn.currentIndex = myRepeater.localModel.length - 1
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: -StudioTheme.Values.border
|
||||
|
||||
StudioControls.ActionIndicator {
|
||||
id: actionIndicator
|
||||
width: actionIndicator.visible ? __actionIndicatorWidth : 0
|
||||
height: actionIndicator.visible ? __actionIndicatorHeight : 0
|
||||
showBackground: true
|
||||
|
||||
icon.color: extFuncLogic.color
|
||||
icon.text: extFuncLogic.glyph
|
||||
onClicked: extFuncLogic.show()
|
||||
}
|
||||
StudioControls.AbstractButton {
|
||||
buttonIcon: "+"
|
||||
iconFont: StudioTheme.Constants.font
|
||||
enabled: !myRepeater.dirty
|
||||
onClicked: {
|
||||
var idx = myRepeater.localModel.push("") - 1
|
||||
myRepeater.model = myRepeater.localModel // trigger on change handler
|
||||
myRepeater.dirty = true
|
||||
myColumn.currentIndex = idx
|
||||
myColumn.currentItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
StudioControls.AbstractButton {
|
||||
buttonIcon: "-"
|
||||
iconFont: StudioTheme.Constants.font
|
||||
enabled: myRepeater.model.length
|
||||
onClicked: {
|
||||
var lastItem = myColumn.currentIndex === myRepeater.localModel.length - 1
|
||||
if (myColumn.currentItem.initialModelData === "") {
|
||||
myRepeater.localModel.pop()
|
||||
myRepeater.dirty = false
|
||||
myRepeater.model = myRepeater.localModel // trigger on change handler
|
||||
} else {
|
||||
editableListView.remove(myColumn.currentIndex)
|
||||
}
|
||||
if (!lastItem)
|
||||
myColumn.currentIndex = myColumn.currentIndex - 1
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
color: StudioTheme.Values.themeControlBackground
|
||||
border.width: StudioTheme.Values.border
|
||||
border.color: StudioTheme.Values.themeControlOutline
|
||||
height: StudioTheme.Values.height
|
||||
width: editableListView.width - (StudioTheme.Values.height - StudioTheme.Values.border) * (actionIndicatorVisible ? 3 : 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Quick 3D.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
import QtQuick 2.12
|
||||
import HelperWidgets 2.0 as HelperWidgets
|
||||
|
||||
HelperWidgets.ComboBox {
|
||||
id: comboBox
|
||||
|
||||
property alias typeFilter: itemFilterModel.typeFilter
|
||||
|
||||
manualMapping: true
|
||||
editable: true
|
||||
model: comboBox.addDefaultItem(itemFilterModel.itemModel)
|
||||
|
||||
HelperWidgets.ItemFilterModel {
|
||||
id: itemFilterModel
|
||||
modelNodeBackendProperty: modelNodeBackend
|
||||
}
|
||||
|
||||
property string defaultItem: qsTr("[None]")
|
||||
property string textValue: comboBox.backendValue.expression
|
||||
property bool block: false
|
||||
property bool dirty: true
|
||||
|
||||
onTextValueChanged: {
|
||||
if (comboBox.block)
|
||||
return
|
||||
|
||||
comboBox.setCurrentText(comboBox.textValue)
|
||||
}
|
||||
onModelChanged: comboBox.setCurrentText(comboBox.textValue)
|
||||
onCompressedActivated: comboBox.handleActivate(index)
|
||||
Component.onCompleted: comboBox.setCurrentText(comboBox.textValue)
|
||||
|
||||
onEditTextChanged: comboBox.dirty = true
|
||||
onFocusChanged: {
|
||||
if (comboBox.dirty)
|
||||
comboBox.handleActivate(comboBox.currentIndex)
|
||||
}
|
||||
|
||||
function handleActivate(index)
|
||||
{
|
||||
if (!comboBox.__isCompleted || comboBox.backendValue === undefined)
|
||||
return
|
||||
|
||||
var cText = (index === -1) ? comboBox.editText : comboBox.textAt(index)
|
||||
comboBox.block = true
|
||||
comboBox.setCurrentText(cText)
|
||||
comboBox.block = false
|
||||
}
|
||||
|
||||
function setCurrentText(text)
|
||||
{
|
||||
if (!comboBox.__isCompleted || comboBox.backendValue === undefined)
|
||||
return
|
||||
|
||||
comboBox.currentIndex = comboBox.find(text)
|
||||
|
||||
if (text === "") {
|
||||
comboBox.currentIndex = 0
|
||||
comboBox.editText = comboBox.defaultItem
|
||||
} else {
|
||||
if (comboBox.currentIndex === -1)
|
||||
comboBox.editText = text
|
||||
else if (comboBox.currentIndex === 0)
|
||||
comboBox.editText = comboBox.defaultItem
|
||||
}
|
||||
|
||||
if (comboBox.currentIndex === 0) {
|
||||
comboBox.backendValue.resetValue()
|
||||
} else {
|
||||
if (comboBox.backendValue.expression !== comboBox.editText)
|
||||
comboBox.backendValue.expression = comboBox.editText
|
||||
}
|
||||
comboBox.dirty = false
|
||||
}
|
||||
|
||||
function addDefaultItem(arr)
|
||||
{
|
||||
var copy = arr.slice()
|
||||
copy.unshift(comboBox.defaultItem)
|
||||
return copy
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Quick 3D.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
import QtQuick 2.12
|
||||
import HelperWidgets 2.0 as HelperWidgets
|
||||
import StudioControls 1.0 as StudioControls
|
||||
|
||||
StudioControls.ComboBox {
|
||||
id: comboBox
|
||||
|
||||
property alias typeFilter: itemFilterModel.typeFilter
|
||||
|
||||
property var initialModelData
|
||||
property bool __isCompleted: false
|
||||
|
||||
editable: true
|
||||
model: itemFilterModel.itemModel
|
||||
|
||||
HelperWidgets.ItemFilterModel {
|
||||
id: itemFilterModel
|
||||
modelNodeBackendProperty: modelNodeBackend
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
comboBox.__isCompleted = true
|
||||
|
||||
// Workaround for proper initialization. Use the initial modelData value and search for it
|
||||
// in the model. If nothing was found, set the editText to the initial modelData.
|
||||
comboBox.currentIndex = comboBox.find(comboBox.initialModelData)
|
||||
|
||||
if (comboBox.currentIndex === -1)
|
||||
comboBox.editText = comboBox.initialModelData
|
||||
}
|
||||
}
|
@@ -17,6 +17,7 @@ ComboBox 2.0 ComboBox.qml
|
||||
CustomCheckBoxStyle 2.0 CustomCheckBoxStyle.qml
|
||||
CustomComboBoxStyle 2.0 CustomComboBoxStyle.qml
|
||||
CustomSpinBoxStyle 2.0 CustomSpinBoxStyle.qml
|
||||
EditableListView 2.0 EditableListView.qml
|
||||
ExpandingSpacer 2.0 ExpandingSpacer.qml
|
||||
ExtendedFunctionButton 2.0 ExtendedFunctionButton.qml
|
||||
ExtendedFunctionLogic 2.0 ExtendedFunctionLogic.qml
|
||||
@@ -30,6 +31,8 @@ GradientPresetTabContent 2.0 GradientPresetTabContent.qml
|
||||
GroupBox 2.0 GroupBox.qml
|
||||
HueSlider 2.0 HueSlider.qml
|
||||
IconLabel 2.0 IconLabel.qml
|
||||
ItemFilterComboBox 2.0 ItemFilterComboBox.qml
|
||||
ListViewComboBox 2.0 ListViewComboBox.qml
|
||||
Label 2.0 Label.qml
|
||||
LineEdit 2.0 LineEdit.qml
|
||||
OriginControl 2.0 OriginControl.qml
|
||||
|
@@ -20,7 +20,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
enable_testing()
|
||||
|
||||
add_executable(%{TestCaseName} %{TestCaseFileWithCppSuffix})
|
||||
add_test(%{TestCaseName} COMMAND %{TestCaseName})
|
||||
add_test(NAME %{TestCaseName} COMMAND %{TestCaseName})
|
||||
|
||||
@if "%{RequireGUI}" == "true"
|
||||
target_link_libraries(%{TestCaseName} PRIVATE Qt5::Gui Qt5::Test)
|
||||
@@ -46,7 +46,7 @@ enable_testing()
|
||||
add_definitions(-DQUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
add_executable(%{TestCaseName} %{MainCppName})
|
||||
add_test(%{TestCaseName} COMMAND %{TestCaseName})
|
||||
add_test(NAME %{TestCaseName} COMMAND %{TestCaseName})
|
||||
|
||||
target_link_libraries(%{TestCaseName} PRIVATE Qt5::QuickTest)
|
||||
|
||||
@@ -91,7 +91,7 @@ include_directories(${GTestIncludes})
|
||||
|
||||
add_executable(%{TestCaseName} %{MainCppName} %{TestCaseFileWithHeaderSuffix}
|
||||
${GTestFiles})
|
||||
add_test(%{TestCaseName} COMMAND %{TestCaseName})
|
||||
add_test(NAME %{TestCaseName} COMMAND %{TestCaseName})
|
||||
target_link_libraries(%{TestCaseName} PRIVATE Threads::Threads)
|
||||
|
||||
@endif
|
||||
@@ -103,7 +103,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
enable_testing()
|
||||
|
||||
add_executable(%{TestCaseName} %{MainCppName})
|
||||
add_test(%{TestCaseName} COMMAND %{TestCaseName})
|
||||
add_test(NAME %{TestCaseName} COMMAND %{TestCaseName})
|
||||
|
||||
if (DEFINED ENV{BOOST_INCLUDE_DIR})
|
||||
set(BOOST_INCLUDE_DIR $ENV{BOOST_INCLUDE_DIR})
|
||||
|
@@ -1674,7 +1674,8 @@ bool Check::visit(CallExpression *ast)
|
||||
if (!whiteListedFunction && !isMathFunction && !isDateFunction && !isDirectInConnectionsScope)
|
||||
addMessage(ErrFunctionsNotSupportedInQmlUi, location);
|
||||
|
||||
static const QStringList globalFunctions = {"String", "Boolean", "Date", "Number", "Object", "Array", "QT_TR_NOOP", "QT_TRANSLATE_NOOP", "QT_TRID_NOOP"};
|
||||
static const QStringList globalFunctions = {"String", "Boolean", "Date", "Number", "Object", "Array", "Symbol", "Object", "Function", "RegExp",
|
||||
"QT_TR_NOOP", "QT_TRANSLATE_NOOP", "QT_TRID_NOOP"};
|
||||
|
||||
if (!name.isEmpty() && name.at(0).isUpper() && !globalFunctions.contains(name)) {
|
||||
addMessage(WarnExpectedNewWithUppercaseFunction, location);
|
||||
|
@@ -145,7 +145,7 @@ void AndroidDebugSupport::start()
|
||||
setSymbolFile(runControl()->buildDirectory().pathAppended("app_process"));
|
||||
setSkipExecutableValidation(true);
|
||||
setUseExtendedRemote(true);
|
||||
QString devicePreferredAbi = AndroidManager::devicePreferredAbi(target);
|
||||
QString devicePreferredAbi = AndroidManager::apkDevicePreferredAbi(target);
|
||||
setAbi(AndroidManager::androidAbi2Abi(devicePreferredAbi));
|
||||
QUrl gdbServer;
|
||||
gdbServer.setHost(QHostAddress(QHostAddress::LocalHost).toString());
|
||||
|
@@ -509,7 +509,7 @@ void AndroidDeployQtStep::gatherFilesToPull()
|
||||
|
||||
QString linkerName("linker");
|
||||
QString libDirName("lib");
|
||||
auto preferreABI = AndroidManager::devicePreferredAbi(target());
|
||||
auto preferreABI = AndroidManager::apkDevicePreferredAbi(target());
|
||||
if (preferreABI == "arm64-v8a" || preferreABI == "x86_64") {
|
||||
m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process";
|
||||
libDirName = "lib64";
|
||||
|
@@ -56,12 +56,14 @@ AndroidDevice::AndroidDevice()
|
||||
setOsType(Utils::OsTypeOtherUnix);
|
||||
|
||||
setDeviceState(DeviceReadyToUse);
|
||||
QString activityPath;
|
||||
const AndroidConfig &config = AndroidConfigurations::currentConfig();
|
||||
AndroidManager::apkInfo(config.qtLiveApkPath(), nullptr, nullptr, &activityPath);
|
||||
qCDebug(androidDeviceLog) << "Using Qt live apk from: " << config.qtLiveApkPath()
|
||||
<< "Activity Path:" << activityPath;
|
||||
setQmlsceneCommand(activityPath);
|
||||
if (config.qtLiveApkPath().exists()) {
|
||||
QString activityPath;
|
||||
AndroidManager::apkInfo(config.qtLiveApkPath(), nullptr, nullptr, &activityPath);
|
||||
qCDebug(androidDeviceLog) << "Using Qt live apk from: " << config.qtLiveApkPath()
|
||||
<< "Activity Path:" << activityPath;
|
||||
setQmlsceneCommand(activityPath);
|
||||
}
|
||||
}
|
||||
|
||||
IDevice::DeviceInfo AndroidDevice::deviceInformation() const
|
||||
|
@@ -423,9 +423,8 @@ void AndroidManager::setDeviceSerialNumber(ProjectExplorer::Target *target, cons
|
||||
target->setNamedSettings(AndroidDeviceSn, deviceSerialNumber);
|
||||
}
|
||||
|
||||
QString AndroidManager::devicePreferredAbi(Target *target)
|
||||
static QString preferredAbi(const QStringList &appAbis, Target *target)
|
||||
{
|
||||
auto appAbis = applicationAbis(target);
|
||||
const auto deviceAbis = target->namedSettings(AndroidDeviceAbis).toStringList();
|
||||
for (const auto &abi : deviceAbis) {
|
||||
if (appAbis.contains(abi))
|
||||
@@ -434,6 +433,16 @@ QString AndroidManager::devicePreferredAbi(Target *target)
|
||||
return {};
|
||||
}
|
||||
|
||||
QString AndroidManager::apkDevicePreferredAbi(Target *target)
|
||||
{
|
||||
auto libsPath = dirPath(target).pathAppended("libs");
|
||||
QStringList apkAbis;
|
||||
for (const auto &abi : QDir{libsPath.toString()}.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
|
||||
if (QDir{libsPath.pathAppended(abi).toString()}.entryList(QStringList("*.so"), QDir::Files | QDir::NoDotAndDotDot).length())
|
||||
apkAbis << abi;
|
||||
return preferredAbi(apkAbis, target);
|
||||
}
|
||||
|
||||
void AndroidManager::setDeviceAbis(ProjectExplorer::Target *target, const QStringList &deviceAbis)
|
||||
{
|
||||
target->setNamedSettings(AndroidDeviceAbis, deviceAbis);
|
||||
|
@@ -84,7 +84,7 @@ public:
|
||||
static QString deviceSerialNumber(ProjectExplorer::Target *target);
|
||||
static void setDeviceSerialNumber(ProjectExplorer::Target *target, const QString &deviceSerialNumber);
|
||||
|
||||
static QString devicePreferredAbi(ProjectExplorer::Target *target);
|
||||
static QString apkDevicePreferredAbi(ProjectExplorer::Target *target);
|
||||
static void setDeviceAbis(ProjectExplorer::Target *target, const QStringList &deviceAbis);
|
||||
|
||||
static int deviceApiLevel(ProjectExplorer::Target *target);
|
||||
|
@@ -224,7 +224,7 @@ void AndroidRunner::remoteErrorOutput(const QString &output)
|
||||
}
|
||||
|
||||
void AndroidRunner::handleRemoteProcessStarted(Utils::Port gdbServerPort,
|
||||
const QUrl &qmlServer, int pid)
|
||||
const QUrl &qmlServer, qint64 pid)
|
||||
{
|
||||
m_pid = ProcessHandle(pid);
|
||||
m_gdbServerPort = gdbServerPort;
|
||||
|
@@ -72,7 +72,7 @@ private:
|
||||
void remoteOutput(const QString &output);
|
||||
void remoteErrorOutput(const QString &output);
|
||||
void gotRemoteOutput(const QString &output);
|
||||
void handleRemoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, int pid);
|
||||
void handleRemoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, qint64 pid);
|
||||
void handleRemoteProcessFinished(const QString &errString = QString());
|
||||
void checkAVD();
|
||||
void launchAVD();
|
||||
|
@@ -225,7 +225,9 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
|
||||
<< "Extra Start Args:" << m_amStartExtraArgs
|
||||
<< "Before Start ADB cmds:" << m_beforeStartAdbCommands
|
||||
<< "After finish ADB cmds:" << m_afterFinishAdbCommands;
|
||||
m_gdbserverPath = AndroidConfigurations::instance()->currentConfig().gdbServer(AndroidManager::devicePreferredAbi(target)).toString();
|
||||
QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target);
|
||||
if (!preferredAbi.isEmpty())
|
||||
m_gdbserverPath = AndroidConfigurations::instance()->currentConfig().gdbServer(preferredAbi).toString();
|
||||
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit());
|
||||
m_useAppParamsForQmlDebugger = version->qtVersion() >= QtSupport::QtVersionNumber(5, 12);
|
||||
}
|
||||
|
@@ -64,7 +64,7 @@ public:
|
||||
void handleJdbSettled();
|
||||
|
||||
signals:
|
||||
void remoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, int pid);
|
||||
void remoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, qint64 pid);
|
||||
void remoteProcessFinished(const QString &errString = QString());
|
||||
|
||||
void remoteOutput(const QString &output);
|
||||
|
@@ -294,7 +294,7 @@ private:
|
||||
const std::map<SdkManagerOutputParser::MarkerTag, const char *> markerTags {
|
||||
{SdkManagerOutputParser::MarkerTag::InstalledPackagesMarker, "Installed packages:"},
|
||||
{SdkManagerOutputParser::MarkerTag::AvailablePackagesMarkers, "Available Packages:"},
|
||||
{SdkManagerOutputParser::MarkerTag::AvailablePackagesMarkers, "Available Updates:"},
|
||||
{SdkManagerOutputParser::MarkerTag::AvailableUpdatesMarker, "Available Updates:"},
|
||||
{SdkManagerOutputParser::MarkerTag::PlatformMarker, "platforms"},
|
||||
{SdkManagerOutputParser::MarkerTag::SystemImageMarker, "system-images"},
|
||||
{SdkManagerOutputParser::MarkerTag::BuildToolsMarker, "build-tools"},
|
||||
|
@@ -122,10 +122,10 @@ void CMakeBuildConfiguration::initialize()
|
||||
|
||||
auto androidAbis = bs->data(Android::Constants::AndroidABIs).toStringList();
|
||||
QString preferredAbi;
|
||||
if (androidAbis.contains("arm64-v8a")) {
|
||||
preferredAbi = "arm64-v8a";
|
||||
} else if (androidAbis.isEmpty() || androidAbis.contains("armeabi-v7a")) {
|
||||
if (androidAbis.contains("armeabi-v7a")) {
|
||||
preferredAbi = "armeabi-v7a";
|
||||
} else if (androidAbis.isEmpty() || androidAbis.contains("arm64-v8a")) {
|
||||
preferredAbi = "arm64-v8a";
|
||||
} else {
|
||||
preferredAbi = androidAbis.first();
|
||||
}
|
||||
|
@@ -76,13 +76,12 @@ static std::vector<std::unique_ptr<CMakeTool>> autoDetectCMakeTools()
|
||||
path = Utils::filteredUnique(path);
|
||||
|
||||
if (HostOsInfo::isWindowsHost()) {
|
||||
const QString progFiles = QLatin1String(qgetenv("ProgramFiles"));
|
||||
path.append(Utils::FilePath::fromString(progFiles + "/CMake"));
|
||||
path.append(Utils::FilePath::fromString(progFiles + "/CMake/bin"));
|
||||
const QString progFilesX86 = QLatin1String(qgetenv("ProgramFiles(x86)"));
|
||||
if (!progFilesX86.isEmpty()) {
|
||||
path.append(Utils::FilePath::fromString(progFilesX86 + "/CMake"));
|
||||
path.append(Utils::FilePath::fromString(progFilesX86 + "/CMake/bin"));
|
||||
for (auto envVar : {"ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"}) {
|
||||
if (qEnvironmentVariableIsSet(envVar)) {
|
||||
const QString progFiles = qEnvironmentVariable(envVar);
|
||||
path.append(Utils::FilePath::fromString(progFiles + "/CMake"));
|
||||
path.append(Utils::FilePath::fromString(progFiles + "/CMake/bin"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -203,7 +203,7 @@ void filteredFlags(const QString &fileName,
|
||||
if (CppTools::ProjectFile::isHeader(CppTools::ProjectFile::classify(fileName)))
|
||||
fileKind = cpp ? CppTools::ProjectFile::CXXHeader : CppTools::ProjectFile::CHeader;
|
||||
else
|
||||
fileKind = cpp ? CppTools::ProjectFile::CXXSource : CppTools::ProjectFile::CXXHeader;
|
||||
fileKind = cpp ? CppTools::ProjectFile::CXXSource : CppTools::ProjectFile::CSource;
|
||||
}
|
||||
|
||||
// Skip all remaining Windows flags except feature flags.
|
||||
|
@@ -62,6 +62,7 @@ public:
|
||||
QString settingsKey;
|
||||
|
||||
bool enforceNewline = false;
|
||||
bool prependCarriageReturn = false;
|
||||
bool scrollToBottom = true;
|
||||
bool linksActive = true;
|
||||
bool zoomEnabled = false;
|
||||
@@ -390,7 +391,16 @@ int OutputWindow::maxCharCount() const
|
||||
|
||||
void OutputWindow::appendMessage(const QString &output, OutputFormat format)
|
||||
{
|
||||
QString out = SynchronousProcess::normalizeNewlines(output);
|
||||
QString out = output;
|
||||
if (d->prependCarriageReturn) {
|
||||
d->prependCarriageReturn = false;
|
||||
out.prepend('\r');
|
||||
}
|
||||
out = SynchronousProcess::normalizeNewlines(out);
|
||||
if (out.endsWith('\r')) {
|
||||
d->prependCarriageReturn = true;
|
||||
out.chop(1);
|
||||
}
|
||||
|
||||
if (out.size() > d->maxCharCount) {
|
||||
// Current line alone exceeds limit, we need to cut it.
|
||||
@@ -435,20 +445,22 @@ void OutputWindow::appendMessage(const QString &output, OutputFormat format)
|
||||
} else {
|
||||
newline = out.indexOf(QLatin1Char('\n'));
|
||||
moveCursor(QTextCursor::End);
|
||||
if (newline != -1 && d->formatter)
|
||||
d->formatter->appendMessage(out.left(newline), format);// doesn't enforce new paragraph like appendPlainText
|
||||
if (newline != -1) {
|
||||
if (d->formatter)
|
||||
d->formatter->appendMessage(out.left(newline), format);// doesn't enforce new paragraph like appendPlainText
|
||||
out = out.mid(newline);
|
||||
}
|
||||
}
|
||||
|
||||
QString s = out.mid(newline+1);
|
||||
if (s.isEmpty()) {
|
||||
if (out.isEmpty()) {
|
||||
d->enforceNewline = true;
|
||||
} else {
|
||||
if (s.endsWith(QLatin1Char('\n'))) {
|
||||
if (out.endsWith(QLatin1Char('\n'))) {
|
||||
d->enforceNewline = true;
|
||||
s.chop(1);
|
||||
out.chop(1);
|
||||
}
|
||||
if (d->formatter)
|
||||
d->formatter->appendMessage(s, format);
|
||||
d->formatter->appendMessage(out, format);
|
||||
}
|
||||
} else {
|
||||
if (d->formatter)
|
||||
@@ -502,6 +514,7 @@ bool OutputWindow::isScrollbarAtBottom() const
|
||||
void OutputWindow::clear()
|
||||
{
|
||||
d->enforceNewline = false;
|
||||
d->prependCarriageReturn = false;
|
||||
QPlainTextEdit::clear();
|
||||
if (d->formatter)
|
||||
d->formatter->clear();
|
||||
|
@@ -2114,7 +2114,10 @@ GlobalBreakpointItem::GlobalBreakpointItem()
|
||||
}
|
||||
|
||||
GlobalBreakpointItem::~GlobalBreakpointItem()
|
||||
{}
|
||||
{
|
||||
delete m_marker;
|
||||
m_marker = nullptr;
|
||||
}
|
||||
|
||||
QVariant GlobalBreakpointItem::data(int column, int role) const
|
||||
{
|
||||
@@ -2414,8 +2417,6 @@ BreakpointManager::BreakpointManager()
|
||||
this, &BreakpointManager::loadSessionData);
|
||||
connect(SessionManager::instance(), &SessionManager::aboutToSaveSession,
|
||||
this, &BreakpointManager::saveSessionData);
|
||||
connect(SessionManager::instance(), &SessionManager::aboutToUnloadSession,
|
||||
this, &BreakpointManager::aboutToUnloadSession);
|
||||
}
|
||||
|
||||
QAbstractItemModel *BreakpointManager::model()
|
||||
@@ -2797,12 +2798,6 @@ void BreakpointManager::saveSessionData()
|
||||
SessionManager::setValue("Breakpoints", list);
|
||||
}
|
||||
|
||||
void BreakpointManager::aboutToUnloadSession()
|
||||
{
|
||||
saveSessionData();
|
||||
clear();
|
||||
}
|
||||
|
||||
void BreakpointManager::loadSessionData()
|
||||
{
|
||||
clear();
|
||||
|
@@ -312,7 +312,6 @@ private:
|
||||
|
||||
void loadSessionData();
|
||||
void saveSessionData();
|
||||
void aboutToUnloadSession();
|
||||
|
||||
bool contextMenuEvent(const Utils::ItemViewEvent &ev);
|
||||
void gotoLocation(const GlobalBreakpoint &gbp) const;
|
||||
|
@@ -262,8 +262,7 @@ void QmlInspectorAgent::onResult(quint32 queryId, const QVariant &value,
|
||||
if (index < 0) {
|
||||
if (QTC_GUARD(m_qmlEngine))
|
||||
m_qmlEngine->expressionEvaluated(queryId, value);
|
||||
} else {
|
||||
Q_ASSERT(index < m_engines.length());
|
||||
} else if (QTC_GUARD(index < m_engines.length())) {
|
||||
const int engineId = m_engines.at(index).debugId();
|
||||
m_rootContexts.insert(engineId, qvariant_cast<ContextReference>(value));
|
||||
if (m_rootContexts.size() == m_engines.size()) {
|
||||
@@ -373,7 +372,7 @@ void QmlInspectorAgent::reloadEngines()
|
||||
|
||||
void QmlInspectorAgent::queryEngineContext()
|
||||
{
|
||||
qCDebug(qmlInspectorLog) << __FUNCTION__;
|
||||
qCDebug(qmlInspectorLog) << __FUNCTION__ << "pending queries:" << m_rootContextQueryIds;
|
||||
|
||||
if (!isConnected() || !boolSetting(ShowQmlObjectTree))
|
||||
return;
|
||||
@@ -381,6 +380,7 @@ void QmlInspectorAgent::queryEngineContext()
|
||||
log(LogSend, "LIST_OBJECTS");
|
||||
|
||||
m_rootContexts.clear();
|
||||
m_rootContextQueryIds.clear();
|
||||
for (const auto &engine : qAsConst(m_engines))
|
||||
m_rootContextQueryIds.append(m_engineClient->queryRootContexts(engine));
|
||||
}
|
||||
|
@@ -261,6 +261,19 @@ void McuTarget::setColorDepth(int colorDepth)
|
||||
m_colorDepth = colorDepth;
|
||||
}
|
||||
|
||||
static QString findInProgramFiles(const QString &folder)
|
||||
{
|
||||
for (auto envVar : {"ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"}) {
|
||||
if (!qEnvironmentVariableIsSet(envVar))
|
||||
continue;
|
||||
const Utils::FilePath dir =
|
||||
Utils::FilePath::fromUserInput(qEnvironmentVariable(envVar) + "/" + folder);
|
||||
if (dir.exists())
|
||||
return dir.toString();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static McuPackage *createQtForMCUsPackage()
|
||||
{
|
||||
auto result = new McuPackage(
|
||||
@@ -280,8 +293,7 @@ static McuPackage *createArmGccPackage()
|
||||
if (qEnvironmentVariableIsSet(envVar))
|
||||
defaultPath = qEnvironmentVariable(envVar);
|
||||
if (defaultPath.isEmpty() && Utils::HostOsInfo::isWindowsHost()) {
|
||||
const QDir installDir(
|
||||
qEnvironmentVariable("ProgramFiles(x86)") + "/GNU Tools ARM Embedded/");
|
||||
const QDir installDir(findInProgramFiles("/GNU Tools ARM Embedded/"));
|
||||
if (installDir.exists()) {
|
||||
// If GNU Tools installation dir has only one sub dir,
|
||||
// select the sub dir, otherwise the installation dir.
|
||||
@@ -320,11 +332,14 @@ static McuPackage *createStm32CubeFwF7SdkPackage()
|
||||
|
||||
static McuPackage *createStm32CubeProgrammerPackage()
|
||||
{
|
||||
const QString defaultPath =
|
||||
Utils::HostOsInfo::isWindowsHost() ?
|
||||
QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles"))
|
||||
+ "/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
|
||||
: QDir::homePath();
|
||||
|
||||
QString defaultPath = QDir::homePath();
|
||||
if (Utils::HostOsInfo::isWindowsHost()) {
|
||||
const QString programPath =
|
||||
findInProgramFiles("/STMicroelectronics/STM32Cube/STM32CubeProgrammer/");
|
||||
if (!programPath.isEmpty())
|
||||
defaultPath = programPath;
|
||||
}
|
||||
auto result = new McuPackage(
|
||||
McuPackage::tr("STM32CubeProgrammer"),
|
||||
defaultPath,
|
||||
@@ -351,11 +366,12 @@ static McuPackage *createEvkbImxrt1050SdkPackage()
|
||||
|
||||
static McuPackage *createSeggerJLinkPackage()
|
||||
{
|
||||
const QString defaultPath =
|
||||
Utils::HostOsInfo::isWindowsHost() ?
|
||||
QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles(x86)"))
|
||||
+ "/SEGGER/JLink"
|
||||
: QString("%{Env:SEGGER_JLINK_SOFTWARE_AND_DOCUMENTATION_PATH}");
|
||||
QString defaultPath = QString("%{Env:SEGGER_JLINK_SOFTWARE_AND_DOCUMENTATION_PATH}");
|
||||
if (Utils::HostOsInfo::isWindowsHost()) {
|
||||
const QString programPath = findInProgramFiles("/SEGGER/JLink");
|
||||
if (!programPath.isEmpty())
|
||||
defaultPath = programPath;
|
||||
}
|
||||
auto result = new McuPackage(
|
||||
McuPackage::tr("SEGGER JLink"),
|
||||
defaultPath,
|
||||
@@ -471,6 +487,13 @@ static bool mcuTargetIsDesktop(const McuTarget* mcuTarget)
|
||||
return mcuTarget->qulPlatform() == "Qt";
|
||||
}
|
||||
|
||||
static Utils::FilePath jomExecutablePath()
|
||||
{
|
||||
return Utils::HostOsInfo::isWindowsHost() ?
|
||||
Utils::FilePath::fromUserInput(Core::ICore::libexecPath() + "/jom.exe")
|
||||
: Utils::FilePath();
|
||||
}
|
||||
|
||||
static void setKitProperties(const QString &kitName, ProjectExplorer::Kit *k,
|
||||
const McuTarget* mcuTarget)
|
||||
{
|
||||
@@ -484,9 +507,13 @@ static void setKitProperties(const QString &kitName, ProjectExplorer::Kit *k,
|
||||
if (mcuTargetIsDesktop(mcuTarget)) {
|
||||
k->setDeviceTypeForIcon(Constants::DEVICE_TYPE);
|
||||
} else {
|
||||
k->setIrrelevantAspects({SysRootKitAspect::id(),
|
||||
"QtSupport.QtInformation" // QtKitAspect::id()
|
||||
});
|
||||
QSet<Core::Id> irrelevant = {
|
||||
SysRootKitAspect::id(),
|
||||
"QtSupport.QtInformation" // QtKitAspect::id()
|
||||
};
|
||||
if (jomExecutablePath().exists()) // TODO: add id() getter to CMakeGeneratorKitAspect
|
||||
irrelevant.insert("CMake.GeneratorKitInformation");
|
||||
k->setIrrelevantAspects(irrelevant);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,10 +575,9 @@ static void setKitEnvironment(ProjectExplorer::Kit *k, const McuTarget* mcuTarge
|
||||
QDir::toNativeSeparators(package->path())});
|
||||
}
|
||||
pathAdditions.append("${Path}");
|
||||
if (Utils::HostOsInfo::isWindowsHost())
|
||||
pathAdditions.append(QDir::toNativeSeparators(Core::ICore::libexecPath())); // for jom
|
||||
pathAdditions.append(QDir::toNativeSeparators(Core::ICore::libexecPath() + "/clang/bin"));
|
||||
changes.append({"Path", pathAdditions.join(Utils::HostOsInfo::pathListSeparator())});
|
||||
const QString path = QLatin1String(Utils::HostOsInfo().isWindowsHost() ? "Path" : "PATH");
|
||||
changes.append({path, pathAdditions.join(Utils::HostOsInfo::pathListSeparator())});
|
||||
EnvironmentKitAspect::setEnvironmentChanges(k, changes);
|
||||
}
|
||||
|
||||
@@ -574,9 +600,12 @@ static void setKitCMakeOptions(ProjectExplorer::Kit *k, const McuTarget* mcuTarg
|
||||
if (mcuTarget->colorDepth() >= 0)
|
||||
config.append(CMakeConfigItem("QUL_COLOR_DEPTH",
|
||||
QString::number(mcuTarget->colorDepth()).toLatin1()));
|
||||
CMakeConfigurationKitAspect::setConfiguration(k, config);
|
||||
if (Utils::HostOsInfo::isWindowsHost())
|
||||
const Utils::FilePath jom = jomExecutablePath();
|
||||
if (jom.exists()) {
|
||||
config.append(CMakeConfigItem("CMAKE_MAKE_PROGRAM", jom.toString().toLatin1()));
|
||||
CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM");
|
||||
}
|
||||
CMakeConfigurationKitAspect::setConfiguration(k, config);
|
||||
}
|
||||
|
||||
QString McuSupportOptions::kitName(const McuTarget *mcuTarget) const
|
||||
|
@@ -27,6 +27,8 @@
|
||||
#include "mcusupportoptionspage.h"
|
||||
#include "mcusupportoptions.h"
|
||||
|
||||
#include <cmakeprojectmanager/cmakeprojectconstants.h>
|
||||
#include <cmakeprojectmanager/cmaketoolmanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
@@ -36,6 +38,7 @@
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDir>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
@@ -44,6 +47,11 @@
|
||||
namespace McuSupport {
|
||||
namespace Internal {
|
||||
|
||||
static bool cMakeAvailable()
|
||||
{
|
||||
return !CMakeProjectManager::CMakeToolManager::cmakeTools().isEmpty();
|
||||
}
|
||||
|
||||
class McuSupportOptionsWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
@@ -53,12 +61,16 @@ public:
|
||||
void showMcuTargetPackages();
|
||||
McuTarget *currentMcuTarget() const;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
QString m_armGccPath;
|
||||
const McuSupportOptions *m_options;
|
||||
QMap <McuPackage*, QWidget*> m_packageWidgets;
|
||||
QMap <McuTarget*, QWidget*> m_mcuTargetPacketWidgets;
|
||||
QFormLayout *m_packagesLayout = nullptr;
|
||||
QLabel *m_statusIcon = nullptr;
|
||||
QLabel *m_statusLabel = nullptr;
|
||||
QComboBox *m_mcuTargetComboBox = nullptr;
|
||||
};
|
||||
@@ -87,17 +99,29 @@ McuSupportOptionsWidget::McuSupportOptionsWidget(const McuSupportOptions *option
|
||||
m_packagesLayout = new QFormLayout;
|
||||
m_packagesGroupBox->setLayout(m_packagesLayout);
|
||||
|
||||
m_statusIcon = new QLabel;
|
||||
m_statusIcon->setAlignment(Qt::AlignBottom);
|
||||
m_statusLabel = new QLabel;
|
||||
mainLayout->addWidget(m_statusLabel, 2);
|
||||
m_statusLabel->setWordWrap(true);
|
||||
m_statusLabel->setAlignment(Qt::AlignBottom | Qt::AlignLeft);
|
||||
m_statusLabel->setOpenExternalLinks(false);
|
||||
auto statusWidget = new QWidget;
|
||||
auto statusLayout = new QHBoxLayout(statusWidget);
|
||||
statusLayout->setMargin(0);
|
||||
statusLayout->addWidget(m_statusIcon, 0);
|
||||
statusLayout->addWidget(m_statusLabel, 2);
|
||||
mainLayout->addWidget(statusWidget, 2);
|
||||
|
||||
connect(options, &McuSupportOptions::changed, this, &McuSupportOptionsWidget::updateStatus);
|
||||
connect(m_mcuTargetComboBox, &QComboBox::currentTextChanged,
|
||||
this, &McuSupportOptionsWidget::showMcuTargetPackages);
|
||||
connect(m_statusLabel, &QLabel::linkActivated, this, []{
|
||||
Core::ICore::showOptionsDialog(
|
||||
CMakeProjectManager::Constants::CMAKE_SETTINGSPAGE_ID,
|
||||
Core::ICore::mainWindow());
|
||||
});
|
||||
|
||||
showMcuTargetPackages();
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
void McuSupportOptionsWidget::updateStatus()
|
||||
@@ -106,12 +130,22 @@ void McuSupportOptionsWidget::updateStatus()
|
||||
if (!mcuTarget)
|
||||
return;
|
||||
|
||||
m_statusLabel->setText(mcuTarget->isValid()
|
||||
static const QPixmap okIcon = Utils::Icons::OK.pixmap();
|
||||
static const QPixmap notOkIcon = Utils::Icons::BROKEN.pixmap();
|
||||
m_statusIcon->setPixmap(cMakeAvailable() && mcuTarget->isValid() ? okIcon : notOkIcon);
|
||||
|
||||
QStringList errorStrings;
|
||||
if (!mcuTarget->isValid())
|
||||
errorStrings << "Provide the package paths in order to create a kit for your target.";
|
||||
if (!cMakeAvailable())
|
||||
errorStrings << "No CMake tool was detected. Add a CMake tool in the "
|
||||
"<a href=\"cmake\">CMake options</a> and press Apply.";
|
||||
|
||||
m_statusLabel->setText(errorStrings.isEmpty()
|
||||
? QString::fromLatin1("A kit <b>%1</b> for the selected target can be generated. "
|
||||
"Press Apply to generate it.").arg(m_options->kitName(
|
||||
mcuTarget))
|
||||
: QString::fromLatin1("Provide the package paths in order to create a kit for "
|
||||
"your target."));
|
||||
: errorStrings.join("<br/>"));
|
||||
}
|
||||
|
||||
void McuSupportOptionsWidget::showMcuTargetPackages()
|
||||
@@ -143,6 +177,12 @@ McuTarget *McuSupportOptionsWidget::currentMcuTarget() const
|
||||
return m_options->mcuTargets.isEmpty() ? nullptr : m_options->mcuTargets.at(mcuTargetIndex);
|
||||
}
|
||||
|
||||
void McuSupportOptionsWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
McuSupportOptionsPage::McuSupportOptionsPage(QObject* parent)
|
||||
: Core::IOptionsPage(parent)
|
||||
{
|
||||
@@ -168,8 +208,8 @@ void McuSupportOptionsPage::apply()
|
||||
QTC_ASSERT(m_options->armGccPackage, return);
|
||||
QTC_ASSERT(m_options->qtForMCUsSdkPackage, return);
|
||||
|
||||
if (!widget()->isVisible())
|
||||
return; // Only create/overwrite kits when this option page is shown
|
||||
if (!widget()->isVisible() || !cMakeAvailable())
|
||||
return;
|
||||
|
||||
const McuTarget *mcuTarget = m_widget->currentMcuTarget();
|
||||
if (!mcuTarget)
|
||||
|
@@ -42,12 +42,16 @@ using namespace Utils;
|
||||
namespace McuSupport {
|
||||
namespace Internal {
|
||||
|
||||
static CommandLine flashAndRunCommand(Target *target)
|
||||
static FilePath cmakeFilePath(const Target *target)
|
||||
{
|
||||
const QString projectName = target->project()->displayName();
|
||||
|
||||
const CMakeProjectManager::CMakeTool *tool =
|
||||
CMakeProjectManager::CMakeKitAspect::cmakeTool(target->kit());
|
||||
return tool->filePath();
|
||||
}
|
||||
|
||||
static QStringList flashAndRunArgs(const Target *target)
|
||||
{
|
||||
const QString projectName = target->project()->displayName();
|
||||
|
||||
// TODO: Hack! Implement flash target name handling, properly
|
||||
const QString targetName =
|
||||
@@ -55,23 +59,19 @@ static CommandLine flashAndRunCommand(Target *target)
|
||||
? QString("flash_%1").arg(projectName)
|
||||
: QString("flash_%1_and_bootloader").arg(projectName);
|
||||
|
||||
return CommandLine(tool->filePath(), {
|
||||
"--build",
|
||||
".",
|
||||
"--target",
|
||||
targetName
|
||||
});
|
||||
return {"--build", ".", "--target", targetName};
|
||||
}
|
||||
|
||||
FlashAndRunConfiguration::FlashAndRunConfiguration(Target *target, Core::Id id)
|
||||
: RunConfiguration(target, id)
|
||||
{
|
||||
auto effectiveFlashAndRunCall = addAspect<BaseStringAspect>();
|
||||
effectiveFlashAndRunCall->setLabelText(tr("Effective flash and run call:"));
|
||||
effectiveFlashAndRunCall->setDisplayStyle(BaseStringAspect::TextEditDisplay);
|
||||
auto flashAndRunParameters = addAspect<BaseStringAspect>();
|
||||
flashAndRunParameters->setLabelText("Flash and run CMake parameters:");
|
||||
flashAndRunParameters->setDisplayStyle(BaseStringAspect::TextEditDisplay);
|
||||
flashAndRunParameters->setSettingsKey("FlashAndRunConfiguration.Parameters");
|
||||
|
||||
setUpdater([target, effectiveFlashAndRunCall] {
|
||||
effectiveFlashAndRunCall->setValue(flashAndRunCommand(target).toUserOutput());
|
||||
setUpdater([target, flashAndRunParameters] {
|
||||
flashAndRunParameters->setValue(flashAndRunArgs(target).join(' '));
|
||||
});
|
||||
|
||||
update();
|
||||
@@ -86,8 +86,11 @@ public:
|
||||
: SimpleTargetRunner(runControl)
|
||||
{
|
||||
setStarter([this, runControl] {
|
||||
ProjectExplorer::Target *target = runControl->target();
|
||||
const CommandLine cmd = flashAndRunCommand(target);
|
||||
const Target *target = runControl->target();
|
||||
const CommandLine cmd(
|
||||
cmakeFilePath(target),
|
||||
runControl->runConfiguration()->aspect<BaseStringAspect>()->value(),
|
||||
CommandLine::Raw);
|
||||
Runnable r;
|
||||
r.workingDirectory =
|
||||
target->activeBuildConfiguration()->buildDirectory().toUserOutput();
|
||||
|
@@ -1178,7 +1178,7 @@ static QString wrappedMakeCommand(const QString &command)
|
||||
return command;
|
||||
QTextStream stream(&wrapper);
|
||||
stream << "chcp 65001\n";
|
||||
stream << command << " %*";
|
||||
stream << "\"" << QDir::toNativeSeparators(command) << "\" %*";
|
||||
|
||||
return wrapperPath;
|
||||
}
|
||||
|
@@ -25,6 +25,11 @@
|
||||
\" <comment>Python source file without console</comment>\",
|
||||
\" <glob pattern=\'*.pyw\'/>\",
|
||||
\" </mime-type>\",
|
||||
\" <mime-type type=\'text/x-python-interface\'>\",
|
||||
\" <sub-class-of type=\'text/x-python\'/>\",
|
||||
\" <comment>Python module interface file</comment>\",
|
||||
\" <glob pattern=\'*.pyi\'/>\",
|
||||
\" </mime-type>\",
|
||||
\" <mime-type type=\'text/x-python-project\'>\",
|
||||
\" <sub-class-of type=\'text/x-python\'/>\",
|
||||
\" <comment>Qt Creator Python project file</comment>\",
|
||||
|
@@ -193,6 +193,21 @@ PythonProject::PythonProject(const FilePath &fileName)
|
||||
setBuildSystemCreator([](Target *t) { return new PythonBuildSystem(t); });
|
||||
}
|
||||
|
||||
static FileType getFileType(const FilePath &f)
|
||||
{
|
||||
if (f.endsWith(".py"))
|
||||
return FileType::Source;
|
||||
if (f.endsWith(".pyproject") || f.endsWith(".pyqtc"))
|
||||
return FileType::Project;
|
||||
if (f.endsWith(".qrc"))
|
||||
return FileType::Resource;
|
||||
if (f.endsWith(".ui"))
|
||||
return FileType::Form;
|
||||
if (f.endsWith(".qml") || f.endsWith(".js"))
|
||||
return FileType::QML;
|
||||
return Node::fileTypeForFileName(f);
|
||||
}
|
||||
|
||||
void PythonBuildSystem::triggerParsing()
|
||||
{
|
||||
ParseGuard guard = guardParsingRun();
|
||||
@@ -205,13 +220,7 @@ void PythonBuildSystem::triggerParsing()
|
||||
for (const QString &f : qAsConst(m_files)) {
|
||||
const QString displayName = baseDir.relativeFilePath(f);
|
||||
const FilePath filePath = FilePath::fromString(f);
|
||||
FileType fileType;
|
||||
if (f.endsWith(".py"))
|
||||
fileType = FileType::Source;
|
||||
else if (f.endsWith(".pyproject") || f.endsWith(".pyqtc"))
|
||||
fileType = FileType::Project;
|
||||
else
|
||||
fileType = Node::fileTypeForFileName(filePath);
|
||||
const FileType fileType = getFileType(filePath);
|
||||
|
||||
newRoot->addNestedNode(std::make_unique<PythonFileNode>(filePath, displayName, fileType));
|
||||
if (fileType == FileType::Source) {
|
||||
|
@@ -32,6 +32,9 @@
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <qtsupport/baseqtversion.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
|
||||
#include <resourceeditor/resourcenode.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -409,11 +412,16 @@ bool QmakeProFileNode::setData(Core::Id role, const QVariant &value) const
|
||||
QmakeProFile *pro = proFile();
|
||||
if (!pro)
|
||||
return false;
|
||||
|
||||
const QString arch = pro->singleVariableValue(Variable::AndroidArch);
|
||||
const QString scope = "contains(ANDROID_TARGET_ARCH," + arch + ')';
|
||||
auto flags = QmakeProjectManager::Internal::ProWriter::ReplaceValues
|
||||
| QmakeProjectManager::Internal::ProWriter::MultiLine;
|
||||
QString scope;
|
||||
int flags = QmakeProjectManager::Internal::ProWriter::ReplaceValues;
|
||||
if (Target *target = m_buildSystem->target()) {
|
||||
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit());
|
||||
if (version && version->qtVersion() < QtSupport::QtVersionNumber(5, 14, 0)) {
|
||||
const QString arch = pro->singleVariableValue(Variable::AndroidArch);
|
||||
scope = "contains(ANDROID_TARGET_ARCH," + arch + ')';
|
||||
flags |= QmakeProjectManager::Internal::ProWriter::MultiLine;
|
||||
}
|
||||
}
|
||||
|
||||
if (role == Android::Constants::AndroidExtraLibs)
|
||||
return pro->setProVariable("ANDROID_EXTRA_LIBS", value.toStringList(), scope, flags);
|
||||
|
@@ -722,8 +722,8 @@ void QMakeStepConfigWidget::updateSummaryLabel()
|
||||
item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||
item->setCheckState(Qt::Unchecked);
|
||||
isAndroid = isAndroid && abi.osFlavor() == Abi::OSFlavor::AndroidLinuxFlavor;
|
||||
if (isAndroid && (item->text() == "arm64-v8a" ||
|
||||
(m_preferredAbiIndex == -1 && item->text() == "armeabi-v7a"))) {
|
||||
if (isAndroid && (item->text() == "armeabi-v7a" ||
|
||||
(m_preferredAbiIndex == -1 && item->text() == "arm64-v8a"))) {
|
||||
m_preferredAbiIndex = abisListWidget->count() - 1;
|
||||
}
|
||||
}
|
||||
|
@@ -140,6 +140,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
valueschangedcommand.cpp valueschangedcommand.h
|
||||
changeselectioncommand.cpp changeselectioncommand.h
|
||||
drop3dlibraryitemcommand.cpp drop3dlibraryitemcommand.h
|
||||
change3dviewcommand.cpp change3dviewcommand.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
@@ -234,6 +235,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
snappinglinecreator.cpp snappinglinecreator.h
|
||||
toolbox.cpp toolbox.h
|
||||
option3daction.cpp option3daction.h
|
||||
editview3dproxydialog.cpp editview3dproxydialog.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
@@ -524,6 +526,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX components/bindingeditor
|
||||
SOURCES bindingeditor.cpp bindingeditor.h
|
||||
actioneditor.cpp actioneditor.h
|
||||
bindingeditordialog.cpp bindingeditordialog.h
|
||||
bindingeditorwidget.cpp bindingeditorwidget.h
|
||||
)
|
||||
@@ -624,6 +627,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
detail/keyframeitem.cpp detail/keyframeitem.h
|
||||
detail/playhead.cpp detail/playhead.h
|
||||
detail/selectableitem.cpp detail/selectableitem.h
|
||||
detail/selectionmodel.cpp detail/selectionmodel.h
|
||||
detail/selector.cpp detail/selector.h
|
||||
detail/shortcut.cpp detail/shortcut.h
|
||||
detail/treeitemdelegate.cpp detail/treeitemdelegate.h
|
||||
|
@@ -0,0 +1,131 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "actioneditor.h"
|
||||
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
|
||||
#include <metainfo.h>
|
||||
#include <qmlmodelnodeproxy.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <propertyeditorvalue.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
static ActionEditor *s_lastActionEditor = nullptr;
|
||||
|
||||
ActionEditor::ActionEditor(QObject *)
|
||||
: m_index(QModelIndex())
|
||||
{
|
||||
}
|
||||
|
||||
ActionEditor::~ActionEditor()
|
||||
{
|
||||
hideWidget();
|
||||
}
|
||||
|
||||
void ActionEditor::registerDeclarativeType()
|
||||
{
|
||||
qmlRegisterType<ActionEditor>("HelperWidgets", 2, 0, "ActionEditor");
|
||||
}
|
||||
|
||||
void ActionEditor::showWidget(int x, int y)
|
||||
{
|
||||
if (s_lastActionEditor)
|
||||
s_lastActionEditor->hideWidget();
|
||||
s_lastActionEditor = this;
|
||||
|
||||
m_dialog = new BindingEditorDialog(Core::ICore::dialogParent(),
|
||||
BindingEditorDialog::DialogType::ActionDialog);
|
||||
|
||||
|
||||
QObject::connect(m_dialog, &BindingEditorDialog::accepted,
|
||||
this, &ActionEditor::accepted);
|
||||
QObject::connect(m_dialog, &BindingEditorDialog::rejected,
|
||||
this, &ActionEditor::rejected);
|
||||
|
||||
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m_dialog->showWidget(x, y);
|
||||
m_dialog->activateWindow();
|
||||
}
|
||||
|
||||
void ActionEditor::hideWidget()
|
||||
{
|
||||
if (s_lastActionEditor == this)
|
||||
s_lastActionEditor = nullptr;
|
||||
if (m_dialog)
|
||||
{
|
||||
m_dialog->unregisterAutoCompletion(); //we have to do it separately, otherwise we have an autocompletion action override
|
||||
m_dialog->close();
|
||||
}
|
||||
}
|
||||
|
||||
QString ActionEditor::bindingValue() const
|
||||
{
|
||||
if (!m_dialog)
|
||||
return {};
|
||||
|
||||
return m_dialog->editorValue();
|
||||
}
|
||||
|
||||
void ActionEditor::setBindingValue(const QString &text)
|
||||
{
|
||||
if (m_dialog)
|
||||
m_dialog->setEditorValue(text);
|
||||
}
|
||||
|
||||
bool ActionEditor::hasModelIndex() const
|
||||
{
|
||||
return m_index.isValid();
|
||||
}
|
||||
|
||||
void ActionEditor::resetModelIndex()
|
||||
{
|
||||
m_index = QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex ActionEditor::modelIndex() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
void ActionEditor::setModelIndex(const QModelIndex &index)
|
||||
{
|
||||
m_index = index;
|
||||
}
|
||||
|
||||
void ActionEditor::updateWindowName()
|
||||
{
|
||||
if (!m_dialog.isNull())
|
||||
{
|
||||
m_dialog->setWindowTitle(tr("Action Editor"));
|
||||
m_dialog->raise();
|
||||
}
|
||||
}
|
||||
|
||||
} // QmlDesigner namespace
|
@@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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 https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ACTIONEDITOR_H
|
||||
#define ACTIONEDITOR_H
|
||||
|
||||
#include <bindingeditor/bindingeditordialog.h>
|
||||
#include <qmldesignercorelib_global.h>
|
||||
#include <modelnode.h>
|
||||
|
||||
#include <QtQml>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ActionEditor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString text READ bindingValue WRITE setBindingValue)
|
||||
|
||||
public:
|
||||
ActionEditor(QObject *parent = nullptr);
|
||||
~ActionEditor();
|
||||
|
||||
static void registerDeclarativeType();
|
||||
|
||||
Q_INVOKABLE void showWidget(int x, int y);
|
||||
Q_INVOKABLE void hideWidget();
|
||||
|
||||
QString bindingValue() const;
|
||||
void setBindingValue(const QString &text);
|
||||
|
||||
bool hasModelIndex() const;
|
||||
void resetModelIndex();
|
||||
QModelIndex modelIndex() const;
|
||||
void setModelIndex(const QModelIndex &index);
|
||||
|
||||
Q_INVOKABLE void updateWindowName();
|
||||
|
||||
signals:
|
||||
void accepted();
|
||||
void rejected();
|
||||
|
||||
private:
|
||||
QVariant backendValue() const;
|
||||
QVariant modelNodeBackend() const;
|
||||
QVariant stateModelNode() const;
|
||||
|
||||
private:
|
||||
QPointer<BindingEditorDialog> m_dialog;
|
||||
QModelIndex m_index;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
QML_DECLARE_TYPE(QmlDesigner::ActionEditor)
|
||||
|
||||
#endif //ACTIONEDITOR_H
|
@@ -1,7 +1,9 @@
|
||||
HEADERS += $$PWD/bindingeditor.h
|
||||
HEADERS += $$PWD/actioneditor.h
|
||||
HEADERS += $$PWD/bindingeditordialog.h
|
||||
HEADERS += $$PWD/bindingeditorwidget.h
|
||||
|
||||
SOURCES += $$PWD/bindingeditor.cpp
|
||||
SOURCES += $$PWD/actioneditor.cpp
|
||||
SOURCES += $$PWD/bindingeditordialog.cpp
|
||||
SOURCES += $$PWD/bindingeditorwidget.cpp
|
||||
|
@@ -41,10 +41,12 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
BindingEditorDialog::BindingEditorDialog(QWidget *parent)
|
||||
BindingEditorDialog::BindingEditorDialog(QWidget *parent, DialogType type)
|
||||
: QDialog(parent)
|
||||
, m_dialogType(type)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setWindowFlag(Qt::Tool, true);
|
||||
setWindowTitle(defaultTitle());
|
||||
setModal(false);
|
||||
|
||||
@@ -58,12 +60,14 @@ BindingEditorDialog::BindingEditorDialog(QWidget *parent)
|
||||
QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked,
|
||||
this, &BindingEditorDialog::accepted);
|
||||
|
||||
QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &BindingEditorDialog::itemIDChanged);
|
||||
QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &BindingEditorDialog::propertyIDChanged);
|
||||
QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
|
||||
this, &BindingEditorDialog::textChanged);
|
||||
if (m_dialogType == DialogType::BindingDialog) {
|
||||
QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &BindingEditorDialog::itemIDChanged);
|
||||
QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &BindingEditorDialog::propertyIDChanged);
|
||||
QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
|
||||
this, &BindingEditorDialog::textChanged);
|
||||
}
|
||||
}
|
||||
|
||||
BindingEditorDialog::~BindingEditorDialog()
|
||||
@@ -185,10 +189,12 @@ void BindingEditorDialog::setupJSEditor()
|
||||
void BindingEditorDialog::setupUIComponents()
|
||||
{
|
||||
m_verticalLayout = new QVBoxLayout(this);
|
||||
m_comboBoxLayout = new QHBoxLayout;
|
||||
|
||||
m_comboBoxItem = new QComboBox(this);
|
||||
m_comboBoxProperty = new QComboBox(this);
|
||||
if (m_dialogType == DialogType::BindingDialog) {
|
||||
m_comboBoxLayout = new QHBoxLayout;
|
||||
m_comboBoxItem = new QComboBox(this);
|
||||
m_comboBoxProperty = new QComboBox(this);
|
||||
}
|
||||
|
||||
m_editorWidget->setParent(this);
|
||||
m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
|
||||
@@ -199,11 +205,11 @@ void BindingEditorDialog::setupUIComponents()
|
||||
m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
|
||||
|
||||
|
||||
m_comboBoxLayout->addWidget(m_comboBoxItem);
|
||||
m_comboBoxLayout->addWidget(m_comboBoxProperty);
|
||||
|
||||
m_verticalLayout->addLayout(m_comboBoxLayout);
|
||||
if (m_dialogType == DialogType::BindingDialog) {
|
||||
m_comboBoxLayout->addWidget(m_comboBoxItem);
|
||||
m_comboBoxLayout->addWidget(m_comboBoxProperty);
|
||||
m_verticalLayout->addLayout(m_comboBoxLayout);
|
||||
}
|
||||
m_verticalLayout->addWidget(m_editorWidget);
|
||||
m_verticalLayout->addWidget(m_buttonBox);
|
||||
|
||||
|
@@ -57,8 +57,14 @@ public:
|
||||
QStringList properties;
|
||||
};
|
||||
|
||||
enum DialogType {
|
||||
Unknown = 0,
|
||||
BindingDialog = 1,
|
||||
ActionDialog = 2
|
||||
};
|
||||
|
||||
public:
|
||||
BindingEditorDialog(QWidget *parent = nullptr);
|
||||
BindingEditorDialog(QWidget *parent = nullptr, DialogType type = DialogType::BindingDialog);
|
||||
~BindingEditorDialog() override;
|
||||
|
||||
void showWidget(int x, int y);
|
||||
@@ -84,6 +90,7 @@ public slots:
|
||||
void textChanged();
|
||||
|
||||
private:
|
||||
DialogType m_dialogType = DialogType::BindingDialog;
|
||||
TextEditor::BaseTextEditor *m_editor = nullptr;
|
||||
BindingEditorWidget *m_editorWidget = nullptr;
|
||||
QVBoxLayout *m_verticalLayout = nullptr;
|
||||
|
@@ -47,6 +47,7 @@ QStringList propertyNameListToStringList(const QmlDesigner::PropertyNameList &pr
|
||||
foreach (QmlDesigner::PropertyName propertyName, propertyNameList) {
|
||||
stringList << QString::fromUtf8(propertyName);
|
||||
}
|
||||
stringList.removeDuplicates();
|
||||
return stringList;
|
||||
}
|
||||
|
||||
@@ -127,7 +128,7 @@ void ConnectionModel::addSignalHandler(const SignalHandlerProperty &signalHandle
|
||||
ModelNode connectionsModelNode = signalHandlerProperty.parentModelNode();
|
||||
|
||||
if (connectionsModelNode.bindingProperty("target").isValid()) {
|
||||
idLabel =connectionsModelNode.bindingProperty("target").expression();
|
||||
idLabel = connectionsModelNode.bindingProperty("target").expression();
|
||||
}
|
||||
|
||||
targetItem = new QStandardItem(idLabel);
|
||||
@@ -281,6 +282,12 @@ void ConnectionModel::variantPropertyChanged(const VariantProperty &variantPrope
|
||||
resetModel();
|
||||
}
|
||||
|
||||
void ConnectionModel::abstractPropertyChanged(const AbstractProperty &abstractProperty)
|
||||
{
|
||||
if (isConnection(abstractProperty.parentModelNode()))
|
||||
resetModel();
|
||||
}
|
||||
|
||||
void ConnectionModel::deleteConnectionByRow(int currentRow)
|
||||
{
|
||||
signalHandlerPropertyForRow(currentRow).parentModelNode().destroy();
|
||||
|
@@ -29,6 +29,7 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class AbstractProperty;
|
||||
class ModelNode;
|
||||
class BindingProperty;
|
||||
class SignalHandlerProperty;
|
||||
@@ -59,6 +60,7 @@ public:
|
||||
|
||||
void bindingPropertyChanged(const BindingProperty &bindingProperty);
|
||||
void variantPropertyChanged(const VariantProperty &variantProperty);
|
||||
void abstractPropertyChanged(const AbstractProperty &abstractProperty);
|
||||
|
||||
void deleteConnectionByRow(int currentRow);
|
||||
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include <bindingproperty.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
#include <variantproperty.h>
|
||||
#include <signalhandlerproperty.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
@@ -139,6 +140,13 @@ void ConnectionView::bindingPropertiesChanged(const QList<BindingProperty> &prop
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionView::signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty> &propertyList,
|
||||
AbstractView::PropertyChangeFlags /*propertyChange*/)
|
||||
{
|
||||
for (const SignalHandlerProperty &signalHandlerProperty : propertyList)
|
||||
connectionModel()->abstractPropertyChanged(signalHandlerProperty);
|
||||
}
|
||||
|
||||
void ConnectionView::selectedNodesChanged(const QList<ModelNode> & selectedNodeList,
|
||||
const QList<ModelNode> & /*lastSelectedNodeList*/)
|
||||
{
|
||||
|
@@ -65,6 +65,7 @@ public:
|
||||
void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) override;
|
||||
void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange) override;
|
||||
void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange) override;
|
||||
void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty>& propertyList, PropertyChangeFlags propertyChange) override;
|
||||
|
||||
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
|
||||
const QList<ModelNode> &lastSelectedNodeList) override;
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "connectionmodel.h"
|
||||
#include "dynamicpropertiesmodel.h"
|
||||
#include "theme.h"
|
||||
#include "signalhandlerproperty.h"
|
||||
|
||||
#include <designersettings.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
@@ -43,6 +44,9 @@
|
||||
|
||||
#include <QToolButton>
|
||||
#include <QStyleFactory>
|
||||
#include <QMenu>
|
||||
|
||||
#include <bindingeditor/actioneditor.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
@@ -52,6 +56,27 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
|
||||
QFrame(parent),
|
||||
ui(new Ui::ConnectionViewWidget)
|
||||
{
|
||||
m_actionEditor = new QmlDesigner::ActionEditor(this);
|
||||
QObject::connect(m_actionEditor, &QmlDesigner::ActionEditor::accepted,
|
||||
[&]() {
|
||||
if (m_actionEditor->hasModelIndex()) {
|
||||
ConnectionModel *connectionModel = qobject_cast<ConnectionModel *>(ui->connectionView->model());
|
||||
if (connectionModel->rowCount() > m_actionEditor->modelIndex().row())
|
||||
{
|
||||
SignalHandlerProperty signalHandler =
|
||||
connectionModel->signalHandlerPropertyForRow(m_actionEditor->modelIndex().row());
|
||||
signalHandler.setSource(m_actionEditor->bindingValue());
|
||||
}
|
||||
m_actionEditor->resetModelIndex();
|
||||
}
|
||||
|
||||
m_actionEditor->hideWidget();
|
||||
});
|
||||
QObject::connect(m_actionEditor, &QmlDesigner::ActionEditor::rejected,
|
||||
[&]() {
|
||||
m_actionEditor->resetModelIndex();
|
||||
m_actionEditor->hideWidget();
|
||||
});
|
||||
|
||||
setWindowTitle(tr("Connections", "Title of connection view"));
|
||||
ui->setupUi(this);
|
||||
@@ -96,6 +121,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
|
||||
|
||||
ConnectionViewWidget::~ConnectionViewWidget()
|
||||
{
|
||||
delete m_actionEditor;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
@@ -116,9 +142,37 @@ void ConnectionViewWidget::setConnectionModel(ConnectionModel *model)
|
||||
ui->connectionView->horizontalHeader()->setDefaultSectionSize(160);
|
||||
ui->connectionView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
ui->connectionView->setItemDelegate(new ConnectionDelegate);
|
||||
|
||||
connect(ui->connectionView->selectionModel(), &QItemSelectionModel::currentRowChanged,
|
||||
this, &ConnectionViewWidget::connectionTableViewSelectionChanged);
|
||||
}
|
||||
|
||||
void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
if (currentTab() != ConnectionTab || ui->connectionView == nullptr)
|
||||
return;
|
||||
|
||||
//adjusting qpoint to the qtableview entrances:
|
||||
QPoint posInTable(ui->connectionView->mapFromGlobal(mapToGlobal(event->pos())));
|
||||
posInTable = QPoint(posInTable.x(), posInTable.y() - ui->connectionView->horizontalHeader()->height());
|
||||
|
||||
//making sure that we have source column in our hands:
|
||||
QModelIndex index = ui->connectionView->indexAt(posInTable).siblingAtColumn(ConnectionModel::SourceRow);
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
QMenu menu(this);
|
||||
|
||||
menu.addAction(tr("Open Action Editor"), [&]() {
|
||||
if (index.isValid()) {
|
||||
m_actionEditor->showWidget(mapToGlobal(event->pos()).x(), mapToGlobal(event->pos()).y());
|
||||
m_actionEditor->setBindingValue(index.data().toString());
|
||||
m_actionEditor->setModelIndex(index);
|
||||
m_actionEditor->updateWindowName();
|
||||
}
|
||||
});
|
||||
|
||||
menu.exec(event->globalPos());
|
||||
}
|
||||
|
||||
void ConnectionViewWidget::setDynamicPropertiesModel(DynamicPropertiesModel *model)
|
||||
@@ -155,7 +209,6 @@ QList<QToolButton *> ConnectionViewWidget::createToolBarWidgets()
|
||||
buttons << new QToolButton();
|
||||
buttons.constLast()->setIcon(Utils::Icons::MINUS.icon());
|
||||
buttons.constLast()->setToolTip(tr("Remove selected binding or connection."));
|
||||
buttons.constLast()->setShortcut(QKeySequence(Qt::Key_Delete));
|
||||
connect(buttons.constLast(), &QAbstractButton::clicked, this, &ConnectionViewWidget::removeButtonClicked);
|
||||
connect(this, &ConnectionViewWidget::setEnabledRemoveButton, buttons.constLast(), &QWidget::setEnabled);
|
||||
|
||||
|
@@ -38,6 +38,8 @@ namespace QmlDesigner {
|
||||
|
||||
namespace Ui { class ConnectionViewWidget; }
|
||||
|
||||
class ActionEditor;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class BindingModel;
|
||||
@@ -88,6 +90,9 @@ signals:
|
||||
void setEnabledAddButton(bool enabled);
|
||||
void setEnabledRemoveButton(bool enabled);
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
|
||||
private:
|
||||
void handleTabChanged(int i);
|
||||
void removeButtonClicked();
|
||||
@@ -95,6 +100,7 @@ private:
|
||||
|
||||
private:
|
||||
Ui::ConnectionViewWidget *ui;
|
||||
QmlDesigner::ActionEditor *m_actionEditor;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -52,7 +52,7 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
|
||||
box->addWidget(splitter);
|
||||
setLayout(box);
|
||||
|
||||
connect(m_tree, &TreeView::curvesSelected, m_view, &GraphicsView::reset);
|
||||
connect(m_tree->selectionModel(), &SelectionModel::curvesSelected, m_view, &GraphicsView::reset);
|
||||
}
|
||||
|
||||
void CurveEditor::zoomX(double zoom)
|
||||
@@ -67,7 +67,7 @@ void CurveEditor::zoomY(double zoom)
|
||||
|
||||
void CurveEditor::clearCanvas()
|
||||
{
|
||||
m_view->reset(m_tree->selection());
|
||||
m_view->reset({});
|
||||
}
|
||||
|
||||
QToolBar *CurveEditor::createToolBar()
|
||||
|
@@ -14,6 +14,7 @@ HEADERS += \
|
||||
$$PWD/detail/keyframeitem.h \
|
||||
$$PWD/detail/playhead.h \
|
||||
$$PWD/detail/selectableitem.h \
|
||||
$$PWD/detail/selectionmodel.h \
|
||||
$$PWD/detail/selector.h \
|
||||
$$PWD/detail/shortcut.h \
|
||||
$$PWD/detail/treeitemdelegate.h \
|
||||
@@ -36,6 +37,7 @@ SOURCES += \
|
||||
$$PWD/detail/keyframeitem.cpp \
|
||||
$$PWD/detail/playhead.cpp \
|
||||
$$PWD/detail/selectableitem.cpp \
|
||||
$$PWD/detail/selectionmodel.cpp \
|
||||
$$PWD/detail/selector.cpp \
|
||||
$$PWD/detail/shortcut.cpp \
|
||||
$$PWD/detail/treeitemdelegate.cpp \
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "curveeditormodel.h"
|
||||
#include "treeitem.h"
|
||||
#include "detail/graphicsview.h"
|
||||
#include "detail/selectionmodel.h"
|
||||
|
||||
namespace DesignTools {
|
||||
|
||||
@@ -53,7 +54,9 @@ void CurveEditorModel::setCurve(unsigned int id, const AnimationCurve &curve)
|
||||
|
||||
void CurveEditorModel::reset(const std::vector<TreeItem *> &items)
|
||||
{
|
||||
std::vector<TreeItem::Path> sel = selection();
|
||||
std::vector<TreeItem::Path> sel;
|
||||
if (SelectionModel *sm = selectionModel())
|
||||
sel = sm->selectedPaths();
|
||||
|
||||
beginResetModel();
|
||||
|
||||
@@ -67,7 +70,8 @@ void CurveEditorModel::reset(const std::vector<TreeItem *> &items)
|
||||
|
||||
endResetModel();
|
||||
|
||||
select(sel);
|
||||
if (SelectionModel *sm = selectionModel())
|
||||
sm->select(sel);
|
||||
}
|
||||
|
||||
} // End namespace DesignTools.
|
||||
|
@@ -81,6 +81,8 @@ CurveEditorStyleDialog::CurveEditorStyleDialog(CurveEditorStyle &style, QWidget
|
||||
, m_playheadColor(new ColorControl(style.playhead.color))
|
||||
|
||||
{
|
||||
setWindowFlag(Qt::Tool, true);
|
||||
|
||||
m_canvasMargin->setValue(style.canvasMargin);
|
||||
m_zoomInWidth->setValue(style.zoomInWidth);
|
||||
m_zoomInHeight->setValue(style.zoomInHeight);
|
||||
|
@@ -339,6 +339,8 @@ void CurveItem::setInterpolation(Keyframe::Interpolation interpolation)
|
||||
|
||||
void CurveItem::connect(GraphicsScene *scene)
|
||||
{
|
||||
QObject::connect(this, &CurveItem::curveChanged, scene, &GraphicsScene::curveChanged);
|
||||
|
||||
for (auto *frame : m_keyframes) {
|
||||
QObject::connect(frame, &KeyframeItem::keyframeMoved, scene, &GraphicsScene::keyframeMoved);
|
||||
QObject::connect(frame, &KeyframeItem::handleMoved, scene, &GraphicsScene::handleMoved);
|
||||
|
@@ -68,11 +68,8 @@ void GraphicsScene::addCurveItem(CurveItem *item)
|
||||
{
|
||||
m_dirty = true;
|
||||
item->setDirty(false);
|
||||
|
||||
connect(item, &CurveItem::curveChanged, this, &GraphicsScene::curveChanged);
|
||||
|
||||
addItem(item);
|
||||
item->connect(this);
|
||||
addItem(item);
|
||||
}
|
||||
|
||||
void GraphicsScene::setComponentTransform(const QTransform &transform)
|
||||
|
@@ -554,7 +554,7 @@ double GraphicsView::timeLabelInterval(QPainter *painter, double maxTime)
|
||||
double tickDistance = mapTimeToX(deltaTime);
|
||||
|
||||
while (true) {
|
||||
if (tickDistance == 0 && deltaTime > maxTime)
|
||||
if (tickDistance == 0 && deltaTime >= maxTime)
|
||||
return maxTime;
|
||||
|
||||
if (tickDistance > minTextSpacing)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user