diff --git a/README.md b/README.md index 55ce5919e68..4ecf9f0aeb9 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,10 @@ Prerequisites: * Debugging Tools for Windows (optional, for MSVC debugging support with CDB) * On Mac OS X: latest Xcode * On Linux: GCC 7 or later -* LLVM/Clang 10 or later (optional, LLVM/Clang 13 is recommended. +* LLVM/Clang 10 or later (optional, LLVM/Clang 14 is recommended. See [instructions](#getting-llvmclang-for-the-clang-code-model) on how to get LLVM. - The ClangFormat, ClangPchManager and ClangRefactoring use the LLVM C++ API. + The ClangFormat plugin uses the LLVM C++ API. Since the LLVM C++ API provides no compatibility guarantee, if later versions don't compile we don't support that version.) * CMake @@ -149,8 +149,8 @@ like Qt and LLVM, additionally run ## Getting LLVM/Clang for the Clang Code Model -The Clang Code Model depends on the LLVM/Clang libraries. The currently -recommended LLVM/Clang version is 13.0. +The Clang code model uses `Clangd` and the ClangFormat plugin depends on the +LLVM/Clang libraries. The currently recommended LLVM/Clang version is 14.0. ### Prebuilt LLVM/Clang packages diff --git a/dist/changelog/changes-8.0.0.md b/dist/changelog/changes-8.0.0.md index 87bf811f3df..35675b2281f 100644 --- a/dist/changelog/changes-8.0.0.md +++ b/dist/changelog/changes-8.0.0.md @@ -10,6 +10,11 @@ the public Git repository. For example: git clone git://code.qt.io/qt-creator/qt-creator.git git log --cherry-pick --pretty=oneline origin/7.0..v8.0.0 +General +------- + +* Moved `Tools > Options` to `Edit > Preferences` + Help ---- @@ -20,24 +25,38 @@ Editing * Added shortcut for adding next search match to multi-selection * Added warning when editing generated file (QTCREATORBUG-27173) -* Added option for hiding line ending information +* Added option for hiding line ending information `Text Editor > Display > + Display file line ending` * Fixed updating of annotations (QTCREATORBUG-26812) * Fixed that whitespace was not selected on double-click (QTCREATORBUG-24607) * Fixed `Rewrap Paragraph` when indenting with tabs (QTCREATORBUG-27602) +* Fixed code folding marker visibility after `Open in New Window` + (QTCREATORBUG-27748) ### C++ * Removed `libclang` based code model * Fixed that `Generate Setter and Getter` generated non-static methods for static pointer types (QTCREATORBUG-27547) +* Fixed `Add Local Declaration` for class templates (QTCREATORBUG-26004) +* Fixed that `Follow Symbol Under Cursor` could jump to new location even after + the user started doing other things (QTCREATORBUG-20878) +* Fixed that macros were highlighted as preprocessor statements + (QTCREATORBUG-23548) +* Fixed initialization of pointer variables when generating member for + `Q_PROPERTY` (QTCREATORBUG-27770) * Clangd * Increased minimum `Clangd` version to 14 + * Added warning and disabling of `Clangd` by default on machines with low + memory (QTCREATORBUG-19297) * Improved performance of `compile_commands.json` creation * Replaced some refactoring actions by the ones from `Clangd` * Added desugaring of types and warning about unused includes * Added option for ignoring big files * Added information on parent function to `Find References With Access Type` (QTCREATORBUG-27550) + * Added warning icon and deprecation tag to completion items for deprecated + API (QTCREATORBUG-2325) * Worked around `Clangd` highlighting issue (QTCREATORBUG-27601) * Fixed `Follow Symbol Under Cursor` for template types (QTCREATORBUG-27524) * Fixed that issues from other files could be shown in `Issues` @@ -47,7 +66,7 @@ Editing * Fixed that UI files with same name could confuse code model (QTCREATORBUG-27584) * clang-format - * Simplified options dialog + * Fixed cursor position when undoing formatting (QTCREATORBUG-27608) ### QML @@ -55,6 +74,10 @@ Editing (QTCREATORBUG-23411) * Fixed handling of JavaScript string templates (QTCREATORBUG-21869) * Fixed formatting issue with nullish coalescing operator (QTCREATORBUG-27344) +* Fixed that `Follow Symbol Under Cursor` could open file from build directory + instead of source directory (QTCREATORBUG-27173) +* Fixed member lookup for items with same name in different modules + (QTCREATORBUG-26714) ### Python @@ -70,6 +93,8 @@ Editing ### Language Server Protocol * Improved performance for large server responses +* Added support for dragging in `Outline` (QTCREATORBUG-27502) +* Fixed order of outline items (QTCREATORBUG-4346) * Fixed semantic highlighting after server reset * Fixed that semantic update was delayed by `Document update threshold` even after saving @@ -80,6 +105,10 @@ Editing * Added button for copying image as data URL +### FakeVim + +* Partially implemented multi repeat command `:g, :v` + Projects -------- @@ -97,12 +126,20 @@ Projects * Removed hardcoded `QT_QML_DEBUG` from wizard created project files * Fixed issue when reconfiguring with `QML debugging and profiling` option enabled +* Fixed missing path to `ninja` for `ExternalProject_Add` (QTCREATORBUG-27495) +* Fixed that headers were wrongly classified as `C` code if `qt_add_qml_module` + is used (QTCREATORBUG-27117) + +### Compilation Database + +* Fixed wrong removal of command line options (QTCREATORBUG-22949) Debugging --------- * Switched fallback Qt version for debug information to Qt 6.2 * Added pretty printer for `QAnyStringView` +* Added workaround for LLDB on Ubuntu 22.04 Analyzer -------- @@ -143,6 +180,8 @@ Platforms * Removed support for Universal Windows Platform (UWP) * Added auto-detection for MSVC ARM toolchain and debugger * Fixed ABI detection on ARM Windows +* Fixed ABI detection of static Qt (QTCREATORBUG-27735) +* Fixed interrupting remote CDB processes (QTCREATORBUG-21657) ### macOS @@ -156,9 +195,14 @@ Platforms * Aligned platform names with Android Studio (QTCREATORBUG-27161) * Fixed issues with newer SDK tools (QTCREATORBUG-27174) +### iOS + +* Improved consecutive deployment speed (QTCREATORBUG-24371) + ### Remote Linux * Switched to `echo` for testing connection +* Fixed deployment of multiple directories with `rsync` ### Docker @@ -178,6 +222,7 @@ Credits for these changes go to: -------------------------------- Aaron Barany Adam Treat +Aleksei German Alesandro Portale Alessandro Portale Alexander Akulich @@ -187,6 +232,8 @@ Andre Hartmann André Pönitz Artem Sokolovskii Assam Boudjelthia +Bartlomiej Moskal +BogDan Vatra Christiaan Janssen Christian Kandeler Christian Stenger @@ -201,16 +248,20 @@ Evgeny Shtanov Fawzi Mohamed Henning Gruendl Ihor Ivlev +Ippei Sugita Jaroslaw Kobus Knud Dollereder Leena Miettinen +Mahmoud Badri Marcus Tillmanns +Mats Honkamaa Maximilian Goldstein Miikka Heikkinen Orgad Shaneh Piotr Mućko Rafael Roquetto Robert Löhning +Samuel Ghinet Sergey Morozov Tapani Mattila Tasuku Suzuki diff --git a/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png b/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png index 17dbf6bda25..e0f5e44e7c9 100644 Binary files a/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png and b/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png differ diff --git a/doc/qtcreator/images/qtcreator-gitlab-clone-repository.png b/doc/qtcreator/images/qtcreator-gitlab-clone-repository.png new file mode 100644 index 00000000000..35194c4e4f2 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-gitlab-clone-repository.png differ diff --git a/doc/qtcreator/images/qtcreator-gitlab-preferences-add-server.png b/doc/qtcreator/images/qtcreator-gitlab-preferences-add-server.png new file mode 100644 index 00000000000..f1963b3484d Binary files /dev/null and b/doc/qtcreator/images/qtcreator-gitlab-preferences-add-server.png differ diff --git a/doc/qtcreator/images/qtcreator-gitlab-preferences-project.png b/doc/qtcreator/images/qtcreator-gitlab-preferences-project.png new file mode 100644 index 00000000000..835434f5c35 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-gitlab-preferences-project.png differ diff --git a/doc/qtcreator/images/qtcreator-gitlab-preferences.png b/doc/qtcreator/images/qtcreator-gitlab-preferences.png new file mode 100644 index 00000000000..459d5d60ccb Binary files /dev/null and b/doc/qtcreator/images/qtcreator-gitlab-preferences.png differ diff --git a/doc/qtcreator/images/qtcreator-gitlab-project-list.png b/doc/qtcreator/images/qtcreator-gitlab-project-list.png new file mode 100644 index 00000000000..039e294ef97 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-gitlab-project-list.png differ diff --git a/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png b/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png new file mode 100644 index 00000000000..862c88d17e3 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png differ diff --git a/doc/qtcreator/images/qtcreator-language-client-options-java.png b/doc/qtcreator/images/qtcreator-language-client-options-java.png index d70df4dd477..592d7d2f5a3 100644 Binary files a/doc/qtcreator/images/qtcreator-language-client-options-java.png and b/doc/qtcreator/images/qtcreator-language-client-options-java.png differ diff --git a/doc/qtcreator/images/qtcreator-language-client-options.png b/doc/qtcreator/images/qtcreator-language-client-options.png deleted file mode 100644 index 0ae18ec4e41..00000000000 Binary files a/doc/qtcreator/images/qtcreator-language-client-options.png and /dev/null differ diff --git a/doc/qtcreator/images/qtcreator-language-server-generic-stdio.png b/doc/qtcreator/images/qtcreator-language-server-generic-stdio.png new file mode 100644 index 00000000000..4c0b26b8b68 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-language-server-generic-stdio.png differ diff --git a/doc/qtcreator/images/qtcreator-python-advanced.png b/doc/qtcreator/images/qtcreator-python-advanced.png new file mode 100644 index 00000000000..eea49d610cf Binary files /dev/null and b/doc/qtcreator/images/qtcreator-python-advanced.png differ diff --git a/doc/qtcreator/images/qtcreator-python-interpreters.png b/doc/qtcreator/images/qtcreator-python-interpreters.png new file mode 100644 index 00000000000..546adb1b2d3 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-python-interpreters.png differ diff --git a/doc/qtcreator/images/qtcreator-python-plugins.png b/doc/qtcreator/images/qtcreator-python-plugins.png new file mode 100644 index 00000000000..c2ba0b05a17 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-python-plugins.png differ diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index 86797263481..bc736490c68 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -50,8 +50,8 @@ architectures (ABIs) installed as one. To enable helpful code editing features for Java, such as code completion, - highlighting, function tooltips, and navigating in code, specify settings - for a \l{Specifying Java Language Server Settings}{Java language server}. + highlighting, function tooltips, and navigating in code, add a + \l{Java Language Server}{Java language server}. The Android Debug Bridge (adb) command line tool is integrated to \QC to enable you to deploy applications to connected Android devices, to run diff --git a/doc/qtcreator/src/editors/creator-code-indentation.qdoc b/doc/qtcreator/src/editors/creator-code-indentation.qdoc index 6a0e93985a3..1816872a160 100644 --- a/doc/qtcreator/src/editors/creator-code-indentation.qdoc +++ b/doc/qtcreator/src/editors/creator-code-indentation.qdoc @@ -109,7 +109,7 @@ \image qtcreator-options-code-style-cpp.png "C++ Code Style options" \li Give a name to the settings and click \uicontrol OK. \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-cpp.png "Edit Code Style Settings dialog" + \image qtcreator-code-style-settings-edit-cpp.png "Edit Code Style dialog" \endlist You can specify how to: @@ -129,7 +129,7 @@ You can use the live preview to see how the options change the indentation. To specify different settings for a particular project, select - \uicontrol Projects > \uicontrol {Code Style Settings}. + \uicontrol Projects > \uicontrol {Code Style}. \include creator-clangformat.qdocinc clang format \endif @@ -146,14 +146,17 @@ \image qtcreator-options-code-style-qml.png "QML Code Style options" \li Give a name to the settings and click \uicontrol OK. \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-qtquick.png "Edit Code Style Settings dialog" + \image qtcreator-code-style-settings-edit-qtquick.png "Edit Code Style dialog" \endlist You can specify how to interpret the \key Tab key presses and how to align continuation lines. + In \uicontrol {Line length}, you can adjust the maximum line length for + code lines. + To specify different settings for a particular project, select - \uicontrol Projects > \uicontrol {Code Style Settings}. + \uicontrol Projects > \uicontrol {Code Style}. \if defined(qtcreator) \section1 Indenting Nim Files @@ -167,7 +170,7 @@ \image qtcreator-options-code-style-nim.png "Nim Code Style options" \li Give a name to the settings and click \uicontrol OK. \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-nim.png "Edit Code Style Settings dialog" + \image qtcreator-code-style-settings-edit-nim.png "Edit Code Style dialog" \endlist You can specify how to interpret the \key Tab key presses and how to align diff --git a/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc b/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc index f034fde0bed..c4b8d14873e 100644 --- a/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc +++ b/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc @@ -125,7 +125,9 @@ \section2 Selecting Line Ending Style To switch between Windows line endings (CRLF) and Unix line endings (LF), - select the ending style on the editor toolbar (6). + select the ending style on the editor toolbar (6). To hide this field, + select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Text Editor} + > \uicontrol Display, and deselect \uicontrol {Display file line ending}. To set the line endings to use for all projects by default, select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Text Editor} > diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc index 60706a70c84..f4ee40a9bf3 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -176,6 +176,9 @@ \li In \uicontrol {Document update threshold}, specify the amount of time \QC waits before sending document changes to the server. If the document changes again while waiting, this timeout is reset. + \li Select \uicontrol {Ignore files greater than} to make parsing faster + by ignoring big files. Specify the maximum size of files to parse in + the field next to the check box. \li The \uicontrol {Diagnostic Configuration} field shows the Clang checks to perform. Click the value of the field to open the \uicontrol {Diagnostic Configurations} dialog, where you can diff --git a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc index 30d3ba4dc4b..384707adae4 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc @@ -79,33 +79,31 @@ \section1 Specifying Settings for Language Clients - You can add a generic generic stdIO language server for Python, for example. - For \l{Connecting Android Devices}{Android development}, you can add a Java - language server. + \QC supports adding a Java language server for + \l{Connecting Android Devices}{Android development}. A Python language + server is added by default and you can edit its preferences. + For other languages, you can add generic stdIO language servers. - \section2 Adding Language Servers - - To view a list of language servers, select \uicontrol Edit > - \uicontrol Preferences > \uicontrol {Language Client} (or - \uicontrol {Qt Creator} > \uicontrol Preferences > - \uicontrol {Language Client} > on \macos). - - \image qtcreator-language-client-options.png "Language client options page" + To add language servers, select \uicontrol Edit > \uicontrol Preferences > + \uicontrol {Language Client} > \uicontrol Add (or \uicontrol {Qt Creator} > + \uicontrol Preferences > \uicontrol {Language Client} > \uicontrol Add + on \macos). To enable a language server, select the check box next to the language - server name and specify settings for the server. + server name and set server preferences. To remove language servers from the list, select \uicontrol Delete. - \section2 Specifying Generic Settings + \section2 Generic StdIO Language Server To add a generic language server: \list 1 \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Language Client} > \uicontrol Add > - \uicontrol {New Generic StdIO Language Server} + \uicontrol {Generic StdIO Language Server} to add a generic language server. + \image qtcreator-language-server-generic-stdio.png \li In the \uicontrol Name field, enter a name for the language server. Select the \inlineimage icons/replace.png (\uicontrol {Variables}) button to use a variable for the server @@ -119,8 +117,9 @@ with a matching MIME type is opened. \l{Viewing Output} {General Messages} displays information about the connection to the language server. - \li In the \uicontrol Initialization field, you can add language server - specific JSON attributes to pass to an \c initialize request. + \li In the \uicontrol {Initialization options} field, you can add + language server specific JSON attributes to pass to an \c initialize + request. \li In the \uicontrol Executable field, enter the path to the language server executable. \li In the \uicontrol Arguments field, enter any required command line @@ -128,15 +127,15 @@ arguments. \endlist - \section2 Specifying Java Language Server Settings + \section2 Java Language Server To add a Java language server: \list 1 \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Language Client} > \uicontrol Add > - \uicontrol {New Java Language Server} to add a Java language server. - \image qtcreator-language-client-options-java.png "Java language server options" + \uicontrol {Java Language Server} to add a Java language server. + \image qtcreator-language-client-options-java.png "Java language server preferences" \li In the \uicontrol Name field, enter a name for the language server. Select the \inlineimage icons/replace.png (\uicontrol {Variables}) button to use a variable for the server @@ -146,6 +145,25 @@ the Java language server \c .jar file. \endlist + \section2 Python Language Server + + To set preferences for Python language servers: + + \list 1 + \li Select \uicontrol Edit > \uicontrol Preferences > + \uicontrol Python > \uicontrol {Language Server Configuration} to + select the Python language server plugins to use. + \image qtcreator-python-plugins.png "Python Language Server Configuration" + \li Select \uicontrol Advanced to configure the plugins. + \image qtcreator-python-advanced.png "Python language server plugin configuration" + \endlist + + For a complete list of configuration options, see + \l{https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md} + {Python Language Server Configuration}. + + To disable the Python language server, deselect + \uicontrol {Use Python Language Server}. \section1 Supported Locator Filters @@ -166,7 +184,7 @@ responses that contain the requested information if the language server is capable of handling the requests. To inspect the communication between \QC and language servers and view server capabilities, select \uicontrol Tools - > \uicontrol {Debug \QC} > \uicontrol {Inspect Language Client}. + > \uicontrol {Debug \QC} > \uicontrol {Inspect Language Clients}. \image qtcreator-language-client-inspector-log.png "Language Client Inspector dialog" @@ -201,11 +219,11 @@ For a clangd server, you can inspect the total amount of memory used by a particular component in \uicontrol {Memory Usage}. - \image qtcreator-language-client-inspector-capabilities.png "Language Client Inspector Capabilities tab" + \image qtcreator-language-client-inspector-memory-usage.png "Language Client Inspector Memory Usage tab" \section1 Reporting Issues - The language service client has been mostly tested with Python and Java. + The language server client has been mostly tested with Python and Java. If problems arise when you try them or some other language, please select \uicontrol Help > \uicontrol {Report Bug} to report them in the \l{https://bugreports.qt.io/}{Qt Project Bug Tracker}. The reports diff --git a/doc/qtcreator/src/python/creator-python-project.qdocinc b/doc/qtcreator/src/python/creator-python-project.qdocinc index 1409b7d840b..3e9bbb83047 100644 --- a/doc/qtcreator/src/python/creator-python-project.qdocinc +++ b/doc/qtcreator/src/python/creator-python-project.qdocinc @@ -33,6 +33,21 @@ to gain access to individual Qt modules, such as \l {Qt Core}, \l {Qt GUI}, and \l {Qt Widgets}. + If you have not installed PySide6, \QC prompts you to install it after + the project is created. Further, it prompts you to install the + \l {Python Language Server}{Python language server} that provides services + such as code completion and annotations. Select \uicontrol Install to install + PySide6 and the language server. + + To view and manage the available Python interpreters, select \uicontrol Edit + > \uicontrol Preferences > \uicontrol Python > \uicontrol Interpreters. + + \image qtcreator-python-interpreters.png "Python Interpreters in Preferences" + + You can add and remove interpreters and clean up references to interpreters + that have been uninstalled, but still appear in the list. In addition, you + can set the interpreter to use by default. + The Qt for Python Application wizards generate a \c {.pyproject} file that lists the files in the Python project and a \c {.py} file that contains some boilerplate code. In addition, the widget based UI wizard creates a diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index ffdc1f1f039..b401e05bffa 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -69,6 +69,7 @@ \li \l{Using ClearCase} \li \l{Using CVS} \li \l{Using Git} + \li \l{Using GitLab} \li \l{Using Mercurial} \li \l{Using Perforce} \li \l{Using Subversion} diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc index be69ff17d54..ffde43b7b1b 100644 --- a/doc/qtcreator/src/user-interface/creator-ui.qdoc +++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc @@ -220,6 +220,9 @@ \li Export SVG images to pixmaps + \li Copy an image as a data URL, which enables you to include it in web + pages as if it were an external resource + \li Switch between background and outline modes \li Zoom in and out diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs-gitlab.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs-gitlab.qdoc new file mode 100644 index 00000000000..7c4e9589a48 --- /dev/null +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs-gitlab.qdoc @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \previouspage creator-vcs-git.html + \page creator-vcs-gitlab.html + \nextpage creator-vcs-mercurial.html + + \title Using GitLab + + GitLab is a DevOps tool developed by GitLab. You can clone projects from + GitLab servers and use \l{Using Git}{Git} to manage your local and remote + repositories. + + To enable the experimental GitLab plugin, select \uicontrol Help > + \uicontrol {About Plugins} > \uicontrol {Version Control} > + \uicontrol GitLab. Then select \uicontrol {Restart Now} to + restart \QC and load the plugin. + + To use GitLab, you must create a connection to the GitLab server and clone + the projects you want to work on. You can also link previously cloned + projects to GitLab in the project settings. This enables you to receive + event notifications in the \l {Viewing Output}{Version Control} pane. + + \section1 Connecting to GitLab Servers + + To connect to a GitLab server, you need to specify the server host name and + port number, as well as an access token that you create in GitLab for \QC. + The permission scope of the token must be at least \c read_api or \c api. + + To specify connections to GitLab servers, select \uicontrol Edit > + \uicontrol Preferences > \uicontrol {Version Control} > \uicontrol GitLab: + + \image qtcreator-gitlab-preferences.png + + To add GitLab servers: + + \list 1 + \li Select \uicontrol Add to open the \uicontrol {Add Server} dialog: + \image qtcreator-gitlab-preferences-add-server.png + \li In \uicontrol Host, enter the host name of the GitLab server. + \li In \uicontrol Description, enter a free-form text that is displayed + in the GitLab settings of a linked project. + \li In \uicontrol {Access token}, enter the access token you created for + \QC in the GitLab server, in \uicontrol Preferences > + \uicontrol {Access Tokens}. + \li In \uicontrol Port, enter a port number. + \li Deselect the \uicontrol HTTPS check box to use an HTTP connection + instead of a secure connection. + \li Select \uicontrol Add to create the connection. + \endlist + + In the \uicontrol GitLab tab, \uicontrol curl displays the path to the + \c curl tool used for HTTP connections. You can specify another path to + use another instance of the tool than the one found by \QC. + + To edit the selected connection, select \uicontrol Edit. + + To remove the selected connection, select \uicontrol Remove. + + \section1 Cloning Projects + + You can clone projects from the connected GitLab servers. \QC reads your + user name and ID from the access token and displays the available projects + in each server. You can search for a particular project or browse projects + in the list. + + To clone projects from GitLab: + + \list 1 + \li Select \uicontrol Tools > \uicontrol GitLab to view a list of + connected GitLab servers and available projects in each server: + \image qtcreator-gitlab-project-list.png + \li In \uicontrol Remote, select a GitLab server. + \li In \uicontrol Projects, select the project to clone. + \li Select \uicontrol Clone to open the \uicontrol {Clone Repository} + dialog: + \image qtcreator-gitlab-clone-repository.png + \li In \uicontrol Repository, specify the URL of the repository. + \li In \uicontrol Path, specify the path where to clone the repository. + \li In \uicontrol Directory, specify the name of the directory for the + cloned repository. + \li Select the \uicontrol Recursive check box to also clone submodules + of the repository. + \li Select \uicontrol Clone to clone the project to the specified + directory. + \endlist + + \QC automatically opens the project. If the cloned project has several + project files (such as CMakeList.txt, .pro, and .qbs), \QC prompts you to + select the one to open. If it does not contain a project file that \QC can + open, select \uicontrol File > \uicontrol {New Project} > + \uicontrol {Import Project} > \uicontrol {Import Existing Project} to + import the project as a generic project. For more information, see + \l {Using Project Wizards}. + + \section1 Linking Projects with GitLab + + Link a project with a GitLab token to receive notifications on events, such + as merge requests, issues, or comments, in the \uicontrol {Version Control} + pane. The information is fetched every 15 minutes. Only events that occurred + after the last time you logged into GitLab are displayed when you open the + project for the first time. Subsequently, events that occurred after the last + successful fetch are listed. + + To link with GitLab: + + \list 1 + \li In the \uicontrol Projects mode, select \uicontrol {GitLab} to view + the GitLab settings for the currently active project: + \image qtcreator-gitlab-preferences-project.png + \li In \uicontrol Host, select the URL of the GitLab server. + \li In \uicontrol {Linked GitLab configuration}, select the GitLab + server settings to use. + \li Select \uicontrol {Link with GitLab} to receive event notifications + in the \uicontrol {Version Control} pane. + \endlist + + To test the connection to the host using the access token specified in the + GitLab configuration, select \uicontrol {Test Connection}. + + To stop the reception of event notifications, select + \uicontrol {Unlink from GitLab}. +*/ diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc index 244cb995a8b..e4212947a7b 100644 --- a/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc @@ -30,7 +30,7 @@ // ********************************************************************** /*! - \previouspage creator-vcs-git.html + \previouspage creator-vcs-gitlab.html \page creator-vcs-mercurial.html \nextpage creator-vcs-perforce.html diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc index 3555b137d82..27869401a4d 100644 --- a/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -72,6 +72,10 @@ \li Git version 1.9.0, or later Gerrit version 2.6, or later + \row + \li \l{Using GitLab}{GitLab} + \li \l{http://gitlab.com/} + \li Experimental \row \li \l{Using Mercurial}{Mercurial} \li \l{http://mercurial.selenic.com/} @@ -124,6 +128,7 @@ \li \l{https://doc.qt.io/qtcreator/creator-vcs-fossil.html} {Qt Creator Fossil Plugin Manual} \li \l{Using Git} + \li \l{Using GitLab} \li \l{Using Mercurial} \li \l{Using Perforce} \li \l{Using Subversion} diff --git a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc index e4ced3102b0..bb1e08c611e 100644 --- a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc +++ b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc @@ -36,7 +36,7 @@ \nextpage studio-porting-projects.html \else \previouspage creator-vcs-cvs.html - \nextpage creator-vcs-mercurial.html + \nextpage creator-vcs-gitlab.html \endif \title Using Git diff --git a/doc/qtdesignstudio/images/icons/apply-material.png b/doc/qtdesignstudio/images/icons/apply-material.png new file mode 100644 index 00000000000..d0b347470bc Binary files /dev/null and b/doc/qtdesignstudio/images/icons/apply-material.png differ diff --git a/doc/qtdesignstudio/images/material-editor-browser.webp b/doc/qtdesignstudio/images/material-editor-browser.webp new file mode 100644 index 00000000000..d3963b522e4 Binary files /dev/null and b/doc/qtdesignstudio/images/material-editor-browser.webp differ diff --git a/doc/qtdesignstudio/images/materials-remove-material.png b/doc/qtdesignstudio/images/materials-remove-material.png new file mode 100644 index 00000000000..9ef0a91e5be Binary files /dev/null and b/doc/qtdesignstudio/images/materials-remove-material.png differ diff --git a/doc/qtdesignstudio/images/navigator-material-texture.png b/doc/qtdesignstudio/images/navigator-material-texture.png new file mode 100644 index 00000000000..4256e959c61 Binary files /dev/null and b/doc/qtdesignstudio/images/navigator-material-texture.png differ diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp new file mode 100644 index 00000000000..0306408df16 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp differ diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp new file mode 100644 index 00000000000..1c5b1cecf28 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp differ diff --git a/doc/qtdesignstudio/images/timeline-bind-animation-state.png b/doc/qtdesignstudio/images/timeline-bind-animation-state.png new file mode 100644 index 00000000000..7e65c85a30c Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-bind-animation-state.png differ diff --git a/doc/qtdesignstudio/images/timeline-insert-keyframe.png b/doc/qtdesignstudio/images/timeline-insert-keyframe.png new file mode 100644 index 00000000000..c46a7118067 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-insert-keyframe.png differ diff --git a/doc/qtdesignstudio/images/timeline-per-property-recording.png b/doc/qtdesignstudio/images/timeline-per-property-recording.png new file mode 100644 index 00000000000..7daa337aa1a Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-per-property-recording.png differ diff --git a/doc/qtdesignstudio/images/timeline-settings-dialog-second.png b/doc/qtdesignstudio/images/timeline-settings-dialog-second.png new file mode 100644 index 00000000000..03cd0be3555 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-settings-dialog-second.png differ diff --git a/doc/qtdesignstudio/images/timeline-settings-dialog.png b/doc/qtdesignstudio/images/timeline-settings-dialog.png new file mode 100644 index 00000000000..aa910e67f63 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-settings-dialog.png differ diff --git a/doc/qtdesignstudio/images/timeline-settings-property-binding.png b/doc/qtdesignstudio/images/timeline-settings-property-binding.png new file mode 100644 index 00000000000..a774bcd84a2 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-settings-property-binding.png differ diff --git a/doc/qtdesignstudio/images/timeline-states.png b/doc/qtdesignstudio/images/timeline-states.png new file mode 100644 index 00000000000..a1dc73e51eb Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-states.png differ diff --git a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc index af83a8e918d..a8f1a172f20 100644 --- a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc +++ b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc @@ -60,7 +60,7 @@ \li \l{Lists and Other Data Models} \row \li Timeline - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \if defined(qtdesignstudio) \row \li Event List diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index f3a7a0d4f7d..8cba9a73076 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -39,6 +39,7 @@ \list \li \l{Form Editor} \li \l{3D Editor} + \li \l{Material Editor and Browser} \li \l{Components} \li \l{Assets} \li \l{Navigator} diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index dee9a01a9d9..1995c343b83 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -26,7 +26,7 @@ /*! \previouspage qtquick-form-editor.html \page studio-3d-editor.html - \nextpage quick-components-view.html + \nextpage studio-material-editor.html \title 3D Editor diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc index 73d4f66937e..abddc903a97 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc @@ -32,7 +32,7 @@ \title Materials and Shaders - \image studio-qtquick-3d-material.png "Material attached to model in Design mode" + \image studio-qtquick-3d-material.webp "Material attached to model in Design mode" Materials and shaders define how object surfaces are rendered in \QDS and live preview. As you change the properties of materials, new shaders are @@ -40,6 +40,10 @@ a shader depends on a combination of the properties that are set on it, and the context of the scene itself. + It is recommended that you use the \l {Material Editor and Browser} when + working with materials, but you can also add materials using the components + library. + The materials that you used in your imported scenes are imported to \QDS as \l{Qt Quick 3D} components. When you add a View3D component, it contains a DefaultMaterial component. You can use the following predefined Qt Quick @@ -62,171 +66,12 @@ defines an image and how the image is mapped to meshes in a 3D scene. For more information, see \l {Textures}. - You can modify material properties in the \uicontrol Properties view, as - instructed in the following sections. The availability of the properties - depends on the material type. + You can create and modify materials in + \uicontrol {Material Editor} and \uicontrol {Material Browser}. The availability + of the properties depends on the material type. - \image studio-qtquick-3d-default-material.png "DefaultMaterial properties" - - To enable the material to use vertex colors from the mesh, select the - \uicontrol {Enable vertex colors} check box. These are multiplied - by any other colors specified for the material. + \image studio-qtquick-3d-default-material.webp "DefaultMaterial properties" You can animate material properties in the \uicontrol Timeline view, as instructed in \l {Creating Timeline Animations}. - - \section1 Blending Colors - - To determine how the colors of a model blend with the colors of the models - behind it, set the \uicontrol {Blend mode} property. To make opaque objects - occlude the objects behind them, select \uicontrol {SourceOver}. - - For a lighter result, select \uicontrol Screen to blend colors using an - inverted multiply or \uicontrol ColorDodge to blend them by inverted - division. Color dodge procudes an even lighter result than screen. - - For a darker result, select \uicontrol Multiply to blend colors using a - multiply or \uicontrol ColorBurn to blend them by inverted division, where - the result also is inverted. Color burn produces an even darker result than - multiply. - - The screen and multiply modes are order-independent, so select them to - avoid \e popping, which can happen when using semi-opaque objects and - sorting the back and front faces or models. - - For a result with higher contrast, select \uicontrol Overlay, which is a mix - of the multiply and screen modes. - - \section1 Lighting Materials - - To set the lighting method for generating a material, use the - \uicontrol Lighting property. Select \uicontrol {Fragment lighting} to - calculate diffuse and specular lighting for each rendered pixel. Some - effects, such as Fresnel or a bump map, require fragment lighting. - - To skip lighting calculation, select \uicontrol {No lighting}. This is very - fast and quite effective when using image maps that do not need to be shaded - by lighting. - - To set the base color for the material, use the \uicontrol {Diffuse Color} - property. You can either use the color picker or specify a RBG value. Set - the diffuse color to black to create purely-specular materials, such as - metals or mirrors. To apply a texture to a material, set it as the value of - the \uicontrol {Diffuse map} property. Using a texture with transparency - also applies the alpha channel as an \uicontrol {Opacity map}. You can set - the opacity of the material independently of the model as the value of the - \uicontrol Opacity property. - - \section1 Self-Illuminating Materials - - To set the color and amount of self-illumination for a material, use the - \uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In - a scene with black ambient lighting, a material with an emissive factor of 0 - is black where the light does not shine on it. Setting the emissive factor - to 1 shows the material in its diffuse color instead. - - To use a Texture for specifying the emissive factor for different parts of - the material, set the \uicontrol {Emissive map} property. Using a grayscale - image does not affect the color of the result, while using a color image - produces glowing regions with the color affected by the emissive map. - - \section1 Using Highlights and Reflections - - You can control the highlights and reflections on a material by setting the - properties in the \uicontrol Specular group. You can use the color picker - or set a RGB value to specify the color used to adjust specular reflections. - Use white for no effect - - To use a color texture to modulate the amount and the color of specularity - across the surface of a material, set the \uicontrol {Specular map} - property. Set the \uicontrol {Specular amount} property to specify the - strength of specularity. This property does not affect the specular - reflection map, but it does affect the amount of reflections from a scene's - light probe. - - \note Unless your mesh is high-resolution, you may need to use fragment - lighting to get good specular highlights from scene lights. - - To determine how to calculate specular highlights for lights in the scene, - set the \uicontrol {Specular model}. In addition to the default mode, you - can use the GGX or Ward lighting model. - - To use a Texture for specular highlighting on a material, set the - \uicontrol {Reflection map} property. When the texture is applied using - environmental mapping (not UV mapping), the map appears to be reflecting - from the environment as you rotate the model. Specular reflection maps are - an easy way to add a high-quality look at a relatively low cost. - - To specify an image to use as the specular reflection map, set the - \uicontrol {Light probe} property. - - Crisp images cause your material to look very glossy. The more you - blur your image, the softer your material appears. - - To decrease head-on reflections (looking directly at the surface) - while maintaining reflections seen at grazing angles, set the - \uicontrol {Fresnel power} property. To select the angles to control, - set the \uicontrol {Index of refraction} property. - - To control the size of the specular highlights generated from lights and the - clarity of reflections in general, set the \uicontrol {Specular roughness} - property. Larger values increase the roughness, while softening specular - highlights and blurring reflections. To control the specular roughness of - the material using a Texture, set the \uicontrol {Roughness map property}. - - \section1 Simulating Geometry Displacement - - Specify the properties in the \uicontrol {Bump/Normal} group to simulate - fine geometry displacement across the surface of the material. Set the - \uicontrol {Bump map} property to use a grayscale texture for the - simulation. Brighter pixels indicate raised regions. - - To use a RGB image for simulation, set the \uicontrol {Normal map} property. - The RGB channels indicate XYZ normal deviations. - - The amount of displacement is controlled by the \uicontrol {Bump amount} - property. - - Bump and normal maps do not affect the silhouette of a model. To affect the - silhouette, set the \uicontrol {Displacement map} property. It specifies a - grayscale image used to offset the vertices of geometry across the surface - of the material. The \uicontrol {Displacement amount} property specifies the - offset amount. - - \section1 Specifying Material Translucency - - Set the properties in the \uicontrol Translucency group to control how much - light can pass through the material from behind. To use a grayscale texture, - specify it as the value of the \uicontrol {Translucency map} property. - - To specify the amount of light wrap for the translucency map, set the - \uicontrol {Diffuse light wrap} property. A value of 0 does not wrap the - light at all, while a value of 1 wraps the light all around the object. - - To specify the amount of falloff for the translucency based on - the angle of the normals of the object to the light source, set - the \uicontrol {Translucency falloff} property. - - \section1 Culling Faces - - Set the \uicontrol {Culling mode} property to determine whether the front - and back faces of a model are rendered. Culling modes check whether the - points in the polygon appear in clockwise or counter-clockwise order when - projected onto the screen. If front-facing polygons have a clockwise - winding, but the polygon projected on the screen has a counter-clockwise - winding, the projected polygon is rotated to face away from the camera and - is not rendered. Culling makes rendering objects quicker and more efficient - by reducing the number of polygons to draw. - - \section1 Applying Materials to Models - - To apply materials to models, you should first delete the default material, - and then drag-and-drop a new material from \l Assets to a model component - in \l Navigator. - - You can apply the same material to another component as well. Again, - delete the default material first. You should then select the component and - go to the \uicontrol Properties view. Find the \uicontrol Materials property, - select the \inlineimage icons/plus.png - icon, and choose the new material in the dropdown menu. */ diff --git a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc index 464926ea351..2d800909d6d 100644 --- a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc @@ -25,7 +25,7 @@ /*! \page quick-components-view.html - \previouspage studio-3d-editor.html + \previouspage studio-material-editor.html \nextpage quick-assets.html \title Components diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc index 9c6b7296313..3245b28b59d 100644 --- a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc @@ -38,9 +38,9 @@ \image studio-timeline-empty.png "Empty Timeline view" Select the \inlineimage icons/plus.png - (\uicontrol {Add Timeline}) button to \l{Creating Timelines} - {create a timeline} and specify settings for it in the - \uicontrol {Timeline Settings} dialog. + (\uicontrol {Add Timeline}) button to + \l{Creating a Timeline}{create a timeline} and specify settings for it in + the \uicontrol {Timeline Settings} dialog. \image studio-timeline-settings.png "Timeline Settings dialog" @@ -124,11 +124,11 @@ \li \inlineimage icons/animation.png \li Opens the \uicontrol {Timeline Settings} dialog for editing timeline settings. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li Timeline ID \li Displays the ID of the current timeline. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li \inlineimage icons/to_first_frame.png \li \uicontrol {To Start (Home)} moves to the first frame on the @@ -170,7 +170,7 @@ \li Specifies the first frame of the timeline. Negative values are allowed. The difference between the start frame and the end frame determines the duration of the animation. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li \inlineimage icons/zoom_small.png \li \uicontrol {Zoom Out} (\key Ctrl+-) zooms out of the view. @@ -189,7 +189,7 @@ the start frame and the end frame determines the duration of the animation, so if the start frame is 0, the end frame equals the duration. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li State Name \li Displays the name of the current state. diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc index fc088945cac..e5d938a4701 100644 --- a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc @@ -30,18 +30,19 @@ \title Creating Timeline Animations - You can create timeline and keyframe based animations for linear + You can create timelines and keyframe-based animations for linear interpolation through intermediate values at specified keyframes instead of immediately changing to the target value. - \section1 Creating Timelines + You can also bind the timeline to a property value of a component such as + a slider and control the animation this way. - You specify settings for the timeline and for running the animation in the - \uicontrol {Timeline Settings} dialog. The \uicontrol Animation radio button - is selected for a timeline animation and the \uicontrol {Expression binding} - radio button for a \l{Setting Bindings}{property animation}. + \section1 Creating an Animation - \image studio-timeline-settings.png "Timeline Settings dialog" + To create an animation, whether it's a keyframe animation or an animation + bound to a property value, you first need to create a timeline. + + \section2 Creating a Timeline To create a timeline to animate a UI component: @@ -50,95 +51,97 @@ (\uicontrol {Add Timeline}) button to specify settings for the timeline and running the animation in the \uicontrol {Timeline Settings} dialog. - \li In the \uicontrol {Timeline ID} field, enter an ID that describes - the animated component. - \li In the \uicontrol {Start frame} field, set the first frame of the - timeline. Negative values are allowed. - \li In the \uicontrol {End frame} field, set the last frame of the - timeline. - \li In the \uicontrol {Animation ID} field, enter an ID for the - animation. - \li Select the \uicontrol {Running in Base State} check box to run the - animation when the base state is applied. Deselect the check box - if you want to run the animation when some other state is applied. - For more information, see \l{Binding Animations to States}. - \li In the \uicontrol {Start frame} field, set the first frame of the - animation. - \li In the \uicontrol {End frame} field, set the last frame of the - animation. - \li In the \uicontrol {Duration} field, set the length of the - animation from the start frame to the end frame. If you set a - shorter duration than the number of frames, frames are left out - from the end of the animation when viewing it. - \li Select the \uicontrol Continuous check box to loop the animation - indefinitely. - \li In the \uicontrol Loops field, select the number of times to run - the animation as a loop. The default number of loops is one, which - means that you must restart the animation to see it again - \li Select the \uicontrol {Ping pong} check box to play the animation - backwards back to the beginning when it reaches the end. - \li In the \uicontrol Finished field, select the state - to apply when the animation finishes. + \li On the \uicontrol {Timeline Settings} tab: + \list + \li In the \uicontrol {Timeline ID} field, enter an id that + describes the timeline. + \li In the \uicontrol {Start frame} field, set the first frame + of the timeline. Negative values are allowed. + \li In the \uicontrol {End frame} field, set the last frame + of the timeline. + \image timeline-settings-dialog.png + \endlist + \li On the \uicontrol {Animation Settings} tab: + \list + \li In the \uicontrol {Animation ID} field, enter an ID for the + animation. + \li Optional. Select the \uicontrol {Running in Base State} + check box to run the animation when the base state is applied. + Clear the check box to run the animation when some other state + is applied. For more information, see + \l{Binding Animations to States}. + \li In the \uicontrol {Start frame} field, set the first frame + of the animation. + \li In the \uicontrol {End frame} field, set the last frame of + the animation. + \li In the \uicontrol {Duration} field, set the length of the + animation in milliseconds. + \li Optional. Select the \uicontrol Continuous check box to + loop the animation indefinitely. + \li Optional. In the \uicontrol Loops field, set the number of + times to run the animation. The default number of + loops is one, which means that you must restart the animation + to see it again. + \li Optional. Select the \uicontrol {Ping pong} check box to + play the animation backwards back to the beginning when it + reaches the end. + \li Optional. In the \uicontrol Finished field, select the state + to transition to when the animation finishes. + \endlist \li Select \uicontrol Close to close the dialog and save the settings. \endlist - To create additional timelines, select the \inlineimage icons/plus.png - (\uicontrol {Add Timeline}) button next to the - \uicontrol {Timeline Settings} tab. + Now, with the settings set for the timeline and the animation, you + set the keyframes for the properties to animate. - To specify settings for running timeline animations, select the - \inlineimage icons/plus.png - (\uicontrol {Add Animation}) button next to the - \uicontrol {Animation Settings} tab. For example, you could create - settings for running a part of the timeline animation between specified - frames or for running the animation backwards from the last frame to the - first. + \section3 Creating Additional Timelines - To modify the settings, select the \inlineimage icons/animation.png - (\uicontrol {Timeline Settings (S)}) button on the \l{Timeline Toolbar} - {toolbar} (or press \key S) in the \l Timeline view. + You can create more than one timeline. The purpose of several timelines is + to use different timelines in different states. - \section2 Binding Animations to States + To create a timeline for a second state: - The table at the bottom of the \uicontrol {Timeline Settings} dialog lists - the available states. Double-click the values in the \uicontrol Timeline - and \uicontrol Animation column to bind the states to animations. In the - \uicontrol {Fixed Frame} column, you can bind the states that don't have - animations to fixed frames. + \list 1 + \li In \uicontrol {Timeline}, open the \uicontrol {Timeline Settings} + dialog. + \li Next to the \uicontrol {Timeline Settings} tab, select + \inlineimage icons/plus.png + . This creates another timeline. + \li In the table below the \uicontrol {Animation Settings} tab, set the + Timeline for the state where you want to use it. + \image timeline-settings-dialog-second.png + \endlist + To set the keyframe values for the timeline you created, first select the + state in \uicontrol {States} and the timeline is available in + \uicontrol{Timelines}. - \section1 Managing Keyframes - - To animate components in the \l Timeline view, move to a frame - on the timeline and specify changes in the values of a property. \QC - automatically adds keyframes between two keyframes and sets their values - evenly to create an appearance of movement or transformation. - - \image studio-timeline-with-tracks.png "Timeline view" + \image timeline-states.png \section2 Setting Keyframe Values - You can insert keyframes for all the properties of all the components that - you want to animate first, and then record the changes in their values by - selecting the \inlineimage icons/local_record_keyframes.png - (\uicontrol {Per Property Recording}) button for one property at a time. - For example, you can hide and show components by turning their visibility - off and on or by setting their opacity to 0 or 1. + When you create a timeline, \QDS creates one animation for the timeline. + You can create as many animations for a timeline as you want. For example, + you can create animations to run just a small section of the timeline or to + run the timeline backwards. - You can also select the \uicontrol {Auto Key (K)} button (or press \key K) - to record changes in property values, but you need to be more careful about - which property values you are changing to avoid surprises. + To animate components in the \l Timeline view, you set keyframe values for + the property to animate. \QDS automatically adds keyframes between two + keyframes and sets their values evenly to create, for example, movement or + transformation. - To record the changes of property values: + To set keyframe values for a component property: \list 1 \li In the \l Navigator view, select the component to animate. \li In the \l Properties view, select \inlineimage icons/action-icon.png (\uicontrol Actions) > \uicontrol {Insert Keyframe} for the property that you want to animate. + \image timeline-insert-keyframe.png \li In the \l Timeline view, select the \uicontrol {Per Property Recording} button to start recording property changes. - \li Check that the playhead is in frame 0 and enter the value of the + \image timeline-per-property-recording.png + \li Ensure that the playhead is in frame 0 and enter the value of the property in the field next to the property name on the timeline. Press \key Enter to save the value. \li Move the playhead to another frame on the timeline and specify @@ -148,11 +151,67 @@ \uicontrol {Per Property Recording} again to stop recording. \endlist + \section2 Binding a Timeline to a Property + + When you bind a timeline to a component property, the animation's + current frame is controlled by the value of the property. + + In this example, you bind the timeline to a slider component. + + With a timeline created and keyframe values set: + + \list 1 + \li From \uicontrol {Components}, drag a slider to + \uicontrol {Form Editor} or \uicontrol {Navigator}. + \li In \uicontrol {Navigator}, select \e slider and in + \uicontrol {Properties}, set: + \list + \li \uicontrol To to 1000. + \note The \uicontrol From and \uicontrol To values of the slider + should match the \uicontrol {Start Frame} and + \uicontrol {End Frame} values of the timeline if you want to + control the complete animation with the slider. + \endlist + \li In the \uicontrol {Timeline Settings} dialog, select + \inlineimage icons/minus.png + next to the \uicontrol {Animation Settings} tab to delete the + animation. If you have several animations, delete all. + \li In \uicontrol {Expression binding}, enter \c {slider.value}. + \image timeline-settings-property-binding.png + \endlist + + \section2 Binding Animations to States + + You can bind animations to states, this means that the animation will run + when you enter the state. + + To bind an animation to a state: + \list 1 + \li In the table at the bottom of the \uicontrol {Timeline Settings} + dialog lists: + \list + \li Double-click the value in the \uicontrol Timeline field and select + the timeline with the animation you want to bind to the state. + \li Double-click the value in the \uicontrol Animation field and + select the animation you want to bind to the state. + \image timeline-bind-animation-state.png + \endlist + \endlist + To bind a state to a certain keyframe in an animation without running the + animation, set the keyframe in the \uicontrol{Fixed Frame} field. + + \section1 Managing Keyframes + + \image studio-timeline-with-tracks.png "Timeline view" + + \section2 Editing Keyframes + To remove all the changes you recorded for a property, right-click the property name on the timeline and select \uicontrol {Remove Property}. To add keyframes to the keyframe track of a component at the current - position of the playhead, select \uicontrol {Add Keyframes at Current Frame}. + position of the playhead, right-click the component name on the timeline and + select \uicontrol {Add Keyframes at Current Frame}. Keyframes are marked on the timeline by using \l{keyframe_marker}{markers} of different colors and shapes, depending on whether they are active or @@ -162,7 +221,7 @@ \section2 Editing Keyframe Values To fine-tune the value of a keyframe, double-click a keyframe marker or - select \uicontrol {Edit Keyframe} in the context menu. + right-click it and select \uicontrol {Edit Keyframe} in the context menu. The \uicontrol {Edit Keyframe} dialog displays the name of the property you are animating and its current value at the frame specified in the @@ -173,27 +232,36 @@ \section2 Copying Keyframes You can copy the keyframes from the keyframe track for a component and - paste them to the keyframe track of another component. To copy all - keyframes from one track to another one, first right-click the component ID - and select \uicontrol {Copy All Keyframes} in the context menu. - Then right-click the other component ID, and select - \uicontrol {Paste Keyframes} in the context menu. + paste them to the keyframe track of another component. + + To copy all keyframes from one track to another one: + \list 1 + \li Right-click the component ID and select + \uicontrol {Copy All Keyframes} in the context menu. + \li Right-click the other component ID, and select + \uicontrol {Paste Keyframes} in the context menu. + \endlist \section2 Deleting Keyframes - To delete the selected keyframe, select \uicontrol {Delete Keyframe} in the - context menu. + To delete a keyframe, right-click it and select \uicontrol {Delete Keyframe} + in the context menu. - To delete all keyframes from the selected component, select + To delete all keyframes from the selected component, right-click the + component name in \uicontrol {Timeline} and select \uicontrol {Delete All Keyframes} in the context menu. \section1 Viewing the Animation - You can view the animation on the canvas by moving the playhead along the - timeline. + To preview your animation, do one of the following in the + \uicontrol{Timeline} view: + \list + \li Drag the playhead along the timeline. + \li Select \inlineimage icons/start_playback.png + button or press \key Space. + \endlist - To preview the animation, select the \uicontrol {Play (Space)} - button or press \key Space. To preview the whole UI, select the + To preview the whole UI, select the \inlineimage icons/live_preview.png (\uicontrol {Show Live Preview}) button on the canvas toolbar or press \key {Alt+P}. diff --git a/doc/qtdesignstudio/src/views/studio-material-editor.qdoc b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc new file mode 100644 index 00000000000..fcfa9823e9f --- /dev/null +++ b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \page studio-material-editor.html + \previouspage studio-3d-editor.html + \nextpage quick-components-view.html + + + \title Material Editor and Browser + + In the \uicontrol {Material Editor} and \uicontrol {Material Browser} views, + you create and manage materials. + + \image material-editor-browser.webp "Material Editor and Browser" + + \section1 Creating a Material + + To create a new material, do one of the following: + + \list + \li In \uicontrol {Material Browser}, select \inlineimage icons/plus.png + . + \li In \uicontrol {Material Editor}, select \inlineimage icons/plus.png + . + \endlist + + \section1 Editing a Material + + To edit a material, select it in \uicontrol{Material Browser} and edit its + properties in \uicontrol{Material Editor}. If \uicontrol {Material Editor} + is closed, open it in one of the following ways: + + \list + \li In \uicontrol{Navigator}, right-click an object that has the material + assigned to it and select \uicontrol {Edit Material}. + \li In \uicontrol{Material Browser}, double-click a material. + \endlist + + \section1 Assigning a Material to an Object + + To assign a material to a 3D object in your project, first select the object + in \uicontrol Navigator or \uicontrol {3D Editor}. Then, do one of the + following: + + \list + \li In \uicontrol {Material Browser}, right-click the material and select + \uicontrol {Apply to Selected}. If there already is any material assigned + to the object, you can select whether to replace the material or to add + another material to the object. + \li In \uicontrol {Material Editor}, select + \inlineimage icons/apply-material.png + . This replaces any material already assigned to the object. + \endlist + + \section1 Removing a Material from an Object + + To remove an assigned material from an object: + \list 1 + \li In \uicontrol{Navigator}, select the object. + \li In \uicontrol{Properties}, select + \inlineimage icons/close.png + next to the material. + \image materials-remove-material.png + \endlist + + \section1 Using Texture Maps + + In \QDS you can add many different texture maps to your material. + + To add a texture map to a material: + \list 1 + \li Select the material in \uicontrol{Material Browser}. + \li From \uicontrol {Assets}, drag an image to the correct map field + in \uicontrol {Material Editor}. For example, to add a diffuse map, drag + the image to \uicontrol{Diffuse Map} in \uicontrol{Material Editor}. + \endlist + + \section2 Using a Reflection Map for Environmental Mapping + + To use a texture for environmental mapping, you need to set the mapping + mode to \e {environment}. + + To add a reflection map for environmental mapping to a material: + + \list 1 + \li Select the material in \uicontrol {Material Browser}. + \li From \uicontrol{Assets}, drag an image to + \uicontrol{Reflection Map}. + \li In \uicontrol {Navigator}, select + \inlineimage icons/filtericon.png + and then clear \uicontrol {Show Only Visible Components}. Now the + texture you just added to the material is visible in + \uicontrol {Navigator}. + \image navigator-material-texture.png + \li In \uicontrol {Navigator}, select the texture. + \li In \uicontrol {Properties}, set \uicontrol {Texture Mapping} to + \uicontrol {Environment}. + \endlist + + \section1 Blending Colors + + To determine how the colors of a model blend with the colors of the models + behind it, set the \uicontrol {Blend mode} property. To make opaque objects + occlude the objects behind them, select \uicontrol {SourceOver}. + + For a lighter result, select \uicontrol Screen to blend colors using an + inverted multiply or \uicontrol ColorDodge to blend them by inverted + division. Color dodge produces an even lighter result than screen. + + For a darker result, select \uicontrol Multiply to blend colors using a + multiply or \uicontrol ColorBurn to blend them by inverted division, where + the result also is inverted. Color burn produces an even darker result than + multiply. + + The screen and multiply modes are order-independent, so select them to + avoid \e popping, which can happen when using semi-opaque objects and + sorting the back and front faces or models. + + For a result with higher contrast, select \uicontrol Overlay, which is a mix + of the multiply and screen modes. + + \section1 Lighting Materials + + To set the lighting method for generating a material, use the + \uicontrol Lighting property. Select \uicontrol {Fragment lighting} to + calculate diffuse and specular lighting for each rendered pixel. Some + effects, such as Fresnel or a bump map, require fragment lighting. + + To skip lighting calculation, select \uicontrol {No lighting}. This is very + fast and quite effective when using image maps that do not need to be shaded + by lighting. + + To set the base color for the material, use the \uicontrol {Diffuse Color} + property. You can either use the color picker or specify a RBG value. Set + the diffuse color to black to create purely-specular materials, such as + metals or mirrors. To apply a texture to a material, set it as the value of + the \uicontrol {Diffuse map} property. Using a texture with transparency + also applies the alpha channel as an \uicontrol {Opacity map}. You can set + the opacity of the material independently of the model as the value of the + \uicontrol Opacity property. + + \section1 Self-Illuminating Materials + + To set the color and amount of self-illumination for a material, use the + \uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In + a scene with black ambient lighting, a material with an emissive factor of 0 + is black where the light does not shine on it. Setting the emissive factor + to 1 shows the material in its diffuse color instead. + + To use a Texture for specifying the emissive factor for different parts of + the material, set the \uicontrol {Emissive map} property. Using a grayscale + image does not affect the color of the result, while using a color image + produces glowing regions with the color affected by the emissive map. + + \section1 Using Highlights and Reflections + + You can control the highlights and reflections on a material by setting the + properties in the \uicontrol Specular group. You can use the color picker + or set a RGB value to specify the color used to adjust specular reflections. + Use white for no effect. + + To use a color texture to modulate the amount and the color of specularity + across the surface of a material, set the \uicontrol {Specular map} + property. Set the \uicontrol {Specular amount} property to specify the + strength of specularity. This property does not affect the specular + reflection map, but it does affect the amount of reflections from a scene's + light probe. + + \note Unless your mesh is high-resolution, you may need to use fragment + lighting to get good specular highlights from scene lights. + + To determine how to calculate specular highlights for lights in the scene, + set the \uicontrol {Specular model}. In addition to the default mode, you + can use the GGX or Ward lighting model. + + To use a Texture for specular highlighting on a material, set the + \uicontrol {Reflection map} property. When the texture is applied using + environmental mapping (not UV mapping), the map appears to be reflecting + from the environment as you rotate the model. Specular reflection maps are + an easy way to add a high-quality look at a relatively low cost. + + To specify an image to use as the specular reflection map, set the + \uicontrol {Light probe} property. + + Crisp images cause your material to look very glossy. The more you + blur your image, the softer your material appears. + + To decrease head-on reflections (looking directly at the surface) + while maintaining reflections seen at grazing angles, set the + \uicontrol {Fresnel power} property. To select the angles to control, + set the \uicontrol {Index of refraction} property. + + To control the size of the specular highlights generated from lights and the + clarity of reflections in general, set the \uicontrol {Specular roughness} + property. Larger values increase the roughness, while softening specular + highlights and blurring reflections. To control the specular roughness of + the material using a Texture, set the \uicontrol {Roughness map property}. + + \section1 Simulating Geometry Displacement + + Specify the properties in the \uicontrol {Bump/Normal} group to simulate + fine geometry displacement across the surface of the material. Set the + \uicontrol {Bump map} property to use a grayscale texture for the + simulation. Brighter pixels indicate raised regions. + + To use an image for simulation, set the \uicontrol {Normal map} property. + The RGB channels indicate XYZ normal deviations. + + The amount of displacement is controlled by the \uicontrol {Bump amount} + property. + + Bump and normal maps do not affect the silhouette of a model. To affect the + silhouette, set the \uicontrol {Displacement map} property. It specifies a + grayscale image used to offset the vertices of geometry across the surface + of the material. The \uicontrol {Displacement amount} property specifies the + offset amount. + + \section1 Specifying Material Translucency + + Set the properties in the \uicontrol Translucency group to control how much + light can pass through the material from behind. To use a grayscale texture, + specify it as the value of the \uicontrol {Translucency map} property. + + To specify the amount of light wrap for the translucency map, set the + \uicontrol {Diffuse light wrap} property. A value of 0 does not wrap the + light at all, while a value of 1 wraps the light all around the object. + + To specify the amount of falloff for the translucency based on + the angle of the normals of the object to the light source, set + the \uicontrol {Translucency falloff} property. + + \section1 Culling Faces + + Set the \uicontrol {Culling mode} property to determine whether the front + and back faces of a model are rendered. Culling modes check whether the + points in the polygon appear in clockwise or counter-clockwise order when + projected onto the screen. If front-facing polygons have a clockwise + winding, but the polygon projected on the screen has a counter-clockwise + winding, the projected polygon is rotated to face away from the camera and + is not rendered. Culling makes rendering objects quicker and more efficient + by reducing the number of polygons to draw. + +*/ diff --git a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h index c69d478875d..47196df8d24 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h @@ -61,7 +61,8 @@ public: QSize captureImageMinimumSize, QSize captureImageMaximumSize, qint32 stateInstanceId, - const QList &edit3dBackgroundColor) + const QList &edit3dBackgroundColor, + const QColor &edit3dGridColor) : instances(instanceContainer) , reparentInstances(reparentContainer) , ids(idVector) @@ -78,6 +79,7 @@ public: , captureImageMaximumSize(captureImageMaximumSize) , stateInstanceId{stateInstanceId} , edit3dBackgroundColor{edit3dBackgroundColor} + , edit3dGridColor{edit3dGridColor} {} friend QDataStream &operator<<(QDataStream &out, const CreateSceneCommand &command) @@ -98,6 +100,7 @@ public: out << command.captureImageMinimumSize; out << command.captureImageMaximumSize; out << command.edit3dBackgroundColor; + out << command.edit3dGridColor; return out; } @@ -120,6 +123,7 @@ public: in >> command.captureImageMinimumSize; in >> command.captureImageMaximumSize; in >> command.edit3dBackgroundColor; + in >> command.edit3dGridColor; return in; } @@ -141,6 +145,7 @@ public: QSize captureImageMaximumSize; qint32 stateInstanceId = 0; QList edit3dBackgroundColor; + QColor edit3dGridColor; }; QDebug operator<<(QDebug debug, const CreateSceneCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h index cfe4529ba1b..95ca0d3ce25 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h @@ -40,6 +40,7 @@ public: ActiveSceneChanged, RenderModelNodePreviewImage, Import3DSupport, + ModelAtPos, None }; PuppetToCreatorCommand(Type type, const QVariant &data); diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index cc3611df764..13d39739437 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -57,10 +57,12 @@ public: ParticlesRestart, ParticlesSeek, SelectBackgroundColor, + SelectGridColor, ResetBackgroundColor, + GetModelAtPos }; - explicit View3DActionCommand(Type type, const QVariant &value); + View3DActionCommand(Type type, const QVariant &value); View3DActionCommand() = default; diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc index 7e023c127b7..bbe9a910db6 100644 --- a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc +++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc @@ -13,7 +13,7 @@ mockfiles/images/directional@2x.png mockfiles/images/point.png mockfiles/images/point@2x.png - mockfiles/images/floor_tex.png + mockfiles/images/static_floor.png mockfiles/images/spot.png mockfiles/images/spot@2x.png mockfiles/qt5/AdjustableArrow.qml diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png new file mode 100644 index 00000000000..93073719f55 Binary files /dev/null and b/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png differ diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml index 9a95ca34b98..09a4ebdc3f3 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml @@ -47,6 +47,7 @@ Item { property alias contentItem: contentItem property color backgroundGradientColorStart: "#222222" property color backgroundGradientColorEnd: "#999999" + property color gridColor: "#aaaaaa" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -96,12 +97,14 @@ Item { {"usePerspective": usePerspective, "showSceneLight": showEditLight, "showGrid": showGrid, + "gridColor": gridColor, "importScene": activeScene, "cameraZoomFactor": cameraControl._zoomFactor, "z": 1}); editView.usePerspective = Qt.binding(function() {return usePerspective;}); editView.showSceneLight = Qt.binding(function() {return showEditLight;}); editView.showGrid = Qt.binding(function() {return showGrid;}); + editView.gridColor = Qt.binding(function() {return gridColor;}); editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;}); selectionBoxes.length = 0; @@ -217,10 +220,19 @@ Item { function updateViewStates(viewStates) { if ("selectBackgroundColor" in viewStates) { - var color = viewStates.selectBackgroundColor - backgroundGradientColorStart = color[0]; - backgroundGradientColorEnd = color[1]; + if (Array.isArray(viewStates.selectBackgroundColor)) { + var colors = viewStates.selectBackgroundColor + backgroundGradientColorStart = colors[0]; + backgroundGradientColorEnd = colors[1]; + } else { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color; + backgroundGradientColorEnd = color; + } } + + if ("selectGridColor" in viewStates) + viewRoot.gridColor = viewStates.selectGridColor } // If resetToDefault is true, tool states not specifically set to anything will be reset to diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml index e450a5a796c..d9df67fe7c4 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml @@ -33,6 +33,7 @@ Node { property alias lines: gridGeometry.lines property alias step: gridGeometry.step property alias subdivAlpha: subGridMaterial.opacity + property alias gridColor: mainGridMaterial.diffuseColor eulerRotation.x: 90 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index c36d8c227c3..9fee06e0ad1 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -45,10 +45,6 @@ View3D { Node { DirectionalLight { - shadowMapQuality: Light.ShadowMapQualityMedium - shadowFilter: 20 - shadowFactor: 21 - castsShadow: true eulerRotation.x: -26 eulerRotation.y: -57 } @@ -68,25 +64,5 @@ View3D { source: "#Sphere" materials: previewMaterial } - - Model { - id: floorModel - source: "#Rectangle" - scale.y: 8 - scale.x: 8 - eulerRotation.x: -90 - materials: floorMaterial - DefaultMaterial { - id: floorMaterial - diffuseMap: floorTex - - Texture { - id: floorTex - source: "../images/floor_tex.png" - scaleU: floorModel.scale.x - scaleV: floorModel.scale.y - } - } - } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index a6d5c6b1db5..70b9dbc4d0e 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -123,14 +123,13 @@ Item { anchors.fill: parent } - Rectangle { + // We can use static image in Qt5 as only small previews will be generated + Image { id: backgroundRect anchors.fill: parent z: -1 - gradient: Gradient { - GradientStop { position: 1.0; color: "#222222" } - GradientStop { position: 0.0; color: "#999999" } - } + source: "../images/static_floor.png" + fillMode: Image.Stretch } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index 5c8b9e1cd72..82688bbef5a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -37,7 +37,7 @@ View3D { function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, model, root, 1040, closeUp); } @@ -70,7 +70,7 @@ View3D { materials: [ DefaultMaterial { - diffuseColor: "#4aee45" + diffuseColor: "#999999" } ] } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml index 7a376179d82..4032e245ed0 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml @@ -32,6 +32,7 @@ View3D { property bool usePerspective: false property alias showSceneLight: sceneLight.visible property alias showGrid: helperGrid.visible + property alias gridColor: helperGrid.gridColor property alias sceneHelpers: sceneHelpers property alias perspectiveCamera: scenePerspectiveCamera property alias orthoCamera: sceneOrthoCamera diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index 228154a9a49..a3f14e9d113 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -48,6 +48,7 @@ Item { property alias contentItem: contentItem property color backgroundGradientColorStart: "#222222" property color backgroundGradientColorEnd: "#999999" + property color gridColor: "#aaaaaa" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -100,12 +101,14 @@ Item { {"usePerspective": usePerspective, "showSceneLight": showEditLight, "showGrid": showGrid, + "gridColor": gridColor, "importScene": activeScene, "cameraZoomFactor": cameraControl._zoomFactor, "z": 1}); editView.usePerspective = Qt.binding(function() {return usePerspective;}); editView.showSceneLight = Qt.binding(function() {return showEditLight;}); editView.showGrid = Qt.binding(function() {return showGrid;}); + editView.gridColor = Qt.binding(function() {return gridColor;}); editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;}); selectionBoxes.length = 0; @@ -211,10 +214,19 @@ Item { function updateViewStates(viewStates) { if ("selectBackgroundColor" in viewStates) { - var color = viewStates.selectBackgroundColor - backgroundGradientColorStart = color[0]; - backgroundGradientColorEnd = color[1]; + if (Array.isArray(viewStates.selectBackgroundColor)) { + var colors = viewStates.selectBackgroundColor + backgroundGradientColorStart = colors[0]; + backgroundGradientColorEnd = colors[1]; + } else { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color; + backgroundGradientColorEnd = color; + } } + + if ("selectGridColor" in viewStates) + viewRoot.gridColor = viewStates.selectGridColor } // If resetToDefault is true, tool states not specifically set to anything will be reset to diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml index 66f383518eb..ef10818eedc 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml @@ -33,6 +33,7 @@ Node { property alias lines: gridGeometry.lines property alias step: gridGeometry.step property alias subdivAlpha: subGridMaterial.opacity + property alias gridColor: mainGridMaterial.diffuseColor eulerRotation.x: 90 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index ed5cfea56f4..94051d5f6e6 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -45,10 +45,6 @@ View3D { Node { DirectionalLight { - shadowMapQuality: Light.ShadowMapQualityMedium - shadowFilter: 20 - shadowFactor: 21 - castsShadow: true eulerRotation.x: -26 eulerRotation.y: -57 } @@ -70,24 +66,5 @@ View3D { materials: previewMaterial } - Model { - id: floorModel - source: "#Rectangle" - scale.y: 8 - scale.x: 8 - eulerRotation.x: -90 - materials: floorMaterial - DefaultMaterial { - id: floorMaterial - diffuseMap: floorTex - - Texture { - id: floorTex - source: "../images/floor_tex.png" - scaleU: floorModel.scale.x - scaleV: floorModel.scale.y - } - } - } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 5caac0047c4..031d01d65fb 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -126,6 +126,50 @@ Item { GradientStop { position: 1.0; color: "#222222" } GradientStop { position: 0.0; color: "#999999" } } + + // Use View3D instead of static image to make background look good on all resolutions + View3D { + anchors.fill: parent + environment: sceneEnv + + SceneEnvironment { + id: sceneEnv + antialiasingMode: SceneEnvironment.MSAA + antialiasingQuality: SceneEnvironment.High + } + + DirectionalLight { + eulerRotation.x: -26 + eulerRotation.y: -57 + } + + PerspectiveCamera { + y: 125 + z: 120 + eulerRotation.x: -31 + clipNear: 1 + clipFar: 1000 + } + + Model { + id: floorModel + source: "#Rectangle" + scale.y: 8 + scale.x: 8 + eulerRotation.x: -90 + materials: floorMaterial + DefaultMaterial { + id: floorMaterial + diffuseMap: floorTex + Texture { + id: floorTex + source: "../images/floor_tex.png" + scaleU: floorModel.scale.x + scaleV: floorModel.scale.y + } + } + } + } } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 1762e3c9a4d..ea2e23837fd 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -37,7 +37,7 @@ View3D { function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, model, root, 1040, closeUp); } @@ -70,7 +70,7 @@ View3D { materials: [ DefaultMaterial { - diffuseColor: "#4aee45" + diffuseColor: "#999999" } ] } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml index e59392b1ee2..1d0e0377d3b 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml @@ -32,6 +32,7 @@ View3D { property bool usePerspective: false property alias showSceneLight: sceneLight.visible property alias showGrid: helperGrid.visible + property alias gridColor: helperGrid.gridColor property alias sceneHelpers: sceneHelpers property alias perspectiveCamera: scenePerspectiveCamera property alias orthoCamera: sceneOrthoCamera diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 74c2eb270ef..590785a30e3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -812,7 +812,7 @@ QVector3D GeneralHelper::pivotScenePosition(QQuick3DNode *node) const // Calculate bounds for given node, including all child nodes. // Returns true if the tree contains at least one Model node. bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, - QVector3D &maxBounds, bool recursive) + QVector3D &maxBounds) { if (!node) { const float halfExtent = 100.f; @@ -825,7 +825,7 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec auto nodePriv = QQuick3DObjectPrivate::get(node); auto renderNode = static_cast(nodePriv->spatialNode); - if (recursive && renderNode) { + if (renderNode) { #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty)) renderNode->calculateLocalTransform(); @@ -850,7 +850,7 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec if (auto childNode = qobject_cast(child)) { QVector3D newMinBounds = minBounds; QVector3D newMaxBounds = maxBounds; - bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); + bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds); // Ignore any subtrees that do not have Model in them as we don't need those // for visual bounds calculations if (childHasModel) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 5bb1fa1662f..8014a711875 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -130,7 +130,7 @@ private: void handlePendingToolStateUpdate(); QVector3D pivotScenePosition(QQuick3DNode *node) const; bool getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, - QVector3D &maxBounds, bool recursive = false); + QVector3D &maxBounds); QTimer m_overlayUpdateTimer; QTimer m_toolStateUpdateTimer; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp index 2dd653273cd..76deb3a3b39 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp @@ -198,8 +198,7 @@ void IconRenderer::finishCreateIcon() render(saveFile); - // Allow little time for file operations to finish - QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit); + QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit); } void IconRenderer::render(const QString &fileName) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 5183b5cd8fc..4448e2cee1f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -848,6 +848,18 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D(bool timerC m_activeSceneIdUpdateTimer.stop(); } + // We may have to substitute another scene to work around QTBUG-103316 + // The worked around issue is that if a material is used in multiple scenes, there is some + // kind of ownership for it in the first View3D that uses it, so if that view is not rendered + // first, the material will not be properly initialized for other views using it. + // To make materials work properly, we ensure that views are rendered at least once in the + // order they appear in the scene. + if (!m_priorityView3DsToRender.isEmpty()) { + QObject *sceneRoot = find3DSceneRoot(m_priorityView3DsToRender.first()); + if (sceneRoot) + activeSceneVar = objectToVariant(sceneRoot); + } + QMetaObject::invokeMethod(m_editView3DData.rootItem, "setActiveScene", Qt::QueuedConnection, Q_ARG(QVariant, activeSceneVar), Q_ARG(QVariant, QVariant::fromValue(sceneId))); @@ -1012,7 +1024,7 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() // If we have only one or no render queued, send the result to the creator side. // Otherwise, we'll hold on that until we have rendered all pending frames to ensure sent // results are correct. - if (m_need3DEditViewRender <= 1) { + if (m_priorityView3DsToRender.isEmpty() && m_need3DEditViewRender <= 1) { nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::Render3DView, QVariant::fromValue(imgContainer)}); #ifdef QUICK3D_PARTICLES_MODULE @@ -1023,6 +1035,25 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() #endif } + if (!m_priorityView3DsToRender.isEmpty()) { + static int tryCounter = 0; + QObject *sceneRoot = find3DSceneRoot(m_priorityView3DsToRender.first()); + bool needAnotherRender = false; + if (sceneRoot) { + // Active scene is updated asynchronously, so verify we are actually rendering + // the correct priority scene + QObject *activeScene = QQmlProperty::read(m_editView3DData.rootItem, "activeScene").value(); + needAnotherRender = activeScene != sceneRoot; + } + + if (!needAnotherRender || ++tryCounter > 10) { + m_priorityView3DsToRender.removeFirst(); + updateActiveSceneToEditView3D(); + tryCounter = 0; + } + ++m_need3DEditViewRender; + } + if (m_need3DEditViewRender > 0) { // We queue another render even if the requested render count was one, because another // render is needed to ensure gizmo geometries are properly updated. @@ -1059,6 +1090,13 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView() { // This crashes on Qt 6.0.x due to QtQuick3D issue, so the preview generation is disabled #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) || QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) + if (!m_priorityView3DsToRender.isEmpty()) { + // Postpone any preview renders until we have rendered the priority views to ensure + // materials in material library are properly initialized + m_renderModelNodeImageViewTimer.start(17); + return; + } + RequestModelNodePreviewImageCommand cmd = *m_modelNodePreviewImageCommands.begin(); ServerNodeInstance instance; if (cmd.renderItemId() >= 0) @@ -1578,6 +1616,8 @@ void Qt5InformationNodeInstanceServer::add3DViewPorts(const QList &instanceList, - const QHash &toolStates) + const CreateSceneCommand &command) { #ifdef QUICK3D_MODULE if (!m_editView3DData.rootItem) @@ -1779,6 +1819,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList &toolStates = command.edit3dToolStates; QString lastSceneId; auto helper = qobject_cast(m_3dHelper); if (helper) { @@ -1832,11 +1873,23 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QListcomponentCompleted(createComponentCompletedCommand(instanceList)); if (ViewConfig::isQuick3DMode()) { - setup3DEditView(instanceList, command.edit3dToolStates); + setup3DEditView(instanceList, command); updateRotationBlocks(command.auxiliaryChanges); } @@ -1967,12 +2020,6 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com #ifdef IMPORT_QUICK3D_ASSETS QTimer::singleShot(0, this, &Qt5InformationNodeInstanceServer::resolveImportSupport); #endif - - if (!command.edit3dBackgroundColor.isEmpty()) { - View3DActionCommand backgroundColorCommand(View3DActionCommand::SelectBackgroundColor, - QVariant::fromValue(command.edit3dBackgroundColor)); - view3DAction(backgroundColorCommand); - } } void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList &childList) @@ -2237,9 +2284,12 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c case View3DActionCommand::ShowCameraFrustum: updatedToolState.insert("showCameraFrustum", command.isEnabled()); break; - case View3DActionCommand::SelectBackgroundColor: { + case View3DActionCommand::SelectBackgroundColor: updatedViewState.insert("selectBackgroundColor", command.value()); break; + case View3DActionCommand::SelectGridColor: { + updatedViewState.insert("selectGridColor", command.value()); + break; } #ifdef QUICK3D_PARTICLES_MODULE case View3DActionCommand::ShowParticleEmitter: @@ -2269,6 +2319,32 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c m_particleAnimationDriver->setSeekerPosition(static_cast(command).position()); break; #endif +#ifdef QUICK3D_MODULE + case View3DActionCommand::GetModelAtPos: { + // pick a Quick3DModel at view position + auto helper = qobject_cast(m_3dHelper); + if (!helper) + return; + + QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context()); + QObject *obj = qvariant_cast(editViewProp.read()); + QQuick3DViewport *editView = qobject_cast(obj); + + QPointF pos = command.value().toPointF(); + QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit(); + + // filter out picks of models created dynamically or inside components + QQuick3DModel *resolvedPick = qobject_cast(helper->resolvePick(hitModel)); + + if (resolvedPick) { + ServerNodeInstance instance = instanceForObject(resolvedPick); + nodeInstanceClient()->handlePuppetToCreatorCommand( + {PuppetToCreatorCommand::ModelAtPos, QVariant(instance.instanceId())}); + } + return; + } +#endif + default: break; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 291b2c3eecd..c85a2730c46 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -114,7 +114,7 @@ private: void createEditView3D(); void create3DPreviewView(); void setup3DEditView(const QList &instanceList, - const QHash &toolStates); + const CreateSceneCommand &command); void createCameraAndLightGizmos(const QList &instanceList) const; void add3DViewPorts(const QList &instanceList); void add3DScenes(const QList &instanceList); @@ -165,6 +165,7 @@ private: QSet m_view3Ds; QMultiHash m_3DSceneMap; // key: scene root, value: node QObject *m_active3DView = nullptr; + QList m_priorityView3DsToRender; QObject *m_active3DScene = nullptr; QSet m_parentChangedSet; QList m_completedComponentList; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 32f63a8cd66..3ccd6c60dce 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -405,6 +405,7 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) QQuickItemPrivate *pItem = QQuickItemPrivate::get(item); const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS"); + const bool smoothRendering = qEnvironmentVariableIsSet("QMLPUPPET_SMOOTH_RENDERING"); if (renderEffects) { if (parentEffectItem(item)) @@ -427,17 +428,20 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) ServerNodeInstance instance = instanceForObject(item); + const bool rootIs3DObject = rootIsRenderable3DObject(); + // Setting layer enabled to false messes up the bounding rect. // Therefore we calculate it upfront. QRectF renderBoundingRect; if (instance.isValid()) renderBoundingRect = instance.boundingRect(); - - else if (rootIsRenderable3DObject()) + else if (rootIs3DObject) renderBoundingRect = item->boundingRect(); else renderBoundingRect = ServerNodeInstance::effectAdjustedBoundingRect(item); + const int scaleFactor = (smoothRendering && !rootIs3DObject) ? 2 : 1; + // Hide immediate children that have instances and are QQuickItems so we get only // the parent item's content, as compositing is handled on creator side. QSet layerChildren; @@ -470,6 +474,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) // us to render it to a texture that we can grab to an image. QSGRenderContext *rc = QQuickWindowPrivate::get(m_viewData.window.data())->context; QSGLayer *layer = rc->sceneGraphContext()->createLayer(rc); + if (smoothRendering) + layer->setSamples(4); layer->setItem(pItem->itemNode()); layer->setRect(QRectF(renderBoundingRect.x(), @@ -478,8 +484,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) -renderBoundingRect.height())); const QSize minSize = rc->sceneGraphContext()->minimumFBOSize(); - layer->setSize(QSize(qMax(minSize.width(), int(renderBoundingRect.width())), - qMax(minSize.height(), int(renderBoundingRect.height())))); + layer->setSize(QSize(qMax(minSize.width(), int(renderBoundingRect.width() * scaleFactor)), + qMax(minSize.height(), int(renderBoundingRect.height() * scaleFactor)))); layer->scheduleUpdate(); if (layer->updateTexture()) @@ -489,6 +495,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) delete layer; layer = nullptr; + + renderImage.setDevicePixelRatio(scaleFactor); }); m_viewData.renderControl->render(); @@ -514,7 +522,6 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) if (!isLayerEnabled(pItem)) pItem->derefFromEffectItem(false); - #else Q_UNUSED(item) #endif diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 2ff23395761..59e7a4aa821 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -111,8 +111,6 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() } } - clearChangedPropertyList(); - if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { if (windowDirty) nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); @@ -134,13 +132,15 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() } if (rootIsRenderable3DObject() && rootNodeInstance().contentItem() - && DesignerSupport::isDirty(rootNodeInstance().contentItem(), - DesignerSupport::AllMask) + && !changedPropertyList().isEmpty() && nodeInstanceClient()->bytesToWrite() < 10000) { + Internal::QuickItemNodeInstance::updateDirtyNode(rootNodeInstance().contentItem()); nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); } + clearChangedPropertyList(); + inFunction = false; } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index 41d0015ce56..5b1f3171adb 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -504,12 +504,12 @@ QImage QuickItemNodeInstance::renderImage() const if (s_unifiedRenderPath) { renderImage = nodeInstanceServer()->grabWindow(); renderImage = renderImage.copy(renderBoundingRect.toRect()); + /* When grabbing an offscren window the device pixel ratio is 1 */ + renderImage.setDevicePixelRatio(1); } else { renderImage = nodeInstanceServer()->grabItem(quickItem()); } - /* When grabbing an offscren window the device pixel ratio is 1 */ - renderImage.setDevicePixelRatio(1); #endif return renderImage; diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index 130ec2aff68..e19b13fc0fb 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -59,6 +59,10 @@ Item { width: itemLibraryIconWidth // to be set in Qml context height: itemLibraryIconHeight // to be set in Qml context source: itemLibraryIconPath // to be set by model + + // Icons generated for components can change if the component is edited, + // so don't cache them locally at Image level. + cache: itemComponentSource === "" } Text { diff --git a/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml b/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml index 89f71e78d37..de4ea147c07 100644 --- a/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml +++ b/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml @@ -29,7 +29,7 @@ import QtQuick 2.15 QtObject { id: values - property string baseFont: "TitilliumWeb" + property string baseFont: "Titillium Web" property real scaleFactor: 1.0 property real checkBoxSize: Math.round(26 * values.scaleFactor) diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index ab061e4289c..0419b945b9c 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -128,7 +128,7 @@ Item { StudioControls.MenuSeparator {} StudioControls.MenuItem { - text: qsTr("New Material") + text: qsTr("Create New Material") onTriggered: materialBrowserModel.addNewMaterial() } @@ -169,7 +169,8 @@ Item { } Text { - text: qsTr("No materials yet.\nClick '+' above to start.") + text: qsTr("There are no materials in this project.
Select '+' to create one.") + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize horizontalAlignment: Text.AlignHCenter @@ -179,7 +180,8 @@ Item { } Text { - text: qsTr("Add QtQuick3D module using the Components view to enable the Material Browser."); + text: qsTr("To use Material Browser, first add the QtQuick3D module in the Components view."); + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize topPadding: 30 diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml index 4eeb120b27c..640383d4e18 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml @@ -72,9 +72,12 @@ Rectangle { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: (mouse) => { + onPressed: (mouse) => { materialBrowserModel.selectMaterial(index) - if (mouse.button === Qt.RightButton) + + if (mouse.button === Qt.LeftButton) + rootView.startDragMaterial(index, mapToGlobal(mouse.x, mouse.y)) + else if (mouse.button === Qt.RightButton) root.showContextMenu() } diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml index 80ec524e23e..a9e272b6d51 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml @@ -48,8 +48,9 @@ PropertyEditorPane { height: 150 Text { - text: hasQuick3DImport ? qsTr("No materials yet.\nClick '+' above to start.") - : qsTr("Add QtQuick3D module using the Components view to enable the Material Editor.") + text: hasQuick3DImport ? qsTr("There are no materials in this project.
Select '+' to create one.") + : qsTr("To use Material Editor, first add the QtQuick3D module in the Components view.") + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize horizontalAlignment: Text.AlignHCenter diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml index c610df94c5e..80a8d9abbe9 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml @@ -63,7 +63,7 @@ Rectangle { buttonSize: root.height enabled: hasQuick3DImport onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial) - tooltip: qsTr("Add a new material.") + tooltip: qsTr("Create new material.") } IconButton { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml index 54cf89cf255..208632d8c04 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml @@ -75,7 +75,7 @@ Section { + StudioTheme.Values.actionIndicatorWidth width: implicitWidth backendValue: backendValues.display - model: [ "IconOnly", "TextOnly", "TextBesideIcon" ] + model: [ "IconOnly", "TextOnly", "TextBesideIcon", "TextUnderIcon" ] scope: "AbstractButton" enabled: backendValue.isAvailable } @@ -140,6 +140,7 @@ Section { SecondColumnLayout { CheckBox { + id: autoRepeat text: backendValues.autoRepeat.valueToString implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth @@ -148,5 +149,63 @@ Section { ExpandingSpacer {} } + + PropertyLabel { + text: qsTr("Repeat delay") + tooltip: qsTr("Initial delay of auto-repetition in milliseconds.") + enabled: autoRepeat.checked + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 0 + backendValue: backendValues.autoRepeatDelay + enabled: autoRepeat.checked + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "ms" + elide: Text.ElideNone + enabled: autoRepeat.checked + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Repeat interval") + tooltip: qsTr("Interval of auto-repetition in milliseconds.") + enabled: autoRepeat.checked + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 0 + backendValue: backendValues.autoRepeatInterval + enabled: autoRepeat.checked + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "ms" + elide: Text.ElideNone + enabled: autoRepeat.checked + } + + ExpandingSpacer {} + } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml index 0a92222b578..6d025a77619 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml @@ -70,4 +70,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml index 6e57108f627..8f155958453 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml @@ -48,9 +48,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml index 80b27fabfdb..3280065a3e2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml @@ -47,9 +47,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml index 0f9e81c6969..3b79e7bc811 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml @@ -49,9 +49,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml index debeeeaecf1..3e04a71fee6 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml @@ -138,4 +138,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml new file mode 100644 index 00000000000..d692c7ae6e3 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import HelperWidgets 2.0 +import QtQuickDesignerTheme 1.0 +import StudioTheme 1.0 as StudioTheme + +Column { + anchors.left: parent.left + anchors.right: parent.right + + ControlSection {} + + FontSection {} + + PaddingSection {} +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml index 995997af65a..8e3fda088fa 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml @@ -67,7 +67,10 @@ Column { Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } - ControlLabel { text: "ms" } + ControlLabel { + text: "ms" + elide: Text.ElideNone + } ExpandingSpacer {} } @@ -76,9 +79,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml index e3fae4a024a..b1fc7b60319 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml @@ -194,4 +194,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml index 33b98e44814..201356811af 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml @@ -50,6 +50,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml index a8b5801fde1..5f811e08fda 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml @@ -73,4 +73,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml new file mode 100644 index 00000000000..a487223608b --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import HelperWidgets 2.0 +import StudioTheme 1.0 as StudioTheme + +Section { + id: root + + property bool blockedByContext: backendValues.display.enumeration === "TextOnly" + + caption: qsTr("Icon") + width: parent.width + + SectionLayout { + // We deliberately kept the "name" property out as it is only properly supported by linux + // based operating systems out of the box. + + PropertyLabel { + text: qsTr("Source") + blockedByTemplate: !backendValues.icon_source.isAvailable + enabled: !root.blockedByContext + } + + SecondColumnLayout { + UrlChooser { + backendValue: backendValues.icon_source + enabled: backendValues.icon_source.isAvailable && !root.blockedByContext + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Color") + blockedByTemplate: !backendValues.icon_color.isAvailable + enabled: !root.blockedByContext + } + + ColorEditor { + backendValue: backendValues.icon_color + supportGradient: false + enabled: backendValues.icon_color.isAvailable && !root.blockedByContext + } + + PropertyLabel { + text: qsTr("Size") + blockedByTemplate: !backendValues.icon_width.isAvailable + enabled: !root.blockedByContext + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.icon_width + maximumValue: 0xffff + minimumValue: 0 + decimals: 0 + enabled: backendValues.icon_width.isAvailable && !root.blockedByContext + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The width of the object + text: qsTr("W", "width") + tooltip: qsTr("Width") + enabled: backendValues.icon_width.isAvailable && !root.blockedByContext + } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.icon_height + maximumValue: 0xffff + minimumValue: 0 + decimals: 0 + enabled: backendValues.icon_height.isAvailable && !root.blockedByContext + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The height of the object + text: qsTr("H", "height") + tooltip: qsTr("Height") + enabled: backendValues.icon_height.isAvailable && !root.blockedByContext + } +/* + TODO QDS-4836 + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + LinkIndicator2D {} +*/ + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Cache") + tooltip: qsTr("Whether the icon should be cached.") + blockedByTemplate: !backendValues.icon_cache.isAvailable + enabled: !root.blockedByContext + } + + SecondColumnLayout { + CheckBox { + text: backendValues.icon_cache.valueToString + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.icon_cache + enabled: backendValues.icon_cache.isAvailable && !root.blockedByContext + } + + ExpandingSpacer {} + } + + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml index 17e35771fef..b7d838e62b6 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. @@ -35,8 +35,8 @@ ****************************************************************************/ import QtQuick 2.15 -import HelperWidgets 2.0 import QtQuick.Layouts 1.15 +import HelperWidgets 2.0 import StudioTheme 1.0 as StudioTheme Section { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml index 88f8dbf86b7..a3ab1a1a8aa 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml @@ -46,9 +46,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml index cda496c3d11..f951120b994 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml @@ -106,4 +106,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml index e3cac6ca29b..4b0745617fb 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml @@ -118,4 +118,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml index dde8aab73d1..e61b880e5fc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml @@ -48,6 +48,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml index 205df61e8bf..4acec20e119 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml @@ -129,4 +129,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml index 8c54760a8a6..7573c4a8496 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml @@ -44,9 +44,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml index 31e32eeed7a..341f6d73694 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml @@ -48,9 +48,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml index 430a7b49987..c3737bf6ebe 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml @@ -213,4 +213,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml index b3d316321cc..e2b38a3b04d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml @@ -98,9 +98,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml index a38ea1ce220..53f4effcc52 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml @@ -98,6 +98,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml index f3ff89f91ec..8b04f8c1a26 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml @@ -197,4 +197,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml index 01322a57ba2..83486e7f14b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml @@ -158,4 +158,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml index 3f8bb535cf5..7f70792e96f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml @@ -46,6 +46,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml index ec3156bd556..e888c6500bd 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml @@ -46,9 +46,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml index aab4f96a29e..f12353e6512 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml @@ -89,6 +89,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml index b5805ef74c9..8f5b4d00008 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml @@ -46,7 +46,11 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml index b8814131f0e..77487cf28bc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml @@ -44,9 +44,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml index ad67f2b0b8c..e58a8abf71e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml @@ -122,4 +122,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml index 8c54760a8a6..7573c4a8496 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml @@ -44,9 +44,13 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml index 445c3bc256b..3bd62e1acbf 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml @@ -73,6 +73,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml index 923f78e9c37..7e9e2ada89a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml @@ -46,9 +46,13 @@ Column { AbstractButtonSection {} - ControlSection { } + IconSection {} + + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml index 53345e711a5..34e74c87ae3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml @@ -70,4 +70,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml index 487cd148606..5769a040070 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml @@ -106,4 +106,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml index 7cded878a1d..1a17b828081 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml @@ -33,7 +33,7 @@ PropertyEditorPane { id: itemPane ComponentSection { - showState: majorVersion >= 6 + showState: majorQtQuickVersion >= 6 } Column { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 4b5f5caf4ac..2f087c3b299 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -36,6 +36,7 @@ StudioControls.ComboBox { property string fontFilter: "*.ttf *.otf" property bool showExtendedFunctionButton: true + hasActiveDrag: activeDragSuffix !== "" && root.fontFilter.includes(activeDragSuffix) labelColor: colorLogic.textColor editable: true @@ -47,16 +48,45 @@ StudioControls.ComboBox { filter: root.fontFilter } + DropArea { + id: dropArea + + anchors.fill: parent + + property string assetPath: "" + + onEntered: function(drag) { + dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0] + drag.accepted = root.hasActiveDrag + root.hasActiveHoverDrag = drag.accepted + } + + onExited: root.hasActiveHoverDrag = false + + onDropped: function(drop) { + drop.accepted = root.hasActiveHoverDrag + var fontLoader = root.createFontLoader("file:" + dropArea.assetPath) + if (fontLoader.status === FontLoader.Ready) { + root.backendValue.value = fontLoader.name + root.currentIndex = root.find(root.backendValue.value) + } + root.hasActiveHoverDrag = false + root.backendValue.commitDrop(dropArea.assetPath) + } + } + function createFontLoader(fontUrl) { return Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: "' + fontUrl + '"; }', root, "dynamicFontLoader") } function setupModel() { - var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] // default fonts + // default fonts + var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] - for (var i = 0; i < fileModel.fullPathModel.length; ++i) { // add custom fonts - var fontLoader = createFontLoader(fileModel.docPath + "/" + fileModel.fullPathModel[i]) + for (var i = 0; i < fileModel.model.length; ++i) { // add custom fonts + var fontLoader = root.createFontLoader(fileModel.docPath + "/" + + fileModel.model[i].relativeFilePath) familyNames.push(fontLoader.name) } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml index 2fc10b18554..dcd4733134a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml @@ -34,10 +34,10 @@ Rectangle { signal clicked() property alias icon: icon.text - property alias enabled: mouseArea.enabled property alias tooltip: toolTip.text property alias iconSize: icon.font.pixelSize + property bool enabled: true property int buttonSize: StudioTheme.Values.height property color normalColor: StudioTheme.Values.themeControlBackground property color hoverColor: StudioTheme.Values.themeControlBackgroundHover @@ -46,9 +46,10 @@ Rectangle { width: buttonSize height: buttonSize - color: mouseArea.pressed ? pressColor - : mouseArea.containsMouse ? hoverColor - : normalColor + color: !enabled ? normalColor + : mouseArea.pressed ? pressColor + : mouseArea.containsMouse ? hoverColor + : normalColor Behavior on color { ColorAnimation { @@ -71,7 +72,11 @@ Rectangle { anchors.fill: parent hoverEnabled: true - onClicked: root.clicked() + onClicked: { + // We need to keep mouse area enabled even when button is disabled to make tooltip work + if (root.enabled) + root.clicked() + } } ToolTip { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index f6766234d06..ecb4936bd7d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -44,6 +44,9 @@ Row { // by QtQuick3D to add built-in primitives to the model. property var defaultItems + // Current item + property string absoluteFilePath: "" + FileResourcesModel { id: fileModel modelNodeBackendProperty: modelNodeBackend @@ -60,6 +63,7 @@ Row { property ListModel listModel: ListModel {} + hasActiveDrag: activeDragSuffix !== "" && root.filter.includes(activeDragSuffix) implicitWidth: StudioTheme.Values.singleControlColumnWidth + StudioTheme.Values.actionIndicatorWidth width: implicitWidth @@ -69,26 +73,99 @@ Row { // when the combobox is closed by focusing on some other control. property int hoverIndex: -1 + DropArea { + id: dropArea + + anchors.fill: parent + + property string assetPath: "" + + onEntered: function(drag) { + dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0] + drag.accepted = comboBox.hasActiveDrag + comboBox.hasActiveHoverDrag = drag.accepted + } + + onExited: comboBox.hasActiveHoverDrag = false + + onDropped: function(drop) { + drop.accepted = comboBox.hasActiveHoverDrag + comboBox.editText = dropArea.assetPath + comboBox.accepted() + comboBox.hasActiveHoverDrag = false + root.backendValue.commitDrop(dropArea.assetPath) + } + } + ToolTip { id: toolTip visible: comboBox.hover && toolTip.text !== "" text: root.backendValue.valueToString delay: StudioTheme.Values.toolTipDelay - height: StudioTheme.Values.toolTipHeight + background: Rectangle { color: StudioTheme.Values.themeToolTipBackground border.color: StudioTheme.Values.themeToolTipOutline border.width: StudioTheme.Values.border } - contentItem: Text { - color: StudioTheme.Values.themeToolTipText - text: toolTip.text - verticalAlignment: Text.AlignVCenter + + contentItem: RowLayout { + spacing: 10 + + Item { + visible: thumbnail.status === Image.Ready + Layout.preferredWidth: 100 + Layout.preferredHeight: 100 + + Image { + id: checker + visible: !root.isMesh(root.absoluteFilePath) + anchors.fill: parent + fillMode: Image.Tile + source: "images/checkers.png" + } + + Image { + id: thumbnail + asynchronous: true + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: { + if (root.isBuiltInPrimitive(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + + root.absoluteFilePath.substring(1, root.absoluteFilePath.length) + + ".builtin" + + if (fileModel.isLocal(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + root.absoluteFilePath + + return root.absoluteFilePath + } + } + } + + ColumnLayout { + Text { + text: root.fileName(toolTip.text) + color: StudioTheme.Values.themeToolTipText + font: toolTip.font + } + + Text { + Layout.fillWidth: true + text: root.isBuiltInPrimitive(toolTip.text) ? qsTr("Built-in primitive") + : toolTip.text + font: toolTip.font + color: StudioTheme.Values.themeToolTipText + wrapMode: Text.WordWrap + } + } } } delegate: ItemDelegate { - required property string fullPath + required property string absoluteFilePath + required property string relativeFilePath required property string name required property int group required property int index @@ -150,20 +227,66 @@ Row { } ToolTip { - id: itemToolTip - visible: delegateRoot.hovered && comboBox.highlightedIndex === index - text: fullPath + id: delegateToolTip + visible: delegateRoot.hovered + text: delegateRoot.relativeFilePath delay: StudioTheme.Values.toolTipDelay - height: StudioTheme.Values.toolTipHeight + background: Rectangle { color: StudioTheme.Values.themeToolTipBackground border.color: StudioTheme.Values.themeToolTipOutline border.width: StudioTheme.Values.border } - contentItem: Text { - color: StudioTheme.Values.themeToolTipText - text: itemToolTip.text - verticalAlignment: Text.AlignVCenter + + contentItem: RowLayout { + spacing: 10 + + Item { + visible: delegateThumbnail.status === Image.Ready + Layout.preferredWidth: 100 + Layout.preferredHeight: 100 + + Image { + id: delegateChecker + visible: !root.isMesh(delegateRoot.absoluteFilePath) + anchors.fill: parent + fillMode: Image.Tile + source: "images/checkers.png" + } + + Image { + id: delegateThumbnail + asynchronous: true + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: { + if (root.isBuiltInPrimitive(delegateRoot.name)) + return "image://qmldesigner_thumbnails/" + + delegateRoot.name.substring(1, delegateRoot.name.length) + + ".builtin" + + return "image://qmldesigner_thumbnails/" + delegateRoot.absoluteFilePath + } + } + } + + ColumnLayout { + Text { + text: delegateRoot.name + color: StudioTheme.Values.themeToolTipText + font: delegateToolTip.font + } + + Text { + Layout.fillWidth: true + text: root.isBuiltInPrimitive(delegateToolTip.text) + ? qsTr("Built-in primitive") + : delegateToolTip.text + font: delegateToolTip.font + color: StudioTheme.Values.themeToolTipText + wrapMode: Text.WordWrap + } + } } } } @@ -197,8 +320,9 @@ Row { if (root.backendValue.isBound) { comboBox.textValue = root.backendValue.expression } else { - var fullPath = root.backendValue.valueToString - comboBox.textValue = fullPath.substr(fullPath.lastIndexOf('/') + 1) + // Can be absolute or relative file path + var filePath = root.backendValue.valueToString + comboBox.textValue = filePath.substr(filePath.lastIndexOf('/') + 1) } comboBox.setCurrentText(comboBox.textValue) @@ -230,9 +354,13 @@ Row { // Check if value set by user matches with a name in the model then pick the full path let index = comboBox.find(inputValue) if (index !== -1) - inputValue = comboBox.items.get(index).model.fullPath + inputValue = comboBox.items.get(index).model.relativeFilePath root.backendValue.value = inputValue + + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + comboBox.dirty = false } @@ -252,11 +380,14 @@ Row { let inputValue = comboBox.editText if (index >= 0) - inputValue = comboBox.items.get(index).model.fullPath + inputValue = comboBox.items.get(index).model.relativeFilePath if (root.backendValue.value !== inputValue) root.backendValue.value = inputValue + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + comboBox.dirty = false } @@ -273,6 +404,23 @@ Row { } } + function isBuiltInPrimitive(value) { + return value.startsWith('#') + } + + function isMesh(value) { + return root.isBuiltInPrimitive(value) + || root.hasFileExtension(root.fileName(value), "mesh") + } + + function hasFileExtension(fileName, extension) { + return fileName.split('.').pop() === extension + } + + function fileName(filePath) { + return filePath.substr(filePath.lastIndexOf('/') + 1) + } + function createModel() { // Build the combobox model comboBox.listModel.clear() @@ -284,17 +432,22 @@ Row { if (root.defaultItems !== undefined) { for (var i = 0; i < root.defaultItems.length; ++i) { comboBox.listModel.append({ - fullPath: root.defaultItems[i], + absoluteFilePath: "", + relativeFilePath: root.defaultItems[i], name: root.defaultItems[i], group: 0 }) } } - for (var j = 0; j < fileModel.fullPathModel.length; ++j) { + const myModel = fileModel.model + for (var j = 0; j < myModel.length; ++j) { + let item = myModel[j] + comboBox.listModel.append({ - fullPath: fileModel.fullPathModel[j], - name: fileModel.fileNameModel[j], + absoluteFilePath: item.absoluteFilePath, + relativeFilePath: item.relativeFilePath, + name: item.fileName, group: 1 }) } @@ -304,7 +457,7 @@ Row { Connections { target: fileModel - function onFullPathModelChanged() { + function onModelChanged() { root.createModel() comboBox.setCurrentText(comboBox.textValue) } @@ -315,6 +468,9 @@ Row { Component.onCompleted: { root.createModel() comboBox.updateTextValue() + + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) } function indexOf(model, criteria) { @@ -333,7 +489,7 @@ Row { if (comboBox.popup.opened && !root.backendValue.isBound) { var index = root.indexOf(comboBox.items, function(item) { - return item.fullPath === root.backendValue.value + return item.relativeFilePath === root.backendValue.value }) if (index !== -1) { @@ -352,8 +508,10 @@ Row { iconColor: root.textColor onClicked: { fileModel.openFileDialog() - if (fileModel.fileName !== "") + if (fileModel.fileName !== "") { root.backendValue.value = fileModel.fileName + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + } } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml index 577257de709..c594220d5e0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml @@ -136,7 +136,7 @@ T.AbstractButton { when: myButton.globalHover && !myButton.hover && !myButton.pressed && myButton.enabled PropertyChanges { target: buttonBackground - color: StudioTheme.Values.themeControlBackgroundGlobalHover + color: StudioTheme.Values.themeControlBackground } }, State { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml index 2d3bb74c3f7..5af0f5fe6e9 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml @@ -37,6 +37,9 @@ Rectangle { property bool pressed: checkIndicatorMouseArea.containsPress property bool checked: false + property bool hasActiveDrag: myControl.hasActiveDrag ?? false + property bool hasActiveHoverDrag: myControl.hasActiveHoverDrag ?? false + color: StudioTheme.Values.themeControlBackground border.width: 0 @@ -79,12 +82,20 @@ Rectangle { name: "default" when: myControl.enabled && checkIndicator.enabled && !myControl.edit && !checkIndicator.hover && !myControl.hover && !myControl.drag - && !checkIndicator.checked + && !checkIndicator.checked && !checkIndicator.hasActiveDrag PropertyChanges { target: checkIndicator color: StudioTheme.Values.themeControlBackground } }, + State { + name: "dragHover" + when: myControl.enabled && checkIndicator.hasActiveHoverDrag + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: myControl.enabled && checkIndicator.enabled && !myControl.drag diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index 70cbdf000ec..f57a1c404e3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -50,9 +50,6 @@ T.ComboBox { property alias textInput: comboBoxInput - property int borderWidth: myComboBox.hasActiveHoverDrag ? StudioTheme.Values.borderHover - : StudioTheme.Values.border - signal compressedActivated(int index, int reason) enum ActivatedReason { EditingFinished, Other } @@ -61,7 +58,7 @@ T.ComboBox { height: StudioTheme.Values.defaultControlHeight leftPadding: actionIndicator.width - rightPadding: popupIndicator.width + myComboBox.borderWidth + rightPadding: popupIndicator.width + StudioTheme.Values.border font.pixelSize: StudioTheme.Values.myFontSize wheelEnabled: false @@ -91,7 +88,6 @@ T.ComboBox { myControl: myComboBox text: myComboBox.editText - borderWidth: myComboBox.borderWidth onEditingFinished: { comboBoxInput.deselect() @@ -113,16 +109,16 @@ T.ComboBox { myControl: myComboBox myPopup: myComboBox.popup x: comboBoxInput.x + comboBoxInput.width - y: myComboBox.borderWidth - width: StudioTheme.Values.checkIndicatorWidth - myComboBox.borderWidth - height: StudioTheme.Values.checkIndicatorHeight - myComboBox.borderWidth * 2 + y: StudioTheme.Values.border + width: StudioTheme.Values.checkIndicatorWidth - StudioTheme.Values.border + height: StudioTheme.Values.checkIndicatorHeight - StudioTheme.Values.border * 2 } background: Rectangle { id: comboBoxBackground color: StudioTheme.Values.themeControlBackground border.color: StudioTheme.Values.themeControlOutline - border.width: myComboBox.borderWidth + border.width: StudioTheme.Values.border x: actionIndicator.width width: myComboBox.width - actionIndicator.width height: myComboBox.height @@ -149,7 +145,7 @@ T.ComboBox { width: comboBoxPopup.width - comboBoxPopup.leftPadding - comboBoxPopup.rightPadding - (comboBoxPopupScrollBar.visible ? comboBoxPopupScrollBar.contentItem.implicitWidth + 2 : 0) // TODO Magic number - height: StudioTheme.Values.height - 2 * myComboBox.borderWidth + height: StudioTheme.Values.height - 2 * StudioTheme.Values.border padding: 0 enabled: model.enabled === undefined ? true : model.enabled @@ -203,9 +199,9 @@ T.ComboBox { popup: T.Popup { id: comboBoxPopup - x: actionIndicator.width + myComboBox.borderWidth + x: actionIndicator.width + StudioTheme.Values.border y: myComboBox.height - width: myComboBox.width - actionIndicator.width - myComboBox.borderWidth * 2 + width: myComboBox.width - actionIndicator.width - StudioTheme.Values.border * 2 // TODO Setting the height on the popup solved the problem with the popup of height 0, // but it has the problem that it sometimes extend over the border of the actual window // and is then cut off. @@ -213,7 +209,7 @@ T.ComboBox { + comboBoxPopup.bottomPadding, myComboBox.Window.height - topMargin - bottomMargin, StudioTheme.Values.maxComboBoxPopupHeight) - padding: myComboBox.borderWidth + padding: StudioTheme.Values.border margins: 0 // If not defined margin will be -1 closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside @@ -245,7 +241,7 @@ T.ComboBox { State { name: "default" when: myComboBox.enabled && !myComboBox.hover && !myComboBox.edit && !myComboBox.open - && !myComboBox.activeFocus + && !myComboBox.activeFocus && !myComboBox.hasActiveDrag PropertyChanges { target: myComboBox wheelEnabled: false @@ -257,9 +253,23 @@ T.ComboBox { PropertyChanges { target: comboBoxBackground color: StudioTheme.Values.themeControlBackground - border.color: myComboBox.hasActiveDrag ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeControlOutline - border.width: myComboBox.borderWidth + } + }, + State { + name: "acceptsDrag" + when: myComboBox.enabled && myComboBox.hasActiveDrag && !myComboBox.hasActiveHoverDrag + PropertyChanges { + target: comboBoxBackground + border.color: StudioTheme.Values.themeControlOutlineInteraction + } + }, + State { + name: "dragHover" + when: myComboBox.enabled && myComboBox.hasActiveHoverDrag + PropertyChanges { + target: comboBoxBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeControlOutlineInteraction } }, // This state is intended for ComboBoxes which aren't editable, but have focus e.g. via diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml index c6b91dc1ad0..e2596876987 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml @@ -34,7 +34,6 @@ TextInput { property bool edit: textInput.activeFocus property bool hover: mouseArea.containsMouse && textInput.enabled - property int borderWidth: StudioTheme.Values.border z: 2 font: myControl.font @@ -56,11 +55,11 @@ TextInput { Rectangle { id: textInputBackground - x: textInput.borderWidth - y: textInput.borderWidth + x: StudioTheme.Values.border + y: StudioTheme.Values.border z: -1 width: textInput.width - height: StudioTheme.Values.height - textInput.borderWidth * 2 + height: StudioTheme.Values.height - StudioTheme.Values.border * 2 color: StudioTheme.Values.themeControlBackground border.width: 0 } @@ -94,7 +93,7 @@ TextInput { State { name: "default" when: myControl.enabled && !textInput.edit && !textInput.hover && !myControl.hover - && !myControl.open + && !myControl.open && !myControl.hasActiveDrag PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackground @@ -105,6 +104,14 @@ TextInput { acceptedButtons: Qt.LeftButton } }, + State { + name: "dragHover" + when: myControl.enabled && myControl.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: myControl.hover && !textInput.hover && !textInput.edit && !myControl.open diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml index 30142652ab3..1c2fa82c14d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml @@ -65,7 +65,8 @@ Item { property alias actionIndicator: actionIndicator // This property is used to indicate the global hover state - property bool hover: actionIndicator.hover || textInput.hover || checkIndicator.hover + property bool hover: (actionIndicator.hover || textInput.hover || checkIndicator.hover) + && root.enabled property alias edit: textInput.edit property alias open: popup.visible @@ -87,6 +88,9 @@ Item { property alias popupScrollBar: popupScrollBar property alias popupMouseArea: popupMouseArea + property bool hasActiveDrag: false // an item that can be dropped here is being dragged + property bool hasActiveHoverDrag: false // an item that can be dropped her is being hovered on top + width: StudioTheme.Values.defaultControlWidth height: StudioTheme.Values.defaultControlHeight implicitHeight: StudioTheme.Values.defaultControlHeight @@ -468,9 +472,11 @@ Item { State { name: "default" when: root.enabled && !textInput.edit && !root.hover && !root.open + && !root.hasActiveDrag PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline } PropertyChanges { target: textInputMouseArea @@ -478,6 +484,23 @@ Item { acceptedButtons: Qt.LeftButton } }, + State { + name: "acceptsDrag" + when: root.enabled && root.hasActiveDrag && !root.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + border.color: StudioTheme.Values.themeInteraction + } + }, + State { + name: "dragHover" + when: root.enabled && root.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeInteraction + } + }, State { name: "globalHover" when: root.hover && !textInput.hover && !textInput.edit && !root.open @@ -514,6 +537,7 @@ Item { PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackgroundDisabled + border.color: StudioTheme.Values.themeControlOutlineDisabled } PropertyChanges { target: textInput @@ -585,12 +609,20 @@ Item { name: "default" when: root.enabled && checkIndicator.enabled && !root.edit && !checkIndicator.hover && !root.hover - && !checkIndicator.checked + && !checkIndicator.checked && !root.hasActiveHoverDrag PropertyChanges { target: checkIndicator color: StudioTheme.Values.themeControlBackground } }, + State { + name: "dragHover" + when: root.enabled && root.hasActiveHoverDrag + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: root.enabled && checkIndicator.enabled diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index 5a3e99d4590..cefd1d7d866 100644 Binary files a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf and b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf differ diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml index a539a0aeb25..93682263778 100644 --- a/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml +++ b/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml @@ -165,7 +165,7 @@ VersionData { } QtQuick.Controls.AbstractButton { - bannedProperties: ["display", "autoExclusive"] + bannedProperties: ["display", "autoExclusive", "icon"] } QtQuick.Controls.ProgressBar { diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl new file mode 100644 index 00000000000..7bd94416c44 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +%{FormClass} { + button.onClicked: console.log("Button Pressed") +} diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl new file mode 100644 index 00000000000..1fcbbe97566 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl @@ -0,0 +1,33 @@ +/* +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 +@if %{UseQtQuickControls2} +import QtQuick.Controls 2.15 +@endif +@if %{UseImport} +import %{ApplicationImport} +@endif + +%{RootItem} { +@if %{UseImport} + width: Constants.width + height: Constants.height +@else + width: 1024 + height: 768 +@endif + + property alias button: button + + Button { + id: button + x: 64 + y: 64 + text: qsTr("Button") + } +} diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png new file mode 100644 index 00000000000..473a8430fe5 Binary files /dev/null and b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png differ diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png new file mode 100644 index 00000000000..9cf67e875bd Binary files /dev/null and b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png differ diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json new file mode 100644 index 00000000000..26c628f4b31 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json @@ -0,0 +1,132 @@ +{ + "version": 1, + "supportedProjectTypes": [ ], + "id": "Q.QtStudio.QmlUIForm.2", + "category": "B.StudioQtQuickFiles", + "trDescription": "Creates a UI file (.ui.qml) along with a matching QML file for implementation purposes.", + "trDisplayName": "QtQuick UI Form", + "trDisplayCategory": "Qt Quick Files", + "icon": "file_ui.png", + "platformIndependent": true, + + "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", + "options" : [ + { "key": "QmlFile", "value": "%{Class}.%{JS: Util.preferredSuffix('text/x-qml')}" }, + { "key": "UiFile", "value": "%{FormClass}.%{JS: Util.preferredSuffix('application/x-qt.ui+qml')}" }, + { "key": "ApplicationImport", "value": "%{QmlProjectName} 1.0" }, + { "key": "RootItem", "value": "%{JS: %{RootItemCB}.RootItem}" }, + { "key": "UseImportDefault", "value": "%{JS: false}" }, + { "key": "UseQtQuickControls2Default", "value": "%{JS: true}" } + ], + "pages" : + [ + { + "trDisplayName": "Define Class", + "trShortTitle": "Details", + "typeId": "Fields", + "data" : + [ + { + "name": "Class", + "trDisplayName": "Component name:", + "mandatory": true, + "type": "LineEdit", + "data": { + "validator": "(?:[A-Z_][a-zA-Z_0-9]*|)", + "fixup": "%{JS: '%{INPUT}'.charAt(0).toUpperCase() + '%{INPUT}'.slice(1) }" + } + }, + { + "name": "Sp1", + "type": "Spacer", + "data": { "factor": 2 } + }, + { + "name": "FormClass", + "trDisplayName": "Component form name:", + "mandatory": true, + "type": "LineEdit", + "data": { + "validator": "(?:[A-Z_][a-zA-Z_0-9]*|)", + "fixup": "%{JS: '%{INPUT}'.charAt(0).toUpperCase() + '%{INPUT}'.slice(1) }", + "trText": "%{Class}Form" + } + }, + { + "name": "TargetPath", + "type": "PathChooser", + "trDisplayName": "Path:", + "mandatory": true, + "data": + { + "kind": "directory", + "basePath": "%{InitialPath}", + "path": "%{InitialPath}" + } + }, + { + "name": "RootItemCB", + "trDisplayName": "Root Item:", + "type": "ComboBox", + "data": + { + "index": 0, + "items": + [ + { + "trKey": "Item", + "value": + "({ + 'RootItem': 'Item' + })" + }, + { + "trKey": "Rectangle", + "value": + "({ + 'RootItem': 'Rectangle' + })" + } + ] + } + }, + { + "name": "UseImport", + "trDisplayName": "Use Application Import", + "type": "CheckBox", + "data": + { + "checked": "%{UseImportDefault}" + } + }, + { + "name": "UseQtQuickControls2", + "trDisplayName": "Use QtQuick Controls 2", + "type": "CheckBox", + "data": + { + "checked": "%{UseQtQuickControls2Default}" + } + } + ] + } + ], + "generators" : + [ + { + "typeId": "File", + "data": [ + { + "source": "file.qml.tpl", + "target": "%{TargetPath}/%{QmlFile}", + "openInEditor": true + }, + { + "source": "fileForm.ui.qml.tpl", + "target": "%{TargetPath}/%{UiFile}", + "openInEditor": true + } + ] + } + ] +} diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl index 338621b72e0..843185a029f 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl @@ -16,12 +16,6 @@ Rectangle { color: Constants.backgroundColor - Text { - text: qsTr("Hello %{ProjectName}") - anchors.centerIn: parent - font.family: Constants.font.family - } - View3D { id: view3D anchors.fill: parent @@ -63,4 +57,12 @@ Rectangle { diffuseColor: "#4aee45" } } + + Text { + text: qsTr("Hello %{ProjectName}") + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 100 + font.family: Constants.font.family + } } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl index 3d2490e8d9c..6b2195d6d1c 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -90,7 +90,7 @@ Project { /* Required for deployment */ targetDirectory: "/opt/%{ProjectName}" - qdsVersion: "3.4" + qdsVersion: "3.5" quickVersion: "%{QtQuickVersion}" diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index 5e72d6660e3..96e6a87b8ac 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -93,12 +93,12 @@ void Database::activateLogging() void Database::open(LockingMode lockingMode) { m_databaseBackend.open(m_databaseFilePath, m_openMode); - m_databaseBackend.setLockingMode(lockingMode); - m_databaseBackend.setJournalMode(m_journalMode); if (m_busyTimeout > 0ms) m_databaseBackend.setBusyTimeout(m_busyTimeout); else m_databaseBackend.registerBusyHandler(); + m_databaseBackend.setLockingMode(lockingMode); + m_databaseBackend.setJournalMode(m_journalMode); registerTransactionStatements(); m_isOpen = true; } diff --git a/src/libs/utils/deviceshell.h b/src/libs/utils/deviceshell.h index d25746ddf12..5f285103c86 100644 --- a/src/libs/utils/deviceshell.h +++ b/src/libs/utils/deviceshell.h @@ -64,6 +64,8 @@ public: DeviceShell(); virtual ~DeviceShell(); + bool start(); + bool runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); RunResult outputForRunInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); @@ -76,7 +78,6 @@ protected: virtual void startupFailed(const CommandLine &cmdLine); RunResult run(const CommandLine &cmd, const QByteArray &stdInData = {}); - bool start(); void close(); private: diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 63c3ee7c7b0..c4942aee3ff 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -336,7 +336,7 @@ void AndroidConfig::parseDependenciesJson() if (HostOsInfo::isWindowsHost()) appendEssentialsFromArray(commonEssentials[WindowsOsKey].toArray()); - if (HostOsInfo::isMacHost()) + else if (HostOsInfo::isMacHost()) appendEssentialsFromArray(commonEssentials[macOsKey].toArray()); else appendEssentialsFromArray(commonEssentials[LinuxOsKey].toArray()); diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index fc8dd9f41ca..fa57b05c44d 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -28,6 +28,7 @@ #include "androidconfigurations.h" #include "androidmanager.h" +#include > #include #include @@ -95,43 +96,7 @@ bool AndroidQtVersion::supportsMultipleQtAbis() const Abis AndroidQtVersion::detectQtAbis() const { - auto androidAbi2Abi = [](const QString &androidAbi) { - if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A) { - return Abi{Abi::Architecture::ArmArchitecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 64, androidAbi}; - } else if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A) { - return Abi{Abi::Architecture::ArmArchitecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 32, androidAbi}; - } else if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_X86_64) { - return Abi{Abi::Architecture::X86Architecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 64, androidAbi}; - } else if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_X86) { - return Abi{Abi::Architecture::X86Architecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 32, androidAbi}; - } else { - return Abi{Abi::Architecture::UnknownArchitecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 0, androidAbi}; - } - }; - Abis abis; - for (const auto &abi : androidAbis()) - abis << androidAbi2Abi(abi); - return abis; + return Utils::transform(androidAbis(), &AndroidManager::androidAbi2Abi); } void AndroidQtVersion::addToEnvironment(const Kit *k, Utils::Environment &env) const diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp index bc6d2757dfa..101a80f5317 100644 --- a/src/plugins/baremetal/iarewtoolchain.cpp +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -347,10 +347,10 @@ ToolChain::BuiltInHeaderPathsRunner IarToolChain::createBuiltInHeaderPathsRunner HeaderPathsCache headerPaths = headerPathsCache(); return [env, compiler, headerPaths, languageId](const QStringList &flags, - const QString &fileName, + const FilePath &sysRoot, const QString &) { Q_UNUSED(flags) - Q_UNUSED(fileName) + Q_UNUSED(sysRoot) const HeaderPaths paths = dumpHeaderPaths(compiler, languageId, env); headerPaths->insert({}, paths); diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index 8b1d9683262..44e8737ac32 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -473,9 +473,9 @@ ToolChain::BuiltInHeaderPathsRunner KeilToolChain::createBuiltInHeaderPathsRunne const HeaderPathsCache headerPaths = headerPathsCache(); return [compiler, - headerPaths](const QStringList &flags, const QString &fileName, const QString &) { + headerPaths](const QStringList &flags, const FilePath &sysRoot, const QString &) { Q_UNUSED(flags) - Q_UNUSED(fileName) + Q_UNUSED(sysRoot) const HeaderPaths paths = dumpHeaderPaths(compiler); headerPaths->insert({}, paths); diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp index bccd5a4c19d..9ed380f5c80 100644 --- a/src/plugins/baremetal/sdcctoolchain.cpp +++ b/src/plugins/baremetal/sdcctoolchain.cpp @@ -258,7 +258,7 @@ ToolChain::BuiltInHeaderPathsRunner SdccToolChain::createBuiltInHeaderPathsRunne const FilePath compiler = compilerCommand(); const Abi abi = targetAbi(); - return [env, compiler, abi](const QStringList &, const QString &, const QString &) { + return [env, compiler, abi](const QStringList &, const FilePath &, const QString &) { return dumpHeaderPaths(compiler, env, abi); }; } diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index b9ee78b50ef..22b55170a6f 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -594,7 +594,7 @@ Utils::Text::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBl const QByteArray buffer = m_doc->toPlainText().toUtf8(); ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; - if (formatCodeInsteadOfIndent() + if (formatWhileTyping() && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition) && (typedChar == ';' || typedChar == '}')) { // Format before current position only in case the cursor is inside the indented block. diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index bcfd4ca4a47..0b96451aca0 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -72,6 +72,7 @@ public: protected: virtual bool formatCodeInsteadOfIndent() const { return false; } + virtual bool formatWhileTyping() const { return false; } virtual int lastSaveRevision() const { return 0; } private: diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index ddf0415ef49..e3e7629065b 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -85,6 +85,7 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(TextEditor::ICodeStylePreferenc initChecksAndPreview(!codeStyle->isReadOnly()); initOverrideCheckBox(); + initCheckBoxes(); initIndentationOrFormattingCombobox(); showOrHideWidgets(); @@ -128,6 +129,45 @@ void ClangFormatConfigWidget::initChecksAndPreview(bool enabled) m_preview->textDocument()->indenter()->setFileName(fileName); } +void ClangFormatConfigWidget::initCheckBoxes() +{ + if (m_project) { + m_ui->formatOnSave->hide(); + m_ui->formatWhileTyping->hide(); + return; + } + + m_ui->formatOnSave->show(); + m_ui->formatWhileTyping->show(); + + auto setEnableCheckBoxes = [this](int index) { + bool isFormatting = index == static_cast(ClangFormatSettings::Mode::Formatting); + + m_ui->formatOnSave->setEnabled(isFormatting); + m_ui->formatWhileTyping->setEnabled(isFormatting); + }; + setEnableCheckBoxes(m_ui->indentingOrFormatting->currentIndex()); + connect(m_ui->indentingOrFormatting, QOverload::of(&QComboBox::currentIndexChanged), + this, setEnableCheckBoxes); + + m_ui->formatOnSave->setChecked(ClangFormatSettings::instance().formatOnSave()); + m_ui->formatWhileTyping->setChecked(ClangFormatSettings::instance().formatWhileTyping()); + + connect(m_ui->formatOnSave, &QCheckBox::toggled, + this, [](bool checked) { + ClangFormatSettings &settings = ClangFormatSettings::instance(); + settings.setFormatOnSave(checked); + settings.write(); + }); + + connect(m_ui->formatWhileTyping, &QCheckBox::toggled, + this, [](bool checked) { + ClangFormatSettings &settings = ClangFormatSettings::instance(); + settings.setFormatWhileTyping(checked); + settings.write(); + }); +} + void ClangFormatConfigWidget::initOverrideCheckBox() { if (m_project) { @@ -190,7 +230,9 @@ void ClangFormatConfigWidget::initIndentationOrFormattingCombobox() m_ui->indentingOrFormatting->setCurrentIndex( static_cast(ClangFormatSettings::instance().mode())); - m_ui->indentingOrFormatting->show(); + const bool isGlobal = !m_project; + m_ui->indentingOrFormatting->setVisible(isGlobal); + m_ui->formattingModeLabel->setVisible(isGlobal); connect(m_ui->indentingOrFormatting, QOverload::of(&QComboBox::currentIndexChanged), this, [](int index) { @@ -219,6 +261,7 @@ void ClangFormatConfigWidget::showOrHideWidgets() if (!m_ui->overrideDefault->isChecked() && m_project) { // Show the fallback configuration only globally. + m_ui->fallbackConfig->hide(); m_checksScrollArea->hide(); m_preview->hide(); m_ui->verticalLayout->addStretch(1); @@ -226,6 +269,7 @@ void ClangFormatConfigWidget::showOrHideWidgets() } createStyleFileIfNeeded(!m_project); + m_ui->fallbackConfig->show(); m_checksScrollArea->show(); m_preview->show(); diff --git a/src/plugins/clangformat/clangformatconfigwidget.h b/src/plugins/clangformat/clangformatconfigwidget.h index 52a5a94bc18..3b6f2aa1634 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.h +++ b/src/plugins/clangformat/clangformatconfigwidget.h @@ -65,6 +65,7 @@ private: void showOrHideWidgets(); void initChecksAndPreview(bool enabled); void initOverrideCheckBox(); + void initCheckBoxes(); void connectChecks(); void fillTable(); diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui index 814f558ca8a..a0a042c273e 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.ui +++ b/src/plugins/clangformat/clangformatconfigwidget.ui @@ -27,7 +27,7 @@ 8 - + @@ -39,7 +39,7 @@ - + Qt::Horizontal @@ -53,6 +53,20 @@ + + + + Format while typing + + + + + + + Format edited code on file save + + + diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h index 74e84efa170..cb201665da9 100644 --- a/src/plugins/clangformat/clangformatconstants.h +++ b/src/plugins/clangformat/clangformatconstants.h @@ -32,6 +32,8 @@ static const char SETTINGS_FILE_ALT_NAME[] = "_clang-format"; static const char SAMPLE_FILE_NAME[] = "test.cpp"; static const char SETTINGS_ID[] = "ClangFormat"; static const char OVERRIDE_FILE_ID[] = "ClangFormat.OverrideFile"; +static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; +static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; static const char MODE_ID[] = "ClangFormat.Mode"; static const char OPEN_CURRENT_CONFIG_ID[] = "ClangFormat.OpenCurrentConfig"; } // namespace Constants diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 6f7bb32ca8e..4d7273024ec 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -114,7 +114,13 @@ int ClangFormatIndenter::lastSaveRevision() const bool ClangFormatIndenter::formatOnSave() const { - return !isBeautifierOnSaveActivated() && formatCodeInsteadOfIndent(); + return ClangFormatSettings::instance().formatOnSave() && !isBeautifierOnSaveActivated() + && formatCodeInsteadOfIndent(); +} + +bool ClangFormatIndenter::formatWhileTyping() const +{ + return ClangFormatSettings::instance().formatWhileTyping() && formatCodeInsteadOfIndent(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatindenter.h b/src/plugins/clangformat/clangformatindenter.h index 83f0b912f68..9e1a65fb3d4 100644 --- a/src/plugins/clangformat/clangformatindenter.h +++ b/src/plugins/clangformat/clangformatindenter.h @@ -40,6 +40,7 @@ public: private: bool formatCodeInsteadOfIndent() const override; + bool formatWhileTyping() const override; int lastSaveRevision() const override; }; diff --git a/src/plugins/clangformat/clangformatsettings.cpp b/src/plugins/clangformat/clangformatsettings.cpp index 2326f7b8ce1..7ab17c00418 100644 --- a/src/plugins/clangformat/clangformatsettings.cpp +++ b/src/plugins/clangformat/clangformatsettings.cpp @@ -30,8 +30,6 @@ namespace ClangFormat { static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent"; -static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; -static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; ClangFormatSettings &ClangFormatSettings::instance() { @@ -45,15 +43,15 @@ ClangFormatSettings::ClangFormatSettings() settings->beginGroup(QLatin1String(Constants::SETTINGS_ID)); m_overrideDefaultFile = settings->value(QLatin1String(Constants::OVERRIDE_FILE_ID), false) .toBool(); + m_formatWhileTyping = settings->value(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), false) + .toBool(); + m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false) + .toBool(); // Convert old settings to new ones. New settings were added to QtC 8.0 bool isOldFormattingOn - = settings->value(QLatin1String(FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool() - || settings->value(QLatin1String(FORMAT_CODE_ON_SAVE_ID), false).toBool(); - + = settings->value(QLatin1String(FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool(); Core::ICore::settings()->remove(QLatin1String(FORMAT_CODE_INSTEAD_OF_INDENT_ID)); - Core::ICore::settings()->remove(QLatin1String(FORMAT_CODE_ON_SAVE_ID)); - Core::ICore::settings()->remove(QLatin1String(FORMAT_WHILE_TYPING_ID)); if (isOldFormattingOn) { settings->setValue(QLatin1String(Constants::MODE_ID), @@ -72,6 +70,8 @@ void ClangFormatSettings::write() const QSettings *settings = Core::ICore::settings(); settings->beginGroup(QLatin1String(Constants::SETTINGS_ID)); settings->setValue(QLatin1String(Constants::OVERRIDE_FILE_ID), m_overrideDefaultFile); + settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping); + settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave); settings->setValue(QLatin1String(Constants::MODE_ID), static_cast(m_mode)); settings->endGroup(); } @@ -86,6 +86,26 @@ bool ClangFormatSettings::overrideDefaultFile() const return m_overrideDefaultFile; } +void ClangFormatSettings::setFormatWhileTyping(bool enable) +{ + m_formatWhileTyping = enable; +} + +bool ClangFormatSettings::formatWhileTyping() const +{ + return m_formatWhileTyping; +} + +void ClangFormatSettings::setFormatOnSave(bool enable) +{ + m_formatOnSave = enable; +} + +bool ClangFormatSettings::formatOnSave() const +{ + return m_formatOnSave; +} + void ClangFormatSettings::setMode(Mode mode) { m_mode = mode; diff --git a/src/plugins/clangformat/clangformatsettings.h b/src/plugins/clangformat/clangformatsettings.h index 88b37d393e2..685dc042e8c 100644 --- a/src/plugins/clangformat/clangformatsettings.h +++ b/src/plugins/clangformat/clangformatsettings.h @@ -49,9 +49,17 @@ public: void setMode(Mode mode); Mode mode() const; + void setFormatWhileTyping(bool enable); + bool formatWhileTyping() const; + + void setFormatOnSave(bool enable); + bool formatOnSave() const; + private: - bool m_overrideDefaultFile = false; Mode m_mode; + bool m_overrideDefaultFile = false; + bool m_formatWhileTyping = false; + bool m_formatOnSave = false; }; } // namespace ClangFormat diff --git a/src/plugins/clangformat/tests/clangformat-test.cpp b/src/plugins/clangformat/tests/clangformat-test.cpp index 174a3d11705..0493eeca97a 100644 --- a/src/plugins/clangformat/tests/clangformat-test.cpp +++ b/src/plugins/clangformat/tests/clangformat-test.cpp @@ -53,6 +53,7 @@ public: private: bool formatCodeInsteadOfIndent() const override { return true; } + bool formatWhileTyping() const override { return true; } }; ClangFormatTest::ClangFormatTest() diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp index 85a180e4e95..15651214bdc 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp @@ -45,6 +45,7 @@ using namespace CppEditor; using namespace ProjectExplorer; +using namespace Utils; namespace CompilationDatabaseProjectManager { namespace Internal { @@ -124,7 +125,7 @@ public: QStringList flags; QString fileName; QString workingDir; - QString sysRoot; + FilePath sysRoot; }; } @@ -183,8 +184,8 @@ void CompilationDatabaseTests::testFilterArguments() {"RELATIVE_PLUGIN_PATH", "\"../lib/qtcreator/plugins\""}, {"QT_CREATOR", "1"}})); QCOMPARE(testData.fileKind, CppEditor::ProjectFile::Kind::CXXSource); - QCOMPARE(testData.sysRoot, HostOsInfo::isWindowsHost() ? QString("C:\\sysroot\\embedded") - : QString("/opt/sysroot/embedded")); + QCOMPARE(testData.sysRoot.toString(), HostOsInfo::isWindowsHost() ? QString("C:\\sysroot\\embedded") + : QString("/opt/sysroot/embedded")); } static QString kCmakeCommand diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index 632db825562..a60d2ed9141 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -38,6 +38,7 @@ #include using namespace ProjectExplorer; +using namespace Utils; namespace CompilationDatabaseProjectManager { namespace Internal { @@ -102,7 +103,7 @@ void filteredFlags(const QString &fileName, HeaderPaths &headerPaths, Macros ¯os, CppEditor::ProjectFile::Kind &fileKind, - QString &sysRoot) + Utils::FilePath &sysRoot) { if (flags.empty()) return; @@ -192,7 +193,7 @@ void filteredFlags(const QString &fileName, if (flag.startsWith("--sysroot=")) { if (sysRoot.isEmpty()) - sysRoot = updatedPathFlag(flag.mid(10), workingDir); + sysRoot = FilePath::fromString(updatedPathFlag(flag.mid(10), workingDir)); continue; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h index 3952b41c6b2..70a94382923 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h @@ -25,10 +25,8 @@ #pragma once -#include "compilationdatabaseconstants.h" - #include -#include +#include #include #include @@ -65,7 +63,7 @@ void filteredFlags(const QString &fileName, QVector &headerPaths, QVector ¯os, CppEditor::ProjectFile::Kind &fileKind, - QString &sysRoot); + Utils::FilePath &sysRoot); QStringList splitCommandLine(QString commandLine, QSet &flagsCache); diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index caeeddded9d..b31125fbb33 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -25,6 +25,8 @@ #include "compilationdbparser.h" +#include "compilationdatabaseconstants.h" + #include #include #include diff --git a/src/plugins/coreplugin/editormanager/editorview.cpp b/src/plugins/coreplugin/editormanager/editorview.cpp index fcfef3d1f57..a8ee45501dc 100644 --- a/src/plugins/coreplugin/editormanager/editorview.cpp +++ b/src/plugins/coreplugin/editormanager/editorview.cpp @@ -407,8 +407,7 @@ void EditorView::openDroppedFiles(const QList &files) }; auto openEntry = [&](const DropSupport::FileSpec &spec) { if (first) { - first = false; - EditorManagerPrivate::openEditorAt(this, specToLink(spec)); + first = !EditorManagerPrivate::openEditorAt(this, specToLink(spec)); } else if (spec.column != -1 || spec.line != -1) { EditorManagerPrivate::openEditorAt(this, specToLink(spec), diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 880719420b6..0b77c0ef48b 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -727,7 +727,7 @@ void MainWindow::registerDefaultActions() medit->appendGroup(Constants::G_EDIT_PREFERENCES); medit->addSeparator(Constants::G_EDIT_PREFERENCES); - m_optionsAction = new QAction(tr("&Preferences..."), this); + m_optionsAction = new QAction(tr("Pr&eferences..."), this); m_optionsAction->setMenuRole(QAction::PreferencesRole); cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS); cmd->setDefaultKeySequence(QKeySequence::Preferences); diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 3038bf98f9a..e25e2d02843 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -314,16 +314,38 @@ QVersionNumber ClangdSettings::clangdVersion(const FilePath &clangdFilePath) return it->second; } -FilePath ClangdSettings::clangdIncludePath() const +static FilePath getClangHeadersPathFromClang(const FilePath &clangdFilePath) { - QTC_ASSERT(useClangd(), return {}); - FilePath clangdPath = clangdFilePath(); - QTC_ASSERT(!clangdPath.isEmpty() && clangdPath.exists(), return {}); - const QVersionNumber version = clangdVersion(); + const FilePath clangFilePath = clangdFilePath.absolutePath().pathAppended("clang") + .withExecutableSuffix(); + if (!clangFilePath.exists()) + return {}; + QtcProcess clang; + clang.setCommand({clangFilePath, {"-print-resource-dir"}}); + clang.start(); + if (!clang.waitForFinished()) + return {}; + const FilePath resourceDir = FilePath::fromUserInput(QString::fromLocal8Bit( + clang.readAllStandardOutput().trimmed())); + if (resourceDir.isEmpty() || !resourceDir.exists()) + return {}; + const FilePath includeDir = resourceDir.pathAppended("include"); + if (!includeDir.exists()) + return {}; + return includeDir; +} + +static FilePath getClangHeadersPath(const FilePath &clangdFilePath) +{ + const FilePath headersPath = getClangHeadersPathFromClang(clangdFilePath); + if (!headersPath.isEmpty()) + return headersPath; + + const QVersionNumber version = ClangdSettings::clangdVersion(clangdFilePath); QTC_ASSERT(!version.isNull(), return {}); static const QStringList libDirs{"lib", "lib64"}; for (const QString &libDir : libDirs) { - const FilePath includePath = clangdPath.absolutePath().parentDir().pathAppended(libDir) + const FilePath includePath = clangdFilePath.absolutePath().parentDir().pathAppended(libDir) .pathAppended("clang").pathAppended(version.toString()).pathAppended("include"); if (includePath.exists()) return includePath; @@ -332,6 +354,21 @@ FilePath ClangdSettings::clangdIncludePath() const return {}; } +FilePath ClangdSettings::clangdIncludePath() const +{ + QTC_ASSERT(useClangd(), return {}); + FilePath clangdPath = clangdFilePath(); + QTC_ASSERT(!clangdPath.isEmpty() && clangdPath.exists(), return {}); + static QHash headersPathCache; + const auto it = headersPathCache.constFind(clangdPath); + if (it != headersPathCache.constEnd()) + return *it; + const FilePath headersPath = getClangHeadersPath(clangdPath); + if (!headersPath.isEmpty()) + headersPathCache.insert(clangdPath, headersPath); + return headersPath; +} + FilePath ClangdSettings::clangdUserConfigFilePath() { return FilePath::fromString( diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index 80a8cce0bd3..2b01b86c273 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -473,7 +473,7 @@ bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, boo if (!editedRanges.empty()) { QTextCursor cursor(document()); - cursor.beginEditBlock(); + cursor.joinPreviousEditBlock(); indenter()->format(editedRanges); cursor.endEditBlock(); } diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 6258c9355a7..39bcc5118c0 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -1533,7 +1533,7 @@ void CppModelManager::setupFallbackProjectPart() if (sysroot.isEmpty()) sysroot = Utils::FilePath::fromString(defaultTc->sysRoot()); Utils::Environment env = defaultKit->buildEnvironment(); - tcInfo = ToolChainInfo(defaultTc, sysroot.toString(), env); + tcInfo = ToolChainInfo(defaultTc, sysroot, env); const auto macroInspectionWrapper = [runner = tcInfo.macroInspectionRunner]( const QStringList &flags) { ToolChain::MacroInspectionReport report = runner(flags); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 03c6529d1ee..207b0c90fe7 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -4189,9 +4189,12 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d // member variable if (generateFlags & Flag::GenerateMemberVariable) { - const QString storageDeclaration = overview.prettyType(memberVariableType, - data.memberVariableName) - + QLatin1String(";\n"); + QString storageDeclaration = overview.prettyType(memberVariableType, data.memberVariableName); + if (memberVariableType->asPointerType() + && m_operation->semanticInfo().doc->translationUnit()->languageFeatures().cxx11Enabled) { + storageDeclaration.append(" = nullptr"); + } + storageDeclaration.append(";\n"); addHeaderCode(InsertionPointLocator::Private, storageDeclaration); } diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 04f1a1ab043..2b7b671ef09 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -109,7 +109,6 @@ public: ContainerShell(const QString &containerId) : m_containerId(containerId) { - start(); } private: @@ -464,9 +463,7 @@ void DockerDevicePrivate::startContainer() "or restart Qt Creator.")); }); - if (m_shell->state() != DeviceShell::State::Succeeded) { - m_shell.reset(); - DockerApi::recheckDockerDaemon(); + if (!m_shell->start()) { qCWarning(dockerDeviceLog) << "Container shell failed to start"; } } diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp index 3b8b3a49380..8ed88ea7593 100644 --- a/src/plugins/projectexplorer/customtoolchain.cpp +++ b/src/plugins/projectexplorer/customtoolchain.cpp @@ -139,7 +139,8 @@ ToolChain::BuiltInHeaderPathsRunner CustomToolChain::createBuiltInHeaderPathsRun const HeaderPaths builtInHeaderPaths = m_builtInHeaderPaths; // This runner must be thread-safe! - return [builtInHeaderPaths](const QStringList &cxxFlags, const QString &, const QString &) { + return [builtInHeaderPaths](const QStringList &cxxFlags, const FilePath &sysRoot, const QString &) { + Q_UNUSED(sysRoot) HeaderPaths flagHeaderPaths; for (const QString &cxxFlag : cxxFlags) { if (cxxFlag.startsWith(QLatin1String("-I"))) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index beb91799715..ee0a0e3e363 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -126,18 +126,18 @@ using namespace Internal; // Helpers: // -------------------------------------------------------------------------- -static const char compilerPlatformCodeGenFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformCodeGenFlags"; -static const char compilerPlatformLinkerFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformLinkerFlags"; -static const char targetAbiKeyC[] = "ProjectExplorer.GccToolChain.TargetAbi"; -static const char originalTargetTripleKeyC[] = "ProjectExplorer.GccToolChain.OriginalTargetTriple"; -static const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedAbis"; -static const char parentToolChainIdKeyC[] = "ProjectExplorer.ClangToolChain.ParentToolChainId"; -static const char binaryRegexp[] = "(?:^|-|\\b)(?:gcc|g\\+\\+|clang(?:\\+\\+)?)(?:-([\\d.]+))?$"; +const char compilerPlatformCodeGenFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformCodeGenFlags"; +const char compilerPlatformLinkerFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformLinkerFlags"; +const char targetAbiKeyC[] = "ProjectExplorer.GccToolChain.TargetAbi"; +const char originalTargetTripleKeyC[] = "ProjectExplorer.GccToolChain.OriginalTargetTriple"; +const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedAbis"; +const char parentToolChainIdKeyC[] = "ProjectExplorer.ClangToolChain.ParentToolChainId"; +const char binaryRegexp[] = "(?:^|-|\\b)(?:gcc|g\\+\\+|clang(?:\\+\\+)?)(?:-([\\d.]+))?$"; -static QByteArray runGcc(const FilePath &gcc, const QStringList &arguments, const Environment &env) +static QString runGcc(const FilePath &gcc, const QStringList &arguments, const Environment &env) { if (!gcc.isExecutableFile()) - return QByteArray(); + return {}; QtcProcess cpp; Environment environment(env); @@ -150,11 +150,11 @@ static QByteArray runGcc(const FilePath &gcc, const QStringList &arguments, cons if (cpp.result() != ProcessResult::FinishedWithSuccess || cpp.exitCode() != 0) { Core::MessageManager::writeFlashing({"Compiler feature detection failure!", cpp.exitMessage(), - QString::fromUtf8(cpp.allRawOutput())}); - return QByteArray(); + cpp.allOutput()}); + return {}; } - return cpp.allOutput().toUtf8(); + return cpp.allOutput(); } static ProjectExplorer::Macros gccPredefinedMacros(const FilePath &gcc, @@ -164,7 +164,7 @@ static ProjectExplorer::Macros gccPredefinedMacros(const FilePath &gcc, QStringList arguments = args; arguments << "-"; - ProjectExplorer::Macros predefinedMacros = Macro::toMacros(runGcc(gcc, arguments, env)); + ProjectExplorer::Macros predefinedMacros = Macro::toMacros(runGcc(gcc, arguments, env).toUtf8()); // Sanity check in case we get an error message instead of real output: QTC_CHECK(predefinedMacros.isEmpty() || predefinedMacros.front().type == ProjectExplorer::MacroType::Define); @@ -189,7 +189,7 @@ HeaderPaths GccToolChain::gccHeaderPaths(const FilePath &gcc, { HeaderPaths builtInHeaderPaths; QByteArray line; - QByteArray data = runGcc(gcc, arguments, env); + QByteArray data = runGcc(gcc, arguments, env).toUtf8(); QBuffer cpp(&data); cpp.open(QIODevice::ReadOnly); while (cpp.canReadLine()) { @@ -277,7 +277,7 @@ static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, QStringList arguments = extraArgs; arguments << "-dumpmachine"; - QString machine = QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed(); + QString machine = runGcc(path, arguments, env).trimmed().section('\n', 0, 0, QString::SectionSkipEmpty); if (machine.isEmpty()) { // ICC does not implement the -dumpmachine option on macOS. if (HostOsInfo::isMacHost() && (path.fileName() == "icc" || path.fileName() == "icpc")) @@ -293,7 +293,7 @@ static QString gccVersion(const FilePath &path, { QStringList arguments = extraArgs; arguments << "-dumpversion"; - return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed(); + return runGcc(path, arguments, env).trimmed(); } static FilePath gccInstallDir(const FilePath &compiler, @@ -302,7 +302,7 @@ static FilePath gccInstallDir(const FilePath &compiler, { QStringList arguments = extraArgs; arguments << "-print-search-dirs"; - QString output = QString::fromLocal8Bit(runGcc(compiler, arguments, env)).trimmed(); + QString output = runGcc(compiler, arguments, env).trimmed(); // Expected output looks like this: // install: /usr/lib/gcc/x86_64-linux-gnu/7/ // ... @@ -596,15 +596,15 @@ QStringList GccToolChain::includedFiles(const QStringList &flags, const QString } QStringList GccToolChain::gccPrepareArguments(const QStringList &flags, - const QString &sysRoot, + const FilePath &sysRoot, const QStringList &platformCodeGenFlags, - Utils::Id languageId, + Id languageId, OptionsReinterpreter reinterpretOptions) { QStringList arguments; const bool hasKitSysroot = !sysRoot.isEmpty(); if (hasKitSysroot) - arguments.append(QString::fromLatin1("--sysroot=%1").arg(sysRoot)); + arguments.append(QString("--sysroot=%1").arg(sysRoot.nativePath())); QStringList allFlags; allFlags << platformCodeGenFlags << flags; @@ -629,7 +629,7 @@ HeaderPaths GccToolChain::builtInHeaderPaths(const Utils::Environment &env, Utils::Id languageId, ExtraHeaderPathsFunction extraHeaderPathsFunction, const QStringList &flags, - const QString &sysRoot, + const Utils::FilePath &sysRoot, const QString &originalTargetTriple) { QStringList arguments = gccPrepareArguments(flags, @@ -677,7 +677,7 @@ ToolChain::BuiltInHeaderPathsRunner GccToolChain::createBuiltInHeaderPathsRunner headerCache = headerPathsCache(), languageId = language(), extraHeaderPathsFunction = m_extraHeaderPathsFunction](const QStringList &flags, - const QString &sysRoot, + const FilePath &sysRoot, const QString &) { return builtInHeaderPaths(fullEnv, compilerCommand, @@ -1449,8 +1449,7 @@ void GccToolChainConfigWidget::handleCompilerCommandChange() Abis abiList; if (!path.isEmpty()) { - QFileInfo fi(path.toFileInfo()); - haveCompiler = fi.isExecutable() && fi.isFile(); + haveCompiler = path.isExecutableFile(); } if (haveCompiler) { Environment env = path.deviceEnvironment(); @@ -1712,7 +1711,7 @@ ToolChain::BuiltInHeaderPathsRunner ClangToolChain::createBuiltInHeaderPathsRunn headerCache = headerPathsCache(), languageId = language(), extraHeaderPathsFunction = m_extraHeaderPathsFunction](const QStringList &flags, - const QString &sysRoot, + const FilePath &sysRoot, const QString &target) { return builtInHeaderPaths(fullEnv, compilerCommand, diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index bad26674e23..980ea3fb8b7 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -151,7 +151,7 @@ protected: Utils::Id languageId, ExtraHeaderPathsFunction extraHeaderPathsFunction, const QStringList &flags, - const QString &sysRoot, + const Utils::FilePath &sysRoot, const QString &originalTargetTriple); static HeaderPaths gccHeaderPaths(const Utils::FilePath &gcc, @@ -175,7 +175,7 @@ protected: private: void updateSupportedAbis() const; static QStringList gccPrepareArguments(const QStringList &flags, - const QString &sysRoot, + const Utils::FilePath &sysRoot, const QStringList &platformCodeGenFlags, Utils::Id languageId, OptionsReinterpreter reinterpretOptions); diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 05a362bd3f7..93bfe31ae43 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -309,7 +309,18 @@ void KitManager::restoreKits() } static const auto isHostKit = [](const Kit *kit) { - return kitMatchesAbiList(kit, {Abi::hostAbi()}); + const Abi hostAbi = Abi::hostAbi(); + if (HostOsInfo::isMacHost() && hostAbi.architecture() == Abi::ArmArchitecture) { + const Abi x86Abi(Abi::X86Architecture, + hostAbi.os(), + hostAbi.osFlavor(), + hostAbi.binaryFormat(), + hostAbi.wordWidth()); + + return kitMatchesAbiList(kit, {hostAbi, x86Abi}); + } + + return kitMatchesAbiList(kit, {hostAbi}); }; static const auto deviceTypeForKit = [](const Kit *kit) { diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index d4530a58324..890b4a4e532 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -69,16 +69,19 @@ using namespace ProjectExplorer; // nmake/jom messages. static Task handleNmakeJomMessage(const QString &line) { + Task::TaskType type = Task::Unknown; int matchLength = 0; - if (line.startsWith("Error:")) + if (line.startsWith("Error:")) { matchLength = 6; - else if (line.startsWith("Warning:")) + type = Task::Error; + } else if (line.startsWith("Warning:")) { matchLength = 8; - - if (!matchLength) + type = Task::Warning; + } else { return {}; + } - CompileTask task(Task::Error, line.mid(matchLength).trimmed()); + CompileTask task(type, line.mid(matchLength).trimmed()); task.details << line; return std::move(task); } diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index cd76162d402..7ab685bdfc9 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1142,7 +1142,7 @@ ToolChain::BuiltInHeaderPathsRunner MsvcToolChain::createBuiltInHeaderPathsRunne Utils::Environment fullEnv = env; addToEnvironment(fullEnv); - return [this, fullEnv](const QStringList &, const QString &, const QString &) { + return [this, fullEnv](const QStringList &, const FilePath &, const QString &) { QMutexLocker locker(&m_headerPathsMutex); const auto envList = fullEnv.toStringList(); const auto it = m_headerPathsPerEnv.constFind(envList); diff --git a/src/plugins/projectexplorer/rawprojectpart.cpp b/src/plugins/projectexplorer/rawprojectpart.cpp index 35e96b75d87..b222610446d 100644 --- a/src/plugins/projectexplorer/rawprojectpart.cpp +++ b/src/plugins/projectexplorer/rawprojectpart.cpp @@ -29,7 +29,6 @@ #include "buildconfiguration.h" #include "kitinformation.h" #include "project.h" -#include "projectexplorerconstants.h" #include "target.h" #include @@ -165,7 +164,7 @@ KitInfo::KitInfo(Kit *kit) } // Sysroot - sysRootPath = SysRootKitAspect::sysRoot(kit).toString(); + sysRootPath = SysRootKitAspect::sysRoot(kit); } bool KitInfo::isValid() const @@ -174,7 +173,7 @@ bool KitInfo::isValid() const } ToolChainInfo::ToolChainInfo(const ToolChain *toolChain, - const QString &sysRootPath, + const Utils::FilePath &sysRootPath, const Utils::Environment &env) { if (toolChain) { diff --git a/src/plugins/projectexplorer/rawprojectpart.h b/src/plugins/projectexplorer/rawprojectpart.h index 3bf7d31b906..569e2fd8af9 100644 --- a/src/plugins/projectexplorer/rawprojectpart.h +++ b/src/plugins/projectexplorer/rawprojectpart.h @@ -138,7 +138,7 @@ public: Utils::QtMajorVersion projectPartQtVersion = Utils::QtMajorVersion::None; - QString sysRootPath; + Utils::FilePath sysRootPath; }; class PROJECTEXPLORER_EXPORT ToolChainInfo @@ -146,7 +146,7 @@ class PROJECTEXPLORER_EXPORT ToolChainInfo public: ToolChainInfo() = default; ToolChainInfo(const ProjectExplorer::ToolChain *toolChain, - const QString &sysRootPath, + const Utils::FilePath &sysRootPath, const Utils::Environment &env); bool isValid() const { return type.isValid(); } @@ -161,7 +161,7 @@ public: Utils::FilePath installDir; QStringList extraCodeModelFlags; - QString sysRootPath; // For headerPathsRunner. + Utils::FilePath sysRootPath; // For headerPathsRunner. ProjectExplorer::ToolChain::BuiltInHeaderPathsRunner headerPathsRunner; ProjectExplorer::ToolChain::MacroInspectionRunner macroInspectionRunner; }; diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index 6a3ced00535..1b6ed3e7a2b 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -147,7 +147,7 @@ public: // A BuiltInHeaderPathsRunner is created in the ui thread and runs in another thread. using BuiltInHeaderPathsRunner = std::function; + const QStringList &cxxflags, const Utils::FilePath &sysRoot, const QString &originalTargetTriple)>; virtual BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &env) const = 0; virtual void addToEnvironment(Utils::Environment &env) const = 0; virtual Utils::FilePath makeCommand(const Utils::Environment &env) const = 0; diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 6f9c674f3d7..8236553abce 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -189,6 +189,7 @@ extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/edit3d SOURCES edit3dview.cpp edit3dview.h + edit3dviewconfig.h edit3dwidget.cpp edit3dwidget.h edit3dcanvas.cpp edit3dcanvas.h edit3dactions.cpp edit3dactions.h @@ -333,6 +334,7 @@ extend_qtc_plugin(QmlDesigner gradientpresetitem.cpp gradientpresetitem.h gradientpresetlistmodel.cpp gradientpresetlistmodel.h propertyeditorcontextobject.cpp propertyeditorcontextobject.h + propertyeditorimageprovider.cpp propertyeditorimageprovider.h propertyeditorqmlbackend.cpp propertyeditorqmlbackend.h propertyeditortransaction.cpp propertyeditortransaction.h propertyeditorvalue.cpp propertyeditorvalue.h @@ -453,7 +455,8 @@ extend_qtc_plugin(QmlDesigner SOURCES explicitimagecacheimageprovider.cpp explicitimagecacheimageprovider.h - + smallimagecacheprovider.cpp + smallimagecacheprovider.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp index 81dc1ce486c..a565b464450 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp @@ -81,7 +81,7 @@ bool AssetExporterView::saveQmlFile(QString *error) const void AssetExporterView::modelAttached(Model *model) { - if (model->rewriterView() && model->rewriterView()->inErrorState()) + if (model->rewriterView() && !model->rewriterView()->errors().isEmpty()) setState(LoadState::QmlErrorState); AbstractView::modelAttached(model); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp index 9d11d264008..943693f2232 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp @@ -75,7 +75,7 @@ QPixmap AssetsLibraryIconProvider::requestPixmap(const QString &id, QSize *size, pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); if (requestedSize.isValid()) - return pixmap.scaled(requestedSize); + return pixmap.scaled(requestedSize, Qt::KeepAspectRatio); return pixmap; } diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 7cf91158d65..632574fb0fc 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -91,10 +91,6 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_assetsToDrag.clear(); } } - } else if (event->type() == QMouseEvent::MouseButtonRelease) { - m_assetsToDrag.clear(); - if (m_model) - m_model->endDrag(); } return QObject::eventFilter(obj, event); diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 7f5649ea5f6..a0bd7a23896 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -513,7 +513,7 @@ public: ->currentModel(); if (currentModel->rewriterView() - && currentModel->rewriterView()->inErrorState()) { + && !currentModel->rewriterView()->errors().isEmpty()) { throw DocumentError{}; } diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index fd8d11768e5..068e9cf2fd8 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -478,19 +478,16 @@ static void layoutHelperFunction(const SelectionContext &selectionContext, const QmlItemNode qmlItemNode = QmlItemNode(selectionContext.firstSelectedModelNode()); if (qmlItemNode.hasInstanceParentItem()) { - ModelNode layoutNode; - selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction1",[=, &layoutNode](){ + + selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction",[=](){ QmlItemNode parentNode = qmlItemNode.instanceParentItem(); NodeMetaInfo metaInfo = selectionContext.view()->model()->metaInfo(layoutType); - layoutNode = selectionContext.view()->createModelNode(layoutType, metaInfo.majorVersion(), metaInfo.minorVersion()); + const ModelNode layoutNode = selectionContext.view()->createModelNode(layoutType, metaInfo.majorVersion(), metaInfo.minorVersion()); reparentTo(layoutNode, parentNode); - }); - - selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction2",[=](){ QList sortedSelectedNodes = selectionContext.selectedModelNodes(); Utils::sort(sortedSelectedNodes, lessThan); diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index 9af8651c44e..c32edec724d 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -110,9 +110,11 @@ void DebugView::nodeCreated(const ModelNode &createdNode) QString string; message.setString(&string); message << createdNode; + message << createdNode.majorVersion() << "." << createdNode.minorVersion(); message << createdNode.nodeSource(); - message << "MetaInfo " << createdNode.metaInfo().isValid(); + message << "MetaInfo " << createdNode.metaInfo().isValid() << " "; if (createdNode.metaInfo().isValid()) { + message << createdNode.metaInfo().majorVersion() << "." << createdNode.metaInfo().minorVersion(); message << createdNode.metaInfo().componentFileName(); } log("::nodeCreated:", message.readAll()); diff --git a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp index 76db41a177e..3d7a9207c08 100644 --- a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp @@ -23,85 +23,56 @@ ** ****************************************************************************/ -#include "backgroundcolorselection.h" +#pragma once + +#include -#include #include -#include -#include + +#include "backgroundcolorselection.h" +#include "edit3dviewconfig.h" using namespace QmlDesigner; -namespace { -QList readBackgroundColorConfiguration() -{ - QVariant var = QmlDesigner::DesignerSettings::getValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); - - if (!var.isValid()) - return {}; - - auto colorNameList = var.value>(); - QTC_ASSERT(colorNameList.size() == 2, return {}); - - return {colorNameList[0], colorNameList[1]}; -} - -void setBackgroundColorConfiguration(const QList &colorConfig) -{ - auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); - View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, - QVariant::fromValue(colorConfig)); - view->view3DAction(cmd); -} - -void saveBackgroundColorConfiguration(const QList &colorConfig) -{ - QList colorsSaved = {colorConfig[0].name(), colorConfig[1].name()}; - QmlDesigner::DesignerSettings::setValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, - QVariant::fromValue(colorsSaved)); -} - -} // namespace - -QColorDialog *BackgroundColorSelection::createDialog(QWidget *parent) -{ - auto dialog = new QColorDialog(parent); - - dialog->setModal(true); - dialog->setAttribute(Qt::WA_DeleteOnClose); - - const QList oldColorConfig = readBackgroundColorConfiguration(); - - dialog->show(); - - QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [](const QColor &color) { - setBackgroundColorConfiguration({color, color}); - }); - - QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [](const QColor &color) { - saveBackgroundColorConfiguration({color, color}); - }); - - if (!oldColorConfig.isEmpty()) { - QObject::connect(dialog, &QColorDialog::rejected, dialog, [oldColorConfig]() { - setBackgroundColorConfiguration(oldColorConfig); - }); - } - - return dialog; -} - -void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent) +void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType) { if (m_dialog) return; - m_dialog = BackgroundColorSelection::createDialog(parent); + m_dialog = BackgroundColorSelection::createColorDialog(parent, key, cmdType); QTC_ASSERT(m_dialog, return); QObject::connect(m_dialog, &QWidget::destroyed, m_dialog, [&]() { m_dialog = nullptr; }); } + +QColorDialog *BackgroundColorSelection::createColorDialog(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType) +{ + auto dialog = new QColorDialog(parent); + + dialog->setModal(true); + dialog->setAttribute(Qt::WA_DeleteOnClose); + + QList oldColorConfig = Edit3DViewConfig::load(key); + + dialog->show(); + + QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [cmdType](const QColor &color) { + Edit3DViewConfig::set(cmdType, color); + }); + + QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [key](const QColor &color) { + Edit3DViewConfig::save(key, color); + }); + + if (Edit3DViewConfig::isValid(oldColorConfig)) { + QObject::connect(dialog, &QColorDialog::rejected, dialog, [cmdType, oldColorConfig]() { + Edit3DViewConfig::set(cmdType, oldColorConfig); + }); + } + + return dialog; +} diff --git a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h index d8832f40fda..f7df55b8e30 100644 --- a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h @@ -25,9 +25,13 @@ #pragma once -#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QColorDialog) namespace QmlDesigner { + class BackgroundColorSelection : public QObject { Q_OBJECT @@ -37,10 +41,13 @@ public: : QObject{parent} {} - static void showBackgroundColorSelectionWidget(QWidget *parent); + static void showBackgroundColorSelectionWidget(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType); private: - static QColorDialog *createDialog(QWidget *parent); + static QColorDialog *createColorDialog(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType); + inline static QColorDialog *m_dialog = nullptr; }; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp index 76343584c9c..e90f20767d1 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp @@ -48,7 +48,8 @@ Edit3DActionTemplate::Edit3DActionTemplate(const QString &description, void Edit3DActionTemplate::actionTriggered(bool b) { - if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor) { + if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor + && m_type != View3DActionCommand::SelectGridColor) { auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); View3DActionCommand cmd(m_type, b); view->view3DAction(cmd); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index efb9e24c1ca..02d798c1f6b 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -186,42 +186,17 @@ void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e) void Edit3DCanvas::dropEvent(QDropEvent *e) { - auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode(); - QTC_ASSERT(modelNode.isValid(), return); + m_parent->view()->executeInTransaction(__FUNCTION__, [&] { + auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode(); + QTC_ASSERT(modelNode.isValid(), return); - e->accept(); - m_parent->view()->setSelectedModelNode(modelNode); + e->accept(); + m_parent->view()->setSelectedModelNode(modelNode); - // if added node is a Model, assign it a material - if (modelNode.isSubclassOf("QtQuick3D.Model")) { - ModelNode matLib = m_parent->view()->modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return); - - const QList materials = matLib.directSubModelNodes(); - ModelNode material; - if (materials.size() > 0) { - for (const ModelNode &mat : materials) { - if (mat.isSubclassOf("QtQuick3D.Material")) { - material = mat; - break; - } - } - } - - // if no valid material, create a new default material - if (!material.isValid()) { - NodeMetaInfo metaInfo = m_parent->view()->model()->metaInfo("QtQuick3D.DefaultMaterial"); - material = m_parent->view()->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), - metaInfo.minorVersion()); - VariantProperty matNameProp = material.variantProperty("objectName"); - matNameProp.setValue("New Material"); - material.validId(); - matLib.defaultNodeListProperty().reparentHere(material); - } - - BindingProperty modelMatsProp = modelNode.bindingProperty("materials"); - modelMatsProp.setExpression(material.id()); - } + // if added node is a Model, assign it a material + if (modelNode.isSubclassOf("QtQuick3D.Model")) + m_parent->view()->assignMaterialTo3dModel(modelNode); + }); } void Edit3DCanvas::focusOutEvent(QFocusEvent *focusEvent) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 30f909f1598..bcce905b4fa 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -28,6 +28,8 @@ #include "edit3dcanvas.h" #include "edit3dview.h" #include "edit3dwidget.h" +#include "edit3dviewconfig.h" +#include "backgroundcolorselection.h" #include #include @@ -42,8 +44,6 @@ #include #include -#include - #include #include @@ -210,8 +210,6 @@ void Edit3DView::modelAttached(Model *model) void Edit3DView::modelAboutToBeDetached(Model *model) { - QTC_ASSERT(edit3DWidget()->canvas(), return); - // Hide the canvas when model is detached (i.e. changing documents) if (edit3DWidget() && edit3DWidget()->canvas()) { m_canvasCache.insert(model, edit3DWidget()->canvas()->renderImage()); @@ -241,6 +239,16 @@ void Edit3DView::customNotification(const AbstractView *view, const QString &ide resetPuppet(); } +void Edit3DView::modelAtPosReady(const ModelNode &modelNode) +{ + if (!m_droppedMaterial.isValid() || !modelNode.isValid()) + return; + + executeInTransaction(__FUNCTION__, [&] { + assignMaterialTo3dModel(modelNode, m_droppedMaterial); + }); +} + void Edit3DView::sendInputEvent(QInputEvent *e) const { if (nodeInstanceView()) @@ -266,6 +274,70 @@ void Edit3DView::setSeeker(SeekerSlider *slider) m_seeker = slider; } +Edit3DAction *Edit3DView::createSelectBackgrounColorAction() +{ + QString description = QCoreApplication::translate("SelectBackgroundColorAction", + "Select Background Color"); + QString tooltip = QCoreApplication::translate("SelectBackgroundColorAction", + "Select a color for the background of the 3D Editor."); + + auto operation = [this](const SelectionContext &) { + BackgroundColorSelection::showBackgroundColorSelectionWidget( + edit3DWidget(), + DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, + View3DActionCommand::SelectBackgroundColor); + }; + + return new Edit3DAction( + Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor, + description, + {}, false, false, {}, {}, operation, + tooltip); +} + +Edit3DAction *Edit3DView::createGridColorSelectionAction() +{ + QString description = QCoreApplication::translate("SelectGridColorAction", "Select Grid Color"); + QString tooltip = QCoreApplication::translate("SelectGridColorAction", + "Select a color for the grid lines of the 3D Editor."); + + auto operation = [this](const SelectionContext &) { + BackgroundColorSelection::showBackgroundColorSelectionWidget( + edit3DWidget(), + DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, + View3DActionCommand::SelectGridColor); + }; + + return new Edit3DAction( + Constants::EDIT3D_EDIT_SELECT_GRID_COLOR, View3DActionCommand::SelectGridColor, + description, {}, false, false, {}, {}, operation, + tooltip); +} + +Edit3DAction *Edit3DView::createResetColorAction() +{ + QString description = QCoreApplication::translate("ResetEdit3DColorsAction", "Reset Colors"); + QString tooltip = QCoreApplication::translate("ResetEdit3DColorsAction", + "Reset the background color and the color of the " + "grid lines of the 3D Editor to the default valus."); + + auto operation = [](const SelectionContext &) { + QList bgColors = {QRgb(0x222222), QRgb(0x999999)}; + Edit3DViewConfig::set(View3DActionCommand::SelectBackgroundColor, bgColors); + Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, bgColors); + + QColor gridColor{0xaaaaaa}; + Edit3DViewConfig::set(View3DActionCommand::SelectGridColor, gridColor); + Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, gridColor); + }; + + return new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor, + description, + {}, false, false, {}, {}, operation, + tooltip); +} + void Edit3DView::createEdit3DActions() { m_selectionModeAction @@ -338,32 +410,6 @@ void Edit3DView::createEdit3DActions() QKeySequence(Qt::Key_G), true, true, {}, {}, nullptr, QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid.")); - SelectionContextOperation showBackgroundColorSelection = [this](const SelectionContext &) { - BackgroundColorSelection::showBackgroundColorSelectionWidget(edit3DWidget()); - }; - - m_backgroundColorSelectionAction = new Edit3DAction( - QmlDesigner::Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor, - QCoreApplication::translate("SelectBackgroundColorAction", "Select Background Color"), - {}, false, false, {}, {}, showBackgroundColorSelection, - QCoreApplication::translate("SelectBackgroundColorAction", "Select a color for the background of the 3D Editor.")); - - m_resetBackgroundColorAction = new Edit3DAction( - QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor, - QCoreApplication::translate("ResetBackgroundColorAction", "Reset Background Color"), - {}, false, false, {}, {}, [](const SelectionContext &) { - QList colors = {QRgb(0x222222), QRgb(0x999999)}; - auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); - View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, QVariant::fromValue(colors)); - view->view3DAction(cmd); - - QList colorsToSave = {colors[0].name(), colors[1].name()}; - QmlDesigner::DesignerSettings::setValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, - QVariant::fromValue(colorsToSave)); - }, - QCoreApplication::translate("ResetBackgroundColorAction", "Reset background color of the 3D Editor to the default value.")); - m_showSelectionBoxAction = new Edit3DAction( QmlDesigner::Constants::EDIT3D_EDIT_SHOW_SELECTION_BOX, View3DActionCommand::ShowSelectionBox, QCoreApplication::translate("ShowSelectionBoxAction", "Show Selection Boxes"), @@ -521,8 +567,9 @@ void Edit3DView::createEdit3DActions() m_visibilityToggleActions << m_showCameraFrustumAction; m_visibilityToggleActions << m_showParticleEmitterAction; - m_backgroundColorActions << m_backgroundColorSelectionAction; - m_backgroundColorActions << m_resetBackgroundColorAction; + m_backgroundColorActions << createSelectBackgrounColorAction(); + m_backgroundColorActions << createGridColorSelectionAction(); + m_backgroundColorActions << createResetColorAction(); } QVector Edit3DView::leftActions() const @@ -568,5 +615,10 @@ void Edit3DView::addQuick3DImport() tr("Could not add QtQuick3D import to project.")); } +void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos) +{ + m_droppedMaterial = matNode; + QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetModelAtPos, pos}); } +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index e5cb2aba51b..4d96a7549f3 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -64,6 +64,7 @@ public: void modelAboutToBeDetached(Model *model) override; void importsChanged(const QList &addedImports, const QList &removedImports) override; void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; + void modelAtPosReady(const ModelNode &modelNode) override; void sendInputEvent(QInputEvent *e) const; void edit3DViewResized(const QSize &size) const; @@ -78,13 +79,16 @@ public: void setSeeker(SeekerSlider *slider); void addQuick3DImport(); - -protected: + void dropMaterial(const ModelNode &matNode, const QPointF &pos); private: void createEdit3DWidget(); void checkImports(); + Edit3DAction *createSelectBackgrounColorAction(); + Edit3DAction *createGridColorSelectionAction(); + Edit3DAction *createResetColorAction(); + QPointer m_edit3DWidget; QVector m_leftActions; QVector m_rightActions; @@ -101,8 +105,6 @@ private: Edit3DAction *m_orientationModeAction = nullptr; Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_showGridAction = nullptr; - Edit3DAction *m_backgroundColorSelectionAction = nullptr; - Edit3DAction *m_resetBackgroundColorAction = nullptr; Edit3DAction *m_showSelectionBoxAction = nullptr; Edit3DAction *m_showIconGizmoAction = nullptr; Edit3DAction *m_showCameraFrustumAction = nullptr; @@ -116,6 +118,7 @@ private: SeekerSlider *m_seeker = nullptr; int particlemode; ModelCache m_canvasCache; + ModelNode m_droppedMaterial; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h b/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h new file mode 100644 index 00000000000..8e4081176af --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace QmlDesigner { + +class Edit3DViewConfig +{ +public: + static QList load(const char key[]) + { + QVariant var = DesignerSettings::getValue(key); + + if (!var.isValid()) + return {}; + + auto colorNameList = var.value(); + + return Utils::transform(colorNameList, [](const QString &colorName) { + return QColor{colorName}; + }); + } + + static void set(View3DActionCommand::Type type, const QList &colorConfig) + { + if (colorConfig.size() == 1) + set(type, colorConfig.at(0)); + else + setVariant(type, QVariant::fromValue(colorConfig)); + } + + static void set(View3DActionCommand::Type type, const QColor &color) + { + setVariant(type, QVariant::fromValue(color)); + } + + static void save(const QByteArray &key, const QList &colorConfig) + { + QStringList colorNames = Utils::transform(colorConfig, [](const QColor &color) { + return color.name(); + }); + + saveVariant(key, QVariant::fromValue(colorNames)); + } + + static void save(const QByteArray &key, const QColor &color) + { + saveVariant(key, QVariant::fromValue(color.name())); + } + + static bool isValid(const QList &colorConfig) { return !colorConfig.isEmpty(); } + +private: + static void setVariant(View3DActionCommand::Type type, const QVariant &colorConfig) + { + auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); + View3DActionCommand cmd(type, colorConfig); + view->view3DAction(cmd); + } + + static void saveVariant(const QByteArray &key, const QVariant &colorConfig) + { + DesignerSettings::setValue(key, colorConfig); + } +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index afa05dd67e2..a6672b9f164 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -242,12 +242,28 @@ void Edit3DWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) { const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() ->viewManager().designerActionManager(); - if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData())) + if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData()) + || dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_MATERIAL)) { dragEnterEvent->acceptProposedAction(); + } } void Edit3DWidget::dropEvent(QDropEvent *dropEvent) { + // handle dropping materials + if (dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + QByteArray data = dropEvent->mimeData()->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = m_view->modelNodeForInternalId(internalId); + + if (matNode.isValid()) + m_view->dropMaterial(matNode, dropEvent->position()); + return; + } + + // handle dropping external assets const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() ->viewManager().designerActionManager(); QHash addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index c4a64adf8f5..819bf58b34a 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -33,6 +33,8 @@ #include #include "qmldesignerconstants.h" +#include + #include #include #include @@ -405,10 +407,23 @@ void DragTool::move(const QPointF &scenePosition, const QList & void DragTool::commitTransaction() { try { + handleView3dDrop(); m_rewriterTransaction.commit(); } catch (const RewritingException &e) { e.showException(); } } +void DragTool::handleView3dDrop() +{ + // If a View3D is dropped, we need to assign material to the included model + for (const QmlItemNode &dragNode : qAsConst(m_dragNodes)) { + if (dragNode.modelNode().isSubclassOf("QtQuick3D.View3D")) { + const QList models = dragNode.modelNode().subModelNodesOfType("QtQuick3D.Model"); + QTC_ASSERT(models.size() == 1, return); + view()->assignMaterialTo3dModel(models.at(0)); + } + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h index 63d3de6e8f7..bb6f5622631 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.h +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h @@ -90,6 +90,7 @@ protected: void move(const QPointF &scenePos, const QList &itemList); void createDragNodes(const QMimeData *mimeData, const QPointF &scenePosition, const QList &itemList); void commitTransaction(); + void handleView3dDrop(); private: MoveManipulator m_moveManipulator; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 47ce7b6c5be..42ecfc06792 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -471,7 +471,7 @@ void FormEditorView::documentMessagesChanged(const QList &error if (!errors.isEmpty() && !model()->rewriterView()->hasIncompleteTypeInformation()) m_formEditorWidget->showErrorMessageBox(errors); - else + else if (rewriterView()->errors().isEmpty()) m_formEditorWidget->hideErrorMessageBox(); checkRootModelNode(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 0fe286a9982..dc29dab8c1b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -74,7 +74,7 @@ static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString formatter->plainTextEdit()->verticalScrollBar()->maximum()); } -static const int rowHeight = 28; +static const int rowHeight = 32; static const int checkBoxColWidth = 18; static const int labelMinWidth = 130; static const int controlMinWidth = 65; @@ -781,7 +781,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid( int &globalOptionsHeight = advanced ? m_advancedData.optionsHeight : m_simpleData.optionsHeight; globalOptionRows = qMax(globalOptionRows, optionRows); globalOptionsHeight = qMax(rowHeight * optionRows + 20, globalOptionsHeight); - layout->setContentsMargins(8, 8, 8, 0); + layout->setContentsMargins(8, 6, 8, 0); return layout; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index e3aae0cb7d5..8e8087dd214 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -90,21 +91,16 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, if (!isCancelled()) { const auto parseData = m_parseData; - for (const auto &pd : parseData) { - if (!startImportProcess(pd)) { - addError(tr("Failed to start import 3D asset process."), - pd.sourceInfo.absoluteFilePath()); - m_parseData.remove(pd.importId); - } - } + for (const auto &pd : parseData) + m_puppetQueue.append(pd.importId); + startNextImportProcess(); } if (!isCancelled()) { // Wait for puppet processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { postImport(); } else { - m_qmlPuppetCount = static_cast(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Importing 3D assets."); addInfo(progressTitle); notifyProgress(0, progressTitle); @@ -142,21 +138,14 @@ void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &sr emit infoReported(infoMsg, srcPath); } -void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, - int importId) +void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode) - ++m_qmlImportFinishedCount; + m_puppetProcess.reset(); - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); - - if (m_parseData.contains(importId)) { - const ParseData &pd = m_parseData[importId]; + if (m_parseData.contains(m_currentImportId)) { + const ParseData &pd = m_parseData[m_currentImportId]; QString errStr; if (exitStatus == QProcess::ExitStatus::CrashExit) { errStr = tr("Import process crashed."); @@ -179,15 +168,19 @@ void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::Exi addError(tr("Asset import process failed: \"%1\".") .arg(pd.sourceInfo.absoluteFilePath())); addError(errStr); - m_parseData.remove(importId); + m_parseData.remove(m_currentImportId); } } - if (m_qmlImportFinishedCount == m_qmlPuppetCount) { + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextImportProcess(); + + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport); } else { - notifyProgress(int(100. * (double(m_qmlImportFinishedCount) / double(m_qmlPuppetCount)))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -196,17 +189,17 @@ void ItemLibraryAssetImporter::iconProcessFinished(int exitCode, QProcess::ExitS Q_UNUSED(exitCode) Q_UNUSED(exitStatus) - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); + m_puppetProcess.reset(); - if (m_qmlPuppetProcesses.empty()) { + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextIconProcess(); + + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::finalizeQuick3DImport); } else { - notifyProgress(int(100. * (1. - (double(m_qmlPuppetProcesses.size()) / double(m_qmlPuppetCount))))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -225,11 +218,11 @@ void ItemLibraryAssetImporter::reset() m_tempDir = new QTemporaryDir; m_importFiles.clear(); m_overwrittenImports.clear(); - m_qmlPuppetProcesses.clear(); - m_qmlPuppetCount = 0; - m_qmlImportFinishedCount = 0; + m_puppetProcess.reset(); m_parseData.clear(); m_requiredImports.clear(); + m_currentImportId = 0; + m_puppetQueue.clear(); } void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, @@ -351,7 +344,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa return true; } -void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) +void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd) { QDir outDir = pd.outDir; if (pd.originalAssetName != pd.assetName) { @@ -452,8 +445,10 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) "QtQuick3D", impVersionStr)); } } - if (impVersionMajor > 0 && impVersionMajor < 6 - && startIconProcess(24, iconFileName, qmlIt.filePath())) { + if (impVersionMajor > 0 && impVersionMajor < 6) { + pd.iconFile = iconFileName; + pd.iconSource = qmlIt.filePath(); + m_puppetQueue.append(pd.importId); // Since icon is generated by external process, the file won't be // ready for asset gathering below, so assume its generation succeeds // and add it now. @@ -589,84 +584,101 @@ ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAsset return OverwriteResult::Skip; } -bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd) +void ItemLibraryAssetImporter::startNextImportProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - QJsonDocument optDoc(pd.options); - puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() - << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + QJsonDocument optDoc(pd.options); - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - importProcessFinished(exitCode, exitStatus, pd.importId); - }, - puppetArgs); + puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() + << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + m_currentImportId = pd.importId; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + importProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start import 3D asset process."), + pd.sourceInfo.absoluteFilePath()); + m_parseData.remove(pd.importId); + m_puppetProcess.reset(); + } } } - return false; } -bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFile, - const QString &iconSource) +void ItemLibraryAssetImporter::startNextIconProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource; - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - iconProcessFinished(exitCode, exitStatus); - }, - puppetArgs); - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + puppetArgs << "--rendericon" << QString::number(24) << pd.iconFile << pd.iconSource; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + iconProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start icon generation process."), + pd.sourceInfo.absoluteFilePath()); + m_puppetProcess.reset(); + } } } - return false; } void ItemLibraryAssetImporter::postImport() { - Q_ASSERT(m_qmlPuppetProcesses.empty()); + QTC_ASSERT(m_puppetQueue.isEmpty() && !m_puppetProcess, return); if (!isCancelled()) { - for (const auto &pd : qAsConst(m_parseData)) + for (auto &pd : m_parseData) postParseQuick3DAsset(pd); + startNextIconProcess(); } if (!isCancelled()) { // Wait for icon generation processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { finalizeQuick3DImport(); } else { - m_qmlPuppetCount = static_cast(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Generating icons."); addInfo(progressTitle); notifyProgress(0, progressTitle); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h index 83be9af5f4e..1f0009eaab5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h @@ -74,7 +74,7 @@ signals: void importFinished(); private slots: - void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, int importId); + void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); private: @@ -87,6 +87,8 @@ private: QString assetName; QString originalAssetName; int importId; + QString iconFile; + QString iconSource; }; void notifyFinished(); @@ -96,7 +98,7 @@ private: const QSet &preselectedFilesForOverwrite); bool preParseQuick3DAsset(const QString &file, ParseData &pd, const QSet &preselectedFilesForOverwrite); - void postParseQuick3DAsset(const ParseData &pd); + void postParseQuick3DAsset(ParseData &pd); void copyImportedFiles(); void notifyProgress(int value, const QString &text); @@ -110,8 +112,8 @@ private: }; OverwriteResult confirmAssetOverwrite(const QString &assetName); - bool startImportProcess(const ParseData &pd); - bool startIconProcess(int size, const QString &iconFile, const QString &iconSource); + void startNextImportProcess(); + void startNextIconProcess(); void postImport(); void finalizeQuick3DImport(); QString sourceSceneTargetFilePath(const ParseData &pd); @@ -122,12 +124,12 @@ private: bool m_cancelled = false; QString m_importPath; QTemporaryDir *m_tempDir = nullptr; - std::vector m_qmlPuppetProcesses; - int m_qmlPuppetCount = 0; - int m_qmlImportFinishedCount = 0; + QProcessUniquePointer m_puppetProcess; int m_importIdCounter = 0; + int m_currentImportId = 0; QHash m_parseData; QString m_progressTitle; QList m_requiredImports; + QList m_puppetQueue; }; } // QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index e6f2b2825e5..e1911036b53 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -126,10 +126,6 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_itemToDrag = {}; } } - } else if (event->type() == QMouseEvent::MouseButtonRelease) { - m_itemToDrag = {}; - if (model) - model->endDrag(); } return QObject::eventFilter(obj, event); @@ -147,7 +143,7 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache) , m_itemsWidget(new QQuickWidget(this)) , m_imageCache{imageCache} { - m_compressionTimer.setInterval(200); + m_compressionTimer.setInterval(1000); m_compressionTimer.setSingleShot(true); ItemLibraryModel::registerQmlTypes(); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp index d0420163c3a..49f313534d1 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp @@ -120,6 +120,11 @@ void MaterialBrowserModel::setHasModelSelection(bool b) emit hasModelSelectionChanged(); } +QList MaterialBrowserModel::materials() const +{ + return m_materialList; +} + void MaterialBrowserModel::setSearchText(const QString &searchText) { QString lowerSearchText = searchText.toLower(); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h index 32db357caeb..73e6b2f99c6 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h @@ -58,6 +58,7 @@ public: bool hasModelSelection() const; void setHasModelSelection(bool b); + QList materials() const; void setMaterials(const QList &materials, bool hasQuick3DImport); void removeMaterial(const ModelNode &material); void updateMaterialName(const ModelNode &material); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index d8c7286411f..e232f6cc08d 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -96,11 +96,19 @@ void MaterialBrowserView::modelAttached(Model *model) m_widget->clearSearchFilter(); m_hasQuick3DImport = model->hasImport("QtQuick3D"); - QTimer::singleShot(0, this, &MaterialBrowserView::refreshModel); + + // Project load is already very busy and may even trigger puppet reset, so let's wait a moment + // before refreshing the model + QTimer::singleShot(1000, this, [this]() { + refreshModel(true); + }); } -void MaterialBrowserView::refreshModel() +void MaterialBrowserView::refreshModel(bool updateImages) { + if (!model() || !model()->nodeInstanceView()) + return; + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); QList materials; @@ -114,8 +122,10 @@ void MaterialBrowserView::refreshModel() m_widget->materialBrowserModel()->setMaterials(materials, m_hasQuick3DImport); - for (const ModelNode &node : std::as_const(materials)) - model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + if (updateImages) { + for (const ModelNode &node : std::as_const(materials)) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + } } bool MaterialBrowserView::isMaterial(const ModelNode &node) const @@ -203,8 +213,12 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node, bool matRemoved = oldParentNode.isValid() && oldParentNode.id() == Constants::MATERIAL_LIB_ID; if (matAdded || matRemoved) { - refreshModel(); - + if (matAdded && !m_puppetResetPending) { + // Workaround to fix various material issues all likely caused by QTBUG-103316 + resetPuppet(); + m_puppetResetPending = true; + } + refreshModel(!matAdded); int idx = m_widget->materialBrowserModel()->materialIndex(node); m_widget->materialBrowserModel()->selectMaterial(idx); } @@ -251,7 +265,9 @@ void MaterialBrowserView::importsChanged(const QList &addedImports, cons return; m_hasQuick3DImport = hasQuick3DImport; - refreshModel(); + + // Import change will trigger puppet reset, so we don't want to update previews immediately + refreshModel(false); } void MaterialBrowserView::customNotification(const AbstractView *view, const QString &identifier, @@ -269,4 +285,22 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt } } +void MaterialBrowserView::instancesCompleted(const QVector &completedNodeList) +{ + for (const ModelNode &node : completedNodeList) { + // We use root node completion as indication of puppet reset + if (node.isRootNode()) { + m_puppetResetPending = false; + QTimer::singleShot(1000, this, [this]() { + if (!model() || !model()->nodeInstanceView()) + return; + const QList materials = m_widget->materialBrowserModel()->materials(); + for (const ModelNode &node : materials) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + }); + break; + } + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h index e140eede136..503986a28ec 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h @@ -60,14 +60,16 @@ public: void importsChanged(const QList &addedImports, const QList &removedImports) override; void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; + void instancesCompleted(const QVector &completedNodeList) override; private: - void refreshModel(); + void refreshModel(bool updateImages); bool isMaterial(const ModelNode &node) const; QPointer m_widget; bool m_hasQuick3DImport = false; bool m_autoSelectModelMaterial = false; // TODO: wire this to some action + bool m_puppetResetPending = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp index 156add5d2da..3982d534546 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,27 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event) if (event->type() == QEvent::FocusOut) { if (obj == m_quickWidget.data()) QMetaObject::invokeMethod(m_quickWidget->rootObject(), "closeContextMenu"); + } else if (event->type() == QMouseEvent::MouseMove) { + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + QTC_ASSERT(document, return false); + Model *model = document->currentModel(); + QTC_ASSERT(model, return false); + + if (m_materialToDrag.isValid()) { + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + QByteArray data; + QMimeData *mimeData = new QMimeData; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_materialToDrag.internalId(); + mimeData->setData(Constants::MIME_TYPE_MATERIAL, data); + mimeData->removeFormat("text/plain"); + + model->startDrag(mimeData, m_previewImageProvider->requestPixmap( + QString::number(m_materialToDrag.internalId()), nullptr, {128, 128})); + m_materialToDrag = {}; + } + } } return QObject::eventFilter(obj, event); @@ -166,6 +188,12 @@ void MaterialBrowserWidget::handleSearchfilterChanged(const QString &filterText) } } +void MaterialBrowserWidget::startDragMaterial(int index, const QPointF &mousePos) +{ + m_materialToDrag = m_materialBrowserModel->materialAt(index); + m_dragStartPoint = mousePos.toPoint(); +} + QString MaterialBrowserWidget::qmlSourcesPath() { #ifdef SHARE_QML_PATH diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h index f5f737007e7..30f9d05b509 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h @@ -69,6 +69,7 @@ public: void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); + Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos); QQuickWidget *quickWidget() const; @@ -86,6 +87,9 @@ private: PreviewImageProvider *m_previewImageProvider = nullptr; QString m_filterText; + + ModelNode m_materialToDrag; + QPoint m_dragStartPoint; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index aad0ea660ad..3184c718d99 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -73,52 +73,21 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F7), m_stackedWidget); connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml); + m_ensureMatLibTimer.callOnTimeout([this] { + if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation() + && model()->rewriterView()->errors().isEmpty()) { + executeInTransaction("MaterialEditorView::MaterialEditorView", [this] { + ensureMaterialLibraryNode(); + }); + m_ensureMatLibTimer.stop(); + } + }); + m_stackedWidget->setStyleSheet(Theme::replaceCssColors( QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); m_stackedWidget->setMinimumWidth(250); } -void MaterialEditorView::ensureMaterialLibraryNode() -{ - if (!m_hasQuick3DImport) - return; - - m_materialLibrary = modelNodeForId(Constants::MATERIAL_LIB_ID); - if (m_materialLibrary.isValid()) - return; - - // create material library node - TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" : "QtQuick.Item"; - NodeMetaInfo metaInfo = model()->metaInfo(nodeType); - m_materialLibrary = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion()); - - m_materialLibrary.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID); - rootModelNode().defaultNodeListProperty().reparentHere(m_materialLibrary); - - const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); - if (materials.isEmpty()) - return; - - RewriterTransaction transaction = beginRewriterTransaction( - "MaterialEditorView::ensureMaterialLibraryNode"); - - try { - // move all materials to under material library node - for (const ModelNode &node : materials) { - // if material has no name, set name to id - QString matName = node.variantProperty("objectName").value().toString(); - if (matName.isEmpty()) { - VariantProperty objNameProp = node.variantProperty("objectName"); - objNameProp.setValue(node.id()); - } - - m_materialLibrary.defaultNodeListProperty().reparentHere(node); - } - } catch (Exception &e) { - e.showException(); - } -} - MaterialEditorView::~MaterialEditorView() { qDeleteAll(m_qmlBackendHash); @@ -447,15 +416,15 @@ void MaterialEditorView::handleToolBarAction(int action) } case MaterialEditorContextObject::AddNewMaterial: { - ensureMaterialLibraryNode(); - + if (!model()) + break; executeInTransaction("MaterialEditorView:handleToolBarAction", [&] { NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), metaInfo.minorVersion()); renameMaterial(newMatNode, "New Material"); - m_materialLibrary.defaultNodeListProperty().reparentHere(newMatNode); + materialLibraryNode().defaultNodeListProperty().reparentHere(newMatNode); }); break; } @@ -567,6 +536,11 @@ void MaterialEditorView::modelAttached(Model *model) m_hasQuick3DImport = model->hasImport("QtQuick3D"); + // Creating the material library node on model attach causes errors as long as the type information + // not complete yet, so we keep checking until type info is complete. + if (m_hasQuick3DImport) + m_ensureMatLibTimer.start(500); + if (!m_setupCompleted) { reloadQml(); m_setupCompleted = true; @@ -580,8 +554,6 @@ void MaterialEditorView::modelAboutToBeDetached(Model *model) { AbstractView::modelAboutToBeDetached(model); m_qmlBackEnd->materialEditorTransaction()->end(); - - } void MaterialEditorView::propertiesRemoved(const QList &propertyList) @@ -589,6 +561,7 @@ void MaterialEditorView::propertiesRemoved(const QList &proper if (noValidSelection()) return; + bool changed = false; for (const AbstractProperty &property : propertyList) { ModelNode node(property.parentModelNode()); @@ -597,8 +570,11 @@ void MaterialEditorView::propertiesRemoved(const QList &proper if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) { setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name())); + changed = true; } } + if (changed) + requestPreviewRender(); } void MaterialEditorView::variantPropertiesChanged(const QList &propertyList, PropertyChangeFlags /*propertyChange*/) @@ -660,7 +636,7 @@ void MaterialEditorView::auxiliaryDataChanged(const ModelNode &node, const Prope // request render image for the selected material node void MaterialEditorView::requestPreviewRender() { - if (m_selectedMaterial.isValid()) + if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid()) model()->nodeInstanceView()->previewImageDataForGenericNode(m_selectedMaterial, {}); } @@ -707,6 +683,7 @@ void MaterialEditorView::instancePropertyChanged(const QList &propertyPair : propertyList) { const ModelNode modelNode = propertyPair.first; const QmlObjectNode qmlObjectNode(modelNode); @@ -718,8 +695,11 @@ void MaterialEditorView::instancePropertyChanged(const QList &addedImports, const m_hasQuick3DImport = model()->hasImport("QtQuick3D"); m_qmlBackEnd->contextObject()->setHasQuick3DImport(m_hasQuick3DImport); + if (m_hasQuick3DImport) + m_ensureMatLibTimer.start(500); + resetView(); } @@ -763,7 +746,8 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) { QTC_ASSERT(material.isValid(), return); - ensureMaterialLibraryNode(); + if (!model()) + return; TypeName matType = material.type(); QmlObjectNode sourceMat(material); @@ -790,7 +774,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression()); } - m_materialLibrary.defaultNodeListProperty().reparentHere(duplicateMat); + materialLibraryNode().defaultNodeListProperty().reparentHere(duplicateMat); }); } @@ -816,11 +800,16 @@ void MaterialEditorView::customNotification(const AbstractView *view, const QStr void QmlDesigner::MaterialEditorView::highlightSupportedProperties(bool highlight) { + if (!m_selectedMaterial.isValid()) + return; + DesignerPropertyMap &propMap = m_qmlBackEnd->backendValuesPropertyMap(); const QStringList propNames = propMap.keys(); + NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo(); + QTC_ASSERT(metaInfo.isValid(), return); for (const QString &propName : propNames) { - if (propName.endsWith("Map")) { + if (metaInfo.propertyTypeName(propName.toLatin1()) == "QtQuick3D.Texture") { QObject *propEditorValObj = propMap.value(propName).value(); PropertyEditorValue *propEditorVal = qobject_cast(propEditorValObj); propEditorVal->setHasActiveDrag(highlight); @@ -852,7 +841,6 @@ void MaterialEditorView::setValue(const QmlObjectNode &qmlObjectNode, const Prop { m_locked = true; m_qmlBackEnd->setValue(qmlObjectNode, name, value); - requestPreviewRender(); m_locked = false; } diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index 3e8632d26f6..ff734ed30b8 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -99,7 +99,6 @@ private: void highlightSupportedProperties(bool highlight = true); QString generateIdFromName(const QString &name); - void ensureMaterialLibraryNode(); void requestPreviewRender(); void applyMaterialToSelectedModels(const ModelNode &material, bool add = false); @@ -115,7 +114,7 @@ private: bool noValidSelection() const; ModelNode m_selectedMaterial; - ModelNode m_materialLibrary; + QTimer m_ensureMatLibTimer; QShortcut *m_updateShortcut = nullptr; int m_timerId = 0; QStackedWidget *m_stackedWidget = nullptr; diff --git a/src/plugins/qmldesigner/components/navigator/checkers.png b/src/plugins/qmldesigner/components/navigator/checkers.png new file mode 100644 index 00000000000..72cb9f03506 Binary files /dev/null and b/src/plugins/qmldesigner/components/navigator/checkers.png differ diff --git a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp index 00987711c56..178f79e18a3 100644 --- a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp +++ b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp @@ -56,6 +56,8 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i // ParticleAbstractShape3D // -> ParticleEmitter3D // -> Attractor3D + // Material + // -> Model const TypeName textureType = "QtQuick3D.Texture"; if (insertInfo.isSubclassOf(textureType)) { @@ -104,6 +106,9 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i if (parentInfo.isSubclassOf("QtQuick3D.Particles3D.ParticleEmitter3D") || parentInfo.isSubclassOf("QtQuick3D.Particles3D.Attractor3D")) propertyList.append("shape"); + } else if (insertInfo.isSubclassOf("QtQuick3D.Material")) { + if (parentInfo.isSubclassOf("QtQuick3D.Particles3D.Model")) + propertyList.append("materials"); } } diff --git a/src/plugins/qmldesigner/components/navigator/navigator.qrc b/src/plugins/qmldesigner/components/navigator/navigator.qrc index fca836a09be..e595bae0f9b 100644 --- a/src/plugins/qmldesigner/components/navigator/navigator.qrc +++ b/src/plugins/qmldesigner/components/navigator/navigator.qrc @@ -13,5 +13,6 @@ export_unchecked.png export_unchecked@2x.png tooltip_placeholder.png + checkers.png diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 0a92f81d93f..d347854f004 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -464,6 +464,7 @@ QStringList NavigatorTreeModel::mimeTypes() const { const static QStringList types({Constants::MIME_TYPE_MODELNODE_LIST, Constants::MIME_TYPE_ITEM_LIBRARY_INFO, + Constants::MIME_TYPE_MATERIAL, Constants::MIME_TYPE_ASSETS}); return types; @@ -559,6 +560,8 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, if (dropModelIndex.model() == this) { if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) { handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex); + } else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + handleMaterialDrop(mimeData, rowNumber, dropModelIndex); } else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) { const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(','); NodeAbstractProperty targetProperty; @@ -686,18 +689,20 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in bool validContainer = false; ModelNode targetNode = targetProperty.parentModelNode(); - // don't allow dropping materials on any node but Models - QString itemType = QString::fromLatin1(itemLibraryEntry.typeName()); - if (itemType.startsWith("QtQuick3D.") && itemType.endsWith("Material") - && !targetNode.isSubclassOf("QtQuick3D.Model")) { - return; - } - QmlObjectNode newQmlObjectNode; m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryItemDrop", [&] { newQmlObjectNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, QPointF(), targetProperty, false); ModelNode newModelNode = newQmlObjectNode.modelNode(); if (newModelNode.isValid()) { + if (newModelNode.isSubclassOf("QtQuick3D.Material")) { + // Don't allow dropping materials on any node but Models + if (!targetNode.isSubclassOf("QtQuick3D.Model")) { + newQmlObjectNode.destroy(); + return; + } + m_view->assignMaterialTo3dModel(targetNode, newModelNode); + } + ChooseFromPropertyListDialog *dialog = ChooseFromPropertyListDialog::createIfNeeded( targetNode, newModelNode, Core::ICore::dialogParent()); if (dialog) { @@ -734,28 +739,10 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in if (newModelNode.isSubclassOf("QtQuick3D.View3D")) { const QList models = newModelNode.subModelNodesOfType("QtQuick3D.Model"); - QTC_ASSERT(models.size() == 1, return); - - assignMaterialToModel(models.at(0)); + m_view->assignMaterialTo3dModel(models.at(0)); } else if (newModelNode.isSubclassOf("QtQuick3D.Model")) { - assignMaterialToModel(newModelNode); - } - - // dropping a material on a model - if (newModelNode.isSubclassOf("QtQuick3D.Material") - && targetNode.isSubclassOf("QtQuick3D.Model")) { - // parent material to material library and assign it to target model - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - - QTC_ASSERT(matLib.isValid(), return); - - VariantProperty objName = newModelNode.variantProperty("objectName"); - objName.setValue("New Material"); - BindingProperty matsProp = targetNode.bindingProperty("materials"); - matsProp.setExpression(newModelNode.id()); - matLib.defaultNodeListProperty().reparentHere(newModelNode); - return; + m_view->assignMaterialTo3dModel(newModelNode); } if (!validContainer) { @@ -795,6 +782,33 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in } } +void NavigatorTreeModel::handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex) +{ + QTC_ASSERT(m_view, return); + + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + int targetRowNumber = rowNumber; + NodeAbstractProperty targetProperty; + + bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber, "materials"); + if (!foundTarget) + return; + + ModelNode targetNode = targetProperty.parentModelNode(); + if (!targetNode.isSubclassOf("QtQuick3D.Model")) + return; + + QByteArray data = mimeData->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = m_view->modelNodeForInternalId(internalId); + + m_view->executeInTransaction(__FUNCTION__, [&] { + m_view->assignMaterialTo3dModel(targetNode, matNode); + }); +} + ModelNode NavigatorTreeModel::handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty, const QModelIndex &rowModelIndex, @@ -1089,40 +1103,6 @@ ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targ return {}; } -// Add a material to a Quick3D.Model node -void NavigatorTreeModel::assignMaterialToModel(const ModelNode &node) -{ - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - - QTC_ASSERT(matLib.isValid(), return); - QTC_ASSERT(node.isSubclassOf("QtQuick3D.Model"), return); - - const QList materials = matLib.directSubModelNodes(); - ModelNode material; - if (materials.size() > 0) { - for (const ModelNode &mat : materials) { - if (mat.isSubclassOf("QtQuick3D.Material")) { - material = mat; - break; - } - } - } - - // if no valid material, create a new default material - if (!material.isValid()) { - NodeMetaInfo metaInfo = m_view->model()->metaInfo("QtQuick3D.DefaultMaterial"); - material = m_view->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), - metaInfo.minorVersion()); - VariantProperty matNameProp = material.variantProperty("objectName"); - matNameProp.setValue("New Material"); - material.validId(); - matLib.defaultNodeListProperty().reparentHere(material); - } - - BindingProperty modelMatsProp = node.bindingProperty("materials"); - modelMatsProp.setExpression(material.id()); -} - TypeName propertyType(const NodeAbstractProperty &property) { return property.parentModelNode().metaInfo().propertyTypeName(property.name()); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 0fcb7aab3eb..153491bfc14 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -115,6 +115,7 @@ private: int targetIndex, bool executeInTransaction = true); void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); + void handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); ModelNode handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty, const QModelIndex &rowModelIndex, bool &outMoveNodesAfter); ModelNode handleItemLibraryFontDrop(const QString &fontFamily, NodeAbstractProperty targetProperty, @@ -130,7 +131,6 @@ private: bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp, const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter); ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath); - void assignMaterialToModel(const ModelNode &node); QList nodesToPersistentIndex(const QList &modelNodes); void addImport(const QString &importName); QList filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const; diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index 3adfc91781d..cc3934b6289 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -275,6 +275,15 @@ void NavigatorView::dragStarted(QMimeData *mimeData) m_widget->setDragType(itemLibraryEntry.typeName()); m_widget->update(); + } else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + QByteArray data = mimeData->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = modelNodeForInternalId(internalId); + + m_widget->setDragType(matNode.metaInfo().typeName()); + m_widget->update(); } } diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp index 800104bfb30..b352f1daa21 100644 --- a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp @@ -28,7 +28,8 @@ #include -#include +#include +#include namespace QmlDesigner { @@ -43,6 +44,17 @@ PreviewToolTip::PreviewToolTip(QWidget *parent) m_ui->typeLabel->setElideMode(Qt::ElideLeft); m_ui->infoLabel->setElideMode(Qt::ElideLeft); setStyleSheet(QString("QWidget { background-color: %1 }").arg(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal).name())); + m_ui->imageLabel->setStyleSheet("background-color: rgba(0, 0, 0, 0)"); + + static QPixmap checkers; + if (checkers.isNull()) { + checkers = {150, 150}; + QPainter painter(&checkers); + painter.setBrush(QPixmap(":/navigator/icon/checkers.png")); + painter.drawRect(0, 0, 150, 150); + } + m_ui->labelBackground->setPixmap(checkers); + } PreviewToolTip::~PreviewToolTip() diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.ui b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui index 1c06a248f03..c8520751a8e 100644 --- a/src/plugins/qmldesigner/components/navigator/previewtooltip.ui +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui @@ -81,28 +81,72 @@ 6 - - - - 0 - 0 - - - - - 150 - 150 - - - - QFrame::Box - - - QFrame::Plain - - - Qt::AlignCenter - + + + + + 0 + 0 + 150 + 150 + + + + + 0 + 0 + + + + + 150 + 150 + + + + QFrame::Box + + + QFrame::Plain + + + false + + + Qt::AlignCenter + + + + + + 0 + 0 + 150 + 150 + + + + + 0 + 0 + + + + + 150 + 150 + + + + QFrame::Box + + + QFrame::Plain + + + Qt::AlignCenter + + diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp index e15ff49744e..18fcba3efc2 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp @@ -29,11 +29,11 @@ #include -#include #include +#include -#include #include +#include #include #include @@ -46,11 +46,13 @@ FileResourcesModel::FileResourcesModel(QObject *parent) , m_filter(QLatin1String("(*.*)")) { ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( - QmlDesigner::DocumentManager::currentFilePath()); + QmlDesigner::DocumentManager::currentFilePath()); if (project) { - connect(project, &ProjectExplorer::Project::fileListChanged, - this, &FileResourcesModel::refreshModel); + connect(project, + &ProjectExplorer::Project::fileListChanged, + this, + &FileResourcesModel::refreshModel); } } @@ -58,14 +60,14 @@ void FileResourcesModel::setModelNodeBackend(const QVariant &modelNodeBackend) { auto modelNodeBackendObject = modelNodeBackend.value(); - const auto backendObjectCasted = - qobject_cast(modelNodeBackendObject); + const auto backendObjectCasted = qobject_cast( + modelNodeBackendObject); if (backendObjectCasted) { QmlDesigner::Model *model = backendObjectCasted->qmlObjectNode().modelNode().model(); m_docPath = QDir{QFileInfo{model->fileUrl().toLocalFile()}.absolutePath()}; - m_path = QUrl::fromLocalFile(QmlDesigner::DocumentManager::currentProjectDirPath() - .toFileInfo().absoluteFilePath()); + m_path = QUrl::fromLocalFile( + QmlDesigner::DocumentManager::currentProjectDirPath().toFileInfo().absoluteFilePath()); } setupModel(); @@ -96,6 +98,8 @@ void FileResourcesModel::setPath(const QUrl &url) { m_path = url; setupModel(); + + emit pathChanged(url); } QUrl FileResourcesModel::path() const @@ -110,10 +114,13 @@ QUrl FileResourcesModel::docPath() const void FileResourcesModel::setFilter(const QString &filter) { - if (m_filter != filter) { - m_filter = filter; - setupModel(); - } + if (m_filter == filter) + return; + + m_filter = filter; + setupModel(); + + emit filterChanged(filter); } QString FileResourcesModel::filter() const @@ -121,14 +128,9 @@ QString FileResourcesModel::filter() const return m_filter; } -QStringList FileResourcesModel::fullPathModel() const +QList FileResourcesModel::model() const { - return m_fullPathModel; -} - -QStringList FileResourcesModel::fileNameModel() const -{ - return m_fileNameModel; + return m_model; } void FileResourcesModel::openFileDialog() @@ -164,6 +166,25 @@ void FileResourcesModel::openFileDialog() } } +QString FileResourcesModel::resolve(const QString &relative) const +{ + if (relative.startsWith('#')) + return relative; + + if (QDir::isAbsolutePath(relative)) + return relative; + + if (!QUrl::fromUserInput(relative, m_docPath.path()).isLocalFile()) + return relative; + + return QFileInfo(m_docPath, relative).absoluteFilePath(); +} + +bool FileResourcesModel::isLocal(const QString &path) const +{ + return QUrl::fromUserInput(path, m_docPath.path()).isLocalFile(); +} + void FileResourcesModel::registerDeclarativeType() { qmlRegisterType("HelperWidgets", 2, 0, "FileResourcesModel"); @@ -207,8 +228,7 @@ void FileResourcesModel::setupModel() void FileResourcesModel::refreshModel() { - m_fullPathModel.clear(); - m_fileNameModel.clear(); + m_model.clear(); QStringList filterList = m_filter.split(QLatin1Char(' ')); @@ -216,18 +236,17 @@ void FileResourcesModel::refreshModel() while (it.hasNext()) { QString absolutePath = it.next(); if (filterMetaIcons(absolutePath)) { - QString filePath = m_docPath.relativeFilePath(absolutePath); - m_fullPathModel.append(filePath); + QString relativeFilePath = m_docPath.relativeFilePath(absolutePath); + m_model.append( + FileResourcesItem(absolutePath, + relativeFilePath, + relativeFilePath.mid(relativeFilePath.lastIndexOf('/') + 1))); } } - Utils::sort(m_fullPathModel, [](const QString &s1, const QString &s2) { - return s1.mid(s1.lastIndexOf('/') + 1).toLower() < s2.mid(s2.lastIndexOf('/') + 1).toLower(); + Utils::sort(m_model, [](const FileResourcesItem &i1, const FileResourcesItem &i2) { + return i1.fileName().toLower() < i2.fileName().toLower(); }); - for (const QString &fullPath : qAsConst(m_fullPathModel)) - m_fileNameModel.append(fullPath.mid(fullPath.lastIndexOf('/') + 1)); - - emit fullPathModelChanged(); - emit fileNameModelChanged(); + emit modelChanged(); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h index f0380c5a52e..5f49c936cb7 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h @@ -33,17 +33,47 @@ #include #include +class FileResourcesItem +{ + Q_GADGET + + Q_PROPERTY(QString absoluteFilePath READ absoluteFilePath CONSTANT) + Q_PROPERTY(QString relativeFilePath READ relativeFilePath CONSTANT) + Q_PROPERTY(QString fileName READ fileName CONSTANT) + +public: + FileResourcesItem(const QString &absoluteFilePath, + const QString &relativeFilePath, + const QString &fileName) + : m_absoluteFilePath(absoluteFilePath) + , m_relativeFilePath(relativeFilePath) + , m_fileName(fileName) + {} + + FileResourcesItem() = default; + FileResourcesItem(const FileResourcesItem &other) = default; + FileResourcesItem &operator=(const FileResourcesItem &other) = default; + + const QString &absoluteFilePath() const { return m_absoluteFilePath; } + const QString &relativeFilePath() const { return m_relativeFilePath; } + const QString &fileName() const { return m_fileName; } + +private: + QString m_absoluteFilePath; + QString m_relativeFilePath; + QString m_fileName; +}; + class FileResourcesModel : public QObject { Q_OBJECT Q_PROPERTY(QString fileName READ fileName WRITE setFileNameStr NOTIFY fileNameChanged) - Q_PROPERTY(QString filter READ filter WRITE setFilter) + Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) - Q_PROPERTY(QUrl path READ path WRITE setPath) - Q_PROPERTY(QUrl docPath READ docPath) - Q_PROPERTY(QStringList fullPathModel READ fullPathModel NOTIFY fullPathModelChanged) - Q_PROPERTY(QStringList fileNameModel READ fileNameModel NOTIFY fileNameModelChanged) + Q_PROPERTY(QUrl path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(QUrl docPath READ docPath CONSTANT) + Q_PROPERTY(QList model READ model NOTIFY modelChanged) public: explicit FileResourcesModel(QObject *parent = nullptr); @@ -57,20 +87,23 @@ public: QUrl docPath() const; void setFilter(const QString &filter); QString filter() const; - QStringList fullPathModel() const; - QStringList fileNameModel() const; + QList model() const; + void setupModel(); void refreshModel(); Q_INVOKABLE void openFileDialog(); + Q_INVOKABLE QString resolve(const QString &relative) const; + Q_INVOKABLE bool isLocal(const QString &path) const; static void registerDeclarativeType(); signals: void fileNameChanged(const QUrl &fileName); + void filterChanged(const QString &filte); void modelNodeBackendChanged(); - void fullPathModelChanged(); - void fileNameModelChanged(); + void pathChanged(const QUrl &path); + void modelChanged(); private: QVariant modelNodeBackend() const; @@ -83,8 +116,7 @@ private: QString m_filter; QString m_currentPath; QString m_lastResourcePath; - QStringList m_fullPathModel; - QStringList m_fileNameModel; + QList m_model; }; QML_DECLARE_TYPE(FileResourcesModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index 3a9a138b2a3..8ba1325efaf 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -322,6 +322,19 @@ void PropertyEditorContextObject::insertKeyframe(const QString &propertyName) }); } +QString PropertyEditorContextObject::activeDragSuffix() const +{ + return m_activeDragSuffix; +} + +void PropertyEditorContextObject::setActiveDragSuffix(const QString &suffix) +{ + if (m_activeDragSuffix != suffix) { + m_activeDragSuffix = suffix; + emit activeDragSuffixChanged(); + } +} + int PropertyEditorContextObject::majorVersion() const { return m_majorVersion; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h index 6a3e410c8a1..f5a2224c8b7 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h @@ -56,6 +56,8 @@ class PropertyEditorContextObject : public QObject Q_PROPERTY(int majorQtQuickVersion READ majorQtQuickVersion WRITE setMajorQtQuickVersion NOTIFY majorQtQuickVersionChanged) Q_PROPERTY(int minorQtQuickVersion READ minorQtQuickVersion WRITE setMinorQtQuickVersion NOTIFY minorQtQuickVersionChanged) + Q_PROPERTY(QString activeDragSuffix READ activeDragSuffix NOTIFY activeDragSuffixChanged) + Q_PROPERTY(bool hasAliasExport READ hasAliasExport NOTIFY hasAliasExportChanged) Q_PROPERTY(bool hasActiveTimeline READ hasActiveTimeline NOTIFY hasActiveTimelineChanged) @@ -102,6 +104,9 @@ public: Q_INVOKABLE bool isBlocked(const QString &propName) const; + QString activeDragSuffix() const; + void setActiveDragSuffix(const QString &suffix); + int majorVersion() const; int majorQtQuickVersion() const; int minorQtQuickVersion() const; @@ -134,6 +139,7 @@ signals: void specificQmlComponentChanged(); void hasAliasExportChanged(); void hasActiveTimelineChanged(); + void activeDragSuffixChanged(); public slots: @@ -182,6 +188,8 @@ private: bool m_aliasExport = false; bool m_setHasActiveTimeline = false; + + QString m_activeDragSuffix; }; class EasingCurveEditor : public QObject diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp new file mode 100644 index 00000000000..2037e1509e9 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "propertyeditorimageprovider.h" +#include "assetslibrarymodel.h" + +#include +#include +#include + +#include +#include + +namespace QmlDesigner { + +QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QString &id, + const QSize &requestedSize) +{ + const QString suffix = "*." + id.split('.').last().toLower(); + + if (suffix == "*.mesh") + return m_smallImageCacheProvider.requestImageResponse(id, requestedSize); + + if (suffix == "*.builtin") + return m_smallImageCacheProvider.requestImageResponse("#" + id.split('.').first(), + requestedSize); + + QImage image; + auto response = std::make_unique(image); + + QMetaObject::invokeMethod( + response.get(), + [response = QPointer(response.get()), image, suffix, id] { + if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) + response->setImage(QImage(Utils::StyleHelper::dpiSpecificImageFile(id))); + else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) + response->setImage(HdrImage{id}.image()); + else + response->abort(); + }, + Qt::QueuedConnection); + + return response.release(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h new file mode 100644 index 00000000000..bb883e44504 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include "imagecache/smallimagecacheprovider.h" + +#include + +namespace QmlDesigner { + +class PropertyEditorImageProvider : public QQuickAsyncImageProvider +{ +public: + PropertyEditorImageProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {}) + : m_smallImageCacheProvider(imageCache, defaultImage) + {} + + QQuickImageResponse *requestImageResponse(const QString &id, + const QSize &requestedSize) override; + +private: + SmallImageCacheProvider m_smallImageCacheProvider; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 8026fc7d6f1..c3e201bf1d9 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -95,9 +95,12 @@ static QObject *variantToQObject(const QVariant &value) namespace QmlDesigner { -PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor) : - m_view(new Quick2PropertyEditorView), m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor)), m_dummyPropertyEditorValue(new PropertyEditorValue()), - m_contextObject(new PropertyEditorContextObject()) +PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor, + AsynchronousImageCache &imageCache) + : m_view(new Quick2PropertyEditorView(imageCache)) + , m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor)) + , m_dummyPropertyEditorValue(new PropertyEditorValue()) + , m_contextObject(new PropertyEditorContextObject()) { m_view->engine()->setOutputWarningsToStandardError(QmlDesignerPlugin::instance() ->settings().value(DesignerSettingsKey::SHOW_PROPERTYEDITOR_WARNINGS).toBool()); @@ -115,7 +118,9 @@ PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyE PropertyEditorQmlBackend::~PropertyEditorQmlBackend() = default; -void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name, PropertyEditorView *propertyEditor, const QString &type) +void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name, + PropertyEditorView *propertyEditor, + const QString &type) { QmlDesigner::PropertyName propertyName(name); propertyName.replace('.', '_'); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h index 983a917f2fd..7abfc550d87 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h @@ -50,7 +50,8 @@ class PropertyEditorQmlBackend public: - PropertyEditorQmlBackend(PropertyEditorView *propertyEditor); + PropertyEditorQmlBackend(PropertyEditorView *propertyEditor, + class AsynchronousImageCache &imageCache); ~PropertyEditorQmlBackend(); void setup(const QmlObjectNode &fxObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 6ea079b6f16..c68db4c57f7 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -518,14 +518,15 @@ bool PropertyEditorValue::idListReplace(int idx, const QString &value) void PropertyEditorValue::commitDrop(const QString &path) { - if (m_modelNode.isSubclassOf("QtQuick3D.Material") && nameAsQString().endsWith("Map")) { + if (m_modelNode.isSubclassOf("QtQuick3D.Material") + && m_modelNode.metaInfo().propertyTypeName(m_name) == "QtQuick3D.Texture") { // create a texture node QmlDesigner::NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo("QtQuick3D.Texture"); QmlDesigner::ModelNode texture = m_modelNode.view()->createModelNode("QtQuick3D.Texture", metaInfo.majorVersion(), metaInfo.minorVersion()); texture.validId(); - modelNode().view()->rootModelNode().defaultNodeListProperty().reparentHere(texture); + m_modelNode.view()->rootModelNode().defaultNodeListProperty().reparentHere(texture); // TODO: group textures under 1 node (just like materials) // set texture source @@ -537,6 +538,8 @@ void PropertyEditorValue::commitDrop(const QString &path) // assign the texture to the property setExpressionWithEmit(texture.id()); } + + m_modelNode.view()->model()->endDrag(); } QStringList PropertyEditorValue::generateStringList(const QString &string) const diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 4f3859d00d7..fb1be16dc73 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -26,8 +26,8 @@ #include "propertyeditorview.h" #include "propertyeditorqmlbackend.h" -#include "propertyeditorvalue.h" #include "propertyeditortransaction.h" +#include "propertyeditorvalue.h" #include #include @@ -70,16 +70,16 @@ static bool propertyIsAttachedLayoutProperty(const PropertyName &propertyName) return propertyName.contains("Layout."); } -PropertyEditorView::PropertyEditorView(QWidget *parent) : - AbstractView(parent), - m_parent(parent), - m_updateShortcut(nullptr), - m_timerId(0), - m_stackedWidget(new PropertyEditorWidget(parent)), - m_qmlBackEndForCurrentType(nullptr), - m_locked(false), - m_setupCompleted(false), - m_singleShotTimer(new QTimer(this)) +PropertyEditorView::PropertyEditorView(AsynchronousImageCache &imageCache) + : AbstractView() + , m_imageCache(imageCache) + , m_updateShortcut(nullptr) + , m_timerId(0) + , m_stackedWidget(new PropertyEditorWidget()) + , m_qmlBackEndForCurrentType(nullptr) + , m_locked(false) + , m_setupCompleted(false) + , m_singleShotTimer(new QTimer(this)) { m_qmlDir = PropertyEditorQmlBackend::propertyEditorResourcesPath(); @@ -118,7 +118,7 @@ void PropertyEditorView::setupPane(const TypeName &typeName) PropertyEditorQmlBackend *qmlBackend = m_qmlBackendHash.value(qmlFile.toString()); if (!qmlBackend) { - qmlBackend = new PropertyEditorQmlBackend(this); + qmlBackend = new PropertyEditorQmlBackend(this, m_imageCache); qmlBackend->initialSetup(typeName, qmlSpecificsFile, this); qmlBackend->setSource(qmlFile); @@ -486,7 +486,7 @@ void PropertyEditorView::setupQmlBackend() QString currentStateName = currentState().isBaseState() ? currentState().name() : QStringLiteral("invalid state"); if (!currentQmlBackend) { - currentQmlBackend = new PropertyEditorQmlBackend(this); + currentQmlBackend = new PropertyEditorQmlBackend(this, m_imageCache); m_stackedWidget->addWidget(currentQmlBackend->widget()); m_qmlBackendHash.insert(qmlFile.toString(), currentQmlBackend); @@ -852,7 +852,26 @@ void PropertyEditorView::nodeReparented(const ModelNode &node, m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(m_selectedNode)); } -void PropertyEditorView::setValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value) +void PropertyEditorView::dragStarted(QMimeData *mimeData) +{ + if (!mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) + return; + + const QString assetPath = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)) + .split(',')[0]; + const QString suffix = "*." + assetPath.split('.').last().toLower(); + + m_qmlBackEndForCurrentType->contextObject()->setActiveDragSuffix(suffix); +} + +void PropertyEditorView::dragEnded() +{ + m_qmlBackEndForCurrentType->contextObject()->setActiveDragSuffix(""); +} + +void PropertyEditorView::setValue(const QmlObjectNode &qmlObjectNode, + const PropertyName &name, + const QVariant &value) { m_locked = true; m_qmlBackEndForCurrentType->setValue(qmlObjectNode, name, value); @@ -871,6 +890,4 @@ void PropertyEditorView::reloadQml() resetView(); } - -} //QmlDesigner - +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 06e86fd57cd..09d6dc7f419 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -51,7 +51,7 @@ class PropertyEditorView: public AbstractView Q_OBJECT public: - PropertyEditorView(QWidget *parent = nullptr); + PropertyEditorView(class AsynchronousImageCache &imageCache); ~PropertyEditorView() override; bool hasWidget() const override; @@ -87,6 +87,9 @@ public: const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; + void dragStarted(QMimeData *mimeData) override; + void dragEnded() override; + void changeValue(const QString &name); void changeExpression(const QString &name); void exportPropertyAsAlias(const QString &name); @@ -119,8 +122,8 @@ private: //functions bool noValidSelection() const; private: //variables + AsynchronousImageCache &m_imageCache; ModelNode m_selectedNode; - QWidget *m_parent; QShortcut *m_updateShortcut; int m_timerId; PropertyEditorWidget* m_stackedWidget; diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp index 35b74111d1e..08358353c10 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp @@ -36,6 +36,7 @@ #include "gradientpresetdefaultlistmodel.h" #include "itemfiltermodel.h" #include "propertyeditorcontextobject.h" +#include "propertyeditorimageprovider.h" #include "propertyeditorqmlbackend.h" #include "propertyeditorvalue.h" #include "qmlanchorbindingproxy.h" @@ -45,11 +46,13 @@ namespace QmlDesigner { -Quick2PropertyEditorView::Quick2PropertyEditorView(QWidget *parent) : - QQuickWidget(parent) +Quick2PropertyEditorView::Quick2PropertyEditorView(AsynchronousImageCache &imageCache) + : QQuickWidget() { setResizeMode(QQuickWidget::SizeRootObjectToView); Theme::setupTheme(engine()); + engine()->addImageProvider("qmldesigner_thumbnails", + new PropertyEditorImageProvider(imageCache)); } void Quick2PropertyEditorView::registerQmlTypes() diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h index 7bfc6f15580..ca92f2a6efd 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h @@ -35,7 +35,7 @@ class Quick2PropertyEditorView : public QQuickWidget Q_OBJECT public: - explicit Quick2PropertyEditorView(QWidget *parent = nullptr); + explicit Quick2PropertyEditorView(class AsynchronousImageCache &imageCache); static void registerQmlTypes(); }; diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp index efec8afd9c7..077a6e14c36 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -258,12 +259,7 @@ void TextEditorView::gotoCursorPosition(int line, int column) void TextEditorView::reformatFile() { - int oldLine = -1; - - if (m_widget) - oldLine = m_widget->currentLine(); - - QByteArray editorState = m_widget->textEditor()->saveState(); + QTC_ASSERT(!m_widget.isNull(), return); auto document = qobject_cast(Core::EditorManager::currentDocument()); @@ -292,16 +288,21 @@ void TextEditorView::reformatFile() return; const QString &newText = QmlJS::reformat(currentDocument); - QTextCursor tc(document->document()); + if (currentDocument->source() == newText) + return; + + QTextCursor tc = m_widget->textEditor()->textCursor(); + int pos = m_widget->textEditor()->textCursor().position(); Utils::ChangeSet changeSet; changeSet.replace(0, document->plainText().length(), newText); + + tc.beginEditBlock(); changeSet.apply(&tc); + tc.setPosition(pos); + tc.endEditBlock(); - m_widget->textEditor()->restoreState(editorState); - - if (m_widget) - m_widget->gotoCursorPosition(oldLine, 0); + m_widget->textEditor()->setTextCursor(tc); } } diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp index 82dcb44d850..09e9b9f05a3 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp @@ -251,50 +251,54 @@ ModelNode TransitionEditorView::addNewTransition() if (!idPropertyList.isEmpty()) { executeInTransaction( - " TransitionEditorView::addNewTransition", [&transition, idPropertyList, root, this]() { - transition = createModelNode("QtQuick.Transition", - 2, - 0, - {{ - "from", - "*", - }, - { - "to", - "*", - }}); - transition.setAuxiliaryData("transitionDuration", 2000); - transition.validId(); - root.nodeListProperty("transitions").reparentHere(transition); + " TransitionEditorView::addNewTransition", [&transition, idPropertyList, root, this]() { - for (auto it = idPropertyList.cbegin(); it != idPropertyList.cend(); ++it) { - ModelNode parallelAnimation = createModelNode("QtQuick.ParallelAnimation", - 2, - 12); - transition.defaultNodeAbstractProperty().reparentHere(parallelAnimation); - for (const QString &property : it.value()) { - ModelNode sequentialAnimation - = createModelNode("QtQuick.SequentialAnimation", 2, 12); - parallelAnimation.defaultNodeAbstractProperty().reparentHere( - sequentialAnimation); + const NodeMetaInfo transitionMetaInfo = model()->metaInfo("QtQuick.Transition"); + transition = createModelNode("QtQuick.Transition", + transitionMetaInfo.majorVersion(), + transitionMetaInfo.minorVersion(), + {{ + "from", + "*", + }, + { + "to", + "*", + }}); + transition.setAuxiliaryData("transitionDuration", 2000); + transition.validId(); + root.nodeListProperty("transitions").reparentHere(transition); - ModelNode pauseAnimation = createModelNode("QtQuick.PauseAnimation", - 2, - 12, - {{"duration", 50}}); - sequentialAnimation.defaultNodeAbstractProperty().reparentHere( - pauseAnimation); + for (auto it = idPropertyList.cbegin(); it != idPropertyList.cend(); ++it) { + ModelNode parallelAnimation = createModelNode("QtQuick.ParallelAnimation"); + transition.defaultNodeAbstractProperty().reparentHere(parallelAnimation); + for (const QString &property : it.value()) { + ModelNode sequentialAnimation + = createModelNode("QtQuick.SequentialAnimation"); + parallelAnimation.defaultNodeAbstractProperty().reparentHere( + sequentialAnimation); - ModelNode propertyAnimation = createModelNode("QtQuick.PropertyAnimation", - 2, - 12, - {{"property", property}, - {"duration", 150}}); - propertyAnimation.bindingProperty("target").setExpression(it.key()); - sequentialAnimation.defaultNodeAbstractProperty().reparentHere( - propertyAnimation); - } + const NodeMetaInfo pauseMetaInfo = model()->metaInfo("QtQuick.PauseAnimation"); + + ModelNode pauseAnimation = createModelNode("QtQuick.PauseAnimation", + pauseMetaInfo.majorVersion(), + pauseMetaInfo.minorVersion(), + {{"duration", 50}}); + sequentialAnimation.defaultNodeAbstractProperty().reparentHere( + pauseAnimation); + + const NodeMetaInfo propertyMetaInfo = model()->metaInfo("QtQuick.PauseAnimation"); + + ModelNode propertyAnimation = createModelNode("QtQuick.PropertyAnimation", + propertyMetaInfo.majorVersion(), + propertyMetaInfo.minorVersion(), + {{"property", property}, + {"duration", 150}}); + propertyAnimation.bindingProperty("target").setExpression(it.key()); + sequentialAnimation.defaultNodeAbstractProperty().reparentHere( + propertyAnimation); } + } }); } else { QString properties; diff --git a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp index d94221f3826..57a96f1c1c1 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp @@ -30,12 +30,12 @@ #include #include -namespace QmlDesigner { +namespace { -class ImageRespose : public QQuickImageResponse +class ImageResponse : public QQuickImageResponse { public: - ImageRespose(const QImage &defaultImage) + ImageResponse(const QImage &defaultImage) : m_image(defaultImage) {} @@ -57,14 +57,18 @@ private: QImage m_image; }; +} // namespace + +namespace QmlDesigner { + QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const QString &id, const QSize &) { - auto response = std::make_unique(m_defaultImage); + auto response = std::make_unique<::ImageResponse>(m_defaultImage); m_cache.requestImage( id, - [response = QPointer(response.get())](const QImage &image) { + [response = QPointer<::ImageResponse>(response.get())](const QImage &image) { QMetaObject::invokeMethod( response, [response, image] { @@ -73,7 +77,7 @@ QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const }, Qt::QueuedConnection); }, - [response = QPointer(response.get())](ImageCache::AbortReason abortReason) { + [response = QPointer<::ImageResponse>(response.get())](ImageCache::AbortReason abortReason) { QMetaObject::invokeMethod( response, [response, abortReason] { diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index 429ca328afd..0a225d1ab09 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -96,11 +96,11 @@ void ImageCacheCollector::start(Utils::SmallStringView name, model->setRewriterView(&rewriterView); - bool is3DRoot = !rewriterView.inErrorState() + bool is3DRoot = rewriterView.errors().isEmpty() && (rewriterView.rootModelNode().isSubclassOf("QtQuick3D.Node") || rewriterView.rootModelNode().isSubclassOf("QtQuick3D.Material")); - if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() + if (!rewriterView.errors().isEmpty() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() && !is3DRoot)) { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed); diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp new file mode 100644 index 00000000000..7602ee7a119 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "meshimagecachecollector.h" +#include "imagecacheconnectionmanager.h" + +#include +#include +#include + +#include + +namespace QmlDesigner { + +MeshImageCacheCollector::MeshImageCacheCollector( + ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, + ImageCacheCollectorNullImageHandling nullImageHandling) + : m_imageCacheCollector(connectionManager, + captureImageMinimumSize, + captureImageMaximumSize, + nullImageHandling) +{} + +MeshImageCacheCollector::~MeshImageCacheCollector() = default; + +void MeshImageCacheCollector::start(Utils::SmallStringView name, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData, + CaptureCallback captureCallback, + AbortCallback abortCallback) +{ + QTemporaryFile file(QDir::tempPath() + "/mesh-XXXXXX.qml"); + if (file.open()) { + QString qtQuickVersion; + QString qtQuick3DVersion; + QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit()); + if (qtVersion && qtVersion->qtVersion() < QtSupport::QtVersionNumber(6, 0, 0)) { + qtQuickVersion = "2.15"; + qtQuick3DVersion = "1.15"; + } + + QString content{ + R"(import QtQuick %1 + import QtQuick3D %2 + Node { + Model { + source: "%3" + DefaultMaterial { id: defaultMaterial; diffuseColor: "#ff999999" } + materials: [ defaultMaterial ] + } + })"}; + + content = content.arg(qtQuickVersion, qtQuick3DVersion, QString(name)); + + file.write(content.toUtf8()); + file.close(); + } + + Utils::PathString path{file.fileName()}; + + m_imageCacheCollector.start(path, state, auxiliaryData, captureCallback, abortCallback); +} + +std::pair MeshImageCacheCollector::createImage(Utils::SmallStringView, + Utils::SmallStringView, + const ImageCache::AuxiliaryData &) +{ + return {}; +} + +QIcon MeshImageCacheCollector::createIcon(Utils::SmallStringView, + Utils::SmallStringView, + const ImageCache::AuxiliaryData &) +{ + return {}; +} + +void MeshImageCacheCollector::setTarget(ProjectExplorer::Target *target) +{ + m_imageCacheCollector.setTarget(target); +} + +ProjectExplorer::Target *MeshImageCacheCollector::target() const +{ + return m_imageCacheCollector.target(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h new file mode 100644 index 00000000000..c2cc63bfd9e --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include "imagecachecollectorinterface.h" +#include "imagecachecollector.h" + +namespace ProjectExplorer { +class Target; +} + +namespace QmlDesigner { + +class ImageCacheConnectionManager; + +class MeshImageCacheCollector final : public ImageCacheCollectorInterface +{ +public: + MeshImageCacheCollector(ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, + ImageCacheCollectorNullImageHandling nullImageHandling = {}); + + ~MeshImageCacheCollector(); + + void start(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData, + CaptureCallback captureCallback, + AbortCallback abortCallback) override; + + std::pair createImage(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData) override; + + QIcon createIcon(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData) override; + + void setTarget(ProjectExplorer::Target *target); + ProjectExplorer::Target *target() const; + +private: + ImageCacheCollector m_imageCacheCollector; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp new file mode 100644 index 00000000000..36bd55c2fe6 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "smallimagecacheprovider.h" + +#include + +#include + +namespace QmlDesigner { + +QQuickTextureFactory *ImageResponse::textureFactory() const +{ + return QQuickTextureFactory::textureFactoryForImage(m_image); +} + +void ImageResponse::setImage(const QImage &image) +{ + m_image = image; + + emit finished(); +} + +void ImageResponse::abort() +{ + emit finished(); +} + +QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString &id, const QSize &) +{ + auto response = std::make_unique(m_defaultImage); + + m_cache.requestSmallImage( + id, + [response = QPointer(response.get())](const QImage &image) { + QMetaObject::invokeMethod( + response, + [response, image] { + if (response) + response->setImage(image); + }, + Qt::QueuedConnection); + }, + [response = QPointer(response.get())]( + ImageCache::AbortReason abortReason) { + QMetaObject::invokeMethod( + response, + [response, abortReason] { + switch (abortReason) { + case ImageCache::AbortReason::Failed: + if (response) + response->abort(); + break; + case ImageCache::AbortReason::Abort: + response->cancel(); + break; + } + }, + Qt::QueuedConnection); + }); + + return response.release(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h new file mode 100644 index 00000000000..05674143e67 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace QmlDesigner { + +class AsynchronousImageCache; + +class ImageResponse : public QQuickImageResponse +{ +public: + ImageResponse(const QImage &defaultImage) + : m_image(defaultImage) + {} + + QQuickTextureFactory *textureFactory() const override; + + void setImage(const QImage &image); + + void abort(); + +private: + QImage m_image; +}; + +class SmallImageCacheProvider : public QQuickAsyncImageProvider +{ +public: + SmallImageCacheProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {}) + : m_cache{imageCache} + , m_defaultImage(defaultImage) + {} + + QQuickImageResponse *requestImageResponse(const QString &id, + const QSize &requestedSize) override; + +private: + AsynchronousImageCache &m_cache; + QImage m_defaultImage; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp index 99573f175fb..67ccc7b75c0 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp @@ -28,11 +28,17 @@ #include #include +#include + namespace QmlDesigner { Sqlite::TimeStamp TimeStampProvider::timeStamp(Utils::SmallStringView name) const { - return QFileInfo{QString{name}}.lastModified().toSecsSinceEpoch(); + QFileInfo info{QString{name}}; + if (info.exists()) + return info.lastModified().toSecsSinceEpoch(); + + return {std::numeric_limits::max()}; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 23273939b49..3c4eca04413 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -109,6 +109,8 @@ public: RewriterTransaction beginRewriterTransaction(const QByteArray &identifier); + ModelNode createModelNode(const TypeName &typeName); + ModelNode createModelNode(const TypeName &typeName, int majorVersion, int minorVersion, @@ -163,6 +165,7 @@ public: void emitUpdateActiveScene3D(const QVariantMap &sceneState); void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void emitImport3DSupportChanged(const QVariantMap &supportMap); + void emitModelAtPosResult(const ModelNode &modelNode); void sendTokenToInstances(const QString &token, int number, const QVector &nodeVector); @@ -227,6 +230,7 @@ public: virtual void renderImage3DChanged(const QImage &image); virtual void updateActiveScene3D(const QVariantMap &sceneState); virtual void updateImport3DSupport(const QVariantMap &supportMap); + virtual void modelAtPosReady(const ModelNode &modelNode); virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); virtual void dragStarted(QMimeData *mimeData); @@ -234,6 +238,10 @@ public: void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); + void ensureMaterialLibraryNode(); + ModelNode materialLibraryNode(); + void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {}); + NodeInstanceView *nodeInstanceView() const; RewriterView *rewriterView() const; diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index e3a4af0b758..4e099290cd0 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -127,7 +127,6 @@ public: void addError(const DocumentMessage &error); void enterErrorState(const QString &errorMessage); - bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } void leaveErrorState() { m_rewritingErrorMessage.clear(); } void resetToLastCorrectQml(); @@ -202,6 +201,7 @@ private: //variables void setupCanonicalHashes() const; void handleLibraryInfoUpdate(); void handleProjectUpdate(); + bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } TextModifier *m_textModifier = nullptr; int transactionLevel = 0; diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index dd77c07f459..1be785655a2 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -51,7 +51,8 @@ class ViewManagerData; class QMLDESIGNERCORE_EXPORT ViewManager { public: - ViewManager(class AsynchronousImageCache &imageCache); + ViewManager(class AsynchronousImageCache &imageCache, + class AsynchronousImageCache &meshImageCache); ~ViewManager(); void attachRewriterView(); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 3555bcdefca..f92df89a9db 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -90,6 +90,7 @@ #include #include #include +#include #endif #include @@ -103,6 +104,7 @@ #include #include #include +#include #include @@ -985,17 +987,6 @@ QList filterNodesForSkipItems(const QList &nodeList) return filteredNodeList; } -QList readBackgroundColorConfiguration(const QVariant &var) -{ - if (!var.isValid()) - return {}; - - auto colorNameList = var.value>(); - QTC_ASSERT(colorNameList.size() == 2, return {}); - - return {colorNameList[0], colorNameList[1]}; -} - CreateSceneCommand NodeInstanceView::createCreateSceneCommand() { QList nodeList = allModelNodes(); @@ -1150,16 +1141,15 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) stateInstanceId = stateNode.internalId(); - QVariant value + QColor gridColor; + QList backgroundColor; + #ifndef QMLDESIGNER_TEST - = QmlDesigner::DesignerSettings::getValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); -#else - = {}; + backgroundColor = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); + QList gridColorList = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR); + if (!gridColorList.isEmpty()) + gridColor = gridColorList.at(0); #endif - QList edit3dBackgroundColor; - if (value.isValid()) - edit3dBackgroundColor = readBackgroundColorConfiguration(value); return CreateSceneCommand( instanceContainerList, @@ -1182,7 +1172,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() m_captureImageMinimumSize, m_captureImageMaximumSize, stateInstanceId, - edit3dBackgroundColor); + backgroundColor, + gridColor); } ClearSceneCommand NodeInstanceView::createClearSceneCommand() const @@ -1700,6 +1691,10 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand } else if (command.type() == PuppetToCreatorCommand::Import3DSupport) { const QVariantMap supportMap = qvariant_cast(command.data()); emitImport3DSupportChanged(supportMap); + } else if (command.type() == PuppetToCreatorCommand::ModelAtPos) { + ModelNode modelNode = modelNodeForInternalId(command.data().toUInt()); + if (modelNode.isValid()) + emitModelAtPosResult(modelNode); } } @@ -1727,7 +1722,7 @@ void NodeInstanceView::view3DAction(const View3DActionCommand &command) void NodeInstanceView::requestModelNodePreviewImage(const ModelNode &node, const ModelNode &renderNode) { - if (node.isValid()) { + if (m_nodeInstanceServer && node.isValid()) { auto instance = instanceForModelNode(node); if (instance.isValid()) { qint32 renderItemId = -1; @@ -1767,7 +1762,16 @@ void NodeInstanceView::timerEvent(QTimerEvent *event) QVariant NodeInstanceView::modelNodePreviewImageDataToVariant(const ModelNodePreviewImageData &imageData) { - static const QPixmap placeHolder(":/navigator/icon/tooltip_placeholder.png"); + static QPixmap placeHolder; + if (placeHolder.isNull()) { + QPixmap placeHolderSrc(":/navigator/icon/tooltip_placeholder.png"); + placeHolder = {150, 150}; + // Placeholder has transparency, but we don't want to show the checkerboard, so + // paint in the correct background color + placeHolder.fill(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal)); + QPainter painter(&placeHolder); + painter.drawPixmap(0, 0, 150, 150, placeHolderSrc); + } QVariantMap map; map.insert("type", imageData.type); diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index 38c88a1cee1..f2baf9c9844 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -505,6 +505,12 @@ QProcessEnvironment PuppetCreator::processEnvironment() const #ifndef QMLDESIGNER_TEST const QString controlsStyle = m_designerSettings.value(DesignerSettingsKey:: CONTROLS_STYLE).toString(); + + const bool smoothRendering = m_designerSettings.value(DesignerSettingsKey::SMOOTH_RENDERING) + .toBool(); + + if (smoothRendering) + environment.set("QMLPUPPET_SMOOTH_RENDERING", "true"); #else const QString controlsStyle; #endif diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index a980dc458f4..634c9aa64b6 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -363,7 +363,8 @@ static inline bool isValueType(const TypeName &type) "vector2d", "vector3d", "vector4d", - "font"}); + "font", + "QQuickIcon"}); return objectValuesList.contains(type); } @@ -380,7 +381,8 @@ static inline bool isValueType(const QString &type) "vector2d", "vector3d", "vector4d", - "font"}); + "font", + "QQuickIcon"}); return objectValuesList.contains(type); } diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index b22ba232f9b..310dcdcdab1 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -31,6 +31,11 @@ #include "nodeinstanceview.h" #include #include +#include +#include +#include +#include +#include #ifndef QMLDESIGNER_TEST #include @@ -85,6 +90,12 @@ RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &ide return RewriterTransaction(this, identifier); } +ModelNode AbstractView::createModelNode(const TypeName &typeName) +{ + const NodeMetaInfo metaInfo = model()->metaInfo(typeName); + return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion()); +} + ModelNode AbstractView::createModelNode(const TypeName &typeName, int majorVersion, int minorVersion, @@ -392,6 +403,9 @@ void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/) { } +// a Quick3DModel that is picked at the requested position in the 3D Editor +void AbstractView::modelAtPosReady(const ModelNode & /*modelNode*/) {} + void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/) { } @@ -783,6 +797,12 @@ void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap) model()->d->notifyImport3DSupportChanged(supportMap); } +void AbstractView::emitModelAtPosResult(const ModelNode &modelNode) +{ + if (model()) + model()->d->notifyModelAtPosResult(modelNode); +} + void AbstractView::emitRewriterEndTransaction() { if (model()) @@ -803,6 +823,104 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion); } +// Creates material library if it doesn't exist and moves any existing materials into it +// This function should be called only from inside a transaction, as it potentially does many +// changes to model, or undo stack should be cleared after the call. +void AbstractView::ensureMaterialLibraryNode() +{ + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + if (matLib.isValid()) + return; + + // Create material library node + TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" + : "QtQuick.Item"; + NodeMetaInfo metaInfo = model()->metaInfo(nodeType); + matLib = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion()); + + matLib.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID); + rootModelNode().defaultNodeListProperty().reparentHere(matLib); + + const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); + if (!materials.isEmpty()) { + // Move all materials to under material library node + for (const ModelNode &node : materials) { + // If material has no name, set name to id + QString matName = node.variantProperty("objectName").value().toString(); + if (matName.isEmpty()) { + VariantProperty objNameProp = node.variantProperty("objectName"); + objNameProp.setValue(node.id()); + } + + matLib.defaultNodeListProperty().reparentHere(node); + } + } +} + +// Returns ModelNode for project's material library. +ModelNode AbstractView::materialLibraryNode() +{ + ensureMaterialLibraryNode(); + + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + QTC_ASSERT(matLib.isValid(), return {}); + + return matLib; +} + +// Assigns given material to a 3D model. +// The assigned material is also inserted into material library if not already there. +// If given material is not valid, first existing material from material library is used, +// or if material library is empty, a new material is created. +// This function should be called only from inside a transaction, as it potentially does many +// changes to model. +void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode) +{ + QTC_ASSERT(modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Model"), return); + + ModelNode matLib = materialLibraryNode(); + + if (!matLib.isValid()) + return; + + ModelNode newMaterialNode; + + if (materialNode.isValid() && materialNode.isSubclassOf("QtQuick3D.Material")) { + newMaterialNode = materialNode; + } else { + const QList materials = matLib.directSubModelNodes(); + if (materials.size() > 0) { + for (const ModelNode &mat : materials) { + if (mat.isSubclassOf("QtQuick3D.Material")) { + newMaterialNode = mat; + break; + } + } + } + + // if no valid material, create a new default material + if (!newMaterialNode.isValid()) { + NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); + newMaterialNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), + metaInfo.minorVersion()); + newMaterialNode.validId(); + } + } + + QTC_ASSERT(newMaterialNode.isValid(), return); + + VariantProperty matNameProp = newMaterialNode.variantProperty("objectName"); + if (matNameProp.value().isNull()) + matNameProp.setValue("New Material"); + + if (!newMaterialNode.hasParentProperty() + || newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) { + matLib.defaultNodeListProperty().reparentHere(newMaterialNode); + } + BindingProperty modelMatsProp = modelNode.bindingProperty("materials"); + modelMatsProp.setExpression(newMaterialNode.id()); +} + ModelNode AbstractView::currentStateNode() const { if (model()) diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 4e38fb3cfb3..772149a33d9 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -589,6 +589,11 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap) notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); }); } +void ModelPrivate::notifyModelAtPosResult(const ModelNode &modelNode) +{ + notifyInstanceChanges([&](AbstractView *view) { view->modelAtPosReady(modelNode); }); +} + void ModelPrivate::notifyDragStarted(QMimeData *mimeData) { notifyInstanceChanges([&](AbstractView *view) { view->dragStarted(mimeData); }); @@ -1390,14 +1395,18 @@ void Model::changeImports(const QList &importsToBeAdded, void Model::setPossibleImports(const QList &possibleImports) { - d->m_possibleImportList = possibleImports; - d->notifyPossibleImportsChanged(possibleImports); + if (d->m_possibleImportList != possibleImports) { + d->m_possibleImportList = possibleImports; + d->notifyPossibleImportsChanged(possibleImports); + } } void Model::setUsedImports(const QList &usedImports) { - d->m_usedImportList = usedImports; - d->notifyUsedImportsChanged(usedImports); + if (d->m_usedImportList != usedImports) { + d->m_usedImportList = usedImports; + d->notifyUsedImportsChanged(usedImports); + } } static bool compareVersions(const QString &version1, const QString &version2, bool allowHigherVersion) @@ -1517,7 +1526,9 @@ void Model::startDrag(QMimeData *mimeData, const QPixmap &icon) auto drag = new QDrag(this); drag->setPixmap(icon); drag->setMimeData(mimeData); - drag->exec(); + if (drag->exec() == Qt::IgnoreAction) + endDrag(); + drag->deleteLater(); } diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index 09595670534..c6ed24f681f 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -182,6 +182,7 @@ public: void notifyUpdateActiveScene3D(const QVariantMap &sceneState); void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void notifyImport3DSupportChanged(const QVariantMap &supportMap); + void notifyModelAtPosResult(const ModelNode &modelNode); void notifyDragStarted(QMimeData *mimeData); void notifyDragEnded(); diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp index 9dcba56a7fb..d89765b5bf5 100644 --- a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp @@ -222,7 +222,7 @@ void ModelToTextMerger::applyChanges() return; dumpRewriteActions(QStringLiteral("Before compression")); - RewriteActionCompressor compress(propertyOrder()); + RewriteActionCompressor compress(propertyOrder(), m_rewriterView->positionStorage()); compress(m_rewriteActions, m_rewriterView->textModifier()->tabSettings()); dumpRewriteActions(QStringLiteral("After compression")); diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp index 6422765ec3a..abdba538232 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp @@ -56,6 +56,7 @@ void RewriteActionCompressor::operator()(QList &actions, compressImports(actions); compressRereparentActions(actions); compressReparentIntoSamePropertyActions(actions); + compressReparentIntoNewPropertyActions(actions); compressPropertyActions(actions); compressAddEditRemoveNodeActions(actions); compressAddEditActions(actions, tabSettings); @@ -152,6 +153,35 @@ void RewriteActionCompressor::compressReparentIntoSamePropertyActions(QList &actions) const +{ + QList actionsToRemove; + + QList removeActions; + + for (int i = actions.size(); --i >= 0; ) { + RewriteAction *action = actions.at(i); + + if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) { + if (m_positionStore->nodeOffset(reparentAction->targetProperty().parentModelNode()) < 0) { + actionsToRemove.append(action); + + const ModelNode childNode = reparentAction->reparentedNode(); + + if (m_positionStore->nodeOffset(childNode) > 0) + removeActions.append(new RemoveNodeRewriteAction(childNode)); + } + } + } + + for (RewriteAction *action : qAsConst(actionsToRemove)) { + actions.removeOne(action); + delete action; + } + + actions.append(removeActions); +} + void RewriteActionCompressor::compressAddEditRemoveNodeActions(QList &actions) const { QList actionsToRemove; diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h index 57139f98115..02c1e3ad48a 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h @@ -33,7 +33,10 @@ namespace Internal { class RewriteActionCompressor { public: - RewriteActionCompressor(const PropertyNameList &propertyOrder): m_propertyOrder(propertyOrder) {} + RewriteActionCompressor(const PropertyNameList &propertyOrder, ModelNodePositionStorage *positionStore) : + m_propertyOrder(propertyOrder), + m_positionStore(positionStore) + {} void operator()(QList &actions, const TextEditor::TabSettings &tabSettings) const; @@ -42,6 +45,7 @@ private: void compressRereparentActions(QList &actions) const; void compressReparentIntoSamePropertyActions(QList &actions) const; + void compressReparentIntoNewPropertyActions(QList &actions) const; void compressAddEditRemoveNodeActions(QList &actions) const; void compressPropertyActions(QList &actions) const; void compressAddEditActions(QList &actions, const TextEditor::TabSettings &tabSettings) const; @@ -49,6 +53,7 @@ private: private: PropertyNameList m_propertyOrder; + ModelNodePositionStorage *m_positionStore; }; } // namespace Internal diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index 730bfbb0fb5..d1b53b05ae2 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -62,8 +62,9 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg) class ViewManagerData { public: - ViewManagerData(AsynchronousImageCache &imageCache) + ViewManagerData(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache) : itemLibraryView(imageCache) + , propertyEditorView(meshImageCache) {} InteractiveConnectionManager connectionManager; @@ -94,8 +95,8 @@ static CrumbleBar *crumbleBar() { return QmlDesignerPlugin::instance()->mainWidget()->crumbleBar(); } -ViewManager::ViewManager(AsynchronousImageCache &imageCache) - : d(std::make_unique(imageCache)) +ViewManager::ViewManager(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache) + : d(std::make_unique(imageCache, meshImageCache)) { d->formEditorView.setGotoErrorCallback([this](int line, int column) { d->textEditorView.gotoCursorPosition(line, column); diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 20083068c16..1b9651d471d 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -82,6 +82,8 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, true); const QStringList defaultValue = QStringList() << "#222222" << "#999999"; restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, defaultValue); + restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, "#aaaaaa"); + restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false); settings->endGroup(); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 8c249fc65e0..f39268b1869 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -50,6 +50,7 @@ const char WARNING_FOR_DESIGNER_FEATURES_IN_EDITOR[] = "WarnAboutQtQuickDesigner const char SHOW_DEBUGVIEW[] = "ShowQtQuickDesignerDebugView"; const char ENABLE_DEBUGVIEW[] = "EnableQtQuickDesignerDebugView"; const char EDIT3DVIEW_BACKGROUND_COLOR[] = "Edit3DViewBackgroundColor"; +const char EDIT3DVIEW_GRID_COLOR[] = "Edit3DViewGridLineColor"; const char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar"; const char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet"; const char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory"; @@ -72,6 +73,7 @@ const char COLOR_PALETTE_FAVORITE[] = "ColorPaletteFavorite"; const char ALWAYS_DESIGN_MODE[] = "AlwaysDesignMode"; const char DISABLE_ITEM_LIBRARY_UPDATE_TIMER[] = "DisableItemLibraryUpdateTimer"; const char ASK_BEFORE_DELETING_ASSET[] = "AskBeforeDeletingAsset"; +const char SMOOTH_RENDERING[] = "SmoothRendering"; } class QMLDESIGNERCORE_EXPORT DesignerSettings : public QHash diff --git a/src/plugins/qmldesigner/dynamiclicensecheck.h b/src/plugins/qmldesigner/dynamiclicensecheck.h index f8362cec946..197f5da4152 100644 --- a/src/plugins/qmldesigner/dynamiclicensecheck.h +++ b/src/plugins/qmldesigner/dynamiclicensecheck.h @@ -37,6 +37,7 @@ namespace QmlDesigner { enum FoundLicense { + noLicense, community, professional, enterprise @@ -57,12 +58,28 @@ inline ExtensionSystem::IPlugin *licenseCheckerPlugin() inline FoundLicense checkLicense() { + static FoundLicense license = noLicense; + + if (license != noLicense) + return license; + if (auto plugin = Internal::licenseCheckerPlugin()) { bool retVal = false; + bool success = QMetaObject::invokeMethod(plugin, - "qdsEnterpriseLicense", + "evaluationLicense", Qt::DirectConnection, Q_RETURN_ARG(bool, retVal)); + + if (success && retVal) + return enterprise; + + retVal = false; + + success = QMetaObject::invokeMethod(plugin, + "qdsEnterpriseLicense", + Qt::DirectConnection, + Q_RETURN_ARG(bool, retVal)); if (success && retVal) return enterprise; else diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 8dc2b947496..486faeaa267 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -66,6 +66,7 @@ const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle"; const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle"; const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid"; const char EDIT3D_EDIT_SELECT_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.SelectBackgroundColor"; +const char EDIT3D_EDIT_SELECT_GRID_COLOR[] = "QmlDesigner.Editor3D.SelectGridColor"; const char EDIT3D_EDIT_RESET_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.ResetBackgroundColor"; const char EDIT3D_EDIT_SHOW_SELECTION_BOX[] = "QmlDesigner.Editor3D.ToggleSelectionBox"; const char EDIT3D_EDIT_SHOW_ICON_GIZMO[] = "QmlDesigner.Editor3D.ToggleIconGizmo"; @@ -91,6 +92,7 @@ const char MATERIAL_LIB_ID[] = "__materialLibrary__"; const char MIME_TYPE_ITEM_LIBRARY_INFO[] = "application/vnd.qtdesignstudio.itemlibraryinfo"; const char MIME_TYPE_ASSETS[] = "application/vnd.qtdesignstudio.assets"; +const char MIME_TYPE_MATERIAL[] = "application/vnd.qtdesignstudio.material"; const char MIME_TYPE_ASSET_IMAGE[] = "application/vnd.qtdesignstudio.asset.image"; const char MIME_TYPE_ASSET_FONT[] = "application/vnd.qtdesignstudio.asset.font"; const char MIME_TYPE_ASSET_SHADER[] = "application/vnd.qtdesignstudio.asset.shader"; diff --git a/src/plugins/qmldesigner/qmldesignercore.cmake b/src/plugins/qmldesigner/qmldesignercore.cmake index 46e30173a3b..8795659c691 100644 --- a/src/plugins/qmldesigner/qmldesignercore.cmake +++ b/src/plugins/qmldesigner/qmldesignercore.cmake @@ -27,8 +27,6 @@ function(extend_with_qmldesigner_core target_name) QmlProjectManager QtSupport TextEditor - DEFINES - TEST_EXPORTS INCLUDES ${CMAKE_CURRENT_FUNCTION_LIST_DIR} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/components @@ -137,6 +135,8 @@ function(extend_with_qmldesigner_core target_name) imagecache/imagecachegeneratorinterface.h imagecache/imagecachestorage.h imagecache/imagecachestorageinterface.h + imagecache/meshimagecachecollector.cpp + imagecache/meshimagecachecollector.h imagecache/synchronousimagecache.cpp imagecache/timestampprovider.cpp imagecache/timestampprovider.h diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 131bedac04d..331c8e7852f 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -135,7 +135,8 @@ class QmlDesignerPluginPrivate { public: QmlDesignerProjectManager projectManager; - ViewManager viewManager{projectManager.asynchronousImageCache()}; + ViewManager viewManager{projectManager.asynchronousImageCache(), + projectManager.asynchronousMeshImageCache()}; DocumentManager documentManager; ShortCutManager shortCutManager; SettingsPage settingsPage; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 84ad776c3f0..db508d25ba9 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -441,6 +441,10 @@ Project { "imagecache/imagecachegenerator.h", "imagecache/imagecachestorageinterface.h", "imagecache/imagecachestorage.h", + "imagecache/meshimagecachecollector.cpp", + "imagecache/meshimagecachecollector.h", + "imagecache/smallimagecacheprovider.cpp", + "imagecache/smallimagecacheprovider.h", "imagecache/synchronousimagecache.cpp", "imagecache/timestampproviderinterface.h", "imagecache/timestampprovider.h", @@ -562,6 +566,7 @@ Project { "debugview/debugviewwidget.ui", "edit3d/edit3dview.cpp", "edit3d/edit3dview.h", + "edit3d/edit3dviewconfig.h", "edit3d/backgroundcolorselection.cpp", "edit3d/backgroundcolorselection.h", "edit3d/edit3dwidget.cpp", @@ -773,6 +778,8 @@ Project { "propertyeditor/gradientpresetlistmodel.h", "propertyeditor/propertyeditorcontextobject.cpp", "propertyeditor/propertyeditorcontextobject.h", + "propertyeditor/propertyeditorimageprovider.cpp", + "propertyeditor/propertyeditorimageprovider.h", "propertyeditor/propertyeditortransaction.cpp", "propertyeditor/propertyeditortransaction.h", "propertyeditor/propertyeditorvalue.cpp", diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index c4e678f5e55..02b398282e4 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -51,7 +51,8 @@ #include #include #include -#include +#include +#include #include @@ -79,7 +80,7 @@ QString defaultImagePath() return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem()); } -class TimeStampProvider : public TimeStampProviderInterface +class PreviewTimeStampProvider : public TimeStampProviderInterface { public: Sqlite::TimeStamp timeStamp(Utils::SmallStringView) const override @@ -102,15 +103,18 @@ class QmlDesignerProjectManager::ImageCacheData { public: Sqlite::Database database{Utils::PathString{ - Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, + Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, Sqlite::JournalMode::Wal, Sqlite::LockingMode::Normal}; ImageCacheStorage storage{database}; ImageCacheConnectionManager connectionManager; - ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}}; - ImageCacheGenerator generator{collector, storage}; + MeshImageCacheCollector meshImageCollector{connectionManager, QSize{300, 300}, QSize{600, 600}}; + ImageCacheGenerator meshGenerator{meshImageCollector, storage}; + ImageCacheCollector nodeInstanceCollector{connectionManager, QSize{300, 300}, QSize{600, 600}}; + ImageCacheGenerator nodeInstanceGenerator{nodeInstanceCollector, storage}; TimeStampProvider timeStampProvider; - AsynchronousImageCache asynchronousImageCache{storage, generator, timeStampProvider}; + AsynchronousImageCache asynchronousImageCache{storage, nodeInstanceGenerator, timeStampProvider}; + AsynchronousImageCache asynchronousMeshImageCache{storage, meshGenerator, timeStampProvider}; }; class QmlDesignerProjectManager::PreviewImageCacheData @@ -163,10 +167,10 @@ public: QSize{300, 300}, QSize{1000, 1000}, ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; - TimeStampProvider timeStampProvider; + PreviewTimeStampProvider timeStampProvider; AsynchronousImageFactory factory; ProjectStorageData projectStorageData; - ::ProjectExplorer::Target *activeTarget = nullptr; + QPointer<::ProjectExplorer::Target> activeTarget; }; QmlDesignerProjectManager::QmlDesignerProjectManager() @@ -209,6 +213,11 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache() return imageCacheData()->asynchronousImageCache; } +AsynchronousImageCache &QmlDesignerProjectManager::asynchronousMeshImageCache() +{ + return imageCacheData()->asynchronousMeshImageCache; +} + void QmlDesignerProjectManager::editorOpened(::Core::IEditor *) {} void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *) @@ -381,17 +390,21 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache m_imageCacheData = std::make_unique(); auto setTargetInImageCache = [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { - if (target == imageCacheData->collector.target()) + if (target == imageCacheData->nodeInstanceCollector.target()) return; if (target) imageCacheData->asynchronousImageCache.clean(); - imageCacheData->collector.setTarget(target); + // TODO wrap in function in image cache data + imageCacheData->meshImageCollector.setTarget(target); + imageCacheData->nodeInstanceCollector.setTarget(target); }; if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { - m_imageCacheData->collector.setTarget(project->activeTarget()); + // TODO wrap in function in image cache data + m_imageCacheData->meshImageCollector.setTarget(project->activeTarget()); + m_imageCacheData->nodeInstanceCollector.setTarget(project->activeTarget()); QObject::connect(project, &ProjectExplorer::Project::activeTargetChanged, this, diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h index b3567d3b127..88414cc4bb8 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h @@ -59,6 +59,7 @@ public: void registerPreviewImageProvider(QQmlEngine *engine) const; class AsynchronousImageCache &asynchronousImageCache(); + class AsynchronousImageCache &asynchronousMeshImageCache(); private: void editorOpened(::Core::IEditor *editor); diff --git a/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png index d4ecf00031f..31b8fed6668 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png and b/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png differ diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 1af226ae49f..700402680a9 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -182,6 +182,7 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.designerAlwaysDesignModeCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, m_ui.askBeforeDeletingAssetCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::SMOOTH_RENDERING, m_ui.smoothRendering->isChecked()); return settings; } @@ -264,6 +265,7 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.emulationGroupBox->setVisible(showAdvancedFeatures); m_ui.debugGroupBox->setVisible(showAdvancedFeatures); m_ui.featureTimelineEditorCheckBox->setVisible(standaloneMode); + m_ui.smoothRendering->setChecked(settings.value(DesignerSettingsKey::SMOOTH_RENDERING).toBool()); } void SettingsPageWidget::apply() diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index eace952540a..004f8a68eb6 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -99,6 +99,23 @@ + + + + Enable Smooth Rendering in Form Editor + + + + + + + + + + Smooth Rendering: + + + diff --git a/src/plugins/qmlprojectmanager/qdslandingpage.h b/src/plugins/qmlprojectmanager/qdslandingpage.h index 3447a2bf915..7162705021e 100644 --- a/src/plugins/qmlprojectmanager/qdslandingpage.h +++ b/src/plugins/qmlprojectmanager/qdslandingpage.h @@ -39,7 +39,7 @@ class DesignModeContext : public Core::IContext Q_OBJECT public: - DesignModeContext(QWidget *widget) { setWidget(widget); } + DesignModeContext(QWidget *widget) : Core::IContext(widget) { setWidget(widget); } }; class QdsLandingPageWidget : public QWidget diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index ef5fcba0fd6..7c5d09faddb 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -130,7 +130,7 @@ void GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished() void GenericLinuxDeviceConfigurationWidget::gdbServerEditingFinished() { - device()->setDebugServerPath(FilePath::fromString(m_ui->gdbServerLineEdit->text())); + device()->setDebugServerPath(device()->filePath(m_ui->gdbServerLineEdit->text())); } void GenericLinuxDeviceConfigurationWidget::handleFreePortsChanged() @@ -213,6 +213,7 @@ void GenericLinuxDeviceConfigurationWidget::initGui() m_ui->timeoutSpinBox->setValue(sshParams.timeout); m_ui->userLineEdit->setText(sshParams.userName()); m_ui->keyFileLineEdit->setFilePath(sshParams.privateKeyFile); - m_ui->gdbServerLineEdit->setText(device()->debugServerPath().toString()); + // FIXME: Use a remote executable line edit + m_ui->gdbServerLineEdit->setText(device()->debugServerPath().path()); updatePortsWarningLabel(); } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 69910f01315..0ec48a41fe9 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -380,7 +381,6 @@ public: bool setupShell(); bool runInShell(const CommandLine &cmd, const QByteArray &data = {}); - QByteArray outputForRunInShell(const QString &cmd); QByteArray outputForRunInShell(const CommandLine &cmd); void attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters); @@ -734,7 +734,7 @@ void SshProcessInterfacePrivate::doStart() CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const { - Utils::CommandLine cmd{SshSettings::sshFilePath()}; + CommandLine cmd{SshSettings::sshFilePath()}; if (!m_sshParameters.x11DisplayName.isEmpty()) cmd.addArg("-X"); @@ -769,6 +769,25 @@ static SshParameters displayless(const SshParameters &sshParameters) class ShellThreadHandler : public QObject { + class LinuxDeviceShell : public DeviceShell + { + public: + LinuxDeviceShell(const CommandLine &cmdLine) + : m_cmdLine(cmdLine) + { + } + + private: + void setupShellProcess(QtcProcess *shellProcess) override + { + SshParameters::setupSshEnvironment(shellProcess); + shellProcess->setCommand(m_cmdLine); + } + + private: + const CommandLine m_cmdLine; + }; + public: ~ShellThreadHandler() { @@ -778,10 +797,6 @@ public: void closeShell() { - if (m_shell && m_shell->isRunning()) { - m_shell->write("exit\n"); - m_shell->waitForFinished(-1); - } m_shell.reset(); } @@ -790,9 +805,6 @@ public: { closeShell(); setSshParameters(parameters); - m_shell.reset(new QtcProcess); - - SshParameters::setupSshEnvironment(m_shell.get()); const FilePath sshPath = SshSettings::sshFilePath(); CommandLine cmd { sshPath }; @@ -801,93 +813,23 @@ public: << m_displaylessSshParameters.host()); cmd.addArg("/bin/sh"); - m_shell->setCommand(cmd); - m_shell->setProcessMode(ProcessMode::Writer); - m_shell->setWriteData("echo\n"); - m_shell->start(); - - auto failed = [this] { - closeShell(); - qCDebug(linuxDeviceLog) << "Failed to connect to" << m_displaylessSshParameters.host(); - return false; - }; - - QDeadlineTimer timer(30000); - if (!m_shell->waitForStarted(timer.remainingTime())) - return failed(); - - while (true) { - if (!m_shell->waitForReadyRead(timer.remainingTime())) - return failed(); - - const QByteArray output = m_shell->readAllStandardOutput(); - if (output == "\n") - break; // expected output from echo - if (output.size() > 0) - return failed(); // other unidentified output - - // In case of trying to run a shell using SSH_ASKPASS, it may happen - // that we receive ready read signal but for error channel, while output - // channel still is empty. In this case we wait in loop until the user - // provides the right password, otherwise we timeout after 30 seconds. - } - return true; + m_shell.reset(new LinuxDeviceShell(cmd)); + connect(m_shell.get(), &DeviceShell::done, this, [this] { m_shell.reset(); }); + return m_shell->start(); } // Call me with shell mutex locked bool runInShell(const CommandLine &cmd, const QByteArray &data = {}) { QTC_ASSERT(m_shell, return false); - QTC_CHECK(m_shell->readAllStandardOutput().isNull()); // clean possible left-overs - QTC_CHECK(m_shell->readAllStandardError().isNull()); // clean possible left-overs - - QString prefix; - if (!data.isEmpty()) - prefix = "echo '" + QString::fromUtf8(data.toBase64()) + "' | base64 -d | "; - const QString suffix = " > /dev/null 2>&1\necho $?\n"; - const QString command = prefix + cmd.toUserOutput() + suffix; - - m_shell->write(command); - DEBUG("RUN1 " << cmd.toUserOutput()); - m_shell->waitForReadyRead(); - const QByteArray output = m_shell->readAllStandardOutput(); - DEBUG("GOT1 " << output); - bool ok = false; - const int result = output.toInt(&ok); - LOG("Run command in shell:" << cmd.toUserOutput() << "result: " << output << " ==>" << result); - QTC_ASSERT(ok, return false); - return !result; + return m_shell->runInShell(cmd, data); } // Call me with shell mutex locked - QByteArray outputForRunInShell(const QString &cmd) + QByteArray outputForRunInShell(const CommandLine &cmd) { QTC_ASSERT(m_shell, return {}); - QTC_CHECK(m_shell->readAllStandardOutput().isNull()); // clean possible left-overs - QTC_CHECK(m_shell->readAllStandardError().isNull()); // clean possible left-overs - auto cleanup = qScopeGuard([this] { m_shell->readAllStandardOutput(); }); // clean on assert - - const QString suffix = " 2> /dev/null \necho $? 1>&2\n"; - const QString command = cmd + suffix; - - m_shell->write(command); - DEBUG("RUN2 " << cmd.toUserOutput()); - - while (true) { - m_shell->waitForReadyRead(); - const QByteArray error = m_shell->readAllStandardError(); - if (!error.isNull()) { - bool ok = false; - const int result = error.toInt(&ok); - QTC_ASSERT(ok, return {}); - QTC_ASSERT(!result, return {}); - break; - } - } - const QByteArray output = m_shell->readAllStandardOutput(); - DEBUG("GOT2 " << output); - LOG("Run command in shell:" << cmd << "output size:" << output.size()); - return output; + return m_shell->outputForRunInShell(cmd).stdOut; } void setSshParameters(const SshParameters &sshParameters) @@ -970,7 +912,7 @@ private: mutable QMutex m_mutex; SshParameters m_displaylessSshParameters; QList m_connections; - std::unique_ptr m_shell; + std::unique_ptr m_shell; }; // LinuxDevice @@ -1089,7 +1031,7 @@ public: private: void start() override { m_reader.start(); } void readerFinished() { emit finished(m_reader.remoteEnvironment(), true); } - void readerError() { emit finished(Utils::Environment(), false); } + void readerError() { emit finished(Environment(), false); } Internal::RemoteLinuxEnvironmentReader m_reader; }; @@ -1172,7 +1114,7 @@ bool LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &da return ret; } -QByteArray LinuxDevicePrivate::outputForRunInShell(const QString &cmd) +QByteArray LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd) { QMutexLocker locker(&m_shellMutex); DEBUG(cmd); @@ -1185,11 +1127,6 @@ QByteArray LinuxDevicePrivate::outputForRunInShell(const QString &cmd) return ret; } -QByteArray LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd) -{ - return outputForRunInShell(cmd.toUserOutput()); -} - void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters) { @@ -1337,7 +1274,7 @@ qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const CommandLine cmd("df", {"-k"}); cmd.addArg(filePath.path()); cmd.addArgs("|tail -n 1 |sed 's/ */ /g'|cut -d ' ' -f 4", CommandLine::Raw); - const QByteArray output = d->outputForRunInShell(cmd.toUserOutput()); + const QByteArray output = d->outputForRunInShell(cmd); bool ok = false; const qint64 size = output.toLongLong(&ok); if (ok) @@ -1365,7 +1302,7 @@ QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) cons return perm; } -bool LinuxDevice::setPermissions(const Utils::FilePath &filePath, QFileDevice::Permissions permissions) const +bool LinuxDevice::setPermissions(const FilePath &filePath, QFileDevice::Permissions permissions) const { QTC_ASSERT(handlesFile(filePath), return false); const int flags = int(permissions); @@ -1394,7 +1331,7 @@ QByteArray LinuxDevice::fileContents(const FilePath &filePath, qint64 limit, qin CommandLine cmd(FilePath::fromString("dd"), args, CommandLine::Raw); const QByteArray output = d->outputForRunInShell(cmd); - DEBUG(output << output << QByteArray::fromHex(output)); + DEBUG(output << QByteArray::fromHex(output)); return output; } diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index 4a4eae51c2c..409f80dfa7f 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -122,6 +123,8 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged); connect(d->m_ui.smartSelectionChanging, &QAbstractButton::clicked, this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged); + + d->m_ui.mouseHiding->setVisible(!Utils::HostOsInfo::isMacHost()); } BehaviorSettingsWidget::~BehaviorSettingsWidget() diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index 50b5626ca76..22c937ac1c8 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -270,13 +270,13 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason, if (processor != m_asyncProcessor) return; invalidateCurrentRequestData(); - if (processor && processor->needsRestart() && m_receivedContentWhileWaiting) { + if (processor->needsRestart() && m_receivedContentWhileWaiting) { delete newProposal; m_receivedContentWhileWaiting = false; requestProposal(reason, m_assistKind, m_requestProvider); } else { displayProposal(newProposal, reason); - if (processor && processor->running()) + if (processor->running()) m_asyncProcessor = processor; else emit q->finished(); diff --git a/src/plugins/texteditor/codeassist/iassistproposal.h b/src/plugins/texteditor/codeassist/iassistproposal.h index 1393cbab835..feb92caf9f2 100644 --- a/src/plugins/texteditor/codeassist/iassistproposal.h +++ b/src/plugins/texteditor/codeassist/iassistproposal.h @@ -65,7 +65,7 @@ protected: int m_basePosition; bool m_isFragile = false; bool m_supportsPrefix = true; - AssistReason m_reason; + AssistReason m_reason = IdleEditor; }; } // TextEditor diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 3aeb86bad2e..9a4b997ffc2 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -3375,7 +3375,7 @@ void TextEditorWidget::setMouseHidingEnabled(bool b) bool TextEditorWidget::mouseHidingEnabled() const { - return d->m_behaviorSettings.m_mouseHiding; + return Utils::HostOsInfo::isMacHost() ? false : d->m_behaviorSettings.m_mouseHiding; } void TextEditorWidget::setScrollWheelZoomingEnabled(bool b) diff --git a/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt b/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt index a77550fa468..bd701ac2433 100644 --- a/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt +++ b/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt @@ -4,7 +4,7 @@ if(APPLE) elseif(UNIX) set(plugin_output_name "libtest") else() - set(plugin_output_name "testd") + set(plugin_output_name "test$<$:d>") endif() file(RELATIVE_PATH TEST_PLUGIN_PATH ${QtCreator_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index ac0440b65d7..1c0239b542e 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -1152,6 +1152,102 @@ void tst_TestCore::testRewriterTransactionAddingAfterReparenting() } } +void tst_TestCore::testRewriterReparentToNewNode() +{ + const QLatin1String qmlString("\n" + "import QtQuick 2.0\n" + "\n" + "Item {\n" + " Item {}\n" + " Item {}\n" + " Item {}\n" + " Item {}\n" + "}\n"); + + QPlainTextEdit textEdit; + textEdit.setPlainText(qmlString); + NotIndentingTextEditModifier modifier(&textEdit); + + QScopedPointer model(Model::create("QtQuick.Rectangle")); + + QScopedPointer testRewriterView(new TestRewriterView(0, RewriterView::Amend)); + testRewriterView->setTextModifier(&modifier); + model->attachView(testRewriterView.data()); + + QVERIFY(testRewriterView->errors().isEmpty()); + + ModelNode rootModelNode = testRewriterView->rootModelNode(); + QVERIFY(rootModelNode.isValid()); + + const QList children = rootModelNode.directSubModelNodes(); + + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(rectangle); + + rectangle.setIdWithoutRefactoring("newParent"); + + QVERIFY(rectangle.isValid()); + + for (const ModelNode &child : children) + rectangle.nodeListProperty("data").reparentHere(child); + + { + RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(rectangle); + + rectangle.setIdWithoutRefactoring("newParent2"); + + for (const ModelNode &child : children) + rectangle.nodeListProperty("data").reparentHere(child); + } + + QCOMPARE(testRewriterView->allModelNodes().count(), 7); + + const QLatin1String expectedOutcome("\nimport QtQuick 2.0\n\n" + "Item {\n\n" + " Rectangle {\n" + " id: newParent\n" + " }\n\n" + " Rectangle {\n" + " id: newParent2\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n" + " }\n}\n"); + + + QCOMPARE(textEdit.toPlainText(), expectedOutcome); + + rectangle.destroy(); + + QCOMPARE(testRewriterView->allModelNodes().count(), 6); + + { + RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); + + ModelNode newChild = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(newChild); + newChild.setIdWithoutRefactoring("newChild"); + ModelNode newParent = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(newParent); + + newParent.setIdWithoutRefactoring("newParent3"); + + for (const ModelNode &child : children) + newParent.nodeListProperty("data").reparentHere(child); + + newParent.nodeListProperty("data").reparentHere(newChild); + } + + QCOMPARE(testRewriterView->allModelNodes().count(), 8); +} + void tst_TestCore::testRewriterForGradientMagic() { const QLatin1String qmlString("\n" diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h index 9a8aeb6450b..5248763fef9 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h @@ -144,6 +144,7 @@ private slots: void testRewriterChangeImports(); void testRewriterUnicodeChars(); void testRewriterTransactionAddingAfterReparenting(); + void testRewriterReparentToNewNode(); // // unit tests QmlModelNodeFacade/QmlModelState diff --git a/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt b/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt index a2965b22f1b..9a50fab71be 100644 --- a/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt +++ b/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt @@ -8,7 +8,6 @@ add_qtc_test(tst_qml_wizard DEPENDS Core Utils StudioWelcome ProjectExplorer QmlDesigner Googletest DEFINES QT_CREATOR - QMLDESIGNER_TEST IDE_PLUGIN_PATH="${PROJECT_BINARY_DIR}/${IDE_PLUGIN_PATH}" IDE_DATA_PATH="${PROJECT_BINARY_DIR}/${IDE_DATA_PATH}" TESTSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}" diff --git a/tests/system/objects.map b/tests/system/objects.map index 81120f94964..7922cacca2c 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -89,7 +89,7 @@ :JsonWizard_ProjectExplorer::JsonFieldPage {type='ProjectExplorer::JsonFieldPage' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} :Kits_QtVersion_QComboBox {container=':qt_tabwidget_stackedwidget_QWidget' leftWidget=':QtVersionLabel_KitPage' type='QComboBox' unnamed='1' visible='1'} :Locals and Expressions_Debugger::Internal::WatchTreeView {container=':Debugger.Docks.LocalsAndWatchersDockWidget.Inspector_QFrame' name='WatchWindow' type='Debugger::Internal::WatchTreeView' visible='1'} -:Minimal required Qt version:_QLabel {text='Minimal required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} +:Minimal required Qt version:_QLabel {text='Minimum required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} :New Text File.Add to project:_QLabel {name='projectLabel' text='Add to project:' type='QLabel' visible='1' window=':New_ProjectExplorer::JsonWizard'} :New Text File.nameLineEdit_Utils::FileNameValidatingLineEdit {name='nameLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1' window=':New_ProjectExplorer::JsonWizard'} :New.comboBox_QComboBox {name='comboBox' type='QComboBox' visible='1' window=':New_Core::Internal::NewDialog'} diff --git a/tests/system/suite_editors/tst_edit_externally/test.py b/tests/system/suite_editors/tst_edit_externally/test.py index d0fd4a643e8..4bf6c2bf790 100644 --- a/tests/system/suite_editors/tst_edit_externally/test.py +++ b/tests/system/suite_editors/tst_edit_externally/test.py @@ -48,7 +48,7 @@ def main(): mBox = ("{text?='The file * has been changed on disk. Do you want to reload it?' " "type='QMessageBox' unnamed='1' visible='1'}") popupText = ("

The file %s has been changed on disk. Do you want to reload it?

" - "

The default behavior can be set in Tools > Options > Environment > System.

") + "

The default behavior can be set in Edit > Preferences > Environment > System.

") formerContent = None for i, currentFile in enumerate(files): diff --git a/tests/system/suite_general/tst_create_proj_wizard/test.py b/tests/system/suite_general/tst_create_proj_wizard/test.py index 38550a96aff..00bccc86259 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -55,14 +55,19 @@ def main(): # skip non-configurable if "Import" in category: continue + # FIXME + if "Qt for Python" in category: + continue mouseClick(waitForObjectItem(categoriesView, "Projects." + category)) templatesView = waitForObject("{name='templatesView' type='QListView' visible='1'}") # needed because categoriesView and templatesView using same model for template in dumpItems(templatesView.model(), templatesView.rootIndex()): template = template.replace(".", "\\.") + # FIXME this needs Qt6.2+ + if template == "Qt Quick 2 Extension Plugin": + continue # skip non-configurable - if (template not in ["Qt Quick UI Prototype", "Auto Test Project", "Qt Creator Plugin"] - and "Qt for Python - " not in template): # FIXME + if template not in ["Qt Quick UI Prototype", "Auto Test Project", "Qt Creator Plugin"]: availableProjectTypes.append({category:template}) safeClickButton("Cancel") for current in availableProjectTypes: diff --git a/tests/system/suite_general/tst_default_settings/test.py b/tests/system/suite_general/tst_default_settings/test.py index bf0d55c6895..88b2160e5ea 100644 --- a/tests/system/suite_general/tst_default_settings/test.py +++ b/tests/system/suite_general/tst_default_settings/test.py @@ -171,37 +171,6 @@ def __kitFunc__(it, foundQt, foundCompNames): details = details.replace("", "").replace("", "") test.warning("Detected error and/or warning: %s" % details) -def __extendExpectedCompilersWithInternalClang__(expected): - global appContext - # QC ships a clang itself - regex = '^(.*(qtcreator(.exe)?|Qt Creator))( .*)?$' # QC with optional arguments - qcPath = re.match(regex, appContext.commandLine) - if qcPath is None: - test.warning("Regular expression failed.") - else: - qcPath = qcPath.group(1) - if platform.system() == 'Darwin': - internalClang = os.path.join(qcPath, '..', '..', 'Resources') - elif platform.system() in ('Windows', 'Microsoft'): - internalClang = os.path.join(qcPath, '..') - else: - internalClang = os.path.join(qcPath, '..', '..', 'libexec', 'qtcreator') - internalClang = os.path.join(internalClang, 'clang', 'bin', 'clang') - if platform.system() in ('Microsoft', 'Windows'): - internalClang += '-cl.exe' - internalClang = os.path.abspath(internalClang) - if os.path.exists(internalClang): - if platform.system() in ('Microsoft', 'Windows'): - # just add a fuzzy comparable name - everything else is not worth the effort here - expected.append({'^Default LLVM \d{2} bit based on MSVC\d{4}$':''}) - else: - expected.append(internalClang) - else: - test.fail("QC package seems to be faulty - missing internal provided clang.\nIf this " - "is not a package, but a self-compiled QC, just copy the clang executable " - "located inside the LLVM_INSTALL_DIR/bin (used while building) to the " - "expected path.", "Expected '%s'" % internalClang) - def __getExpectedCompilers__(): # TODO: enhance this to distinguish between C and C++ compilers expected = [] @@ -219,8 +188,6 @@ def __getExpectedCompilers__(): if xcodeClang and os.path.exists(xcodeClang) and xcodeClang not in expected: expected.append(xcodeClang) - __extendExpectedCompilersWithInternalClang__(expected) - for compiler in compilers: compilerPath = which(compiler) if compilerPath: @@ -309,13 +276,6 @@ def __compareCompilers__(foundCompilers, expectedCompilers): if isString(currentExp): continue key = currentExp.keys()[0] - # special case for (fuzzy) regex comparison on Windows (internal LLVM) - if isWin and key.startswith('^') and key.endswith('$'): - if re.match(key, currentFound.keys()[0], flags): - test.verify(os.path.exists(currentFound.values()[0].rsplit(" ", 1)[0]), - "Verifying whether shipped clang got set up.") - foundExp = True - break # the regex .*? is used for the different possible version strings of the WinSDK # if it's present a regex will be validated otherwise simple string comparison if (((".*?" in key and re.match(key, currentFound.keys()[0], flags)) diff --git a/tests/system/suite_qtquick/tst_qtquick_creation4/test.py b/tests/system/suite_qtquick/tst_qtquick_creation4/test.py index 82d04ef8d3d..9408acaf7df 100644 --- a/tests/system/suite_qtquick/tst_qtquick_creation4/test.py +++ b/tests/system/suite_qtquick/tst_qtquick_creation4/test.py @@ -26,6 +26,10 @@ source("../../shared/qtcreator.py") def main(): + # FIXME + test.warning("Qt Quick 2 Extension Plugin needs Qt6.2+ nowadays.") + return + startQC() if not startedWithoutPluginError(): return