Merge remote-tracking branch 'origin/7.0'
Conflicts: src/plugins/webassembly/webassemblyrunconfiguration.cpp src/tools/processlauncher/launchersockethandler.cpp Change-Id: Iab052af98013aa59282c16f22ae6e9ecb32f50c4
@@ -23,7 +23,7 @@ instructions:
|
|||||||
maxTimeBetweenOutput: 360
|
maxTimeBetweenOutput: 360
|
||||||
userMessageOnFailure: "Failed to extract LLVM package, check logs."
|
userMessageOnFailure: "Failed to extract LLVM package, check logs."
|
||||||
- type: ExecuteCommand
|
- type: ExecuteCommand
|
||||||
command: "python -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --elfutils-path {{.AgentWorkingDir}}/build/qt_temp/elfutils --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache"
|
command: "python3 -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --elfutils-path {{.AgentWorkingDir}}/build/qt_temp/elfutils --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache"
|
||||||
maxTimeInSeconds: 36000
|
maxTimeInSeconds: 36000
|
||||||
maxTimeBetweenOutput: 3600
|
maxTimeBetweenOutput: 3600
|
||||||
userMessageOnFailure: "Failed to run build.py, check logs."
|
userMessageOnFailure: "Failed to run build.py, check logs."
|
||||||
@@ -50,7 +50,7 @@ instructions:
|
|||||||
maxTimeBetweenOutput: 360
|
maxTimeBetweenOutput: 360
|
||||||
userMessageOnFailure: "Failed to extract LLVM package, check logs."
|
userMessageOnFailure: "Failed to extract LLVM package, check logs."
|
||||||
- type: ExecuteCommand
|
- type: ExecuteCommand
|
||||||
command: "python -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --keychain-unlock-script /Users/qt/unlock-keychain.sh --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache"
|
command: "python3 -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --keychain-unlock-script /Users/qt/unlock-keychain.sh --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache"
|
||||||
maxTimeInSeconds: 36000
|
maxTimeInSeconds: 36000
|
||||||
maxTimeBetweenOutput: 3600
|
maxTimeBetweenOutput: 3600
|
||||||
userMessageOnFailure: "Failed to run build.py, check logs."
|
userMessageOnFailure: "Failed to run build.py, check logs."
|
||||||
|
@@ -96,7 +96,7 @@ instructions:
|
|||||||
|
|
||||||
- type: PrependToEnvironmentVariable
|
- type: PrependToEnvironmentVariable
|
||||||
variableName: PATH
|
variableName: PATH
|
||||||
variableValue: "{{.InstallDir}}\\bin;"
|
variableValue: "{{.Env.PYTHON3_PATH}};{{.Env.PIP3_PATH}};C:\\Utils\\gnuwin21\\bin;{{.InstallDir}}\\bin;"
|
||||||
enable_if:
|
enable_if:
|
||||||
condition: property
|
condition: property
|
||||||
property: target.os
|
property: target.os
|
||||||
|
@@ -32,7 +32,7 @@ instructions:
|
|||||||
property: host.os
|
property: host.os
|
||||||
in_values: [MacOS, Linux, Windows]
|
in_values: [MacOS, Linux, Windows]
|
||||||
- type: ExecuteCommand
|
- type: ExecuteCommand
|
||||||
command: "python -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} --icu7z http://master.qt.io/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z {{.Env.QTC_QT_MODULES}}"
|
command: "python3 -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} --icu7z http://master.qt.io/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z {{.Env.QTC_QT_MODULES}}"
|
||||||
executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution
|
executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution
|
||||||
maxTimeInSeconds: 3600
|
maxTimeInSeconds: 3600
|
||||||
maxTimeBetweenOutput: 360
|
maxTimeBetweenOutput: 360
|
||||||
@@ -42,7 +42,7 @@ instructions:
|
|||||||
property: host.os
|
property: host.os
|
||||||
equals_value: Linux
|
equals_value: Linux
|
||||||
- type: ExecuteCommand
|
- type: ExecuteCommand
|
||||||
command: "python -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} {{.Env.QTC_QT_MODULES}}"
|
command: "python3 -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} {{.Env.QTC_QT_MODULES}}"
|
||||||
executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution
|
executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution
|
||||||
maxTimeInSeconds: 3600
|
maxTimeInSeconds: 3600
|
||||||
maxTimeBetweenOutput: 360
|
maxTimeBetweenOutput: 360
|
||||||
@@ -52,7 +52,7 @@ instructions:
|
|||||||
property: host.os
|
property: host.os
|
||||||
equals_value: MacOS
|
equals_value: MacOS
|
||||||
- type: ExecuteCommand
|
- type: ExecuteCommand
|
||||||
command: "C:\\Python27\\Scripts\\pip.exe install pywin32"
|
command: "pip.exe install pywin32"
|
||||||
maxTimeInSeconds: 1200
|
maxTimeInSeconds: 1200
|
||||||
maxTimeBetweenOutput: 120
|
maxTimeBetweenOutput: 120
|
||||||
userMessageOnFailure: "Failed to install win32api, check logs."
|
userMessageOnFailure: "Failed to install win32api, check logs."
|
||||||
|
@@ -452,11 +452,10 @@
|
|||||||
The Performance Analyzer can read Perf data files generated in either frame
|
The Performance Analyzer can read Perf data files generated in either frame
|
||||||
pointer or dwarf mode. However, to generate the files correctly, numerous
|
pointer or dwarf mode. However, to generate the files correctly, numerous
|
||||||
preconditions have to be met. All system images for the
|
preconditions have to be met. All system images for the
|
||||||
\l{http://doc.qt.io/QtForDeviceCreation/qtee-supported-platforms.html}
|
\l{https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html}
|
||||||
{Qt for Device Creation reference devices}, except for Freescale iMX53 Quick
|
{Boot2Qt:Supported Target Devices and Development Hosts} are correctly set
|
||||||
Start Board and SILICA Architect Tibidabo, are correctly set up for
|
up for profiling in the dwarf mode. For other devices, check whether Perf
|
||||||
profiling in the dwarf mode. For other devices, check whether Perf can read
|
can read back its own data in a sensible way by checking the output of
|
||||||
back its own data in a sensible way by checking the output of
|
|
||||||
\c {perf report} or \c {perf script} for the recorded Perf data files.
|
\c {perf report} or \c {perf script} for the recorded Perf data files.
|
||||||
|
|
||||||
\section1 Loading and Saving Trace Files
|
\section1 Loading and Saving Trace Files
|
||||||
|
@@ -157,3 +157,15 @@
|
|||||||
\externalpage https://microsoft.github.io/language-server-protocol/
|
\externalpage https://microsoft.github.io/language-server-protocol/
|
||||||
\title Language Server Protocol
|
\title Language Server Protocol
|
||||||
*/
|
*/
|
||||||
|
/*!
|
||||||
|
\externalpage https://docs.microsoft.com/en-us/java/openjdk/download
|
||||||
|
\title Download OpenJDK
|
||||||
|
*/
|
||||||
|
/*!
|
||||||
|
\externalpage https://developer.android.com/studio
|
||||||
|
\title Download Android Studio
|
||||||
|
*/
|
||||||
|
/*!
|
||||||
|
\externalpage https://developer.android.com/studio/install
|
||||||
|
\title Android Studio Installation Guide
|
||||||
|
*/
|
||||||
|
@@ -63,8 +63,8 @@
|
|||||||
\note On Ubuntu Linux, the development user account must have access to
|
\note On Ubuntu Linux, the development user account must have access to
|
||||||
plugged in devices. To allow the development user access to the device
|
plugged in devices. To allow the development user access to the device
|
||||||
via USB, create a new \c udev rule, as described in
|
via USB, create a new \c udev rule, as described in
|
||||||
\l{https://doc.qt.io/QtForDeviceCreation/b2qt-requirements-x11.html#setting-up-usb-access-to-embedded-devices}
|
\l{https://doc.qt.io/Boot2Qt/b2qt-requirements-x11.html#setting-up-usb-access-to-embedded-devices}
|
||||||
{Setting Up USB Access to Embedded Devices}.
|
{Boot2Qt: Setting Up USB Access to Embedded Devices}.
|
||||||
|
|
||||||
You can edit the settings later in \uicontrol Tools > \uicontrol Options >
|
You can edit the settings later in \uicontrol Tools > \uicontrol Options >
|
||||||
\uicontrol Devices > \uicontrol Devices.
|
\uicontrol Devices > \uicontrol Devices.
|
||||||
|
@@ -65,24 +65,22 @@
|
|||||||
license holders, tooling is provided to customize the contents of the stack
|
license holders, tooling is provided to customize the contents of the stack
|
||||||
as well as to take it into desired production hardware.
|
as well as to take it into desired production hardware.
|
||||||
|
|
||||||
Either Windows 7 or later or Ubuntu Linux 64-bit 12.04 LTS
|
Either Windows 10 64-bit or later or Ubuntu Linux 64-bit 20.04 LTS
|
||||||
or later is required to install and use Boot2Qt.
|
or later is required to install and use Boot2Qt.
|
||||||
|
|
||||||
The following topics contain more information about developing applications
|
The following topics contain more information about developing applications
|
||||||
for Boot2Qt devices:
|
for Boot2Qt devices:
|
||||||
|
|
||||||
\list
|
\list
|
||||||
\li \l{https://doc.qt.io/QtForDeviceCreation/qtee-supported-platforms.html}
|
\li \l{https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html}
|
||||||
{Reference Target Devices and Development Hosts}
|
{Boot2Qt: Supported Target Devices and Development Hosts}
|
||||||
\li \l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html}
|
\li \l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html}
|
||||||
{Installation Guides}
|
{Boot2Qt: Installation Guides}
|
||||||
\li \l{Connecting Boot2Qt Devices}
|
\li \l{Connecting Boot2Qt Devices}
|
||||||
\li \l{Specifying Run Settings for Boot2Qt Devices}
|
\li \l{Specifying Run Settings for Boot2Qt Devices}
|
||||||
\li \l{Deploying Applications to Boot2Qt Devices}
|
\li \l{Deploying Applications to Boot2Qt Devices}
|
||||||
\li \l{https://doc.qt.io/qtcreator/creator-overview-qtasam.html}
|
\li \l{https://doc.qt.io/qtcreator/creator-overview-qtasam.html}
|
||||||
{Qt Creator Plugin for Qt Application Manager}
|
{Qt Creator Plugin for Qt Application Manager}
|
||||||
\li \l{https://doc.qt.io/QtForDeviceCreation/index.html}
|
|
||||||
{Qt for Device Creation}
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 Generic Remote Linux
|
\section1 Generic Remote Linux
|
||||||
|
@@ -32,10 +32,8 @@
|
|||||||
must create connections from the development host to the device and add the
|
must create connections from the development host to the device and add the
|
||||||
device configurations to \l{glossary-buildandrun-kit}{kits}. Select
|
device configurations to \l{glossary-buildandrun-kit}{kits}. Select
|
||||||
\uicontrol {Manage Kits} to add devices to kits. For more information, see
|
\uicontrol {Manage Kits} to add devices to kits. For more information, see
|
||||||
the \l{http://doc.qt.io/QtForDeviceCreation/qtee-installation-guide.html}
|
\l{http://doc.qt.io/Boot2Qt/b2qt-installation-guides.html}
|
||||||
{Installation Guide} in the
|
{Boot2Qt: Installation Guide}.
|
||||||
\l{http://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation}
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
The run settings display the path to the executable file on the development
|
The run settings display the path to the executable file on the development
|
||||||
host and on the device.
|
host and on the device.
|
||||||
|
@@ -40,9 +40,8 @@
|
|||||||
\l{http://qt.io/licensing/}{Qt license}:
|
\l{http://qt.io/licensing/}{Qt license}:
|
||||||
|
|
||||||
\list
|
\list
|
||||||
\li \l{http://doc.qt.io/QtForDeviceCreation/index.html}{Developing for
|
\li \l{https://doc.qt.io/Boot2Qt/index.html}{Boot2Qt}
|
||||||
embedded devices}
|
\li \l{https://doc.qt.io/qtcreator/creator-overview-qtasam.html}
|
||||||
\li \l{http://doc.qt.io/qtcreator/creator-overview-qtasam.html}
|
|
||||||
{Qt Application Manager} integration
|
{Qt Application Manager} integration
|
||||||
\endlist
|
\endlist
|
||||||
*/
|
*/
|
||||||
|
@@ -44,12 +44,10 @@
|
|||||||
\l{Connecting Android Devices} and \l{Connecting iOS Devices}.
|
\l{Connecting Android Devices} and \l{Connecting iOS Devices}.
|
||||||
|
|
||||||
To run an example application on a Boot2Qt device, you must set up
|
To run an example application on a Boot2Qt device, you must set up
|
||||||
Qt for Device Creation on the development host and create connections
|
Boot2Qt on the development host and create connections
|
||||||
between the host and devices. For more information, see
|
between the host and devices. For more information, see
|
||||||
\l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html}
|
\l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html}
|
||||||
{Installation Guides} in the
|
{Boot2Qt: Installation Guides}
|
||||||
\l{http://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation}
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
If you have \l{Qt Design Studio Manual}{\QDS} installed, you can open
|
If you have \l{Qt Design Studio Manual}{\QDS} installed, you can open
|
||||||
\QDS examples from \QC in \QDS.
|
\QDS examples from \QC in \QDS.
|
||||||
|
@@ -49,7 +49,7 @@
|
|||||||
\list
|
\list
|
||||||
\li \l{Connecting Android Devices}{Android Device}
|
\li \l{Connecting Android Devices}{Android Device}
|
||||||
\li \l{Connecting Bare Metal Devices}{Bare Metal Device}
|
\li \l{Connecting Bare Metal Devices}{Bare Metal Device}
|
||||||
\li \l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html}
|
\li \l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html}
|
||||||
{Boot2Qt Device} (commercial only)
|
{Boot2Qt Device} (commercial only)
|
||||||
\li \l{Emulator}{Boot2Qt Emulator Device} (commercial only)
|
\li \l{Emulator}{Boot2Qt Emulator Device} (commercial only)
|
||||||
\li \l{Connecting Generic Remote Linux Devices}{Generic Remote Linux Device}
|
\li \l{Connecting Generic Remote Linux Devices}{Generic Remote Linux Device}
|
||||||
|
@@ -24,11 +24,12 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\previouspage creator-live-preview-devices.html
|
|
||||||
\page qt-design-viewer.html
|
\page qt-design-viewer.html
|
||||||
\if defined(qtdesignstudio)
|
\if defined(qtdesignstudio)
|
||||||
|
\previouspage creator-live-preview-android.html
|
||||||
\nextpage studio-exporting-and-importing.html
|
\nextpage studio-exporting-and-importing.html
|
||||||
\else
|
\else
|
||||||
|
\previouspage creator-live-preview-devices.html
|
||||||
\nextpage creator-building-targets.html
|
\nextpage creator-building-targets.html
|
||||||
\endif
|
\endif
|
||||||
|
|
||||||
|
@@ -26,8 +26,11 @@
|
|||||||
/*!
|
/*!
|
||||||
\previouspage creator-live-preview-desktop.html
|
\previouspage creator-live-preview-desktop.html
|
||||||
\page creator-live-preview-devices.html
|
\page creator-live-preview-devices.html
|
||||||
|
\if defined(qtdesignstudio)
|
||||||
|
\nextpage creator-live-preview-android.html
|
||||||
|
\else
|
||||||
\nextpage qt-design-viewer.html
|
\nextpage qt-design-viewer.html
|
||||||
|
\endif
|
||||||
\title Previewing on Devices
|
\title Previewing on Devices
|
||||||
|
|
||||||
To preview UIs on Android devices, you need to enable USB debugging on them
|
To preview UIs on Android devices, you need to enable USB debugging on them
|
||||||
@@ -78,19 +81,17 @@
|
|||||||
|
|
||||||
\section2 Previewing on Boot2Qt Devices
|
\section2 Previewing on Boot2Qt Devices
|
||||||
|
|
||||||
You can preview UIs on Boot2Qt devices that are supported by
|
You can preview UIs on Boot2Qt devices. For a list of supported devices, see
|
||||||
\l{Qt for Device Creation}. For a list of supported devices, see
|
\l{https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html}
|
||||||
\l{https://doc.qt.io/QtForDeviceCreation/qtdc-supported-platforms.html}
|
{Boot2Qt: Supported Target Devices and Development Hosts}.
|
||||||
{Reference Target Devices and Development Hosts}.
|
|
||||||
|
|
||||||
You must configure the device as instructed in the
|
You must configure the device as instructed in the
|
||||||
\l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html}
|
\l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html}
|
||||||
{Installation Guides}.
|
{Boot2Qt: Installation Guides}.
|
||||||
|
|
||||||
\note At the time of this writing, \macos is not supported as a development
|
\note At the time of this writing, \macos is not supported as a development
|
||||||
host for Qt for Device Creation. This means that you cannot preview UIs on
|
host for Boot2Qt. This means that you cannot preview UIs on
|
||||||
devices if you are using \QC on \macos. For more information about
|
devices if you are using \QC on \macos. For more information, see
|
||||||
supported development hosts, see
|
\l {https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html#supported-development-hosts}
|
||||||
\l {https://doc.qt.io/QtForDeviceCreation/qtdc-supported-platforms.html#supported-development-hosts}
|
{Boot2Qt: Supported Development Hosts}.
|
||||||
{Supported Development Hosts}.
|
|
||||||
*/
|
*/
|
||||||
|
@@ -72,6 +72,14 @@
|
|||||||
devices is set up automatically. You only need to connect your
|
devices is set up automatically. You only need to connect your
|
||||||
devices to your system.
|
devices to your system.
|
||||||
\endif
|
\endif
|
||||||
|
|
||||||
|
\if defined(qtdesignstudio)
|
||||||
|
\li \l{Previewing Android applications}
|
||||||
|
|
||||||
|
You can preview Android applications live using an Android
|
||||||
|
emulator.
|
||||||
|
|
||||||
|
\endif
|
||||||
\li \l{Previewing in Browsers}
|
\li \l{Previewing in Browsers}
|
||||||
|
|
||||||
You can open \l{https://qt-webassembly.io/designviewer/}{\QDV}
|
You can open \l{https://qt-webassembly.io/designviewer/}{\QDV}
|
||||||
|
BIN
doc/qtdesignstudio/images/android-studio-avd-manager.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
doc/qtdesignstudio/images/android-studio-sdk-manager.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
doc/qtdesignstudio/images/android-studio-sdk-tools.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
doc/qtdesignstudio/images/menu-build-qml-preview.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
doc/qtdesignstudio/images/qtds-android-sdk-changes-dialog.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
doc/qtdesignstudio/images/qtds-android-sdk-licenses-dialog.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
doc/qtdesignstudio/images/qtds-options-accept-licenses.png
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
doc/qtdesignstudio/images/qtds-options-devices.png
Normal file
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 120 KiB |
BIN
doc/qtdesignstudio/images/qtds-options-kits.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
doc/qtdesignstudio/images/qtds-run-settings.png
Normal file
After Width: | Height: | Size: 182 KiB |
BIN
doc/qtdesignstudio/images/qtds-running-emulator.png
Normal file
After Width: | Height: | Size: 225 KiB |
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 27 KiB |
BIN
doc/qtdesignstudio/images/toolbar-show-live-preview.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
@@ -0,0 +1,200 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Design Studio 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\previouspage creator-live-preview-devices.html
|
||||||
|
\page creator-live-preview-android.html
|
||||||
|
\nextpage qt-design-viewer.html
|
||||||
|
|
||||||
|
\title Previewing Android Applications
|
||||||
|
|
||||||
|
In \QDS, you can preview Android applications live using an Android emulator.
|
||||||
|
|
||||||
|
\section1 Prerequisites
|
||||||
|
|
||||||
|
\section2 Install OpenJDK 11
|
||||||
|
|
||||||
|
You need to install OpenJDK 11 as described in \l{Getting Started with Qt for Android},
|
||||||
|
to do this:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li On Linux:
|
||||||
|
\list 1
|
||||||
|
\li In the command line, run:
|
||||||
|
\code
|
||||||
|
sudo apt-get install openjdk-11-jdk
|
||||||
|
\endcode
|
||||||
|
\endlist
|
||||||
|
\li On macOS:
|
||||||
|
\list 1
|
||||||
|
\li Download OpenJDK 11 from \l{Download OpenJDK}.
|
||||||
|
\li In the command line, run:
|
||||||
|
\code
|
||||||
|
cd ~/Downloads
|
||||||
|
tar xf microsoft-jdk-11.0.13.8.1-macos-x64.tar.gz
|
||||||
|
\endcode
|
||||||
|
\li Copy the unzipped folder to a location where macOS searches for Java by default:
|
||||||
|
\code
|
||||||
|
sudo cp -Rv jdk-11.0.13+8 /Library/Java/JavaVirtualMachines/
|
||||||
|
\endcode
|
||||||
|
\li Check if Java was correctly installed:
|
||||||
|
\code
|
||||||
|
java -version
|
||||||
|
\endcode
|
||||||
|
The Java installation is correct if the command returns something like:
|
||||||
|
\code
|
||||||
|
openjdk version "11.0.13" 2021-10-19 LTS
|
||||||
|
OpenJDK Runtime Environment Microsoft-27990 (build 11.0.13+8-LTS)
|
||||||
|
OpenJDK 64-Bit Server VM Microsoft-27990 (build 11.0.13+8-LTS, mixed mode)
|
||||||
|
\endcode
|
||||||
|
\endlist
|
||||||
|
\li On Windows:
|
||||||
|
\list
|
||||||
|
\li OpenJDK 11 is automatically installed with Android Studio.
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\section2 Install Android Studio and SDK Tools
|
||||||
|
|
||||||
|
You need to install Android Studio:
|
||||||
|
|
||||||
|
\list 1
|
||||||
|
\li Download Android Studio from \l{Download Android Studio}.
|
||||||
|
\li Install Android Studio according to the
|
||||||
|
\l{Android Studio Installation Guide}.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
Next, you need to install Android SDK command-line tools:
|
||||||
|
|
||||||
|
\list 1
|
||||||
|
\li Run Android Studio and on the welcome page, select \uicontrol{More Actions} >
|
||||||
|
\uicontrol{SDK Manager}.
|
||||||
|
\image android-studio-sdk-manager.png
|
||||||
|
\li Select \uicontrol{Android SDK Build-Tools 32-rc1}, \uicontrol{NDK (Side by side)}, and
|
||||||
|
\uicontrol{Android SDK Command-line Tools (latest)}.
|
||||||
|
\image android-studio-sdk-tools.png
|
||||||
|
\li Select \uicontrol{Apply} and follow the instructions in the wizard to finalize the
|
||||||
|
installation.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\section2 Install Android SDK Packages in \QDS
|
||||||
|
|
||||||
|
You need to install Android SDK packages in \QDS:
|
||||||
|
\list 1
|
||||||
|
\li Run \QDS.
|
||||||
|
\li Go to \uicontrol Tools > \uicontrol Options > \uicontrol{Devices}.
|
||||||
|
\li Select \uicontrol Yes on the \uicontrol{Missing Android SDK Packages} dialog.
|
||||||
|
\image qtds-options-dialog-missing-packages.png
|
||||||
|
\li Select \uicontrol OK on the \uicontrol{Android SDK Changes} dialog.
|
||||||
|
\image qtds-android-sdk-changes-dialog.png
|
||||||
|
\li Select \uicontrol Yes on the \uicontrol{Android SDK Licenses} dialog.
|
||||||
|
\image qtds-android-sdk-licenses-dialog.png
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\note The installation can take a while. If the installation process seems to
|
||||||
|
have stopped working, try to restart \QDS and run the installation again.
|
||||||
|
|
||||||
|
After completing these steps, you should no longer have any errors on the
|
||||||
|
\uicontrol Tools > \uicontrol Options > \uicontrol Devices page.
|
||||||
|
\image qtds-options-accept-licenses.png
|
||||||
|
|
||||||
|
\section2 Create Android Virtual Devices
|
||||||
|
|
||||||
|
Next, you need to create an Android Virtual Device (AVD):
|
||||||
|
|
||||||
|
\note You might need to download a system image depending on your setup.
|
||||||
|
|
||||||
|
\list 1
|
||||||
|
\li Run Android Studio and on the welcome page, select \uicontrol{More Actions} >
|
||||||
|
\uicontrol{AVD Manager}.
|
||||||
|
\image android-studio-avd-manager.png
|
||||||
|
\li Select \uicontrol{Create Virtual Device} and follow the instructions in the wizard to
|
||||||
|
finalize the creation.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\QDS has a AVD manager where you can create AVDs as well but it is recommended to use Android
|
||||||
|
Studio because then you can directly install the needed system package for the selected device
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
To create an AVD in \QDS:
|
||||||
|
\list 1
|
||||||
|
\li Go to \uicontrol Tools > \uicontrol Options.
|
||||||
|
\li On the \uicontrol Devices tab, select \uicontrol Add and follow the wizard to finalize
|
||||||
|
the creation. If there is no entry for \e{Android Device} in the
|
||||||
|
\uicontrol{Available device types} list, try restarting \QDS.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\note Many device images require Intel HAXM to work on Windows 10 and later, you can
|
||||||
|
download and install the drivers from
|
||||||
|
\l{https://github.com/intel/haxm/wiki/Installation-Instructions-on-Windows}{here}.
|
||||||
|
|
||||||
|
\image qtds-options-devices.png
|
||||||
|
|
||||||
|
\section2 Set the AVD as the Device in the Android Kit
|
||||||
|
|
||||||
|
Next, you need to set the AVD as the Android device kit. You do this under the the
|
||||||
|
\uicontrol Kits tab. If the \uicontrol Kits list is empty, restart \QDS.
|
||||||
|
|
||||||
|
\image qtds-options-kits.png
|
||||||
|
|
||||||
|
\section1 Create a Project and Run the Emulator
|
||||||
|
|
||||||
|
Now, you are set up and can create a project in \QDS. In the project, configure it to run on the
|
||||||
|
Android device:
|
||||||
|
\list 1
|
||||||
|
\li Select the \uicontrol Projects mode tab.
|
||||||
|
\li Under \uicontrol{Build & Run}, select the Android device.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\image qtds-run-settings.png
|
||||||
|
|
||||||
|
Next, to run the emulator, do one of the following:
|
||||||
|
\list
|
||||||
|
\li Select \uicontrol{Show Live Preview} in the \uicontrol{Form Editor} toolbar.
|
||||||
|
\image toolbar-show-live-preview.png
|
||||||
|
\li Select \uicontrol Build > \uicontrol{QML Preview}.
|
||||||
|
\note The \uicontrol Build menu option is not visible by default. To show
|
||||||
|
it, go to \uicontrol Tools > \uicontrol Options > \uicontrol Environment
|
||||||
|
> \uicontrol {Qt Design Studio Configuration}.
|
||||||
|
\image menu-build-qml-preview.png
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
Now the emulator runs, the qtdesignviewer APK delivered with the \QDS installation
|
||||||
|
is uploaded, and the project is uploaded and shown in the emulator.
|
||||||
|
\image qtds-running-emulator.png
|
||||||
|
|
||||||
|
Note the following:
|
||||||
|
\list
|
||||||
|
\li The qtdesignviewer for Android currently has no live preview. You have to restart
|
||||||
|
the preview to see updates.
|
||||||
|
\li Android typically has very high DPI and it is good to familiarize yourself with how
|
||||||
|
\l{https://doc-snapshots.qt.io/qt6-dev/highdpi.html}{high DPI works in Qt 6}. You can,
|
||||||
|
for example, use QT_SCALE_FACTOR or QT_USE_PHYSICAL_DPI. You can define those in the
|
||||||
|
\e .qmlproject file.
|
||||||
|
\li The qtdesignviewer for Android is currently built with Qt 6.2 and comes with all
|
||||||
|
QML modules shipped with \QDS 2.3.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
*/
|
@@ -97,6 +97,25 @@
|
|||||||
handle, such as gradient fill colors or a mixed radius, the frames are
|
handle, such as gradient fill colors or a mixed radius, the frames are
|
||||||
exported as images.
|
exported as images.
|
||||||
|
|
||||||
|
|
||||||
|
\section2 Using Variants
|
||||||
|
Figma variants are exported as a component with states. All variants
|
||||||
|
inside a \e component-set are merged together and the differences across
|
||||||
|
the variants are translated into states.
|
||||||
|
|
||||||
|
For an optimal output, follow these guidelines:
|
||||||
|
\list
|
||||||
|
\li \QBF panel is disabled for variants. Before adding
|
||||||
|
a variant to a component, the \QBF settings for the component
|
||||||
|
should be complete.
|
||||||
|
\li Do not change the layer names across the variants. The \l ID of
|
||||||
|
a layer is derived from the layer name which in turn is used
|
||||||
|
to identify the property differences for the state generation, so
|
||||||
|
it is essential to keep the layer names same across variants.
|
||||||
|
\li Adding and removing layers across the variants is fine and
|
||||||
|
encouraged to create the variant differences.
|
||||||
|
\endlist
|
||||||
|
|
||||||
\section1 Exporting Designs
|
\section1 Exporting Designs
|
||||||
|
|
||||||
\image qt-figma-bridge.png "Qt Bridge for Figma"
|
\image qt-figma-bridge.png "Qt Bridge for Figma"
|
||||||
|
@@ -67,7 +67,7 @@
|
|||||||
\section1 Embedding Resources into Applications
|
\section1 Embedding Resources into Applications
|
||||||
|
|
||||||
Alternatively, you can embedd the resources into your application by
|
Alternatively, you can embedd the resources into your application by
|
||||||
selecting \uicontrol Build > \uicontrol {Generate RCC Resource File}.
|
selecting \uicontrol Build > \uicontrol {Generate Deployable Package}.
|
||||||
Select the location for the .qmlrc file, and then select the files to
|
Select the location for the .qmlrc file, and then select the files to
|
||||||
embedd in the \uicontrol {Add Resources} dialog.
|
embedd in the \uicontrol {Add Resources} dialog.
|
||||||
|
|
||||||
|
@@ -151,6 +151,7 @@
|
|||||||
\list
|
\list
|
||||||
\li \l{Previewing on Desktop}
|
\li \l{Previewing on Desktop}
|
||||||
\li \l{Previewing on Devices}
|
\li \l{Previewing on Devices}
|
||||||
|
\li \l{Previewing Android Applications}
|
||||||
\li \l{Previewing in Browsers}
|
\li \l{Previewing in Browsers}
|
||||||
\endlist
|
\endlist
|
||||||
\li \l {Asset Creation with Other Tools}
|
\li \l {Asset Creation with Other Tools}
|
||||||
|
@@ -31,7 +31,7 @@
|
|||||||
\nextpage studio-3d-particle-system.html
|
\nextpage studio-3d-particle-system.html
|
||||||
\title Particles
|
\title Particles
|
||||||
|
|
||||||
A \e {particle system} enables you to use sprites, 3D models, or images to
|
With a \e {particle system} you can use sprites, 3D models, or images to
|
||||||
create effects that are hard to reproduce with conventional rendering
|
create effects that are hard to reproduce with conventional rendering
|
||||||
techniques. This includes chaotic systems, natural phenomena, or processes
|
techniques. This includes chaotic systems, natural phenomena, or processes
|
||||||
caused by chemical reactions. For example, you can simulate fire, smoke,
|
caused by chemical reactions. For example, you can simulate fire, smoke,
|
||||||
@@ -47,15 +47,16 @@
|
|||||||
\li \l {Particle Directions}
|
\li \l {Particle Directions}
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 Adding a Particle System
|
Preset particle \l{Particle Components}{components},
|
||||||
|
\l{Particle Templates}{templates}, and \l{Particle Effects}{effects} are
|
||||||
Preset particle components are available in
|
available in \uicontrol Components > \uicontrol {QtQuick3D Particles3D}
|
||||||
\uicontrol Components > \uicontrol {Qt Quick 3D Particles 3D}
|
|
||||||
after you add the \uicontrol {QtQuick3D.Particles3D} module to
|
after you add the \uicontrol {QtQuick3D.Particles3D} module to
|
||||||
your project, as instructed in \l{Adding and Removing Modules}.
|
your project, as instructed in \l{Adding and Removing Modules}.
|
||||||
|
|
||||||
\image studio-3d-particles.png "3D Particles"
|
\image studio-3d-particles.png "3D Particles"
|
||||||
|
|
||||||
|
\section1 Particle Components
|
||||||
|
|
||||||
When you add an instance of the \uicontrol {Particle System} component to a
|
When you add an instance of the \uicontrol {Particle System} component to a
|
||||||
scene, \QDS automatically adds instances of the \uicontrol {Sprite Particle},
|
scene, \QDS automatically adds instances of the \uicontrol {Sprite Particle},
|
||||||
\uicontrol Emitter, and \uicontrol {Vector Direction} components for you.
|
\uicontrol Emitter, and \uicontrol {Vector Direction} components for you.
|
||||||
@@ -82,53 +83,6 @@
|
|||||||
to simulate flying objects that follow wavy curves, or an instance of the
|
to simulate flying objects that follow wavy curves, or an instance of the
|
||||||
\uicontrol {Point Rotator} to simulate windy weather.
|
\uicontrol {Point Rotator} to simulate windy weather.
|
||||||
|
|
||||||
To add a particle system that emits sprite particles:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Select \uicontrol Assets > \inlineimage icons/plus.png
|
|
||||||
to add your sprites, 3D models, textures, and other graphical
|
|
||||||
\l{Assets}{assets} to the project.
|
|
||||||
\li Drag-and-drop an instance of the \uicontrol {Particle System}
|
|
||||||
component from \uicontrol Components to a scene component instance
|
|
||||||
in \l Navigator.
|
|
||||||
\li Drag-and-drop the sprite image from \uicontrol Assets to the sprite
|
|
||||||
particle instance in \uicontrol Navigator.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
Add instances of other components according to your use case.
|
|
||||||
|
|
||||||
\section1 Performance Considerations
|
|
||||||
|
|
||||||
The particles are designed to be usable on a variety of hardware on
|
|
||||||
desktops, as well as mobile and embedded devices. However, in addition
|
|
||||||
to rendering the maximum amount of particle elements on the screen,
|
|
||||||
extensibility to different use-cases, rendering quality, integration
|
|
||||||
with the other UI elements, are also important.
|
|
||||||
|
|
||||||
Currently, the rendering runs on GPU, while the particle system logic
|
|
||||||
runs on CPU. However, the \e {stateless particle system} enables you
|
|
||||||
to move the system logic onto GPU if that seems beneficial. The initial
|
|
||||||
measurements indicate that the system is quite well balanced between
|
|
||||||
CPU and GPU. The stateless system also enables animating particles by
|
|
||||||
using a \l{Timeline}{timeline}. The model particles use instanced rendering
|
|
||||||
to boost the performance. Therefore, OpenGL ES 2.0 isn't sufficient to make
|
|
||||||
rendering performant, and at least OpenGL ES 3.0, Vulkan, or some other
|
|
||||||
modern backend is required.
|
|
||||||
|
|
||||||
To get a more concrete view on the actual performance, the video below shows
|
|
||||||
a particles Testbed application running on four different Android devices.
|
|
||||||
These devices and their chipsets and GPUs could be considered to be
|
|
||||||
lower-end to mid-range, confirming that the particles can perform well also
|
|
||||||
on affordable hardware.
|
|
||||||
|
|
||||||
\youtube 9MqUCP6JLCQ
|
|
||||||
|
|
||||||
\section1 Summary of 3D Particles
|
|
||||||
|
|
||||||
\note The \uicontrol {Particles 3D} components are released as a tech
|
|
||||||
preview feature in \QDS 2.2, and their functionality will be improved
|
|
||||||
in future releases.
|
|
||||||
|
|
||||||
The following table lists preset particle components.
|
The following table lists preset particle components.
|
||||||
|
|
||||||
\table
|
\table
|
||||||
@@ -207,6 +161,190 @@
|
|||||||
\li Applies random wave curves to particles.
|
\li Applies random wave curves to particles.
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
\section1 Particle Templates
|
||||||
|
|
||||||
|
A particle template is a preset of particle components that you can use to
|
||||||
|
create specific particle effects in a convenient way.
|
||||||
|
|
||||||
|
The following table lists particle templates and their components.
|
||||||
|
|
||||||
|
\table
|
||||||
|
\header
|
||||||
|
\li Template
|
||||||
|
\li Components
|
||||||
|
\row
|
||||||
|
\li Animated Sprite
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Particle Emitter
|
||||||
|
\list
|
||||||
|
\li Sprite Particle
|
||||||
|
\li Sprite Sequence
|
||||||
|
\li Texture
|
||||||
|
\endlist
|
||||||
|
\li Vector Direction
|
||||||
|
\endlist
|
||||||
|
\row
|
||||||
|
\li Attractor
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Particle Emitter
|
||||||
|
\list
|
||||||
|
\li Sprite Particle
|
||||||
|
\li Vector Direction
|
||||||
|
\endlist
|
||||||
|
\li Particle Attractor
|
||||||
|
\endlist
|
||||||
|
\row
|
||||||
|
\li Burst
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Particle Emitter
|
||||||
|
\list
|
||||||
|
\li Sprite Particle
|
||||||
|
\li Vector Direction
|
||||||
|
\li Emit Burst
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
\row
|
||||||
|
\li Model Blend
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Particle Emitter
|
||||||
|
\list
|
||||||
|
\li Node
|
||||||
|
\li Model Blend Particle
|
||||||
|
\li Particle Emitter
|
||||||
|
\list
|
||||||
|
\li Vector Direction
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
\row
|
||||||
|
\li Model Shape
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Particle Emitter
|
||||||
|
\list
|
||||||
|
\li Sprite Particle
|
||||||
|
\list
|
||||||
|
\li Vector Direction
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
\li Particle Model Shape
|
||||||
|
\endlist
|
||||||
|
\row
|
||||||
|
\li Particle Trail
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Trail Emitter
|
||||||
|
\list
|
||||||
|
\li Vector Direction
|
||||||
|
\li Sprite Particle
|
||||||
|
\endlist
|
||||||
|
\li Particle Emitter
|
||||||
|
\list
|
||||||
|
\li Vector Direction
|
||||||
|
\li Sprite Particle
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
\row
|
||||||
|
\li Sprite
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Sprite Emitter
|
||||||
|
\list
|
||||||
|
\li Sprite Particle
|
||||||
|
\li Vector Direction
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
\row
|
||||||
|
\li Wander
|
||||||
|
\li
|
||||||
|
Particle System
|
||||||
|
\list
|
||||||
|
\li Sprite Emitter
|
||||||
|
\list
|
||||||
|
\li Sprite Particle
|
||||||
|
\list
|
||||||
|
\li Texture
|
||||||
|
\endlist
|
||||||
|
\li Wander
|
||||||
|
\li Node
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
\section1 Particle Effects
|
||||||
|
|
||||||
|
A particle effect is a ready-made effect that you can use to create, for
|
||||||
|
example, fire, rain, or mist in a convenient way.
|
||||||
|
|
||||||
|
The following particle effects are available:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li Clouds
|
||||||
|
\li Dust
|
||||||
|
\li Exhaust
|
||||||
|
\li Fire
|
||||||
|
\li Heavy Rain
|
||||||
|
\li Heavy Tire Spray
|
||||||
|
\li Light Rain
|
||||||
|
\li Light Tire Spray
|
||||||
|
\li Rain Mist
|
||||||
|
\li Snow
|
||||||
|
\li Steam
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\section1 Adding a Particle System
|
||||||
|
|
||||||
|
The recommended way to add a particle system is to use one of the
|
||||||
|
\l{Particle Templates}{particle templates} and then add or remove
|
||||||
|
particle components according to your use case.
|
||||||
|
|
||||||
|
For example, to add a particle system that emits sprite particles:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li From \uicontrol {Qt Quick 3D Particles System Templates} in
|
||||||
|
\uicontrol {Components}, drag \uicontrol Sprite to a scene component in
|
||||||
|
\uicontrol Navigator. You can also drag it to \uicontrol {3D Editor}.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\image studio-3d-particles-sprite-template.png
|
||||||
|
|
||||||
|
\section1 Performance Considerations
|
||||||
|
|
||||||
|
The particles are designed to be usable on a variety of hardware on
|
||||||
|
desktops, as well as mobile and embedded devices. However, in addition
|
||||||
|
to rendering the maximum amount of particle elements on the screen,
|
||||||
|
extensibility to different use-cases, rendering quality, integration
|
||||||
|
with the other UI elements, are also important.
|
||||||
|
|
||||||
|
Currently, the rendering runs on GPU, while the particle system logic
|
||||||
|
runs on CPU. However, the \e {stateless particle system} enables you
|
||||||
|
to move the system logic onto GPU if that seems beneficial. The initial
|
||||||
|
measurements indicate that the system is quite well balanced between
|
||||||
|
CPU and GPU. The stateless system also enables animating particles by
|
||||||
|
using a \l{Timeline}{timeline}. The model particles use instanced rendering
|
||||||
|
to boost the performance. Therefore, OpenGL ES 2.0 isn't sufficient to make
|
||||||
|
rendering performant, and at least OpenGL ES 3.0, Vulkan, or some other
|
||||||
|
modern backend is required.
|
||||||
|
|
||||||
|
To get a more concrete view on the actual performance, the video below shows
|
||||||
|
a particles Testbed application running on four different Android devices.
|
||||||
|
These devices and their chipsets and GPUs could be considered to be
|
||||||
|
lower-end to mid-range, confirming that the particles can perform well also
|
||||||
|
on affordable hardware.
|
||||||
|
|
||||||
|
\youtube 9MqUCP6JLCQ
|
||||||
|
|
||||||
\section1 Particle System Tutorials
|
\section1 Particle System Tutorials
|
||||||
|
|
||||||
\list
|
\list
|
||||||
|
@@ -67,41 +67,6 @@ if [ -d "$assetimporterSrcDir" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# collect tls plugins to have ssl download feature available
|
|
||||||
tlsDestDir="$app_path/Contents/PlugIns/tls"
|
|
||||||
tlssrcDir="$plugin_src/tls"
|
|
||||||
if [ -d "$tlssrcDir" ]; then
|
|
||||||
if [ ! -d "$tlsDestDir" ]; then
|
|
||||||
echo "- Copying tls plugins to have ssl download feature available"
|
|
||||||
mkdir -p "$tlsDestDir"
|
|
||||||
find "$tlssrcDir" -iname "*.dylib" -maxdepth 1 -exec cp {} "$tlsDestDir"/ \;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# workaround for Qt 6.2:
|
|
||||||
# - QTBUG-94796 macdeployqt does not deploy /Contents/PlugIns/sqldrivers/libqsqlite.dylib anymore
|
|
||||||
sqldriversDestDir="$app_path/Contents/PlugIns/sqldrivers"
|
|
||||||
sqldriversSrcDir="$plugin_src/sqldrivers"
|
|
||||||
if [ -d "$sqldriversSrcDir" ]; then
|
|
||||||
if [ ! -d "$sqldriversDestDir" ]; then
|
|
||||||
echo "- Copying sqlitedriver plugin"
|
|
||||||
mkdir -p "$sqldriversDestDir"
|
|
||||||
cp "$sqldriversSrcDir/libqsqlite.dylib" "$sqldriversDestDir/libqsqlite.dylib"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# workaround for Qt 6.2:
|
|
||||||
# - QTBUG-94796 macdeployqt does not deploy /Contents/PlugIns/imageformats/libqsvg.dylib anymore
|
|
||||||
imageformatsDestDir="$app_path/Contents/PlugIns/imageformats"
|
|
||||||
imageformatsSrcDir="$plugin_src/imageformats"
|
|
||||||
if [ -d "$imageformatsSrcDir" ]; then
|
|
||||||
if [ ! -d "$imageformatsDestDir" ]; then
|
|
||||||
echo "- Copying sqlitedriver plugin"
|
|
||||||
mkdir -p "$imageformatsDestDir"
|
|
||||||
cp "$imageformatsSrcDir/libqsvg.dylib" "$imageformatsDestDir/libqsvg.dylib"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# copy Qt Quick 2 imports
|
# copy Qt Quick 2 imports
|
||||||
imports2Dir="$app_path/Contents/Imports/qtquick2"
|
imports2Dir="$app_path/Contents/Imports/qtquick2"
|
||||||
if [ -d "$quick2_src" ]; then
|
if [ -d "$quick2_src" ]; then
|
||||||
@@ -209,3 +174,19 @@ if [ ! -d "$app_path/Contents/Frameworks/QtCore.framework" ]; then
|
|||||||
"$clangbackendArgument" || exit 1
|
"$clangbackendArgument" || exit 1
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# clean up after macdeployqt
|
||||||
|
# it deploys some plugins (and libs for these) that interfere with what we want
|
||||||
|
echo "Cleaning up after macdeployqt..."
|
||||||
|
toRemove=(\
|
||||||
|
"Contents/PlugIns/tls/libqopensslbackend.dylib" \
|
||||||
|
"Contents/PlugIns/sqldrivers/libqsqlpsql.dylib" \
|
||||||
|
"Contents/PlugIns/sqldrivers/libqsqlodbc.dylib" \
|
||||||
|
"Contents/Frameworks/libpq.*dylib" \
|
||||||
|
"Contents/Frameworks/libssl.*dylib" \
|
||||||
|
"Contents/Frameworks/libcrypto.*dylib" \
|
||||||
|
)
|
||||||
|
for f in "${toRemove[@]}"; do
|
||||||
|
echo "- removing \"$app_path/$f\""
|
||||||
|
rm "$app_path"/$f 2> /dev/null; done
|
||||||
|
exit 0
|
||||||
|
@@ -25,9 +25,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <qmetatype.h>
|
#include <QSize>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <qmetatype.h>
|
||||||
|
|
||||||
#include "instancecontainer.h"
|
#include "instancecontainer.h"
|
||||||
#include "reparentcontainer.h"
|
#include "reparentcontainer.h"
|
||||||
@@ -55,6 +56,8 @@ public:
|
|||||||
const QUrl &resourceUrl,
|
const QUrl &resourceUrl,
|
||||||
const QHash<QString, QVariantMap> &edit3dToolStates,
|
const QHash<QString, QVariantMap> &edit3dToolStates,
|
||||||
const QString &language,
|
const QString &language,
|
||||||
|
QSize captureImageMinimumSize,
|
||||||
|
QSize captureImageMaximumSize,
|
||||||
qint32 stateInstanceId)
|
qint32 stateInstanceId)
|
||||||
: instances(instanceContainer)
|
: instances(instanceContainer)
|
||||||
, reparentInstances(reparentContainer)
|
, reparentInstances(reparentContainer)
|
||||||
@@ -68,6 +71,8 @@ public:
|
|||||||
, resourceUrl(resourceUrl)
|
, resourceUrl(resourceUrl)
|
||||||
, edit3dToolStates(edit3dToolStates)
|
, edit3dToolStates(edit3dToolStates)
|
||||||
, language(language)
|
, language(language)
|
||||||
|
, captureImageMinimumSize(captureImageMinimumSize)
|
||||||
|
, captureImageMaximumSize(captureImageMaximumSize)
|
||||||
, stateInstanceId{stateInstanceId}
|
, stateInstanceId{stateInstanceId}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -86,6 +91,8 @@ public:
|
|||||||
out << command.edit3dToolStates;
|
out << command.edit3dToolStates;
|
||||||
out << command.language;
|
out << command.language;
|
||||||
out << command.stateInstanceId;
|
out << command.stateInstanceId;
|
||||||
|
out << command.captureImageMinimumSize;
|
||||||
|
out << command.captureImageMaximumSize;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -105,6 +112,8 @@ public:
|
|||||||
in >> command.edit3dToolStates;
|
in >> command.edit3dToolStates;
|
||||||
in >> command.language;
|
in >> command.language;
|
||||||
in >> command.stateInstanceId;
|
in >> command.stateInstanceId;
|
||||||
|
in >> command.captureImageMinimumSize;
|
||||||
|
in >> command.captureImageMaximumSize;
|
||||||
|
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
@@ -122,6 +131,8 @@ public:
|
|||||||
QUrl resourceUrl;
|
QUrl resourceUrl;
|
||||||
QHash<QString, QVariantMap> edit3dToolStates;
|
QHash<QString, QVariantMap> edit3dToolStates;
|
||||||
QString language;
|
QString language;
|
||||||
|
QSize captureImageMinimumSize;
|
||||||
|
QSize captureImageMaximumSize;
|
||||||
qint32 stateInstanceId = 0;
|
qint32 stateInstanceId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -38,16 +38,22 @@ namespace QmlDesigner {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
QImage renderImage(ServerNodeInstance rootNodeInstance)
|
QImage renderImage(ServerNodeInstance rootNodeInstance, QSize minimumSize, QSize maximumSize)
|
||||||
{
|
{
|
||||||
rootNodeInstance.updateDirtyNodeRecursive();
|
rootNodeInstance.updateDirtyNodeRecursive();
|
||||||
|
|
||||||
QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize();
|
QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize();
|
||||||
if (previewImageSize.isEmpty())
|
if (previewImageSize.isEmpty()) {
|
||||||
previewImageSize = {150, 150};
|
previewImageSize = minimumSize;
|
||||||
|
} else if (previewImageSize.width() < minimumSize.width()
|
||||||
|
|| previewImageSize.height() < minimumSize.height()) {
|
||||||
|
previewImageSize.scale(minimumSize, Qt::KeepAspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
if (previewImageSize.width() > 150 || previewImageSize.height() > 150)
|
if (previewImageSize.width() > maximumSize.width()
|
||||||
previewImageSize.scale({150, 150}, Qt::KeepAspectRatio);
|
|| previewImageSize.height() > maximumSize.height()) {
|
||||||
|
previewImageSize.scale(maximumSize, Qt::KeepAspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize);
|
QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize);
|
||||||
|
|
||||||
@@ -73,7 +79,7 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands(
|
|||||||
|
|
||||||
DesignerSupport::polishItems(quickWindow());
|
DesignerSupport::polishItems(quickWindow());
|
||||||
|
|
||||||
QImage image = renderImage(rooNodeInstance);
|
QImage image = renderImage(rooNodeInstance, m_minimumSize, m_maximumSize);
|
||||||
|
|
||||||
nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(image)});
|
nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(image)});
|
||||||
|
|
||||||
@@ -82,4 +88,12 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlDesigner::Qt5CaptureImageNodeInstanceServer::createScene(const CreateSceneCommand &command)
|
||||||
|
{
|
||||||
|
m_minimumSize = command.captureImageMinimumSize;
|
||||||
|
m_maximumSize = command.captureImageMaximumSize;
|
||||||
|
|
||||||
|
Qt5PreviewNodeInstanceServer::createScene(command);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@@ -36,10 +36,14 @@ public:
|
|||||||
: Qt5PreviewNodeInstanceServer(nodeInstanceClient)
|
: Qt5PreviewNodeInstanceServer(nodeInstanceClient)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void createScene(const CreateSceneCommand &command) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void collectItemChangesAndSendChangeCommands() override;
|
void collectItemChangesAndSendChangeCommands() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QSize m_minimumSize;
|
||||||
|
QSize m_maximumSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -285,6 +285,7 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: delegateStateImageSource
|
source: delegateStateImageSource
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
|
mipmap: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -95,6 +95,15 @@ Project {
|
|||||||
@if %{IsQt6Project}
|
@if %{IsQt6Project}
|
||||||
/* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */
|
/* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */
|
||||||
widgetApp: true
|
widgetApp: true
|
||||||
|
|
||||||
|
/* args: Specifies command line arguments for qsb tool to generate shaders.
|
||||||
|
files: Specifies target files for qsb tool. If path is included, it must be relative to this file.
|
||||||
|
Wildcard '*' can be used in the file name part of the path.
|
||||||
|
e.g. files: [ "content/shaders/*.vert", "*.frag" ] */
|
||||||
|
ShaderTool {
|
||||||
|
args: "-s --glsl \\\"100 es,120,150\\\" --hlsl 50 --msl 12"
|
||||||
|
files: [ "content/shaders/*" ]
|
||||||
|
}
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
multilanguageSupport: true
|
multilanguageSupport: true
|
||||||
|
@@ -84,10 +84,13 @@ void NamePrettyPrinter::visit(const TemplateNameId *name)
|
|||||||
|
|
||||||
TemplateArgument templArg = name->templateArgumentAt(index);
|
TemplateArgument templArg = name->templateArgumentAt(index);
|
||||||
QString arg;
|
QString arg;
|
||||||
if (templArg.type().isValid())
|
if (templArg.type().isValid()) {
|
||||||
arg = overview()->prettyType(templArg.type());
|
Overview o = *_overview;
|
||||||
else if (const NumericLiteral *num = templArg.numericLiteral())
|
o.showReturnTypes = true;
|
||||||
|
arg = o.prettyType(templArg.type());
|
||||||
|
} else if (const NumericLiteral *num = templArg.numericLiteral()) {
|
||||||
arg = QString::fromLatin1(num->chars(), num->size());
|
arg = QString::fromLatin1(num->chars(), num->size());
|
||||||
|
}
|
||||||
|
|
||||||
if (arg.isEmpty())
|
if (arg.isEmpty())
|
||||||
_name += QString::fromLatin1("_Tp%1").arg(index + 1);
|
_name += QString::fromLatin1("_Tp%1").arg(index + 1);
|
||||||
|
@@ -290,8 +290,8 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
|
|||||||
for (const QString &shellCmd : commands)
|
for (const QString &shellCmd : commands)
|
||||||
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||||
}
|
}
|
||||||
const auto data = runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST).toStringList();
|
const auto preStartCmdList = runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST);
|
||||||
for (const QString &shellCmd : data)
|
for (const QString &shellCmd : preStartCmdList.toStringList())
|
||||||
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||||
|
|
||||||
if (auto aspect = runControl->aspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) {
|
if (auto aspect = runControl->aspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) {
|
||||||
@@ -300,8 +300,8 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
|
|||||||
for (const QString &shellCmd : commands)
|
for (const QString &shellCmd : commands)
|
||||||
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||||
}
|
}
|
||||||
const auto data2 = runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST).toStringList();
|
const auto postFinishCmdList = runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST);
|
||||||
for (const QString &shellCmd : data)
|
for (const QString &shellCmd : postFinishCmdList.toStringList())
|
||||||
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||||
|
|
||||||
m_debugServerPath = debugServer(m_useLldb, target).toString();
|
m_debugServerPath = debugServer(m_useLldb, target).toString();
|
||||||
|
@@ -677,6 +677,7 @@ public:
|
|||||||
|
|
||||||
void update();
|
void update();
|
||||||
void finalize();
|
void finalize();
|
||||||
|
void resetData(bool resetFollowSymbolData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IAssistProposal *perform(const AssistInterface *) override
|
IAssistProposal *perform(const AssistInterface *) override
|
||||||
@@ -689,8 +690,6 @@ private:
|
|||||||
return createProposal(false);
|
return createProposal(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetData();
|
|
||||||
|
|
||||||
IAssistProposal *immediateProposalImpl() const;
|
IAssistProposal *immediateProposalImpl() const;
|
||||||
IAssistProposal *createProposal(bool final) const;
|
IAssistProposal *createProposal(bool final) const;
|
||||||
CppEditor::VirtualFunctionProposalItem *createEntry(const QString &name,
|
CppEditor::VirtualFunctionProposalItem *createEntry(const QString &name,
|
||||||
@@ -726,7 +725,7 @@ public:
|
|||||||
{
|
{
|
||||||
closeTempDocuments();
|
closeTempDocuments();
|
||||||
if (virtualFuncAssistProcessor)
|
if (virtualFuncAssistProcessor)
|
||||||
virtualFuncAssistProcessor->cancel();
|
virtualFuncAssistProcessor->resetData(false);
|
||||||
for (const MessageId &id : qAsConst(pendingSymbolInfoRequests))
|
for (const MessageId &id : qAsConst(pendingSymbolInfoRequests))
|
||||||
q->cancelRequest(id);
|
q->cancelRequest(id);
|
||||||
for (const MessageId &id : qAsConst(pendingGotoImplRequests))
|
for (const MessageId &id : qAsConst(pendingGotoImplRequests))
|
||||||
@@ -2715,6 +2714,7 @@ private:
|
|||||||
const AstNode &m_ast;
|
const AstNode &m_ast;
|
||||||
const QTextDocument * const m_doc;
|
const QTextDocument * const m_doc;
|
||||||
const QString &m_docContent;
|
const QString &m_docContent;
|
||||||
|
AstNode::FileStatus m_currentFileStatus = AstNode::FileStatus::Unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
// clangd reports also the #ifs, #elses and #endifs around the disabled code as disabled,
|
// clangd reports also the #ifs, #elses and #endifs around the disabled code as disabled,
|
||||||
@@ -2839,11 +2839,16 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (it->kind() == "Call") {
|
if (it->kind() == "Call") {
|
||||||
// In class templates, member calls can result in "Call" nodes rather than
|
// The first child is e.g. a called lambda or an object on which
|
||||||
// "CXXMemberCall". We try to detect this by checking for a certain kind of
|
// the call happens, and should not be highlighted as an output argument.
|
||||||
// child node.
|
// If the call is not fully resolved (as in templates), we don't
|
||||||
|
// know whether the argument is passed as const or not.
|
||||||
|
if (it->arcanaContains("dependent type"))
|
||||||
|
return false;
|
||||||
const QList<AstNode> children = it->children().value_or(QList<AstNode>());
|
const QList<AstNode> children = it->children().value_or(QList<AstNode>());
|
||||||
return children.isEmpty() || children.first().kind() != "CXXDependentScopeMember";
|
return children.isEmpty()
|
||||||
|
|| (children.first().range() != (it - 1)->range()
|
||||||
|
&& children.first().kind() != "UnresolvedLookup");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The token should get marked for e.g. lambdas, but not for assignment operators,
|
// The token should get marked for e.g. lambdas, but not for assignment operators,
|
||||||
@@ -2863,7 +2868,7 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
|
|||||||
// The callable is never displayed as an output parameter.
|
// The callable is never displayed as an output parameter.
|
||||||
// TODO: A good argument can be made to display objects on which a non-const
|
// TODO: A good argument can be made to display objects on which a non-const
|
||||||
// operator or function is called as output parameters.
|
// operator or function is called as output parameters.
|
||||||
if (children.at(1).range() == range)
|
if (children.at(1).range().contains(range))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QList<AstNode> firstChildTree{children.first()};
|
QList<AstNode> firstChildTree{children.first()};
|
||||||
@@ -2883,6 +2888,8 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
|
|||||||
|
|
||||||
if (it->kind() == "Lambda")
|
if (it->kind() == "Lambda")
|
||||||
return false;
|
return false;
|
||||||
|
if (it->kind() == "BinaryOperator")
|
||||||
|
return false;
|
||||||
if (it->hasConstType())
|
if (it->hasConstType())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -3110,7 +3117,7 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc,
|
|||||||
|
|
||||||
void ClangdClient::VirtualFunctionAssistProcessor::cancel()
|
void ClangdClient::VirtualFunctionAssistProcessor::cancel()
|
||||||
{
|
{
|
||||||
resetData();
|
resetData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangdClient::VirtualFunctionAssistProcessor::update()
|
void ClangdClient::VirtualFunctionAssistProcessor::update()
|
||||||
@@ -3132,15 +3139,16 @@ void ClangdClient::VirtualFunctionAssistProcessor::finalize()
|
|||||||
} else {
|
} else {
|
||||||
setAsyncProposalAvailable(proposal);
|
setAsyncProposalAvailable(proposal);
|
||||||
}
|
}
|
||||||
resetData();
|
resetData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangdClient::VirtualFunctionAssistProcessor::resetData()
|
void ClangdClient::VirtualFunctionAssistProcessor::resetData(bool resetFollowSymbolData)
|
||||||
{
|
{
|
||||||
if (!m_data)
|
if (!m_data)
|
||||||
return;
|
return;
|
||||||
m_data->followSymbolData->virtualFuncAssistProcessor = nullptr;
|
m_data->followSymbolData->virtualFuncAssistProcessor = nullptr;
|
||||||
m_data->followSymbolData.reset();
|
if (resetFollowSymbolData)
|
||||||
|
m_data->followSymbolData.reset();
|
||||||
m_data = nullptr;
|
m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3503,6 +3511,8 @@ QIcon ClangdCompletionItem::icon() const
|
|||||||
case SpecialQtType::None:
|
case SpecialQtType::None:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (item().kind().value_or(CompletionItemKind::Text) == CompletionItemKind::Property)
|
||||||
|
return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::VarPublicStatic);
|
||||||
return LanguageClientCompletionItem::icon();
|
return LanguageClientCompletionItem::icon();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4080,7 +4090,13 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node)
|
|||||||
{
|
{
|
||||||
if (m_future.isCanceled())
|
if (m_future.isCanceled())
|
||||||
return;
|
return;
|
||||||
switch (node.fileStatus(m_filePath)) {
|
const AstNode::FileStatus prevFileStatus = m_currentFileStatus;
|
||||||
|
m_currentFileStatus = node.fileStatus(m_filePath);
|
||||||
|
if (m_currentFileStatus == AstNode::FileStatus::Unknown
|
||||||
|
&& prevFileStatus != AstNode::FileStatus::Ours) {
|
||||||
|
m_currentFileStatus = prevFileStatus;
|
||||||
|
}
|
||||||
|
switch (m_currentFileStatus) {
|
||||||
case AstNode::FileStatus::Ours:
|
case AstNode::FileStatus::Ours:
|
||||||
case AstNode::FileStatus::Unknown:
|
case AstNode::FileStatus::Unknown:
|
||||||
collectFromNode(node);
|
collectFromNode(node);
|
||||||
@@ -4095,6 +4111,7 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_currentFileStatus = prevFileStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClangdClient::FollowSymbolData::defLinkIsAmbiguous() const
|
bool ClangdClient::FollowSymbolData::defLinkIsAmbiguous() const
|
||||||
|
@@ -27,8 +27,9 @@
|
|||||||
|
|
||||||
#include <texteditor/codeassist/iassistproposalmodel.h>
|
#include <texteditor/codeassist/iassistproposalmodel.h>
|
||||||
|
|
||||||
#include <QString>
|
#include <QList>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
namespace TextEditor { class BaseTextEditor; }
|
namespace TextEditor { class BaseTextEditor; }
|
||||||
|
|
||||||
|
@@ -1321,6 +1321,14 @@ void ClangdTestHighlighting::test_data()
|
|||||||
<< QList<int>{C_FIELD} << 0;
|
<< QList<int>{C_FIELD} << 0;
|
||||||
QTest::newRow("member call on dependent (3)") << 999 << 9 << 999 << 12
|
QTest::newRow("member call on dependent (3)") << 999 << 9 << 999 << 12
|
||||||
<< QList<int>{C_LOCAL} << 0;
|
<< QList<int>{C_LOCAL} << 0;
|
||||||
|
QTest::newRow("member access via operator->") << 1009 << 7 << 1009 << 21
|
||||||
|
<< QList<int>{C_FIELD} << 0;
|
||||||
|
QTest::newRow("lambda call in member") << 1023 << 9 << 1023 << 15
|
||||||
|
<< QList<int>{C_LOCAL} << 0;
|
||||||
|
QTest::newRow("call on inherited member") << 1024 << 9 << 1024 << 12
|
||||||
|
<< QList<int>{C_FIELD} << 0;
|
||||||
|
QTest::newRow("pass inherited member by value") << 1038 << 21 << 1038 << 26
|
||||||
|
<< QList<int>{C_FIELD} << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangdTestHighlighting::test()
|
void ClangdTestHighlighting::test()
|
||||||
@@ -1423,12 +1431,12 @@ void ClangdTestHighlighting::test()
|
|||||||
void ClangdTestHighlighting::testIfdefedOutBlocks()
|
void ClangdTestHighlighting::testIfdefedOutBlocks()
|
||||||
{
|
{
|
||||||
QCOMPARE(m_ifdefedOutBlocks.size(), 3);
|
QCOMPARE(m_ifdefedOutBlocks.size(), 3);
|
||||||
QCOMPARE(m_ifdefedOutBlocks.at(0).first(), 12033);
|
QCOMPARE(m_ifdefedOutBlocks.at(0).first(), 12056);
|
||||||
QCOMPARE(m_ifdefedOutBlocks.at(0).last(), 12050);
|
QCOMPARE(m_ifdefedOutBlocks.at(0).last(), 12073);
|
||||||
QCOMPARE(m_ifdefedOutBlocks.at(1).first(), 13351);
|
QCOMPARE(m_ifdefedOutBlocks.at(1).first(), 13374);
|
||||||
QCOMPARE(m_ifdefedOutBlocks.at(1).last(), 13364);
|
QCOMPARE(m_ifdefedOutBlocks.at(1).last(), 13387);
|
||||||
QCOMPARE(m_ifdefedOutBlocks.at(2).first(), 13390);
|
QCOMPARE(m_ifdefedOutBlocks.at(2).first(), 13413);
|
||||||
QCOMPARE(m_ifdefedOutBlocks.at(2).last(), 13402);
|
QCOMPARE(m_ifdefedOutBlocks.at(2).last(), 13425);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ auto *rawVariable = R"(Vari
|
|||||||
auto Character = 'c';
|
auto Character = 'c';
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template<typename T> class vector {};
|
template<typename T> class vector { public: void clear(); };
|
||||||
template<typename T, typename U> class pair {};
|
template<typename T, typename U> class pair {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -999,3 +999,44 @@ public:
|
|||||||
ptr->bar();
|
ptr->bar();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace std { template<typename T> struct optional { T* operator->(); }; }
|
||||||
|
struct structWithData { int value; };
|
||||||
|
struct structWithOptional { std::optional<structWithData> opt_my_struct1; };
|
||||||
|
|
||||||
|
void foo(structWithOptional & s)
|
||||||
|
{
|
||||||
|
s.opt_my_struct1->value = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BaseWithMember
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::vector<unsigned char> vec;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> class Derived : public BaseWithMember
|
||||||
|
{
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
auto lambda = [&] {};
|
||||||
|
lambda();
|
||||||
|
vec.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool testVal(int val);
|
||||||
|
class BaseWithMember2
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
template<typename T> class Derived2 : public BaseWithMember2
|
||||||
|
{
|
||||||
|
bool foo()
|
||||||
|
{
|
||||||
|
if (testVal(value))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@@ -259,7 +259,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
|||||||
m_configView->setUniformRowHeights(true);
|
m_configView->setUniformRowHeights(true);
|
||||||
m_configView->setSortingEnabled(true);
|
m_configView->setSortingEnabled(true);
|
||||||
m_configView->sortByColumn(0, Qt::AscendingOrder);
|
m_configView->sortByColumn(0, Qt::AscendingOrder);
|
||||||
auto stretcher = new HeaderViewStretcher(m_configView->header(), 0);
|
(void) new HeaderViewStretcher(m_configView->header(), 0);
|
||||||
m_configView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
m_configView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||||
m_configView->setAlternatingRowColors(true);
|
m_configView->setAlternatingRowColors(true);
|
||||||
@@ -373,18 +373,15 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
|||||||
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
|
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
|
||||||
m_configModel->setInitialParametersConfiguration(
|
m_configModel->setInitialParametersConfiguration(
|
||||||
m_buildConfiguration->initialCMakeConfiguration());
|
m_buildConfiguration->initialCMakeConfiguration());
|
||||||
m_configView->expandAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(bc->buildSystem(), &BuildSystem::parsingFinished, this, [this, stretcher] {
|
connect(bc->buildSystem(), &BuildSystem::parsingFinished, this, [this] {
|
||||||
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
|
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
|
||||||
m_configModel->setInitialParametersConfiguration(
|
m_configModel->setInitialParametersConfiguration(
|
||||||
m_buildConfiguration->initialCMakeConfiguration());
|
m_buildConfiguration->initialCMakeConfiguration());
|
||||||
m_buildConfiguration->filterConfigArgumentsFromAdditionalCMakeArguments();
|
m_buildConfiguration->filterConfigArgumentsFromAdditionalCMakeArguments();
|
||||||
updateFromKit();
|
updateFromKit();
|
||||||
m_configView->expandAll();
|
|
||||||
m_configView->setEnabled(true);
|
m_configView->setEnabled(true);
|
||||||
stretcher->stretch();
|
|
||||||
updateButtonState();
|
updateButtonState();
|
||||||
m_showProgressTimer.stop();
|
m_showProgressTimer.stop();
|
||||||
m_progressIndicator->hide();
|
m_progressIndicator->hide();
|
||||||
@@ -402,10 +399,6 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
|||||||
m_progressIndicator->hide();
|
m_progressIndicator->hide();
|
||||||
updateConfigurationStateSelection();
|
updateConfigurationStateSelection();
|
||||||
});
|
});
|
||||||
connect(m_configTextFilterModel, &QAbstractItemModel::modelReset, this, [this, stretcher]() {
|
|
||||||
m_configView->expandAll();
|
|
||||||
stretcher->stretch();
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(m_configModel, &QAbstractItemModel::dataChanged,
|
connect(m_configModel, &QAbstractItemModel::dataChanged,
|
||||||
this, &CMakeBuildSettingsWidget::updateButtonState);
|
this, &CMakeBuildSettingsWidget::updateButtonState);
|
||||||
|
@@ -216,8 +216,8 @@ void SearchResultTreeItemDelegate::drawText(QPainter *painter,
|
|||||||
const QString textBefore = text.left(searchTermStart).replace(QLatin1Char('\t'), m_tabString);
|
const QString textBefore = text.left(searchTermStart).replace(QLatin1Char('\t'), m_tabString);
|
||||||
const QString textHighlight = text.mid(searchTermStart, searchTermLength).replace(QLatin1Char('\t'), m_tabString);
|
const QString textHighlight = text.mid(searchTermStart, searchTermLength).replace(QLatin1Char('\t'), m_tabString);
|
||||||
const QString textAfter = text.mid(searchTermStart + searchTermLength).replace(QLatin1Char('\t'), m_tabString);
|
const QString textAfter = text.mid(searchTermStart + searchTermLength).replace(QLatin1Char('\t'), m_tabString);
|
||||||
int searchTermStartPixels = painter->fontMetrics().horizontalAdvance(textBefore);
|
int searchTermStartPixels = option.fontMetrics.horizontalAdvance(textBefore);
|
||||||
int searchTermLengthPixels = painter->fontMetrics().horizontalAdvance(textHighlight);
|
int searchTermLengthPixels = option.fontMetrics.horizontalAdvance(textHighlight);
|
||||||
|
|
||||||
// rects
|
// rects
|
||||||
QRect beforeHighlightRect(rect);
|
QRect beforeHighlightRect(rect);
|
||||||
|
@@ -3273,6 +3273,58 @@ void QuickfixTest::testGenerateGetterSetterOnlySetter()
|
|||||||
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
|
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QuickfixTest::testGenerateGetterSetterAnonymousClass()
|
||||||
|
{
|
||||||
|
QList<TestDocumentPtr> testDocuments;
|
||||||
|
QByteArray original;
|
||||||
|
QByteArray expected;
|
||||||
|
QuickFixSettings s;
|
||||||
|
s->setterInCppFileFrom = 1;
|
||||||
|
s->setterParameterNameTemplate = "value";
|
||||||
|
|
||||||
|
// Header File
|
||||||
|
original = R"(
|
||||||
|
class {
|
||||||
|
int @m_foo;
|
||||||
|
} bar;
|
||||||
|
)";
|
||||||
|
expected = R"(
|
||||||
|
class {
|
||||||
|
int m_foo;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int foo() const
|
||||||
|
{
|
||||||
|
return m_foo;
|
||||||
|
}
|
||||||
|
void setFoo(int value)
|
||||||
|
{
|
||||||
|
if (m_foo == value)
|
||||||
|
return;
|
||||||
|
m_foo = value;
|
||||||
|
emit fooChanged();
|
||||||
|
}
|
||||||
|
void resetFoo()
|
||||||
|
{
|
||||||
|
setFoo({}); // TODO: Adapt to use your actual default defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void fooChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_PROPERTY(int foo READ foo WRITE setFoo RESET resetFoo NOTIFY fooChanged)
|
||||||
|
} bar;
|
||||||
|
)";
|
||||||
|
testDocuments << CppTestDocument::create("file.h", original, expected);
|
||||||
|
|
||||||
|
// Source File
|
||||||
|
testDocuments << CppTestDocument::create("file.cpp", {}, {});
|
||||||
|
|
||||||
|
GenerateGetterSetter factory;
|
||||||
|
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
void QuickfixTest::testGenerateGetterSetterInlineInHeaderFile()
|
void QuickfixTest::testGenerateGetterSetterInlineInHeaderFile()
|
||||||
{
|
{
|
||||||
QList<TestDocumentPtr> testDocuments;
|
QList<TestDocumentPtr> testDocuments;
|
||||||
@@ -3362,6 +3414,43 @@ void QuickfixTest::testGenerateGetterSetterOnlySetterHeaderFileWithIncludeGuard(
|
|||||||
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
|
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QuickfixTest::testGenerateGetterFunctionAsTemplateArg()
|
||||||
|
{
|
||||||
|
QList<TestDocumentPtr> testDocuments;
|
||||||
|
const QByteArray original = R"(
|
||||||
|
template<typename T> class TS {};
|
||||||
|
template<typename T, typename U> class TS<T(U)> {};
|
||||||
|
|
||||||
|
class S2 {
|
||||||
|
TS<int(int)> @member;
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
const QByteArray expected = R"(
|
||||||
|
template<typename T> class TS {};
|
||||||
|
template<typename T, typename U> class TS<T(U)> {};
|
||||||
|
|
||||||
|
class S2 {
|
||||||
|
TS<int(int)> member;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const TS<int (int)> &getMember() const
|
||||||
|
{
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
|
||||||
|
testDocuments << CppTestDocument::create("file.h", original, expected);
|
||||||
|
|
||||||
|
QuickFixSettings s;
|
||||||
|
s->getterOutsideClassFrom = 0;
|
||||||
|
s->getterInCppFileFrom = 0;
|
||||||
|
s->getterNameTemplate = "get<Name>";
|
||||||
|
|
||||||
|
GenerateGetterSetter factory;
|
||||||
|
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
class CppCodeStyleSettingsChanger {
|
class CppCodeStyleSettingsChanger {
|
||||||
public:
|
public:
|
||||||
CppCodeStyleSettingsChanger(const CppCodeStyleSettings &settings);
|
CppCodeStyleSettingsChanger(const CppCodeStyleSettings &settings);
|
||||||
|
@@ -113,8 +113,10 @@ private slots:
|
|||||||
void testGenerateGetterSetterGeneralTests();
|
void testGenerateGetterSetterGeneralTests();
|
||||||
void testGenerateGetterSetterOnlyGetter();
|
void testGenerateGetterSetterOnlyGetter();
|
||||||
void testGenerateGetterSetterOnlySetter();
|
void testGenerateGetterSetterOnlySetter();
|
||||||
|
void testGenerateGetterSetterAnonymousClass();
|
||||||
void testGenerateGetterSetterInlineInHeaderFile();
|
void testGenerateGetterSetterInlineInHeaderFile();
|
||||||
void testGenerateGetterSetterOnlySetterHeaderFileWithIncludeGuard();
|
void testGenerateGetterSetterOnlySetterHeaderFileWithIncludeGuard();
|
||||||
|
void testGenerateGetterFunctionAsTemplateArg();
|
||||||
void testGenerateGettersSetters_data();
|
void testGenerateGettersSetters_data();
|
||||||
void testGenerateGettersSetters();
|
void testGenerateGettersSetters();
|
||||||
|
|
||||||
|
@@ -3907,7 +3907,12 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d
|
|||||||
else
|
else
|
||||||
getterInClassDeclaration += QLatin1String(" const");
|
getterInClassDeclaration += QLatin1String(" const");
|
||||||
getterInClassDeclaration.prepend(m_settings->getterAttributes + QLatin1Char(' '));
|
getterInClassDeclaration.prepend(m_settings->getterAttributes + QLatin1Char(' '));
|
||||||
|
|
||||||
auto getterLocation = m_settings->determineGetterLocation(1);
|
auto getterLocation = m_settings->determineGetterLocation(1);
|
||||||
|
// if we have an anonymous class we must add code inside the class
|
||||||
|
if (data.clazz->name()->isAnonymousNameId())
|
||||||
|
getterLocation = CppQuickFixSettings::FunctionLocation::InsideClass;
|
||||||
|
|
||||||
if (getterLocation == CppQuickFixSettings::FunctionLocation::InsideClass) {
|
if (getterLocation == CppQuickFixSettings::FunctionLocation::InsideClass) {
|
||||||
getterInClassDeclaration += QLatin1String("\n{\nreturn ") + returnExpression
|
getterInClassDeclaration += QLatin1String("\n{\nreturn ") + returnExpression
|
||||||
+ QLatin1String(";\n}\n");
|
+ QLatin1String(";\n}\n");
|
||||||
@@ -4026,6 +4031,10 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d
|
|||||||
body += "}";
|
body += "}";
|
||||||
|
|
||||||
auto setterLocation = m_settings->determineSetterLocation(body.count('\n') - 2);
|
auto setterLocation = m_settings->determineSetterLocation(body.count('\n') - 2);
|
||||||
|
// if we have an anonymous class we must add code inside the class
|
||||||
|
if (data.clazz->name()->isAnonymousNameId())
|
||||||
|
setterLocation = CppQuickFixSettings::FunctionLocation::InsideClass;
|
||||||
|
|
||||||
if (setterLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile())
|
if (setterLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile())
|
||||||
setterLocation = CppQuickFixSettings::FunctionLocation::OutsideClass;
|
setterLocation = CppQuickFixSettings::FunctionLocation::OutsideClass;
|
||||||
|
|
||||||
@@ -4100,6 +4109,10 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d
|
|||||||
body.replace(QRegularExpression("\\b" + parameterName + "\\b"), "defaultValue");
|
body.replace(QRegularExpression("\\b" + parameterName + "\\b"), "defaultValue");
|
||||||
// body.count('\n') - 2 : do not count the 2 at start
|
// body.count('\n') - 2 : do not count the 2 at start
|
||||||
auto resetLocation = m_settings->determineSetterLocation(body.count('\n') - 2);
|
auto resetLocation = m_settings->determineSetterLocation(body.count('\n') - 2);
|
||||||
|
// if we have an anonymous class we must add code inside the class
|
||||||
|
if (data.clazz->name()->isAnonymousNameId())
|
||||||
|
resetLocation = CppQuickFixSettings::FunctionLocation::InsideClass;
|
||||||
|
|
||||||
if (resetLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile())
|
if (resetLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile())
|
||||||
resetLocation = CppQuickFixSettings::FunctionLocation::OutsideClass;
|
resetLocation = CppQuickFixSettings::FunctionLocation::OutsideClass;
|
||||||
|
|
||||||
|
@@ -290,6 +290,13 @@ bool DebuggerItem::addAndroidLldbPythonEnv(const Utils::FilePath &lldbCmd, Utils
|
|||||||
if (pythonBinDir.exists()) {
|
if (pythonBinDir.exists()) {
|
||||||
env.set("PYTHONHOME", pythonDir.toUserOutput());
|
env.set("PYTHONHOME", pythonDir.toUserOutput());
|
||||||
env.prependOrSetPath(pythonBinDir);
|
env.prependOrSetPath(pythonBinDir);
|
||||||
|
|
||||||
|
if (HostOsInfo::isAnyUnixHost()) {
|
||||||
|
const FilePath pythonLibDir = pythonDir.pathAppended("lib");
|
||||||
|
if (pythonLibDir.exists())
|
||||||
|
env.prependOrSet("LD_LIBRARY_PATH", pythonLibDir.toString());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -435,17 +435,22 @@ void GenericBuildSystem::parse(RefreshOptions options)
|
|||||||
|
|
||||||
if (options & Configuration) {
|
if (options & Configuration) {
|
||||||
m_rawProjectIncludePaths = readLines(m_includesFileName);
|
m_rawProjectIncludePaths = readLines(m_includesFileName);
|
||||||
Utils::FilePaths normalPaths;
|
QStringList normalPaths;
|
||||||
Utils::FilePaths frameworkPaths;
|
QStringList frameworkPaths;
|
||||||
const auto baseDir = Utils::FilePath::fromString(m_includesFileName).parentDir();
|
const auto baseDir = Utils::FilePath::fromString(m_includesFileName).parentDir();
|
||||||
for (const QString &rawPath : qAsConst(m_rawProjectIncludePaths)) {
|
for (const QString &rawPath : qAsConst(m_rawProjectIncludePaths)) {
|
||||||
if (rawPath.startsWith("-F"))
|
if (rawPath.startsWith("-F"))
|
||||||
frameworkPaths << baseDir.resolvePath(rawPath.mid(2));
|
frameworkPaths << rawPath.mid(2);
|
||||||
else
|
else
|
||||||
normalPaths << baseDir.resolvePath(rawPath);
|
normalPaths << rawPath;
|
||||||
}
|
}
|
||||||
m_projectIncludePaths = toUserHeaderPaths(normalPaths);
|
const auto expandedPaths = [this](const QStringList &paths) {
|
||||||
m_projectIncludePaths << toFrameworkHeaderPaths(frameworkPaths);
|
return Utils::transform(processEntries(paths), [](const auto &pair) {
|
||||||
|
return pair.first;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
m_projectIncludePaths = toUserHeaderPaths(expandedPaths(normalPaths));
|
||||||
|
m_projectIncludePaths << toFrameworkHeaderPaths(expandedPaths(frameworkPaths));
|
||||||
m_cxxflags = readFlags(m_cxxflagsFileName);
|
m_cxxflags = readFlags(m_cxxflagsFileName);
|
||||||
m_cflags = readFlags(m_cflagsFileName);
|
m_cflags = readFlags(m_cflagsFileName);
|
||||||
}
|
}
|
||||||
|
@@ -50,31 +50,17 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
namespace {
|
class AssetsLibraryView::ImageCacheData
|
||||||
ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
|
|
||||||
{
|
|
||||||
if (project)
|
|
||||||
return project->activeTarget();
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
class ImageCacheData
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Sqlite::Database database{Utils::PathString{
|
Sqlite::Database database{Utils::PathString{
|
||||||
Core::ICore::cacheResourcePath("imagecache-v2.db").toString()},
|
Core::ICore::cacheResourcePath("fontimagecache.db").toString()},
|
||||||
Sqlite::JournalMode::Wal,
|
Sqlite::JournalMode::Wal,
|
||||||
Sqlite::LockingMode::Normal};
|
Sqlite::LockingMode::Normal};
|
||||||
ImageCacheStorage<Sqlite::Database> storage{database};
|
ImageCacheStorage<Sqlite::Database> storage{database};
|
||||||
ImageCacheConnectionManager connectionManager;
|
|
||||||
ImageCacheCollector collector{connectionManager};
|
|
||||||
ImageCacheFontCollector fontCollector;
|
ImageCacheFontCollector fontCollector;
|
||||||
ImageCacheGenerator generator{collector, storage};
|
|
||||||
ImageCacheGenerator fontGenerator{fontCollector, storage};
|
ImageCacheGenerator fontGenerator{fontCollector, storage};
|
||||||
TimeStampProvider timeStampProvider;
|
TimeStampProvider timeStampProvider;
|
||||||
AsynchronousImageCache cache{storage, generator, timeStampProvider};
|
|
||||||
AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider};
|
AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider};
|
||||||
SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector};
|
SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector};
|
||||||
};
|
};
|
||||||
@@ -94,9 +80,8 @@ bool AssetsLibraryView::hasWidget() const
|
|||||||
WidgetInfo AssetsLibraryView::widgetInfo()
|
WidgetInfo AssetsLibraryView::widgetInfo()
|
||||||
{
|
{
|
||||||
if (m_widget.isNull()) {
|
if (m_widget.isNull()) {
|
||||||
m_widget = new AssetsLibraryWidget{imageCacheData()->cache,
|
m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache,
|
||||||
imageCacheData()->asynchronousFontImageCache,
|
imageCacheData()->synchronousFontImageCache};
|
||||||
imageCacheData()->synchronousFontImageCache};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, 0, tr("Assets"));
|
return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, 0, tr("Assets"));
|
||||||
@@ -128,49 +113,18 @@ void AssetsLibraryView::setResourcePath(const QString &resourcePath)
|
|||||||
m_lastResourcePath = resourcePath;
|
m_lastResourcePath = resourcePath;
|
||||||
|
|
||||||
if (m_widget.isNull()) {
|
if (m_widget.isNull()) {
|
||||||
m_widget = new AssetsLibraryWidget{m_imageCacheData->cache,
|
m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache,
|
||||||
m_imageCacheData->asynchronousFontImageCache,
|
imageCacheData()->synchronousFontImageCache};
|
||||||
m_imageCacheData->synchronousFontImageCache};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_widget->setResourcePath(resourcePath);
|
m_widget->setResourcePath(resourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageCacheData *AssetsLibraryView::imageCacheData()
|
AssetsLibraryView::ImageCacheData *AssetsLibraryView::imageCacheData()
|
||||||
{
|
{
|
||||||
std::call_once(imageCacheFlag, [this]() {
|
std::call_once(imageCacheFlag,
|
||||||
m_imageCacheData = std::make_unique<ImageCacheData>();
|
[this]() { m_imageCacheData = std::make_unique<ImageCacheData>(); });
|
||||||
auto setTargetInImageCache =
|
|
||||||
[imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) {
|
|
||||||
if (target == imageCacheData->collector.target())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (target)
|
|
||||||
imageCacheData->cache.clean();
|
|
||||||
|
|
||||||
imageCacheData->collector.setTarget(target);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (auto project = ProjectExplorer::SessionManager::startupProject(); project) {
|
|
||||||
m_imageCacheData->collector.setTarget(project->activeTarget());
|
|
||||||
connect(project,
|
|
||||||
&ProjectExplorer::Project::activeTargetChanged,
|
|
||||||
this,
|
|
||||||
setTargetInImageCache);
|
|
||||||
}
|
|
||||||
connect(ProjectExplorer::SessionManager::instance(),
|
|
||||||
&ProjectExplorer::SessionManager::startupProjectChanged,
|
|
||||||
this,
|
|
||||||
[=](ProjectExplorer::Project *project) {
|
|
||||||
setTargetInImageCache(activeTarget(project));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return m_imageCacheData.get();
|
return m_imageCacheData.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
AsynchronousImageCache &AssetsLibraryView::imageCache()
|
|
||||||
{
|
|
||||||
return imageCacheData()->cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -34,7 +34,6 @@
|
|||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class AssetsLibraryWidget;
|
class AssetsLibraryWidget;
|
||||||
class ImageCacheData;
|
|
||||||
class AsynchronousImageCache;
|
class AsynchronousImageCache;
|
||||||
|
|
||||||
class AssetsLibraryView : public AbstractView
|
class AssetsLibraryView : public AbstractView
|
||||||
@@ -54,9 +53,8 @@ public:
|
|||||||
|
|
||||||
void setResourcePath(const QString &resourcePath);
|
void setResourcePath(const QString &resourcePath);
|
||||||
|
|
||||||
AsynchronousImageCache &imageCache();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class ImageCacheData;
|
||||||
ImageCacheData *imageCacheData();
|
ImageCacheData *imageCacheData();
|
||||||
|
|
||||||
std::once_flag imageCacheFlag;
|
std::once_flag imageCacheFlag;
|
||||||
|
@@ -110,16 +110,14 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event)
|
|||||||
return QObject::eventFilter(obj, event);
|
return QObject::eventFilter(obj, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache,
|
AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache,
|
||||||
AsynchronousImageCache &asynchronousFontImageCache,
|
SynchronousImageCache &synchronousFontImageCache)
|
||||||
SynchronousImageCache &synchronousFontImageCache)
|
|
||||||
: m_itemIconSize(24, 24)
|
: m_itemIconSize(24, 24)
|
||||||
, m_fontImageCache(synchronousFontImageCache)
|
, m_fontImageCache(synchronousFontImageCache)
|
||||||
, m_assetsIconProvider(new AssetsLibraryIconProvider(synchronousFontImageCache))
|
, m_assetsIconProvider(new AssetsLibraryIconProvider(synchronousFontImageCache))
|
||||||
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
|
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
|
||||||
, m_assetsModel(new AssetsLibraryModel(m_fileSystemWatcher, this))
|
, m_assetsModel(new AssetsLibraryModel(m_fileSystemWatcher, this))
|
||||||
, m_assetsWidget(new QQuickWidget(this))
|
, m_assetsWidget(new QQuickWidget(this))
|
||||||
, m_imageCache{imageCache}
|
|
||||||
{
|
{
|
||||||
m_assetCompressionTimer.setInterval(200);
|
m_assetCompressionTimer.setInterval(200);
|
||||||
m_assetCompressionTimer.setSingleShot(true);
|
m_assetCompressionTimer.setSingleShot(true);
|
||||||
|
@@ -60,8 +60,7 @@ class AssetsLibraryWidget : public QFrame
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AssetsLibraryWidget(AsynchronousImageCache &imageCache,
|
AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache,
|
||||||
AsynchronousImageCache &asynchronousFontImageCache,
|
|
||||||
SynchronousImageCache &synchronousFontImageCache);
|
SynchronousImageCache &synchronousFontImageCache);
|
||||||
~AssetsLibraryWidget();
|
~AssetsLibraryWidget();
|
||||||
|
|
||||||
@@ -110,7 +109,6 @@ private:
|
|||||||
std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
|
std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
|
||||||
|
|
||||||
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
|
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
|
||||||
AsynchronousImageCache &m_imageCache;
|
|
||||||
QPointer<Model> m_model;
|
QPointer<Model> m_model;
|
||||||
QStringList m_assetsToDrag;
|
QStringList m_assetsToDrag;
|
||||||
bool m_updateRetry = false;
|
bool m_updateRetry = false;
|
||||||
|
@@ -41,29 +41,6 @@ typedef unsigned char RGBE[4];
|
|||||||
#define B 2
|
#define B 2
|
||||||
#define E 3
|
#define E 3
|
||||||
|
|
||||||
struct M8E8
|
|
||||||
{
|
|
||||||
quint8 m;
|
|
||||||
quint8 e;
|
|
||||||
M8E8() : m(0), e(0){
|
|
||||||
}
|
|
||||||
M8E8(const float val) {
|
|
||||||
float l2 = 1.f + std::floor(log2f(val));
|
|
||||||
float mm = val / powf(2.f, l2);
|
|
||||||
m = quint8(mm * 255.f);
|
|
||||||
e = quint8(l2 + 128);
|
|
||||||
}
|
|
||||||
M8E8(const float val, quint8 exp) {
|
|
||||||
if (val <= 0) {
|
|
||||||
m = e = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float mm = val / powf(2.f, exp - 128);
|
|
||||||
m = quint8(mm * 255.f);
|
|
||||||
e = exp;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QByteArray fileToByteArray(QString const &filename)
|
QByteArray fileToByteArray(QString const &filename)
|
||||||
{
|
{
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
@@ -147,17 +124,18 @@ void decodeScanlineToImageData(RGBE *scanline, int width, void *outBuf, quint32
|
|||||||
rgbaF32[R] = convertComponent(scanline[i][E], scanline[i][R]);
|
rgbaF32[R] = convertComponent(scanline[i][E], scanline[i][R]);
|
||||||
rgbaF32[G] = convertComponent(scanline[i][E], scanline[i][G]);
|
rgbaF32[G] = convertComponent(scanline[i][E], scanline[i][G]);
|
||||||
rgbaF32[B] = convertComponent(scanline[i][E], scanline[i][B]);
|
rgbaF32[B] = convertComponent(scanline[i][E], scanline[i][B]);
|
||||||
rgbaF32[3] = 1.0f;
|
rgbaF32[E] = 1.0f;
|
||||||
|
|
||||||
float max = qMax(rgbaF32[R], qMax(rgbaF32[G], rgbaF32[B]));
|
|
||||||
M8E8 ex(max);
|
|
||||||
M8E8 a(rgbaF32[R], ex.e);
|
|
||||||
M8E8 b(rgbaF32[G], ex.e);
|
|
||||||
M8E8 c(rgbaF32[B], ex.e);
|
|
||||||
quint8 *dst = target + i * 4;
|
quint8 *dst = target + i * 4;
|
||||||
dst[0] = c.m;
|
|
||||||
dst[1] = b.m;
|
auto getColor = [](float src) -> quint8 {
|
||||||
dst[2] = a.m;
|
const float srcColor = (src > 1.0f) ? 1.0f : src;
|
||||||
|
return quint8(srcColor * 255.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
dst[0] = getColor(rgbaF32[B]);
|
||||||
|
dst[1] = getColor(rgbaF32[G]);
|
||||||
|
dst[2] = getColor(rgbaF32[R]);
|
||||||
dst[3] = 255;
|
dst[3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,8 @@
|
|||||||
#include <qmldesignerplugin.h>
|
#include <qmldesignerplugin.h>
|
||||||
#include <qmldesignerconstants.h>
|
#include <qmldesignerconstants.h>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
static inline bool itemsHaveSameParent(const QList<ModelNode> &siblingList)
|
static inline bool itemsHaveSameParent(const QList<ModelNode> &siblingList)
|
||||||
@@ -94,10 +96,24 @@ bool selectionHasSameParent(const SelectionContext &selectionState)
|
|||||||
return !selectionState.selectedModelNodes().isEmpty() && itemsHaveSameParent(selectionState.selectedModelNodes());
|
return !selectionState.selectedModelNodes().isEmpty() && itemsHaveSameParent(selectionState.selectedModelNodes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fileComponentExists(const ModelNode &modelNode)
|
||||||
|
{
|
||||||
|
if (!modelNode.metaInfo().isFileComponent())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const QString fileName = modelNode.metaInfo().componentFileName();
|
||||||
|
|
||||||
|
if (fileName.contains("qml/QtQuick"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return QFile::exists(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
bool selectionIsComponent(const SelectionContext &selectionState)
|
bool selectionIsComponent(const SelectionContext &selectionState)
|
||||||
{
|
{
|
||||||
return selectionState.currentSingleSelectedNode().isValid()
|
return selectionState.currentSingleSelectedNode().isValid()
|
||||||
&& selectionState.currentSingleSelectedNode().isComponent();
|
&& selectionState.currentSingleSelectedNode().isComponent()
|
||||||
|
&& fileComponentExists(selectionState.currentSingleSelectedNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool selectionIsImported3DAsset(const SelectionContext &selectionState)
|
bool selectionIsImported3DAsset(const SelectionContext &selectionState)
|
||||||
|
@@ -55,6 +55,7 @@
|
|||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -73,7 +74,11 @@ static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString
|
|||||||
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int rowHeight = 26;
|
static const int rowHeight = 28;
|
||||||
|
static const int checkBoxColWidth = 18;
|
||||||
|
static const int labelMinWidth = 130;
|
||||||
|
static const int controlMinWidth = 65;
|
||||||
|
static const int columnSpacing = 16;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +125,12 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
|||||||
|
|
||||||
ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
|
ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
|
||||||
|
|
||||||
|
ui->advancedSettingsButton->setStyleSheet(
|
||||||
|
"QPushButton#advancedSettingsButton {background-color: transparent}");
|
||||||
|
ui->advancedSettingsButton->setStyleSheet(
|
||||||
|
QString("QPushButton { border: none; color :%1 }").arg(
|
||||||
|
Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_HighlightColor).name()));
|
||||||
|
|
||||||
QStringList importPaths;
|
QStringList importPaths;
|
||||||
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||||
if (doc) {
|
if (doc) {
|
||||||
@@ -196,6 +207,13 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
|||||||
++optIndex;
|
++optIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize lists in loop for Qt5 compatibility
|
||||||
|
for (int i = 0; i < optIndex; ++i) {
|
||||||
|
m_simpleData.contentWidgets.append({});
|
||||||
|
m_advancedData.contentWidgets.append({});
|
||||||
|
m_labelToControlWidgetMaps.append(QHash<QString, QWidget *>());
|
||||||
|
}
|
||||||
|
|
||||||
// Create tab for each supported extension group that also has files included in the import
|
// Create tab for each supported extension group that also has files included in the import
|
||||||
QMap<QString, int> tabMap; // QMap used for alphabetical order
|
QMap<QString, int> tabMap; // QMap used for alphabetical order
|
||||||
for (const auto &file : qAsConst(m_quick3DFiles)) {
|
for (const auto &file : qAsConst(m_quick3DFiles)) {
|
||||||
@@ -214,22 +232,21 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
|||||||
auto tabIt = tabMap.constBegin();
|
auto tabIt = tabMap.constBegin();
|
||||||
while (tabIt != tabMap.constEnd()) {
|
while (tabIt != tabMap.constEnd()) {
|
||||||
createTab(tabIt.key(), tabIt.value(), groups[tabIt.value()]);
|
createTab(tabIt.key(), tabIt.value(), groups[tabIt.value()]);
|
||||||
++tabIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pad all tabs to same height
|
auto padGrid = [](QWidget *widget, int optionRows) {
|
||||||
for (int i = 0; i < ui->tabWidget->count(); ++i) {
|
auto grid = qobject_cast<QGridLayout *>(widget->layout());
|
||||||
auto optionsArea = qobject_cast<QScrollArea *>(ui->tabWidget->widget(i));
|
|
||||||
if (optionsArea && optionsArea->widget()) {
|
|
||||||
auto grid = qobject_cast<QGridLayout *>(optionsArea->widget()->layout());
|
|
||||||
if (grid) {
|
if (grid) {
|
||||||
int rows = grid->rowCount();
|
int rows = grid->rowCount();
|
||||||
for (int j = rows; j < m_optionsRows; ++j) {
|
for (int i = rows; i <optionRows; ++i) {
|
||||||
grid->addWidget(new QWidget(optionsArea->widget()), j, 0);
|
grid->addWidget(new QWidget(widget), i, 0);
|
||||||
grid->setRowMinimumHeight(j, rowHeight);
|
grid->setRowMinimumHeight(i, rowHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
padGrid(m_simpleData.contentWidgets[tabIt.value()], m_simpleData.optionsRows);
|
||||||
|
padGrid(m_advancedData.contentWidgets[tabIt.value()], m_advancedData.optionsRows);
|
||||||
|
|
||||||
|
++tabIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->setCurrentIndex(0);
|
ui->tabWidget->setCurrentIndex(0);
|
||||||
@@ -257,8 +274,10 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
|||||||
for (const auto &file : qAsConst(m_quick3DFiles))
|
for (const auto &file : qAsConst(m_quick3DFiles))
|
||||||
addInfo(file);
|
addInfo(file);
|
||||||
|
|
||||||
QTimer::singleShot(0, [this]() {
|
connect(ui->advancedSettingsButton, &QPushButton::clicked,
|
||||||
ui->tabWidget->setMaximumHeight(m_optionsHeight + ui->tabWidget->tabBar()->height() + 10);
|
this, &ItemLibraryAssetImportDialog::toggleAdvanced);
|
||||||
|
|
||||||
|
QTimer::singleShot(0, this, [this]() {
|
||||||
updateUi();
|
updateUi();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -390,28 +409,45 @@ void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode,
|
|||||||
void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex,
|
void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex,
|
||||||
const QJsonObject &groups)
|
const QJsonObject &groups)
|
||||||
{
|
{
|
||||||
const int checkBoxColWidth = 18;
|
|
||||||
const int labelMinWidth = 130;
|
|
||||||
const int controlMinWidth = 65;
|
|
||||||
const int columnSpacing = 16;
|
|
||||||
int rowIndex[2] = {0, 0};
|
|
||||||
|
|
||||||
QJsonObject &options = m_importOptions[optionsIndex];
|
|
||||||
|
|
||||||
// First index has ungrouped widgets, rest are groups
|
|
||||||
// First item in each real group is group label
|
|
||||||
QVector<QVector<QPair<QWidget *, QWidget *>>> widgets;
|
|
||||||
QHash<QString, int> groupIndexMap;
|
|
||||||
QHash<QString, QPair<QWidget *, QWidget *>> optionToWidgetsMap;
|
|
||||||
QHash<QString, QJsonArray> conditionMap;
|
|
||||||
QHash<QWidget *, QWidget *> conditionalWidgetMap;
|
|
||||||
QHash<QString, QString> optionToGroupMap;
|
|
||||||
|
|
||||||
auto optionsArea = new QScrollArea(ui->tabWidget);
|
auto optionsArea = new QScrollArea(ui->tabWidget);
|
||||||
optionsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
optionsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
auto optionsAreaContents = new QWidget(optionsArea);
|
auto optionsAreaContents = new QWidget(optionsArea);
|
||||||
|
m_simpleData.contentWidgets[optionsIndex] = new QWidget(optionsAreaContents);
|
||||||
|
m_advancedData.contentWidgets[optionsIndex] = new QWidget(optionsAreaContents);
|
||||||
|
|
||||||
auto layout = new QGridLayout(optionsAreaContents);
|
// Advanced widgets need to be set up first, as simple widgets will connect to those
|
||||||
|
QGridLayout *advancedLayout = createOptionsGrid(m_advancedData.contentWidgets[optionsIndex], true,
|
||||||
|
optionsIndex, groups);
|
||||||
|
QGridLayout *simpleLayout = createOptionsGrid(m_simpleData.contentWidgets[optionsIndex], false,
|
||||||
|
optionsIndex, groups);
|
||||||
|
|
||||||
|
m_advancedData.contentWidgets[optionsIndex]->setLayout(advancedLayout);
|
||||||
|
m_simpleData.contentWidgets[optionsIndex]->setLayout(simpleLayout);
|
||||||
|
|
||||||
|
m_advancedData.contentWidgets[optionsIndex]->setVisible(false);
|
||||||
|
|
||||||
|
auto layout = new QVBoxLayout(optionsAreaContents);
|
||||||
|
layout->addWidget(m_simpleData.contentWidgets[optionsIndex]);
|
||||||
|
layout->addWidget(m_advancedData.contentWidgets[optionsIndex]);
|
||||||
|
|
||||||
|
optionsAreaContents->setContentsMargins(0, 0, 0, 0);
|
||||||
|
optionsAreaContents->setLayout(layout);
|
||||||
|
optionsAreaContents->setMinimumWidth(
|
||||||
|
(checkBoxColWidth + labelMinWidth + controlMinWidth) * 2 + columnSpacing);
|
||||||
|
optionsAreaContents->setObjectName("optionsAreaContents"); // For stylesheet
|
||||||
|
|
||||||
|
optionsArea->setWidget(optionsAreaContents);
|
||||||
|
optionsArea->setStyleSheet("QScrollArea {background-color: transparent}");
|
||||||
|
optionsAreaContents->setStyleSheet(
|
||||||
|
"QWidget#optionsAreaContents {background-color: transparent}");
|
||||||
|
|
||||||
|
ui->tabWidget->addTab(optionsArea, tr("%1 options").arg(tabLabel));
|
||||||
|
}
|
||||||
|
|
||||||
|
QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||||
|
QWidget *contentWidget, bool advanced, int optionsIndex, const QJsonObject &groups)
|
||||||
|
{
|
||||||
|
auto layout = new QGridLayout();
|
||||||
layout->setColumnMinimumWidth(0, checkBoxColWidth);
|
layout->setColumnMinimumWidth(0, checkBoxColWidth);
|
||||||
layout->setColumnMinimumWidth(1, labelMinWidth);
|
layout->setColumnMinimumWidth(1, labelMinWidth);
|
||||||
layout->setColumnMinimumWidth(2, controlMinWidth);
|
layout->setColumnMinimumWidth(2, controlMinWidth);
|
||||||
@@ -427,14 +463,29 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
layout->setColumnStretch(5, 4);
|
layout->setColumnStretch(5, 4);
|
||||||
layout->setColumnStretch(6, 2);
|
layout->setColumnStretch(6, 2);
|
||||||
|
|
||||||
|
// First index has ungrouped widgets, rest are groups
|
||||||
|
// First item in each real group is group label
|
||||||
|
QVector<QVector<QPair<QWidget *, QWidget *>>> widgets;
|
||||||
|
QHash<QString, int> groupIndexMap;
|
||||||
|
QHash<QString, QPair<QWidget *, QWidget *>> optionToWidgetsMap;
|
||||||
|
QHash<QString, QJsonArray> conditionMap;
|
||||||
|
QHash<QWidget *, QWidget *> conditionalWidgetMap;
|
||||||
|
QHash<QString, QString> optionToGroupMap;
|
||||||
|
|
||||||
|
int rowIndex[2] = {0, 0};
|
||||||
|
|
||||||
widgets.append(QVector<QPair<QWidget *, QWidget *>>());
|
widgets.append(QVector<QPair<QWidget *, QWidget *>>());
|
||||||
|
|
||||||
for (const auto &group : groups) {
|
const QStringList &groupIds = groups.keys();
|
||||||
|
for (const QString &groupId : groupIds) {
|
||||||
|
if (!advanced && !isSimpleGroup(groupId))
|
||||||
|
continue;
|
||||||
|
const auto &group = groups.value(groupId);
|
||||||
const QString name = group.toObject().value("name").toString();
|
const QString name = group.toObject().value("name").toString();
|
||||||
const QJsonArray items = group.toObject().value("items").toArray();
|
const QJsonArray items = group.toObject().value("items").toArray();
|
||||||
for (const auto &item : items)
|
for (const auto &item : items)
|
||||||
optionToGroupMap.insert(item.toString(), name);
|
optionToGroupMap.insert(item.toString(), name);
|
||||||
auto groupLabel = new QLabel(name, optionsAreaContents);
|
auto groupLabel = new QLabel(name, contentWidget);
|
||||||
QFont labelFont = groupLabel->font();
|
QFont labelFont = groupLabel->font();
|
||||||
labelFont.setBold(true);
|
labelFont.setBold(true);
|
||||||
groupLabel->setFont(labelFont);
|
groupLabel->setFont(labelFont);
|
||||||
@@ -442,8 +493,11 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
groupIndexMap.insert(name, widgets.size() - 1);
|
groupIndexMap.insert(name, widgets.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject &options = m_importOptions[optionsIndex];
|
||||||
const auto optKeys = options.keys();
|
const auto optKeys = options.keys();
|
||||||
for (const auto &optKey : optKeys) {
|
for (const auto &optKey : optKeys) {
|
||||||
|
if (!advanced && !isSimpleOption(optKey))
|
||||||
|
continue;
|
||||||
QJsonObject optObj = options.value(optKey).toObject();
|
QJsonObject optObj = options.value(optKey).toObject();
|
||||||
const QString optName = optObj.value("name").toString();
|
const QString optName = optObj.value("name").toString();
|
||||||
const QString optDesc = optObj.value("description").toString();
|
const QString optDesc = optObj.value("description").toString();
|
||||||
@@ -452,24 +506,41 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
QJsonValue optValue = optObj.value("value");
|
QJsonValue optValue = optObj.value("value");
|
||||||
QJsonArray conditions = optObj.value("conditions").toArray();
|
QJsonArray conditions = optObj.value("conditions").toArray();
|
||||||
|
|
||||||
auto *optLabel = new QLabel(optionsAreaContents);
|
auto *optLabel = new QLabel(contentWidget);
|
||||||
optLabel->setText(optName);
|
optLabel->setText(optName);
|
||||||
optLabel->setToolTip(optDesc);
|
optLabel->setToolTip(optDesc);
|
||||||
|
|
||||||
QWidget *optControl = nullptr;
|
QWidget *optControl = nullptr;
|
||||||
if (optType == "Boolean") {
|
if (optType == "Boolean") {
|
||||||
auto *optCheck = new QCheckBox(optionsAreaContents);
|
auto *optCheck = new QCheckBox(contentWidget);
|
||||||
optCheck->setChecked(optValue.toBool());
|
optCheck->setChecked(optValue.toBool());
|
||||||
optControl = optCheck;
|
optControl = optCheck;
|
||||||
QObject::connect(optCheck, &QCheckBox::toggled,
|
if (advanced) {
|
||||||
[this, optCheck, optKey, optionsIndex]() {
|
QObject::connect(optCheck, &QCheckBox::toggled, this,
|
||||||
QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
|
[this, optCheck, optKey, optionsIndex]() {
|
||||||
QJsonValue value(optCheck->isChecked());
|
QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
|
||||||
optObj.insert("value", value);
|
QJsonValue value(optCheck->isChecked());
|
||||||
m_importOptions[optionsIndex].insert(optKey, optObj);
|
optObj.insert("value", value);
|
||||||
});
|
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Simple options also exist in advanced, so don't connect simple controls directly
|
||||||
|
// to import options. Connect them instead to corresponding advanced controls.
|
||||||
|
auto *advCheck = qobject_cast<QCheckBox *>(
|
||||||
|
m_labelToControlWidgetMaps[optionsIndex].value(optKey));
|
||||||
|
if (advCheck) {
|
||||||
|
QObject::connect(optCheck, &QCheckBox::toggled, this, [optCheck, advCheck]() {
|
||||||
|
if (advCheck->isChecked() != optCheck->isChecked())
|
||||||
|
advCheck->setChecked(optCheck->isChecked());
|
||||||
|
});
|
||||||
|
QObject::connect(advCheck, &QCheckBox::toggled, this, [optCheck, advCheck]() {
|
||||||
|
if (advCheck->isChecked() != optCheck->isChecked())
|
||||||
|
optCheck->setChecked(advCheck->isChecked());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (optType == "Real") {
|
} else if (optType == "Real") {
|
||||||
auto *optSpin = new QDoubleSpinBox(optionsAreaContents);
|
auto *optSpin = new QDoubleSpinBox(contentWidget);
|
||||||
double min = -999999999.;
|
double min = -999999999.;
|
||||||
double max = 999999999.;
|
double max = 999999999.;
|
||||||
double step = 1.;
|
double step = 1.;
|
||||||
@@ -493,13 +564,31 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
optSpin->setSingleStep(step);
|
optSpin->setSingleStep(step);
|
||||||
optSpin->setMinimumWidth(controlMinWidth);
|
optSpin->setMinimumWidth(controlMinWidth);
|
||||||
optControl = optSpin;
|
optControl = optSpin;
|
||||||
QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
if (advanced) {
|
||||||
[this, optSpin, optKey, optionsIndex]() {
|
QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
|
||||||
QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
|
[this, optSpin, optKey, optionsIndex]() {
|
||||||
QJsonValue value(optSpin->value());
|
QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
|
||||||
optObj.insert("value", value);
|
QJsonValue value(optSpin->value());
|
||||||
m_importOptions[optionsIndex].insert(optKey, optObj);
|
optObj.insert("value", value);
|
||||||
});
|
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
auto *advSpin = qobject_cast<QDoubleSpinBox *>(
|
||||||
|
m_labelToControlWidgetMaps[optionsIndex].value(optKey));
|
||||||
|
if (advSpin) {
|
||||||
|
// Connect corresponding advanced control
|
||||||
|
QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||||
|
this, [optSpin, advSpin]() {
|
||||||
|
if (advSpin->value() != optSpin->value())
|
||||||
|
advSpin->setValue(optSpin->value());
|
||||||
|
});
|
||||||
|
QObject::connect(advSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||||
|
this, [optSpin, advSpin]() {
|
||||||
|
if (advSpin->value() != optSpin->value())
|
||||||
|
optSpin->setValue(advSpin->value());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning() << __FUNCTION__ << "Unsupported option type:" << optType;
|
qWarning() << __FUNCTION__ << "Unsupported option type:" << optType;
|
||||||
continue;
|
continue;
|
||||||
@@ -515,6 +604,8 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
else
|
else
|
||||||
widgets[0].append({optLabel, optControl});
|
widgets[0].append({optLabel, optControl});
|
||||||
optionToWidgetsMap.insert(optKey, {optLabel, optControl});
|
optionToWidgetsMap.insert(optKey, {optLabel, optControl});
|
||||||
|
if (advanced)
|
||||||
|
m_labelToControlWidgetMaps[optionsIndex].insert(optKey, optControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle conditions
|
// Handle conditions
|
||||||
@@ -562,7 +653,7 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
else
|
else
|
||||||
conditionalWidgetMap.insert(optCb, conControl);
|
conditionalWidgetMap.insert(optCb, conControl);
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
optCb, &QCheckBox::toggled,
|
optCb, &QCheckBox::toggled, optCb,
|
||||||
[optCb, conLabel, conControl, mode, enableConditionally]() {
|
[optCb, conLabel, conControl, mode, enableConditionally]() {
|
||||||
enableConditionally(optCb, conLabel, conControl, mode);
|
enableConditionally(optCb, conLabel, conControl, mode);
|
||||||
});
|
});
|
||||||
@@ -586,7 +677,7 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
enableConditionally(optSpin, conLabel, conControl, mode);
|
enableConditionally(optSpin, conLabel, conControl, mode);
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||||
[optSpin, conLabel, conControl, mode, enableConditionally]() {
|
optSpin, [optSpin, conLabel, conControl, mode, enableConditionally]() {
|
||||||
enableConditionally(optSpin, conLabel, conControl, mode);
|
enableConditionally(optSpin, conLabel, conControl, mode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -646,8 +737,13 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (widgets.size() == 1 && widgets[0].isEmpty()) {
|
if (widgets.size() == 1 && widgets[0].isEmpty()) {
|
||||||
layout->addWidget(new QLabel(tr("No options available for this type."),
|
if (advanced) {
|
||||||
optionsAreaContents), 0, 0, 2, 7, Qt::AlignCenter);
|
layout->addWidget(new QLabel(tr("No options available for this type."),
|
||||||
|
contentWidget), 0, 0, 2, 7, Qt::AlignCenter);
|
||||||
|
} else {
|
||||||
|
layout->addWidget(new QLabel(tr("No simple options available for this type."),
|
||||||
|
contentWidget), 0, 0, 2, 7, Qt::AlignCenter);
|
||||||
|
}
|
||||||
incrementColIndex(0);
|
incrementColIndex(0);
|
||||||
incrementColIndex(0);
|
incrementColIndex(0);
|
||||||
}
|
}
|
||||||
@@ -663,7 +759,7 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
for (int j = 1; j < groupWidgets.size(); ++j)
|
for (int j = 1; j < groupWidgets.size(); ++j)
|
||||||
insertOptionToLayout(col, groupWidgets[j]);
|
insertOptionToLayout(col, groupWidgets[j]);
|
||||||
// Add a separator line after each group
|
// Add a separator line after each group
|
||||||
auto *separator = new QFrame(optionsAreaContents);
|
auto *separator = new QFrame(contentWidget);
|
||||||
separator->setMaximumHeight(1);
|
separator->setMaximumHeight(1);
|
||||||
separator->setFrameShape(QFrame::HLine);
|
separator->setFrameShape(QFrame::HLine);
|
||||||
separator->setFrameShadow(QFrame::Sunken);
|
separator->setFrameShadow(QFrame::Sunken);
|
||||||
@@ -681,38 +777,56 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option
|
|||||||
}
|
}
|
||||||
|
|
||||||
int optionRows = qMax(rowIndex[0], rowIndex[1]);
|
int optionRows = qMax(rowIndex[0], rowIndex[1]);
|
||||||
m_optionsRows = qMax(m_optionsRows, optionRows);
|
int &globalOptionRows = advanced ? m_advancedData.optionsRows : m_simpleData.optionsRows;
|
||||||
m_optionsHeight = qMax(rowHeight * optionRows + 16, m_optionsHeight);
|
int &globalOptionsHeight = advanced ? m_advancedData.optionsHeight : m_simpleData.optionsHeight;
|
||||||
layout->setContentsMargins(8, 8, 8, 8);
|
globalOptionRows = qMax(globalOptionRows, optionRows);
|
||||||
optionsAreaContents->setContentsMargins(0, 0, 0, 0);
|
globalOptionsHeight = qMax(rowHeight * optionRows + 20, globalOptionsHeight);
|
||||||
optionsAreaContents->setLayout(layout);
|
layout->setContentsMargins(8, 8, 8, 0);
|
||||||
optionsAreaContents->setMinimumWidth(
|
|
||||||
(checkBoxColWidth + labelMinWidth + controlMinWidth) * 2 + columnSpacing);
|
|
||||||
optionsAreaContents->setObjectName("optionsAreaContents"); // For stylesheet
|
|
||||||
|
|
||||||
optionsArea->setWidget(optionsAreaContents);
|
return layout;
|
||||||
optionsArea->setStyleSheet("QScrollArea {background-color: transparent}");
|
|
||||||
optionsAreaContents->setStyleSheet(
|
|
||||||
"QWidget#optionsAreaContents {background-color: transparent}");
|
|
||||||
|
|
||||||
ui->tabWidget->addTab(optionsArea, tr("%1 options").arg(tabLabel));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::updateUi()
|
void ItemLibraryAssetImportDialog::updateUi()
|
||||||
{
|
{
|
||||||
auto optionsArea = qobject_cast<QScrollArea *>(ui->tabWidget->currentWidget());
|
auto optionsArea = qobject_cast<QScrollArea *>(ui->tabWidget->currentWidget());
|
||||||
if (optionsArea) {
|
if (optionsArea) {
|
||||||
|
int optionsHeight = m_advancedMode ? m_advancedData.optionsHeight
|
||||||
|
: m_simpleData.optionsHeight;
|
||||||
|
|
||||||
|
ui->tabWidget->setMaximumHeight(optionsHeight + ui->tabWidget->tabBar()->height() + 10);
|
||||||
auto optionsAreaContents = optionsArea->widget();
|
auto optionsAreaContents = optionsArea->widget();
|
||||||
int scrollBarWidth = optionsArea->verticalScrollBar()->isVisible()
|
int scrollBarWidth = optionsArea->verticalScrollBar()->isVisible()
|
||||||
? optionsArea->verticalScrollBar()->width() : 0;
|
? optionsArea->verticalScrollBar()->width() : 0;
|
||||||
optionsAreaContents->resize(optionsArea->contentsRect().width()
|
|
||||||
- scrollBarWidth - 8, m_optionsHeight);
|
optionsAreaContents->resize(optionsArea->contentsRect().width() - scrollBarWidth - 8,
|
||||||
|
optionsHeight);
|
||||||
|
|
||||||
|
resize(width(), m_dialogHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ItemLibraryAssetImportDialog::isSimpleGroup(const QString &id)
|
||||||
|
{
|
||||||
|
static QStringList simpleGroups {
|
||||||
|
"globalScale"
|
||||||
|
};
|
||||||
|
|
||||||
|
return simpleGroups.contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemLibraryAssetImportDialog::isSimpleOption(const QString &id)
|
||||||
|
{
|
||||||
|
static QStringList simpleOptions {
|
||||||
|
"globalScale",
|
||||||
|
"globalScaleValue"
|
||||||
|
};
|
||||||
|
|
||||||
|
return simpleOptions.contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
|
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event)
|
m_dialogHeight = event->size().height();
|
||||||
updateUi();
|
updateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,4 +915,27 @@ void ItemLibraryAssetImportDialog::onClose()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemLibraryAssetImportDialog::toggleAdvanced()
|
||||||
|
{
|
||||||
|
m_advancedMode = !m_advancedMode;
|
||||||
|
for (const auto &widget : qAsConst(m_simpleData.contentWidgets)) {
|
||||||
|
if (widget)
|
||||||
|
widget->setVisible(!m_advancedMode);
|
||||||
|
}
|
||||||
|
for (const auto &widget : qAsConst(m_advancedData.contentWidgets)) {
|
||||||
|
if (widget)
|
||||||
|
widget->setVisible(m_advancedMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_advancedMode)
|
||||||
|
ui->advancedSettingsButton->setText(tr("Hide Advanced Options"));
|
||||||
|
else
|
||||||
|
ui->advancedSettingsButton->setText(tr("Show All Options"));
|
||||||
|
|
||||||
|
int diff = qMin(300, m_advancedData.optionsHeight - m_simpleData.optionsHeight);
|
||||||
|
m_dialogHeight = qMax(350, m_dialogHeight + (m_advancedMode ? diff : -diff));
|
||||||
|
|
||||||
|
updateUi();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,10 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QGridLayout;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
class OutputFormatter;
|
class OutputFormatter;
|
||||||
}
|
}
|
||||||
@@ -76,21 +80,37 @@ private:
|
|||||||
void onImportNearlyFinished();
|
void onImportNearlyFinished();
|
||||||
void onImportFinished();
|
void onImportFinished();
|
||||||
void onClose();
|
void onClose();
|
||||||
|
void toggleAdvanced();
|
||||||
|
|
||||||
void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
|
void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
|
||||||
|
QGridLayout *createOptionsGrid(QWidget *contentWidget, bool advanced, int optionsIndex,
|
||||||
|
const QJsonObject &groups);
|
||||||
void updateUi();
|
void updateUi();
|
||||||
|
|
||||||
|
bool isSimpleGroup(const QString &id);
|
||||||
|
bool isSimpleOption(const QString &id);
|
||||||
|
|
||||||
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
|
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
|
||||||
Utils::OutputFormatter *m_outputFormatter = nullptr;
|
Utils::OutputFormatter *m_outputFormatter = nullptr;
|
||||||
|
|
||||||
|
struct OptionsData
|
||||||
|
{
|
||||||
|
int optionsRows = 0;
|
||||||
|
int optionsHeight = 0;
|
||||||
|
QList<QWidget *> contentWidgets; // Tab content widgets
|
||||||
|
};
|
||||||
|
|
||||||
QStringList m_quick3DFiles;
|
QStringList m_quick3DFiles;
|
||||||
QString m_quick3DImportPath;
|
QString m_quick3DImportPath;
|
||||||
ItemLibraryAssetImporter m_importer;
|
ItemLibraryAssetImporter m_importer;
|
||||||
QVector<QJsonObject> m_importOptions;
|
QVector<QJsonObject> m_importOptions;
|
||||||
QHash<QString, int> m_extToImportOptionsMap;
|
QHash<QString, int> m_extToImportOptionsMap;
|
||||||
int m_optionsHeight = 0;
|
|
||||||
int m_optionsRows = 0;
|
|
||||||
QSet<QString> m_preselectedFilesForOverwrite;
|
QSet<QString> m_preselectedFilesForOverwrite;
|
||||||
bool m_closeOnFinish = true;
|
bool m_closeOnFinish = true;
|
||||||
|
QList<QHash<QString, QWidget *>> m_labelToControlWidgetMaps;
|
||||||
|
OptionsData m_simpleData;
|
||||||
|
OptionsData m_advancedData;
|
||||||
|
bool m_advancedMode = false;
|
||||||
|
int m_dialogHeight = 350;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -6,68 +6,118 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>631</width>
|
<width>630</width>
|
||||||
<height>750</height>
|
<height>350</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Asset Import</string>
|
<string>Asset Import</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
<item>
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="sizePolicy">
|
<item>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<horstretch>0</horstretch>
|
<property name="sizePolicy">
|
||||||
<verstretch>2</verstretch>
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
</sizepolicy>
|
<horstretch>0</horstretch>
|
||||||
</property>
|
<verstretch>2</verstretch>
|
||||||
<property name="currentIndex">
|
</sizepolicy>
|
||||||
<number>0</number>
|
</property>
|
||||||
</property>
|
<property name="currentIndex">
|
||||||
<property name="tabBarAutoHide">
|
<number>0</number>
|
||||||
<bool>false</bool>
|
</property>
|
||||||
</property>
|
<property name="tabBarAutoHide">
|
||||||
<widget class="QWidget" name="modelOptionsTab">
|
<bool>false</bool>
|
||||||
<attribute name="title">
|
</property>
|
||||||
<string>Import Options</string>
|
<widget class="QWidget" name="modelOptionsTab">
|
||||||
</attribute>
|
<attribute name="title">
|
||||||
</widget>
|
<string>Import Options</string>
|
||||||
</widget>
|
</attribute>
|
||||||
</item>
|
</widget>
|
||||||
<item>
|
</widget>
|
||||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
</item>
|
||||||
<property name="sizePolicy">
|
<item>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<horstretch>0</horstretch>
|
<item>
|
||||||
<verstretch>1</verstretch>
|
<spacer name="horizontalSpacer">
|
||||||
</sizepolicy>
|
<property name="orientation">
|
||||||
</property>
|
<enum>Qt::Horizontal</enum>
|
||||||
<property name="readOnly">
|
</property>
|
||||||
<bool>true</bool>
|
<property name="sizeHint" stdset="0">
|
||||||
</property>
|
<size>
|
||||||
</widget>
|
<width>80</width>
|
||||||
</item>
|
<height>20</height>
|
||||||
<item>
|
</size>
|
||||||
<widget class="QLabel" name="progressLabel">
|
</property>
|
||||||
<property name="text">
|
</spacer>
|
||||||
<string/>
|
</item>
|
||||||
</property>
|
<item>
|
||||||
</widget>
|
<widget class="QPushButton" name="advancedSettingsButton">
|
||||||
</item>
|
<property name="text">
|
||||||
<item>
|
<string>Show All Settings</string>
|
||||||
<widget class="QProgressBar" name="progressBar">
|
</property>
|
||||||
<property name="value">
|
</widget>
|
||||||
<number>0</number>
|
</item>
|
||||||
</property>
|
<item>
|
||||||
</widget>
|
<spacer name="horizontalSpacer_2">
|
||||||
</item>
|
<property name="orientation">
|
||||||
<item>
|
<enum>Qt::Horizontal</enum>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
</property>
|
||||||
<property name="standardButtons">
|
<property name="sizeType">
|
||||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>8</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="progressLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
@@ -62,7 +62,7 @@ ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class ImageCacheData
|
class ItemLibraryView::ImageCacheData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Sqlite::Database database{Utils::PathString{
|
Sqlite::Database database{Utils::PathString{
|
||||||
@@ -71,7 +71,7 @@ public:
|
|||||||
Sqlite::LockingMode::Normal};
|
Sqlite::LockingMode::Normal};
|
||||||
ImageCacheStorage<Sqlite::Database> storage{database};
|
ImageCacheStorage<Sqlite::Database> storage{database};
|
||||||
ImageCacheConnectionManager connectionManager;
|
ImageCacheConnectionManager connectionManager;
|
||||||
ImageCacheCollector collector{connectionManager};
|
ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}};
|
||||||
ImageCacheFontCollector fontCollector;
|
ImageCacheFontCollector fontCollector;
|
||||||
ImageCacheGenerator generator{collector, storage};
|
ImageCacheGenerator generator{collector, storage};
|
||||||
ImageCacheGenerator fontGenerator{fontCollector, storage};
|
ImageCacheGenerator fontGenerator{fontCollector, storage};
|
||||||
@@ -177,7 +177,7 @@ void ItemLibraryView::usedImportsChanged(const QList<Import> &usedImports)
|
|||||||
m_widget->updateUsedImports(usedImports);
|
m_widget->updateUsedImports(usedImports);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageCacheData *ItemLibraryView::imageCacheData()
|
ItemLibraryView::ImageCacheData *ItemLibraryView::imageCacheData()
|
||||||
{
|
{
|
||||||
std::call_once(imageCacheFlag, [this]() {
|
std::call_once(imageCacheFlag, [this]() {
|
||||||
m_imageCacheData = std::make_unique<ImageCacheData>();
|
m_imageCacheData = std::make_unique<ImageCacheData>();
|
||||||
|
@@ -34,7 +34,6 @@
|
|||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class ItemLibraryWidget;
|
class ItemLibraryWidget;
|
||||||
class ImageCacheData;
|
|
||||||
class AsynchronousImageCache;
|
class AsynchronousImageCache;
|
||||||
|
|
||||||
class ItemLibraryView : public AbstractView
|
class ItemLibraryView : public AbstractView
|
||||||
@@ -65,6 +64,7 @@ protected:
|
|||||||
void updateImports();
|
void updateImports();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class ImageCacheData;
|
||||||
ImageCacheData *imageCacheData();
|
ImageCacheData *imageCacheData();
|
||||||
|
|
||||||
std::once_flag imageCacheFlag;
|
std::once_flag imageCacheFlag;
|
||||||
|
@@ -273,8 +273,10 @@ void ItemLibraryWidget::handleAddImport(int index)
|
|||||||
Import import = m_addModuleModel->getImportAt(index);
|
Import import = m_addModuleModel->getImportAt(index);
|
||||||
if (import.isLibraryImport() && (import.url().startsWith("QtQuick")
|
if (import.isLibraryImport() && (import.url().startsWith("QtQuick")
|
||||||
|| import.url().startsWith("SimulinkConnector"))) {
|
|| import.url().startsWith("SimulinkConnector"))) {
|
||||||
|
QString importStr = import.toImportString();
|
||||||
|
importStr.replace(' ', '-');
|
||||||
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED
|
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED
|
||||||
+ import.toImportString());
|
+ importStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Import> imports;
|
QList<Import> imports;
|
||||||
|
@@ -28,30 +28,87 @@
|
|||||||
#include <utils/stylehelper.h>
|
#include <utils/stylehelper.h>
|
||||||
#include <theme.h>
|
#include <theme.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QStyle>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
LineEdit::LineEdit(QWidget *parent)
|
||||||
|
: QLineEdit(parent)
|
||||||
|
{
|
||||||
|
clearButton = new QToolButton(this);
|
||||||
|
|
||||||
|
const QString fontName = "qtds_propertyIconFont.ttf";
|
||||||
|
const int searchIconSize = 16;
|
||||||
|
const int clearIconSize = 12;
|
||||||
|
const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::DSiconColor));
|
||||||
|
|
||||||
|
const QIcon searchIcon
|
||||||
|
= Utils::StyleHelper::getIconFromIconFont(fontName,
|
||||||
|
QmlDesigner::Theme::getIconUnicode(
|
||||||
|
QmlDesigner::Theme::Icon::search),
|
||||||
|
searchIconSize,
|
||||||
|
searchIconSize,
|
||||||
|
iconColor);
|
||||||
|
|
||||||
|
const QIcon clearIcon
|
||||||
|
= Utils::StyleHelper::getIconFromIconFont(fontName,
|
||||||
|
QmlDesigner::Theme::getIconUnicode(
|
||||||
|
QmlDesigner::Theme::Icon::closeCross),
|
||||||
|
clearIconSize,
|
||||||
|
clearIconSize,
|
||||||
|
iconColor);
|
||||||
|
|
||||||
|
addAction(searchIcon, QLineEdit::LeadingPosition);
|
||||||
|
|
||||||
|
clearButton->setIcon(clearIcon);
|
||||||
|
clearButton->setIconSize(QSize(clearIconSize, clearIconSize));
|
||||||
|
clearButton->setCursor(Qt::ArrowCursor);
|
||||||
|
clearButton->hide();
|
||||||
|
clearButton->setStyleSheet(Theme::replaceCssColors(
|
||||||
|
QString("QToolButton { border: none; padding: 0px; }"
|
||||||
|
"QToolButton:hover { background: creatorTheme.DScontrolBackgroundHover; }")));
|
||||||
|
|
||||||
|
setClearButtonEnabled(false);
|
||||||
|
|
||||||
|
connect(clearButton, &QToolButton::clicked, this, &QLineEdit::clear);
|
||||||
|
connect(this, &QLineEdit::textChanged, this, &LineEdit::updateClearButton);
|
||||||
|
|
||||||
|
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||||
|
setStyleSheet(QString("QLineEdit { padding-right: %1px; } ")
|
||||||
|
.arg(clearButton->sizeHint().width() + frameWidth + 8));
|
||||||
|
|
||||||
|
setFixedHeight(29);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEdit::resizeEvent(QResizeEvent *)
|
||||||
|
{
|
||||||
|
QSize hint = clearButton->sizeHint();
|
||||||
|
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||||
|
|
||||||
|
clearButton->move(rect().right() - frameWidth - hint.width() - 3,
|
||||||
|
(rect().bottom() + 1 - hint.height()) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEdit::updateClearButton(const QString& text)
|
||||||
|
{
|
||||||
|
clearButton->setVisible(!text.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
NavigatorSearchWidget::NavigatorSearchWidget(QWidget *parent)
|
NavigatorSearchWidget::NavigatorSearchWidget(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
auto layout = new QBoxLayout(QBoxLayout::LeftToRight);
|
auto layout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->setContentsMargins(5, 5, 5, 3);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
const QString fontName = "qtds_propertyIconFont.ttf";
|
m_textField = new LineEdit;
|
||||||
const int iconSize = 15;
|
m_textField->setPlaceholderText(tr("Search"));
|
||||||
const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::IconsBaseColor));
|
|
||||||
const QIcon searchIcon = Utils::StyleHelper::getIconFromIconFont(
|
|
||||||
fontName, QmlDesigner::Theme::getIconUnicode(QmlDesigner::Theme::Icon::search),
|
|
||||||
iconSize, iconSize, iconColor);
|
|
||||||
|
|
||||||
m_textField = new QLineEdit;
|
|
||||||
m_textField->setPlaceholderText(tr("Filter"));
|
|
||||||
m_textField->setFrame(false);
|
m_textField->setFrame(false);
|
||||||
m_textField->setClearButtonEnabled(true);
|
|
||||||
m_textField->addAction(searchIcon, QLineEdit::LeadingPosition);
|
|
||||||
|
|
||||||
connect(m_textField, &QLineEdit::textChanged, this, &NavigatorSearchWidget::textChanged);
|
connect(m_textField, &QLineEdit::textChanged, this, &NavigatorSearchWidget::textChanged);
|
||||||
|
|
||||||
|
@@ -27,8 +27,27 @@
|
|||||||
|
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
class QToolButton;
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class LineEdit : public QLineEdit
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
LineEdit(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateClearButton(const QString &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QToolButton *clearButton;
|
||||||
|
};
|
||||||
|
|
||||||
class NavigatorSearchWidget : public QWidget
|
class NavigatorSearchWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -42,8 +61,7 @@ signals:
|
|||||||
void textChanged(const QString &text);
|
void textChanged(const QString &text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
LineEdit *m_textField;
|
||||||
QLineEdit *m_textField;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //QmlDesigner
|
} //QmlDesigner
|
||||||
|
@@ -69,6 +69,10 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view)
|
|||||||
toolBar->setParent(this);
|
toolBar->setParent(this);
|
||||||
layout->addWidget(toolBar);
|
layout->addWidget(toolBar);
|
||||||
|
|
||||||
|
m_searchWidget = new NavigatorSearchWidget();
|
||||||
|
connect(m_searchWidget, &NavigatorSearchWidget::textChanged, this, &NavigatorWidget::textFilterChanged);
|
||||||
|
layout->addWidget(m_searchWidget);
|
||||||
|
|
||||||
layout->addWidget(m_treeView);
|
layout->addWidget(m_treeView);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
@@ -161,10 +165,6 @@ QToolBar *NavigatorWidget::createToolBar()
|
|||||||
for (auto toolButton : buttons)
|
for (auto toolButton : buttons)
|
||||||
toolBar->addWidget(toolButton);
|
toolBar->addWidget(toolButton);
|
||||||
|
|
||||||
m_searchWidget = new NavigatorSearchWidget();
|
|
||||||
connect(m_searchWidget, &NavigatorSearchWidget::textChanged, this, &NavigatorWidget::textFilterChanged);
|
|
||||||
toolBar->addWidget(m_searchWidget);
|
|
||||||
|
|
||||||
return toolBar;
|
return toolBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,7 +68,8 @@ void PreviewImageTooltip::setImage(const QImage &image, bool scale)
|
|||||||
if (scale) {
|
if (scale) {
|
||||||
m_ui->imageLabel->setPixmap(pm.scaled(m_ui->imageLabel->width(),
|
m_ui->imageLabel->setPixmap(pm.scaled(m_ui->imageLabel->width(),
|
||||||
m_ui->imageLabel->height(),
|
m_ui->imageLabel->height(),
|
||||||
Qt::KeepAspectRatio));
|
Qt::KeepAspectRatio,
|
||||||
|
Qt::SmoothTransformation));
|
||||||
} else {
|
} else {
|
||||||
m_ui->imageLabel->setPixmap(pm);
|
m_ui->imageLabel->setPixmap(pm);
|
||||||
}
|
}
|
||||||
|
@@ -61,8 +61,12 @@ QString fileToString(const QString &filename)
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
|
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
|
||||||
|
QSize captureImageMinimumSize,
|
||||||
|
QSize captureImageMaximumSize,
|
||||||
ImageCacheCollectorNullImageHandling nullImageHandling)
|
ImageCacheCollectorNullImageHandling nullImageHandling)
|
||||||
: m_connectionManager{connectionManager}
|
: m_connectionManager{connectionManager}
|
||||||
|
, captureImageMinimumSize{captureImageMinimumSize}
|
||||||
|
, captureImageMaximumSize{captureImageMaximumSize}
|
||||||
, nullImageHandling{nullImageHandling}
|
, nullImageHandling{nullImageHandling}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -76,6 +80,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|
|||||||
{
|
{
|
||||||
RewriterView rewriterView{RewriterView::Amend, nullptr};
|
RewriterView rewriterView{RewriterView::Amend, nullptr};
|
||||||
NodeInstanceView nodeInstanceView{m_connectionManager};
|
NodeInstanceView nodeInstanceView{m_connectionManager};
|
||||||
|
nodeInstanceView.setCaptureImageMinimumAndMaximumSize(captureImageMinimumSize,
|
||||||
|
captureImageMaximumSize);
|
||||||
|
|
||||||
const QString filePath{name};
|
const QString filePath{name};
|
||||||
std::unique_ptr<Model> model{QmlDesigner::Model::create("QtQuick/Item", 2, 1)};
|
std::unique_ptr<Model> model{QmlDesigner::Model::create("QtQuick/Item", 2, 1)};
|
||||||
@@ -107,7 +113,10 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|
|||||||
|| !image.isNull()) {
|
|| !image.isNull()) {
|
||||||
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
|
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
|
||||||
Qt::KeepAspectRatio);
|
Qt::KeepAspectRatio);
|
||||||
QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize);
|
QImage smallImage = image.isNull() ? QImage{}
|
||||||
|
: image.scaled(smallImageSize,
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
captureCallback(image, smallImage);
|
captureCallback(image, smallImage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -51,6 +51,8 @@ class ImageCacheCollector final : public ImageCacheCollectorInterface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
|
ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
|
||||||
|
QSize captureImageMinimumSize,
|
||||||
|
QSize captureImageMaximumSize,
|
||||||
ImageCacheCollectorNullImageHandling nullImageHandling = {});
|
ImageCacheCollectorNullImageHandling nullImageHandling = {});
|
||||||
|
|
||||||
~ImageCacheCollector();
|
~ImageCacheCollector();
|
||||||
@@ -75,6 +77,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
ImageCacheConnectionManager &m_connectionManager;
|
ImageCacheConnectionManager &m_connectionManager;
|
||||||
QPointer<ProjectExplorer::Target> m_target;
|
QPointer<ProjectExplorer::Target> m_target;
|
||||||
|
QSize captureImageMinimumSize;
|
||||||
|
QSize captureImageMaximumSize;
|
||||||
ImageCacheCollectorNullImageHandling nullImageHandling{};
|
ImageCacheCollectorNullImageHandling nullImageHandling{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -161,6 +161,13 @@ public:
|
|||||||
m_crashCallback = std::move(crashCallback);
|
m_crashCallback = std::move(crashCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCaptureImageMinimumAndMaximumSize(QSize captureImageMinimumSize,
|
||||||
|
QSize captureImageMaximumSize)
|
||||||
|
{
|
||||||
|
m_captureImageMinimumSize = captureImageMinimumSize;
|
||||||
|
m_captureImageMaximumSize = captureImageMaximumSize;
|
||||||
|
}
|
||||||
|
|
||||||
void startNanotrace();
|
void startNanotrace();
|
||||||
void endNanotrace();
|
void endNanotrace();
|
||||||
|
|
||||||
@@ -237,6 +244,7 @@ private: // functions
|
|||||||
void updateWatcher(const QString &path);
|
void updateWatcher(const QString &path);
|
||||||
void handleShaderChanges();
|
void handleShaderChanges();
|
||||||
void handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader);
|
void handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader);
|
||||||
|
void updateQsbPathToFilterMap();
|
||||||
void updateRotationBlocks();
|
void updateRotationBlocks();
|
||||||
void maybeResetOnPropertyChange(const PropertyName &name, const ModelNode &node,
|
void maybeResetOnPropertyChange(const PropertyName &name, const ModelNode &node,
|
||||||
PropertyChangeFlags flags);
|
PropertyChangeFlags flags);
|
||||||
@@ -288,9 +296,12 @@ private:
|
|||||||
QTimer m_generateQsbFilesTimer;
|
QTimer m_generateQsbFilesTimer;
|
||||||
Utils::FilePath m_qsbPath;
|
Utils::FilePath m_qsbPath;
|
||||||
QSet<QString> m_pendingUpdateDirs;
|
QSet<QString> m_pendingUpdateDirs;
|
||||||
QSet<QString> m_pendingQsbTargets;
|
QHash<QString, bool> m_qsbTargets; // Value indicates if target is pending qsb generation
|
||||||
int m_remainingQsbTargets;
|
QHash<QString, QStringList> m_qsbPathToFilterMap;
|
||||||
|
int m_remainingQsbTargets = 0;
|
||||||
QTimer m_rotBlockTimer;
|
QTimer m_rotBlockTimer;
|
||||||
|
QSize m_captureImageMinimumSize{150, 150};
|
||||||
|
QSize m_captureImageMaximumSize{1000, 1000};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ProxyNodeInstanceView
|
} // namespace ProxyNodeInstanceView
|
||||||
|
@@ -98,6 +98,7 @@
|
|||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
|
|
||||||
#include <qmlprojectmanager/qmlmultilanguageaspect.h>
|
#include <qmlprojectmanager/qmlmultilanguageaspect.h>
|
||||||
|
#include <qmlprojectmanager/qmlproject.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -113,6 +114,8 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
debug = false
|
debug = false
|
||||||
@@ -174,9 +177,6 @@ NodeInstanceView::NodeInstanceView(ConnectionManagerInterface &connectionManager
|
|||||||
m_generateQsbFilesTimer.setInterval(100);
|
m_generateQsbFilesTimer.setInterval(100);
|
||||||
QObject::connect(&m_generateQsbFilesTimer, &QTimer::timeout, [this] {
|
QObject::connect(&m_generateQsbFilesTimer, &QTimer::timeout, [this] {
|
||||||
handleShaderChanges();
|
handleShaderChanges();
|
||||||
|
|
||||||
if (m_qsbPath.isEmpty() || m_remainingQsbTargets <= 0)
|
|
||||||
m_resetTimer.start();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged,
|
connect(m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged,
|
||||||
@@ -196,8 +196,12 @@ NodeInstanceView::NodeInstanceView(ConnectionManagerInterface &connectionManager
|
|||||||
|
|
||||||
});
|
});
|
||||||
connect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, [this](const QString &path) {
|
connect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, [this](const QString &path) {
|
||||||
m_pendingQsbTargets.insert(path);
|
if (m_qsbTargets.contains(path)) {
|
||||||
m_generateQsbFilesTimer.start();
|
m_qsbTargets.insert(path, true);
|
||||||
|
m_generateQsbFilesTimer.start();
|
||||||
|
} else if (m_remainingQsbTargets <= 0) {
|
||||||
|
m_resetTimer.start();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
m_rotBlockTimer.setSingleShot(true);
|
m_rotBlockTimer.setSingleShot(true);
|
||||||
@@ -277,7 +281,15 @@ void NodeInstanceView::modelAttached(Model *model)
|
|||||||
activateState(newStateInstance);
|
activateState(newStateInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateWatcher({});
|
// If model gets attached on non-main thread of the application, do not attempt to monitor
|
||||||
|
// file changes. Such models are typically short lived for specific purpose, and timers
|
||||||
|
// will not work at all, if the thread is not based on QThread.
|
||||||
|
if (QThread::currentThread() == qApp->thread()) {
|
||||||
|
m_generateQsbFilesTimer.stop();
|
||||||
|
m_qsbTargets.clear();
|
||||||
|
updateQsbPathToFilterMap();
|
||||||
|
updateWatcher({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeInstanceView::modelAboutToBeDetached(Model * model)
|
void NodeInstanceView::modelAboutToBeDetached(Model * model)
|
||||||
@@ -303,6 +315,9 @@ void NodeInstanceView::modelAboutToBeDetached(Model * model)
|
|||||||
m_pendingUpdateDirs.clear();
|
m_pendingUpdateDirs.clear();
|
||||||
m_fileSystemWatcher->removePaths(m_fileSystemWatcher->directories());
|
m_fileSystemWatcher->removePaths(m_fileSystemWatcher->directories());
|
||||||
m_fileSystemWatcher->removePaths(m_fileSystemWatcher->files());
|
m_fileSystemWatcher->removePaths(m_fileSystemWatcher->files());
|
||||||
|
|
||||||
|
m_generateQsbFilesTimer.stop();
|
||||||
|
m_qsbTargets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeInstanceView::handleCrash()
|
void NodeInstanceView::handleCrash()
|
||||||
@@ -1123,24 +1138,27 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
|
|||||||
if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0))
|
if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0))
|
||||||
stateInstanceId = stateNode.internalId();
|
stateInstanceId = stateNode.internalId();
|
||||||
|
|
||||||
return CreateSceneCommand(instanceContainerList,
|
return CreateSceneCommand(
|
||||||
reparentContainerList,
|
instanceContainerList,
|
||||||
idContainerList,
|
reparentContainerList,
|
||||||
valueContainerList,
|
idContainerList,
|
||||||
bindingContainerList,
|
valueContainerList,
|
||||||
auxiliaryContainerVector,
|
bindingContainerList,
|
||||||
importVector,
|
auxiliaryContainerVector,
|
||||||
mockupTypesVector,
|
importVector,
|
||||||
model()->fileUrl(),
|
mockupTypesVector,
|
||||||
|
model()->fileUrl(),
|
||||||
#ifndef QMLDESIGNER_TEST
|
#ifndef QMLDESIGNER_TEST
|
||||||
QUrl::fromLocalFile(QmlDesigner::DocumentManager::currentResourcePath()
|
QUrl::fromLocalFile(
|
||||||
.toFileInfo().absoluteFilePath()),
|
QmlDesigner::DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath()),
|
||||||
#else
|
#else
|
||||||
QUrl::fromLocalFile(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath()),
|
QUrl::fromLocalFile(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath()),
|
||||||
#endif
|
#endif
|
||||||
m_edit3DToolStates[model()->fileUrl()],
|
m_edit3DToolStates[model()->fileUrl()],
|
||||||
lastUsedLanguage,
|
lastUsedLanguage,
|
||||||
stateInstanceId);
|
m_captureImageMinimumSize,
|
||||||
|
m_captureImageMaximumSize,
|
||||||
|
stateInstanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearSceneCommand NodeInstanceView::createClearSceneCommand() const
|
ClearSceneCommand NodeInstanceView::createClearSceneCommand() const
|
||||||
@@ -1488,9 +1506,6 @@ void NodeInstanceView::setTarget(ProjectExplorer::Target *newTarget)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_generateQsbFilesTimer.stop();
|
|
||||||
m_pendingQsbTargets.clear();
|
|
||||||
m_remainingQsbTargets = 0;
|
|
||||||
restartProcess();
|
restartProcess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1885,12 +1900,18 @@ void NodeInstanceView::updateWatcher(const QString &path)
|
|||||||
QStringList oldDirs;
|
QStringList oldDirs;
|
||||||
QStringList newFiles;
|
QStringList newFiles;
|
||||||
QStringList newDirs;
|
QStringList newDirs;
|
||||||
|
QStringList qsbFiles;
|
||||||
|
#ifndef QMLDESIGNER_TEST
|
||||||
|
const QString projPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString();
|
||||||
|
#else
|
||||||
|
const QString projPath = QFileInfo(model()->fileUrl().toLocalFile()).absolutePath();
|
||||||
|
#endif
|
||||||
|
|
||||||
const QStringList files = m_fileSystemWatcher->files();
|
const QStringList files = m_fileSystemWatcher->files();
|
||||||
const QStringList directories = m_fileSystemWatcher->directories();
|
const QStringList directories = m_fileSystemWatcher->directories();
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
// Do full update
|
// Do full update
|
||||||
rootPath = QFileInfo(model()->fileUrl().toLocalFile()).absolutePath();
|
rootPath = projPath;
|
||||||
if (!directories.isEmpty())
|
if (!directories.isEmpty())
|
||||||
m_fileSystemWatcher->removePaths(directories);
|
m_fileSystemWatcher->removePaths(directories);
|
||||||
if (!files.isEmpty())
|
if (!files.isEmpty())
|
||||||
@@ -1916,12 +1937,47 @@ void NodeInstanceView::updateWatcher(const QString &path)
|
|||||||
// Common shader suffixes
|
// Common shader suffixes
|
||||||
static const QStringList filterList {"*.frag", "*.vert",
|
static const QStringList filterList {"*.frag", "*.vert",
|
||||||
"*.glsl", "*.glslv", "*.glslf",
|
"*.glsl", "*.glslv", "*.glslf",
|
||||||
"*.vsh","*.fsh"};
|
"*.vsh", "*.fsh"};
|
||||||
|
|
||||||
QDirIterator fileIterator(rootPath, filterList, QDir::Files, QDirIterator::Subdirectories);
|
QDirIterator fileIterator(rootPath, filterList, QDir::Files, QDirIterator::Subdirectories);
|
||||||
while (fileIterator.hasNext())
|
while (fileIterator.hasNext())
|
||||||
newFiles.append(fileIterator.next());
|
newFiles.append(fileIterator.next());
|
||||||
|
|
||||||
|
// Find out which shader files need qsb files generated for them.
|
||||||
|
// Go through all configured paths and find files that match the specified filter in that path.
|
||||||
|
bool generateQsb = false;
|
||||||
|
QHash<QString, QStringList>::const_iterator it = m_qsbPathToFilterMap.constBegin();
|
||||||
|
while (it != m_qsbPathToFilterMap.constEnd()) {
|
||||||
|
if (!it.key().isEmpty() && !it.key().startsWith(rootPath)) {
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDirIterator qsbIterator(it.key().isEmpty() ? rootPath : it.key(),
|
||||||
|
it.value(), QDir::Files,
|
||||||
|
it.key().isEmpty() ? QDirIterator::Subdirectories
|
||||||
|
: QDirIterator::NoIteratorFlags);
|
||||||
|
|
||||||
|
while (qsbIterator.hasNext()) {
|
||||||
|
QString qsbFile = qsbIterator.next();
|
||||||
|
|
||||||
|
if (qsbFile.endsWith(".qsb"))
|
||||||
|
continue; // Skip any generated files that are caught by wildcards
|
||||||
|
|
||||||
|
// Filters may specify shader files with non-default suffixes, so add them to newFiles
|
||||||
|
if (!newFiles.contains(qsbFile))
|
||||||
|
newFiles.append(qsbFile);
|
||||||
|
|
||||||
|
// Only generate qsb files for newly detected files. This avoids immediately regenerating
|
||||||
|
// qsb file if it's manually deleted, as directory change triggers calling this method.
|
||||||
|
if (!oldFiles.contains(qsbFile)) {
|
||||||
|
m_qsbTargets.insert(qsbFile, true);
|
||||||
|
generateQsb = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
if (oldDirs != newDirs) {
|
if (oldDirs != newDirs) {
|
||||||
if (!oldDirs.isEmpty())
|
if (!oldDirs.isEmpty())
|
||||||
m_fileSystemWatcher->removePaths(oldDirs);
|
m_fileSystemWatcher->removePaths(oldDirs);
|
||||||
@@ -1934,15 +1990,10 @@ void NodeInstanceView::updateWatcher(const QString &path)
|
|||||||
m_fileSystemWatcher->removePaths(oldFiles);
|
m_fileSystemWatcher->removePaths(oldFiles);
|
||||||
if (!newFiles.isEmpty())
|
if (!newFiles.isEmpty())
|
||||||
m_fileSystemWatcher->addPaths(newFiles);
|
m_fileSystemWatcher->addPaths(newFiles);
|
||||||
|
|
||||||
for (const auto &newFile : qAsConst(newFiles)) {
|
|
||||||
if (!oldFiles.contains(newFile))
|
|
||||||
m_pendingQsbTargets.insert(newFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_pendingQsbTargets.isEmpty())
|
|
||||||
m_generateQsbFilesTimer.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (generateQsb)
|
||||||
|
m_generateQsbFilesTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeInstanceView::handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader)
|
void NodeInstanceView::handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader)
|
||||||
@@ -1969,51 +2020,102 @@ void NodeInstanceView::handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const
|
|||||||
qsbProcess->deleteLater();
|
qsbProcess->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeInstanceView::handleShaderChanges()
|
void NodeInstanceView::updateQsbPathToFilterMap()
|
||||||
{
|
{
|
||||||
m_remainingQsbTargets += m_pendingQsbTargets.size();
|
m_qsbPathToFilterMap.clear();
|
||||||
|
if (m_currentTarget && !m_qsbPath.isEmpty()) {
|
||||||
|
const auto bs = qobject_cast<QmlProjectManager::QmlBuildSystem *>(m_currentTarget->buildSystem());
|
||||||
|
const QStringList shaderToolFiles = bs->shaderToolFiles();
|
||||||
|
|
||||||
for (const auto &shader : qAsConst(m_pendingQsbTargets)) {
|
#ifndef QMLDESIGNER_TEST
|
||||||
// Run qsb for changed shader file
|
const QString projPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString();
|
||||||
if (!m_qsbPath.isEmpty() && !shader.isEmpty()) {
|
#else
|
||||||
const Utils::FilePath sourceFile = Utils::FilePath::fromString(shader);
|
const QString projPath = QFileInfo(model()->fileUrl().toLocalFile()).absolutePath();
|
||||||
const Utils::FilePath srcPath = sourceFile.absolutePath();
|
#endif
|
||||||
const Utils::FilePath outPath = Utils::FilePath::fromString(shader + ".qsb");
|
// Parse ShaderTool files from project configuration.
|
||||||
|
// Separate files to path and file name (called filter here as it can contain wildcards)
|
||||||
if (!sourceFile.exists() || (outPath.exists() && outPath.lastModified() > sourceFile.lastModified())) {
|
// and group filters by paths. Blank path indicates project-wide file wildcard.
|
||||||
--m_remainingQsbTargets;
|
for (const auto &file : shaderToolFiles) {
|
||||||
continue;
|
int idx = file.lastIndexOf('/');
|
||||||
}
|
QString key;
|
||||||
|
QString filter;
|
||||||
// Run QSB with same parameters as Qt build does
|
if (idx >= 0) {
|
||||||
// TODO: Parameters should be configurable (QDS-6590)
|
key = projPath + "/" + file.left(idx);
|
||||||
const QStringList args = {"-s", "--glsl", "100 es,120,150", "--hlsl", "50", "--msl", "12",
|
filter = file.mid(idx + 1);
|
||||||
"-o", outPath.toString(), shader};
|
|
||||||
auto qsbProcess = new Utils::QtcProcess;
|
|
||||||
qsbProcess->setWorkingDirectory(srcPath);
|
|
||||||
qsbProcess->setCommand({m_qsbPath, args});
|
|
||||||
qsbProcess->start();
|
|
||||||
|
|
||||||
if (!qsbProcess->waitForStarted()) {
|
|
||||||
handleQsbProcessExit(qsbProcess, shader);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qsbProcess->state() == QProcess::Running) {
|
|
||||||
connect(qsbProcess, &Utils::QtcProcess::finished,
|
|
||||||
[thisView = QPointer<NodeInstanceView>(this), qsbProcess, shader]() {
|
|
||||||
if (thisView)
|
|
||||||
thisView->handleQsbProcessExit(qsbProcess, shader);
|
|
||||||
else
|
|
||||||
qsbProcess->deleteLater();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
handleQsbProcessExit(qsbProcess, shader);
|
filter = file;
|
||||||
}
|
}
|
||||||
|
m_qsbPathToFilterMap[key].append(filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_pendingQsbTargets.clear();
|
void NodeInstanceView::handleShaderChanges()
|
||||||
|
{
|
||||||
|
if (!m_currentTarget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto bs = qobject_cast<QmlProjectManager::QmlBuildSystem *>(m_currentTarget->buildSystem());
|
||||||
|
QStringList baseArgs = bs->shaderToolArgs();
|
||||||
|
if (baseArgs.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QStringList newShaders;
|
||||||
|
QHash<QString, bool>::iterator it = m_qsbTargets.begin();
|
||||||
|
while (it != m_qsbTargets.end()) {
|
||||||
|
if (it.value()) {
|
||||||
|
newShaders.append(it.key());
|
||||||
|
it.value() = false;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newShaders.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_remainingQsbTargets += newShaders.size();
|
||||||
|
|
||||||
|
for (const auto &shader : qAsConst(newShaders)) {
|
||||||
|
const Utils::FilePath srcFile = Utils::FilePath::fromString(shader);
|
||||||
|
const Utils::FilePath srcPath = srcFile.absolutePath();
|
||||||
|
const Utils::FilePath outPath = Utils::FilePath::fromString(shader + ".qsb");
|
||||||
|
|
||||||
|
if (!srcFile.exists()) {
|
||||||
|
m_qsbTargets.remove(shader);
|
||||||
|
--m_remainingQsbTargets;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((outPath.exists() && outPath.lastModified() > srcFile.lastModified())) {
|
||||||
|
--m_remainingQsbTargets;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList args = baseArgs;
|
||||||
|
args.append(outPath.toString());
|
||||||
|
args.append(shader);
|
||||||
|
auto qsbProcess = new Utils::QtcProcess;
|
||||||
|
qsbProcess->setWorkingDirectory(srcPath);
|
||||||
|
qsbProcess->setCommand({m_qsbPath, args});
|
||||||
|
qsbProcess->start();
|
||||||
|
|
||||||
|
if (!qsbProcess->waitForStarted()) {
|
||||||
|
handleQsbProcessExit(qsbProcess, shader);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qsbProcess->state() == QProcess::Running) {
|
||||||
|
connect(qsbProcess, &Utils::QtcProcess::finished,
|
||||||
|
[thisView = QPointer<NodeInstanceView>(this), qsbProcess, shader]() {
|
||||||
|
if (thisView)
|
||||||
|
thisView->handleQsbProcessExit(qsbProcess, shader);
|
||||||
|
else
|
||||||
|
qsbProcess->deleteLater();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
handleQsbProcessExit(qsbProcess, shader);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeInstanceView::updateRotationBlocks()
|
void NodeInstanceView::updateRotationBlocks()
|
||||||
|
@@ -353,7 +353,7 @@ void GenerateResource::generateMenuEntry()
|
|||||||
|
|
||||||
// ToDo: move this to QtCreator and add tr to the string then
|
// ToDo: move this to QtCreator and add tr to the string then
|
||||||
auto rccAction = new QAction(QCoreApplication::translate("QmlDesigner::GenerateResource",
|
auto rccAction = new QAction(QCoreApplication::translate("QmlDesigner::GenerateResource",
|
||||||
"Generate RCC Resource File"));
|
"Generate Deployable Package"));
|
||||||
rccAction->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr);
|
rccAction->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr);
|
||||||
QObject::connect(ProjectExplorer::SessionManager::instance(),
|
QObject::connect(ProjectExplorer::SessionManager::instance(),
|
||||||
&ProjectExplorer::SessionManager::startupProjectChanged, [rccAction]() {
|
&ProjectExplorer::SessionManager::startupProjectChanged, [rccAction]() {
|
||||||
|
@@ -90,23 +90,23 @@ const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces";
|
|||||||
|
|
||||||
const int MODELNODE_PREVIEW_IMAGE_DIMENSIONS = 150;
|
const int MODELNODE_PREVIEW_IMAGE_DIMENSIONS = 150;
|
||||||
|
|
||||||
const char EVENT_TIMELINE_ADDED[] = "Timeline Added";
|
const char EVENT_TIMELINE_ADDED[] = "timelineAdded";
|
||||||
const char EVENT_TRANSITION_ADDED[] = "Transition Added";
|
const char EVENT_TRANSITION_ADDED[] = "transitionAdded";
|
||||||
const char EVENT_STATE_ADDED[] = "State Added";
|
const char EVENT_STATE_ADDED[] = "stateAdded";
|
||||||
const char EVENT_CONNECTION_ADDED[] = "Connection Added";
|
const char EVENT_CONNECTION_ADDED[] = "connectionAdded";
|
||||||
const char EVENT_PROPERTY_ADDED[] = "Property Added";
|
const char EVENT_PROPERTY_ADDED[] = "propertyAdded";
|
||||||
const char EVENT_ANNOTATION_ADDED[] = "Annotation Added";
|
const char EVENT_ANNOTATION_ADDED[] = "annotationAdded";
|
||||||
const char EVENT_RESOURCE_IMPORTED[] = "Resource Imported ";
|
const char EVENT_RESOURCE_IMPORTED[] = "resourceImported";
|
||||||
const char EVENT_ACTION_EXECUTED[] = "Action Executed ";
|
const char EVENT_ACTION_EXECUTED[] = "actionExecuted";
|
||||||
const char EVENT_HELP_REQUESTED[] = "Help Requested ";
|
const char EVENT_HELP_REQUESTED[] = "helpRequested";
|
||||||
const char EVENT_IMPORT_ADDED[] = "Import Added ";
|
const char EVENT_IMPORT_ADDED[] = "importAdded:";
|
||||||
const char EVENT_BINDINGEDITOR_OPENED[] = "Binding Editor Opened";
|
const char EVENT_BINDINGEDITOR_OPENED[] = "bindingEditorOpened";
|
||||||
const char EVENT_RICHTEXT_OPENED[] = "Richtext Editor Opened";
|
const char EVENT_RICHTEXT_OPENED[] = "richtextEditorOpened";
|
||||||
const char EVENT_FORMEDITOR_TIME[] = "Form Editor";
|
const char EVENT_FORMEDITOR_TIME[] = "formEditor";
|
||||||
const char EVENT_3DEDITOR_TIME[] = "3D Editor";
|
const char EVENT_3DEDITOR_TIME[] = "3DEditor";
|
||||||
const char EVENT_TIMELINE_TIME[] = "Timeline";
|
const char EVENT_TIMELINE_TIME[] = "timeline";
|
||||||
const char EVENT_TRANSITIONEDITOR_TIME[] = "Transition Editor";
|
const char EVENT_TRANSITIONEDITOR_TIME[] = "transitionEditor";
|
||||||
const char EVENT_CURVEDITOR_TIME[] = "Curve Editor";
|
const char EVENT_CURVEDITOR_TIME[] = "curveEditor";
|
||||||
|
|
||||||
const char PROPERTY_EDITOR_CLASSNAME_PROPERTY[] = "__classNamePrivateInternal";
|
const char PROPERTY_EDITOR_CLASSNAME_PROPERTY[] = "__classNamePrivateInternal";
|
||||||
|
|
||||||
|
@@ -100,6 +100,16 @@ namespace QmlDesigner {
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
QString normalizeIdentifier(const QString &string)
|
||||||
|
{
|
||||||
|
if (string.isEmpty())
|
||||||
|
return {};
|
||||||
|
QString ret = string;
|
||||||
|
ret.remove(' ');
|
||||||
|
ret[0] = ret.at(0).toLower();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
class QtQuickDesignerFactory : public QmlJSEditor::QmlJSEditorFactory
|
class QtQuickDesignerFactory : public QmlJSEditor::QmlJSEditorFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -318,7 +328,7 @@ bool QmlDesignerPlugin::delayedInitialize()
|
|||||||
emitUsageStatistics("StandaloneMode");
|
emitUsageStatistics("StandaloneMode");
|
||||||
if (QmlProjectManager::QmlProject::isQtDesignStudioStartedFromQtC())
|
if (QmlProjectManager::QmlProject::isQtDesignStudioStartedFromQtC())
|
||||||
emitUsageStatistics("QDSlaunchedFromQtC");
|
emitUsageStatistics("QDSlaunchedFromQtC");
|
||||||
emitUsageStatistics("QDSstartupCount");
|
emitUsageStatistics("qdsStartupCount");
|
||||||
|
|
||||||
FoundLicense license = checkLicense();
|
FoundLicense license = checkLicense();
|
||||||
if (license == FoundLicense::enterprise)
|
if (license == FoundLicense::enterprise)
|
||||||
@@ -353,7 +363,7 @@ void QmlDesignerPlugin::extensionsInitialized()
|
|||||||
ExtensionSystem::IPlugin::ShutdownFlag QmlDesignerPlugin::aboutToShutdown()
|
ExtensionSystem::IPlugin::ShutdownFlag QmlDesignerPlugin::aboutToShutdown()
|
||||||
{
|
{
|
||||||
if (QmlProjectManager::QmlProject::isQtDesignStudio())
|
if (QmlProjectManager::QmlProject::isQtDesignStudio())
|
||||||
emitUsageStatistics("QDSstartupCount");
|
emitUsageStatistics("qdsShutdownCount");
|
||||||
|
|
||||||
return SynchronousShutdown;
|
return SynchronousShutdown;
|
||||||
}
|
}
|
||||||
@@ -642,7 +652,8 @@ double QmlDesignerPlugin::formEditorDevicePixelRatio()
|
|||||||
void QmlDesignerPlugin::emitUsageStatistics(const QString &identifier)
|
void QmlDesignerPlugin::emitUsageStatistics(const QString &identifier)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(instance(), return);
|
QTC_ASSERT(instance(), return);
|
||||||
emit instance()->usageStatisticsNotifier(identifier);
|
emit instance()->usageStatisticsNotifier(normalizeIdentifier(identifier));
|
||||||
|
qDebug() << normalizeIdentifier(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifier)
|
void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifier)
|
||||||
@@ -667,7 +678,9 @@ void QmlDesignerPlugin::registerPreviewImageProvider(QQmlEngine *engine)
|
|||||||
|
|
||||||
void QmlDesignerPlugin::emitUsageStatisticsTime(const QString &identifier, int elapsed)
|
void QmlDesignerPlugin::emitUsageStatisticsTime(const QString &identifier, int elapsed)
|
||||||
{
|
{
|
||||||
emit instance()->usageStatisticsUsageTimer(identifier, elapsed);
|
QTC_ASSERT(instance(), return);
|
||||||
|
emit instance()->usageStatisticsUsageTimer(normalizeIdentifier(identifier), elapsed);
|
||||||
|
qDebug() << normalizeIdentifier(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlDesignerPlugin *QmlDesignerPlugin::instance()
|
QmlDesignerPlugin *QmlDesignerPlugin::instance()
|
||||||
|
@@ -108,6 +108,8 @@ public:
|
|||||||
{}
|
{}
|
||||||
ImageCacheConnectionManager connectionManager;
|
ImageCacheConnectionManager connectionManager;
|
||||||
ImageCacheCollector collector{connectionManager,
|
ImageCacheCollector collector{connectionManager,
|
||||||
|
QSize{300, 300},
|
||||||
|
QSize{1000, 1000},
|
||||||
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
|
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
|
||||||
TimeStampProvider timeStampProvider;
|
TimeStampProvider timeStampProvider;
|
||||||
AsynchronousImageFactory factory;
|
AsynchronousImageFactory factory;
|
||||||
|
@@ -161,6 +161,26 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi
|
|||||||
projectItem->addToEnviroment(i.key(), i.value().value.toString());
|
projectItem->addToEnviroment(i.key(), i.value().value.toString());
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
} else if (childNode->name() == "ShaderTool") {
|
||||||
|
QmlJS::SimpleReaderNode::Property commandLine = childNode->property("args");
|
||||||
|
if (commandLine.isValid()) {
|
||||||
|
const QStringList quotedArgs = commandLine.value.toString().split('\"');
|
||||||
|
QStringList args;
|
||||||
|
for (int i = 0; i < quotedArgs.size(); ++i) {
|
||||||
|
// Each odd arg in this list is a single quoted argument, which we should
|
||||||
|
// not be split further
|
||||||
|
if (i % 2 == 0)
|
||||||
|
args.append(quotedArgs[i].trimmed().split(' '));
|
||||||
|
else
|
||||||
|
args.append(quotedArgs[i]);
|
||||||
|
}
|
||||||
|
args.removeAll({});
|
||||||
|
args.append("-o"); // Prepare for adding output file as next arg
|
||||||
|
projectItem->setShaderToolArgs(args);
|
||||||
|
}
|
||||||
|
QmlJS::SimpleReaderNode::Property files = childNode->property("files");
|
||||||
|
if (files.isValid())
|
||||||
|
projectItem->setShaderToolFiles(files.value.toStringList());
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Unknown type:" << childNode->name();
|
qWarning() << "Unknown type:" << childNode->name();
|
||||||
}
|
}
|
||||||
|
@@ -84,6 +84,12 @@ public:
|
|||||||
bool widgetApp() const { return m_widgetApp; }
|
bool widgetApp() const { return m_widgetApp; }
|
||||||
void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; }
|
void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; }
|
||||||
|
|
||||||
|
QStringList shaderToolArgs() const { return m_shaderToolArgs; }
|
||||||
|
void setShaderToolArgs(const QStringList &args) {m_shaderToolArgs = args; }
|
||||||
|
|
||||||
|
QStringList shaderToolFiles() const { return m_shaderToolFiles; }
|
||||||
|
void setShaderToolFiles(const QStringList &files) {m_shaderToolFiles = files; }
|
||||||
|
|
||||||
void appendContent(QmlProjectContentItem *item) { m_content.append(item); }
|
void appendContent(QmlProjectContentItem *item) { m_content.append(item); }
|
||||||
|
|
||||||
Utils::EnvironmentItems environment() const;
|
Utils::EnvironmentItems environment() const;
|
||||||
@@ -107,6 +113,8 @@ protected:
|
|||||||
bool m_qtForMCUs = false;
|
bool m_qtForMCUs = false;
|
||||||
bool m_qt6Project = false;
|
bool m_qt6Project = false;
|
||||||
bool m_widgetApp = false;
|
bool m_widgetApp = false;
|
||||||
|
QStringList m_shaderToolArgs;
|
||||||
|
QStringList m_shaderToolFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlProjectManager
|
} // namespace QmlProjectManager
|
||||||
|
@@ -626,6 +626,20 @@ bool QmlBuildSystem::widgetApp() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList QmlBuildSystem::shaderToolArgs() const
|
||||||
|
{
|
||||||
|
if (m_projectItem)
|
||||||
|
return m_projectItem->shaderToolArgs();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList QmlBuildSystem::shaderToolFiles() const
|
||||||
|
{
|
||||||
|
if (m_projectItem)
|
||||||
|
return m_projectItem->shaderToolFiles();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *)
|
bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *)
|
||||||
{
|
{
|
||||||
if (!dynamic_cast<QmlProjectNode *>(context))
|
if (!dynamic_cast<QmlProjectNode *>(context))
|
||||||
|
@@ -95,6 +95,8 @@ public:
|
|||||||
void setPrimaryLanguage(QString language);
|
void setPrimaryLanguage(QString language);
|
||||||
bool forceFreeType() const;
|
bool forceFreeType() const;
|
||||||
bool widgetApp() const;
|
bool widgetApp() const;
|
||||||
|
QStringList shaderToolArgs() const;
|
||||||
|
QStringList shaderToolFiles() const;
|
||||||
|
|
||||||
bool addFiles(const QStringList &filePaths);
|
bool addFiles(const QStringList &filePaths);
|
||||||
|
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
#include <qtsupport/qtversionmanager.h>
|
#include <qtsupport/qtversionmanager.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/filepath.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
@@ -50,6 +51,8 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace QtSupport {
|
namespace QtSupport {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -101,12 +104,21 @@ ExampleSetModel::ExampleSetModel()
|
|||||||
qWarning() << "Manifest path " << set.manifestPath << "is not a readable directory, ignoring";
|
qWarning() << "Manifest path " << set.manifestPath << "is not a readable directory, ignoring";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
m_extraExampleSets.append(set);
|
|
||||||
if (debugExamples()) {
|
if (debugExamples()) {
|
||||||
qWarning() << "Adding examples set displayName=" << set.displayName
|
qWarning() << "Adding examples set displayName=" << set.displayName
|
||||||
<< ", manifestPath=" << set.manifestPath
|
<< ", manifestPath=" << set.manifestPath
|
||||||
<< ", examplesPath=" << set.examplesPath;
|
<< ", examplesPath=" << set.examplesPath;
|
||||||
}
|
}
|
||||||
|
if (!Utils::anyOf(m_extraExampleSets, [&set](const ExtraExampleSet &s) {
|
||||||
|
return FilePath::fromString(s.examplesPath).cleanPath()
|
||||||
|
== FilePath::fromString(set.examplesPath).cleanPath()
|
||||||
|
&& FilePath::fromString(s.manifestPath).cleanPath()
|
||||||
|
== FilePath::fromString(set.manifestPath).cleanPath();
|
||||||
|
})) {
|
||||||
|
m_extraExampleSets.append(set);
|
||||||
|
} else if (debugExamples()) {
|
||||||
|
qWarning() << "Not adding, because example set with same directories exists";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_extraExampleSets += pluginRegisteredExampleSets();
|
m_extraExampleSets += pluginRegisteredExampleSets();
|
||||||
|
|
||||||
|
@@ -91,10 +91,6 @@
|
|||||||
<tags>qtformcus,mcus,qt,video,2021</tags>
|
<tags>qtformcus,mcus,qt,video,2021</tags>
|
||||||
</tutorial>
|
</tutorial>
|
||||||
|
|
||||||
<tutorial imageUrl=":qtsupport/images/icons/qteventicon.png" difficulty="" projectPath="" name="Talk: Introduction to Qt Creator IDE" isVideo="true" videoUrl="https://www.youtube.com/watch?v=nGFmjOiT22Y" videoLength="1:06:32">
|
|
||||||
<description><![CDATA[Getting started with using Qt Creator for cross-platform development.]]></description>
|
|
||||||
<tags>qt creator,talk,2020</tags>
|
|
||||||
</tutorial>
|
|
||||||
<tutorial imageUrl=":qtsupport/images/icons/qteventicon.png" difficulty="" projectPath="" name="Talk: Custom Qt Creator Wizards" isVideo="true" videoUrl="https://www.youtube.com/watch?v=Ko3DuCgFamo" videoLength="27:21">
|
<tutorial imageUrl=":qtsupport/images/icons/qteventicon.png" difficulty="" projectPath="" name="Talk: Custom Qt Creator Wizards" isVideo="true" videoUrl="https://www.youtube.com/watch?v=Ko3DuCgFamo" videoLength="27:21">
|
||||||
<description><![CDATA[Adding custom file and project creation wizards to Qt Creator.]]></description>
|
<description><![CDATA[Adding custom file and project creation wizards to Qt Creator.]]></description>
|
||||||
<tags>qt creator,wizard,talk,2015</tags>
|
<tags>qt creator,wizard,talk,2015</tags>
|
||||||
|
@@ -41,6 +41,8 @@
|
|||||||
|
|
||||||
#include <projectexplorer/projectexplorer.h>
|
#include <projectexplorer/projectexplorer.h>
|
||||||
|
|
||||||
|
#include <qmldesigner/qmldesignerplugin.h>
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@@ -83,6 +85,7 @@ FileDownloader::~FileDownloader()
|
|||||||
|
|
||||||
void FileDownloader::start()
|
void FileDownloader::start()
|
||||||
{
|
{
|
||||||
|
QmlDesigner::QmlDesignerPlugin::emitUsageStatistics("exampleDownload:" + name());
|
||||||
m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip");
|
m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip");
|
||||||
m_tempFile.open(QIODevice::WriteOnly);
|
m_tempFile.open(QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
108
src/plugins/studiowelcome/qml/splashscreen/CustomButton.ui.qml
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
|
||||||
|
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
|
||||||
|
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
|
||||||
|
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
|
||||||
|
*/
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Templates 2.15
|
||||||
|
import StudioFonts 1.0
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
implicitWidth: Math.max(
|
||||||
|
buttonBackground ? buttonBackground.implicitWidth : 0,
|
||||||
|
textItem.implicitWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(
|
||||||
|
buttonBackground ? buttonBackground.implicitHeight : 0,
|
||||||
|
textItem.implicitHeight + topPadding + bottomPadding)
|
||||||
|
leftPadding: 16
|
||||||
|
rightPadding: 16
|
||||||
|
|
||||||
|
text: "My Button"
|
||||||
|
|
||||||
|
font.family: StudioFonts.titilliumWeb_light
|
||||||
|
|
||||||
|
//property color accentColor: "#047eff"
|
||||||
|
property color accentColor: "#126491"
|
||||||
|
|
||||||
|
background: buttonBackground
|
||||||
|
Rectangle {
|
||||||
|
id: buttonBackground
|
||||||
|
color: "#00000000"
|
||||||
|
implicitWidth: 100
|
||||||
|
implicitHeight: 40
|
||||||
|
opacity: enabled ? 1 : 0.3
|
||||||
|
radius: 2
|
||||||
|
border.color: control.accentColor
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: textItem
|
||||||
|
Text {
|
||||||
|
id: textItem
|
||||||
|
text: control.text
|
||||||
|
|
||||||
|
opacity: enabled ? 1.0 : 0.3
|
||||||
|
color: "#ffffff"
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "normal"
|
||||||
|
when: !control.down
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: buttonBackground
|
||||||
|
color: "#00000000"
|
||||||
|
border.color: control.accentColor
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: "#ffffff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "down"
|
||||||
|
when: control.down
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: "#ffffff"
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: buttonBackground
|
||||||
|
color: control.accentColor
|
||||||
|
border.color: "#00000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -29,7 +29,7 @@ Rectangle {
|
|||||||
id: splashBackground
|
id: splashBackground
|
||||||
width: 460
|
width: 460
|
||||||
height: 480
|
height: 480
|
||||||
color: "#11102d"
|
color: "transparent"
|
||||||
|
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.textureSize: Qt.size(width * 2, height * 2)
|
layer.textureSize: Qt.size(width * 2, height * 2)
|
||||||
@@ -37,6 +37,7 @@ Rectangle {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: composition
|
id: composition
|
||||||
|
anchors.centerIn: parent
|
||||||
width: 460
|
width: 460
|
||||||
height: 480
|
height: 480
|
||||||
|
|
||||||
@@ -56,25 +57,4 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
|
||||||
id: highlight
|
|
||||||
x: -56
|
|
||||||
y: -19
|
|
||||||
width: 520
|
|
||||||
height: 506
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
source: "welcome_windows/highlight.png"
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: hand
|
|
||||||
x: 245
|
|
||||||
y: 227
|
|
||||||
width: 224
|
|
||||||
height: 264
|
|
||||||
visible: true
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
source: "welcome_windows/hand.png"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -32,8 +32,7 @@ import usagestatistics 1.0
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: welcome_splash
|
id: welcome_splash
|
||||||
width: 800
|
anchors.fill: parent
|
||||||
height: 480
|
|
||||||
|
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
orientation: Gradient.Horizontal
|
orientation: Gradient.Horizontal
|
||||||
@@ -46,43 +45,27 @@ Rectangle {
|
|||||||
signal closeClicked
|
signal closeClicked
|
||||||
signal configureClicked
|
signal configureClicked
|
||||||
|
|
||||||
property alias doNotShowAgain: doNotShowCheckBox.checked
|
property bool doNotShowAgain: true
|
||||||
property bool loadingPlugins: true
|
property bool loadingPlugins: true
|
||||||
|
color: "#1d212a"
|
||||||
// called from C++
|
|
||||||
function onPluginInitialized(crashReportingEnabled: bool, crashReportingOn: bool)
|
|
||||||
{
|
|
||||||
loadingPlugins = false
|
|
||||||
|
|
||||||
if (crashReportingEnabled) {
|
|
||||||
var configureButton = "<a href='#' style='text-decoration:none;color:#ffff00'>"
|
|
||||||
+ qsTr("[Configure]") + "</a>";
|
|
||||||
var settingPath = Qt.platform.os === "osx"
|
|
||||||
? qsTr("Qt Creator > Preferences > Environment > System")
|
|
||||||
: qsTr("Tools > Options > Environment > System")
|
|
||||||
var strConfigure = qsTr("Qt Design Studio collects usage statistics and crash reports for the sole purpose of fixing bugs and improving the tool. "
|
|
||||||
+ "You can configure the crash reporter under %1. %2").arg(settingPath).arg(configureButton)
|
|
||||||
|
|
||||||
crash_reporting_text.text = strConfigure
|
|
||||||
crashReportCheckBox.visible = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: logo
|
id: logo
|
||||||
x: 15
|
anchors.top: parent.top
|
||||||
y: 11
|
anchors.left: parent.left
|
||||||
width: 66
|
anchors.margins: 10
|
||||||
height: 50
|
width: 66 * 2
|
||||||
|
height: 50 * 2
|
||||||
|
smooth: true
|
||||||
source: "welcome_windows/logo.png"
|
source: "welcome_windows/logo.png"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: qt_design_studio
|
id: qt_design_studio_text
|
||||||
x: 13
|
anchors.top: logo.top
|
||||||
y: 81
|
anchors.left: logo.right
|
||||||
width: 336
|
anchors.leftMargin: 10
|
||||||
height: 46
|
|
||||||
color: "#25709a"
|
color: "#25709a"
|
||||||
text: qsTr("Qt Design Studio")
|
text: qsTr("Qt Design Studio")
|
||||||
font.pixelSize: 36
|
font.pixelSize: 36
|
||||||
@@ -90,156 +73,89 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: software_for_ui
|
id: qt_design_studio_version_text
|
||||||
x: 15
|
anchors.left: qt_design_studio_text.right
|
||||||
y: 126
|
anchors.baseline: qt_design_studio_text.baseline
|
||||||
width: 300
|
anchors.leftMargin: 10
|
||||||
height: 30
|
color: "#25709a"
|
||||||
color: "#ffffff"
|
text: usageStatisticModel.version
|
||||||
text: qsTr("Software for UI and UX Designers")
|
|
||||||
renderType: Text.QtRendering
|
|
||||||
font.pixelSize: 15
|
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
font.family: StudioFonts.titilliumWeb_light
|
||||||
|
font.pixelSize: 36
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: copyright
|
id: license_variant_text
|
||||||
x: 15
|
anchors.left: qt_design_studio_text.left
|
||||||
y: 155
|
anchors.top: qt_design_studio_text.bottom
|
||||||
width: 270
|
anchors.leftMargin: 5
|
||||||
height: 24
|
|
||||||
color: "#ffffff"
|
color: "#ffffff"
|
||||||
text: qsTr("Copyright 2008 - 2022 The Qt Company")
|
|
||||||
font.pixelSize: 14
|
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: all_rights_reserved
|
|
||||||
x: 15
|
|
||||||
y: 174
|
|
||||||
width: 250
|
|
||||||
height: 24
|
|
||||||
color: "#ffffff"
|
|
||||||
text: qsTr("All Rights Reserved")
|
|
||||||
font.pixelSize: 14
|
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
font.family: StudioFonts.titilliumWeb_light
|
||||||
}
|
font.pixelSize: 20
|
||||||
|
|
||||||
Text {
|
text: {
|
||||||
id: marketing_1
|
if (projectModel.communityVersion)
|
||||||
x: 15
|
return qsTr("Community Edition")
|
||||||
y: 206
|
if (projectModel.enterpriseVersion)
|
||||||
width: 406
|
return qsTr("Enterprise Edition")
|
||||||
height: 31
|
return qsTr("Professional Edition")
|
||||||
color: "#ffffff"
|
}
|
||||||
text: qsTr("Multi-paradigm language for creating highly dynamic applications.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
|
||||||
font.pixelSize: 12
|
|
||||||
font.wordSpacing: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
ProjectModel {
|
||||||
id: marketing_2
|
id: projectModel
|
||||||
x: 15
|
}
|
||||||
y: 229
|
|
||||||
width: 341
|
|
||||||
height: 31
|
|
||||||
color: "#ffffff"
|
|
||||||
text: qsTr("Run your concepts and prototypes on your final hardware.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
|
||||||
font.pixelSize: 12
|
|
||||||
font.wordSpacing: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
UsageStatisticModel {
|
||||||
id: marketing_3
|
id: usageStatisticModel
|
||||||
x: 15
|
|
||||||
y: 252
|
|
||||||
width: 336
|
|
||||||
height: 31
|
|
||||||
color: "#ffffff"
|
|
||||||
text: qsTr("Seamless integration between designer and developer.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
|
||||||
font.pixelSize: 12
|
|
||||||
font.wordSpacing: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: crash_reporting_text
|
|
||||||
color: "#ffffff"
|
|
||||||
anchors.bottom: columnLayout.top
|
|
||||||
textFormat: Text.RichText
|
|
||||||
x: 15
|
|
||||||
y: 280
|
|
||||||
width: 311
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
anchors.bottomMargin: 8
|
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
|
||||||
font.pixelSize: 12
|
|
||||||
font.wordSpacing: 0
|
|
||||||
onLinkActivated: welcome_splash.configureClicked()
|
|
||||||
|
|
||||||
MouseArea { // show hand cursor on link hover
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton // don't eat clicks on the Text
|
|
||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dof_Effect {
|
Dof_Effect {
|
||||||
id: dof_Effect
|
id: dof_effect
|
||||||
x: 358
|
anchors.top: qt_design_studio_text.bottom
|
||||||
|
anchors.horizontalCenter: welcome_splash.horizontalCenter
|
||||||
width: 442
|
width: 442
|
||||||
height: 480
|
height: 480
|
||||||
visible: true
|
|
||||||
maskBlurSamples: 64
|
maskBlurSamples: 64
|
||||||
maskBlurRadius: 32
|
maskBlurRadius: 32
|
||||||
|
|
||||||
Splash_Image25d {
|
Splash_Image25d {
|
||||||
id: animated_artwork
|
id: animated_artwork
|
||||||
x: 358
|
width: dof_effect.width
|
||||||
y: 0
|
height: dof_effect.height
|
||||||
width: 442
|
|
||||||
height: 480
|
|
||||||
clip: true
|
clip: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Text {
|
||||||
id: close_window
|
id: help_us_text
|
||||||
anchors.top: parent.top
|
anchors.left: welcome_splash.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: 8
|
anchors.leftMargin: 10
|
||||||
width: 13
|
anchors.top: dof_effect.bottom
|
||||||
height: 13
|
anchors.topMargin: 10
|
||||||
fillMode: Image.PreserveAspectFit
|
color: "#FFFFFF"
|
||||||
source: "welcome_windows/close.png"
|
text: qsTr("Before we let you move on to your wonderful designs, help us make Qt Design Studio even better by letting us know how you're using it.")
|
||||||
opacity: area.containsMouse ? 1 : 0.8
|
|
||||||
|
|
||||||
MouseArea {
|
font.family: StudioFonts.titilliumWeb_light
|
||||||
id: area
|
font.pixelSize: 18
|
||||||
hoverEnabled: true
|
wrapMode: Text.WordWrap
|
||||||
anchors.fill: parent
|
anchors.rightMargin: 10
|
||||||
anchors.margins: -10
|
|
||||||
onClicked: welcome_splash.closeClicked()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: columnLayout
|
id: columnLayout
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.bottom: parent.bottom
|
anchors.top: help_us_text.bottom
|
||||||
anchors.leftMargin: 16
|
anchors.leftMargin: 10
|
||||||
anchors.bottomMargin: 10
|
anchors.topMargin: 20
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
|
visible: false
|
||||||
id: usageStatisticCheckBox
|
id: usageStatisticCheckBox
|
||||||
text: qsTr("Enable Usage Statistics")
|
text: qsTr("Send Usage Statistics")
|
||||||
checked: usageStatisticModel.usageStatisticEnabled
|
checked: usageStatisticModel.usageStatisticEnabled
|
||||||
padding: 0
|
padding: 0
|
||||||
spacing: 12
|
spacing: 12
|
||||||
@@ -255,11 +171,11 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
|
visible: false
|
||||||
id: crashReportCheckBox
|
id: crashReportCheckBox
|
||||||
text: qsTr("Enable Crash Reports")
|
text: qsTr("Send Crash Reports")
|
||||||
spacing: 12
|
spacing: 12
|
||||||
checked: usageStatisticModel.crashReporterEnabled
|
checked: usageStatisticModel.crashReporterEnabled
|
||||||
visible: false
|
|
||||||
|
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
usageStatisticModel.setCrashReporterEnabled(crashReportCheckBox.checked)
|
usageStatisticModel.setCrashReporterEnabled(crashReportCheckBox.checked)
|
||||||
@@ -274,90 +190,41 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
padding: 0
|
padding: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
|
||||||
id: doNotShowCheckBox
|
|
||||||
text: qsTr("Do not show this again")
|
|
||||||
padding: 0
|
|
||||||
spacing: 12
|
|
||||||
|
|
||||||
contentItem: Text {
|
|
||||||
text: doNotShowCheckBox.text
|
|
||||||
color: "#ffffff"
|
|
||||||
leftPadding: doNotShowCheckBox.indicator.width + doNotShowCheckBox.spacing
|
|
||||||
font.pixelSize: 12
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
x: 16
|
anchors.right: parent.right
|
||||||
y: 277
|
anchors.bottom: welcome_splash.bottom
|
||||||
visible: welcome_splash.loadingPlugins
|
anchors.rightMargin: 10
|
||||||
|
anchors.bottomMargin: 10
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
Text {
|
CustomButton {
|
||||||
id: text1
|
text: qsTr("Don't send")
|
||||||
color: "#ffffff"
|
onClicked: {
|
||||||
text: qsTr("%")
|
usageStatisticModel.setTelemetryEnabled(false)
|
||||||
font.pixelSize: 12
|
usageStatisticModel.setCrashReporterEnabled(false)
|
||||||
|
welcome_splash.closeClicked()
|
||||||
RotationAnimator {
|
|
||||||
target: text1
|
|
||||||
from: 0
|
|
||||||
to: 360
|
|
||||||
duration: 1800
|
|
||||||
running: true
|
|
||||||
loops: -1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
CustomButton {
|
||||||
id: loading_progress
|
text: qsTr("Send analytics data")
|
||||||
color: "#ffffff"
|
onClicked: {
|
||||||
text: qsTr("Loading Plugins")
|
usageStatisticModel.setTelemetryEnabled(true)
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
usageStatisticModel.setCrashReporterEnabled(true)
|
||||||
font.pixelSize: 16
|
welcome_splash.closeClicked()
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: text2
|
|
||||||
color: "#ffffff"
|
|
||||||
text: qsTr("%")
|
|
||||||
font.pixelSize: 12
|
|
||||||
|
|
||||||
RotationAnimator {
|
|
||||||
target: text2
|
|
||||||
from: 0
|
|
||||||
to: 360
|
|
||||||
duration: 2000
|
|
||||||
running: true
|
|
||||||
loops: -1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
CustomButton {
|
||||||
id: all_rights_reserved1
|
y: 430
|
||||||
x: 15
|
text: qsTr("Learn More")
|
||||||
y: 65
|
anchors.left: parent.left
|
||||||
color: "#ffffff"
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 10
|
||||||
font.pixelSize: 13
|
anchors.leftMargin: 10
|
||||||
font.family: StudioFonts.titilliumWeb_light
|
onClicked: Qt.openUrlExternally("https://www.qt.io/terms-conditions/telemetry-privacy")
|
||||||
text: {
|
|
||||||
if (projectModel.communityVersion)
|
|
||||||
return qsTr("Community Edition")
|
|
||||||
if (projectModel.enterpriseVersion)
|
|
||||||
return qsTr("Enterprise Edition")
|
|
||||||
return qsTr("Professional Edition")
|
|
||||||
}
|
|
||||||
|
|
||||||
ProjectModel {
|
|
||||||
id: projectModel
|
|
||||||
}
|
|
||||||
|
|
||||||
UsageStatisticModel {
|
|
||||||
id: usageStatisticModel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,8 +27,8 @@ import QtQuick 2.0
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
width: 800
|
width: 720
|
||||||
height: 480
|
height: 720
|
||||||
|
|
||||||
signal closeClicked
|
signal closeClicked
|
||||||
signal checkBoxToggled
|
signal checkBoxToggled
|
||||||
|
@@ -116,6 +116,7 @@ Item {
|
|||||||
id: image
|
id: image
|
||||||
width: 240
|
width: 240
|
||||||
height: 125
|
height: 125
|
||||||
|
mipmap: true
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,4 +27,5 @@ import QtQuick 2.0
|
|||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
property bool usageStatisticEnabled: false
|
property bool usageStatisticEnabled: false
|
||||||
|
property string version: "3.3.0"
|
||||||
}
|
}
|
||||||
|
@@ -133,11 +133,13 @@ class UsageStatisticPluginModel : public QObject
|
|||||||
|
|
||||||
Q_PROPERTY(bool usageStatisticEnabled MEMBER m_usageStatisticEnabled NOTIFY usageStatisticChanged)
|
Q_PROPERTY(bool usageStatisticEnabled MEMBER m_usageStatisticEnabled NOTIFY usageStatisticChanged)
|
||||||
Q_PROPERTY(bool crashReporterEnabled MEMBER m_crashReporterEnabled NOTIFY crashReporterEnabledChanged)
|
Q_PROPERTY(bool crashReporterEnabled MEMBER m_crashReporterEnabled NOTIFY crashReporterEnabledChanged)
|
||||||
|
Q_PROPERTY(QString version MEMBER m_versionString CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit UsageStatisticPluginModel(QObject *parent = nullptr)
|
explicit UsageStatisticPluginModel(QObject *parent = nullptr)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
|
m_versionString = Core::Constants::IDE_VERSION_DISPLAY;
|
||||||
setupModel();
|
setupModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,13 +162,10 @@ public:
|
|||||||
|
|
||||||
Core::ICore::settings()->setValue(CRASH_REPORTER_SETTING, b);
|
Core::ICore::settings()->setValue(CRASH_REPORTER_SETTING, b);
|
||||||
|
|
||||||
s_pluginInstance->pauseRemoveSplashTimer();
|
|
||||||
|
|
||||||
const QString restartText = tr("The change will take effect after restart.");
|
const QString restartText = tr("The change will take effect after restart.");
|
||||||
Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
|
Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
|
||||||
restartDialog.exec();
|
restartDialog.exec();
|
||||||
|
|
||||||
s_pluginInstance->resumeRemoveSplashTimer();
|
|
||||||
setupModel();
|
setupModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,14 +178,10 @@ public:
|
|||||||
|
|
||||||
settings->setValue(STATISTICS_COLLECTION_MODE, b ? DETAILED_USAGE_STATISTICS : NO_TELEMETRY);
|
settings->setValue(STATISTICS_COLLECTION_MODE, b ? DETAILED_USAGE_STATISTICS : NO_TELEMETRY);
|
||||||
|
|
||||||
// pause remove splash timer while dialog is open otherwise splash crashes upon removal
|
|
||||||
s_pluginInstance->pauseRemoveSplashTimer();
|
|
||||||
|
|
||||||
const QString restartText = tr("The change will take effect after restart.");
|
const QString restartText = tr("The change will take effect after restart.");
|
||||||
Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
|
Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
|
||||||
restartDialog.exec();
|
restartDialog.exec();
|
||||||
|
|
||||||
s_pluginInstance->resumeRemoveSplashTimer();
|
|
||||||
setupModel();
|
setupModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +192,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
bool m_usageStatisticEnabled = false;
|
bool m_usageStatisticEnabled = false;
|
||||||
bool m_crashReporterEnabled = false;
|
bool m_crashReporterEnabled = false;
|
||||||
|
QString m_versionString;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProjectModel : public QAbstractListModel
|
class ProjectModel : public QAbstractListModel
|
||||||
@@ -249,6 +245,9 @@ public:
|
|||||||
const QString &formFile,
|
const QString &formFile,
|
||||||
const QString &explicitQmlproject)
|
const QString &explicitQmlproject)
|
||||||
{
|
{
|
||||||
|
QmlDesigner::QmlDesignerPlugin::emitUsageStatistics("exampleOpened:"
|
||||||
|
+ exampleName);
|
||||||
|
|
||||||
const QString exampleFolder = examplePath + "/" + exampleName + "/";
|
const QString exampleFolder = examplePath + "/" + exampleName + "/";
|
||||||
|
|
||||||
QString projectFile = exampleFolder + exampleName + ".qmlproject";
|
QString projectFile = exampleFolder + exampleName + ".qmlproject";
|
||||||
@@ -517,10 +516,7 @@ void StudioWelcomePlugin::showSystemSettings()
|
|||||||
Core::ICore::infoBar()->removeInfo("WarnCrashReporting");
|
Core::ICore::infoBar()->removeInfo("WarnCrashReporting");
|
||||||
Core::ICore::infoBar()->globallySuppressInfo("WarnCrashReporting");
|
Core::ICore::infoBar()->globallySuppressInfo("WarnCrashReporting");
|
||||||
|
|
||||||
// pause remove splash timer while settings dialog is open otherwise splash crashes upon removal
|
|
||||||
pauseRemoveSplashTimer();
|
|
||||||
Core::ICore::showOptionsDialog(Core::Constants::SETTINGS_ID_SYSTEM);
|
Core::ICore::showOptionsDialog(Core::Constants::SETTINGS_ID_SYSTEM);
|
||||||
resumeRemoveSplashTimer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioWelcomePlugin::StudioWelcomePlugin()
|
StudioWelcomePlugin::StudioWelcomePlugin()
|
||||||
@@ -543,11 +539,6 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro
|
|||||||
|
|
||||||
m_welcomeMode = new WelcomeMode;
|
m_welcomeMode = new WelcomeMode;
|
||||||
|
|
||||||
m_removeSplashTimer.setSingleShot(true);
|
|
||||||
const QString splashScreenTimeoutEntry = "QML/Designer/splashScreenTimeout";
|
|
||||||
m_removeSplashTimer.setInterval(
|
|
||||||
Core::ICore::settings()->value(splashScreenTimeoutEntry, 15000).toInt());
|
|
||||||
connect(&m_removeSplashTimer, &QTimer::timeout, this, [this] { closeSplashScreen(); });
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,8 +611,6 @@ void StudioWelcomePlugin::extensionsInitialized()
|
|||||||
|
|
||||||
s_view->show();
|
s_view->show();
|
||||||
s_view->raise();
|
s_view->raise();
|
||||||
|
|
||||||
m_removeSplashTimer.start();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -633,34 +622,9 @@ bool StudioWelcomePlugin::delayedInitialize()
|
|||||||
|
|
||||||
QTC_ASSERT(s_view->rootObject(), return true);
|
QTC_ASSERT(s_view->rootObject(), return true);
|
||||||
|
|
||||||
#ifdef ENABLE_CRASHPAD
|
|
||||||
const bool crashReportingEnabled = true;
|
|
||||||
const bool crashReportingOn = Core::ICore::settings()->value(CRASH_REPORTER_SETTING, false).toBool();
|
|
||||||
#else
|
|
||||||
const bool crashReportingEnabled = false;
|
|
||||||
const bool crashReportingOn = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(s_view->rootObject(), "onPluginInitialized",
|
|
||||||
Q_ARG(bool, crashReportingEnabled), Q_ARG(bool, crashReportingOn));
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioWelcomePlugin::pauseRemoveSplashTimer()
|
|
||||||
{
|
|
||||||
if (m_removeSplashTimer.isActive()) {
|
|
||||||
m_removeSplashRemainingTime = m_removeSplashTimer.remainingTime(); // milliseconds
|
|
||||||
m_removeSplashTimer.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StudioWelcomePlugin::resumeRemoveSplashTimer()
|
|
||||||
{
|
|
||||||
if (!m_removeSplashTimer.isActive())
|
|
||||||
m_removeSplashTimer.start(m_removeSplashRemainingTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::FilePath StudioWelcomePlugin::defaultExamplesPath()
|
Utils::FilePath StudioWelcomePlugin::defaultExamplesPath()
|
||||||
{
|
{
|
||||||
QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
|
QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
|
||||||
|
@@ -77,9 +77,6 @@ public:
|
|||||||
void extensionsInitialized() override;
|
void extensionsInitialized() override;
|
||||||
bool delayedInitialize() override;
|
bool delayedInitialize() override;
|
||||||
|
|
||||||
void pauseRemoveSplashTimer();
|
|
||||||
void resumeRemoveSplashTimer();
|
|
||||||
|
|
||||||
static Utils::FilePath defaultExamplesPath();
|
static Utils::FilePath defaultExamplesPath();
|
||||||
static QString examplesPathSetting();
|
static QString examplesPathSetting();
|
||||||
|
|
||||||
@@ -88,9 +85,7 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
class WelcomeMode *m_welcomeMode = nullptr;
|
class WelcomeMode *m_welcomeMode = nullptr;
|
||||||
QTimer m_removeSplashTimer;
|
|
||||||
StudioWelcomeSettingsPage m_settingsPage;
|
StudioWelcomeSettingsPage m_settingsPage;
|
||||||
int m_removeSplashRemainingTime = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "texteditor_global.h"
|
#include "texteditor_global.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
@@ -164,11 +164,10 @@ MultiTextCursor TextDocumentPrivate::indentOrUnindent(const MultiTextCursor &cur
|
|||||||
}
|
}
|
||||||
// make sure that selection that begins in first column stays at first column
|
// make sure that selection that begins in first column stays at first column
|
||||||
// even if we insert text at first column
|
// even if we insert text at first column
|
||||||
|
cursor = textCursor;
|
||||||
if (cursorAtBlockStart) {
|
if (cursorAtBlockStart) {
|
||||||
cursor = textCursor;
|
|
||||||
cursor.setPosition(startBlock.position(), QTextCursor::KeepAnchor);
|
cursor.setPosition(startBlock.position(), QTextCursor::KeepAnchor);
|
||||||
} else if (anchorAtBlockStart) {
|
} else if (anchorAtBlockStart) {
|
||||||
cursor = textCursor;
|
|
||||||
cursor.setPosition(startBlock.position(), QTextCursor::MoveAnchor);
|
cursor.setPosition(startBlock.position(), QTextCursor::MoveAnchor);
|
||||||
cursor.setPosition(textCursor.position(), QTextCursor::KeepAnchor);
|
cursor.setPosition(textCursor.position(), QTextCursor::KeepAnchor);
|
||||||
}
|
}
|
||||||
|
@@ -128,6 +128,7 @@ public:
|
|||||||
runControl->buildKey(),
|
runControl->buildKey(),
|
||||||
browserId,
|
browserId,
|
||||||
QString::number(portsGatherer->findEndPoint().port()));
|
QString::number(portsGatherer->findEndPoint().port()));
|
||||||
|
r.environment = runControl->buildEnvironment();
|
||||||
SimpleTargetRunner::doStart(r);
|
SimpleTargetRunner::doStart(r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -226,11 +226,11 @@ def logApplicationOutput():
|
|||||||
# get the output from a given cmdline call
|
# get the output from a given cmdline call
|
||||||
def getOutputFromCmdline(cmdline, environment=None, acceptedError=0):
|
def getOutputFromCmdline(cmdline, environment=None, acceptedError=0):
|
||||||
try:
|
try:
|
||||||
return subprocess.check_output(cmdline, env=environment)
|
return stringify(subprocess.check_output(cmdline, env=environment))
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
if e.returncode != acceptedError:
|
if e.returncode != acceptedError:
|
||||||
test.warning("Command '%s' returned %d" % (e.cmd, e.returncode))
|
test.warning("Command '%s' returned %d" % (e.cmd, e.returncode))
|
||||||
return e.output
|
return stringify(e.output)
|
||||||
|
|
||||||
def selectFromFileDialog(fileName, waitForFile=False, ignoreFinalSnooze=False):
|
def selectFromFileDialog(fileName, waitForFile=False, ignoreFinalSnooze=False):
|
||||||
def __closePopupIfNecessary__():
|
def __closePopupIfNecessary__():
|
||||||
@@ -238,41 +238,29 @@ def selectFromFileDialog(fileName, waitForFile=False, ignoreFinalSnooze=False):
|
|||||||
test.log("Closing active popup widget")
|
test.log("Closing active popup widget")
|
||||||
QApplication.activePopupWidget().close()
|
QApplication.activePopupWidget().close()
|
||||||
|
|
||||||
if platform.system() == "Darwin":
|
fName = os.path.basename(os.path.abspath(fileName))
|
||||||
|
pName = os.path.dirname(os.path.abspath(fileName)) + os.sep
|
||||||
|
try:
|
||||||
|
waitForObject("{name='QFileDialog' type='QFileDialog' visible='1'}", 5000)
|
||||||
|
pathLine = waitForObject("{name='fileNameEdit' type='QLineEdit' visible='1'}")
|
||||||
|
replaceEditorContent(pathLine, pName)
|
||||||
snooze(1)
|
snooze(1)
|
||||||
nativeType("<Command+Shift+g>")
|
clickButton(waitForObject("{text='Open' type='QPushButton'}"))
|
||||||
|
waitFor("str(pathLine.text)==''")
|
||||||
|
replaceEditorContent(pathLine, fName)
|
||||||
snooze(1)
|
snooze(1)
|
||||||
nativeType(fileName)
|
__closePopupIfNecessary__()
|
||||||
snooze(2)
|
clickButton(waitForObject("{text='Open' type='QPushButton'}"))
|
||||||
nativeType("<Return>")
|
except:
|
||||||
snooze(3)
|
nativeType("<Ctrl+a>")
|
||||||
|
nativeType("<Delete>")
|
||||||
|
nativeType(pName + fName)
|
||||||
|
seconds = len(pName + fName) / 20
|
||||||
|
test.log("Using snooze(%d) [problems with event processing of nativeType()]" % seconds)
|
||||||
|
snooze(seconds)
|
||||||
nativeType("<Return>")
|
nativeType("<Return>")
|
||||||
if not ignoreFinalSnooze:
|
if not ignoreFinalSnooze:
|
||||||
snooze(1)
|
snooze(3)
|
||||||
else:
|
|
||||||
fName = os.path.basename(os.path.abspath(fileName))
|
|
||||||
pName = os.path.dirname(os.path.abspath(fileName)) + os.sep
|
|
||||||
try:
|
|
||||||
waitForObject("{name='QFileDialog' type='QFileDialog' visible='1'}", 5000)
|
|
||||||
pathLine = waitForObject("{name='fileNameEdit' type='QLineEdit' visible='1'}")
|
|
||||||
replaceEditorContent(pathLine, pName)
|
|
||||||
snooze(1)
|
|
||||||
clickButton(waitForObject("{text='Open' type='QPushButton'}"))
|
|
||||||
waitFor("str(pathLine.text)==''")
|
|
||||||
replaceEditorContent(pathLine, fName)
|
|
||||||
snooze(1)
|
|
||||||
__closePopupIfNecessary__()
|
|
||||||
clickButton(waitForObject("{text='Open' type='QPushButton'}"))
|
|
||||||
except:
|
|
||||||
nativeType("<Ctrl+a>")
|
|
||||||
nativeType("<Delete>")
|
|
||||||
nativeType(pName + fName)
|
|
||||||
seconds = len(pName + fName) / 20
|
|
||||||
test.log("Using snooze(%d) [problems with event processing of nativeType()]" % seconds)
|
|
||||||
snooze(seconds)
|
|
||||||
nativeType("<Return>")
|
|
||||||
if not ignoreFinalSnooze:
|
|
||||||
snooze(3)
|
|
||||||
if waitForFile:
|
if waitForFile:
|
||||||
fileCombo = waitForObject(":Qt Creator_FilenameQComboBox")
|
fileCombo = waitForObject(":Qt Creator_FilenameQComboBox")
|
||||||
if not waitFor("str(fileCombo.currentText) in fileName", 5000):
|
if not waitFor("str(fileCombo.currentText) in fileName", 5000):
|
||||||
@@ -447,6 +435,7 @@ def iterateQtVersions(keepOptionsOpen=False, alreadyOnOptionsDialog=False,
|
|||||||
rootChildText = str(rootIndex.data()).replace(".", "\\.").replace("_", "\\_")
|
rootChildText = str(rootIndex.data()).replace(".", "\\.").replace("_", "\\_")
|
||||||
for subIndex in dumpIndices(model, rootIndex):
|
for subIndex in dumpIndices(model, rootIndex):
|
||||||
subChildText = str(subIndex.data()).replace(".", "\\.").replace("_", "\\_")
|
subChildText = str(subIndex.data()).replace(".", "\\.").replace("_", "\\_")
|
||||||
|
treeView.scrollTo(subIndex)
|
||||||
mouseClick(waitForObjectItem(treeView, ".".join([rootChildText,subChildText])))
|
mouseClick(waitForObjectItem(treeView, ".".join([rootChildText,subChildText])))
|
||||||
currentText = str(waitForObject(":QtSupport__Internal__QtVersionManager.QLabel").text)
|
currentText = str(waitForObject(":QtSupport__Internal__QtVersionManager.QLabel").text)
|
||||||
matches = pattern.match(currentText)
|
matches = pattern.match(currentText)
|
||||||
@@ -684,3 +673,12 @@ def isString(sth):
|
|||||||
return isinstance(sth, str)
|
return isinstance(sth, str)
|
||||||
else:
|
else:
|
||||||
return isinstance(sth, (str, unicode))
|
return isinstance(sth, (str, unicode))
|
||||||
|
|
||||||
|
# helper function to ensure we get str, converts bytes if necessary
|
||||||
|
def stringify(obj):
|
||||||
|
stringTypes = (str, unicode) if sys.version_info.major == 2 else (str)
|
||||||
|
if isinstance(obj, stringTypes):
|
||||||
|
return obj
|
||||||
|
if isinstance(obj, bytes):
|
||||||
|
tmp = obj.decode('cp1252') if platform.system() in ('Microsoft','Windows') else obj.decode()
|
||||||
|
return tmp
|
||||||
|
@@ -32,8 +32,9 @@ def cmakeSupported():
|
|||||||
versionLines = filter(lambda line: "cmake version " in line,
|
versionLines = filter(lambda line: "cmake version " in line,
|
||||||
getOutputFromCmdline(["cmake", "--version"]).splitlines())
|
getOutputFromCmdline(["cmake", "--version"]).splitlines())
|
||||||
try:
|
try:
|
||||||
test.log("Using " + versionLines[0])
|
versionLine = list(versionLines)[0]
|
||||||
matcher = re.match("cmake version (\d+)\.(\d+)\.\d+", versionLines[0])
|
test.log("Using " + versionLine)
|
||||||
|
matcher = re.match("cmake version (\d+)\.(\d+)\.\d+", versionLine)
|
||||||
major = __builtin__.int(matcher.group(1))
|
major = __builtin__.int(matcher.group(1))
|
||||||
minor = __builtin__.int(matcher.group(2))
|
minor = __builtin__.int(matcher.group(2))
|
||||||
except:
|
except:
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
############################################################################
|
############################################################################
|
||||||
#
|
#
|
||||||
# Copyright (C) 2016 The Qt Company Ltd.
|
# Copyright (C) 2022 The Qt Company Ltd.
|
||||||
# Contact: https://www.qt.io/licensing/
|
# Contact: https://www.qt.io/licensing/
|
||||||
#
|
#
|
||||||
# This file is part of Qt Creator.
|
# This file is part of Qt Creator.
|
||||||
@@ -66,8 +66,8 @@ def main():
|
|||||||
availableProjectTypes.append({category:template})
|
availableProjectTypes.append({category:template})
|
||||||
safeClickButton("Cancel")
|
safeClickButton("Cancel")
|
||||||
for current in availableProjectTypes:
|
for current in availableProjectTypes:
|
||||||
category = current.keys()[0]
|
category = list(current.keys())[0]
|
||||||
template = current.values()[0]
|
template = list(current.values())[0]
|
||||||
with TestSection("Testing project template %s -> %s" % (category, template)):
|
with TestSection("Testing project template %s -> %s" % (category, template)):
|
||||||
displayedPlatforms = __createProject__(category, template)
|
displayedPlatforms = __createProject__(category, template)
|
||||||
if template == "Qt Quick Application":
|
if template == "Qt Quick Application":
|
||||||
|