Merge remote-tracking branch 'origin/7.0'
Conflicts: cmake/QtCreatorIDEBranding.cmake qbs/modules/qtc/qtc.qbs qtcreator_ide_branding.pri Change-Id: Ic02df53b880d0861d9d9ea0df3e0d381ae99f350
83
.github/workflows/build_cmake.yml
vendored
@@ -8,12 +8,12 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 6.2.3
|
QT_VERSION: 6.2.3
|
||||||
CLANG_VERSION: 130
|
CLANG_VERSION: 140
|
||||||
ELFUTILS_VERSION: 0.175
|
ELFUTILS_VERSION: 0.175
|
||||||
CMAKE_VERSION: 3.21.1
|
CMAKE_VERSION: 3.21.1
|
||||||
NINJA_VERSION: 1.10.2
|
NINJA_VERSION: 1.10.2
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
CCACHE_VERSION: 4.5
|
CCACHE_VERSION: 4.6
|
||||||
QT_MIRRORS: download.qt.io;mirrors.ocf.berkeley.edu/qt;ftp.fau.de/qtproject;mirror.bit.edu.cn/qtproject
|
QT_MIRRORS: download.qt.io;mirrors.ocf.berkeley.edu/qt;ftp.fau.de/qtproject;mirror.bit.edu.cn/qtproject
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -31,12 +31,14 @@ jobs:
|
|||||||
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat",
|
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat",
|
||||||
is_msvc: true
|
is_msvc: true
|
||||||
}
|
}
|
||||||
# - {
|
- {
|
||||||
# name: "Windows Latest MinGW", artifact: "Windows-MinGW",
|
name: "Windows Latest MinGW", artifact: "Windows-MinGW",
|
||||||
# os: windows-latest,
|
os: windows-latest,
|
||||||
# cc: "gcc", cxx: "g++",
|
toolchain: "https://github.com/cristianadam/mingw-builds/releases/download/v11.2.0-rev1/x86_64-11.2.0-release-posix-seh-rt_v9-rev1.7z",
|
||||||
# is_msvc: false
|
toolchain_path: "mingw64/bin",
|
||||||
# }
|
cc: "gcc", cxx: "g++",
|
||||||
|
is_msvc: false
|
||||||
|
}
|
||||||
- {
|
- {
|
||||||
name: "Ubuntu Latest GCC", artifact: "Linux",
|
name: "Ubuntu Latest GCC", artifact: "Linux",
|
||||||
os: ubuntu-latest,
|
os: ubuntu-latest,
|
||||||
@@ -111,6 +113,33 @@ jobs:
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
- name: Install system libs
|
||||||
|
shell: cmake -P {0}
|
||||||
|
run: |
|
||||||
|
if ("${{ runner.os }}" STREQUAL "Linux")
|
||||||
|
execute_process(
|
||||||
|
COMMAND sudo apt update
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND sudo apt install libgl1-mesa-dev libvulkan-dev libxcb-xinput-dev libxcb-xinerama0-dev libxkbcommon-dev libxkbcommon-x11-dev
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
if (NOT result EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Failed to install dependencies")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT "x${{ matrix.config.toolchain }}" STREQUAL "x")
|
||||||
|
foreach(retry RANGE 10)
|
||||||
|
file(DOWNLOAD "${{ matrix.config.toolchain }}" ./toolchain.7z SHOW_PROGRESS)
|
||||||
|
file(SIZE ./toolchain.7z fileSize)
|
||||||
|
if (fileSize GREATER 0)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./toolchain.7z)
|
||||||
|
endif()
|
||||||
|
|
||||||
- name: Download Qt
|
- name: Download Qt
|
||||||
id: qt
|
id: qt
|
||||||
shell: cmake -P {0}
|
shell: cmake -P {0}
|
||||||
@@ -121,8 +150,8 @@ jobs:
|
|||||||
if ("${{ runner.os }}" STREQUAL "Windows")
|
if ("${{ runner.os }}" STREQUAL "Windows")
|
||||||
set(url_os "windows_x86")
|
set(url_os "windows_x86")
|
||||||
if ("x${{ matrix.config.environment_script }}" STREQUAL "x")
|
if ("x${{ matrix.config.environment_script }}" STREQUAL "x")
|
||||||
set(qt_package_arch_suffix "win64_mingw81")
|
set(qt_package_arch_suffix "win64_mingw")
|
||||||
set(qt_dir_prefix "${qt_version}/mingw81_64")
|
set(qt_dir_prefix "${qt_version}/mingw_64")
|
||||||
set(qt_package_suffix "-Windows-Windows_10_21H2-Mingw-Windows-Windows_10_21H2-X86_64")
|
set(qt_package_suffix "-Windows-Windows_10_21H2-Mingw-Windows-Windows_10_21H2-X86_64")
|
||||||
elseif ("${{ matrix.config.environment_script }}" MATCHES "vcvars64.bat")
|
elseif ("${{ matrix.config.environment_script }}" MATCHES "vcvars64.bat")
|
||||||
set(qt_package_arch_suffix "win64_msvc2019_64")
|
set(qt_package_arch_suffix "win64_msvc2019_64")
|
||||||
@@ -218,7 +247,7 @@ jobs:
|
|||||||
if ("x${{ matrix.config.environment_script }}" STREQUAL "x")
|
if ("x${{ matrix.config.environment_script }}" STREQUAL "x")
|
||||||
# deploy MinGW
|
# deploy MinGW
|
||||||
foreach(file libwinpthread-1.dll libstdc++-6.dll libgcc_s_seh-1.dll)
|
foreach(file libwinpthread-1.dll libstdc++-6.dll libgcc_s_seh-1.dll)
|
||||||
file(INSTALL "C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/bin/${file}"
|
file(INSTALL "$ENV{GITHUB_WORKSPACE}/${{ matrix.config.toolchain_path }}/${file}"
|
||||||
DESTINATION "qt6/${qt_dir_prefix}/bin"
|
DESTINATION "qt6/${qt_dir_prefix}/bin"
|
||||||
USE_SOURCE_PERMISSIONS)
|
USE_SOURCE_PERMISSIONS)
|
||||||
endforeach()
|
endforeach()
|
||||||
@@ -434,22 +463,6 @@ jobs:
|
|||||||
endforeach()
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
- name: Install system libs
|
|
||||||
shell: cmake -P {0}
|
|
||||||
run: |
|
|
||||||
if ("${{ runner.os }}" STREQUAL "Linux")
|
|
||||||
execute_process(
|
|
||||||
COMMAND sudo apt update
|
|
||||||
)
|
|
||||||
execute_process(
|
|
||||||
COMMAND sudo apt install libgl1-mesa-dev libvulkan-dev libxcb-xinput-dev libxcb-xinerama0-dev libxkbcommon-dev libxkbcommon-x11-dev
|
|
||||||
RESULT_VARIABLE result
|
|
||||||
)
|
|
||||||
if (NOT result EQUAL 0)
|
|
||||||
message(FATAL_ERROR "Failed to install dependencies")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: cmake -P {0}
|
shell: cmake -P {0}
|
||||||
run: |
|
run: |
|
||||||
@@ -516,6 +529,14 @@ jobs:
|
|||||||
unset(NO_DMG)
|
unset(NO_DMG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (NOT "x${{ matrix.config.toolchain_path }}" STREQUAL "x")
|
||||||
|
set(path_separator ":")
|
||||||
|
if ("${{ runner.os }}" STREQUAL "Windows")
|
||||||
|
set(path_separator ";")
|
||||||
|
endif()
|
||||||
|
set(ENV{PATH} "$ENV{GITHUB_WORKSPACE}/${{ matrix.config.toolchain_path }}${path_separator}$ENV{PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND python
|
COMMAND python
|
||||||
-u
|
-u
|
||||||
@@ -673,10 +694,10 @@ jobs:
|
|||||||
name: "Windows Latest MSVC", artifact: "Windows-MSVC",
|
name: "Windows Latest MSVC", artifact: "Windows-MSVC",
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
}
|
}
|
||||||
# - {
|
- {
|
||||||
# name: "Windows Latest MinGW", artifact: "Windows-MinGW",
|
name: "Windows Latest MinGW", artifact: "Windows-MinGW",
|
||||||
# os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
# }
|
}
|
||||||
- {
|
- {
|
||||||
name: "Ubuntu Latest GCC", artifact: "Linux",
|
name: "Ubuntu Latest GCC", artifact: "Linux",
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
|
8
dist/installer/mac/disclaim.entitlements
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
BIN
doc/qtcreator/images/qtcreator-new-project.png
Normal file
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 17 KiB |
BIN
doc/qtcreator/images/qtcreator-new-qt-quick-project.png
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.5 KiB |
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2021 The Qt Company Ltd.
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the Qt Creator documentation.
|
** This file is part of the Qt Creator documentation.
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
To use Conan, install it by using the Qt installer or the tools provided by
|
To use Conan, install it by using the Qt installer or the tools provided by
|
||||||
your operating system. For example, on Windows, you can use the
|
your operating system. For example, on Windows, you can use the
|
||||||
\c {choco install conan} or \{pip install conan} command.
|
\c {choco install conan} or \c {pip install conan} command.
|
||||||
|
|
||||||
To enable the experimental Conan plugin, select \uicontrol Help >
|
To enable the experimental Conan plugin, select \uicontrol Help >
|
||||||
\uicontrol {About Plugins} > \uicontrol Utilities > \uicontrol Conan.
|
\uicontrol {About Plugins} > \uicontrol Utilities > \uicontrol Conan.
|
||||||
|
@@ -97,6 +97,8 @@
|
|||||||
between lines can be useful if there is usually not enough space to
|
between lines can be useful if there is usually not enough space to
|
||||||
display annotations next to the text.
|
display annotations next to the text.
|
||||||
|
|
||||||
|
\image qtcreator-options-text-editor-display.png "Text Editor Display options"
|
||||||
|
|
||||||
If you hide the annotations by deselecting the check box, you can move the
|
If you hide the annotations by deselecting the check box, you can move the
|
||||||
mouse pointer over an icon to view them.
|
mouse pointer over an icon to view them.
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 The Qt Company Ltd.
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the Qt Creator documentation.
|
** This file is part of the Qt Creator documentation.
|
||||||
@@ -40,12 +40,18 @@
|
|||||||
|
|
||||||
\title Configuring the Editor
|
\title Configuring the Editor
|
||||||
|
|
||||||
\QC allows you to configure the text editor to suit your specific
|
You can configure the text editor to suit your specific needs by selecting
|
||||||
needs. To configure the editor, select \uicontrol Tools >
|
\uicontrol Tools > \uicontrol Options > \uicontrol{Text Editor}.
|
||||||
\uicontrol Options > \uicontrol{Text Editor}.
|
|
||||||
|
\image qtcreator-font-colors.png "Text Editor options"
|
||||||
|
|
||||||
|
The settings you specify apply globally to all projects.
|
||||||
|
|
||||||
|
To specify editor behavior for an open project, select \uicontrol Projects >
|
||||||
|
\uicontrol Editor.
|
||||||
|
|
||||||
|
\image qtcreator-editor-settings.png "Editor settings"
|
||||||
|
|
||||||
These settings apply to all projects. To specify editor behavior for an open
|
|
||||||
project, select \uicontrol Projects > \uicontrol Editor.
|
|
||||||
\if defined(qtcreator)
|
\if defined(qtcreator)
|
||||||
For more information, see \l{Specifying Editor Settings}.
|
For more information, see \l{Specifying Editor Settings}.
|
||||||
\endif
|
\endif
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2021 The Qt Company Ltd.
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the Qt Creator documentation.
|
** This file is part of the Qt Creator documentation.
|
||||||
@@ -31,19 +31,22 @@
|
|||||||
|
|
||||||
\image qtcreator-meson-build-settings.png "Meson build settings"
|
\image qtcreator-meson-build-settings.png "Meson build settings"
|
||||||
|
|
||||||
Settings are grouped by category by Meson. All items are user modifiable
|
Meson builds projects in the directory specified in the
|
||||||
except \c backend which is forced to Ninja, \c {buildtype}, \c debug as well
|
\uicontrol {Build directory} field.
|
||||||
as \c optimization to ensure a good compatibility with \QC.
|
|
||||||
|
|
||||||
Each setting type has its own editor. To modif any setting, double-click it,
|
Build settings are grouped by category. You can modify all settings,
|
||||||
either edit the field, or select your choice depending on the control. To
|
except \c backend, which is forced to Ninja, \c {buildtype}, \c debug,
|
||||||
apply changes, select \uicontrol {Apply configuration changes}. This will
|
and \c optimization to ensure compatibility with \QC.
|
||||||
trigger a \c {meson configure} command if there were any configuration
|
|
||||||
changes. If for any reason the build directory configuration is broken,
|
|
||||||
select \uicontrol {Wipe project}. This should fix any build directory.
|
|
||||||
|
|
||||||
\note Any modified setting will remain in bold until \uicontrol
|
To modify a setting, double-click it. Modified settings are formatted in
|
||||||
{Apply configuration changes} is selected.
|
bold until you select \uicontrol {Apply configuration changes} to apply
|
||||||
|
them. This triggers \c {meson configure}. If problems arise, select
|
||||||
|
\uicontrol {Wipe Project} to fix the build directory configuration.
|
||||||
|
|
||||||
|
Meson supports cross-compiling in addition to native building. \QC
|
||||||
|
generates a native build file for you. To use a custom native file or a
|
||||||
|
cross file instead, specify the file name in \uicontrol Parameters.
|
||||||
|
For example, \c {--cross-file cross_file.txt}.
|
||||||
|
|
||||||
For more information about using Meson, see \l{Setting Up Meson}.
|
For more information about using Meson, see \l{Setting Up Meson}.
|
||||||
|
|
||||||
@@ -56,8 +59,7 @@
|
|||||||
|
|
||||||
\image qtcreator-meson-build-steps.png "Meson build steps"
|
\image qtcreator-meson-build-steps.png "Meson build steps"
|
||||||
|
|
||||||
The build errors and warnings are parsed and displayed in the
|
The build errors and warnings are parsed and displayed in \l Issues.
|
||||||
\uicontrol Issues output pane.
|
|
||||||
|
|
||||||
\section1 Meson Clean Steps
|
\section1 Meson Clean Steps
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2020 The Qt Company Ltd.
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the Qt Creator documentation.
|
** This file is part of the Qt Creator documentation.
|
||||||
@@ -99,7 +99,6 @@
|
|||||||
The following features are not supported yet:
|
The following features are not supported yet:
|
||||||
|
|
||||||
\list
|
\list
|
||||||
\li Cross compilation.
|
|
||||||
\li Showing header files in project tree.
|
\li Showing header files in project tree.
|
||||||
\li Configuration change detection, for example when building triggers a
|
\li Configuration change detection, for example when building triggers a
|
||||||
Meson configuration first.
|
Meson configuration first.
|
||||||
|
@@ -80,7 +80,7 @@
|
|||||||
In the first step, you select a template for the project. You can filter
|
In the first step, you select a template for the project. You can filter
|
||||||
templates (1) to view only those that apply to a particular target platform.
|
templates (1) to view only those that apply to a particular target platform.
|
||||||
|
|
||||||
\image qtcreator-new-qt-quick-project-wizard.png
|
\image qtcreator-new-project.png
|
||||||
|
|
||||||
Next, you select a location for the project and specify settings for it.
|
Next, you select a location for the project and specify settings for it.
|
||||||
|
|
||||||
@@ -326,7 +326,7 @@
|
|||||||
\uicontrol {New Subproject}. Follow the steps in the
|
\uicontrol {New Subproject}. Follow the steps in the
|
||||||
\uicontrol {New Subproject} wizard to create a subproject.
|
\uicontrol {New Subproject} wizard to create a subproject.
|
||||||
|
|
||||||
\image qtcreator-new-subproject.png
|
\image qtcreator-new-qt-quick-project.png
|
||||||
|
|
||||||
To add an existing project as a subproject, select
|
To add an existing project as a subproject, select
|
||||||
\uicontrol {Add Existing Projects} in the context menu.
|
\uicontrol {Add Existing Projects} in the context menu.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2021 The Qt Company Ltd.
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the Qt Creator documentation.
|
** This file is part of the Qt Creator documentation.
|
||||||
@@ -38,6 +38,18 @@
|
|||||||
execute any JavaScript functions. Therefore, you must make sure that the
|
execute any JavaScript functions. Therefore, you must make sure that the
|
||||||
port is properly protected by a firewall.
|
port is properly protected by a firewall.
|
||||||
|
|
||||||
|
Optionally, in \uicontrol {Additional startup commands}, you can enter
|
||||||
|
additional settings for debugging C++:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li \l{Adding Custom Debugging Helpers}{Custom debugging helpers}
|
||||||
|
\li \l{Specifying GDB Settings}{GDB commands} to execute after GDB
|
||||||
|
has started, but before the debugged program is started or
|
||||||
|
attached, and before the debugging helpers are initialized
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
However, you can usually leave this field empty.
|
||||||
|
|
||||||
For more information about debugging, see \l{Debugging}.
|
For more information about debugging, see \l{Debugging}.
|
||||||
|
|
||||||
//! [run settings debugger]
|
//! [run settings debugger]
|
||||||
|
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
\title Creating Qt Quick Projects
|
\title Creating Qt Quick Projects
|
||||||
|
|
||||||
\image qmldesigner-new-project.png "New Project dialog"
|
\image qtcreator-new-qt-quick-project.png "New Project dialog"
|
||||||
|
|
||||||
The following table lists the wizard templates for creating a new
|
The following table lists the wizard templates for creating a new
|
||||||
Qt Quick project from scratch.
|
Qt Quick project from scratch.
|
||||||
|
@@ -299,7 +299,7 @@
|
|||||||
\uicontrol {Include Old Entries} and \uicontrol {Include Tags}.
|
\uicontrol {Include Old Entries} and \uicontrol {Include Tags}.
|
||||||
|
|
||||||
To add a tag to a change in the change log, select \uicontrol Branches >
|
To add a tag to a change in the change log, select \uicontrol Branches >
|
||||||
\uicontrol Log. Select the change, and then select > \uicontrol {Add Tag
|
\uicontrol Log. Select the change, and then select \uicontrol {Add Tag
|
||||||
for Change} in the context menu.
|
for Change} in the context menu.
|
||||||
|
|
||||||
If you checked out a specific commit, the list of branches displays a
|
If you checked out a specific commit, the list of branches displays a
|
||||||
|
BIN
doc/qtdesignstudio/images/icons/align-camera-on.png
Normal file
After Width: | Height: | Size: 309 B |
BIN
doc/qtdesignstudio/images/icons/align-view-on.png
Normal file
After Width: | Height: | Size: 321 B |
BIN
doc/qtdesignstudio/images/icons/particle-animation-off.png
Normal file
After Width: | Height: | Size: 549 B |
BIN
doc/qtdesignstudio/images/icons/particle-animation-on.png
Normal file
After Width: | Height: | Size: 316 B |
BIN
doc/qtdesignstudio/images/icons/particle-pause.png
Normal file
After Width: | Height: | Size: 120 B |
BIN
doc/qtdesignstudio/images/icons/particle-play.png
Normal file
After Width: | Height: | Size: 159 B |
BIN
doc/qtdesignstudio/images/icons/particle-restart.png
Normal file
After Width: | Height: | Size: 302 B |
BIN
doc/qtdesignstudio/images/icons/particles-seek.png
Normal file
After Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 40 KiB |
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2021 The Qt Company Ltd.
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the Qt Design Studio documentation.
|
** This file is part of the Qt Design Studio documentation.
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
/*!
|
/*!
|
||||||
\previouspage qtquick-form-editor.html
|
\previouspage qtquick-form-editor.html
|
||||||
\page studio-3d-editor.html
|
\page studio-3d-editor.html
|
||||||
\nextpage quick-library.html
|
\nextpage quick-components-view.html
|
||||||
|
|
||||||
\title 3D Editor
|
\title 3D Editor
|
||||||
|
|
||||||
@@ -64,11 +64,11 @@
|
|||||||
affect only the local transformations of the component or whether they
|
affect only the local transformations of the component or whether they
|
||||||
transform with respect to the global space.
|
transform with respect to the global space.
|
||||||
|
|
||||||
Additional helpful features when editing 3D scenes are the \e {edit light},
|
Another helpful feature when editing 3D scenes is the \e {edit light},
|
||||||
which is a quick way to light the scene, and the grid that helps you to
|
which is a quick way to light the scene.
|
||||||
navigate in 3D space. Select the \inlineimage grid_on.png
|
|
||||||
(\uicontrol {Toggle Grid Visibility}) or press \key G to show or hide the
|
Additionally, you can toggle the visibility of the grid, selection boxes,
|
||||||
grid.
|
icon gizmos, and camera frustums in the 3D scene.
|
||||||
|
|
||||||
To refresh the contents of \uicontrol {3D Editor}, press \key P or
|
To refresh the contents of \uicontrol {3D Editor}, press \key P or
|
||||||
select the \inlineimage icons/reset.png
|
select the \inlineimage icons/reset.png
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
\li To pan, press \key Alt (or \key Option on \macos) and use the
|
\li To pan, press \key Alt (or \key Option on \macos) and use the
|
||||||
middle mouse button to click and drag anywhere in the rendered
|
middle mouse button to click and drag anywhere in the rendered
|
||||||
view to slide the view around.
|
view to slide the view around.
|
||||||
\note At the moment it is not possible to pan using Magic Mouse.
|
\note It is not possible to pan using Magic Mouse.
|
||||||
\li To orbit, press \key Alt and click and drag anywhere in the rendered
|
\li To orbit, press \key Alt and click and drag anywhere in the rendered
|
||||||
view to rotate the view.
|
view to rotate the view.
|
||||||
\li To zoom, use the mouse wheel or press \key Alt and right-click
|
\li To zoom, use the mouse wheel or press \key Alt and right-click
|
||||||
@@ -109,7 +109,7 @@
|
|||||||
select \inlineimage fit_selected.png
|
select \inlineimage fit_selected.png
|
||||||
(\uicontrol {Fit Selected}) or press \key F.
|
(\uicontrol {Fit Selected}) or press \key F.
|
||||||
|
|
||||||
The world axis helper (1) shows the direction of the world axes in view.
|
The world axis helper (1) shows the direction of the world axes in the view.
|
||||||
To point the camera at the currently selected component in the direction of
|
To point the camera at the currently selected component in the direction of
|
||||||
an axis, click the axis. Clicking the dot at the end of the axis will point
|
an axis, click the axis. Clicking the dot at the end of the axis will point
|
||||||
the camera at the opposite direction of the axis. If no component is
|
the camera at the opposite direction of the axis. If no component is
|
||||||
@@ -179,6 +179,7 @@
|
|||||||
{keyboard shortcuts} applicable to your operating system, for example,
|
{keyboard shortcuts} applicable to your operating system, for example,
|
||||||
\key Ctrl+C and \key Ctrl+V on Windows to copy-paste components.
|
\key Ctrl+C and \key Ctrl+V on Windows to copy-paste components.
|
||||||
|
|
||||||
|
\target moving components 3d editor
|
||||||
\section1 Moving Components
|
\section1 Moving Components
|
||||||
|
|
||||||
\image studio-3d-editor-move.png "3D Editor in move mode"
|
\image studio-3d-editor-move.png "3D Editor in move mode"
|
||||||
@@ -233,6 +234,76 @@
|
|||||||
gray handle at the center of the component.
|
gray handle at the center of the component.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
|
\section1 Aligning Views and Cameras
|
||||||
|
|
||||||
|
To align a camera to the \uicontrol {3D Editor} view:
|
||||||
|
\list 1
|
||||||
|
\li Select a camera in \uicontrol {3D Editor} or \uicontrol {Navigator}.
|
||||||
|
\li In \uicontrol {3D Editor},
|
||||||
|
select \inlineimage icons/align-camera-on.png
|
||||||
|
.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
This moves and rotates the camera so that the camera shows the same view
|
||||||
|
as the current view in \uicontrol {3D Editor}.
|
||||||
|
|
||||||
|
To align the \uicontrol {3D Editor} view to a camera:
|
||||||
|
\list 1
|
||||||
|
\li Select a camera in \uicontrol {3D Editor} or \uicontrol {Navigator}.
|
||||||
|
\li In \uicontrol {3D Editor},
|
||||||
|
select \inlineimage icons/align-view-on.png
|
||||||
|
.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
This copies the position as well as x and y rotation values from the
|
||||||
|
camera and applies them to \uicontrol {3D Editor}.
|
||||||
|
|
||||||
|
\section1 Toggling Visibility
|
||||||
|
|
||||||
|
To toggle the visibility of objects in \uicontrol {3D Editor}, select
|
||||||
|
\inlineimage icons/visibilityon.png
|
||||||
|
in the toolbar. This opens a menu with the following options:
|
||||||
|
|
||||||
|
\table
|
||||||
|
\row
|
||||||
|
\li Show Grid
|
||||||
|
\li Toggles the visibility of the helper grid.
|
||||||
|
\row
|
||||||
|
\li Show Selection Boxes
|
||||||
|
\li Toggles the visibility of selection boxes for selected 3D objects.
|
||||||
|
\row
|
||||||
|
\li Show Icon Gizmos
|
||||||
|
\li Toggles the visibility of icon gizmos for object such as cameras,
|
||||||
|
lights, and particle systems.
|
||||||
|
\row
|
||||||
|
\li Always Show Camera Frustums
|
||||||
|
\li Toggles between always showing the camera frustum and showing it
|
||||||
|
only for cameras selected in \uicontrol {3D Editor}.
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
\section1 Particle Editor
|
||||||
|
|
||||||
|
The particle editor tools help you preview your particle systems in
|
||||||
|
\uicontrol {3D Editor}. You can select one particle system to preview at a
|
||||||
|
time.
|
||||||
|
|
||||||
|
To preview a particle system in \uicontrol{3D Editor}:
|
||||||
|
|
||||||
|
\list 1
|
||||||
|
\li Select a particle system in \uicontrol Navigator or
|
||||||
|
\uicontrol {3D Editor}.
|
||||||
|
\li In the \uicontrol {3D Editor}, select
|
||||||
|
\inlineimage icons/particle-animation-on.png
|
||||||
|
to activate particle animation. Now you can see the particle animation in
|
||||||
|
\uicontrol{3D Editor}.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
You can pause the particle animation by selecting
|
||||||
|
\inlineimage icons/particle-animation-on.png
|
||||||
|
. When the animation is paused, you can use
|
||||||
|
\inlineimage icons/particles-seek.png
|
||||||
|
to manually seek forward or backward in the particle animation.
|
||||||
|
|
||||||
\section1 Summary of the 3D Editor Toolbar Buttons
|
\section1 Summary of the 3D Editor Toolbar Buttons
|
||||||
|
|
||||||
The \uicontrol {3D Editor} toolbar contains the following buttons:
|
The \uicontrol {3D Editor} toolbar contains the following buttons:
|
||||||
@@ -254,7 +325,7 @@
|
|||||||
\inlineimage move_on.png
|
\inlineimage move_on.png
|
||||||
\li Activate the Move Tool
|
\li Activate the Move Tool
|
||||||
\li \key W
|
\li \key W
|
||||||
\li \l{Moving Components}
|
\li \l{moving components 3d editor}{Moving Components}
|
||||||
\row
|
\row
|
||||||
\li \inlineimage rotate_off.png
|
\li \inlineimage rotate_off.png
|
||||||
\inlineimage rotate_on.png
|
\inlineimage rotate_on.png
|
||||||
@@ -291,17 +362,47 @@
|
|||||||
\li \key U
|
\li \key U
|
||||||
\li \l{Using Edit Light}
|
\li \l{Using Edit Light}
|
||||||
\row
|
\row
|
||||||
\li \inlineimage grid_off.png
|
\li \inlineimage icons/align-camera-on.png
|
||||||
\inlineimage grid_on.png
|
\li Align Selected Cameras to View
|
||||||
\li Toggle Grid Visibility
|
|
||||||
\li \key G
|
|
||||||
\li
|
\li
|
||||||
|
\li\l{Aligning Views and Cameras}
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/align-view-on.png
|
||||||
|
\li Align View to Selected Camera
|
||||||
|
\li
|
||||||
|
\li \l{Aligning Views and Cameras}
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/visibilityon.png
|
||||||
|
\li Visibility Toggles
|
||||||
|
\li
|
||||||
|
\li \l{Toggling Visibility}
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/particles-seek.png
|
||||||
|
\li Seek Particle System Time
|
||||||
|
\li
|
||||||
|
\li \l{Particle Editor}
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/particle-animation-on.png
|
||||||
|
\inlineimage icons/particle-animation-off.png
|
||||||
|
\li Toggle Particle Animation
|
||||||
|
\li \key V
|
||||||
|
\li \l{Particle Editor}
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/particle-play.png
|
||||||
|
\inlineimage icons/particle-pause.png
|
||||||
|
\li Play/Pause Particles
|
||||||
|
\li \key ,
|
||||||
|
\li \l{Particle Editor}
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/particle-restart.png
|
||||||
|
\li Restart Particles
|
||||||
|
\li \key /
|
||||||
|
\li \l{Particle Editor}
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/reset.png
|
\li \inlineimage icons/reset.png
|
||||||
\li Reset View
|
\li Reset View
|
||||||
\li \key R
|
\li \key P
|
||||||
\li
|
\li
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@@ -229,6 +229,16 @@ def codesign_call():
|
|||||||
codesign_call.extend(signing_flags.split())
|
codesign_call.extend(signing_flags.split())
|
||||||
return codesign_call
|
return codesign_call
|
||||||
|
|
||||||
|
def codesign_executable(path):
|
||||||
|
codesign = codesign_call()
|
||||||
|
if not codesign:
|
||||||
|
return
|
||||||
|
entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
|
||||||
|
'installer', 'mac', os.path.basename(path) + '.entitlements')
|
||||||
|
if os.path.exists(entitlements_path):
|
||||||
|
codesign.extend(['--entitlements', entitlements_path])
|
||||||
|
subprocess.check_call(codesign + [path])
|
||||||
|
|
||||||
def os_walk(path, filter, function):
|
def os_walk(path, filter, function):
|
||||||
for r, _, fs in os.walk(path):
|
for r, _, fs in os.walk(path):
|
||||||
for f in fs:
|
for f in fs:
|
||||||
@@ -237,20 +247,21 @@ def os_walk(path, filter, function):
|
|||||||
function(ff)
|
function(ff)
|
||||||
|
|
||||||
def conditional_sign_recursive(path, filter):
|
def conditional_sign_recursive(path, filter):
|
||||||
codesign = codesign_call()
|
if is_mac_platform():
|
||||||
if is_mac_platform() and codesign:
|
os_walk(path, filter, lambda fp: codesign_executable(fp))
|
||||||
os_walk(path, filter, lambda fp: subprocess.check_call(codesign + [fp]))
|
|
||||||
|
|
||||||
def codesign(app_path):
|
def codesign(app_path):
|
||||||
|
codesign = codesign_call()
|
||||||
|
if not codesign or not is_mac_platform():
|
||||||
|
return
|
||||||
# sign all executables in Resources
|
# sign all executables in Resources
|
||||||
conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Resources'),
|
conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Resources'),
|
||||||
lambda ff: os.access(ff, os.X_OK))
|
lambda ff: os.access(ff, os.X_OK))
|
||||||
# sign all libraries in Imports
|
# sign all libraries in Imports
|
||||||
conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Imports'),
|
conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Imports'),
|
||||||
lambda ff: ff.endswith('.dylib'))
|
lambda ff: ff.endswith('.dylib'))
|
||||||
codesign = codesign_call()
|
|
||||||
if is_mac_platform() and codesign:
|
# sign the whole bundle
|
||||||
entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
|
entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
|
||||||
'installer', 'mac', 'entitlements.plist')
|
'installer', 'mac', 'entitlements.plist')
|
||||||
# sign the whole bundle
|
|
||||||
subprocess.check_call(codesign + ['--deep', app_path, '--entitlements', entitlements_path])
|
subprocess.check_call(codesign + ['--deep', app_path, '--entitlements', entitlements_path])
|
||||||
|
@@ -50,6 +50,7 @@ public:
|
|||||||
ShowSelectionBox,
|
ShowSelectionBox,
|
||||||
ShowIconGizmo,
|
ShowIconGizmo,
|
||||||
ShowCameraFrustum,
|
ShowCameraFrustum,
|
||||||
|
ShowParticleEmitter,
|
||||||
Edit3DParticleModeToggle,
|
Edit3DParticleModeToggle,
|
||||||
ParticlesPlay,
|
ParticlesPlay,
|
||||||
ParticlesRestart,
|
ParticlesRestart,
|
||||||
|
@@ -35,7 +35,6 @@
|
|||||||
<file>mockfiles/qt6/LightGizmo.qml</file>
|
<file>mockfiles/qt6/LightGizmo.qml</file>
|
||||||
<file>mockfiles/qt6/LightIconGizmo.qml</file>
|
<file>mockfiles/qt6/LightIconGizmo.qml</file>
|
||||||
<file>mockfiles/qt6/LightModel.qml</file>
|
<file>mockfiles/qt6/LightModel.qml</file>
|
||||||
<file>mockfiles/qt6/ParticleSystemGizmo.qml</file>
|
|
||||||
<file>mockfiles/qt6/Line3D.qml</file>
|
<file>mockfiles/qt6/Line3D.qml</file>
|
||||||
<file>mockfiles/qt6/MaterialNodeView.qml</file>
|
<file>mockfiles/qt6/MaterialNodeView.qml</file>
|
||||||
<file>mockfiles/qt6/ModelNode2DImageView.qml</file>
|
<file>mockfiles/qt6/ModelNode2DImageView.qml</file>
|
||||||
@@ -44,6 +43,8 @@
|
|||||||
<file>mockfiles/qt6/MoveGizmo.qml</file>
|
<file>mockfiles/qt6/MoveGizmo.qml</file>
|
||||||
<file>mockfiles/qt6/NodeNodeView.qml</file>
|
<file>mockfiles/qt6/NodeNodeView.qml</file>
|
||||||
<file>mockfiles/qt6/Overlay2D.qml</file>
|
<file>mockfiles/qt6/Overlay2D.qml</file>
|
||||||
|
<file>mockfiles/qt6/ParticleSystemGizmo.qml</file>
|
||||||
|
<file>mockfiles/qt6/ParticleEmitterGizmo.qml</file>
|
||||||
<file>mockfiles/qt6/PlanarDraggable.qml</file>
|
<file>mockfiles/qt6/PlanarDraggable.qml</file>
|
||||||
<file>mockfiles/qt6/PlanarMoveHandle.qml</file>
|
<file>mockfiles/qt6/PlanarMoveHandle.qml</file>
|
||||||
<file>mockfiles/qt6/PlanarScaleHandle.qml</file>
|
<file>mockfiles/qt6/PlanarScaleHandle.qml</file>
|
||||||
|
@@ -385,14 +385,12 @@ Item {
|
|||||||
lightIconGizmos[slotFound].targetNode = obj;
|
lightIconGizmos[slotFound].targetNode = obj;
|
||||||
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
||||||
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No free gizmos available, create a new one
|
// No free gizmos available, create a new one
|
||||||
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
|
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
|
||||||
if (gizmoComponent.status === Component.Ready) {
|
if (gizmoComponent.status === Component.Ready) {
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
var gizmo = gizmoComponent.createObject(overlayView,
|
var gizmo = gizmoComponent.createObject(overlayView,
|
||||||
{"view3D": overlayView, "targetNode": obj,
|
{"view3D": overlayView, "targetNode": obj,
|
||||||
"selectedNodes": selectedNodes, "scene": scene,
|
"selectedNodes": selectedNodes, "scene": scene,
|
||||||
@@ -426,7 +424,6 @@ Item {
|
|||||||
cameraGizmos[slotFound].targetNode = obj;
|
cameraGizmos[slotFound].targetNode = obj;
|
||||||
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
||||||
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +431,6 @@ Item {
|
|||||||
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
|
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
|
||||||
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
|
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
|
||||||
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
|
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
|
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
|
||||||
var frustum = frustumComponent.createObject(
|
var frustum = frustumComponent.createObject(
|
||||||
overlayScene,
|
overlayScene,
|
||||||
@@ -463,7 +459,6 @@ Item {
|
|||||||
if (lightIconGizmos[i].targetNode === obj) {
|
if (lightIconGizmos[i].targetNode === obj) {
|
||||||
lightIconGizmos[i].scene = null;
|
lightIconGizmos[i].scene = null;
|
||||||
lightIconGizmos[i].targetNode = null;
|
lightIconGizmos[i].targetNode = null;
|
||||||
_generalHelper.unregisterGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -475,7 +470,6 @@ Item {
|
|||||||
if (cameraGizmos[i].targetNode === obj) {
|
if (cameraGizmos[i].targetNode === obj) {
|
||||||
cameraGizmos[i].scene = null;
|
cameraGizmos[i].scene = null;
|
||||||
cameraGizmos[i].targetNode = null;
|
cameraGizmos[i].targetNode = null;
|
||||||
_generalHelper.unregisterGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,7 @@ Item {
|
|||||||
property bool showSelectionBox: true
|
property bool showSelectionBox: true
|
||||||
property bool showIconGizmo: true
|
property bool showIconGizmo: true
|
||||||
property bool showCameraFrustum: false
|
property bool showCameraFrustum: false
|
||||||
|
property bool showParticleEmitter: false
|
||||||
property bool usePerspective: true
|
property bool usePerspective: true
|
||||||
property bool globalOrientation: false
|
property bool globalOrientation: false
|
||||||
property alias contentItem: contentItem
|
property alias contentItem: contentItem
|
||||||
@@ -58,9 +59,10 @@ Item {
|
|||||||
property var lightIconGizmos: []
|
property var lightIconGizmos: []
|
||||||
property var cameraGizmos: []
|
property var cameraGizmos: []
|
||||||
property var particleSystemIconGizmos: []
|
property var particleSystemIconGizmos: []
|
||||||
|
property var particleEmitterGizmos: []
|
||||||
property var selectionBoxes: []
|
property var selectionBoxes: []
|
||||||
property rect viewPortRect: Qt.rect(0, 0, 1000, 1000)
|
property rect viewPortRect: Qt.rect(0, 0, 1000, 1000)
|
||||||
|
property Node activeParticleSystem: null
|
||||||
property bool shuttingDown: false
|
property bool shuttingDown: false
|
||||||
|
|
||||||
property real fps: 0
|
property real fps: 0
|
||||||
@@ -77,6 +79,7 @@ Item {
|
|||||||
onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox);
|
onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox);
|
||||||
onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo);
|
onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo);
|
||||||
onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum);
|
onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum);
|
||||||
|
onShowParticleEmitterChanged: _generalHelper.storeToolState(sceneId, "showParticleEmitter", showParticleEmitter);
|
||||||
onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
|
onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
|
||||||
onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode);
|
onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode);
|
||||||
|
|
||||||
@@ -232,6 +235,11 @@ Item {
|
|||||||
else if (resetToDefault)
|
else if (resetToDefault)
|
||||||
showCameraFrustum = false;
|
showCameraFrustum = false;
|
||||||
|
|
||||||
|
if ("showParticleEmitter" in toolStates)
|
||||||
|
showParticleEmitter = toolStates.showParticleEmitter;
|
||||||
|
else if (resetToDefault)
|
||||||
|
showParticleEmitter = false;
|
||||||
|
|
||||||
if ("usePerspective" in toolStates)
|
if ("usePerspective" in toolStates)
|
||||||
usePerspective = toolStates.usePerspective;
|
usePerspective = toolStates.usePerspective;
|
||||||
else if (resetToDefault)
|
else if (resetToDefault)
|
||||||
@@ -265,6 +273,7 @@ Item {
|
|||||||
_generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox)
|
_generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox)
|
||||||
_generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo)
|
_generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo)
|
||||||
_generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum)
|
_generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum)
|
||||||
|
_generalHelper.storeToolState(sceneId, "showParticleEmitter", showParticleEmitter)
|
||||||
_generalHelper.storeToolState(sceneId, "usePerspective", usePerspective)
|
_generalHelper.storeToolState(sceneId, "usePerspective", usePerspective)
|
||||||
_generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation)
|
_generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation)
|
||||||
_generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
|
_generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
|
||||||
@@ -376,14 +385,12 @@ Item {
|
|||||||
lightIconGizmos[slotFound].targetNode = obj;
|
lightIconGizmos[slotFound].targetNode = obj;
|
||||||
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
||||||
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No free gizmos available, create a new one
|
// No free gizmos available, create a new one
|
||||||
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
|
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
|
||||||
if (gizmoComponent.status === Component.Ready) {
|
if (gizmoComponent.status === Component.Ready) {
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
var gizmo = gizmoComponent.createObject(overlayView,
|
var gizmo = gizmoComponent.createObject(overlayView,
|
||||||
{"view3D": overlayView, "targetNode": obj,
|
{"view3D": overlayView, "targetNode": obj,
|
||||||
"selectedNodes": selectedNodes, "scene": scene,
|
"selectedNodes": selectedNodes, "scene": scene,
|
||||||
@@ -417,7 +424,6 @@ Item {
|
|||||||
cameraGizmos[slotFound].targetNode = obj;
|
cameraGizmos[slotFound].targetNode = obj;
|
||||||
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
||||||
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +431,6 @@ Item {
|
|||||||
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
|
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
|
||||||
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
|
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
|
||||||
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
|
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
|
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
|
||||||
var frustum = frustumComponent.createObject(
|
var frustum = frustumComponent.createObject(
|
||||||
overlayScene,
|
overlayScene,
|
||||||
@@ -466,26 +471,66 @@ Item {
|
|||||||
particleSystemIconGizmos[slotFound].targetNode = obj;
|
particleSystemIconGizmos[slotFound].targetNode = obj;
|
||||||
particleSystemIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
particleSystemIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
||||||
particleSystemIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
particleSystemIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No free gizmos available, create a new one
|
// No free gizmos available, create a new one
|
||||||
var gizmoComponent = Qt.createComponent("ParticleSystemGizmo.qml");
|
var gizmoComponent = Qt.createComponent("ParticleSystemGizmo.qml");
|
||||||
if (gizmoComponent.status === Component.Ready) {
|
if (gizmoComponent.status === Component.Ready) {
|
||||||
_generalHelper.registerGizmoTarget(obj);
|
|
||||||
var gizmo = gizmoComponent.createObject(overlayView,
|
var gizmo = gizmoComponent.createObject(overlayView,
|
||||||
{"view3D": overlayView, "targetNode": obj,
|
{"view3D": overlayView, "targetNode": obj,
|
||||||
"selectedNodes": selectedNodes, "scene": scene,
|
"selectedNodes": selectedNodes, "scene": scene,
|
||||||
"activeScene": activeScene,
|
"activeScene": activeScene,
|
||||||
"locked": _generalHelper.isLocked(obj),
|
"locked": _generalHelper.isLocked(obj),
|
||||||
"hidden": _generalHelper.isHidden(obj),
|
"hidden": _generalHelper.isHidden(obj),
|
||||||
"globalShow": showIconGizmo});
|
"globalShow": showIconGizmo,
|
||||||
|
"activeParticleSystem": activeParticleSystem});
|
||||||
particleSystemIconGizmos[particleSystemIconGizmos.length] = gizmo;
|
particleSystemIconGizmos[particleSystemIconGizmos.length] = gizmo;
|
||||||
gizmo.clicked.connect(handleObjectClicked);
|
gizmo.clicked.connect(handleObjectClicked);
|
||||||
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
||||||
gizmo.activeScene = Qt.binding(function() {return activeScene;});
|
gizmo.activeScene = Qt.binding(function() {return activeScene;});
|
||||||
gizmo.globalShow = Qt.binding(function() {return showIconGizmo;});
|
gizmo.globalShow = Qt.binding(function() {return showIconGizmo;});
|
||||||
|
gizmo.activeParticleSystem = Qt.binding(function() {return activeParticleSystem;});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addParticleEmitterGizmo(scene, obj)
|
||||||
|
{
|
||||||
|
// Insert into first available gizmo if we don't already have gizmo for this object
|
||||||
|
var slotFound = -1;
|
||||||
|
for (var i = 0; i < particleEmitterGizmos.length; ++i) {
|
||||||
|
if (!particleEmitterGizmos[i].targetNode) {
|
||||||
|
slotFound = i;
|
||||||
|
} else if (particleEmitterGizmos[i].targetNode === obj) {
|
||||||
|
particleEmitterGizmos[i].scene = scene;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slotFound !== -1) {
|
||||||
|
particleEmitterGizmos[slotFound].scene = scene;
|
||||||
|
particleEmitterGizmos[slotFound].targetNode = obj;
|
||||||
|
particleEmitterGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||||
|
particleEmitterGizmos[slotFound].systemHidden = _generalHelper.isHidden(obj.system);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No free gizmos available, create a new one
|
||||||
|
var gizmoComponent = Qt.createComponent("ParticleEmitterGizmo.qml");
|
||||||
|
if (gizmoComponent.status === Component.Ready) {
|
||||||
|
var gizmo = gizmoComponent.createObject(
|
||||||
|
overlayScene,
|
||||||
|
{"targetNode": obj, "selectedNodes": selectedNodes,
|
||||||
|
"activeParticleSystem": activeParticleSystem, "scene": scene,
|
||||||
|
"activeScene": activeScene, "hidden": _generalHelper.isHidden(obj),
|
||||||
|
"systemHidden": _generalHelper.isHidden(obj.system),
|
||||||
|
"globalShow": showParticleEmitter});
|
||||||
|
|
||||||
|
particleEmitterGizmos[particleEmitterGizmos.length] = gizmo;
|
||||||
|
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
||||||
|
gizmo.activeParticleSystem = Qt.binding(function() {return activeParticleSystem;});
|
||||||
|
gizmo.globalShow = Qt.binding(function() {return showParticleEmitter;});
|
||||||
|
gizmo.activeScene = Qt.binding(function() {return activeScene;});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +540,6 @@ Item {
|
|||||||
if (lightIconGizmos[i].targetNode === obj) {
|
if (lightIconGizmos[i].targetNode === obj) {
|
||||||
lightIconGizmos[i].scene = null;
|
lightIconGizmos[i].scene = null;
|
||||||
lightIconGizmos[i].targetNode = null;
|
lightIconGizmos[i].targetNode = null;
|
||||||
_generalHelper.unregisterGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,7 +551,6 @@ Item {
|
|||||||
if (cameraGizmos[i].targetNode === obj) {
|
if (cameraGizmos[i].targetNode === obj) {
|
||||||
cameraGizmos[i].scene = null;
|
cameraGizmos[i].scene = null;
|
||||||
cameraGizmos[i].targetNode = null;
|
cameraGizmos[i].targetNode = null;
|
||||||
_generalHelper.unregisterGizmoTarget(obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,7 +562,17 @@ Item {
|
|||||||
if (particleSystemIconGizmos[i].targetNode === obj) {
|
if (particleSystemIconGizmos[i].targetNode === obj) {
|
||||||
particleSystemIconGizmos[i].scene = null;
|
particleSystemIconGizmos[i].scene = null;
|
||||||
particleSystemIconGizmos[i].targetNode = null;
|
particleSystemIconGizmos[i].targetNode = null;
|
||||||
_generalHelper.unregisterGizmoTarget(obj);
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function releaseParticleEmitterGizmo(obj)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < particleEmitterGizmos.length; ++i) {
|
||||||
|
if (particleEmitterGizmos[i].targetNode === obj) {
|
||||||
|
particleEmitterGizmos[i].scene = null;
|
||||||
|
particleEmitterGizmos[i].targetNode = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -555,6 +608,16 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateParticleEmitterGizmoScene(scene, obj)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < particleEmitterGizmos.length; ++i) {
|
||||||
|
if (particleEmitterGizmos[i].targetNode === obj) {
|
||||||
|
particleEmitterGizmos[i].scene = scene;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
createEditView();
|
createEditView();
|
||||||
selectObjects([]);
|
selectObjects([]);
|
||||||
@@ -588,7 +651,6 @@ Item {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
function onHiddenStateChanged(node)
|
function onHiddenStateChanged(node)
|
||||||
{
|
{
|
||||||
@@ -610,6 +672,15 @@ Item {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (var i = 0; i < particleEmitterGizmos.length; ++i) {
|
||||||
|
if (particleEmitterGizmos[i].targetNode === node) {
|
||||||
|
particleEmitterGizmos[i].hidden = _generalHelper.isHidden(node);
|
||||||
|
return;
|
||||||
|
} else if (particleEmitterGizmos[i].targetNode && particleEmitterGizmos[i].targetNode.system === node) {
|
||||||
|
particleEmitterGizmos[i].systemHidden = _generalHelper.isHidden(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,9 +881,16 @@ Item {
|
|||||||
|
|
||||||
onPressed: (mouse)=> {
|
onPressed: (mouse)=> {
|
||||||
if (viewRoot.editView) {
|
if (viewRoot.editView) {
|
||||||
var pickResult = _generalHelper.pickViewAt(viewRoot.editView, mouse.x, mouse.y);
|
// First pick overlay to check for hits there
|
||||||
handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit),
|
var pickResult = _generalHelper.pickViewAt(overlayView, mouse.x, mouse.y);
|
||||||
mouse.modifiers & Qt.ControlModifier);
|
var resolvedResult = _generalHelper.resolvePick(pickResult.objectHit);
|
||||||
|
if (!resolvedResult) {
|
||||||
|
// No hits from overlay view, pick the main scene
|
||||||
|
pickResult = _generalHelper.pickViewAt(viewRoot.editView, mouse.x, mouse.y);
|
||||||
|
resolvedResult = _generalHelper.resolvePick(pickResult.objectHit);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleObjectClicked(resolvedResult, mouse.modifiers & Qt.ControlModifier);
|
||||||
|
|
||||||
if (pickResult.objectHit) {
|
if (pickResult.objectHit) {
|
||||||
if (transformMode === EditView3D.TransformMode.Move)
|
if (transformMode === EditView3D.TransformMode.Move)
|
||||||
|
@@ -47,6 +47,7 @@ Item {
|
|||||||
property bool locked: false
|
property bool locked: false
|
||||||
property bool globalShow: true
|
property bool globalShow: true
|
||||||
property bool canBeVisible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false)
|
property bool canBeVisible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false)
|
||||||
|
property real iconOpacity: selected ? 0.2 : 1
|
||||||
|
|
||||||
property alias iconSource: iconImage.source
|
property alias iconSource: iconImage.source
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ Item {
|
|||||||
border.color: "#7777ff"
|
border.color: "#7777ff"
|
||||||
border.width: !iconGizmo.locked && iconGizmo.highlightOnHover && iconGizmo.hasMouse ? 2 : 0
|
border.width: !iconGizmo.locked && iconGizmo.highlightOnHover && iconGizmo.hasMouse ? 2 : 0
|
||||||
radius: 5
|
radius: 5
|
||||||
opacity: iconGizmo.selected ? 0.2 : 1
|
opacity: iconGizmo.iconOpacity
|
||||||
Image {
|
Image {
|
||||||
id: iconImage
|
id: iconImage
|
||||||
fillMode: Image.Pad
|
fillMode: Image.Pad
|
||||||
|
@@ -0,0 +1,127 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick3D
|
||||||
|
import QtQuick3D.Particles3D
|
||||||
|
|
||||||
|
Node {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property Node targetNode: null
|
||||||
|
property var selectedNodes: []
|
||||||
|
property Node activeParticleSystem: null
|
||||||
|
property Node scene: null
|
||||||
|
property Node activeScene: null
|
||||||
|
property bool hidden: false
|
||||||
|
property bool systemHidden: false
|
||||||
|
property Node shapeModel: null
|
||||||
|
property bool globalShow: false
|
||||||
|
property bool canBeVisible: activeScene === scene && targetNode && !hidden && !systemHidden
|
||||||
|
property bool partOfActiveSystem: root.targetNode && root.targetNode.system === activeParticleSystem
|
||||||
|
|
||||||
|
opacity: 0.15
|
||||||
|
|
||||||
|
readonly property bool selected: selectedNodes.includes(targetNode)
|
||||||
|
|
||||||
|
visible: canBeVisible && (globalShow || selected)
|
||||||
|
|
||||||
|
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
|
||||||
|
rotation: targetNode ? targetNode.sceneRotation : Qt.quaternion(1, 0, 0, 0)
|
||||||
|
scale: targetNode ? targetNode.sceneScale : Qt.vector3d(1, 1, 1)
|
||||||
|
|
||||||
|
function basicShape()
|
||||||
|
{
|
||||||
|
if (targetNode && targetNode.shape && targetNode.shape instanceof ParticleShape3D) {
|
||||||
|
if (targetNode.shape.type === ParticleShape3D.Cube)
|
||||||
|
return "#Cube";
|
||||||
|
else if (targetNode.shape.type === ParticleShape3D.Cylinder)
|
||||||
|
return "#Cylinder";
|
||||||
|
}
|
||||||
|
return "#Sphere";
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateShape()
|
||||||
|
{
|
||||||
|
if (shapeModel)
|
||||||
|
shapeModel.destroy();
|
||||||
|
|
||||||
|
if (!targetNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (targetNode.shape instanceof ParticleModelShape3D) {
|
||||||
|
shapeModel = _generalHelper.createParticleEmitterGizmoModel(targetNode, defaultMaterial);
|
||||||
|
shapeModel.parent = root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: targetNode
|
||||||
|
function onSystemChanged() { systemHidden = _generalHelper.isHidden(system); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: targetNode
|
||||||
|
function onShapeChanged() { updateShape(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: targetNode.shape instanceof ParticleModelShape3D ? targetNode.shape
|
||||||
|
:null
|
||||||
|
function onDelegateChanged() { updateShape(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: targetNode.shape instanceof ParticleModelShape3D ? targetNode.shape.delegate
|
||||||
|
: null
|
||||||
|
function onSourceChanged() { updateShape(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Model {
|
||||||
|
readonly property Node _pickTarget: root.targetNode
|
||||||
|
materials: [defaultMaterial]
|
||||||
|
source: basicShape()
|
||||||
|
scale: root.targetNode && root.targetNode.shape && targetNode.shape instanceof ParticleShape3D
|
||||||
|
? root.targetNode.shape.extents.times(0.02) // default extent is 50
|
||||||
|
: autoScale.getScale(Qt.vector3d(0.1, 0.1, 0.1))
|
||||||
|
visible: !shapeModel
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoScaleHelper {
|
||||||
|
id: autoScale
|
||||||
|
view3D: overlayView
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultMaterial {
|
||||||
|
id: defaultMaterial
|
||||||
|
diffuseColor: root.selected ? "#FF0000" : partOfActiveSystem ? "#FFFF00" : "#AAAAAA"
|
||||||
|
lighting: DefaultMaterial.NoLighting
|
||||||
|
cullMode: Material.NoCulling
|
||||||
|
}
|
||||||
|
}
|
@@ -28,5 +28,9 @@ import QtQuick3D 6.0
|
|||||||
|
|
||||||
IconGizmo {
|
IconGizmo {
|
||||||
id: particleSystemGizmo
|
id: particleSystemGizmo
|
||||||
|
|
||||||
|
property Node activeParticleSystem: null
|
||||||
|
|
||||||
iconSource: "qrc:///qtquickplugin/mockfiles/images/editor_particlesystem.png"
|
iconSource: "qrc:///qtquickplugin/mockfiles/images/editor_particlesystem.png"
|
||||||
|
iconOpacity: selected || activeParticleSystem == targetNode ? 0.2 : 1
|
||||||
}
|
}
|
||||||
|
@@ -54,6 +54,7 @@ Model {
|
|||||||
|
|
||||||
Model {
|
Model {
|
||||||
id: pickModel
|
id: pickModel
|
||||||
|
readonly property bool _edit3dLocked: true // Make this non-pickable in main picking handling
|
||||||
objectName: "PickModel for " + rotateRing.objectName
|
objectName: "PickModel for " + rotateRing.objectName
|
||||||
source: "../meshes/ringselect.mesh"
|
source: "../meshes/ringselect.mesh"
|
||||||
pickable: true
|
pickable: true
|
||||||
|
@@ -46,6 +46,12 @@
|
|||||||
#include <QtQuick/qquickitem.h>
|
#include <QtQuick/qquickitem.h>
|
||||||
#include <QtCore/qmath.h>
|
#include <QtCore/qmath.h>
|
||||||
|
|
||||||
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
#include <QtQuick3DParticles/private/qquick3dparticlemodelshape_p.h>
|
||||||
|
#include <QtQuick3DParticles/private/qquick3dparticleemitter_p.h>
|
||||||
|
#include <QtQuick3DParticles/private/qquick3dparticletrailemitter_p.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
@@ -404,22 +410,6 @@ QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode)
|
|||||||
return pickNode;
|
return pickNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralHelper::registerGizmoTarget(QQuick3DNode *node)
|
|
||||||
{
|
|
||||||
if (!m_gizmoTargets.contains(node)) {
|
|
||||||
m_gizmoTargets.insert(node);
|
|
||||||
node->installEventFilter(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GeneralHelper::unregisterGizmoTarget(QQuick3DNode *node)
|
|
||||||
{
|
|
||||||
if (m_gizmoTargets.contains(node)) {
|
|
||||||
m_gizmoTargets.remove(node);
|
|
||||||
node->removeEventFilter(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GeneralHelper::isLocked(QQuick3DNode *node) const
|
bool GeneralHelper::isLocked(QQuick3DNode *node) const
|
||||||
{
|
{
|
||||||
if (node) {
|
if (node) {
|
||||||
@@ -460,6 +450,31 @@ bool GeneralHelper::isPickable(QQuick3DNode *node) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emitter gizmo model creation is done in C++ as creating dynamic properties and
|
||||||
|
// assigning materials to dynamically created models is lot simpler in C++
|
||||||
|
QQuick3DNode *GeneralHelper::createParticleEmitterGizmoModel(QQuick3DNode *emitter,
|
||||||
|
QQuick3DMaterial *material) const
|
||||||
|
{
|
||||||
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
auto e = qobject_cast<QQuick3DParticleEmitter *>(emitter);
|
||||||
|
if (!e || qobject_cast<QQuick3DParticleTrailEmitter *>(e) || !material)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto shape = qobject_cast<QQuick3DParticleModelShape *>(e->shape());
|
||||||
|
if (shape && shape->delegate()) {
|
||||||
|
if (auto model = qobject_cast<QQuick3DModel *>(
|
||||||
|
shape->delegate()->create(shape->delegate()->creationContext()))) {
|
||||||
|
QQmlEngine::setObjectOwnership(model, QQmlEngine::JavaScriptOwnership);
|
||||||
|
model->setProperty("_pickTarget", QVariant::fromValue(emitter));
|
||||||
|
QQmlListReference matRef(model, "materials");
|
||||||
|
matRef.append(material);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void GeneralHelper::storeToolState(const QString &sceneId, const QString &tool, const QVariant &state,
|
void GeneralHelper::storeToolState(const QString &sceneId, const QString &tool, const QVariant &state,
|
||||||
int delay)
|
int delay)
|
||||||
{
|
{
|
||||||
@@ -713,21 +728,6 @@ bool GeneralHelper::isRotationBlocked(QQuick3DNode *node) const
|
|||||||
return m_rotationBlockedNodes.contains(node);
|
return m_rotationBlockedNodes.contains(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralHelper::eventFilter(QObject *obj, QEvent *event)
|
|
||||||
{
|
|
||||||
if (event->type() == QEvent::DynamicPropertyChange) {
|
|
||||||
auto node = qobject_cast<QQuick3DNode *>(obj);
|
|
||||||
if (m_gizmoTargets.contains(node)) {
|
|
||||||
auto de = static_cast<QDynamicPropertyChangeEvent *>(event);
|
|
||||||
if (de->propertyName() == "_edit3dLocked")
|
|
||||||
emit lockedStateChanged(node);
|
|
||||||
else if (de->propertyName() == "_edit3dHidden")
|
|
||||||
emit hiddenStateChanged(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QObject::eventFilter(obj, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GeneralHelper::handlePendingToolStateUpdate()
|
void GeneralHelper::handlePendingToolStateUpdate()
|
||||||
{
|
{
|
||||||
m_toolStateUpdateTimer.stop();
|
m_toolStateUpdateTimer.stop();
|
||||||
|
@@ -41,6 +41,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
class QQuick3DCamera;
|
class QQuick3DCamera;
|
||||||
class QQuick3DNode;
|
class QQuick3DNode;
|
||||||
class QQuick3DViewport;
|
class QQuick3DViewport;
|
||||||
|
class QQuick3DMaterial;
|
||||||
class QQuickItem;
|
class QQuickItem;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
@@ -84,11 +85,11 @@ public:
|
|||||||
Q_INVOKABLE QQuick3DPickResult pickViewAt(QQuick3DViewport *view, float posX, float posY);
|
Q_INVOKABLE QQuick3DPickResult pickViewAt(QQuick3DViewport *view, float posX, float posY);
|
||||||
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
|
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
|
||||||
|
|
||||||
Q_INVOKABLE void registerGizmoTarget(QQuick3DNode *node);
|
|
||||||
Q_INVOKABLE void unregisterGizmoTarget(QQuick3DNode *node);
|
|
||||||
Q_INVOKABLE bool isLocked(QQuick3DNode *node) const;
|
Q_INVOKABLE bool isLocked(QQuick3DNode *node) const;
|
||||||
Q_INVOKABLE bool isHidden(QQuick3DNode *node) const;
|
Q_INVOKABLE bool isHidden(QQuick3DNode *node) const;
|
||||||
Q_INVOKABLE bool isPickable(QQuick3DNode *node) const;
|
Q_INVOKABLE bool isPickable(QQuick3DNode *node) const;
|
||||||
|
Q_INVOKABLE QQuick3DNode *createParticleEmitterGizmoModel(QQuick3DNode *emitter,
|
||||||
|
QQuick3DMaterial *material) const;
|
||||||
|
|
||||||
Q_INVOKABLE void storeToolState(const QString &sceneId, const QString &tool,
|
Q_INVOKABLE void storeToolState(const QString &sceneId, const QString &tool,
|
||||||
const QVariant &state, int delayEmit = 0);
|
const QVariant &state, int delayEmit = 0);
|
||||||
@@ -123,9 +124,6 @@ signals:
|
|||||||
void lockedStateChanged(QQuick3DNode *node);
|
void lockedStateChanged(QQuick3DNode *node);
|
||||||
void rotationBlocksChanged();
|
void rotationBlocksChanged();
|
||||||
|
|
||||||
protected:
|
|
||||||
bool eventFilter(QObject *obj, QEvent *event) final;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handlePendingToolStateUpdate();
|
void handlePendingToolStateUpdate();
|
||||||
QVector3D pivotScenePosition(QQuick3DNode *node) const;
|
QVector3D pivotScenePosition(QQuick3DNode *node) const;
|
||||||
@@ -136,7 +134,6 @@ private:
|
|||||||
QTimer m_toolStateUpdateTimer;
|
QTimer m_toolStateUpdateTimer;
|
||||||
QHash<QString, QVariantMap> m_toolStates;
|
QHash<QString, QVariantMap> m_toolStates;
|
||||||
QHash<QString, QVariantMap> m_toolStatesPending;
|
QHash<QString, QVariantMap> m_toolStatesPending;
|
||||||
QSet<QQuick3DNode *> m_gizmoTargets;
|
|
||||||
QSet<QQuick3DNode *> m_rotationBlockedNodes;
|
QSet<QQuick3DNode *> m_rotationBlockedNodes;
|
||||||
|
|
||||||
struct MultiSelData {
|
struct MultiSelData {
|
||||||
|
@@ -113,6 +113,7 @@
|
|||||||
#include <QtQuick3DParticles/private/qquick3dparticle_p.h>
|
#include <QtQuick3DParticles/private/qquick3dparticle_p.h>
|
||||||
#include <QtQuick3DParticles/private/qquick3dparticleaffector_p.h>
|
#include <QtQuick3DParticles/private/qquick3dparticleaffector_p.h>
|
||||||
#include <QtQuick3DParticles/private/qquick3dparticleemitter_p.h>
|
#include <QtQuick3DParticles/private/qquick3dparticleemitter_p.h>
|
||||||
|
#include <QtQuick3DParticles/private/qquick3dparticletrailemitter_p.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef IMPORT_QUICK3D_ASSETS
|
#ifdef IMPORT_QUICK3D_ASSETS
|
||||||
@@ -427,16 +428,25 @@ void Qt5InformationNodeInstanceServer::resetParticleSystem()
|
|||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem)
|
void Qt5InformationNodeInstanceServer::handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem)
|
||||||
{
|
{
|
||||||
if (!m_particleAnimationDriver || targetParticleSystem == m_targetParticleSystem)
|
if (targetParticleSystem == m_targetParticleSystem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_particleAnimationDriver->reset();
|
|
||||||
// stop the previously selected from animating
|
// stop the previously selected from animating
|
||||||
resetParticleSystem();
|
resetParticleSystem();
|
||||||
|
|
||||||
m_targetParticleSystem = targetParticleSystem;
|
m_targetParticleSystem = targetParticleSystem;
|
||||||
|
|
||||||
|
if (m_editView3DData.rootItem) {
|
||||||
|
QQmlProperty systemProperty(m_editView3DData.rootItem, "activeParticleSystem", context());
|
||||||
|
systemProperty.write(objectToVariant(m_targetParticleSystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_particleAnimationDriver)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Ensure clean slate for newly selected system
|
||||||
resetParticleSystem();
|
resetParticleSystem();
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 2)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 2)
|
||||||
QObject::disconnect(m_particleAnimationConnection);
|
QObject::disconnect(m_particleAnimationConnection);
|
||||||
m_particleAnimationConnection = connect(m_particleAnimationDriver, &AnimationDriver::advanced, [this] () {
|
m_particleAnimationConnection = connect(m_particleAnimationDriver, &AnimationDriver::advanced, [this] () {
|
||||||
@@ -507,9 +517,17 @@ static QQuick3DParticleSystem *parentParticleSystem(QObject *selectedObject)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected(QObject *selectedObject)
|
void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected()
|
||||||
{
|
{
|
||||||
|
resetParticleSystem();
|
||||||
|
|
||||||
m_targetParticleSystem = nullptr;
|
m_targetParticleSystem = nullptr;
|
||||||
|
|
||||||
|
if (m_editView3DData.rootItem) {
|
||||||
|
QQmlProperty systemProperty(m_editView3DData.rootItem, "activeParticleSystem", context());
|
||||||
|
systemProperty.write(objectToVariant(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
const auto anim = animations();
|
const auto anim = animations();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto a : anim) {
|
for (auto a : anim) {
|
||||||
@@ -526,7 +544,7 @@ void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected(QObject *s
|
|||||||
void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs)
|
void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs)
|
||||||
{
|
{
|
||||||
#ifdef QUICK3D_PARTICLES_MODULE
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
resetParticleSystem();
|
bool skipSystemDeselect = m_targetParticleSystem == nullptr;
|
||||||
#endif
|
#endif
|
||||||
QList<ServerNodeInstance> instanceList;
|
QList<ServerNodeInstance> instanceList;
|
||||||
const QVariantList varObjs = objs.value<QVariantList>();
|
const QVariantList varObjs = objs.value<QVariantList>();
|
||||||
@@ -535,8 +553,20 @@ void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &ob
|
|||||||
if (obj) {
|
if (obj) {
|
||||||
ServerNodeInstance instance = instanceForObject(obj);
|
ServerNodeInstance instance = instanceForObject(obj);
|
||||||
instanceList << instance;
|
instanceList << instance;
|
||||||
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
if (!skipSystemDeselect) {
|
||||||
|
auto particleSystem = parentParticleSystem(instance.internalObject());
|
||||||
|
skipSystemDeselect = particleSystem == m_targetParticleSystem;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
if (m_targetParticleSystem && !skipSystemDeselect)
|
||||||
|
handleParticleSystemDeselected();
|
||||||
|
#endif
|
||||||
|
|
||||||
selectInstances(instanceList);
|
selectInstances(instanceList);
|
||||||
// Hold selection changes reflected back from designer for a bit
|
// Hold selection changes reflected back from designer for a bit
|
||||||
m_selectionChangeTimer.start(500);
|
m_selectionChangeTimer.start(500);
|
||||||
@@ -745,6 +775,10 @@ void Qt5InformationNodeInstanceServer::handleNode3DDestroyed(QObject *obj)
|
|||||||
} else if (qobject_cast<QQuick3DParticleSystem *>(obj)) {
|
} else if (qobject_cast<QQuick3DParticleSystem *>(obj)) {
|
||||||
QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseParticleSystemGizmo",
|
QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseParticleSystemGizmo",
|
||||||
Q_ARG(QVariant, objectToVariant(obj)));
|
Q_ARG(QVariant, objectToVariant(obj)));
|
||||||
|
} else if (qobject_cast<QQuick3DParticleEmitter *>(obj)
|
||||||
|
&& !qobject_cast<QQuick3DParticleTrailEmitter *>(obj)) {
|
||||||
|
QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseParticleEmitterGizmo",
|
||||||
|
Q_ARG(QVariant, objectToVariant(obj)));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
removeNode3D(obj);
|
removeNode3D(obj);
|
||||||
@@ -853,6 +887,11 @@ void Qt5InformationNodeInstanceServer::resolveSceneRoots()
|
|||||||
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateParticleSystemGizmoScene",
|
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateParticleSystemGizmoScene",
|
||||||
Q_ARG(QVariant, objectToVariant(newRoot)),
|
Q_ARG(QVariant, objectToVariant(newRoot)),
|
||||||
Q_ARG(QVariant, objectToVariant(node)));
|
Q_ARG(QVariant, objectToVariant(node)));
|
||||||
|
} else if (qobject_cast<QQuick3DParticleEmitter *>(node)
|
||||||
|
&& !qobject_cast<QQuick3DParticleTrailEmitter *>(node)) {
|
||||||
|
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateParticleEmitterGizmoScene",
|
||||||
|
Q_ARG(QVariant, objectToVariant(newRoot)),
|
||||||
|
Q_ARG(QVariant, objectToVariant(node)));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1415,15 +1454,19 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
|
|||||||
QHash<QObject *, QObjectList> cameras;
|
QHash<QObject *, QObjectList> cameras;
|
||||||
QHash<QObject *, QObjectList> lights;
|
QHash<QObject *, QObjectList> lights;
|
||||||
QHash<QObject *, QObjectList> particleSystems;
|
QHash<QObject *, QObjectList> particleSystems;
|
||||||
|
QHash<QObject *, QObjectList> particleEmitters;
|
||||||
|
|
||||||
for (const ServerNodeInstance &instance : instanceList) {
|
for (const ServerNodeInstance &instance : instanceList) {
|
||||||
if (instance.isSubclassOf("QQuick3DCamera"))
|
if (instance.isSubclassOf("QQuick3DCamera")) {
|
||||||
cameras[find3DSceneRoot(instance)] << instance.internalObject();
|
cameras[find3DSceneRoot(instance)] << instance.internalObject();
|
||||||
else if (instance.isSubclassOf("QQuick3DAbstractLight"))
|
} else if (instance.isSubclassOf("QQuick3DAbstractLight")) {
|
||||||
lights[find3DSceneRoot(instance)] << instance.internalObject();
|
lights[find3DSceneRoot(instance)] << instance.internalObject();
|
||||||
else if (instance.isSubclassOf("QQuick3DParticleSystem"))
|
} else if (instance.isSubclassOf("QQuick3DParticleSystem")) {
|
||||||
particleSystems[find3DSceneRoot(instance)] << instance.internalObject();
|
particleSystems[find3DSceneRoot(instance)] << instance.internalObject();
|
||||||
|
} else if (instance.isSubclassOf("QQuick3DParticleEmitter")
|
||||||
|
&& !instance.isSubclassOf("QQuick3DParticleTrailEmitter")) {
|
||||||
|
particleEmitters[find3DSceneRoot(instance)] << instance.internalObject();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cameraIt = cameras.constBegin();
|
auto cameraIt = cameras.constBegin();
|
||||||
@@ -1456,6 +1499,17 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
|
|||||||
}
|
}
|
||||||
++particleIt;
|
++particleIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto emitterIt = particleEmitters.constBegin();
|
||||||
|
while (emitterIt != particleEmitters.constEnd()) {
|
||||||
|
const auto emitterObjs = emitterIt.value();
|
||||||
|
for (auto &obj : emitterObjs) {
|
||||||
|
QMetaObject::invokeMethod(m_editView3DData.rootItem, "addParticleEmitterGizmo",
|
||||||
|
Q_ARG(QVariant, objectToVariant(emitterIt.key())),
|
||||||
|
Q_ARG(QVariant, objectToVariant(obj)));
|
||||||
|
}
|
||||||
|
++emitterIt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::add3DViewPorts(const QList<ServerNodeInstance> &instanceList)
|
void Qt5InformationNodeInstanceServer::add3DViewPorts(const QList<ServerNodeInstance> &instanceList)
|
||||||
@@ -1924,6 +1978,9 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
|||||||
QVariantList selectedObjs;
|
QVariantList selectedObjs;
|
||||||
QObject *firstSceneRoot = nullptr;
|
QObject *firstSceneRoot = nullptr;
|
||||||
ServerNodeInstance firstInstance;
|
ServerNodeInstance firstInstance;
|
||||||
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
QList<QQuick3DParticleSystem *> selectedParticleSystems;
|
||||||
|
#endif
|
||||||
for (qint32 id : instanceIds) {
|
for (qint32 id : instanceIds) {
|
||||||
if (hasInstanceForId(id)) {
|
if (hasInstanceForId(id)) {
|
||||||
ServerNodeInstance instance = instanceForId(id);
|
ServerNodeInstance instance = instanceForId(id);
|
||||||
@@ -1937,17 +1994,12 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
|||||||
object = instance.internalObject();
|
object = instance.internalObject();
|
||||||
|
|
||||||
#ifdef QUICK3D_PARTICLES_MODULE
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
auto particlesystem = qobject_cast<QQuick3DParticleSystem *>(instance.internalObject());
|
if (selectedParticleSystems.size() <= 1) {
|
||||||
if (particlesystem) {
|
auto particleSystem = qobject_cast<QQuick3DParticleSystem *>(instance.internalObject());
|
||||||
handleParticleSystemSelected(particlesystem);
|
if (!particleSystem)
|
||||||
} else {
|
particleSystem = parentParticleSystem(instance.internalObject());
|
||||||
particlesystem = parentParticleSystem(instance.internalObject());
|
if (particleSystem && !selectedParticleSystems.contains(particleSystem))
|
||||||
if (particlesystem) {
|
selectedParticleSystems.append(particleSystem);
|
||||||
if (particlesystem != m_targetParticleSystem)
|
|
||||||
handleParticleSystemSelected(particlesystem);
|
|
||||||
} else {
|
|
||||||
handleParticleSystemDeselected(instance.internalObject());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
auto isSelectableAsRoot = [&]() -> bool {
|
auto isSelectableAsRoot = [&]() -> bool {
|
||||||
@@ -1957,6 +2009,8 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
|||||||
|| qobject_cast<QQuick3DAbstractLight *>(object)
|
|| qobject_cast<QQuick3DAbstractLight *>(object)
|
||||||
#ifdef QUICK3D_PARTICLES_MODULE
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|| qobject_cast<QQuick3DParticleSystem *>(object)
|
|| qobject_cast<QQuick3DParticleSystem *>(object)
|
||||||
|
|| qobject_cast<QQuick3DParticleEmitter *>(object)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
@@ -1978,6 +2032,14 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
// We only support exactly one active particle systems at a time
|
||||||
|
if (selectedParticleSystems.size() == 1)
|
||||||
|
handleParticleSystemSelected(selectedParticleSystems[0]);
|
||||||
|
else
|
||||||
|
handleParticleSystemDeselected();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (firstSceneRoot && m_active3DScene != firstSceneRoot) {
|
if (firstSceneRoot && m_active3DScene != firstSceneRoot) {
|
||||||
m_active3DScene = firstSceneRoot;
|
m_active3DScene = firstSceneRoot;
|
||||||
m_active3DView = findView3DForInstance(firstInstance);
|
m_active3DView = findView3DForInstance(firstInstance);
|
||||||
@@ -2105,6 +2167,9 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
|
|||||||
updatedState.insert("showCameraFrustum", command.isEnabled());
|
updatedState.insert("showCameraFrustum", command.isEnabled());
|
||||||
break;
|
break;
|
||||||
#ifdef QUICK3D_PARTICLES_MODULE
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
case View3DActionCommand::ShowParticleEmitter:
|
||||||
|
updatedState.insert("showParticleEmitter", command.isEnabled());
|
||||||
|
break;
|
||||||
case View3DActionCommand::ParticlesPlay:
|
case View3DActionCommand::ParticlesPlay:
|
||||||
m_particleAnimationPlaying = command.isEnabled();
|
m_particleAnimationPlaying = command.isEnabled();
|
||||||
updatedState.insert("particlePlay", command.isEnabled());
|
updatedState.insert("particlePlay", command.isEnabled());
|
||||||
@@ -2220,8 +2285,12 @@ void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInst
|
|||||||
|
|
||||||
QObject *obj = instance.internalObject();
|
QObject *obj = instance.internalObject();
|
||||||
auto node = qobject_cast<QQuick3DNode *>(obj);
|
auto node = qobject_cast<QQuick3DNode *>(obj);
|
||||||
if (node)
|
if (node) {
|
||||||
node->setProperty("_edit3dLocked", edit3dLocked);
|
node->setProperty("_edit3dLocked", edit3dLocked);
|
||||||
|
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
|
||||||
|
if (helper)
|
||||||
|
emit helper->lockedStateChanged(node);
|
||||||
|
}
|
||||||
const auto children = obj->children();
|
const auto children = obj->children();
|
||||||
for (auto child : children) {
|
for (auto child : children) {
|
||||||
if (hasInstanceForObject(child)) {
|
if (hasInstanceForObject(child)) {
|
||||||
@@ -2276,6 +2345,9 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst
|
|||||||
// as changes in the node tree (reparenting, adding new nodes) can make the previously set
|
// as changes in the node tree (reparenting, adding new nodes) can make the previously set
|
||||||
// hide status based on ancestor unreliable.
|
// hide status based on ancestor unreliable.
|
||||||
node->setProperty("_edit3dHidden", edit3dHidden);
|
node->setProperty("_edit3dHidden", edit3dHidden);
|
||||||
|
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
|
||||||
|
if (helper)
|
||||||
|
emit helper->hiddenStateChanged(node);
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1)
|
||||||
if (auto model = qobject_cast<QQuick3DModel *>(node))
|
if (auto model = qobject_cast<QQuick3DModel *>(node))
|
||||||
model->setPickable(!edit3dHidden); // allow 3D objects to receive mouse clicks
|
model->setPickable(!edit3dHidden); // allow 3D objects to receive mouse clicks
|
||||||
|
@@ -151,7 +151,7 @@ private:
|
|||||||
#ifdef QUICK3D_PARTICLES_MODULE
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
void handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem);
|
void handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem);
|
||||||
void resetParticleSystem();
|
void resetParticleSystem();
|
||||||
void handleParticleSystemDeselected(QObject *selectedObject);
|
void handleParticleSystemDeselected();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RenderViewData m_editView3DData;
|
RenderViewData m_editView3DData;
|
||||||
|
@@ -49,7 +49,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ServerNodeInstance m_currentState;
|
ServerNodeInstance m_currentState;
|
||||||
QSize m_previewSize{160, 160};
|
QSize m_previewSize{320, 320};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -32,45 +32,67 @@ import StudioControls 1.0 as StudioControls
|
|||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: rootItem
|
id: root
|
||||||
|
|
||||||
property var selectedAssets: ({})
|
property var selectedAssets: ({})
|
||||||
property int allExpandedState: 0
|
property int allExpandedState: 0
|
||||||
property string contextFilePath: ""
|
property string contextFilePath: ""
|
||||||
property var contextDir: undefined
|
property var contextDir: undefined
|
||||||
property bool isDirContextMenu: false
|
property bool isDirContextMenu: false
|
||||||
|
property var dropExtFiles: [] // array of supported externally dropped files
|
||||||
|
|
||||||
function clearSearchFilter()
|
function clearSearchFilter()
|
||||||
{
|
{
|
||||||
searchBox.text = "";
|
searchBox.text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
DropArea {
|
function updateDropExtFiles(drag)
|
||||||
id: dropArea
|
{
|
||||||
|
root.dropExtFiles = []
|
||||||
property var files // list of supported dropped files
|
for (const u of drag.urls) {
|
||||||
|
var url = u.toString();
|
||||||
enabled: true
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
onEntered: (drag)=> {
|
|
||||||
files = []
|
|
||||||
for (var i = 0; i < drag.urls.length; ++i) {
|
|
||||||
var url = drag.urls[i].toString();
|
|
||||||
if (url.startsWith("file:///")) // remove file scheme (happens on Windows)
|
if (url.startsWith("file:///")) // remove file scheme (happens on Windows)
|
||||||
url = url.substr(8)
|
url = url.substr(8)
|
||||||
|
|
||||||
var ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
|
var ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
|
||||||
if (rootView.supportedDropSuffixes().includes('*.' + ext))
|
if (rootView.supportedDropSuffixes().includes('*.' + ext))
|
||||||
files.push(url)
|
root.dropExtFiles.push(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files.length === 0)
|
drag.accepted = root.dropExtFiles.length > 0
|
||||||
drag.accepted = false;
|
}
|
||||||
|
|
||||||
|
DropArea { // handles external drop on empty area of the view (goes to root folder)
|
||||||
|
id: dropArea
|
||||||
|
y: assetsView.y + assetsView.contentHeight + 5
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height - y
|
||||||
|
|
||||||
|
onEntered: (drag)=> {
|
||||||
|
root.updateDropExtFiles(drag)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropped: {
|
onDropped: {
|
||||||
if (files.length > 0)
|
rootView.handleExtFilesDrop(root.dropExtFiles, assetsModel.rootDir().dirPath)
|
||||||
rootView.handleFilesDrop(files)
|
}
|
||||||
|
|
||||||
|
Canvas { // marker for the drop area
|
||||||
|
id: dropCanvas
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: dropArea.containsDrag
|
||||||
|
|
||||||
|
onWidthChanged: dropCanvas.requestPaint()
|
||||||
|
onHeightChanged: dropCanvas.requestPaint()
|
||||||
|
|
||||||
|
onPaint: {
|
||||||
|
var ctx = getContext("2d")
|
||||||
|
ctx.reset()
|
||||||
|
ctx.strokeStyle = StudioTheme.Values.themeInteraction
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.setLineDash([4, 4])
|
||||||
|
ctx.rect(5, 5, dropCanvas.width - 10, dropCanvas.height - 10)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,9 +101,9 @@ Item {
|
|||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!assetsModel.isEmpty) {
|
if (!assetsModel.isEmpty) {
|
||||||
contextFilePath = ""
|
root.contextFilePath = ""
|
||||||
contextDir = assetsModel.rootDir()
|
root.contextDir = assetsModel.rootDir()
|
||||||
isDirContextMenu = false
|
root.isDirContextMenu = false
|
||||||
contextMenu.popup()
|
contextMenu.popup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,8 +113,8 @@ Item {
|
|||||||
function handleViewFocusOut()
|
function handleViewFocusOut()
|
||||||
{
|
{
|
||||||
contextMenu.close()
|
contextMenu.close()
|
||||||
selectedAssets = {}
|
root.selectedAssets = {}
|
||||||
selectedAssetsChanged()
|
root.selectedAssetsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.Menu {
|
StudioControls.Menu {
|
||||||
@@ -100,42 +122,50 @@ Item {
|
|||||||
|
|
||||||
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
var numSelected = Object.values(root.selectedAssets).filter(p => p).length
|
||||||
|
deleteFileItem.text = numSelected > 1 ? qsTr("Delete Files") : qsTr("Delete File")
|
||||||
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Expand All")
|
text: qsTr("Expand All")
|
||||||
enabled: allExpandedState !== 1
|
enabled: root.allExpandedState !== 1
|
||||||
visible: isDirContextMenu
|
visible: root.isDirContextMenu
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: assetsModel.toggleExpandAll(true)
|
onTriggered: assetsModel.toggleExpandAll(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Collapse All")
|
text: qsTr("Collapse All")
|
||||||
enabled: allExpandedState !== 2
|
enabled: root.allExpandedState !== 2
|
||||||
visible: isDirContextMenu
|
visible: root.isDirContextMenu
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: assetsModel.toggleExpandAll(false)
|
onTriggered: assetsModel.toggleExpandAll(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuSeparator {
|
StudioControls.MenuSeparator {
|
||||||
visible: isDirContextMenu
|
visible: root.isDirContextMenu
|
||||||
height: visible ? StudioTheme.Values.border : 0
|
height: visible ? StudioTheme.Values.border : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
|
id: deleteFileItem
|
||||||
text: qsTr("Delete File")
|
text: qsTr("Delete File")
|
||||||
visible: contextFilePath
|
visible: root.contextFilePath
|
||||||
height: visible ? implicitHeight : 0
|
height: deleteFileItem.visible ? deleteFileItem.implicitHeight : 0
|
||||||
onTriggered: assetsModel.deleteFile(contextFilePath)
|
onTriggered: {
|
||||||
|
assetsModel.deleteFiles(Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuSeparator {
|
StudioControls.MenuSeparator {
|
||||||
visible: contextFilePath
|
visible: root.contextFilePath
|
||||||
height: visible ? StudioTheme.Values.border : 0
|
height: visible ? StudioTheme.Values.border : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Rename Folder")
|
text: qsTr("Rename Folder")
|
||||||
visible: isDirContextMenu
|
visible: root.isDirContextMenu
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: renameFolderDialog.open()
|
onTriggered: renameFolderDialog.open()
|
||||||
}
|
}
|
||||||
@@ -147,14 +177,14 @@ Item {
|
|||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Delete Folder")
|
text: qsTr("Delete Folder")
|
||||||
visible: isDirContextMenu
|
visible: root.isDirContextMenu
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
var dirEmpty = !(contextDir.dirsModel && contextDir.dirsModel.rowCount() > 0)
|
var dirEmpty = !(root.contextDir.dirsModel && root.contextDir.dirsModel.rowCount() > 0)
|
||||||
&& !(contextDir.filesModel && contextDir.filesModel.rowCount() > 0);
|
&& !(root.contextDir.filesModel && root.contextDir.filesModel.rowCount() > 0);
|
||||||
|
|
||||||
if (dirEmpty)
|
if (dirEmpty)
|
||||||
assetsModel.deleteFolder(contextDir.dirPath)
|
assetsModel.deleteFolder(root.contextDir.dirPath)
|
||||||
else
|
else
|
||||||
confirmDeleteFolderDialog.open()
|
confirmDeleteFolderDialog.open()
|
||||||
}
|
}
|
||||||
@@ -235,7 +265,7 @@ Item {
|
|||||||
text: qsTr("Rename")
|
text: qsTr("Rename")
|
||||||
enabled: folderRename.text !== ""
|
enabled: folderRename.text !== ""
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var success = assetsModel.renameFolder(contextDir.dirPath, folderRename.text)
|
var success = assetsModel.renameFolder(root.contextDir.dirPath, folderRename.text)
|
||||||
if (success)
|
if (success)
|
||||||
renameFolderDialog.accept()
|
renameFolderDialog.accept()
|
||||||
|
|
||||||
@@ -251,7 +281,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
folderRename.text = contextDir.dirName
|
folderRename.text = root.contextDir.dirName
|
||||||
folderRename.selectAll()
|
folderRename.selectAll()
|
||||||
folderRename.forceActiveFocus()
|
folderRename.forceActiveFocus()
|
||||||
renameFolderDialog.renameError = false
|
renameFolderDialog.renameError = false
|
||||||
@@ -309,7 +339,7 @@ Item {
|
|||||||
text: qsTr("Create")
|
text: qsTr("Create")
|
||||||
enabled: folderName.text !== ""
|
enabled: folderName.text !== ""
|
||||||
onClicked: {
|
onClicked: {
|
||||||
assetsModel.addNewFolder(contextDir.dirPath + '/' + folderName.text)
|
assetsModel.addNewFolder(root.contextDir.dirPath + '/' + folderName.text)
|
||||||
newFolderDialog.accept()
|
newFolderDialog.accept()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,7 +375,7 @@ Item {
|
|||||||
id: folderNotEmpty
|
id: folderNotEmpty
|
||||||
|
|
||||||
text: qsTr("Folder \"%1\" is not empty. Delete it anyway?")
|
text: qsTr("Folder \"%1\" is not empty. Delete it anyway?")
|
||||||
.arg(contextDir ? contextDir.dirName : "")
|
.arg(root.contextDir ? root.contextDir.dirName : "")
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: confirmDeleteFolderDialog.width
|
width: confirmDeleteFolderDialog.width
|
||||||
@@ -373,7 +403,7 @@ Item {
|
|||||||
text: qsTr("Delete")
|
text: qsTr("Delete")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
assetsModel.deleteFolder(contextDir.dirPath)
|
assetsModel.deleteFolder(root.contextDir.dirPath)
|
||||||
confirmDeleteFolderDialog.accept()
|
confirmDeleteFolderDialog.accept()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,7 +463,7 @@ Item {
|
|||||||
|
|
||||||
spacing: 20
|
spacing: 20
|
||||||
x: 20
|
x: 20
|
||||||
width: rootItem.width - 2 * x
|
width: root.width - 2 * x
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@@ -492,6 +522,8 @@ Item {
|
|||||||
id: dirSection
|
id: dirSection
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
|
id: section
|
||||||
|
|
||||||
width: assetsView.width -
|
width: assetsView.width -
|
||||||
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5
|
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5
|
||||||
caption: dirName
|
caption: dirName
|
||||||
@@ -506,16 +538,31 @@ Item {
|
|||||||
visible: dirVisible
|
visible: dirVisible
|
||||||
expandOnClick: false
|
expandOnClick: false
|
||||||
useDefaulContextMenu: false
|
useDefaulContextMenu: false
|
||||||
|
dropEnabled: true
|
||||||
|
|
||||||
onToggleExpand: {
|
onToggleExpand: {
|
||||||
dirExpanded = !dirExpanded
|
dirExpanded = !dirExpanded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDropEnter: (drag)=> {
|
||||||
|
root.updateDropExtFiles(drag)
|
||||||
|
section.highlight = drag.accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropExit: {
|
||||||
|
section.highlight = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrop: {
|
||||||
|
section.highlight = false
|
||||||
|
rootView.handleExtFilesDrop(root.dropExtFiles, dirPath)
|
||||||
|
}
|
||||||
|
|
||||||
onShowContextMenu: {
|
onShowContextMenu: {
|
||||||
contextFilePath = ""
|
root.contextFilePath = ""
|
||||||
contextDir = model
|
root.contextDir = model
|
||||||
isDirContextMenu = true
|
root.isDirContextMenu = true
|
||||||
allExpandedState = assetsModel.getAllExpandedState()
|
root.allExpandedState = assetsModel.getAllExpandedState()
|
||||||
contextMenu.popup()
|
contextMenu.popup()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,9 +591,9 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
contextFilePath = ""
|
root.contextFilePath = ""
|
||||||
contextDir = model
|
root.contextDir = model
|
||||||
isDirContextMenu = true
|
root.isDirContextMenu = true
|
||||||
contextMenu.popup()
|
contextMenu.popup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,7 +609,8 @@ Item {
|
|||||||
width: assetsView.width -
|
width: assetsView.width -
|
||||||
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
|
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
|
||||||
height: img.height
|
height: img.height
|
||||||
color: selectedAssets[filePath] ? StudioTheme.Values.themeInteraction
|
color: root.selectedAssets[filePath]
|
||||||
|
? StudioTheme.Values.themeInteraction
|
||||||
: (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground
|
: (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground
|
||||||
: "transparent")
|
: "transparent")
|
||||||
|
|
||||||
@@ -601,28 +649,31 @@ Item {
|
|||||||
onPositionChanged: tooltipBackend.reposition()
|
onPositionChanged: tooltipBackend.reposition()
|
||||||
onPressed: (mouse)=> {
|
onPressed: (mouse)=> {
|
||||||
forceActiveFocus()
|
forceActiveFocus()
|
||||||
if (mouse.button === Qt.LeftButton) {
|
|
||||||
var ctrlDown = mouse.modifiers & Qt.ControlModifier
|
var ctrlDown = mouse.modifiers & Qt.ControlModifier
|
||||||
if (!selectedAssets[filePath] && !ctrlDown)
|
if (mouse.button === Qt.LeftButton) {
|
||||||
selectedAssets = {}
|
if (!root.selectedAssets[filePath] && !ctrlDown)
|
||||||
currFileSelected = ctrlDown ? !selectedAssets[filePath] : true
|
root.selectedAssets = {}
|
||||||
selectedAssets[filePath] = currFileSelected
|
currFileSelected = ctrlDown ? !root.selectedAssets[filePath] : true
|
||||||
selectedAssetsChanged()
|
root.selectedAssets[filePath] = currFileSelected
|
||||||
|
root.selectedAssetsChanged()
|
||||||
|
|
||||||
var selectedAssetsArr = []
|
if (currFileSelected) {
|
||||||
for (var assetPath in selectedAssets) {
|
rootView.startDragAsset(
|
||||||
if (selectedAssets[assetPath])
|
Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]),
|
||||||
selectedAssetsArr.push(assetPath)
|
mapToGlobal(mouse.x, mouse.y))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currFileSelected)
|
|
||||||
rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y))
|
|
||||||
} else {
|
} else {
|
||||||
contextFilePath = filePath
|
if (!root.selectedAssets[filePath] && !ctrlDown)
|
||||||
contextDir = model.fileDir
|
root.selectedAssets = {}
|
||||||
|
currFileSelected = root.selectedAssets[filePath] || !ctrlDown
|
||||||
|
root.selectedAssets[filePath] = currFileSelected
|
||||||
|
root.selectedAssetsChanged()
|
||||||
|
|
||||||
|
root.contextFilePath = filePath
|
||||||
|
root.contextDir = model.fileDir
|
||||||
|
root.isDirContextMenu = false
|
||||||
|
|
||||||
tooltipBackend.hideTooltip()
|
tooltipBackend.hideTooltip()
|
||||||
isDirContextMenu = false
|
|
||||||
contextMenu.popup()
|
contextMenu.popup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -630,9 +681,9 @@ Item {
|
|||||||
onReleased: (mouse)=> {
|
onReleased: (mouse)=> {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
if (!(mouse.modifiers & Qt.ControlModifier))
|
if (!(mouse.modifiers & Qt.ControlModifier))
|
||||||
selectedAssets = {}
|
root.selectedAssets = {}
|
||||||
selectedAssets[filePath] = currFileSelected
|
root.selectedAssets[filePath] = currFileSelected
|
||||||
selectedAssetsChanged()
|
root.selectedAssetsChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -32,6 +32,7 @@ import StudioTheme as StudioTheme
|
|||||||
import StudioControls as SC
|
import StudioControls as SC
|
||||||
|
|
||||||
import NewProjectDialog
|
import NewProjectDialog
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: rootDialog
|
id: rootDialog
|
||||||
@@ -161,17 +162,43 @@ Item {
|
|||||||
readonly property int animDur: 500
|
readonly property int animDur: 500
|
||||||
id: tabBar
|
id: tabBar
|
||||||
x: 10 // left padding
|
x: 10 // left padding
|
||||||
width: parent.width - 64 // right padding
|
width: parent.width - 20 // right padding
|
||||||
height: DialogValues.projectViewHeaderHeight
|
height: DialogValues.presetViewHeaderHeight
|
||||||
color: DialogValues.lightPaneColor
|
color: DialogValues.lightPaneColor
|
||||||
|
|
||||||
|
function selectTab(tabIndex, selectLast = false) {
|
||||||
|
var item = repeater.itemAt(tabIndex)
|
||||||
|
tabBarRow.currIndex = tabIndex
|
||||||
|
|
||||||
|
presetView.selectLast = selectLast
|
||||||
|
BackendApi.presetModel.setPage(tabIndex) // NOTE: it resets preset model
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: BackendApi
|
||||||
|
|
||||||
|
function onUserPresetSaved() {
|
||||||
|
var customTabIndex = repeater.count - 1
|
||||||
|
tabBar.selectTab(customTabIndex, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLastUserPresetRemoved() {
|
||||||
|
tabBar.selectTab(0, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: tabBarRow
|
id: tabBarRow
|
||||||
spacing: 20
|
spacing: 20
|
||||||
property int currIndex: 0
|
property int currIndex: 0
|
||||||
|
readonly property string currentTabName:
|
||||||
|
repeater.count > 0 && repeater.itemAt(currIndex)
|
||||||
|
? repeater.itemAt(currIndex).text
|
||||||
|
: ''
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: categoryModel
|
id: repeater
|
||||||
|
model: BackendApi.categoryModel
|
||||||
Text {
|
Text {
|
||||||
text: name
|
text: name
|
||||||
font.weight: Font.DemiBold
|
font.weight: Font.DemiBold
|
||||||
@@ -184,13 +211,7 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabBarRow.currIndex = index
|
tabBar.selectTab(index)
|
||||||
presetModel.setPage(index)
|
|
||||||
projectView.currentIndex = 0
|
|
||||||
projectView.currentIndexChanged()
|
|
||||||
|
|
||||||
strip.x = parent.x
|
|
||||||
strip.width = parent.width
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,8 +220,19 @@ Item {
|
|||||||
} // tabBarRow
|
} // tabBarRow
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
function computeX() {
|
||||||
|
var item = tabBarRow.children[tabBarRow.currIndex] ?? tabBarRow.children[0]
|
||||||
|
return item.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeWidth() {
|
||||||
|
var item = tabBarRow.children[tabBarRow.currIndex] ?? tabBarRow.children[0]
|
||||||
|
return item.width;
|
||||||
|
}
|
||||||
|
|
||||||
id: strip
|
id: strip
|
||||||
width: tabBarRow.children[0].width
|
x: computeX()
|
||||||
|
width: computeWidth()
|
||||||
height: 5
|
height: 5
|
||||||
radius: 2
|
radius: 2
|
||||||
color: DialogValues.textColorInteraction
|
color: DialogValues.textColorInteraction
|
||||||
@@ -209,35 +241,40 @@ Item {
|
|||||||
Behavior on x { SmoothedAnimation { duration: tabBar.animDur } }
|
Behavior on x { SmoothedAnimation { duration: tabBar.animDur } }
|
||||||
Behavior on width { SmoothedAnimation { duration: strip.width === 0 ? 0 : tabBar.animDur } } // do not animate initial width
|
Behavior on width { SmoothedAnimation { duration: strip.width === 0 ? 0 : tabBar.animDur } } // do not animate initial width
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: rootDialog
|
|
||||||
function onWidthChanged() {
|
|
||||||
if (rootDialog.width < 1200) { // 1200 = the width threshold
|
|
||||||
tabBar.width = tabBar.parent.width - 20
|
|
||||||
projectView.width = projectView.parent.width - 20
|
|
||||||
} else {
|
|
||||||
tabBar.width = tabBar.parent.width - 64
|
|
||||||
projectView.width = projectView.parent.width - 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // Rectangle
|
} // Rectangle
|
||||||
|
|
||||||
NewProjectView {
|
Rectangle {
|
||||||
id: projectView
|
id: presetViewFrame
|
||||||
x: 10 // left padding
|
x: 10 // left padding
|
||||||
width: parent.width - 64 // right padding
|
width: parent.width - 20 // right padding
|
||||||
height: DialogValues.projectViewHeight
|
height: DialogValues.presetViewHeight
|
||||||
|
color: DialogValues.darkPaneColor
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: DialogValues.gridMargins
|
||||||
|
|
||||||
|
NewProjectView {
|
||||||
|
id: presetView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
loader: projectDetailsLoader
|
loader: projectDetailsLoader
|
||||||
|
currentTabName: tabBarRow.currentTabName
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: rootDialog
|
target: rootDialog
|
||||||
function onHeightChanged() {
|
function onHeightChanged() {
|
||||||
if (rootDialog.height < 700) { // 700 = minimum height big dialog
|
if (rootDialog.height < 720) { // 720 = minimum height big dialog
|
||||||
projectView.height = DialogValues.projectViewHeight / 2
|
DialogValues.presetViewHeight =
|
||||||
|
DialogValues.presetItemHeight
|
||||||
|
+ 2 * DialogValues.gridMargins
|
||||||
} else {
|
} else {
|
||||||
projectView.height = DialogValues.projectViewHeight
|
DialogValues.presetViewHeight =
|
||||||
|
DialogValues.presetItemHeight * 2
|
||||||
|
+ DialogValues.gridSpacing
|
||||||
|
+ 2 * DialogValues.gridMargins
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,12 +284,12 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: descriptionText
|
id: descriptionText
|
||||||
text: dialogBox.projectDescription
|
text: BackendApi.projectDescription
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
leftPadding: 14
|
leftPadding: 14
|
||||||
width: projectView.width
|
width: presetViewFrame.width
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
maximumLineCount: 4
|
maximumLineCount: 4
|
||||||
@@ -298,7 +335,7 @@ Item {
|
|||||||
iconFont: StudioTheme.Constants.font
|
iconFont: StudioTheme.Constants.font
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
dialogBox.reject();
|
BackendApi.reject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,11 +347,11 @@ Item {
|
|||||||
visible: true
|
visible: true
|
||||||
buttonIcon: qsTr("Create")
|
buttonIcon: qsTr("Create")
|
||||||
iconSize: DialogValues.defaultPixelSize
|
iconSize: DialogValues.defaultPixelSize
|
||||||
enabled: dialogBox.fieldsValid
|
enabled: BackendApi.fieldsValid
|
||||||
iconFont: StudioTheme.Constants.font
|
iconFont: StudioTheme.Constants.font
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
dialogBox.accept();
|
BackendApi.accept();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // RowLayout
|
} // RowLayout
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 5.1 KiB |
@@ -31,16 +31,13 @@ import QtQuick.Layouts
|
|||||||
import StudioControls as SC
|
import StudioControls as SC
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: DialogValues.detailsPaneWidth
|
width: DialogValues.detailsPaneWidth
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: BackendApi.detailsLoaded = true
|
||||||
dialogBox.detailsLoaded = true;
|
Component.onDestruction: BackendApi.detailsLoaded = false
|
||||||
}
|
|
||||||
|
|
||||||
Component.onDestruction: {
|
|
||||||
dialogBox.detailsLoaded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: DialogValues.darkPaneColor
|
color: DialogValues.darkPaneColor
|
||||||
@@ -53,13 +50,13 @@ Item {
|
|||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: DialogValues.defaultPadding
|
spacing: 5
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: detailsHeading
|
id: detailsHeading
|
||||||
text: qsTr("Details")
|
text: qsTr("Details")
|
||||||
height: DialogValues.paneTitleTextHeight
|
height: DialogValues.paneTitleTextHeight
|
||||||
width: parent.width;
|
width: parent.width
|
||||||
font.weight: Font.DemiBold
|
font.weight: Font.DemiBold
|
||||||
font.pixelSize: DialogValues.paneTitlePixelSize
|
font.pixelSize: DialogValues.paneTitlePixelSize
|
||||||
lineHeight: DialogValues.paneTitleLineHeight
|
lineHeight: DialogValues.paneTitleLineHeight
|
||||||
@@ -71,39 +68,36 @@ Item {
|
|||||||
Flickable {
|
Flickable {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - detailsHeading.height - DialogValues.defaultPadding
|
height: parent.height - detailsHeading.height - DialogValues.defaultPadding
|
||||||
|
- savePresetButton.height
|
||||||
contentWidth: parent.width
|
contentWidth: parent.width
|
||||||
contentHeight: scrollContent.height
|
contentHeight: scrollContent.height
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
ScrollBar.vertical: SC.VerticalScrollBar {
|
ScrollBar.vertical: SC.VerticalScrollBar {}
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: scrollContent
|
id: scrollContent
|
||||||
width: parent.width - DialogValues.detailsPanePadding
|
width: parent.width - DialogValues.detailsPanePadding
|
||||||
height: DialogValues.detailsScrollableContentHeight
|
|
||||||
spacing: DialogValues.defaultPadding
|
spacing: DialogValues.defaultPadding
|
||||||
|
|
||||||
SC.TextField {
|
SC.TextField {
|
||||||
id: projectNameTextField
|
id: projectNameTextField
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
translationIndicatorVisible: false
|
translationIndicatorVisible: false
|
||||||
text: dialogBox.projectName
|
text: BackendApi.projectName
|
||||||
width: parent.width
|
width: parent.width
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
text = text.charAt(0).toUpperCase() + text.slice(1)
|
text = text.charAt(0).toUpperCase() + text.slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "projectName"
|
property: "projectName"
|
||||||
value: projectNameTextField.text
|
value: projectNameTextField.text
|
||||||
}
|
}
|
||||||
@@ -118,14 +112,14 @@ Item {
|
|||||||
id: projectLocationTextField
|
id: projectLocationTextField
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
translationIndicatorVisible: false
|
translationIndicatorVisible: false
|
||||||
text: dialogBox.projectLocation
|
text: BackendApi.projectLocation
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
}
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "projectLocation"
|
property: "projectLocation"
|
||||||
value: projectLocationTextField.text
|
value: projectLocationTextField.text
|
||||||
}
|
}
|
||||||
@@ -138,7 +132,7 @@ Item {
|
|||||||
iconFont: StudioTheme.Constants.font
|
iconFont: StudioTheme.Constants.font
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var newLocation = dialogBox.chooseProjectLocation()
|
var newLocation = BackendApi.chooseProjectLocation()
|
||||||
if (newLocation)
|
if (newLocation)
|
||||||
projectLocationTextField.text = newLocation
|
projectLocationTextField.text = newLocation
|
||||||
}
|
}
|
||||||
@@ -159,7 +153,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: statusMessage
|
id: statusMessage
|
||||||
text: dialogBox.statusMessage
|
text: BackendApi.statusMessage
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
@@ -172,7 +166,7 @@ Item {
|
|||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "warning"
|
name: "warning"
|
||||||
when: dialogBox.statusType === "warning"
|
when: BackendApi.statusType === "warning"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: statusMessage
|
target: statusMessage
|
||||||
color: DialogValues.textWarning
|
color: DialogValues.textWarning
|
||||||
@@ -185,7 +179,7 @@ Item {
|
|||||||
|
|
||||||
State {
|
State {
|
||||||
name: "error"
|
name: "error"
|
||||||
when: dialogBox.statusType === "error"
|
when: BackendApi.statusType === "error"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: statusMessage
|
target: statusMessage
|
||||||
color: DialogValues.textError
|
color: DialogValues.textError
|
||||||
@@ -208,7 +202,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "saveAsDefaultLocation"
|
property: "saveAsDefaultLocation"
|
||||||
value: defaultLocationCheckbox.checked
|
value: defaultLocationCheckbox.checked
|
||||||
}
|
}
|
||||||
@@ -219,25 +213,25 @@ Item {
|
|||||||
id: screenSizeComboBox
|
id: screenSizeComboBox
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
currentIndex: -1
|
currentIndex: -1
|
||||||
model: screenSizeModel
|
model: BackendApi.screenSizeModel
|
||||||
textRole: "display"
|
textRole: "display"
|
||||||
width: parent.width
|
width: parent.width
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onActivated: (index) => {
|
onActivated: (index) => {
|
||||||
dialogBox.setScreenSizeIndex(index);
|
BackendApi.setScreenSizeIndex(index);
|
||||||
|
|
||||||
var size = screenSizeModel.screenSizes(index);
|
var size = BackendApi.screenSizeModel.screenSizes(index);
|
||||||
widthField.realValue = size.width;
|
widthField.realValue = size.width;
|
||||||
heightField.realValue = size.height;
|
heightField.realValue = size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: screenSizeModel
|
target: BackendApi.screenSizeModel
|
||||||
function onModelReset() {
|
function onModelReset() {
|
||||||
var newIndex = screenSizeComboBox.currentIndex > -1
|
var newIndex = screenSizeComboBox.currentIndex > -1
|
||||||
? screenSizeComboBox.currentIndex
|
? screenSizeComboBox.currentIndex
|
||||||
: dialogBox.screenSizeIndex()
|
: BackendApi.screenSizeIndex()
|
||||||
|
|
||||||
screenSizeComboBox.currentIndex = newIndex
|
screenSizeComboBox.currentIndex = newIndex
|
||||||
screenSizeComboBox.activated(newIndex)
|
screenSizeComboBox.activated(newIndex)
|
||||||
@@ -248,10 +242,8 @@ Item {
|
|||||||
GridLayout { // orientation + width + height
|
GridLayout { // orientation + width + height
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 85
|
height: 85
|
||||||
|
|
||||||
columns: 4
|
columns: 4
|
||||||
rows: 2
|
rows: 2
|
||||||
|
|
||||||
columnSpacing: 10
|
columnSpacing: 10
|
||||||
rowSpacing: 10
|
rowSpacing: 10
|
||||||
|
|
||||||
@@ -295,10 +287,7 @@ Item {
|
|||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onRealValueChanged: {
|
onRealValueChanged: {
|
||||||
var height = heightField.realValue
|
if (widthField.realValue >= heightField.realValue)
|
||||||
var width = realValue
|
|
||||||
|
|
||||||
if (width >= height)
|
|
||||||
orientationButton.setHorizontal()
|
orientationButton.setHorizontal()
|
||||||
else
|
else
|
||||||
orientationButton.setVertical()
|
orientationButton.setVertical()
|
||||||
@@ -306,7 +295,7 @@ Item {
|
|||||||
} // Width Text Field
|
} // Width Text Field
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "customWidth"
|
property: "customWidth"
|
||||||
value: widthField.realValue
|
value: widthField.realValue
|
||||||
}
|
}
|
||||||
@@ -323,10 +312,7 @@ Item {
|
|||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onRealValueChanged: {
|
onRealValueChanged: {
|
||||||
var height = realValue
|
if (widthField.realValue >= heightField.realValue)
|
||||||
var width = widthField.realValue
|
|
||||||
|
|
||||||
if (width >= height)
|
|
||||||
orientationButton.setHorizontal()
|
orientationButton.setHorizontal()
|
||||||
else
|
else
|
||||||
orientationButton.setVertical()
|
orientationButton.setVertical()
|
||||||
@@ -334,7 +320,7 @@ Item {
|
|||||||
} // Height Text Field
|
} // Height Text Field
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "customHeight"
|
property: "customHeight"
|
||||||
value: heightField.realValue
|
value: heightField.realValue
|
||||||
}
|
}
|
||||||
@@ -345,7 +331,6 @@ Item {
|
|||||||
id: orientationButton
|
id: orientationButton
|
||||||
implicitWidth: 100
|
implicitWidth: 100
|
||||||
implicitHeight: 50
|
implicitHeight: 50
|
||||||
|
|
||||||
checked: false
|
checked: false
|
||||||
hoverEnabled: false
|
hoverEnabled: false
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
@@ -384,19 +369,22 @@ Item {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (widthField.realValue && heightField.realValue) {
|
if (widthField.realValue && heightField.realValue) {
|
||||||
[widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue];
|
[widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue]
|
||||||
checked = !checked
|
orientationButton.checked = !orientationButton.checked
|
||||||
|
|
||||||
|
if (widthField.realValue === heightField.realValue)
|
||||||
|
orientationButton.checked ? setVertical() : setHorizontal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setHorizontal() {
|
function setHorizontal() {
|
||||||
checked = false
|
orientationButton.checked = false
|
||||||
horizontalBar.color = DialogValues.textColorInteraction
|
horizontalBar.color = DialogValues.textColorInteraction
|
||||||
verticalBar.color = "white"
|
verticalBar.color = "white"
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVertical() {
|
function setVertical() {
|
||||||
checked = true
|
orientationButton.checked = true
|
||||||
horizontalBar.color = "white"
|
horizontalBar.color = "white"
|
||||||
verticalBar.color = DialogValues.textColorInteraction
|
verticalBar.color = DialogValues.textColorInteraction
|
||||||
}
|
}
|
||||||
@@ -404,23 +392,27 @@ Item {
|
|||||||
|
|
||||||
} // GridLayout: orientation + width + height
|
} // GridLayout: orientation + width + height
|
||||||
|
|
||||||
Rectangle { width: parent.width; height: 1; color: DialogValues.dividerlineColor }
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: DialogValues.dividerlineColor
|
||||||
|
}
|
||||||
|
|
||||||
SC.CheckBox {
|
SC.CheckBox {
|
||||||
id: useQtVirtualKeyboard
|
id: useQtVirtualKeyboard
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
text: qsTr("Use Qt Virtual Keyboard")
|
text: qsTr("Use Qt Virtual Keyboard")
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
checked: dialogBox.useVirtualKeyboard
|
checked: BackendApi.useVirtualKeyboard
|
||||||
visible: dialogBox.haveVirtualKeyboard
|
visible: BackendApi.haveVirtualKeyboard
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout { // Target Qt Version
|
RowLayout { // Target Qt Version
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: dialogBox.haveTargetQtVersion
|
visible: BackendApi.haveTargetQtVersion
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: "Target Qt Version:"
|
text: qsTr("Target Qt Version:")
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
@@ -432,33 +424,98 @@ Item {
|
|||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
implicitWidth: 70
|
implicitWidth: 70
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
currentIndex: 1
|
currentIndex: BackendApi.targetQtVersionIndex
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement {
|
ListElement { name: "Qt 5" }
|
||||||
name: "Qt 5"
|
ListElement { name: "Qt 6" }
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
name: "Qt 6"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated: (index) => {
|
onActivated: (index) => {
|
||||||
dialogBox.setTargetQtVersion(index)
|
BackendApi.targetQtVersionIndex = index
|
||||||
}
|
}
|
||||||
} // Target Qt Version ComboBox
|
} // Target Qt Version ComboBox
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: BackendApi
|
||||||
|
property: "targetQtVersionIndex"
|
||||||
|
value: qtVersionComboBox.currentIndex
|
||||||
|
}
|
||||||
|
|
||||||
} // RowLayout
|
} // RowLayout
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "useVirtualKeyboard"
|
property: "useVirtualKeyboard"
|
||||||
value: useQtVirtualKeyboard.checked
|
value: useQtVirtualKeyboard.checked
|
||||||
}
|
}
|
||||||
} // ScrollContent Column
|
} // ScrollContent Column
|
||||||
} // ScrollView
|
} // ScrollView
|
||||||
|
|
||||||
} // Column
|
} // Column
|
||||||
|
|
||||||
|
SC.AbstractButton {
|
||||||
|
id: savePresetButton
|
||||||
|
width: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
buttonIcon: qsTr("Save Custom Preset")
|
||||||
|
iconFont: StudioTheme.Constants.font
|
||||||
|
iconSize: DialogValues.defaultPixelSize
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
onClicked: savePresetDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupDialog {
|
||||||
|
id: savePresetDialog
|
||||||
|
title: qsTr("Save Preset")
|
||||||
|
standardButtons: Dialog.Save | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: DialogValues.popupDialogWidth
|
||||||
|
|
||||||
|
onAccepted: BackendApi.savePresetDialogAccept()
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
presetNameTextField.selectAll()
|
||||||
|
presetNameTextField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Preset name")
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
color: DialogValues.textColor
|
||||||
|
}
|
||||||
|
|
||||||
|
SC.TextField {
|
||||||
|
id: presetNameTextField
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
translationIndicatorVisible: false
|
||||||
|
text: qsTr("MyPreset")
|
||||||
|
color: DialogValues.textColor
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
Layout.fillWidth: true
|
||||||
|
maximumLength: 30
|
||||||
|
validator: RegularExpressionValidator { regularExpression: /\w[\w ]*/ }
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
presetNameTextField.text = text.trim()
|
||||||
|
presetNameTextField.text = text.replace(/\s+/g, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: BackendApi
|
||||||
|
property: "presetName"
|
||||||
|
value: presetNameTextField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // Item
|
} // Item
|
||||||
}
|
} // Rectangle
|
||||||
}
|
} // root Item
|
||||||
|
@@ -29,39 +29,57 @@ import QtQml
|
|||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
readonly property int dialogWidth: 1522
|
readonly property int dialogWidth: 1522
|
||||||
readonly property int dialogHeight: 940
|
readonly property int dialogHeight: 940
|
||||||
readonly property int projectViewMinimumWidth: 600
|
readonly property int presetViewMinimumWidth: 600
|
||||||
readonly property int projectViewMinimumHeight: projectViewHeight
|
readonly property int presetViewMinimumHeight: root.gridCellHeight
|
||||||
readonly property int dialogContentHeight: projectViewHeight + 300 // i.e. dialog without header and footer
|
readonly property int dialogContentHeight: root.presetViewHeight + 300 // i.e. dialog without header and footer
|
||||||
readonly property int loadedPanesWidth: detailsPaneWidth + stylesPaneWidth
|
readonly property int loadedPanesWidth: root.detailsPaneWidth + root.stylesPaneWidth
|
||||||
readonly property int detailsPaneWidth: 330 + detailsPanePadding * 2
|
readonly property int detailsPaneWidth: 330 + root.detailsPanePadding * 2
|
||||||
readonly property int dialogTitleTextHeight: 85
|
readonly property int dialogTitleTextHeight: 85
|
||||||
readonly property int paneTitleTextHeight: 47
|
readonly property int paneTitleTextHeight: 47
|
||||||
readonly property int logoWidth: 85
|
readonly property int logoWidth: 85
|
||||||
readonly property int logoHeight: 85
|
readonly property int logoHeight: 85
|
||||||
|
|
||||||
/* detailsScrollableContentHeight - the full height that may need to be scrolled to be fully
|
readonly property int stylesPaneWidth: root.styleImageWidth + root.stylesPanePadding * 2
|
||||||
visible, if the dialog box is too small. */
|
+ root.styleImageBorderWidth * 2 // i.e. 240px
|
||||||
readonly property int detailsScrollableContentHeight: 428
|
|
||||||
readonly property int stylesPaneWidth: styleImageWidth + stylesPanePadding * 2 + styleImageBorderWidth * 2 // i.e. 240px
|
|
||||||
readonly property int detailsPanePadding: 18
|
readonly property int detailsPanePadding: 18
|
||||||
readonly property int stylesPanePadding: 18
|
readonly property int stylesPanePadding: 18
|
||||||
readonly property int defaultPadding: 18
|
readonly property int defaultPadding: 18
|
||||||
readonly property int dialogLeftPadding: 35
|
readonly property int dialogLeftPadding: 35
|
||||||
|
|
||||||
|
readonly property int styleListItemHeight: root.styleImageHeight + root.styleTextHeight
|
||||||
|
+ 2 * root.styleImageBorderWidth
|
||||||
|
+ root.styleListItemBottomMargin
|
||||||
|
+ root.styleListItemSpacing
|
||||||
|
readonly property int styleListItemBottomMargin: 10
|
||||||
|
readonly property int styleListItemSpacing: 4
|
||||||
readonly property int styleImageWidth: 200
|
readonly property int styleImageWidth: 200
|
||||||
|
readonly property int styleImageHeight: 262
|
||||||
readonly property int styleImageBorderWidth: 2
|
readonly property int styleImageBorderWidth: 2
|
||||||
|
readonly property int styleTextHeight: 18
|
||||||
|
|
||||||
readonly property int footerHeight: 73
|
readonly property int footerHeight: 73
|
||||||
readonly property int projectItemWidth: 90
|
readonly property int presetItemWidth: 136
|
||||||
readonly property int projectItemHeight: 144
|
readonly property int presetItemHeight: 110
|
||||||
readonly property int projectViewHeight: projectItemHeight * 2
|
property int presetViewHeight: root.presetItemHeight * 2 + root.gridSpacing + root.gridMargins * 2
|
||||||
readonly property int projectViewHeaderHeight: 38
|
readonly property int presetViewHeaderHeight: 38
|
||||||
|
|
||||||
|
readonly property int gridMargins: 20
|
||||||
|
readonly property int gridCellWidth: root.presetItemWidth + root.gridSpacing
|
||||||
|
readonly property int gridCellHeight: root.presetItemHeight + root.gridSpacing
|
||||||
|
readonly property int gridSpacing: 2
|
||||||
|
|
||||||
readonly property int dialogButtonWidth: 100
|
readonly property int dialogButtonWidth: 100
|
||||||
|
|
||||||
readonly property int loadedPanesHeight: dialogContentHeight
|
// This is for internal popup dialogs
|
||||||
readonly property int detailsPaneHeight: dialogContentHeight
|
readonly property int popupDialogWidth: 270
|
||||||
|
readonly property int popupDialogPadding: 12
|
||||||
|
|
||||||
|
readonly property int loadedPanesHeight: root.dialogContentHeight
|
||||||
|
readonly property int detailsPaneHeight: root.dialogContentHeight
|
||||||
|
|
||||||
readonly property string darkPaneColor: StudioTheme.Values.themeBackgroundColorNormal
|
readonly property string darkPaneColor: StudioTheme.Values.themeBackgroundColorNormal
|
||||||
readonly property string lightPaneColor: StudioTheme.Values.themeBackgroundColorAlternate
|
readonly property string lightPaneColor: StudioTheme.Values.themeBackgroundColorAlternate
|
||||||
@@ -71,6 +89,8 @@ QtObject {
|
|||||||
readonly property string dividerlineColor: StudioTheme.Values.themeTextColorDisabled
|
readonly property string dividerlineColor: StudioTheme.Values.themeTextColorDisabled
|
||||||
readonly property string textError: StudioTheme.Values.themeError
|
readonly property string textError: StudioTheme.Values.themeError
|
||||||
readonly property string textWarning: StudioTheme.Values.themeWarning
|
readonly property string textWarning: StudioTheme.Values.themeWarning
|
||||||
|
readonly property string presetItemBackgroundHover: StudioTheme.Values.themeControlBackgroundGlobalHover
|
||||||
|
readonly property string presetItemBackgroundHoverInteraction: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
|
||||||
readonly property real defaultPixelSize: 14
|
readonly property real defaultPixelSize: 14
|
||||||
readonly property real defaultLineHeight: 21
|
readonly property real defaultLineHeight: 21
|
||||||
|
@@ -28,111 +28,252 @@ import QtQuick.Controls
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import StudioControls as SC
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
GridView {
|
import BackendApi
|
||||||
id: projectView
|
|
||||||
|
ScrollView {
|
||||||
|
id: scrollView
|
||||||
|
|
||||||
required property Item loader
|
required property Item loader
|
||||||
|
required property string currentTabName
|
||||||
|
|
||||||
cellWidth: DialogValues.projectItemWidth
|
property string backgroundHoverColor: DialogValues.presetItemBackgroundHover
|
||||||
cellHeight: DialogValues.projectItemHeight
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
// selectLast: if true, it will select last item in the model after a model reset.
|
||||||
|
property bool selectLast: false
|
||||||
|
|
||||||
children: [
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
Rectangle {
|
ScrollBar.vertical: SC.VerticalScrollBar {
|
||||||
color: DialogValues.darkPaneColor
|
parent: scrollView
|
||||||
anchors.fill: parent
|
x: scrollView.width + (DialogValues.gridMargins
|
||||||
z: -1
|
- StudioTheme.Values.scrollBarThickness) * 0.5
|
||||||
|
y: scrollView.topPadding
|
||||||
|
height: scrollView.availableHeight
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
|
||||||
model: presetModel
|
contentWidth: gridView.contentItem.childrenRect.width
|
||||||
|
contentHeight: gridView.contentItem.childrenRect.height
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: gridView
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
anchors.fill: parent
|
||||||
|
cellWidth: DialogValues.gridCellWidth
|
||||||
|
cellHeight: DialogValues.gridCellHeight
|
||||||
|
rightMargin: -DialogValues.gridSpacing
|
||||||
|
bottomMargin: -DialogValues.gridSpacing
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
model: BackendApi.presetModel
|
||||||
|
|
||||||
// called by onModelReset and when user clicks on an item, or when the header item is changed.
|
// called by onModelReset and when user clicks on an item, or when the header item is changed.
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
dialogBox.selectedPreset = projectView.currentIndex
|
BackendApi.selectedPreset = gridView.currentIndex
|
||||||
var source = dialogBox.currentPresetQmlPath()
|
var source = BackendApi.currentPresetQmlPath()
|
||||||
loader.source = source
|
scrollView.loader.source = source
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: presetModel
|
target: BackendApi.presetModel
|
||||||
|
|
||||||
// called when data is set (setWizardFactories)
|
// called when data is set (setWizardFactories)
|
||||||
function onModelReset() {
|
function onModelReset() {
|
||||||
currentIndex = 0
|
if (scrollView.selectLast) {
|
||||||
currentIndexChanged()
|
gridView.currentIndex = BackendApi.presetModel.rowCount() - 1
|
||||||
|
scrollView.selectLast = false
|
||||||
|
} else {
|
||||||
|
gridView.currentIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will load Details.qml and Styles.qml by setting "source" on the Loader.
|
||||||
|
gridView.currentIndexChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: ItemDelegate {
|
delegate: ItemDelegate {
|
||||||
id: delegate
|
id: delegate
|
||||||
|
|
||||||
width: DialogValues.projectItemWidth
|
property bool hover: delegate.hovered || removeMouseArea.containsMouse
|
||||||
height: DialogValues.projectItemHeight
|
|
||||||
background: null
|
width: DialogValues.presetItemWidth
|
||||||
|
height: DialogValues.presetItemHeight
|
||||||
|
|
||||||
|
onClicked: delegate.GridView.view.currentIndex = index
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: delegateBackground
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
color: delegate.hover ? scrollView.backgroundHoverColor : "transparent"
|
||||||
|
border.color: delegate.hover ? presetName.color : "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
function fontIconCode(index) {
|
function fontIconCode(index) {
|
||||||
var code = presetModel.fontIconCode(index)
|
var code = BackendApi.presetModel.fontIconCode(index)
|
||||||
return code ? code : StudioTheme.Constants.wizardsUnknown
|
return code ? code : StudioTheme.Constants.wizardsUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
contentItem: Item {
|
||||||
width: parent.width
|
anchors.fill: parent
|
||||||
height: parent.height
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: -1
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: projectTypeIcon
|
id: presetIcon
|
||||||
text: fontIconCode(index)
|
text: delegate.fontIconCode(index)
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
width: parent.width
|
|
||||||
height: DialogValues.projectItemHeight / 2
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignBottom
|
verticalAlignment: Text.AlignBottom
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
font.pixelSize: 65
|
font.pixelSize: 65
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
}
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
} // Preset type icon Label
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: projectTypeLabel
|
id: presetName
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
|
|
||||||
text: name
|
text: name
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
width: parent.width
|
width: DialogValues.presetItemWidth - 16
|
||||||
height: DialogValues.projectItemHeight / 2
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignTop
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.preferredWidth: presetName.width
|
||||||
|
Layout.minimumWidth: presetName.width
|
||||||
|
Layout.maximumWidth: presetName.width
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
id: toolTip
|
||||||
|
y: -toolTip.height
|
||||||
|
visible: delegate.hovered && presetName.truncated
|
||||||
|
text: name
|
||||||
|
delay: 1000
|
||||||
|
height: 20
|
||||||
|
|
||||||
|
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
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: presetResolution
|
||||||
|
color: DialogValues.textColor
|
||||||
|
text: resolution
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
|
lineHeightMode: Text.FixedHeight
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignTop
|
verticalAlignment: Text.AlignTop
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ColumnLayout
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: removePresetButton
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: 4
|
||||||
|
visible: isUserPreset === true
|
||||||
|
&& delegate.hover
|
||||||
|
&& scrollView.currentTabName !== BackendApi.recentsTabName()
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
text: StudioTheme.Constants.closeCross
|
||||||
|
color: DialogValues.textColor
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
|
font.pixelSize: StudioTheme.Values.myIconFontSize
|
||||||
}
|
}
|
||||||
} // Column
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
id: removeMouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: removeMouseArea.containsMouse ? Qt.PointingHandCursor
|
||||||
|
: Qt.ArrowCursor
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
delegate.GridView.view.currentIndex = index
|
removePresetDialog.presetName = presetName.text
|
||||||
|
removePresetDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // Delete preset button Item
|
||||||
|
} // Item
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
|
name: "current"
|
||||||
when: delegate.GridView.isCurrentItem
|
when: delegate.GridView.isCurrentItem
|
||||||
PropertyChanges {
|
|
||||||
target: projectTypeLabel
|
|
||||||
color: DialogValues.textColorInteraction
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: projectTypeIcon
|
target: presetName
|
||||||
color: DialogValues.textColorInteraction
|
color: DialogValues.textColorInteraction
|
||||||
}
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: presetResolution
|
||||||
|
color: DialogValues.textColorInteraction
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: presetIcon
|
||||||
|
color: DialogValues.textColorInteraction
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: scrollView
|
||||||
|
backgroundHoverColor: DialogValues.presetItemBackgroundHoverInteraction
|
||||||
|
}
|
||||||
} // State
|
} // State
|
||||||
]
|
]
|
||||||
} // ItemDelegate
|
} // ItemDelegate
|
||||||
|
|
||||||
|
PopupDialog {
|
||||||
|
id: removePresetDialog
|
||||||
|
|
||||||
|
property string presetName
|
||||||
|
|
||||||
|
title: qsTr("Delete Custom Preset")
|
||||||
|
standardButtons: Dialog.Yes | Dialog.No
|
||||||
|
modal: true
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: DialogValues.popupDialogWidth
|
||||||
|
|
||||||
|
onAccepted: BackendApi.removeCurrentPreset()
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Are you sure you want to delete \"" + removePresetDialog.presetName + "\" ?")
|
||||||
|
color: DialogValues.textColor
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
|
width: DialogValues.popupDialogWidth - 2 * DialogValues.popupDialogPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Dialog
|
||||||
} // GridView
|
} // GridView
|
||||||
|
} // ScrollView
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: root
|
||||||
|
padding: DialogValues.popupDialogPadding
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: DialogValues.darkPaneColor
|
||||||
|
border.color: StudioTheme.Values.themeInteraction
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
}
|
||||||
|
|
||||||
|
header: Label {
|
||||||
|
text: root.title
|
||||||
|
visible: root.title
|
||||||
|
elide: Label.ElideRight
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
padding: DialogValues.popupDialogPadding
|
||||||
|
color: DialogValues.textColor
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
x: 1
|
||||||
|
y: 1
|
||||||
|
width: parent.width - 2
|
||||||
|
height: parent.height - 1
|
||||||
|
color: DialogValues.darkPaneColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: PopupDialogButtonBox {
|
||||||
|
visible: count > 0
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,107 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
implicitWidth: Math.max(
|
||||||
|
background ? background.implicitWidth : 0,
|
||||||
|
textItem.implicitWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(
|
||||||
|
background ? background.implicitHeight : 0,
|
||||||
|
textItem.implicitHeight + topPadding + bottomPadding)
|
||||||
|
leftPadding: 4
|
||||||
|
rightPadding: 4
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: background
|
||||||
|
implicitWidth: 80
|
||||||
|
implicitHeight: StudioTheme.Values.height
|
||||||
|
color: StudioTheme.Values.themeControlBackground
|
||||||
|
border.color: StudioTheme.Values.themeControlOutline
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Text {
|
||||||
|
id: textItem
|
||||||
|
text: root.text
|
||||||
|
font.family: StudioTheme.Constants.font.family
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
renderType: Text.QtRendering
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "default"
|
||||||
|
when: !root.hovered && !root.checked && !root.pressed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: background
|
||||||
|
color: StudioTheme.Values.themeControlBackground
|
||||||
|
border.color: StudioTheme.Values.themeControlOutline
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hover"
|
||||||
|
when: root.hovered && !root.checked && !root.pressed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: background
|
||||||
|
color: StudioTheme.Values.themeControlBackgroundHover
|
||||||
|
border.color: StudioTheme.Values.themeControlOutline
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "press"
|
||||||
|
when: root.hovered && root.pressed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: background
|
||||||
|
color: StudioTheme.Values.themeInteraction
|
||||||
|
border.color: StudioTheme.Values.themeInteraction
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: StudioTheme.Values.themeIconColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
DialogButtonBox {
|
||||||
|
id: root
|
||||||
|
padding: DialogValues.popupDialogPadding
|
||||||
|
alignment: Qt.AlignRight | Qt.AlignBottom
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
implicitHeight: 40
|
||||||
|
x: 1
|
||||||
|
y: 1
|
||||||
|
width: parent.width - 2
|
||||||
|
height: parent.height - 2
|
||||||
|
color: DialogValues.darkPaneColor
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: PopupDialogButton {
|
||||||
|
width: root.count === 1 ? root.availableWidth / 2 : undefined
|
||||||
|
}
|
||||||
|
}
|
@@ -23,20 +23,21 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import StudioControls as SC
|
import StudioControls as SC
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: DialogValues.stylesPaneWidth
|
width: DialogValues.stylesPaneWidth
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
dialogBox.stylesLoaded = true;
|
BackendApi.stylesLoaded = true
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: roleNames is called before the backend model (in the proxy class StyleModel) is
|
* TODO: roleNames is called before the backend model (in the proxy class StyleModel) is
|
||||||
@@ -47,7 +48,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
dialogBox.stylesLoaded = false;
|
BackendApi.stylesLoaded = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -57,35 +58,40 @@ Item {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
x: DialogValues.stylesPanePadding
|
x: DialogValues.stylesPanePadding
|
||||||
width: parent.width - DialogValues.stylesPanePadding * 2 + styleScrollBar.width
|
width: parent.width - DialogValues.stylesPanePadding * 2
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
spacing: 5
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: styleTitleText
|
id: styleTitleText
|
||||||
text: qsTr("Style")
|
text: qsTr("Style")
|
||||||
Layout.minimumHeight: DialogValues.paneTitleTextHeight
|
height: DialogValues.paneTitleTextHeight
|
||||||
|
width: parent.width
|
||||||
font.weight: Font.DemiBold
|
font.weight: Font.DemiBold
|
||||||
font.pixelSize: DialogValues.paneTitlePixelSize
|
font.pixelSize: DialogValues.paneTitlePixelSize
|
||||||
lineHeight: DialogValues.paneTitleLineHeight
|
lineHeight: DialogValues.paneTitleLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
verticalAlignment: Qt.AlignVCenter
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
function refresh() {
|
function refresh() {
|
||||||
text = qsTr("Style") + " (" + styleModel.rowCount() + ")"
|
styleTitleText.text = qsTr("Style") + " (" + BackendApi.styleModel.rowCount() + ")"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SC.ComboBox { // Style Filter ComboBox
|
SC.ComboBox { // Style Filter ComboBox
|
||||||
|
id: styleComboBox
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
currentIndex: 0
|
currentIndex: 0
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
valueRole: "value"
|
valueRole: "value"
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
anchors.top: styleTitleText.bottom
|
||||||
|
anchors.topMargin: 5
|
||||||
|
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement { text: qsTr("All"); value: "all" }
|
ListElement { text: qsTr("All"); value: "all" }
|
||||||
@@ -93,80 +99,79 @@ Item {
|
|||||||
ListElement { text: qsTr("Dark"); value: "dark" }
|
ListElement { text: qsTr("Dark"); value: "dark" }
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitWidth: parent.width
|
|
||||||
|
|
||||||
onActivated: (index) => {
|
onActivated: (index) => {
|
||||||
styleModel.filter(currentValue.toLowerCase());
|
BackendApi.styleModel.filter(currentValue.toLowerCase())
|
||||||
styleTitleText.refresh();
|
styleTitleText.refresh()
|
||||||
}
|
}
|
||||||
} // Style Filter ComboBox
|
} // Style Filter ComboBox
|
||||||
|
|
||||||
Item { implicitWidth: 1; implicitHeight: 9 }
|
ScrollView {
|
||||||
|
id: scrollView
|
||||||
|
|
||||||
|
anchors.top: styleComboBox.bottom
|
||||||
|
anchors.topMargin: 11
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: DialogValues.stylesPanePadding
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
|
ScrollBar.vertical: SC.VerticalScrollBar {
|
||||||
|
id: styleScrollBar
|
||||||
|
x: stylesList.width + (DialogValues.stylesPanePadding
|
||||||
|
- StudioTheme.Values.scrollBarThickness) * 0.5
|
||||||
|
}
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: stylesList
|
id: stylesList
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
clip: true
|
|
||||||
model: styleModel
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: listViewMouseArea
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
|
||||||
propagateComposedEvents: true
|
|
||||||
}
|
|
||||||
|
|
||||||
focus: true
|
focus: true
|
||||||
|
clip: true
|
||||||
|
model: BackendApi.styleModel
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
|
||||||
highlightFollowsCurrentItem: false
|
highlightFollowsCurrentItem: false
|
||||||
|
bottomMargin: -DialogValues.styleListItemBottomMargin
|
||||||
ScrollBar.vertical: SC.VerticalScrollBar {
|
|
||||||
id: styleScrollBar
|
|
||||||
property int extraPadding: 0
|
|
||||||
bottomInset: extraPadding
|
|
||||||
bottomPadding: bottomInset + 16
|
|
||||||
viewMouseArea: listViewMouseArea
|
|
||||||
} // ScrollBar
|
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
if (styleModel.rowCount() > 0)
|
if (BackendApi.styleModel.rowCount() > 0)
|
||||||
dialogBox.styleIndex = stylesList.currentIndex;
|
BackendApi.styleIndex = stylesList.currentIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: ItemDelegate {
|
delegate: ItemDelegate {
|
||||||
id: delegateId
|
id: delegateId
|
||||||
height: styleImage.height + DialogValues.styleImageBorderWidth + styleText.height + extraPadding.height + 1
|
width: stylesList.width
|
||||||
width: stylesList.width - styleScrollBar.width
|
height: DialogValues.styleListItemHeight
|
||||||
|
|
||||||
Component.onCompleted: {
|
onClicked: stylesList.currentIndex = index
|
||||||
styleScrollBar.extraPadding = styleText.height + extraPadding.height
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
background: Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: DialogValues.lightPaneColor
|
color: DialogValues.lightPaneColor
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
contentItem: Item {
|
||||||
spacing: 0
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: DialogValues.styleListItemSpacing
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
border.color: index == stylesList.currentIndex ? DialogValues.textColorInteraction : "transparent"
|
width: DialogValues.styleImageWidth
|
||||||
border.width: index == stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0
|
+ 2 * DialogValues.styleImageBorderWidth
|
||||||
|
height: DialogValues.styleImageHeight
|
||||||
|
+ 2 * DialogValues.styleImageBorderWidth
|
||||||
|
border.color: index === stylesList.currentIndex ? DialogValues.textColorInteraction : "transparent"
|
||||||
|
border.width: index === stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
width: parent.width
|
|
||||||
height: parent.height - styleText.height - extraPadding.height
|
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: styleImage
|
id: styleImage
|
||||||
asynchronous: false
|
|
||||||
source: "image://newprojectdialog_library/" + styleModel.iconId(model.index)
|
|
||||||
width: 200
|
|
||||||
height: 262
|
|
||||||
x: DialogValues.styleImageBorderWidth
|
x: DialogValues.styleImageBorderWidth
|
||||||
y: DialogValues.styleImageBorderWidth
|
y: DialogValues.styleImageBorderWidth
|
||||||
|
width: DialogValues.styleImageWidth
|
||||||
|
height: DialogValues.styleImageHeight
|
||||||
|
asynchronous: false
|
||||||
|
source: "image://newprojectdialog_library/" + BackendApi.styleModel.iconId(model.index)
|
||||||
}
|
}
|
||||||
} // Rectangle
|
} // Rectangle
|
||||||
|
|
||||||
@@ -175,35 +180,26 @@ Item {
|
|||||||
text: model.display
|
text: model.display
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
height: 18
|
height: DialogValues.styleTextHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
width: parent.width
|
width: parent.width
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { id: extraPadding; width: 1; height: 10 }
|
|
||||||
} // Column
|
} // Column
|
||||||
} // Rectangle
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: {
|
|
||||||
stylesList.currentIndex = index
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: styleModel
|
target: BackendApi.styleModel
|
||||||
function onModelReset() {
|
function onModelReset() {
|
||||||
stylesList.currentIndex = dialogBox.styleIndex;
|
stylesList.currentIndex = BackendApi.styleIndex
|
||||||
stylesList.currentIndexChanged();
|
stylesList.currentIndexChanged()
|
||||||
styleTitleText.refresh();
|
styleTitleText.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // ListView
|
} // ListView
|
||||||
} // ColumnLayout
|
} // ScrollView
|
||||||
} // Parent Item
|
} // Parent Item
|
||||||
} // Rectangle
|
} // Rectangle
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
singleton DialogValues 1.0 DialogValues.qml
|
PopupDialog 1.0 PopupDialog.qml
|
||||||
|
PopupDialogButton 1.0 PopupDialogButton.qml
|
||||||
|
PopupDialogButtonBox 1.0 PopupDialogButtonBox.qml
|
||||||
Details 1.0 Details.qml
|
Details 1.0 Details.qml
|
||||||
Styles 1.0 Styles.qml
|
singleton DialogValues 1.0 DialogValues.qml
|
||||||
NewProjectView 1.0 NewProjectView.qml
|
NewProjectView 1.0 NewProjectView.qml
|
||||||
|
Styles 1.0 Styles.qml
|
||||||
|
@@ -140,7 +140,7 @@ StudioControls.TextField {
|
|||||||
+ 2 : 0)
|
+ 2 : 0)
|
||||||
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
|
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
|
||||||
color: StudioTheme.Values.themeInteraction
|
color: StudioTheme.Values.themeInteraction
|
||||||
y: listView.currentItem.y
|
y: listView.currentItem?.y ?? 0
|
||||||
}
|
}
|
||||||
highlightFollowsCurrentItem: false
|
highlightFollowsCurrentItem: false
|
||||||
}
|
}
|
||||||
|
@@ -54,6 +54,8 @@ Item {
|
|||||||
property bool expandOnClick: true // if false, toggleExpand signal will be emitted instead
|
property bool expandOnClick: true // if false, toggleExpand signal will be emitted instead
|
||||||
property bool addTopPadding: true
|
property bool addTopPadding: true
|
||||||
property bool addBottomPadding: true
|
property bool addBottomPadding: true
|
||||||
|
property bool dropEnabled: false
|
||||||
|
property bool highlight: false
|
||||||
|
|
||||||
property bool useDefaulContextMenu: true
|
property bool useDefaulContextMenu: true
|
||||||
|
|
||||||
@@ -72,9 +74,22 @@ Item {
|
|||||||
function onExpandAll() { section.expanded = true }
|
function onExpandAll() { section.expanded = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signal drop(var drag)
|
||||||
|
signal dropEnter(var drag)
|
||||||
|
signal dropExit()
|
||||||
signal showContextMenu()
|
signal showContextMenu()
|
||||||
signal toggleExpand()
|
signal toggleExpand()
|
||||||
|
|
||||||
|
DropArea {
|
||||||
|
id: dropArea
|
||||||
|
|
||||||
|
enabled: section.dropEnabled
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onEntered: (drag)=> section.dropEnter(drag)
|
||||||
|
onDropped: (drag)=> section.drop(drag)
|
||||||
|
onExited: section.dropExit()
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: header
|
id: header
|
||||||
@@ -82,7 +97,9 @@ Item {
|
|||||||
visible: !section.hideHeader
|
visible: !section.hideHeader
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
color: Qt.lighter(StudioTheme.Values.themeSectionHeadBackground, 1.0 + (0.2 * section.level))
|
color: section.highlight ? StudioTheme.Values.themeInteraction
|
||||||
|
: Qt.lighter(StudioTheme.Values.themeSectionHeadBackground, 1.0
|
||||||
|
+ (0.2 * section.level))
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
StudioControls.Menu {
|
StudioControls.Menu {
|
||||||
|
@@ -35,37 +35,26 @@ ScrollBar {
|
|||||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
implicitContentHeight + topPadding + bottomPadding)
|
implicitContentHeight + topPadding + bottomPadding)
|
||||||
|
|
||||||
property bool scrollBarVisible: parent.childrenRect.height > parent.height
|
property bool scrollBarVisible: parent.contentHeight > scrollBar.height
|
||||||
// viewMouseArea: if set, the scrollbar will be visible only on hover over the view containing
|
|
||||||
// the mouse area item.
|
|
||||||
property MouseArea viewMouseArea: null
|
|
||||||
|
|
||||||
minimumSize: orientation == Qt.Horizontal ? height / width : width / height
|
|
||||||
|
|
||||||
|
minimumSize: scrollBar.width / scrollBar.height
|
||||||
orientation: Qt.Vertical
|
orientation: Qt.Vertical
|
||||||
policy: computePolicy()
|
policy: scrollBar.scrollBarVisible ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
|
||||||
x: parent.width - width
|
|
||||||
y: 0
|
|
||||||
height: parent.availableHeight
|
height: parent.availableHeight
|
||||||
- (parent.bothVisible ? parent.horizontalThickness : 0)
|
- (parent.bothVisible ? parent.horizontalThickness : 0)
|
||||||
padding: 0
|
padding: scrollBar.active ? StudioTheme.Values.scrollBarActivePadding
|
||||||
|
: StudioTheme.Values.scrollBarInactivePadding
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
implicitWidth: StudioTheme.Values.scrollBarThickness
|
||||||
|
implicitHeight: StudioTheme.Values.scrollBarThickness
|
||||||
color: StudioTheme.Values.themeScrollBarTrack
|
color: StudioTheme.Values.themeScrollBarTrack
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Rectangle {
|
contentItem: Rectangle {
|
||||||
implicitWidth: StudioTheme.Values.scrollBarThickness
|
implicitWidth: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
|
||||||
|
implicitHeight: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
|
||||||
color: StudioTheme.Values.themeScrollBarHandle
|
color: StudioTheme.Values.themeScrollBarHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
function computePolicy() {
|
|
||||||
if (!scrollBar.scrollBarVisible)
|
|
||||||
return ScrollBar.AlwaysOff;
|
|
||||||
|
|
||||||
if (scrollBar.viewMouseArea)
|
|
||||||
return scrollBar.viewMouseArea.containsMouse ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
|
|
||||||
else
|
|
||||||
return ScrollBar.AlwaysOn;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -89,6 +89,8 @@ QtObject {
|
|||||||
property real typeLabelVerticalShift: Math.round(6 * values.scaleFactor)
|
property real typeLabelVerticalShift: Math.round(6 * values.scaleFactor)
|
||||||
|
|
||||||
property real scrollBarThickness: 10
|
property real scrollBarThickness: 10
|
||||||
|
property real scrollBarActivePadding: 1
|
||||||
|
property real scrollBarInactivePadding: 2
|
||||||
|
|
||||||
property real toolTipHeight: 25
|
property real toolTipHeight: 25
|
||||||
property int toolTipDelay: 1000
|
property int toolTipDelay: 1000
|
||||||
|