Merge "Merge remote-tracking branch 'origin/qds/dev'"
@@ -155,27 +155,14 @@
|
|||||||
{Qt Code Review}.
|
{Qt Code Review}.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
\list 1
|
||||||
|
\li Clone the module repository.
|
||||||
\badcode
|
\badcode
|
||||||
git clone https://code.qt.io/qt-labs/qtquickdesigner-components.git
|
git clone https://code.qt.io/qt-labs/qtquickdesigner-components.git
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
Then use qmake from your Qt installation to build the module and to add it
|
\li Install the Qt Quick Designer Components module.
|
||||||
to your Qt. Switch to the directory that contains the sources (usually,
|
|
||||||
qtquickdesigner-components), make sure you checkout the qmake branch, and enter
|
|
||||||
the following commands:
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
<path_to_qmake>\qmake -r
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
On Windows, use the \c nmake and \c {nmake install} commands instead.
|
|
||||||
|
|
||||||
If you prefer CMake instead and you want to benefit from the QML compilation,
|
|
||||||
then you can checkout the dev branch instead. CMake is only supported since Qt 6.2.
|
|
||||||
Enter the following commands:
|
Enter the following commands:
|
||||||
|
|
||||||
\badcode
|
\badcode
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
@@ -183,28 +170,9 @@
|
|||||||
cmake --build .
|
cmake --build .
|
||||||
cmake --install .
|
cmake --install .
|
||||||
\endcode
|
\endcode
|
||||||
|
\note Here, \e <path_to_qt_install_directory> and \e <path_to_qtquickdesigner-components>
|
||||||
\section1 Adding Qt Quick Timeline Module to Qt Installations
|
needs to be replaced with the real location on your local drive. For example,
|
||||||
|
\e <path_to_qt_install_directory> can be something like \e /Qt/6.3.0/msvc2019_64
|
||||||
\note You only need to do this if your Qt version is older than 5.14.
|
and \e <path_to_qtquickdesigner-components> like this \e ../qtquickdesigner-components/
|
||||||
|
\endlist
|
||||||
Check out the \l{Qt Quick Timeline} module from
|
|
||||||
\l{https://codereview.qt-project.org/#/admin/projects/qt/qtquicktimeline}
|
|
||||||
{Qt Code Review}.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
\badcode
|
|
||||||
git clone "https://codereview.qt-project.org/qt/qtquicktimeline"
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
To use qmake, you need to check out a branch or tag that contains the
|
|
||||||
qmake configuration files.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
\badcode
|
|
||||||
git checkout v5.15.2
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
Then build the module and add it to your Qt as described in the previous
|
|
||||||
section.
|
|
||||||
*/
|
*/
|
||||||
|
@@ -4,7 +4,11 @@
|
|||||||
/*!
|
/*!
|
||||||
\page creator-open-documents-view.html
|
\page creator-open-documents-view.html
|
||||||
\previouspage creator-file-system-view.html
|
\previouspage creator-file-system-view.html
|
||||||
|
\if defined(qtdesignstudio)
|
||||||
|
\nextpage studio-content-library.html
|
||||||
|
\else
|
||||||
\nextpage creator-output-panes.html
|
\nextpage creator-output-panes.html
|
||||||
|
\endif
|
||||||
|
|
||||||
\title Open Documents
|
\title Open Documents
|
||||||
|
|
||||||
|
@@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
We will now copy the color animation from the text label to the indicator.
|
We will now copy the color animation from the text label to the indicator.
|
||||||
First, we right-click the text component in the \uicontrol Timeline view to
|
First, we right-click the text component in the \uicontrol Timeline view to
|
||||||
open a context menu and select \uicontrol {Copy All Keyframes from Item} to
|
open a context menu and select \uicontrol {Copy All Keyframes} to
|
||||||
copy the keyframe values we specified for the text label.
|
copy the keyframe values we specified for the text label.
|
||||||
|
|
||||||
Next, we select the indicator in the \uicontrol Navigator, and then select
|
Next, we select the indicator in the \uicontrol Navigator, and then select
|
||||||
|
BIN
doc/qtdesignstudio/images/content-library-add-texture.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
doc/qtdesignstudio/images/content-library.webp
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
doc/qtdesignstudio/images/icons/area.png
Normal file
After Width: | Height: | Size: 360 B |
BIN
doc/qtdesignstudio/images/icons/directional.png
Normal file
After Width: | Height: | Size: 265 B |
BIN
doc/qtdesignstudio/images/icons/line-particles-16px.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
doc/qtdesignstudio/images/icons/point.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
doc/qtdesignstudio/images/icons/repeller-16px.png
Normal file
After Width: | Height: | Size: 488 B |
BIN
doc/qtdesignstudio/images/icons/scale-affector-16px.png
Normal file
After Width: | Height: | Size: 518 B |
BIN
doc/qtdesignstudio/images/icons/spot.png
Normal file
After Width: | Height: | Size: 391 B |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 41 KiB |
BIN
doc/qtdesignstudio/images/select-material-property.png
Normal file
After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 36 KiB |
BIN
doc/qtdesignstudio/images/studio-3d-properties-line-particle.png
Normal file
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 9.3 KiB |
BIN
doc/qtdesignstudio/images/texture-editor.png
Normal file
After Width: | Height: | Size: 55 KiB |
@@ -44,23 +44,19 @@
|
|||||||
|
|
||||||
Property bindings are created implicitly whenever a property is assigned a
|
Property bindings are created implicitly whenever a property is assigned a
|
||||||
JavaScript expression. To set JavaScript expressions as values of properties
|
JavaScript expression. To set JavaScript expressions as values of properties
|
||||||
in the \l Properties view, select the \inlineimage icons/action-icon.png
|
in the \l Properties view:
|
||||||
|
\list 1
|
||||||
|
\li Select the \inlineimage icons/action-icon.png
|
||||||
(\uicontrol Actions) menu next to a property, and then select
|
(\uicontrol Actions) menu next to a property, and then select
|
||||||
\uicontrol {Set Binding}.
|
\uicontrol {Set Binding}.
|
||||||
|
|
||||||
\image qmldesigner-set-expression.png "Actions menu"
|
\image qmldesigner-set-expression.png "Actions menu"
|
||||||
|
|
||||||
In \uicontrol {Binding Editor}, select a component and a property from
|
\li In \uicontrol {Binding Editor}, select a component and a property from
|
||||||
lists of available components and their properties.
|
lists of available components and their properties.
|
||||||
|
|
||||||
\image qmldesigner-binding-editor.png "Binding Editor"
|
\image qmldesigner-binding-editor.png "Binding Editor"
|
||||||
|
\endlist
|
||||||
Alternatively, start typing a
|
|
||||||
string and press \key Ctrl+Space to display a list of properties, IDs, and
|
|
||||||
code snippets. When you enter a period (.) after a property name, a list of
|
|
||||||
available values is displayed. Press \key Enter to accept the first
|
|
||||||
suggestion in the list and to complete the code. For more information, see
|
|
||||||
\l{Completing Code}.
|
|
||||||
|
|
||||||
When a binding is set, the \uicontrol Actions menu icon changes to
|
When a binding is set, the \uicontrol Actions menu icon changes to
|
||||||
\inlineimage icons/action-icon-binding.png
|
\inlineimage icons/action-icon-binding.png
|
||||||
|
@@ -31,11 +31,15 @@
|
|||||||
\list 1
|
\list 1
|
||||||
\li Open the application in \QDS.
|
\li Open the application in \QDS.
|
||||||
\li Select \uicontrol File > \uicontrol {Share Application Online}.
|
\li Select \uicontrol File > \uicontrol {Share Application Online}.
|
||||||
\li In the dialog, select \uicontrol Share.
|
\li Optionally, select \uicontrol {Protect with password}, and enter a password to prevent
|
||||||
|
unauthorized viewing of the application.
|
||||||
|
\note If you share the same application again, you must set the password
|
||||||
|
again. Otherwise, the application is not password protected any longer.
|
||||||
|
\li Select \uicontrol Share.
|
||||||
\image share-online.webp
|
\image share-online.webp
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
In the dialog, you can now open the application in a web
|
You can now open the application in a web
|
||||||
browser, copy the link to share with others, or manage your shared
|
browser, copy the link to share with others, or manage your shared
|
||||||
applications.
|
applications.
|
||||||
|
|
||||||
|
@@ -32,6 +32,8 @@
|
|||||||
\li \l{Projects}
|
\li \l{Projects}
|
||||||
\li \l{File System}
|
\li \l{File System}
|
||||||
\li \l{Open Documents}
|
\li \l{Open Documents}
|
||||||
|
\li \l{Content Library}
|
||||||
|
\li \l{Texture Editor}
|
||||||
\endlist
|
\endlist
|
||||||
\li \l{Managing Workspaces}
|
\li \l{Managing Workspaces}
|
||||||
\li \l{Managing Sessions}
|
\li \l{Managing Sessions}
|
||||||
|
@@ -41,25 +41,25 @@
|
|||||||
\li More Information
|
\li More Information
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \inlineimage directional.png
|
\li \inlineimage icons/directional.png
|
||||||
\li Directional Light
|
\li Directional Light
|
||||||
\li
|
\li
|
||||||
\li \l{DirectionalLight}{Light Directional}
|
\li \l{DirectionalLight}{Light Directional}
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \inlineimage point.png
|
\li \inlineimage icons/point.png
|
||||||
\li Point Light
|
\li Point Light
|
||||||
\li
|
\li
|
||||||
\li \l{PointLight}{Light Point}
|
\li \l{PointLight}{Light Point}
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \inlineimage spot.png
|
\li \inlineimage icons/spot.png
|
||||||
\li Spot Light
|
\li Spot Light
|
||||||
\li
|
\li
|
||||||
\li \l{SpotLight}{Light Spot}
|
\li \l{SpotLight}{Light Spot}
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \inlineimage area.png
|
\li \inlineimage icons/area.png
|
||||||
\li Area Light
|
\li Area Light
|
||||||
\li \inlineimage ok.png
|
\li \inlineimage ok.png
|
||||||
\li \l{AreaLight}{Light Area}
|
\li \l{AreaLight}{Light Area}
|
||||||
|
@@ -70,10 +70,15 @@
|
|||||||
\li \inlineimage icons/attractor-16px.png
|
\li \inlineimage icons/attractor-16px.png
|
||||||
\li Attractor
|
\li Attractor
|
||||||
\li Attracts particles towards a specific point.
|
\li Attracts particles towards a specific point.
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/emit-burst-16px.png
|
||||||
|
\li Dynamic Burst
|
||||||
|
\li Emits particles in dynamic bursts. Use dynamic burst for
|
||||||
|
emitters that are moving.
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/emit-burst-16px.png
|
\li \inlineimage icons/emit-burst-16px.png
|
||||||
\li Emit Burst
|
\li Emit Burst
|
||||||
\li Generates declarative emitter bursts.
|
\li Emits particles in bursts.
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/emitter-16px.png
|
\li \inlineimage icons/emitter-16px.png
|
||||||
\li Emitter
|
\li Emitter
|
||||||
@@ -83,6 +88,10 @@
|
|||||||
\li Gravity
|
\li Gravity
|
||||||
\li Accelerates particles to a vector of the specified magnitude in the
|
\li Accelerates particles to a vector of the specified magnitude in the
|
||||||
specified direction.
|
specified direction.
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/line-particles-16px.png
|
||||||
|
\li Line Particle
|
||||||
|
\li Creates line-shaped sprite particles.
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/model-blend-particle-16px.png
|
\li \inlineimage icons/model-blend-particle-16px.png
|
||||||
\li Model Blend Particle
|
\li Model Blend Particle
|
||||||
@@ -110,6 +119,15 @@
|
|||||||
\li \inlineimage icons/point-rotator-16px.png
|
\li \inlineimage icons/point-rotator-16px.png
|
||||||
\li Point Rotator
|
\li Point Rotator
|
||||||
\li Rotates particles around a pivot point.
|
\li Rotates particles around a pivot point.
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/repeller-16px.png
|
||||||
|
\li Repeller
|
||||||
|
\li Repels particles from its location.
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/scale-affector-16px.png
|
||||||
|
\li Scale Affector
|
||||||
|
\li Scales particles based on the particles' lifetime and other
|
||||||
|
parameters.
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/sprite-particle-16px.png
|
\li \inlineimage icons/sprite-particle-16px.png
|
||||||
\li Sprite Particle
|
\li Sprite Particle
|
||||||
@@ -399,19 +417,23 @@
|
|||||||
visualized, and some logical particles could lead to multiple visual
|
visualized, and some logical particles could lead to multiple visual
|
||||||
particles being drawn on screen.
|
particles being drawn on screen.
|
||||||
|
|
||||||
Two different logical particle components are supported:
|
\QDS supports the following logical particle components:
|
||||||
\uicontrol {Sprite Particle} for \l{Textures}{2D texture} particles and
|
|
||||||
\uicontrol {Model Particle} for \l{3D Models}{3D model} particles. Model
|
|
||||||
particles use \l{Instanced Rendering}{instanced rendering} to enabled the
|
|
||||||
rendering of thousands of particles, with full \l{3D Materials}{materials}
|
|
||||||
and \l{Lights}{lights} support.
|
|
||||||
|
|
||||||
The following components are available for adding logical particles and
|
\list
|
||||||
for modifying their actions and appearance:
|
\li \uicontrol {Sprite Particle} and \uicontrol{Line Particle} for
|
||||||
|
\l{Textures}{2D texture} particles.
|
||||||
|
\li \uicontrol {Model Particle} for \l{3D Models}{3D model} particles.
|
||||||
|
Model particles use \l{Instanced Rendering}{instanced rendering} to render
|
||||||
|
thousands of particles, with full \l{3D Materials}{materials} and
|
||||||
|
\l{Lights}{lights} support.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
You can use the following components to add and modify logical particles:
|
||||||
|
|
||||||
\list
|
\list
|
||||||
\li \l{Sprite Particle}
|
\li \l{Sprite Particle}
|
||||||
\li \l{Sprite Sequence}
|
\li \l{Sprite Sequence}
|
||||||
|
\li \l{Line Particle}
|
||||||
\li \l{Model Particle}
|
\li \l{Model Particle}
|
||||||
\li \l{Model Blend Particle}
|
\li \l{Model Blend Particle}
|
||||||
\endlist
|
\endlist
|
||||||
@@ -509,6 +531,48 @@
|
|||||||
\uicontrol {Frame index} is rendered. When it is enabled, each particle
|
\uicontrol {Frame index} is rendered. When it is enabled, each particle
|
||||||
renders a random frame.
|
renders a random frame.
|
||||||
|
|
||||||
|
\section1 Line Particle
|
||||||
|
|
||||||
|
Specify properties for line particles in \uicontrol Properties >
|
||||||
|
\uicontrol {Line Particle}.
|
||||||
|
|
||||||
|
\image studio-3d-properties-line-particle.png
|
||||||
|
|
||||||
|
\uicontrol {Segments} defines the number of segments in each line.
|
||||||
|
|
||||||
|
\uicontrol {Alpha Fade} defines the alpha fade factor of the lines. The
|
||||||
|
value range is [0, 1]. When the value is greater than 0.0, the line fades
|
||||||
|
more the further the segment is from the first particle segment.
|
||||||
|
|
||||||
|
\uicontrol {Scale Multiplier} modifies the line size for the line segments.
|
||||||
|
The value range is [0, 2]. If the value is less than 1.0,
|
||||||
|
the line gets smaller the further a segment is from the first segment and
|
||||||
|
if the value is greater than 1.0 the line gets bigger.
|
||||||
|
|
||||||
|
\uicontrol {Texcoord Multipier} defines the texture coordinate multiplier of
|
||||||
|
the line. This value is factored to the texture coordinate values of the
|
||||||
|
line.
|
||||||
|
|
||||||
|
\uicontrol {Texcoord Mode} defines the texture coordinate mode of the line.
|
||||||
|
|
||||||
|
\uicontrol {Line Length} defines the length of the line. If the value is
|
||||||
|
set, the line length is limited to the value. In this case the minimum
|
||||||
|
delta of the line is the length divided by the segment count. If the value
|
||||||
|
is not set, the line length varies based on the particle speed, segment
|
||||||
|
count, and minimum delta.
|
||||||
|
|
||||||
|
\uicontrol {Line Length Variation} defines the length variation of the line.
|
||||||
|
This parameter is not used if \uicontrol {Line Length} has not been set.
|
||||||
|
When the length is set, this parameter can be used to vary the length of
|
||||||
|
each line.
|
||||||
|
|
||||||
|
\uicontrol {Minimum Segment Length} defines he minimum length between
|
||||||
|
segment points. This parameter is ignored if \uicontrol {Line Length} is set.
|
||||||
|
|
||||||
|
\uicontrol {Eol Fade Out Duration} defines the end-of-life fade-out duration
|
||||||
|
of the line. If set, each line remains in the place it was when the particle
|
||||||
|
reached the end of its lifetime, then fades out during this time period.
|
||||||
|
|
||||||
\section1 Model Particle
|
\section1 Model Particle
|
||||||
|
|
||||||
Specify properties for model particles in \uicontrol Properties >
|
Specify properties for model particles in \uicontrol Properties >
|
||||||
@@ -678,6 +742,7 @@
|
|||||||
\li \l Emitter
|
\li \l Emitter
|
||||||
\li \l {Trail Emitter}
|
\li \l {Trail Emitter}
|
||||||
\li \l {Emit Burst}
|
\li \l {Emit Burst}
|
||||||
|
\li \l {Dynamic Burst}
|
||||||
\li \l {Model Shape}
|
\li \l {Model Shape}
|
||||||
\li \l {Particle Shape}
|
\li \l {Particle Shape}
|
||||||
\endlist
|
\endlist
|
||||||
@@ -775,6 +840,30 @@
|
|||||||
instance, set \uicontrol Time to 2000, \uicontrol Amount to 50, and
|
instance, set \uicontrol Time to 2000, \uicontrol Amount to 50, and
|
||||||
\uicontrol Duration to 200.
|
\uicontrol Duration to 200.
|
||||||
|
|
||||||
|
\section1 Dynamic Burst
|
||||||
|
|
||||||
|
Specify properties for emit bursts in \uicontrol Properties >
|
||||||
|
\uicontrol {Dynamic Burst}.
|
||||||
|
|
||||||
|
\image studio-3d-properties-particle-dynamic-burst.png
|
||||||
|
|
||||||
|
\uicontrol {Trigger Mode} defines when the burst is triggered:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li Select \uicontrol TriggerTime to emit the burst when the burst time
|
||||||
|
is due.
|
||||||
|
\li Select \uicontrol TriggerStart to emit the burst when the followed
|
||||||
|
particle is emitted.
|
||||||
|
\note This mode only works with trail emitters.
|
||||||
|
\note In this mode, \uicontrol Time and \uicontrol Duration don't have an
|
||||||
|
effect.
|
||||||
|
\li Select \uicontrol TriggerEnd to emit the burst when the followed
|
||||||
|
particle life span ends.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\uicontrol {Amount Variation} defines the random variation in the number of
|
||||||
|
emitted particles.
|
||||||
|
|
||||||
\section1 Particle Shape
|
\section1 Particle Shape
|
||||||
|
|
||||||
The \uicontrol {Particle Shape} component supports shapes, such as cube,
|
The \uicontrol {Particle Shape} component supports shapes, such as cube,
|
||||||
@@ -830,6 +919,9 @@
|
|||||||
\li \l Gravity accelerates particles to a vector of the specified
|
\li \l Gravity accelerates particles to a vector of the specified
|
||||||
magnitude in the specified direction.
|
magnitude in the specified direction.
|
||||||
\li \l {Point Rotator} rotates particles around a pivot point.
|
\li \l {Point Rotator} rotates particles around a pivot point.
|
||||||
|
\li \l Repeller repels particles from its location.
|
||||||
|
\li \l {Scale Affector} scales particles based on its lifetime and other
|
||||||
|
parameters.
|
||||||
\li \l Wander applies random wave curves to particles.
|
\li \l Wander applies random wave curves to particles.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
@@ -909,20 +1001,57 @@
|
|||||||
|
|
||||||
\section1 Point Rotator
|
\section1 Point Rotator
|
||||||
|
|
||||||
Specify settings for \uicontrol {Point Rotator} component instances in
|
|
||||||
\uicontrol Properties > \uicontrol {Point Rotator}.
|
|
||||||
|
|
||||||
\image studio-3d-properties-particle-point-rotator.png "Particle Point Rotator properties"
|
|
||||||
|
|
||||||
The \uicontrol {Point Rotator} component rotates particles around the
|
The \uicontrol {Point Rotator} component rotates particles around the
|
||||||
pivot point specified in \uicontrol {Pivot point} towards the direction
|
pivot point specified in \uicontrol {Pivot point} towards the direction
|
||||||
specified in \uicontrol Direction. Direction \uicontrol X, \uicontrol Y, and
|
specified in \uicontrol Direction. Direction \uicontrol X, \uicontrol Y, and
|
||||||
\uicontrol Z values are automatically normalized to a unit vector.
|
\uicontrol Z values are automatically normalized to a unit vector.
|
||||||
|
|
||||||
|
Specify settings for \uicontrol {Point Rotator} component instances in
|
||||||
|
\uicontrol Properties > \uicontrol {Point Rotator}.
|
||||||
|
|
||||||
|
\image studio-3d-properties-particle-point-rotator.png "Particle Point Rotator properties"
|
||||||
|
|
||||||
\uicontrol Magnitude defines the magnitude in particle position change in
|
\uicontrol Magnitude defines the magnitude in particle position change in
|
||||||
degrees per second. A negative value accelerates in the opposite way from
|
degrees per second. A negative value accelerates in the opposite way from
|
||||||
the direction specified in \uicontrol Direction.
|
the direction specified in \uicontrol Direction.
|
||||||
|
|
||||||
|
\section1 Repeller
|
||||||
|
|
||||||
|
The \uicontrol Repeller component repels particles from its location.
|
||||||
|
|
||||||
|
Specify settings for \uicontrol Repeller component instances in
|
||||||
|
\uicontrol Properties > \uicontrol {Particle Repeller}.
|
||||||
|
|
||||||
|
\image studio-3d-properties-particle-repeller.png
|
||||||
|
|
||||||
|
\uicontrol {Outer Radius} defines the outer radius of the repeller. The
|
||||||
|
particle is not affected until it enters this radius and the repel
|
||||||
|
strength grows smoothly until the particle reaches \uicontrol Radius.
|
||||||
|
|
||||||
|
\uicontrol Radius defines the inner radius of the repeller. Particles
|
||||||
|
located inside \uicontrol Radius are repelled at full strength.
|
||||||
|
|
||||||
|
\uicontrol Strength defines the strength of the repeller.
|
||||||
|
|
||||||
|
\section1 Scale Affector
|
||||||
|
|
||||||
|
\uicontrol {Scale Affector} scales particles based on their lifetime and
|
||||||
|
other parameters.
|
||||||
|
|
||||||
|
\image studio-3d-properties-particle-scale-affector.png
|
||||||
|
|
||||||
|
\uicontrol {Minimum Size} defines the minimum size that the affector can
|
||||||
|
scale particles to.
|
||||||
|
|
||||||
|
\uicontrol {Maximum Size} defines the maximum size that the affector can
|
||||||
|
scale particles to.
|
||||||
|
|
||||||
|
\uicontrol Duration defines the the duration of the scaling cycle in
|
||||||
|
milliseconds.
|
||||||
|
|
||||||
|
\uicontrol {Easing Curve} defines the
|
||||||
|
\l{Editing Easing Curves}{easing curve} for the scaling animation.
|
||||||
|
|
||||||
\section1 Wander
|
\section1 Wander
|
||||||
|
|
||||||
The \uicontrol Wander component applies random wave curves to particles.
|
The \uicontrol Wander component applies random wave curves to particles.
|
||||||
|
@@ -92,7 +92,7 @@
|
|||||||
\image studio-logic-helper-not.png "NOT operator properties"
|
\image studio-logic-helper-not.png "NOT operator properties"
|
||||||
|
|
||||||
We then select the other check box instance and bind the value of its
|
We then select the other check box instance and bind the value of its
|
||||||
\uicontrol Checked field to the value of of \uicontrol Output
|
\uicontrol Checked field to the value of \uicontrol Output
|
||||||
field of the \uicontrol {Not Operator} component.
|
field of the \uicontrol {Not Operator} component.
|
||||||
|
|
||||||
\image studio-logic-helper-not-check-box.png "Check box checked property bound to NOT operator output"
|
\image studio-logic-helper-not-check-box.png "Check box checked property bound to NOT operator output"
|
||||||
|
@@ -51,6 +51,12 @@
|
|||||||
\li Provides an editor for files you created using 3D graphics
|
\li Provides an editor for files you created using 3D graphics
|
||||||
applications and stored in one of the supported formats.
|
applications and stored in one of the supported formats.
|
||||||
\li \l {3D}
|
\li \l {3D}
|
||||||
|
\row
|
||||||
|
\li \l {Material Editor and Browser}
|
||||||
|
\li In the \uicontrol {Material Editor} and
|
||||||
|
\uicontrol {Material Browser} views, you create and manage materials and
|
||||||
|
textures.
|
||||||
|
\li \l {Material Editor and Browser}
|
||||||
\row
|
\row
|
||||||
\li \l Components
|
\li \l Components
|
||||||
\li Contains preset components and your own components, that you can use
|
\li Contains preset components and your own components, that you can use
|
||||||
@@ -121,6 +127,16 @@
|
|||||||
\li \l{Open Documents}
|
\li \l{Open Documents}
|
||||||
\li Shows currently open files.
|
\li Shows currently open files.
|
||||||
\li \l{Open Documents}
|
\li \l{Open Documents}
|
||||||
|
\row
|
||||||
|
\li \l{Content Library}
|
||||||
|
\li The \uicontrol {Content Library} view contains material, texture,
|
||||||
|
and environment bundles with assets that you can use in your project.
|
||||||
|
\li \l{Content Library}
|
||||||
|
\row
|
||||||
|
\li \l{Texture Editor}
|
||||||
|
\li In the \uicontrol {Texture Editor} view, you create and manage
|
||||||
|
textures.
|
||||||
|
\li \l{Texture Editor}
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
\section1 Summary of Main Toolbar Actions
|
\section1 Summary of Main Toolbar Actions
|
||||||
|
66
doc/qtdesignstudio/src/views/studio-content-library.qdoc
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\page studio-content-library.html
|
||||||
|
\previouspage creator-open-documents-view.html
|
||||||
|
\nextpage studio-texture-editor.html
|
||||||
|
|
||||||
|
\title Content Library
|
||||||
|
|
||||||
|
\note The \uicontrol {Content Library} view is included in the
|
||||||
|
\l{https://www.qt.io/pricing}{Qt Design Studio Enterprise license}.
|
||||||
|
|
||||||
|
The \uicontrol{Content Library} view contains material, texture, and
|
||||||
|
environment bundles with assets that you can use in your project. When you
|
||||||
|
have added an asset from \uicontrol {Content Library}, you can use it in
|
||||||
|
your project.
|
||||||
|
|
||||||
|
\image content-library.webp
|
||||||
|
|
||||||
|
\section1 Adding a Material to Your Project
|
||||||
|
|
||||||
|
You can use materials on 3D models.
|
||||||
|
|
||||||
|
To add a material from the \uicontrol {Content Library} view to your
|
||||||
|
project, do one of the following:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li Select the \inlineimage icons/plus.png
|
||||||
|
next to the material in the \uicontrol {Content Library} view.
|
||||||
|
\li Right-click the material in the \uicontrol {Content Library} view and
|
||||||
|
select \uicontrol{Add an instance to the project}.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
You can also add a material to a 3D model straight from the \uicontrol {Content Library} view.
|
||||||
|
This also adds the material to the project.
|
||||||
|
|
||||||
|
To add a material to a 3D model, do one of the following:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li Drag the material from the \uicontrol {Content Library} view to a 3D
|
||||||
|
model in the \uicontrol 3D or \uicontrol Navigator view.
|
||||||
|
\li With a 3D model selected, right-click the material in the
|
||||||
|
\uicontrol {Content Library} view and select \uicontrol{Apply to selected}.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\section1 Adding a Texture or Environment to Your Project
|
||||||
|
|
||||||
|
To add a texture or environment to your project, right-click the image
|
||||||
|
in the \uicontrol {Content Library} view and select one of the options:
|
||||||
|
\list
|
||||||
|
\li \uicontrol {Add image}. This adds the image as an asset to your project. You can
|
||||||
|
access the image from the \uicontrol Assets view.
|
||||||
|
\li \uicontrol {Add texture}. This adds the image as a texture to your project. You can
|
||||||
|
access the texture from the \uicontrol Textures section in the \uicontrol{Material Browser}
|
||||||
|
view.
|
||||||
|
\li \uicontrol {Add light probe}. This adds the image as a light probe for your scene, using
|
||||||
|
the image to illuminate the scene and as a skybox. When you set an image as light probe, the
|
||||||
|
following properties are set for \uicontrol {Scene Environment}:
|
||||||
|
\list
|
||||||
|
\li \uicontrol Background Mode is set to skybox.
|
||||||
|
\li \uicontrol {Light Probe} > \uicontrol Image is set to the selected texture.
|
||||||
|
\endlist
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
*/
|
@@ -10,11 +10,13 @@
|
|||||||
\title Material Editor and Browser
|
\title Material Editor and Browser
|
||||||
|
|
||||||
In the \uicontrol {Material Editor} and \uicontrol {Material Browser} views,
|
In the \uicontrol {Material Editor} and \uicontrol {Material Browser} views,
|
||||||
you create and manage materials.
|
you create and manage materials and textures.
|
||||||
|
|
||||||
\image material-editor-browser.webp "Material Editor and Browser"
|
\image material-editor-browser.webp "Material Editor and Browser"
|
||||||
|
|
||||||
\section1 Creating a Material
|
\section1 Working with Materials
|
||||||
|
|
||||||
|
\section2 Creating a Material
|
||||||
|
|
||||||
To create a new material, do one of the following:
|
To create a new material, do one of the following:
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@
|
|||||||
.
|
.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 Editing a Material
|
\section2 Editing a Material
|
||||||
|
|
||||||
To edit a material, select it in \uicontrol{Material Browser} and edit its
|
To edit a material, select it in \uicontrol{Material Browser} and edit its
|
||||||
properties in \uicontrol{Material Editor}. If \uicontrol {Material Editor}
|
properties in \uicontrol{Material Editor}. If \uicontrol {Material Editor}
|
||||||
@@ -37,7 +39,7 @@
|
|||||||
\li In \uicontrol{Material Browser}, double-click a material.
|
\li In \uicontrol{Material Browser}, double-click a material.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 Assigning a Material to an Object
|
\section2 Assigning a Material to an Object
|
||||||
|
|
||||||
To assign a material to a 3D object in your project, drag the material from
|
To assign a material to a 3D object in your project, drag the material from
|
||||||
\uicontrol {Material Browser} to the object in the \uicontrol Navigator or
|
\uicontrol {Material Browser} to the object in the \uicontrol Navigator or
|
||||||
@@ -57,7 +59,7 @@
|
|||||||
. This replaces any material already assigned to the object.
|
. This replaces any material already assigned to the object.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 Removing a Material from an Object
|
\section2 Removing a Material from an Object
|
||||||
|
|
||||||
To remove an assigned material from an object:
|
To remove an assigned material from an object:
|
||||||
\list 1
|
\list 1
|
||||||
@@ -68,7 +70,7 @@
|
|||||||
\image materials-remove-material.png
|
\image materials-remove-material.png
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 Copying and Pasting Material Properties
|
\section2 Copying and Pasting Material Properties
|
||||||
|
|
||||||
You can copy properties from one material to another. You can choose if you
|
You can copy properties from one material to another. You can choose if you
|
||||||
want to copy all properties or certain property groups.
|
want to copy all properties or certain property groups.
|
||||||
@@ -88,7 +90,7 @@
|
|||||||
\note You can't copy material properties between materials of different
|
\note You can't copy material properties between materials of different
|
||||||
material types.
|
material types.
|
||||||
|
|
||||||
\section1 Using Texture Maps
|
\section2 Using Texture Maps
|
||||||
|
|
||||||
In \QDS you can add many different texture maps to your material.
|
In \QDS you can add many different texture maps to your material.
|
||||||
|
|
||||||
@@ -100,7 +102,7 @@
|
|||||||
the image to \uicontrol{Diffuse Map} in \uicontrol{Material Editor}.
|
the image to \uicontrol{Diffuse Map} in \uicontrol{Material Editor}.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section2 Using a Reflection Map for Environmental Mapping
|
\section3 Using a Reflection Map for Environmental Mapping
|
||||||
|
|
||||||
To use a texture for environmental mapping, you need to set the mapping
|
To use a texture for environmental mapping, you need to set the mapping
|
||||||
mode to \e {environment}.
|
mode to \e {environment}.
|
||||||
@@ -122,7 +124,7 @@
|
|||||||
\uicontrol {Environment}.
|
\uicontrol {Environment}.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 Blending Colors
|
\section2 Blending Colors
|
||||||
|
|
||||||
To determine how the colors of a model blend with the colors of the models
|
To determine how the colors of a model blend with the colors of the models
|
||||||
behind it, set the \uicontrol {Blend mode} property. To make opaque objects
|
behind it, set the \uicontrol {Blend mode} property. To make opaque objects
|
||||||
@@ -144,7 +146,7 @@
|
|||||||
For a result with higher contrast, select \uicontrol Overlay, which is a mix
|
For a result with higher contrast, select \uicontrol Overlay, which is a mix
|
||||||
of the multiply and screen modes.
|
of the multiply and screen modes.
|
||||||
|
|
||||||
\section1 Lighting Materials
|
\section2 Lighting Materials
|
||||||
|
|
||||||
To set the lighting method for generating a material, use the
|
To set the lighting method for generating a material, use the
|
||||||
\uicontrol Lighting property. Select \uicontrol {Fragment lighting} to
|
\uicontrol Lighting property. Select \uicontrol {Fragment lighting} to
|
||||||
@@ -164,7 +166,7 @@
|
|||||||
the opacity of the material independently of the model as the value of the
|
the opacity of the material independently of the model as the value of the
|
||||||
\uicontrol Opacity property.
|
\uicontrol Opacity property.
|
||||||
|
|
||||||
\section1 Self-Illuminating Materials
|
\section2 Self-Illuminating Materials
|
||||||
|
|
||||||
To set the color and amount of self-illumination for a material, use the
|
To set the color and amount of self-illumination for a material, use the
|
||||||
\uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In
|
\uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In
|
||||||
@@ -177,7 +179,7 @@
|
|||||||
image does not affect the color of the result, while using a color image
|
image does not affect the color of the result, while using a color image
|
||||||
produces glowing regions with the color affected by the emissive map.
|
produces glowing regions with the color affected by the emissive map.
|
||||||
|
|
||||||
\section1 Using Highlights and Reflections
|
\section2 Using Highlights and Reflections
|
||||||
|
|
||||||
You can control the highlights and reflections on a material by setting the
|
You can control the highlights and reflections on a material by setting the
|
||||||
properties in the \uicontrol Specular group. You can use the color picker
|
properties in the \uicontrol Specular group. You can use the color picker
|
||||||
@@ -221,7 +223,7 @@
|
|||||||
highlights and blurring reflections. To control the specular roughness of
|
highlights and blurring reflections. To control the specular roughness of
|
||||||
the material using a Texture, set the \uicontrol {Roughness map property}.
|
the material using a Texture, set the \uicontrol {Roughness map property}.
|
||||||
|
|
||||||
\section1 Simulating Geometry Displacement
|
\section2 Simulating Geometry Displacement
|
||||||
|
|
||||||
Specify the properties in the \uicontrol {Bump/Normal} group to simulate
|
Specify the properties in the \uicontrol {Bump/Normal} group to simulate
|
||||||
fine geometry displacement across the surface of the material. Set the
|
fine geometry displacement across the surface of the material. Set the
|
||||||
@@ -240,7 +242,7 @@
|
|||||||
of the material. The \uicontrol {Displacement amount} property specifies the
|
of the material. The \uicontrol {Displacement amount} property specifies the
|
||||||
offset amount.
|
offset amount.
|
||||||
|
|
||||||
\section1 Specifying Material Translucency
|
\section2 Specifying Material Translucency
|
||||||
|
|
||||||
Set the properties in the \uicontrol Translucency group to control how much
|
Set the properties in the \uicontrol Translucency group to control how much
|
||||||
light can pass through the material from behind. To use a grayscale texture,
|
light can pass through the material from behind. To use a grayscale texture,
|
||||||
@@ -254,7 +256,7 @@
|
|||||||
the angle of the normals of the object to the light source, set
|
the angle of the normals of the object to the light source, set
|
||||||
the \uicontrol {Translucency falloff} property.
|
the \uicontrol {Translucency falloff} property.
|
||||||
|
|
||||||
\section1 Culling Faces
|
\section2 Culling Faces
|
||||||
|
|
||||||
Set the \uicontrol {Culling mode} property to determine whether the front
|
Set the \uicontrol {Culling mode} property to determine whether the front
|
||||||
and back faces of a model are rendered. Culling modes check whether the
|
and back faces of a model are rendered. Culling modes check whether the
|
||||||
@@ -265,4 +267,32 @@
|
|||||||
is not rendered. Culling makes rendering objects quicker and more efficient
|
is not rendered. Culling makes rendering objects quicker and more efficient
|
||||||
by reducing the number of polygons to draw.
|
by reducing the number of polygons to draw.
|
||||||
|
|
||||||
|
\section1 Working with Textures
|
||||||
|
|
||||||
|
\target creating texture material browser
|
||||||
|
|
||||||
|
\section2 Creating a Texture
|
||||||
|
|
||||||
|
To create a new texture, do one of the following in
|
||||||
|
\uicontrol {Material Browser}:
|
||||||
|
\list
|
||||||
|
\li Select \inlineimage icons/plus.png
|
||||||
|
in the \uicontrol Textures section.
|
||||||
|
\li Right-click anywhere in the \uicontrol Textures section and select
|
||||||
|
\uicontrol {Create new texture}.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\note You can also create textures from the \l {Assets} or
|
||||||
|
\l {Texture Editor} views.
|
||||||
|
|
||||||
|
\section2 Applying a Texture to a Material
|
||||||
|
|
||||||
|
To apply a texture to a material, select the material in
|
||||||
|
\uicontrol {Material Browser} and do one of the following:
|
||||||
|
\list
|
||||||
|
\li Right-click the texture and select
|
||||||
|
\uicontrol {Apply to selected material}.
|
||||||
|
\li Drag the texture to a supported property in the
|
||||||
|
\uicontrol {Material Editor}
|
||||||
|
\endlist
|
||||||
*/
|
*/
|
||||||
|
47
doc/qtdesignstudio/src/views/studio-texture-editor.qdoc
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\page studio-texture-editor.html
|
||||||
|
\previouspage studio-content-library.html
|
||||||
|
\nextpage creator-project-managing-workspaces.html
|
||||||
|
|
||||||
|
\title Texture Editor
|
||||||
|
|
||||||
|
In the \uicontrol {Texture Editor} view, you create and manage textures.
|
||||||
|
|
||||||
|
\image texture-editor.png
|
||||||
|
|
||||||
|
\section1 Creating a Texture
|
||||||
|
|
||||||
|
To create a texture, select \inlineimage icons/plus.png
|
||||||
|
in the \uicontrol {Texture Editor} view.
|
||||||
|
|
||||||
|
\note You can also create textures from the
|
||||||
|
\l{creating texture material browser}{Material Browser view}.
|
||||||
|
|
||||||
|
When you create a texture, it is empty. To add an image to the texture,
|
||||||
|
do one of the following:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li In the \uicontrol{Texture Editor} view, set the image in the
|
||||||
|
\uicontrol Source property.
|
||||||
|
\li From the \uicontrol Assets view, drag an image to the
|
||||||
|
\uicontrol Source property in the \uicontrol {Texture Editor} view.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\section1 Applying a Texture to a Material
|
||||||
|
|
||||||
|
To apply a texture to a material, first select the material in the
|
||||||
|
\uicontrol {Material Browser} view and then:
|
||||||
|
\list 1
|
||||||
|
\li Select \inlineimage icons/apply-material.png
|
||||||
|
.
|
||||||
|
\li Select the material and property that you want to add the texture to.
|
||||||
|
\image select-material-property.png
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\note You can also apply textures to materials in the
|
||||||
|
\l {Material Editor and Browser}{Material Browser view}.
|
||||||
|
|
||||||
|
*/
|
@@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
\page creator-project-managing-workspaces.html
|
\page creator-project-managing-workspaces.html
|
||||||
|
\if defined(qtdesignstudio)
|
||||||
|
\previouspage studio-texture-editor.html
|
||||||
|
\else
|
||||||
\previouspage creator-open-documents-view.html
|
\previouspage creator-open-documents-view.html
|
||||||
|
\endif
|
||||||
\nextpage creator-project-managing-sessions.html
|
\nextpage creator-project-managing-sessions.html
|
||||||
|
|
||||||
\title Managing Workspaces
|
\title Managing Workspaces
|
||||||
|
@@ -14,3 +14,4 @@ IDE_DOC_FILES_ONLINE = $$PWD/doc/qtcreator/qtcreator-online.qdocconf \
|
|||||||
$$PWD/doc/qtcreatordev/qtcreator-dev-online.qdocconf
|
$$PWD/doc/qtcreatordev/qtcreator-dev-online.qdocconf
|
||||||
IDE_DOC_FILES = $$PWD/doc/qtcreator/qtcreator.qdocconf \
|
IDE_DOC_FILES = $$PWD/doc/qtcreator/qtcreator.qdocconf \
|
||||||
$$PWD/doc/qtcreatordev/qtcreator-dev.qdocconf
|
$$PWD/doc/qtcreatordev/qtcreator-dev.qdocconf
|
||||||
|
|
||||||
|
@@ -126,11 +126,15 @@ if [ ! -d "$app_path/Contents/Frameworks/QtCore.framework" ]; then
|
|||||||
if [ -f "$qml2puppetapp" ]; then
|
if [ -f "$qml2puppetapp" ]; then
|
||||||
qml2puppetArgument="-executable=$qml2puppetapp"
|
qml2puppetArgument="-executable=$qml2puppetapp"
|
||||||
fi
|
fi
|
||||||
|
sdktoolapp="$libexec_path/sdktool"
|
||||||
|
if [ -f "$sdktoolapp" ]; then
|
||||||
|
sdktoolArgument="-executable=$sdktoolapp"
|
||||||
|
fi
|
||||||
|
|
||||||
"$bin_src/macdeployqt" "$app_path" \
|
"$bin_src/macdeployqt" "$app_path" \
|
||||||
"-executable=$app_path/Contents/MacOS/qtdiag" \
|
"-executable=$app_path/Contents/MacOS/qtdiag" \
|
||||||
"-executable=$libexec_path/qtpromaker" \
|
"-executable=$libexec_path/qtpromaker" \
|
||||||
"-executable=$libexec_path/sdktool" \
|
"$sdktoolArgument" \
|
||||||
"-executable=$libexec_path/ios/iostool" \
|
"-executable=$libexec_path/ios/iostool" \
|
||||||
"-executable=$libexec_path/buildoutputparser" \
|
"-executable=$libexec_path/buildoutputparser" \
|
||||||
"-executable=$libexec_path/cpaster" \
|
"-executable=$libexec_path/cpaster" \
|
||||||
|
@@ -35,45 +35,32 @@ Item {
|
|||||||
id: searchBox
|
id: searchBox
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
enabled: !materialsModel.hasMaterialRoot && materialsModel.hasQuick3DImport
|
enabled: {
|
||||||
|
if (tabBar.currIndex == 0) { // Materials tab
|
||||||
|
materialsModel.matBundleExists
|
||||||
|
&& rootView.hasMaterialLibrary
|
||||||
|
&& materialsModel.hasRequiredQuick3DImport
|
||||||
|
} else { // Textures / Environments tabs
|
||||||
|
texturesModel.texBundleExists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onSearchChanged: (searchText) => {
|
onSearchChanged: (searchText) => {
|
||||||
rootView.handleSearchFilterChanged(searchText)
|
rootView.handleSearchFilterChanged(searchText)
|
||||||
|
|
||||||
// make sure categories with matches are expanded
|
// make sure categories with matches are expanded
|
||||||
materialsView.expandVisibleSections()
|
materialsView.expandVisibleSections()
|
||||||
|
texturesView.expandVisibleSections()
|
||||||
|
environmentsView.expandVisibleSections()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
|
||||||
// TODO: only disable the materials section, textures should be available
|
|
||||||
text: {
|
|
||||||
if (materialsModel.hasMaterialRoot)
|
|
||||||
qsTr("<b>Content Library</b> is disabled inside a material component.")
|
|
||||||
else if (!materialsModel.hasQuick3DImport)
|
|
||||||
qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
|
||||||
else
|
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
||||||
textFormat: Text.RichText
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
font.pixelSize: StudioTheme.Values.mediumFontSize
|
|
||||||
topPadding: 30
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
width: root.width
|
|
||||||
visible: text !== ""
|
|
||||||
}
|
|
||||||
|
|
||||||
UnimportBundleMaterialDialog {
|
UnimportBundleMaterialDialog {
|
||||||
id: confirmUnimportDialog
|
id: confirmUnimportDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentLibraryTabBar {
|
ContentLibraryTabBar {
|
||||||
id: tabBar
|
id: tabBar
|
||||||
|
|
||||||
visible: materialsModel.hasQuick3DImport
|
|
||||||
// TODO: update icons
|
// TODO: update icons
|
||||||
tabsModel: [{name: qsTr("Materials"), icon: StudioTheme.Constants.gradient},
|
tabsModel: [{name: qsTr("Materials"), icon: StudioTheme.Constants.gradient},
|
||||||
{name: qsTr("Textures"), icon: StudioTheme.Constants.materialPreviewEnvironment},
|
{name: qsTr("Textures"), icon: StudioTheme.Constants.materialPreviewEnvironment},
|
||||||
@@ -84,7 +71,6 @@ Item {
|
|||||||
width: root.width
|
width: root.width
|
||||||
height: root.height - y
|
height: root.height - y
|
||||||
currentIndex: tabBar.currIndex
|
currentIndex: tabBar.currIndex
|
||||||
visible: materialsModel.hasQuick3DImport
|
|
||||||
|
|
||||||
ContentLibraryMaterialsView {
|
ContentLibraryMaterialsView {
|
||||||
id: materialsView
|
id: materialsView
|
||||||
@@ -94,8 +80,8 @@ Item {
|
|||||||
searchBox: searchBox
|
searchBox: searchBox
|
||||||
|
|
||||||
onUnimport: (bundleMat) => {
|
onUnimport: (bundleMat) => {
|
||||||
unimportBundleMaterialDialog.targetBundleMaterial = bundleMat
|
confirmUnimportDialog.targetBundleMaterial = bundleMat
|
||||||
unimportBundleMaterialDialog.open()
|
confirmUnimportDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ Item {
|
|||||||
anchors.right: img.right
|
anchors.right: img.right
|
||||||
anchors.bottom: img.bottom
|
anchors.bottom: img.bottom
|
||||||
enabled: !materialsModel.importerRunning
|
enabled: !materialsModel.importerRunning
|
||||||
|
visible: containsMouse || mouseArea.containsMouse
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
materialsModel.addToProject(modelData)
|
materialsModel.addToProject(modelData)
|
||||||
|
@@ -10,7 +10,13 @@ StudioControls.Menu {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var targetMaterial: null
|
property var targetMaterial: null
|
||||||
|
property bool hasModelSelection: false
|
||||||
|
property bool importerRunning: false
|
||||||
|
|
||||||
|
readonly property bool targetAvailable: targetMaterial && !importerRunning
|
||||||
|
|
||||||
signal unimport(var bundleMat);
|
signal unimport(var bundleMat);
|
||||||
|
signal addToProject(var bundleMat)
|
||||||
|
|
||||||
function popupMenu(targetMaterial = null)
|
function popupMenu(targetMaterial = null)
|
||||||
{
|
{
|
||||||
@@ -22,31 +28,31 @@ StudioControls.Menu {
|
|||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Apply to selected (replace)")
|
text: qsTr("Apply to selected (replace)")
|
||||||
enabled: root.targetMaterial && materialsModel.hasModelSelection
|
enabled: root.targetAvailable && root.hasModelSelection
|
||||||
onTriggered: materialsModel.applyToSelected(root.targetMaterial, false)
|
onTriggered: root.applyToSelected(root.targetMaterial, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Apply to selected (add)")
|
text: qsTr("Apply to selected (add)")
|
||||||
enabled: root.targetMaterial && materialsModel.hasModelSelection
|
enabled: root.targetAvailable && root.hasModelSelection
|
||||||
onTriggered: materialsModel.applyToSelected(root.targetMaterial, true)
|
onTriggered: root.applyToSelected(root.targetMaterial, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuSeparator {}
|
StudioControls.MenuSeparator {}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
enabled: !materialsModel.importerRunning
|
enabled: root.targetAvailable
|
||||||
text: qsTr("Add an instance to project")
|
text: qsTr("Add an instance to project")
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
materialsModel.addToProject(root.targetMaterial)
|
root.addToProject(root.targetMaterial)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
enabled: !materialsModel.importerRunning && root.targetMaterial && root.targetMaterial.bundleMaterialImported
|
enabled: root.targetAvailable && root.targetMaterial.bundleMaterialImported
|
||||||
text: qsTr("Remove from project")
|
text: qsTr("Remove from project")
|
||||||
|
|
||||||
onTriggered: root.unimport(root.targetMaterial);
|
onTriggered: root.unimport(root.targetMaterial)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,7 @@ HelperWidgets.ScrollView {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
|
interactive: !ctxMenu.opened
|
||||||
|
|
||||||
readonly property int cellWidth: 100
|
readonly property int cellWidth: 100
|
||||||
readonly property int cellHeight: 120
|
readonly property int cellHeight: 120
|
||||||
@@ -31,7 +32,7 @@ HelperWidgets.ScrollView {
|
|||||||
for (let i = 0; i < categoryRepeater.count; ++i) {
|
for (let i = 0; i < categoryRepeater.count; ++i) {
|
||||||
let cat = categoryRepeater.itemAt(i)
|
let cat = categoryRepeater.itemAt(i)
|
||||||
if (cat.visible && !cat.expanded)
|
if (cat.visible && !cat.expanded)
|
||||||
cat.expanded = true
|
cat.expandSection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +40,11 @@ HelperWidgets.ScrollView {
|
|||||||
ContentLibraryMaterialContextMenu {
|
ContentLibraryMaterialContextMenu {
|
||||||
id: ctxMenu
|
id: ctxMenu
|
||||||
|
|
||||||
|
hasModelSelection: materialsModel.hasModelSelection
|
||||||
|
importerRunning: materialsModel.importerRunning
|
||||||
|
|
||||||
onUnimport: (bundleMat) => root.unimport(bundleMat)
|
onUnimport: (bundleMat) => root.unimport(bundleMat)
|
||||||
|
onAddToProject: (bundleMat) => materialsModel.addToProject(bundleMat)
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
@@ -52,10 +57,16 @@ HelperWidgets.ScrollView {
|
|||||||
caption: bundleCategoryName
|
caption: bundleCategoryName
|
||||||
addTopPadding: false
|
addTopPadding: false
|
||||||
sectionBackgroundColor: "transparent"
|
sectionBackgroundColor: "transparent"
|
||||||
visible: bundleCategoryVisible
|
visible: bundleCategoryVisible && !materialsModel.isEmpty
|
||||||
expanded: bundleCategoryExpanded
|
expanded: bundleCategoryExpanded
|
||||||
expandOnClick: false
|
expandOnClick: false
|
||||||
onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded
|
onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded
|
||||||
|
onExpand: bundleCategoryExpanded = true
|
||||||
|
onCollapse: bundleCategoryExpanded = false
|
||||||
|
|
||||||
|
function expandSection() {
|
||||||
|
bundleCategoryExpanded = true
|
||||||
|
}
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
width: root.width
|
width: root.width
|
||||||
@@ -79,13 +90,26 @@ HelperWidgets.ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: noMatchText
|
id: infoText
|
||||||
text: qsTr("No match found.");
|
text: {
|
||||||
|
if (!materialsModel.matBundleExists)
|
||||||
|
qsTr("<b>Content Library</b> materials are not installed.")
|
||||||
|
else if (!rootView.hasQuick3DImport)
|
||||||
|
qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
||||||
|
else if (!materialsModel.hasRequiredQuick3DImport)
|
||||||
|
qsTr("To use <b>Content Library</b>, version 6.3 or later of the QtQuick3D module is required.")
|
||||||
|
else if (!rootView.hasMaterialLibrary)
|
||||||
|
qsTr("<b>Content Library</b> is disabled inside a non-visual component.")
|
||||||
|
else if (!searchBox.isEmpty())
|
||||||
|
qsTr("No match found.")
|
||||||
|
else
|
||||||
|
""
|
||||||
|
}
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
topPadding: 10
|
topPadding: 10
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
visible: materialsModel.isEmpty && !searchBox.isEmpty() && !materialsModel.hasMaterialRoot
|
visible: materialsModel.isEmpty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,9 +12,12 @@ StudioControls.Menu {
|
|||||||
property var targetTexture: null
|
property var targetTexture: null
|
||||||
property bool hasSceneEnv: false
|
property bool hasSceneEnv: false
|
||||||
|
|
||||||
|
property bool canUse3D: targetTexture && rootView.hasQuick3DImport && rootView.hasMaterialLibrary
|
||||||
|
|
||||||
function popupMenu(targetTexture = null)
|
function popupMenu(targetTexture = null)
|
||||||
{
|
{
|
||||||
this.targetTexture = targetTexture
|
this.targetTexture = targetTexture
|
||||||
|
rootView.updateSceneEnvState();
|
||||||
popup()
|
popup()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,13 +31,13 @@ StudioControls.Menu {
|
|||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Add texture")
|
text: qsTr("Add texture")
|
||||||
enabled: root.targetTexture
|
enabled: canUse3D
|
||||||
onTriggered: rootView.addTexture(root.targetTexture)
|
onTriggered: rootView.addTexture(root.targetTexture)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Add light probe")
|
text: qsTr("Add light probe")
|
||||||
enabled: root.hasSceneEnv && root.targetTexture
|
enabled: root.hasSceneEnv && canUse3D
|
||||||
onTriggered: rootView.addLightProbe(root.targetTexture)
|
onTriggered: rootView.addLightProbe(root.targetTexture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,7 @@ HelperWidgets.ScrollView {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
|
interactive: !ctxMenu.opened
|
||||||
|
|
||||||
readonly property int cellWidth: 100
|
readonly property int cellWidth: 100
|
||||||
readonly property int cellHeight: 100
|
readonly property int cellHeight: 100
|
||||||
@@ -32,7 +33,7 @@ HelperWidgets.ScrollView {
|
|||||||
for (let i = 0; i < categoryRepeater.count; ++i) {
|
for (let i = 0; i < categoryRepeater.count; ++i) {
|
||||||
let cat = categoryRepeater.itemAt(i)
|
let cat = categoryRepeater.itemAt(i)
|
||||||
if (cat.visible && !cat.expanded)
|
if (cat.visible && !cat.expanded)
|
||||||
cat.expanded = true
|
cat.expandSection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Column {
|
Column {
|
||||||
@@ -52,10 +53,16 @@ HelperWidgets.ScrollView {
|
|||||||
caption: bundleCategoryName
|
caption: bundleCategoryName
|
||||||
addTopPadding: false
|
addTopPadding: false
|
||||||
sectionBackgroundColor: "transparent"
|
sectionBackgroundColor: "transparent"
|
||||||
visible: bundleCategoryVisible
|
visible: bundleCategoryVisible && !root.model.isEmpty
|
||||||
expanded: bundleCategoryExpanded
|
expanded: bundleCategoryExpanded
|
||||||
expandOnClick: false
|
expandOnClick: false
|
||||||
onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded
|
onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded
|
||||||
|
onExpand: bundleCategoryExpanded = true
|
||||||
|
onCollapse: bundleCategoryExpanded = false
|
||||||
|
|
||||||
|
function expandSection() {
|
||||||
|
bundleCategoryExpanded = true
|
||||||
|
}
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
width: root.width
|
width: root.width
|
||||||
@@ -80,13 +87,20 @@ HelperWidgets.ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: noMatchText
|
id: infoText
|
||||||
text: qsTr("No match found.");
|
text: {
|
||||||
|
if (!root.model.texBundleExists)
|
||||||
|
qsTr("<b>Content Library</b> textures are not installed.")
|
||||||
|
else if (!searchBox.isEmpty())
|
||||||
|
qsTr("No match found.")
|
||||||
|
else
|
||||||
|
""
|
||||||
|
}
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
topPadding: 10
|
topPadding: 10
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
visible: root.model.isEmpty && !searchBox.isEmpty() && !root.model.hasMaterialRoot
|
visible: root.model.isEmpty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,327 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
TreeViewDelegate {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Item assetsView
|
||||||
|
required property Item assetsRoot
|
||||||
|
|
||||||
|
property bool hasChildWithDropHover: false
|
||||||
|
property bool isHoveringDrop: false
|
||||||
|
readonly property string suffix: model.fileName.substr(-4)
|
||||||
|
readonly property bool isFont: root.suffix === ".ttf" || root.suffix === ".otf"
|
||||||
|
readonly property bool isEffect: root.suffix === ".qep"
|
||||||
|
property bool currFileSelected: false
|
||||||
|
property int initialDepth: -1
|
||||||
|
property bool __isDirectory: assetsModel.isDirectory(model.filePath)
|
||||||
|
property int __currentRow: model.index
|
||||||
|
property string __itemPath: model.filePath
|
||||||
|
|
||||||
|
readonly property int __fileItemHeight: thumbnailImage.height
|
||||||
|
readonly property int __dirItemHeight: 21
|
||||||
|
|
||||||
|
implicitHeight: root.__isDirectory ? root.__dirItemHeight : root.__fileItemHeight
|
||||||
|
implicitWidth: root.assetsView.width > 0 ? root.assetsView.width : 10
|
||||||
|
|
||||||
|
leftMargin: root.__isDirectory ? 0 : thumbnailImage.width
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
// the depth of the root path will become available before we get to the actual
|
||||||
|
// items we display, so it's safe to set assetsView.rootPathDepth here. All other
|
||||||
|
// tree items (below the root) will have the indentation (basically, depth) adjusted.
|
||||||
|
if (model.filePath === assetsModel.rootPath()) {
|
||||||
|
root.assetsView.rootPathDepth = root.depth
|
||||||
|
root.assetsView.rootPathRow = root.__currentRow
|
||||||
|
} else if (model.filePath.includes(assetsModel.rootPath())) {
|
||||||
|
root.depth -= root.assetsView.rootPathDepth
|
||||||
|
root.initialDepth = root.depth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround for a bug -- might be fixed by https://codereview.qt-project.org/c/qt/qtdeclarative/+/442721
|
||||||
|
onYChanged: {
|
||||||
|
if (root.__currentRow === root.assetsView.firstRow) {
|
||||||
|
if (root.y > root.assetsView.contentY) {
|
||||||
|
let item = root.assetsView.itemAtCell(0, root.assetsView.rootPathRow)
|
||||||
|
if (!item)
|
||||||
|
root.assetsView.contentY = root.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onImplicitWidthChanged: {
|
||||||
|
// a small hack, to fix a glitch: when resizing the width of the tree view,
|
||||||
|
// the widths of the delegate items remain the same as before, unless we re-set
|
||||||
|
// that width explicitly.
|
||||||
|
var newWidth = root.implicitWidth - (root.assetsView.verticalScrollBar.scrollBarVisible
|
||||||
|
? root.assetsView.verticalScrollBar.width
|
||||||
|
: 0)
|
||||||
|
bg.width = newWidth
|
||||||
|
bg.implicitWidth = newWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
onDepthChanged: {
|
||||||
|
if (root.depth > root.initialDepth && root.initialDepth >= 0)
|
||||||
|
root.depth = root.initialDepth
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: bg
|
||||||
|
|
||||||
|
color: {
|
||||||
|
if (root.__isDirectory && (root.isHoveringDrop || root.hasChildWithDropHover))
|
||||||
|
return StudioTheme.Values.themeInteraction
|
||||||
|
|
||||||
|
if (!root.__isDirectory && root.assetsView.selectedAssets[root.__itemPath])
|
||||||
|
return StudioTheme.Values.themeInteraction
|
||||||
|
|
||||||
|
if (mouseArea.containsMouse)
|
||||||
|
return StudioTheme.Values.themeSectionHeadBackground
|
||||||
|
|
||||||
|
return root.__isDirectory
|
||||||
|
? StudioTheme.Values.themeSectionHeadBackground
|
||||||
|
: "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
// this rectangle exists so as to have some visual indentation for the directories
|
||||||
|
// We prepend a default pane-colored rectangle so that the nested directory will
|
||||||
|
// look moved a bit to the right
|
||||||
|
Rectangle {
|
||||||
|
anchors.top: bg.top
|
||||||
|
anchors.bottom: bg.bottom
|
||||||
|
anchors.left: bg.left
|
||||||
|
|
||||||
|
width: root.indentation * root.depth
|
||||||
|
implicitWidth: root.indentation * root.depth
|
||||||
|
color: StudioTheme.Values.themePanelBackground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Text {
|
||||||
|
id: assetLabel
|
||||||
|
text: assetLabel.__computeText()
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
font.pixelSize: 14
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
function __computeText()
|
||||||
|
{
|
||||||
|
return root.__isDirectory
|
||||||
|
? (root.hasChildren
|
||||||
|
? model.display.toUpperCase()
|
||||||
|
: model.display.toUpperCase() + qsTr(" (empty)"))
|
||||||
|
: model.display
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropArea {
|
||||||
|
id: treeDropArea
|
||||||
|
|
||||||
|
enabled: true
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onEntered: (drag) => {
|
||||||
|
root.assetsRoot.updateDropExtFiles(drag)
|
||||||
|
root.isHoveringDrop = drag.accepted && root.assetsRoot.dropSimpleExtFiles.length > 0
|
||||||
|
if (root.isHoveringDrop)
|
||||||
|
root.assetsView.startDropHoverOver(root.__currentRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropped: (drag) => {
|
||||||
|
root.isHoveringDrop = false
|
||||||
|
root.assetsView.endDropHover(root.__currentRow)
|
||||||
|
|
||||||
|
let dirPath = root.__isDirectory
|
||||||
|
? model.filePath
|
||||||
|
: assetsModel.parentDirPath(model.filePath);
|
||||||
|
|
||||||
|
rootView.emitExtFilesDrop(root.assetsRoot.dropSimpleExtFiles,
|
||||||
|
root.assetsRoot.dropComplexExtFiles,
|
||||||
|
dirPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: {
|
||||||
|
if (root.isHoveringDrop) {
|
||||||
|
root.isHoveringDrop = false
|
||||||
|
root.assetsView.endDropHover(root.__currentRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
|
||||||
|
property bool allowTooltip: true
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
|
||||||
|
onExited: tooltipBackend.hideTooltip()
|
||||||
|
onEntered: mouseArea.allowTooltip = true
|
||||||
|
|
||||||
|
onCanceled: {
|
||||||
|
tooltipBackend.hideTooltip()
|
||||||
|
mouseArea.allowTooltip = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositionChanged: tooltipBackend.reposition()
|
||||||
|
|
||||||
|
onPressed: (mouse) => {
|
||||||
|
forceActiveFocus()
|
||||||
|
mouseArea.allowTooltip = false
|
||||||
|
tooltipBackend.hideTooltip()
|
||||||
|
|
||||||
|
if (root.__isDirectory)
|
||||||
|
return
|
||||||
|
|
||||||
|
var ctrlDown = mouse.modifiers & Qt.ControlModifier
|
||||||
|
if (mouse.button === Qt.LeftButton) {
|
||||||
|
if (!root.assetsView.isAssetSelected(root.__itemPath) && !ctrlDown)
|
||||||
|
root.assetsView.clearSelectedAssets()
|
||||||
|
root.currFileSelected = ctrlDown ? !root.assetsView.isAssetSelected(root.__itemPath) : true
|
||||||
|
root.assetsView.setAssetSelected(root.__itemPath, root.currFileSelected)
|
||||||
|
|
||||||
|
if (root.currFileSelected) {
|
||||||
|
let selectedPaths = root.assetsView.selectedPathsAsList()
|
||||||
|
rootView.startDragAsset(selectedPaths, mapToGlobal(mouse.x, mouse.y))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!root.assetsView.isAssetSelected(root.__itemPath) && !ctrlDown)
|
||||||
|
root.assetsView.clearSelectedAssets()
|
||||||
|
root.currFileSelected = root.assetsView.isAssetSelected(root.__itemPath) || !ctrlDown
|
||||||
|
root.assetsView.setAssetSelected(root.__itemPath, root.currFileSelected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onReleased: (mouse) => {
|
||||||
|
mouseArea.allowTooltip = true
|
||||||
|
|
||||||
|
if (mouse.button === Qt.LeftButton) {
|
||||||
|
if (!(mouse.modifiers & Qt.ControlModifier))
|
||||||
|
root.assetsView.selectedAssets = {}
|
||||||
|
root.assetsView.selectedAssets[root.__itemPath] = root.currFileSelected
|
||||||
|
root.assetsView.selectedAssetsChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDoubleClicked: (mouse) => {
|
||||||
|
forceActiveFocus()
|
||||||
|
allowTooltip = false
|
||||||
|
tooltipBackend.hideTooltip()
|
||||||
|
if (mouse.button === Qt.LeftButton && isEffect)
|
||||||
|
rootView.openEffectMaker(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
visible: !root.isFont && mouseArea.containsMouse && !root.assetsView.contextMenu.visible
|
||||||
|
text: model.filePath
|
||||||
|
delay: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
running: mouseArea.containsMouse && mouseArea.allowTooltip
|
||||||
|
onTriggered: {
|
||||||
|
if (suffix === ".ttf" || suffix === ".otf") {
|
||||||
|
tooltipBackend.name = model.fileName
|
||||||
|
tooltipBackend.path = model.filePath
|
||||||
|
tooltipBackend.showTooltip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // Timer
|
||||||
|
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
if (mouse.button === Qt.LeftButton)
|
||||||
|
root.__toggleExpandCurrentRow()
|
||||||
|
else
|
||||||
|
root.__openContextMenuForCurrentRow()
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // MouseArea
|
||||||
|
|
||||||
|
function __openContextMenuForCurrentRow()
|
||||||
|
{
|
||||||
|
let modelIndex = assetsModel.indexForPath(model.filePath)
|
||||||
|
|
||||||
|
function onFolderCreated(path) {
|
||||||
|
root.assetsView.addCreatedFolder(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.__isDirectory) {
|
||||||
|
var row = root.assetsView.rowAtIndex(modelIndex)
|
||||||
|
var expanded = root.assetsView.isExpanded(row)
|
||||||
|
|
||||||
|
var allExpandedState = root.assetsView.computeAllExpandedState()
|
||||||
|
|
||||||
|
function onFolderRenamed() {
|
||||||
|
if (expanded)
|
||||||
|
root.assetsView.rowToExpand = row
|
||||||
|
}
|
||||||
|
|
||||||
|
root.assetsView.contextMenu.openContextMenuForDir(modelIndex, model.filePath,
|
||||||
|
model.fileName, allExpandedState, onFolderCreated, onFolderRenamed)
|
||||||
|
} else {
|
||||||
|
let parentDirIndex = assetsModel.parentDirIndex(model.filePath)
|
||||||
|
let selectedPaths = root.assetsView.selectedPathsAsList()
|
||||||
|
root.assetsView.contextMenu.openContextMenuForFile(modelIndex, parentDirIndex,
|
||||||
|
selectedPaths, onFolderCreated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __toggleExpandCurrentRow()
|
||||||
|
{
|
||||||
|
if (!root.__isDirectory)
|
||||||
|
return
|
||||||
|
|
||||||
|
let index = root.assetsView.__modelIndex(root.__currentRow)
|
||||||
|
// if the user manually clicked on a directory, then this is definitely not a
|
||||||
|
// an automatic request to expand all.
|
||||||
|
root.assetsView.requestedExpandAll = false
|
||||||
|
|
||||||
|
if (root.assetsView.isExpanded(root.__currentRow)) {
|
||||||
|
root.assetsView.requestedExpandAll = false
|
||||||
|
root.assetsView.collapse(root.__currentRow)
|
||||||
|
} else {
|
||||||
|
root.assetsView.expand(root.__currentRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadImage()
|
||||||
|
{
|
||||||
|
if (root.__isDirectory)
|
||||||
|
return
|
||||||
|
|
||||||
|
thumbnailImage.source = ""
|
||||||
|
thumbnailImage.source = thumbnailImage.__computeSource()
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: thumbnailImage
|
||||||
|
visible: !root.__isDirectory
|
||||||
|
x: root.depth * root.indentation
|
||||||
|
width: 48
|
||||||
|
height: 48
|
||||||
|
cache: false
|
||||||
|
sourceSize.width: 48
|
||||||
|
sourceSize.height: 48
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
source: thumbnailImage.__computeSource()
|
||||||
|
|
||||||
|
function __computeSource()
|
||||||
|
{
|
||||||
|
return root.__isDirectory
|
||||||
|
? ""
|
||||||
|
: "image://qmldesigner_assets/" + model.filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Image
|
||||||
|
} // TreeViewDelegate
|
@@ -1,31 +1,26 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import HelperWidgets as HelperWidgets
|
||||||
import QtQuick.Layouts 1.15
|
import StudioControls as StudioControls
|
||||||
import QtQuickDesignerTheme 1.0
|
import StudioTheme as StudioTheme
|
||||||
import HelperWidgets 2.0
|
|
||||||
import StudioControls 1.0 as StudioControls
|
|
||||||
import StudioTheme 1.0 as StudioTheme
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var selectedAssets: ({})
|
|
||||||
property int allExpandedState: 0
|
|
||||||
property string contextFilePath: ""
|
|
||||||
property var contextDir: undefined
|
|
||||||
property bool isDirContextMenu: false
|
|
||||||
|
|
||||||
// Array of supported externally dropped files that are imported as-is
|
// Array of supported externally dropped files that are imported as-is
|
||||||
property var dropSimpleExtFiles: []
|
property var dropSimpleExtFiles: []
|
||||||
|
|
||||||
// Array of supported externally dropped files that trigger custom import process
|
// Array of supported externally dropped files that trigger custom import process
|
||||||
property var dropComplexExtFiles: []
|
property var dropComplexExtFiles: []
|
||||||
|
|
||||||
|
readonly property int qtVersionAtLeast6_4: rootView.qtVersionIsAtLeast6_4()
|
||||||
|
property bool __searchBoxEmpty: true
|
||||||
|
|
||||||
AssetsContextMenu {
|
AssetsContextMenu {
|
||||||
id: contextMenu
|
id: contextMenu
|
||||||
|
assetsView: assetsView
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearSearchFilter()
|
function clearSearchFilter()
|
||||||
@@ -63,7 +58,7 @@ Item {
|
|||||||
|
|
||||||
onDropped: {
|
onDropped: {
|
||||||
rootView.handleExtFilesDrop(root.dropSimpleExtFiles, root.dropComplexExtFiles,
|
rootView.handleExtFilesDrop(root.dropSimpleExtFiles, root.dropComplexExtFiles,
|
||||||
assetsModel.rootDir().dirPath)
|
assetsModel.rootPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas { // marker for the drop area
|
Canvas { // marker for the drop area
|
||||||
@@ -90,11 +85,15 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!assetsModel.isEmpty) {
|
if (assetsModel.haveFiles) {
|
||||||
root.contextFilePath = ""
|
function onFolderCreated(path) {
|
||||||
root.contextDir = assetsModel.rootDir()
|
assetsView.addCreatedFolder(path)
|
||||||
root.isDirContextMenu = false
|
}
|
||||||
contextMenu.popup()
|
|
||||||
|
var rootIndex = assetsModel.rootIndex()
|
||||||
|
var dirPath = assetsModel.filePath(rootIndex)
|
||||||
|
var dirName = assetsModel.fileName(rootIndex)
|
||||||
|
contextMenu.openContextMenuForRoot(rootIndex, dirPath, dirName, onFolderCreated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,13 +102,8 @@ Item {
|
|||||||
function handleViewFocusOut()
|
function handleViewFocusOut()
|
||||||
{
|
{
|
||||||
contextMenu.close()
|
contextMenu.close()
|
||||||
root.selectedAssets = {}
|
assetsView.selectedAssets = {}
|
||||||
root.selectedAssetsChanged()
|
assetsView.selectedAssetsChanged()
|
||||||
}
|
|
||||||
|
|
||||||
RegExpValidator {
|
|
||||||
id: folderNameValidator
|
|
||||||
regExp: /^(\w[^*/><?\\|:]*)$/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -127,10 +121,29 @@ Item {
|
|||||||
|
|
||||||
width: parent.width - addAssetButton.width - 5
|
width: parent.width - addAssetButton.width - 5
|
||||||
|
|
||||||
onSearchChanged: (searchText) => rootView.handleSearchFilterChanged(searchText)
|
onSearchChanged: (searchText) => {
|
||||||
|
updateSearchFilterTimer.restart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
Timer {
|
||||||
|
id: updateSearchFilterTimer
|
||||||
|
interval: 200
|
||||||
|
repeat: false
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
assetsView.resetVerticalScrollPosition()
|
||||||
|
rootView.handleSearchFilterChanged(searchBox.text)
|
||||||
|
assetsView.expandAll()
|
||||||
|
|
||||||
|
if (root.__searchBoxEmpty && searchBox.text)
|
||||||
|
root.__searchBoxEmpty = false
|
||||||
|
else if (!root.__searchBoxEmpty && !searchBox.text)
|
||||||
|
root.__searchBoxEmpty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.IconButton {
|
||||||
id: addAssetButton
|
id: addAssetButton
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
tooltip: qsTr("Add a new asset to the project.")
|
tooltip: qsTr("Add a new asset to the project.")
|
||||||
@@ -146,14 +159,13 @@ Item {
|
|||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
visible: assetsModel.isEmpty && !searchBox.isEmpty()
|
visible: !assetsModel.haveFiles && !root.__searchBoxEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Item { // placeholder when the assets library is empty
|
Item { // placeholder when the assets library is empty
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - searchRow.height
|
height: parent.height - searchRow.height
|
||||||
visible: assetsModel.isEmpty && searchBox.isEmpty()
|
visible: !assetsModel.haveFiles && root.__searchBoxEmpty
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
DropArea { // handles external drop (goes into default folder based on suffix)
|
DropArea { // handles external drop (goes into default folder based on suffix)
|
||||||
@@ -164,7 +176,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDropped: {
|
onDropped: {
|
||||||
rootView.handleExtFilesDrop(root.dropSimpleExtFiles, root.dropComplexExtFiles)
|
rootView.emitExtFilesDrop(root.dropSimpleExtFiles, root.dropComplexExtFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -217,8 +229,11 @@ Item {
|
|||||||
|
|
||||||
AssetsView {
|
AssetsView {
|
||||||
id: assetsView
|
id: assetsView
|
||||||
|
assetsRoot: root
|
||||||
|
contextMenu: contextMenu
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - y
|
height: parent.height - y
|
||||||
}
|
}
|
||||||
}
|
} // Column
|
||||||
}
|
}
|
||||||
|
@@ -1,90 +1,148 @@
|
|||||||
/****************************************************************************
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
**
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
** 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
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuickDesignerTheme
|
|
||||||
import HelperWidgets as HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
StudioControls.Menu {
|
StudioControls.Menu {
|
||||||
id: contextMenu
|
id: root
|
||||||
|
|
||||||
|
required property Item assetsView
|
||||||
|
|
||||||
|
property bool __isDirectory: false
|
||||||
|
property var __fileIndex: null
|
||||||
|
property string __dirPath: ""
|
||||||
|
property string __dirName: ""
|
||||||
|
property var __onFolderCreated: null
|
||||||
|
property var __onFolderRenamed: null
|
||||||
|
property var __dirIndex: null
|
||||||
|
property string __allExpandedState: ""
|
||||||
|
property var __selectedAssetPathsList: null
|
||||||
|
|
||||||
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
||||||
|
|
||||||
onOpened: {
|
function openContextMenuForRoot(rootModelIndex, dirPath, dirName, onFolderCreated)
|
||||||
var numSelected = Object.values(root.selectedAssets).filter(p => p).length
|
{
|
||||||
deleteFileItem.text = numSelected > 1 ? qsTr("Delete Files") : qsTr("Delete File")
|
root.__onFolderCreated = onFolderCreated
|
||||||
|
root.__fileIndex = ""
|
||||||
|
root.__dirPath = dirPath
|
||||||
|
root.__dirName = dirName
|
||||||
|
root.__dirIndex = rootModelIndex
|
||||||
|
root.__isDirectory = false
|
||||||
|
root.popup()
|
||||||
|
}
|
||||||
|
|
||||||
|
function openContextMenuForDir(dirModelIndex, dirPath, dirName, allExpandedState,
|
||||||
|
onFolderCreated, onFolderRenamed)
|
||||||
|
{
|
||||||
|
root.__onFolderCreated = onFolderCreated
|
||||||
|
root.__onFolderRenamed = onFolderRenamed
|
||||||
|
root.__dirPath = dirPath
|
||||||
|
root.__dirName = dirName
|
||||||
|
root.__fileIndex = ""
|
||||||
|
root.__dirIndex = dirModelIndex
|
||||||
|
root.__isDirectory = true
|
||||||
|
root.__allExpandedState = allExpandedState
|
||||||
|
root.popup()
|
||||||
|
}
|
||||||
|
|
||||||
|
function openContextMenuForFile(fileIndex, dirModelIndex, selectedAssetPathsList, onFolderCreated)
|
||||||
|
{
|
||||||
|
if (selectedAssetPathsList.length > 1) {
|
||||||
|
deleteFileItem.text = qsTr("Delete Files")
|
||||||
|
addTexturesItem.text = qsTr("Add Textures")
|
||||||
|
} else {
|
||||||
|
deleteFileItem.text = qsTr("Delete File")
|
||||||
|
addTexturesItem.text = qsTr("Add Texture")
|
||||||
|
}
|
||||||
|
|
||||||
|
root.__onFolderCreated = onFolderCreated
|
||||||
|
root.__selectedAssetPathsList = selectedAssetPathsList
|
||||||
|
root.__fileIndex = fileIndex
|
||||||
|
root.__dirIndex = dirModelIndex
|
||||||
|
root.__dirPath = assetsModel.filePath(dirModelIndex)
|
||||||
|
root.__isDirectory = false
|
||||||
|
root.popup()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Expand All")
|
text: qsTr("Expand All")
|
||||||
enabled: root.allExpandedState !== 1
|
enabled: root.__allExpandedState !== "all_expanded"
|
||||||
visible: root.isDirContextMenu
|
visible: root.__isDirectory
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: assetsModel.toggleExpandAll(true)
|
onTriggered: root.assetsView.expandAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Collapse All")
|
text: qsTr("Collapse All")
|
||||||
enabled: root.allExpandedState !== 2
|
enabled: root.__allExpandedState !== "all_collapsed"
|
||||||
visible: root.isDirContextMenu
|
visible: root.__isDirectory
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: assetsModel.toggleExpandAll(false)
|
onTriggered: root.assetsView.collapseAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuSeparator {
|
StudioControls.MenuSeparator {
|
||||||
visible: root.isDirContextMenu
|
visible: root.__isDirectory
|
||||||
height: visible ? StudioTheme.Values.border : 0
|
height: visible ? StudioTheme.Values.border : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
id: addTexturesItem
|
||||||
|
text: qsTr("Add Texture")
|
||||||
|
visible: root.__fileIndex && assetsModel.allFilePathsAreImages(root.__selectedAssetPathsList)
|
||||||
|
height: addTexturesItem.visible ? addTexturesItem.implicitHeight : 0
|
||||||
|
onTriggered: rootView.addTextures(root.__selectedAssetPathsList)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
id: addLightProbes
|
||||||
|
text: qsTr("Add Light Probe")
|
||||||
|
visible: root.__fileIndex && root.__selectedAssetPathsList.length === 1
|
||||||
|
&& assetsModel.allFilePathsAreImages(root.__selectedAssetPathsList)
|
||||||
|
height: addLightProbes.visible ? addLightProbes.implicitHeight : 0
|
||||||
|
onTriggered: rootView.addLightProbe(root.__selectedAssetPathsList[0])
|
||||||
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
id: deleteFileItem
|
id: deleteFileItem
|
||||||
text: qsTr("Delete File")
|
text: qsTr("Delete File")
|
||||||
visible: root.contextFilePath
|
visible: root.__fileIndex
|
||||||
height: deleteFileItem.visible ? deleteFileItem.implicitHeight : 0
|
height: deleteFileItem.visible ? deleteFileItem.implicitHeight : 0
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
assetsModel.deleteFiles(Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]))
|
let deleted = assetsModel.requestDeleteFiles(root.__selectedAssetPathsList)
|
||||||
|
if (!deleted)
|
||||||
|
confirmDeleteFiles.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfirmDeleteFilesDialog {
|
||||||
|
id: confirmDeleteFiles
|
||||||
|
parent: root.assetsView
|
||||||
|
files: root.__selectedAssetPathsList
|
||||||
|
|
||||||
|
onAccepted: root.assetsView.selectedAssets = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuSeparator {
|
StudioControls.MenuSeparator {
|
||||||
visible: root.contextFilePath
|
visible: root.__fileIndex
|
||||||
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: root.isDirContextMenu
|
visible: root.__isDirectory
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: renameFolderDialog.open()
|
onTriggered: renameFolderDialog.open()
|
||||||
|
|
||||||
RenameFolderDialog {
|
RenameFolderDialog {
|
||||||
id: renameFolderDialog
|
id: renameFolderDialog
|
||||||
|
parent: root.assetsView
|
||||||
|
dirPath: root.__dirPath
|
||||||
|
dirName: root.__dirName
|
||||||
|
|
||||||
|
onAccepted: root.__onFolderRenamed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +151,10 @@ StudioControls.Menu {
|
|||||||
|
|
||||||
NewFolderDialog {
|
NewFolderDialog {
|
||||||
id: newFolderDialog
|
id: newFolderDialog
|
||||||
|
parent: root.assetsView
|
||||||
|
dirPath: root.__dirPath
|
||||||
|
|
||||||
|
onAccepted: root.__onFolderCreated(newFolderDialog.createdDirPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
onTriggered: newFolderDialog.open()
|
onTriggered: newFolderDialog.open()
|
||||||
@@ -100,21 +162,25 @@ StudioControls.Menu {
|
|||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Delete Folder")
|
text: qsTr("Delete Folder")
|
||||||
visible: root.isDirContextMenu
|
visible: root.__isDirectory
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
|
|
||||||
ConfirmDeleteFolderDialog {
|
ConfirmDeleteFolderDialog {
|
||||||
id: confirmDeleteFolderDialog
|
id: confirmDeleteFolderDialog
|
||||||
|
parent: root.assetsView
|
||||||
|
dirName: root.__dirName
|
||||||
|
dirIndex: root.__dirIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
var dirEmpty = !(root.contextDir.dirsModel && root.contextDir.dirsModel.rowCount() > 0)
|
if (!assetsModel.hasChildren(root.__dirIndex)) {
|
||||||
&& !(root.contextDir.filesModel && root.contextDir.filesModel.rowCount() > 0);
|
// NOTE: the folder may still not be empty -- it doesn't have files visible to the
|
||||||
|
// user, but that doesn't mean that there are no other files (e.g. files of unknown
|
||||||
if (dirEmpty)
|
// types) on disk in this directory.
|
||||||
assetsModel.deleteFolder(root.contextDir.dirPath)
|
assetsModel.deleteFolderRecursively(root.__dirIndex)
|
||||||
else
|
} else {
|
||||||
confirmDeleteFolderDialog.open()
|
confirmDeleteFolderDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,255 +1,311 @@
|
|||||||
/****************************************************************************
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
**
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
** 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
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import HelperWidgets as HelperWidgets
|
||||||
import QtQuickDesignerTheme
|
|
||||||
import HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
import StudioTheme as StudioTheme
|
|
||||||
|
|
||||||
ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
|
TreeView {
|
||||||
id: assetsView
|
id: root
|
||||||
clip: true
|
clip: true
|
||||||
interactive: assetsView.verticalScrollBarVisible && !contextMenu.opened
|
interactive: verticalScrollBar.visible && !root.contextMenu.opened
|
||||||
|
reuseItems: false
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
rowSpacing: 5
|
||||||
|
|
||||||
Column {
|
required property Item assetsRoot
|
||||||
Repeater {
|
required property StudioControls.Menu contextMenu
|
||||||
model: assetsModel // context property
|
property alias verticalScrollBar: verticalScrollBar
|
||||||
delegate: dirSection
|
|
||||||
|
property var selectedAssets: ({})
|
||||||
|
|
||||||
|
// used to see if the op requested is to expand or to collapse.
|
||||||
|
property int lastRowCount: -1
|
||||||
|
// we need this to know if we need to expand further, while we're in onRowsChanged()
|
||||||
|
property bool requestedExpandAll: true
|
||||||
|
// used to compute the visual depth of the items we show to the user.
|
||||||
|
property int rootPathDepth: 0
|
||||||
|
property int rootPathRow: 0
|
||||||
|
// i.e. first child of the root path
|
||||||
|
readonly property int firstRow: root.rootPathRow + 1
|
||||||
|
property int rowToExpand: -1
|
||||||
|
property var __createdDirectories: []
|
||||||
|
|
||||||
|
rowHeightProvider: (row) => {
|
||||||
|
if (row <= root.rootPathRow)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
ScrollBar.vertical: HelperWidgets.VerticalScrollBar {
|
||||||
id: dirSection
|
id: verticalScrollBar
|
||||||
|
scrollBarVisible: root.contentHeight > root.height
|
||||||
Section {
|
|
||||||
id: section
|
|
||||||
|
|
||||||
width: assetsView.width -
|
|
||||||
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5
|
|
||||||
caption: dirName
|
|
||||||
sectionHeight: 30
|
|
||||||
sectionFontSize: 15
|
|
||||||
leftPadding: 0
|
|
||||||
topPadding: dirDepth > 0 ? 5 : 0
|
|
||||||
bottomPadding: 0
|
|
||||||
hideHeader: dirDepth === 0
|
|
||||||
showLeftBorder: dirDepth > 0
|
|
||||||
expanded: dirExpanded
|
|
||||||
visible: dirVisible
|
|
||||||
expandOnClick: false
|
|
||||||
useDefaulContextMenu: false
|
|
||||||
dropEnabled: true
|
|
||||||
|
|
||||||
onToggleExpand: {
|
|
||||||
dirExpanded = !dirExpanded
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropEnter: (drag)=> {
|
model: assetsModel
|
||||||
root.updateDropExtFiles(drag)
|
|
||||||
section.highlight = drag.accepted && root.dropSimpleExtFiles.length > 0
|
onRowsChanged: {
|
||||||
|
if (root.rows > root.rootPathRow + 1 && !assetsModel.haveFiles ||
|
||||||
|
root.rows <= root.rootPathRow + 1 && assetsModel.haveFiles) {
|
||||||
|
assetsModel.syncHaveFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropExit: {
|
updateRows()
|
||||||
section.highlight = false
|
|
||||||
}
|
|
||||||
|
|
||||||
onDrop: {
|
|
||||||
section.highlight = false
|
|
||||||
rootView.handleExtFilesDrop(root.dropSimpleExtFiles,
|
|
||||||
root.dropComplexExtFiles,
|
|
||||||
dirPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowContextMenu: {
|
|
||||||
root.contextFilePath = ""
|
|
||||||
root.contextDir = model
|
|
||||||
root.isDirContextMenu = true
|
|
||||||
root.allExpandedState = assetsModel.getAllExpandedState()
|
|
||||||
contextMenu.popup()
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 5
|
|
||||||
leftPadding: 5
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: dirsModel
|
|
||||||
delegate: dirSection
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: filesModel
|
|
||||||
delegate: fileSection
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: qsTr("Empty folder")
|
|
||||||
color: StudioTheme.Values.themeTextColorDisabled
|
|
||||||
font.pixelSize: 12
|
|
||||||
visible: !(dirsModel && dirsModel.rowCount() > 0)
|
|
||||||
&& !(filesModel && filesModel.rowCount() > 0)
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.RightButton
|
|
||||||
onClicked: {
|
|
||||||
root.contextFilePath = ""
|
|
||||||
root.contextDir = model
|
|
||||||
root.isDirContextMenu = true
|
|
||||||
contextMenu.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: fileSection
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: assetsView.width -
|
|
||||||
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
|
|
||||||
height: img.height
|
|
||||||
color: root.selectedAssets[filePath]
|
|
||||||
? StudioTheme.Values.themeInteraction
|
|
||||||
: (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground
|
|
||||||
: "transparent")
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: 5
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: img
|
|
||||||
asynchronous: true
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
width: 48
|
|
||||||
height: 48
|
|
||||||
source: "image://qmldesigner_assets/" + filePath
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: fileName
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
font.pixelSize: 14
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property string suffix: fileName.substr(-4)
|
|
||||||
readonly property bool isFont: suffix === ".ttf" || suffix === ".otf"
|
|
||||||
readonly property bool isEffect: suffix === ".qep"
|
|
||||||
property bool currFileSelected: false
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: mouseArea
|
|
||||||
|
|
||||||
property bool allowTooltip: true
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
|
|
||||||
onExited: tooltipBackend.hideTooltip()
|
|
||||||
onEntered: allowTooltip = true
|
|
||||||
onCanceled: {
|
|
||||||
tooltipBackend.hideTooltip()
|
|
||||||
allowTooltip = true
|
|
||||||
}
|
|
||||||
onPositionChanged: tooltipBackend.reposition()
|
|
||||||
onPressed: (mouse) => {
|
|
||||||
forceActiveFocus()
|
|
||||||
allowTooltip = false
|
|
||||||
tooltipBackend.hideTooltip()
|
|
||||||
var ctrlDown = mouse.modifiers & Qt.ControlModifier
|
|
||||||
if (mouse.button === Qt.LeftButton) {
|
|
||||||
if (!root.selectedAssets[filePath] && !ctrlDown)
|
|
||||||
root.selectedAssets = {}
|
|
||||||
currFileSelected = ctrlDown ? !root.selectedAssets[filePath] : true
|
|
||||||
root.selectedAssets[filePath] = currFileSelected
|
|
||||||
root.selectedAssetsChanged()
|
|
||||||
|
|
||||||
if (currFileSelected) {
|
|
||||||
rootView.startDragAsset(
|
|
||||||
Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]),
|
|
||||||
mapToGlobal(mouse.x, mouse.y))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!root.selectedAssets[filePath] && !ctrlDown)
|
|
||||||
root.selectedAssets = {}
|
|
||||||
currFileSelected = root.selectedAssets[filePath] || !ctrlDown
|
|
||||||
root.selectedAssets[filePath] = currFileSelected
|
|
||||||
root.selectedAssetsChanged()
|
|
||||||
|
|
||||||
root.contextFilePath = filePath
|
|
||||||
root.contextDir = model.fileDir
|
|
||||||
root.isDirContextMenu = false
|
|
||||||
|
|
||||||
contextMenu.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onReleased: (mouse) => {
|
|
||||||
allowTooltip = true
|
|
||||||
if (mouse.button === Qt.LeftButton) {
|
|
||||||
if (!(mouse.modifiers & Qt.ControlModifier))
|
|
||||||
root.selectedAssets = {}
|
|
||||||
root.selectedAssets[filePath] = currFileSelected
|
|
||||||
root.selectedAssetsChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDoubleClicked: (mouse) => {
|
|
||||||
forceActiveFocus()
|
|
||||||
allowTooltip = false
|
|
||||||
tooltipBackend.hideTooltip()
|
|
||||||
if (mouse.button === Qt.LeftButton && isEffect)
|
|
||||||
rootView.openEffectMaker(filePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolTip {
|
|
||||||
visible: !isFont && mouseArea.containsMouse && !contextMenu.visible
|
|
||||||
text: filePath
|
|
||||||
delay: 1000
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 1000
|
id: updateRowsTimer
|
||||||
running: mouseArea.containsMouse && mouseArea.allowTooltip
|
interval: 200
|
||||||
|
repeat: false
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (suffix === ".ttf" || suffix === ".otf") {
|
root.updateRows()
|
||||||
tooltipBackend.name = fileName
|
|
||||||
tooltipBackend.path = filePath
|
|
||||||
tooltipBackend.showTooltip()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: rootView
|
||||||
|
|
||||||
|
function onDirectoryCreated(path)
|
||||||
|
{
|
||||||
|
root.__createdDirectories.push(path)
|
||||||
|
|
||||||
|
updateRowsTimer.restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: assetsModel
|
||||||
|
function onDirectoryLoaded(path)
|
||||||
|
{
|
||||||
|
// updating rows for safety: the rows might have been created before the
|
||||||
|
// directory (esp. the root path) has been loaded, so we must make sure all rows are
|
||||||
|
// expanded -- otherwise, the tree may not become visible.
|
||||||
|
|
||||||
|
updateRowsTimer.restart()
|
||||||
|
|
||||||
|
let idx = assetsModel.indexForPath(path)
|
||||||
|
let row = root.rowAtIndex(idx)
|
||||||
|
let column = root.columnAtIndex(idx)
|
||||||
|
|
||||||
|
if (row >= root.rootPathRow && !root.isExpanded(row))
|
||||||
|
root.expand(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRootPathChanged()
|
||||||
|
{
|
||||||
|
// when we switch from one project to another, we need to reset the state of the
|
||||||
|
// view: make sure we will do an "expand all" (otherwise, the whole tree might
|
||||||
|
// be collapsed, and with our visible root not being the actual root of the tree,
|
||||||
|
// the entire tree would be invisible)
|
||||||
|
root.lastRowCount = -1
|
||||||
|
root.requestedExpandAll = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFileChanged(filePath)
|
||||||
|
{
|
||||||
|
rootView.invalidateThumbnail(filePath)
|
||||||
|
|
||||||
|
let index = assetsModel.indexForPath(filePath)
|
||||||
|
let cell = root.cellAtIndex(index)
|
||||||
|
let fileItem = root.itemAtCell(cell)
|
||||||
|
|
||||||
|
if (fileItem)
|
||||||
|
fileItem.reloadImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Connections
|
||||||
|
|
||||||
|
function addCreatedFolder(path)
|
||||||
|
{
|
||||||
|
root.__createdDirectories.push(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedPathsAsList()
|
||||||
|
{
|
||||||
|
return Object.keys(root.selectedAssets)
|
||||||
|
.filter(itemPath => root.selectedAssets[itemPath])
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround for a bug -- might be fixed by https://codereview.qt-project.org/c/qt/qtdeclarative/+/442721
|
||||||
|
function resetVerticalScrollPosition()
|
||||||
|
{
|
||||||
|
root.contentY = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRows()
|
||||||
|
{
|
||||||
|
if (root.rows <= 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
while (root.__createdDirectories.length > 0) {
|
||||||
|
let dirPath = root.__createdDirectories.pop()
|
||||||
|
let index = assetsModel.indexForPath(dirPath)
|
||||||
|
let row = root.rowAtIndex(index)
|
||||||
|
|
||||||
|
if (row > 0)
|
||||||
|
root.expand(row)
|
||||||
|
else if (row === -1 && assetsModel.indexIsValid(index)) {
|
||||||
|
// It is possible that this directory, dirPath, was created inside of a parent
|
||||||
|
// directory that was not yet expanded in the TreeView. This can happen with the
|
||||||
|
// bridge plugin. In such a situation, we don't have a "row" for it yet, so we have
|
||||||
|
// to expand its parents, from root to our `index`
|
||||||
|
let parents = assetsModel.parentIndices(index);
|
||||||
|
parents.reverse().forEach(idx => {
|
||||||
|
let row = root.rowAtIndex(idx)
|
||||||
|
if (row > 0)
|
||||||
|
root.expand(row)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we have no way to know beyond doubt here if updateRows() was called due
|
||||||
|
// to a request to expand or to collapse rows - but it should be safe to
|
||||||
|
// assume that, if we have more rows now than the last time, then it's an expand
|
||||||
|
var expanding = (root.rows >= root.lastRowCount)
|
||||||
|
|
||||||
|
if (expanding) {
|
||||||
|
if (root.requestedExpandAll)
|
||||||
|
root.__doExpandAll()
|
||||||
|
} else {
|
||||||
|
if (root.rowToExpand > 0) {
|
||||||
|
root.expand(root.rowToExpand)
|
||||||
|
root.rowToExpand = -1
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// on collapsing, set expandAll flag to false.
|
||||||
|
root.requestedExpandAll = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.lastRowCount = root.rows
|
||||||
|
}
|
||||||
|
|
||||||
|
function __doExpandAll()
|
||||||
|
{
|
||||||
|
let expandedAny = false
|
||||||
|
for (let nRow = 0; nRow < root.rows; ++nRow) {
|
||||||
|
let index = root.__modelIndex(nRow)
|
||||||
|
if (assetsModel.isDirectory(index) && !root.isExpanded(nRow)) {
|
||||||
|
root.expand(nRow);
|
||||||
|
expandedAny = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expandedAny)
|
||||||
|
Qt.callLater(root.forceLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandAll()
|
||||||
|
{
|
||||||
|
// In order for __doExpandAll() to be called repeatedly (every time a new node is
|
||||||
|
// loaded, and then, expanded), we need to set requestedExpandAll to true.
|
||||||
|
root.requestedExpandAll = true
|
||||||
|
root.__doExpandAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
function collapseAll()
|
||||||
|
{
|
||||||
|
root.resetVerticalScrollPosition()
|
||||||
|
|
||||||
|
// collapse all, except for the root path - from the last item (leaves) up to the root
|
||||||
|
for (let nRow = root.rows - 1; nRow >= 0; --nRow) {
|
||||||
|
let index = root.__modelIndex(nRow)
|
||||||
|
// we don't want to collapse the root path, because doing so will hide the contents
|
||||||
|
// of the tree.
|
||||||
|
if (assetsModel.filePath(index) === assetsModel.rootPath())
|
||||||
|
break
|
||||||
|
|
||||||
|
root.collapse(nRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround for a bug -- might be fixed by https://codereview.qt-project.org/c/qt/qtdeclarative/+/442721
|
||||||
|
onContentHeightChanged: {
|
||||||
|
if (root.contentHeight <= root.height) {
|
||||||
|
let first = root.itemAtCell(0, root.firstRow)
|
||||||
|
if (!first)
|
||||||
|
root.contentY = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeAllExpandedState()
|
||||||
|
{
|
||||||
|
var dirsWithChildren = [...Array(root.rows).keys()].filter(row => {
|
||||||
|
let index = root.__modelIndex(row)
|
||||||
|
return assetsModel.isDirectory(index) && assetsModel.hasChildren(index)
|
||||||
|
})
|
||||||
|
|
||||||
|
var countExpanded = dirsWithChildren.filter(row => root.isExpanded(row)).length
|
||||||
|
|
||||||
|
if (countExpanded === dirsWithChildren.length)
|
||||||
|
return "all_expanded"
|
||||||
|
|
||||||
|
if (countExpanded === 0)
|
||||||
|
return "all_collapsed"
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function startDropHoverOver(row)
|
||||||
|
{
|
||||||
|
let index = root.__modelIndex(row)
|
||||||
|
if (assetsModel.isDirectory(index))
|
||||||
|
return
|
||||||
|
|
||||||
|
let parentItem = root.__getDelegateParentForIndex(index)
|
||||||
|
if (parentItem)
|
||||||
|
parentItem.hasChildWithDropHover = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function endDropHover(row)
|
||||||
|
{
|
||||||
|
let index = root.__modelIndex(row)
|
||||||
|
if (assetsModel.isDirectory(index))
|
||||||
|
return
|
||||||
|
|
||||||
|
let parentItem = root.__getDelegateParentForIndex(index)
|
||||||
|
if (parentItem)
|
||||||
|
parentItem.hasChildWithDropHover = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAssetSelected(itemPath)
|
||||||
|
{
|
||||||
|
return root.selectedAssets[itemPath] ? true : false
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSelectedAssets()
|
||||||
|
{
|
||||||
|
root.selectedAssets = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAssetSelected(itemPath, selected)
|
||||||
|
{
|
||||||
|
root.selectedAssets[itemPath] = selected
|
||||||
|
root.selectedAssetsChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
function __getDelegateParentForIndex(index)
|
||||||
|
{
|
||||||
|
let parentIndex = assetsModel.parentDirIndex(index)
|
||||||
|
let parentCell = root.cellAtIndex(parentIndex)
|
||||||
|
return root.itemAtCell(parentCell)
|
||||||
|
}
|
||||||
|
|
||||||
|
function __modelIndex(row)
|
||||||
|
{
|
||||||
|
// The modelIndex() function exists since 6.3. In Qt 6.3, this modelIndex() function was a
|
||||||
|
// member of the TreeView, while in Qt6.4 it was moved to TableView. In Qt6.4, the order of
|
||||||
|
// the arguments was changed.
|
||||||
|
if (assetsRoot.qtVersionAtLeast6_4)
|
||||||
|
return root.modelIndex(0, row)
|
||||||
|
else
|
||||||
|
return root.modelIndex(row, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: AssetDelegate {
|
||||||
|
assetsView: root
|
||||||
|
assetsRoot: root.assetsRoot
|
||||||
|
indentation: 5
|
||||||
|
}
|
||||||
|
} // TreeView
|
||||||
|
@@ -0,0 +1,107 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import HelperWidgets as HelperWidgets
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: root
|
||||||
|
title: qsTr("Confirm Delete Files")
|
||||||
|
anchors.centerIn: parent
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
implicitWidth: 350
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
required property var files
|
||||||
|
|
||||||
|
contentItem: Column {
|
||||||
|
spacing: 20
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: confirmDeleteText
|
||||||
|
|
||||||
|
text: root.files && root.files.length
|
||||||
|
? qsTr("Some files might be in use. Delete anyway?")
|
||||||
|
: ""
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: root.width
|
||||||
|
leftPadding: 10
|
||||||
|
rightPadding: 10
|
||||||
|
|
||||||
|
Keys.onEnterPressed: btnDelete.onClicked()
|
||||||
|
Keys.onReturnPressed: btnDelete.onClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: fileListLoader
|
||||||
|
sourceComponent: null
|
||||||
|
width: parent.width - 20
|
||||||
|
x: 10
|
||||||
|
height: 50
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.CheckBox {
|
||||||
|
id: dontAskAgain
|
||||||
|
text: qsTr("Do not ask this again")
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
width: parent.width
|
||||||
|
x: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
id: btnDelete
|
||||||
|
|
||||||
|
text: qsTr("Delete")
|
||||||
|
onClicked: {
|
||||||
|
assetsModel.deleteFiles(root.files, dontAskAgain.checked)
|
||||||
|
root.accept()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
fileListLoader.sourceComponent = null
|
||||||
|
fileListLoader.sourceComponent = fileListComponent
|
||||||
|
|
||||||
|
confirmDeleteText.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: fileListLoader.sourceComponent = null
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: fileListComponent
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: filesListView
|
||||||
|
model: root.files
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
ScrollBar.vertical: HelperWidgets.VerticalScrollBar {
|
||||||
|
id: verticalScrollBar
|
||||||
|
scrollBarVisible: filesListView.contentHeight > filesListView.height
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Text {
|
||||||
|
elide: Text.ElideLeft
|
||||||
|
text: model.modelData.replace(assetsModel.currentProjectDirPath(), "")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
width: parent.width - (verticalScrollBar.scrollBarVisible ? verticalScrollBar.width : 0)
|
||||||
|
}
|
||||||
|
} // ListView
|
||||||
|
} // Component
|
||||||
|
}
|
@@ -1,38 +1,13 @@
|
|||||||
/****************************************************************************
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
**
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
** 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
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import HelperWidgets as HelperWidgets
|
||||||
import QtQuickDesignerTheme
|
|
||||||
import HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
Dialog {
|
Dialog {
|
||||||
id: confirmDeleteFolderDialog
|
id: root
|
||||||
|
|
||||||
title: qsTr("Folder Not Empty")
|
title: qsTr("Folder Not Empty")
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -40,6 +15,9 @@ Dialog {
|
|||||||
implicitWidth: 300
|
implicitWidth: 300
|
||||||
modal: true
|
modal: true
|
||||||
|
|
||||||
|
required property string dirName
|
||||||
|
required property var dirIndex
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: Column {
|
||||||
spacing: 20
|
spacing: 20
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -47,11 +25,10 @@ Dialog {
|
|||||||
Text {
|
Text {
|
||||||
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(root.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: root.width
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
rightPadding: 10
|
rightPadding: 10
|
||||||
|
|
||||||
@@ -63,27 +40,27 @@ Dialog {
|
|||||||
text: qsTr("If the folder has assets in use, deleting it might cause the project to not work correctly.")
|
text: qsTr("If the folder has assets in use, deleting it might cause the project to not work correctly.")
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: confirmDeleteFolderDialog.width
|
width: root.width
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
rightPadding: 10
|
rightPadding: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
Button {
|
HelperWidgets.Button {
|
||||||
id: btnDelete
|
id: btnDelete
|
||||||
|
|
||||||
text: qsTr("Delete")
|
text: qsTr("Delete")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
assetsModel.deleteFolder(root.contextDir.dirPath)
|
assetsModel.deleteFolderRecursively(root.dirIndex)
|
||||||
confirmDeleteFolderDialog.accept()
|
root.accept()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
HelperWidgets.Button {
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
onClicked: confirmDeleteFolderDialog.reject()
|
onClicked: root.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import HelperWidgets as HelperWidgets
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string message
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
implicitWidth: 300
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
contentItem: Column {
|
||||||
|
spacing: 20
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.message
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: root.width
|
||||||
|
leftPadding: 10
|
||||||
|
rightPadding: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Close")
|
||||||
|
anchors.right: parent.right
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: root.forceActiveFocus()
|
||||||
|
}
|
@@ -68,6 +68,8 @@ Item {
|
|||||||
id: mouseRegion
|
id: mouseRegion
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
tooltip: toolTip
|
||||||
|
|
||||||
onShowContextMenu: delegateRoot.showContextMenu()
|
onShowContextMenu: delegateRoot.showContextMenu()
|
||||||
onPressed: (mouse)=> {
|
onPressed: (mouse)=> {
|
||||||
allowTooltip = false
|
allowTooltip = false
|
||||||
|
@@ -1,44 +1,35 @@
|
|||||||
/****************************************************************************
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
**
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
** 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
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import HelperWidgets as HelperWidgets
|
||||||
import QtQuickDesignerTheme
|
|
||||||
import HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
Dialog {
|
Dialog {
|
||||||
id: newFolderDialog
|
id: root
|
||||||
|
|
||||||
title: qsTr("Create New Folder")
|
title: qsTr("Create New Folder")
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
closePolicy: Popup.CloseOnEscape
|
closePolicy: Popup.CloseOnEscape
|
||||||
modal: true
|
modal: true
|
||||||
|
|
||||||
|
required property string dirPath
|
||||||
|
property string createdDirPath: ""
|
||||||
|
readonly property int __maxPath: 260
|
||||||
|
|
||||||
|
HelperWidgets.RegExpValidator {
|
||||||
|
id: folderNameValidator
|
||||||
|
regExp: /^(\w[^*/><?\\|:]*)$/
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorDialog {
|
||||||
|
id: creationFailedDialog
|
||||||
|
title: qsTr("Could not create folder")
|
||||||
|
message: qsTr("An error occurred while trying to create the folder.")
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: Column {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
@@ -58,6 +49,10 @@ Dialog {
|
|||||||
|
|
||||||
Keys.onEnterPressed: btnCreate.onClicked()
|
Keys.onEnterPressed: btnCreate.onClicked()
|
||||||
Keys.onReturnPressed: btnCreate.onClicked()
|
Keys.onReturnPressed: btnCreate.onClicked()
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
root.createdDirPath = root.dirPath + '/' + folderName.text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +63,13 @@ Dialog {
|
|||||||
visible: folderName.text === ""
|
visible: folderName.text === ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Folder path is too long.")
|
||||||
|
color: "#ff0000"
|
||||||
|
anchors.right: parent.right
|
||||||
|
visible: root.createdDirPath.length > root.__maxPath
|
||||||
|
}
|
||||||
|
|
||||||
Item { // spacer
|
Item { // spacer
|
||||||
width: 1
|
width: 1
|
||||||
height: 20
|
height: 20
|
||||||
@@ -76,20 +78,23 @@ Dialog {
|
|||||||
Row {
|
Row {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
Button {
|
HelperWidgets.Button {
|
||||||
id: btnCreate
|
id: btnCreate
|
||||||
|
|
||||||
text: qsTr("Create")
|
text: qsTr("Create")
|
||||||
enabled: folderName.text !== ""
|
enabled: folderName.text !== "" && root.createdDirPath.length <= root.__maxPath
|
||||||
onClicked: {
|
onClicked: {
|
||||||
assetsModel.addNewFolder(root.contextDir.dirPath + '/' + folderName.text)
|
root.createdDirPath = root.dirPath + '/' + folderName.text
|
||||||
newFolderDialog.accept()
|
if (assetsModel.addNewFolder(root.createdDirPath))
|
||||||
|
root.accept()
|
||||||
|
else
|
||||||
|
creationFailedDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
HelperWidgets.Button {
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
onClicked: newFolderDialog.reject()
|
onClicked: root.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,4 +104,8 @@ Dialog {
|
|||||||
folderName.selectAll()
|
folderName.selectAll()
|
||||||
folderName.forceActiveFocus()
|
folderName.forceActiveFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRejected: {
|
||||||
|
root.createdDirPath = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,38 +1,14 @@
|
|||||||
/****************************************************************************
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
**
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
** 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
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import HelperWidgets as HelperWidgets
|
||||||
import QtQuickDesignerTheme
|
|
||||||
import HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
Dialog {
|
Dialog {
|
||||||
id: renameFolderDialog
|
id: root
|
||||||
|
|
||||||
title: qsTr("Rename Folder")
|
title: qsTr("Rename Folder")
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -41,6 +17,13 @@ Dialog {
|
|||||||
modal: true
|
modal: true
|
||||||
|
|
||||||
property bool renameError: false
|
property bool renameError: false
|
||||||
|
required property string dirPath
|
||||||
|
required property string dirName
|
||||||
|
|
||||||
|
HelperWidgets.RegExpValidator {
|
||||||
|
id: folderNameValidator
|
||||||
|
regExp: /^(\w[^*/><?\\|:]*)$/
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: Column {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
@@ -50,10 +33,10 @@ Dialog {
|
|||||||
|
|
||||||
actionIndicator.visible: false
|
actionIndicator.visible: false
|
||||||
translationIndicator.visible: false
|
translationIndicator.visible: false
|
||||||
width: renameFolderDialog.width - 12
|
width: root.width - 12
|
||||||
validator: folderNameValidator
|
validator: folderNameValidator
|
||||||
|
|
||||||
onEditChanged: renameFolderDialog.renameError = false
|
onEditChanged: root.renameError = false
|
||||||
Keys.onEnterPressed: btnRename.onClicked()
|
Keys.onEnterPressed: btnRename.onClicked()
|
||||||
Keys.onReturnPressed: btnRename.onClicked()
|
Keys.onReturnPressed: btnRename.onClicked()
|
||||||
}
|
}
|
||||||
@@ -61,15 +44,15 @@ Dialog {
|
|||||||
Text {
|
Text {
|
||||||
text: qsTr("Folder name cannot be empty.")
|
text: qsTr("Folder name cannot be empty.")
|
||||||
color: "#ff0000"
|
color: "#ff0000"
|
||||||
visible: folderRename.text === "" && !renameFolderDialog.renameError
|
visible: folderRename.text === "" && !root.renameError
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("Could not rename folder. Make sure no folder with the same name exists.")
|
text: qsTr("Could not rename folder. Make sure no folder with the same name exists.")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: renameFolderDialog.width - 12
|
width: root.width - 12
|
||||||
color: "#ff0000"
|
color: "#ff0000"
|
||||||
visible: renameFolderDialog.renameError
|
visible: root.renameError
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // spacer
|
Item { // spacer
|
||||||
@@ -81,7 +64,7 @@ Dialog {
|
|||||||
text: qsTr("If the folder has assets in use, renaming it might cause the project to not work correctly.")
|
text: qsTr("If the folder has assets in use, renaming it might cause the project to not work correctly.")
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: renameFolderDialog.width
|
width: root.width
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
rightPadding: 10
|
rightPadding: 10
|
||||||
}
|
}
|
||||||
@@ -94,31 +77,31 @@ Dialog {
|
|||||||
Row {
|
Row {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
Button {
|
HelperWidgets.Button {
|
||||||
id: btnRename
|
id: btnRename
|
||||||
|
|
||||||
text: qsTr("Rename")
|
text: qsTr("Rename")
|
||||||
enabled: folderRename.text !== ""
|
enabled: folderRename.text !== ""
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var success = assetsModel.renameFolder(root.contextDir.dirPath, folderRename.text)
|
var success = assetsModel.renameFolder(root.dirPath, folderRename.text)
|
||||||
if (success)
|
if (success)
|
||||||
renameFolderDialog.accept()
|
root.accept()
|
||||||
|
|
||||||
renameFolderDialog.renameError = !success
|
root.renameError = !success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
HelperWidgets.Button {
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
onClicked: renameFolderDialog.reject()
|
onClicked: root.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
folderRename.text = root.contextDir.dirName
|
folderRename.text = root.dirName
|
||||||
folderRename.selectAll()
|
folderRename.selectAll()
|
||||||
folderRename.forceActiveFocus()
|
folderRename.forceActiveFocus()
|
||||||
renameFolderDialog.renameError = false
|
root.renameError = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,153 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuickDesignerTheme
|
||||||
|
import HelperWidgets
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
color: StudioTheme.Values.themePanelBackground
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: col
|
||||||
|
padding: 5
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Select material:")
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: materialsListView
|
||||||
|
|
||||||
|
width: root.width * .5 - 5
|
||||||
|
height: root.height - 60
|
||||||
|
focus: true
|
||||||
|
clip: true
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
ScrollBar.vertical: StudioControls.ScrollBar {
|
||||||
|
visible: materialsListView.height < materialsListView.contentHeight
|
||||||
|
}
|
||||||
|
model: materialsModel
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: materialsListView.width
|
||||||
|
height: 20
|
||||||
|
color: ListView.isCurrentItem ? StudioTheme.Values.themeTextSelectionColor
|
||||||
|
: "transparent"
|
||||||
|
|
||||||
|
function id() {
|
||||||
|
return modelData.match(/\((.*)\)/).pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: modelData
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
leftPadding: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
materialsListView.currentIndex = index
|
||||||
|
rootView.updatePropsModel(id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 5
|
||||||
|
Text {
|
||||||
|
text: qsTr("Select property:")
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: propertiesListView
|
||||||
|
|
||||||
|
width: root.width * .5 - 5
|
||||||
|
height: root.height - 60
|
||||||
|
focus: true
|
||||||
|
clip: true
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
ScrollBar.vertical: StudioControls.ScrollBar {
|
||||||
|
visible: propertiesListView.height < propertiesListView.contentHeight
|
||||||
|
}
|
||||||
|
model: propertiesModel
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: propertiesListView.width
|
||||||
|
height: 20
|
||||||
|
color: ListView.isCurrentItem ? StudioTheme.Values.themeTextSelectionColor
|
||||||
|
: "transparent"
|
||||||
|
|
||||||
|
function propName() {
|
||||||
|
return modelData
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: modelData
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
leftPadding: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
propertiesListView.currentIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 5
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
rootView.closeChooseMatPropsView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Apply")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
let matId = materialsListView.currentItem.id()
|
||||||
|
let prop = propertiesListView.currentItem.propName()
|
||||||
|
|
||||||
|
rootView.applyTextureToProperty(matId, prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -12,6 +12,8 @@ Item {
|
|||||||
|
|
||||||
readonly property int cellWidth: 100
|
readonly property int cellWidth: 100
|
||||||
readonly property int cellHeight: 120
|
readonly property int cellHeight: 120
|
||||||
|
readonly property bool enableUiElements: materialBrowserModel.hasMaterialLibrary
|
||||||
|
&& materialBrowserModel.hasQuick3DImport
|
||||||
|
|
||||||
property var currMaterialItem: null
|
property var currMaterialItem: null
|
||||||
|
|
||||||
@@ -19,6 +21,7 @@ Item {
|
|||||||
function closeContextMenu()
|
function closeContextMenu()
|
||||||
{
|
{
|
||||||
ctxMenu.close()
|
ctxMenu.close()
|
||||||
|
ctxMenuTextures.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from C++ to refresh a preview material after it changes
|
// Called from C++ to refresh a preview material after it changes
|
||||||
@@ -54,16 +57,16 @@ Item {
|
|||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
|
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
if (materialBrowserModel.hasMaterialRoot || !materialBrowserModel.hasQuick3DImport)
|
if (!root.enableUiElements)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var matsSecBottom = mapFromItem(materialsSection, 0, materialsSection.y).y
|
var matsSecBottom = mapFromItem(materialsSection, 0, materialsSection.y).y
|
||||||
+ materialsSection.height;
|
+ materialsSection.height;
|
||||||
|
|
||||||
if (!materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport
|
if (mouse.y < matsSecBottom)
|
||||||
&& mouse.y < matsSecBottom) {
|
|
||||||
ctxMenu.popupMenu()
|
ctxMenu.popupMenu()
|
||||||
}
|
else
|
||||||
|
ctxMenuTextures.popupMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +86,10 @@ Item {
|
|||||||
id: ctxMenu
|
id: ctxMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureBrowserContextMenu {
|
||||||
|
id: ctxMenuTextures
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: col
|
id: col
|
||||||
y: 5
|
y: 5
|
||||||
@@ -90,37 +97,25 @@ Item {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
width: root.width
|
width: root.width
|
||||||
enabled: !materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport
|
enabled: root.enableUiElements
|
||||||
|
|
||||||
StudioControls.SearchBox {
|
StudioControls.SearchBox {
|
||||||
id: searchBox
|
id: searchBox
|
||||||
|
|
||||||
width: root.width - addMaterialButton.width
|
width: root.width
|
||||||
|
|
||||||
onSearchChanged: (searchText) => {
|
onSearchChanged: (searchText) => {
|
||||||
rootView.handleSearchFilterChanged(searchText)
|
rootView.handleSearchFilterChanged(searchText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
|
||||||
id: addMaterialButton
|
|
||||||
|
|
||||||
tooltip: qsTr("Add a material.")
|
|
||||||
|
|
||||||
icon: StudioTheme.Constants.plus
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
buttonSize: searchBox.height
|
|
||||||
onClicked: materialBrowserModel.addNewMaterial()
|
|
||||||
enabled: materialBrowserModel.hasQuick3DImport
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: {
|
text: {
|
||||||
if (materialBrowserModel.hasMaterialRoot)
|
if (!materialBrowserModel.hasQuick3DImport)
|
||||||
qsTr("<b>Material Browser</b> is disabled inside a material component.")
|
|
||||||
else if (!materialBrowserModel.hasQuick3DImport)
|
|
||||||
qsTr("To use <b>Material Browser</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
qsTr("To use <b>Material Browser</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
||||||
|
else if (!materialBrowserModel.hasMaterialLibrary)
|
||||||
|
qsTr("<b>Material Browser</b> is disabled inside a non-visual component.")
|
||||||
else
|
else
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
@@ -141,10 +136,14 @@ Item {
|
|||||||
width: root.width
|
width: root.width
|
||||||
height: root.height - searchBox.height
|
height: root.height - searchBox.height
|
||||||
clip: true
|
clip: true
|
||||||
visible: materialBrowserModel.hasQuick3DImport && !materialBrowserModel.hasMaterialRoot
|
visible: root.enableUiElements
|
||||||
interactive: !ctxMenu.opened
|
interactive: !ctxMenu.opened && !ctxMenuTextures.opened
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
Item {
|
||||||
|
width: root.width
|
||||||
|
height: materialsSection.height
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
id: materialsSection
|
id: materialsSection
|
||||||
|
|
||||||
@@ -195,7 +194,7 @@ Item {
|
|||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
visible: materialBrowserModel.isEmpty && !searchBox.isEmpty() && !materialBrowserModel.hasMaterialRoot
|
visible: materialBrowserModel.isEmpty && !searchBox.isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@@ -210,12 +209,47 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: addMaterialButton
|
||||||
|
|
||||||
|
tooltip: qsTr("Add a material.")
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: scrollView.verticalScrollBarVisible ? 10 : 0
|
||||||
|
icon: StudioTheme.Constants.plus
|
||||||
|
normalColor: "transparent"
|
||||||
|
buttonSize: StudioTheme.Values.sectionHeadHeight
|
||||||
|
onClicked: materialBrowserModel.addNewMaterial()
|
||||||
|
enabled: root.enableUiElements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: root.width
|
||||||
|
height: texturesSection.height
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
id: texturesSection
|
id: texturesSection
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
caption: qsTr("Textures")
|
caption: qsTr("Textures")
|
||||||
|
|
||||||
|
dropEnabled: true
|
||||||
|
|
||||||
|
onDropEnter: (drag) => {
|
||||||
|
drag.accepted = drag.formats[0] === "application/vnd.qtdesignstudio.bundletexture"
|
||||||
|
highlight = drag.accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropExit: {
|
||||||
|
highlight = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrop: {
|
||||||
|
highlight = false
|
||||||
|
rootView.acceptBundleTextureDrop()
|
||||||
|
}
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
width: scrollView.width
|
width: scrollView.width
|
||||||
leftPadding: 5
|
leftPadding: 5
|
||||||
@@ -232,7 +266,7 @@ Item {
|
|||||||
height: root.cellWidth
|
height: root.cellWidth
|
||||||
|
|
||||||
onShowContextMenu: {
|
onShowContextMenu: {
|
||||||
// ctxMenuTexture.popupMenu(this, model) // TODO: implement textures context menu
|
ctxMenuTextures.popupMenu(model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,11 +277,11 @@ Item {
|
|||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
visible: materialBrowserModel.isEmpty && !searchBox.isEmpty() && !materialBrowserModel.hasMaterialRoot
|
visible: materialBrowserTexturesModel.isEmpty && !searchBox.isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text:qsTr("There are no texture in this project.")
|
text:qsTr("There are no textures in this project.")
|
||||||
visible: materialBrowserTexturesModel.isEmpty && searchBox.isEmpty()
|
visible: materialBrowserTexturesModel.isEmpty && searchBox.isEmpty()
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
@@ -257,6 +291,36 @@ Item {
|
|||||||
width: root.width
|
width: root.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: addTextureButton
|
||||||
|
|
||||||
|
tooltip: qsTr("Add a texture.")
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: scrollView.verticalScrollBarVisible ? 10 : 0
|
||||||
|
icon: StudioTheme.Constants.plus
|
||||||
|
normalColor: "transparent"
|
||||||
|
buttonSize: StudioTheme.Values.sectionHeadHeight
|
||||||
|
onClicked: materialBrowserTexturesModel.addNewTexture()
|
||||||
|
enabled: root.enableUiElements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropArea {
|
||||||
|
id: masterDropArea
|
||||||
|
|
||||||
|
property int emptyHeight: scrollView.height - materialsSection.height - texturesSection.height
|
||||||
|
|
||||||
|
width: root.width
|
||||||
|
height: emptyHeight > 0 ? emptyHeight : 0
|
||||||
|
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
onEntered: (drag) => texturesSection.dropEnter(drag)
|
||||||
|
onDropped: (drag) => texturesSection.drop(drag)
|
||||||
|
onExited: texturesSection.dropExit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,13 +36,25 @@ Rectangle {
|
|||||||
mouseArea.forceActiveFocus()
|
mouseArea.forceActiveFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
border.width: materialBrowserModel.selectedIndex === index ? 1 : 0
|
border.width: materialBrowserModel.selectedIndex === index ? rootView.materialSectionFocused ? 3 : 1 : 0
|
||||||
border.color: materialBrowserModel.selectedIndex === index
|
border.color: materialBrowserModel.selectedIndex === index
|
||||||
? StudioTheme.Values.themeControlOutlineInteraction
|
? StudioTheme.Values.themeControlOutlineInteraction
|
||||||
: "transparent"
|
: "transparent"
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
visible: materialVisible
|
visible: materialVisible
|
||||||
|
|
||||||
|
DropArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onEntered: (drag) => {
|
||||||
|
drag.accepted = drag.formats[0] === "application/vnd.qtdesignstudio.texture"
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropped: (drag) => {
|
||||||
|
rootView.acceptTextureDropOnMaterial(index, drag.getDataAsString(drag.keys[0]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
||||||
@@ -50,6 +62,7 @@ Rectangle {
|
|||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
|
||||||
onPressed: (mouse) => {
|
onPressed: (mouse) => {
|
||||||
|
rootView.focusMaterialSection(true)
|
||||||
materialBrowserModel.selectMaterial(index)
|
materialBrowserModel.selectMaterial(index)
|
||||||
|
|
||||||
if (mouse.button === Qt.LeftButton)
|
if (mouse.button === Qt.LeftButton)
|
||||||
@@ -116,7 +129,10 @@ Rectangle {
|
|||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
onClicked: materialBrowserModel.selectMaterial(index)
|
onClicked: {
|
||||||
|
rootView.focusMaterialSection(true)
|
||||||
|
materialBrowserModel.selectMaterial(index)
|
||||||
|
}
|
||||||
onDoubleClicked: root.startRename()
|
onDoubleClicked: root.startRename()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import HelperWidgets
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
StudioControls.Menu {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var targetTexture: null
|
||||||
|
property int copiedTextureInternalId: -1
|
||||||
|
|
||||||
|
function popupMenu(targetTexture = null)
|
||||||
|
{
|
||||||
|
this.targetTexture = targetTexture
|
||||||
|
materialBrowserTexturesModel.updateSceneEnvState()
|
||||||
|
materialBrowserTexturesModel.updateModelSelectionState()
|
||||||
|
popup()
|
||||||
|
}
|
||||||
|
|
||||||
|
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Apply to selected model")
|
||||||
|
enabled: root.targetTexture && materialBrowserTexturesModel.hasSingleModelSelection
|
||||||
|
onTriggered: materialBrowserTexturesModel.applyToSelectedModel(root.targetTexture.textureInternalId)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Apply to selected material")
|
||||||
|
enabled: root.targetTexture && materialBrowserModel.selectedIndex >= 0
|
||||||
|
onTriggered: materialBrowserTexturesModel.applyToSelectedMaterial(root.targetTexture.textureInternalId)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Apply as light probe")
|
||||||
|
enabled: root.targetTexture && materialBrowserTexturesModel.hasSceneEnv
|
||||||
|
onTriggered: materialBrowserTexturesModel.applyAsLightProbe(root.targetTexture.textureInternalId)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuSeparator {}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Duplicate")
|
||||||
|
enabled: root.targetTexture
|
||||||
|
onTriggered: materialBrowserTexturesModel.duplicateTexture(materialBrowserTexturesModel.selectedIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Delete")
|
||||||
|
enabled: root.targetTexture
|
||||||
|
onTriggered: materialBrowserTexturesModel.deleteTexture(materialBrowserTexturesModel.selectedIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuSeparator {}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Create New Texture")
|
||||||
|
onTriggered: materialBrowserTexturesModel.addNewTexture()
|
||||||
|
}
|
||||||
|
}
|
@@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuickDesignerTheme
|
import QtQuickDesignerTheme
|
||||||
import HelperWidgets
|
import HelperWidgets
|
||||||
@@ -13,7 +14,8 @@ Rectangle {
|
|||||||
visible: textureVisible
|
visible: textureVisible
|
||||||
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
border.width: materialBrowserTexturesModel.selectedIndex === index ? 1 : 0
|
border.width: materialBrowserTexturesModel.selectedIndex === index
|
||||||
|
? !rootView.materialSectionFocused ? 3 : 1 : 0
|
||||||
border.color: materialBrowserTexturesModel.selectedIndex === index
|
border.color: materialBrowserTexturesModel.selectedIndex === index
|
||||||
? StudioTheme.Values.themeControlOutlineInteraction
|
? StudioTheme.Values.themeControlOutlineInteraction
|
||||||
: "transparent"
|
: "transparent"
|
||||||
@@ -25,8 +27,10 @@ Rectangle {
|
|||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
onPressed: (mouse) => {
|
onPressed: (mouse) => {
|
||||||
|
rootView.focusMaterialSection(false)
|
||||||
materialBrowserTexturesModel.selectTexture(index)
|
materialBrowserTexturesModel.selectTexture(index)
|
||||||
|
|
||||||
if (mouse.button === Qt.LeftButton)
|
if (mouse.button === Qt.LeftButton)
|
||||||
@@ -34,13 +38,32 @@ Rectangle {
|
|||||||
else if (mouse.button === Qt.RightButton)
|
else if (mouse.button === Qt.RightButton)
|
||||||
root.showContextMenu()
|
root.showContextMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDoubleClicked: materialBrowserTexturesModel.openTextureEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
visible: mouseArea.containsMouse
|
||||||
|
// contentWidth is not calculated correctly by the toolTip (resulting in a wider tooltip than
|
||||||
|
// needed). Using a helper Text to calculate the correct width
|
||||||
|
contentWidth: helperText.width
|
||||||
|
bottomInset: -2
|
||||||
|
text: textureToolTip
|
||||||
|
delay: 1000
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: helperText
|
||||||
|
text: textureToolTip
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
source: textureSource
|
source: "image://materialBrowserTex/" + textureSource
|
||||||
|
asynchronous: true
|
||||||
sourceSize.width: root.width - 10
|
sourceSize.width: root.width - 10
|
||||||
sourceSize.height: root.height - 10
|
sourceSize.height: root.height - 10
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
cache: false
|
smooth: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,8 +32,14 @@ PropertyEditorPane {
|
|||||||
height: 150
|
height: 150
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: hasQuick3DImport ? qsTr("There are no materials in this project.<br>Select '<b>+</b>' to create one.")
|
text: {
|
||||||
: qsTr("To use <b>Material Editor</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
if (!hasQuick3DImport)
|
||||||
|
qsTr("To use <b>Material Editor</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
||||||
|
else if (!hasMaterialLibrary)
|
||||||
|
qsTr("<b>Material Editor</b> is disabled inside a non-visual component.")
|
||||||
|
else
|
||||||
|
qsTr("There are no materials in this project.<br>Select '<b>+</b>' to create one.")
|
||||||
|
}
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: StudioTheme.Values.mediumFontSize
|
font.pixelSize: StudioTheme.Values.mediumFontSize
|
||||||
|
@@ -5,7 +5,7 @@ import QtQuick 2.15
|
|||||||
import QtQuickDesignerTheme 1.0
|
import QtQuickDesignerTheme 1.0
|
||||||
import HelperWidgets 2.0
|
import HelperWidgets 2.0
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme 1.0 as StudioTheme
|
||||||
import ToolBarAction 1.0
|
import MaterialToolBarAction 1.0
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
@@ -28,7 +28,7 @@ Rectangle {
|
|||||||
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
iconSize: StudioTheme.Values.bigIconFontSize
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
buttonSize: root.height
|
buttonSize: root.height
|
||||||
enabled: hasMaterial && hasModelSelection && hasQuick3DImport && !hasMaterialRoot
|
enabled: hasMaterial && hasModelSelection && hasQuick3DImport && hasMaterialLibrary
|
||||||
onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
|
onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
|
||||||
tooltip: qsTr("Apply material to selected model.")
|
tooltip: qsTr("Apply material to selected model.")
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ Rectangle {
|
|||||||
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
iconSize: StudioTheme.Values.bigIconFontSize
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
buttonSize: root.height
|
buttonSize: root.height
|
||||||
enabled: hasQuick3DImport && !hasMaterialRoot
|
enabled: hasQuick3DImport && hasMaterialLibrary
|
||||||
onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial)
|
onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial)
|
||||||
tooltip: qsTr("Create new material.")
|
tooltip: qsTr("Create new material.")
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ Rectangle {
|
|||||||
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
iconSize: StudioTheme.Values.bigIconFontSize
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
buttonSize: root.height
|
buttonSize: root.height
|
||||||
enabled: hasMaterial && hasQuick3DImport && !hasMaterialRoot
|
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
|
||||||
onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentMaterial)
|
onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentMaterial)
|
||||||
tooltip: qsTr("Delete current material.")
|
tooltip: qsTr("Delete current material.")
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ Rectangle {
|
|||||||
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
iconSize: StudioTheme.Values.bigIconFontSize
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
buttonSize: root.height
|
buttonSize: root.height
|
||||||
enabled: hasMaterial && hasQuick3DImport && !hasMaterialRoot
|
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
|
||||||
onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
|
onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
|
||||||
tooltip: qsTr("Open material browser.")
|
tooltip: qsTr("Open material browser.")
|
||||||
}
|
}
|
||||||
|
@@ -140,6 +140,7 @@ Column {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
source: "image://materialEditor/preview"
|
source: "image://materialEditor/preview"
|
||||||
cache: false
|
cache: false
|
||||||
|
smooth: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,6 +45,10 @@ Rectangle {
|
|||||||
onWidthChanged: root.responsiveResize(root.width, root.height)
|
onWidthChanged: root.responsiveResize(root.width, root.height)
|
||||||
onHeightChanged: root.responsiveResize(root.width, root.height)
|
onHeightChanged: root.responsiveResize(root.width, root.height)
|
||||||
|
|
||||||
|
function showEvent() {
|
||||||
|
addCanvas.requestPaint()
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: root.responsiveResize(root.width, root.height)
|
Component.onCompleted: root.responsiveResize(root.width, root.height)
|
||||||
|
|
||||||
function numFit(overall, size, space) {
|
function numFit(overall, size, space) {
|
||||||
@@ -258,6 +262,14 @@ Rectangle {
|
|||||||
// the close of the old popup. Using an int keeps track of number of opened popups.
|
// the close of the old popup. Using an int keeps track of number of opened popups.
|
||||||
property int menuOpen: 0
|
property int menuOpen: 0
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: statesEditorModel
|
||||||
|
function onModelReset() {
|
||||||
|
root.menuOpen = 0
|
||||||
|
editDialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This timer is used to delay the current state animation as it didn't work due to the
|
// This timer is used to delay the current state animation as it didn't work due to the
|
||||||
// repeaters item not being positioned in time resulting in 0 x and y position if the grids
|
// repeaters item not being positioned in time resulting in 0 x and y position if the grids
|
||||||
// row and column were not changed during the layout algorithm .
|
// row and column were not changed during the layout algorithm .
|
||||||
@@ -303,15 +315,8 @@ Rectangle {
|
|||||||
standardButtons: Dialog.Apply | Dialog.Cancel
|
standardButtons: Dialog.Apply | Dialog.Cancel
|
||||||
x: editButton.x - Math.max(0, editButton.x + editDialog.width - root.width)
|
x: editButton.x - Math.max(0, editButton.x + editDialog.width - root.width)
|
||||||
y: toolBar.height
|
y: toolBar.height
|
||||||
closePolicy: Popup.NoAutoClose
|
|
||||||
|
|
||||||
width: Math.min(300, root.width)
|
width: Math.min(300, root.width)
|
||||||
|
closePolicy: Popup.NoAutoClose
|
||||||
function apply() {
|
|
||||||
let renamed = statesEditorModel.renameActiveStateGroup(editTextField.text)
|
|
||||||
if (renamed)
|
|
||||||
editDialog.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
onApplied: editDialog.accept()
|
onApplied: editDialog.accept()
|
||||||
|
|
||||||
@@ -541,7 +546,7 @@ Rectangle {
|
|||||||
baseState: true
|
baseState: true
|
||||||
defaultChecked: !statesEditorModel.baseState.modelHasDefaultState // TODO Make this one a model property
|
defaultChecked: !statesEditorModel.baseState.modelHasDefaultState // TODO Make this one a model property
|
||||||
isChecked: root.currentStateInternalId === 0
|
isChecked: root.currentStateInternalId === 0
|
||||||
thumbnailImageSource: statesEditorModel.baseState.stateImageSource // TODO Get rid of the QVariantMap
|
thumbnailImageSource: statesEditorModel.baseState.stateImageSource ?? "" // TODO Get rid of the QVariantMap
|
||||||
isTiny: root.tinyMode
|
isTiny: root.tinyMode
|
||||||
|
|
||||||
onFocusSignal: root.currentStateInternalId = 0
|
onFocusSignal: root.currentStateInternalId = 0
|
||||||
@@ -854,28 +859,29 @@ Rectangle {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: addWrapper
|
id: addWrapper
|
||||||
|
visible: canAddNewStates
|
||||||
|
|
||||||
Canvas {
|
Canvas {
|
||||||
id: addCanvas
|
id: addCanvas
|
||||||
width: root.thumbWidth
|
width: root.thumbWidth
|
||||||
height: root.thumbHeight
|
height: root.thumbHeight
|
||||||
|
|
||||||
|
property int plusExtend: 20
|
||||||
|
property int halfWidth: addCanvas.width / 2
|
||||||
|
property int halfHeight: addCanvas.height / 2
|
||||||
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
var ctx = getContext("2d")
|
var ctx = getContext("2d")
|
||||||
|
|
||||||
ctx.strokeStyle = StudioTheme.Values.themeStateHighlight
|
ctx.strokeStyle = StudioTheme.Values.themeStateHighlight
|
||||||
ctx.lineWidth = 6
|
ctx.lineWidth = 6
|
||||||
|
|
||||||
var plusExtend = 20
|
|
||||||
var halfWidth = addCanvas.width / 2
|
|
||||||
var halfHeight = addCanvas.height / 2
|
|
||||||
|
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(halfWidth, halfHeight - plusExtend)
|
ctx.moveTo(addCanvas.halfWidth, addCanvas.halfHeight - addCanvas.plusExtend)
|
||||||
ctx.lineTo(halfWidth, halfHeight + plusExtend)
|
ctx.lineTo(addCanvas.halfWidth, addCanvas.halfHeight + addCanvas.plusExtend)
|
||||||
|
|
||||||
ctx.moveTo(halfWidth - plusExtend, halfHeight)
|
ctx.moveTo(addCanvas.halfWidth - addCanvas.plusExtend, addCanvas.halfHeight)
|
||||||
ctx.lineTo(halfWidth + plusExtend, halfHeight)
|
ctx.lineTo(addCanvas.halfWidth + addCanvas.plusExtend, addCanvas.halfHeight)
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
|
|
||||||
ctx.save()
|
ctx.save()
|
||||||
|
@@ -15,6 +15,10 @@ PropertyEditorPane {
|
|||||||
showState: true
|
showState: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InsightSection {
|
||||||
|
visible: insightEnabled
|
||||||
|
}
|
||||||
|
|
||||||
DynamicPropertiesSection {
|
DynamicPropertiesSection {
|
||||||
propertiesModel: SelectionDynamicPropertiesModel {}
|
propertiesModel: SelectionDynamicPropertiesModel {}
|
||||||
visible: !hasMultiSelection
|
visible: !hasMultiSelection
|
||||||
|
@@ -59,10 +59,10 @@ StudioControls.ComboBox {
|
|||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property string assetPath: ""
|
property string dropData: ""
|
||||||
|
|
||||||
onEntered: (drag) => {
|
onEntered: (drag) => {
|
||||||
dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0]
|
dropArea.dropData = drag.getDataAsString(drag.keys[0]).split(",")[0]
|
||||||
drag.accepted = comboBox.backendValue !== undefined && comboBox.backendValue.hasActiveDrag
|
drag.accepted = comboBox.backendValue !== undefined && comboBox.backendValue.hasActiveDrag
|
||||||
comboBox.hasActiveHoverDrag = drag.accepted
|
comboBox.hasActiveHoverDrag = drag.accepted
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ StudioControls.ComboBox {
|
|||||||
onExited: comboBox.hasActiveHoverDrag = false
|
onExited: comboBox.hasActiveHoverDrag = false
|
||||||
|
|
||||||
onDropped: {
|
onDropped: {
|
||||||
comboBox.backendValue.commitDrop(dropArea.assetPath)
|
comboBox.backendValue.commitDrop(dropArea.dropData)
|
||||||
comboBox.hasActiveHoverDrag = false
|
comboBox.hasActiveHoverDrag = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,6 +14,7 @@ Rectangle {
|
|||||||
property alias icon: icon.text
|
property alias icon: icon.text
|
||||||
property alias tooltip: toolTip.text
|
property alias tooltip: toolTip.text
|
||||||
property alias iconSize: icon.font.pixelSize
|
property alias iconSize: icon.font.pixelSize
|
||||||
|
property alias containsMouse: mouseArea.containsMouse
|
||||||
|
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
property int buttonSize: StudioTheme.Values.height
|
property int buttonSize: StudioTheme.Values.height
|
||||||
|
@@ -5,7 +5,7 @@ import QtQuick 2.15
|
|||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
import HelperWidgets 2.0
|
import HelperWidgets 2.0
|
||||||
|
|
||||||
MouseArea {
|
ToolTipArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
||||||
property bool allowTooltip: true
|
property bool allowTooltip: true
|
||||||
|
@@ -0,0 +1,88 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
|
Section {
|
||||||
|
id: root
|
||||||
|
caption: qsTr("Analytics")
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
property string defaultItem: qsTr("[None]")
|
||||||
|
|
||||||
|
function addDefaultItem(arr)
|
||||||
|
{
|
||||||
|
var copy = arr.slice()
|
||||||
|
copy.unshift(root.defaultItem)
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionLayout {
|
||||||
|
PropertyLabel { text: qsTr("Category") }
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
|
||||||
|
|
||||||
|
StudioControls.ComboBox {
|
||||||
|
id: comboBox
|
||||||
|
property var backendValue: backendValues.InsightCategory_category
|
||||||
|
property var valueFromBackend: comboBox.backendValue === undefined ? 0 : comboBox.backendValue.value
|
||||||
|
|
||||||
|
onValueFromBackendChanged: comboBox.invalidate()
|
||||||
|
onModelChanged: comboBox.invalidate()
|
||||||
|
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
width: implicitWidth
|
||||||
|
model: root.addDefaultItem(insightCategories)
|
||||||
|
editable: false
|
||||||
|
|
||||||
|
onCompressedActivated: function(index, reason) {
|
||||||
|
if (comboBox.backendValue === undefined)
|
||||||
|
return
|
||||||
|
|
||||||
|
verifyInsightImport()
|
||||||
|
|
||||||
|
if (index === 0)
|
||||||
|
comboBox.backendValue.resetValue()
|
||||||
|
else
|
||||||
|
comboBox.backendValue.value = comboBox.currentText
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: modelNodeBackend
|
||||||
|
function onSelectionToBeChanged() {
|
||||||
|
comboBox.popup.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function invalidate() {
|
||||||
|
var index = comboBox.find(comboBox.valueFromBackend)
|
||||||
|
if (index < 0) {
|
||||||
|
if (comboBox.valueFromBackend === "") {
|
||||||
|
comboBox.currentIndex = 0
|
||||||
|
comboBox.labelColor = StudioTheme.Values.themeTextColor
|
||||||
|
} else {
|
||||||
|
comboBox.currentIndex = index
|
||||||
|
comboBox.editText = comboBox.valueFromBackend
|
||||||
|
comboBox.labelColor = StudioTheme.Values.themeError
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (index !== comboBox.currentIndex)
|
||||||
|
comboBox.currentIndex = index
|
||||||
|
|
||||||
|
comboBox.labelColor = StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component.onCompleted: comboBox.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -13,6 +13,7 @@ Item {
|
|||||||
|
|
||||||
property alias minimumValue: spinBox.realFrom
|
property alias minimumValue: spinBox.realFrom
|
||||||
property alias maximumValue: spinBox.realTo
|
property alias maximumValue: spinBox.realTo
|
||||||
|
property alias value: spinBox.realValue
|
||||||
property alias stepSize: spinBox.realStepSize
|
property alias stepSize: spinBox.realStepSize
|
||||||
|
|
||||||
property alias backendValue: spinBox.backendValue
|
property alias backendValue: spinBox.backendValue
|
||||||
|
@@ -119,9 +119,9 @@ Section {
|
|||||||
text: qsTr("Render type quality")
|
text: qsTr("Render type quality")
|
||||||
tooltip: qsTr("Overrides the default rendering type quality for this component.")
|
tooltip: qsTr("Overrides the default rendering type quality for this component.")
|
||||||
blockedByTemplate: !root.isBackendValueAvailable("renderTypeQuality")
|
blockedByTemplate: !root.isBackendValueAvailable("renderTypeQuality")
|
||||||
enabled: backendValues.renderType !== undefined
|
enabled: root.isBackendValueAvailable("renderTypeQuality")
|
||||||
? backendValues.renderType.enumeration === "QtRendering"
|
&& (backendValues.renderType.value === "QtRendering"
|
||||||
: false
|
|| backendValues.renderType.enumeration === "QtRendering")
|
||||||
}
|
}
|
||||||
|
|
||||||
SecondColumnLayout {
|
SecondColumnLayout {
|
||||||
@@ -134,7 +134,8 @@ Section {
|
|||||||
"HighRenderTypeQuality", "VeryHighRenderTypeQuality"]
|
"HighRenderTypeQuality", "VeryHighRenderTypeQuality"]
|
||||||
backendValue: backendValues.renderTypeQuality
|
backendValue: backendValues.renderTypeQuality
|
||||||
enabled: root.isBackendValueAvailable("renderTypeQuality")
|
enabled: root.isBackendValueAvailable("renderTypeQuality")
|
||||||
&& backendValues.renderType.enumeration === "QtRendering"
|
&& (backendValues.renderType.value === "QtRendering"
|
||||||
|
|| backendValues.renderType.enumeration === "QtRendering")
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpandingSpacer {}
|
ExpandingSpacer {}
|
||||||
|
@@ -102,8 +102,8 @@ Row {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
visible: thumbnail.status === Image.Ready
|
visible: thumbnail.status === Image.Ready
|
||||||
Layout.preferredWidth: 100
|
Layout.preferredWidth: 96
|
||||||
Layout.preferredHeight: 100
|
Layout.preferredHeight: 96
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: checker
|
id: checker
|
||||||
@@ -116,7 +116,10 @@ Row {
|
|||||||
Image {
|
Image {
|
||||||
id: thumbnail
|
id: thumbnail
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
anchors.fill: parent
|
sourceSize.height: 96
|
||||||
|
sourceSize.width: 96
|
||||||
|
height: 96
|
||||||
|
width: 96
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
source: {
|
source: {
|
||||||
if (root.isBuiltInPrimitive(root.absoluteFilePath))
|
if (root.isBuiltInPrimitive(root.absoluteFilePath))
|
||||||
@@ -231,8 +234,8 @@ Row {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
visible: delegateThumbnail.status === Image.Ready
|
visible: delegateThumbnail.status === Image.Ready
|
||||||
Layout.preferredWidth: 100
|
Layout.preferredWidth: 96
|
||||||
Layout.preferredHeight: 100
|
Layout.preferredHeight: 96
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: delegateChecker
|
id: delegateChecker
|
||||||
@@ -245,7 +248,10 @@ Row {
|
|||||||
Image {
|
Image {
|
||||||
id: delegateThumbnail
|
id: delegateThumbnail
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
anchors.fill: parent
|
sourceSize.height: 96
|
||||||
|
sourceSize.width: 96
|
||||||
|
height: 96
|
||||||
|
width: 96
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
source: {
|
source: {
|
||||||
if (root.isBuiltInPrimitive(delegateRoot.name))
|
if (root.isBuiltInPrimitive(delegateRoot.name))
|
||||||
|
@@ -42,6 +42,7 @@ IconButton 2.0 IconButton.qml
|
|||||||
IconLabel 2.0 IconLabel.qml
|
IconLabel 2.0 IconLabel.qml
|
||||||
ImagePreviewTooltipArea 2.0 ImagePreviewTooltipArea.qml
|
ImagePreviewTooltipArea 2.0 ImagePreviewTooltipArea.qml
|
||||||
ImageSection 2.0 ImageSection.qml
|
ImageSection 2.0 ImageSection.qml
|
||||||
|
InsightSection 2.0 InsightSection.qml
|
||||||
ItemFilterComboBox 2.0 ItemFilterComboBox.qml
|
ItemFilterComboBox 2.0 ItemFilterComboBox.qml
|
||||||
Label 2.0 Label.qml
|
Label 2.0 Label.qml
|
||||||
LineEdit 2.0 LineEdit.qml
|
LineEdit 2.0 LineEdit.qml
|
||||||
|
@@ -57,7 +57,7 @@ TextInput {
|
|||||||
myControl.focus = false
|
myControl.focus = false
|
||||||
} else {
|
} else {
|
||||||
myControl.popup.open()
|
myControl.popup.open()
|
||||||
myControl.forceActiveFocus()
|
//myControl.forceActiveFocus()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
textInput.forceActiveFocus()
|
textInput.forceActiveFocus()
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
import QtQuick %{QtQuickVersion}
|
import QtQuick %{QtQuickVersion}
|
||||||
|
@if !%{IsQt6Project}
|
||||||
|
import QtQuick.Window %{QtQuickVersion}
|
||||||
|
@endif
|
||||||
import %{ApplicationImport}
|
import %{ApplicationImport}
|
||||||
@if %{UseVirtualKeyboard}
|
@if %{UseVirtualKeyboard}
|
||||||
import QtQuick.VirtualKeyboard %{QtQuickVersion}
|
import QtQuick.VirtualKeyboard %{QtQuickVersion}
|
||||||
|
@@ -299,6 +299,10 @@
|
|||||||
"source": "../common/qmlmodules.tpl",
|
"source": "../common/qmlmodules.tpl",
|
||||||
"target": "%{ProjectDirectory}/qmlmodules"
|
"target": "%{ProjectDirectory}/qmlmodules"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/qmlcomponents.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/qmlcomponents"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/main.qml",
|
"source": "../common/main.qml",
|
||||||
"target": "%{ProjectDirectory}/main.qml"
|
"target": "%{ProjectDirectory}/main.qml"
|
||||||
@@ -319,6 +323,11 @@
|
|||||||
"source": "../common/import_qml_plugins.h.tpl",
|
"source": "../common/import_qml_plugins.h.tpl",
|
||||||
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/import_qml_components_plugins.h.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/src/import_qml_components_plugins.h"
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"source": "../common/CMakeLists.content.txt.tpl",
|
"source": "../common/CMakeLists.content.txt.tpl",
|
||||||
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
||||||
|
@@ -295,6 +295,10 @@
|
|||||||
"source": "../common/qmlmodules.tpl",
|
"source": "../common/qmlmodules.tpl",
|
||||||
"target": "%{ProjectDirectory}/qmlmodules"
|
"target": "%{ProjectDirectory}/qmlmodules"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/qmlcomponents.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/qmlcomponents"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/main.qml",
|
"source": "../common/main.qml",
|
||||||
"target": "%{ProjectDirectory}/main.qml"
|
"target": "%{ProjectDirectory}/main.qml"
|
||||||
@@ -315,6 +319,10 @@
|
|||||||
"source": "../common/import_qml_plugins.h.tpl",
|
"source": "../common/import_qml_plugins.h.tpl",
|
||||||
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/import_qml_components_plugins.h.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/src/import_qml_components_plugins.h"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/CMakeLists.content.txt.tpl",
|
"source": "../common/CMakeLists.content.txt.tpl",
|
||||||
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
||||||
|
@@ -2,7 +2,9 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0
|
||||||
|
|
||||||
import QtQuick %{QtQuickVersion}
|
import QtQuick %{QtQuickVersion}
|
||||||
|
@if !%{IsQt6Project}
|
||||||
import QtQuick.Window %{QtQuickVersion}
|
import QtQuick.Window %{QtQuickVersion}
|
||||||
|
@endif
|
||||||
import %{ImportModuleName} %{ImportModuleVersion}
|
import %{ImportModuleName} %{ImportModuleVersion}
|
||||||
@if %{UseVirtualKeyboard}
|
@if %{UseVirtualKeyboard}
|
||||||
import QtQuick.VirtualKeyboard %{QtQuickVersion}
|
import QtQuick.VirtualKeyboard %{QtQuickVersion}
|
||||||
|
@@ -1,24 +1,37 @@
|
|||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.21.1)
|
||||||
|
|
||||||
|
set(BUILD_QDS_COMPONENTS ON CACHE BOOL "Build design studio components")
|
||||||
|
|
||||||
project(%{ProjectName}App LANGUAGES CXX)
|
project(%{ProjectName}App LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS Gui Qml Quick)
|
find_package(QT NAMES Qt6 COMPONENTS Gui Qml Quick)
|
||||||
qt_add_executable(%{ProjectExecutableName} src/main.cpp)
|
find_package(Qt6 REQUIRED COMPONENTS Core Qml Quick)
|
||||||
|
|
||||||
qt_add_resources(%{ProjectExecutableName} "configuration"
|
qt_add_executable(${CMAKE_PROJECT_NAME} src/main.cpp)
|
||||||
|
|
||||||
|
# qt_standard_project_setup() requires Qt 6.3 or higher. See https://doc.qt.io/qt-6/qt-standard-project-setup.html for details.
|
||||||
|
if (${QT_VERSION_MINOR} GREATER_EQUAL 3)
|
||||||
|
qt6_standard_project_setup()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qt_add_resources(${CMAKE_PROJECT_NAME} "configuration"
|
||||||
PREFIX "/"
|
PREFIX "/"
|
||||||
FILES
|
FILES
|
||||||
qtquickcontrols2.conf
|
qtquickcontrols2.conf
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(%{ProjectExecutableName} PRIVATE
|
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
Qt${QT_VERSION_MAJOR}::Gui
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
Qt${QT_VERSION_MAJOR}::Quick
|
Qt${QT_VERSION_MAJOR}::Quick
|
||||||
Qt${QT_VERSION_MAJOR}::Qml
|
Qt${QT_VERSION_MAJOR}::Qml
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (${BUILD_QDS_COMPONENTS})
|
||||||
|
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents)
|
||||||
|
endif ()
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
|
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
|
||||||
|
@@ -100,7 +100,7 @@ Project {
|
|||||||
/* Required for deployment */
|
/* Required for deployment */
|
||||||
targetDirectory: "/opt/%{ProjectName}"
|
targetDirectory: "/opt/%{ProjectName}"
|
||||||
|
|
||||||
qdsVersion: "3.8"
|
qdsVersion: "3.9"
|
||||||
|
|
||||||
quickVersion: "%{QtQuickVersion}"
|
quickVersion: "%{QtQuickVersion}"
|
||||||
|
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
import QtQuick %{QtQuickVersion}
|
import QtQuick %{QtQuickVersion}
|
||||||
|
@if !%{IsQt6Project}
|
||||||
|
import QtQuick.Window %{QtQuickVersion}
|
||||||
|
@endif
|
||||||
import %{ApplicationImport}
|
import %{ApplicationImport}
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
|
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* This file is automatically generated by Qt Design Studio.
|
||||||
|
* Do not change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qqmlextensionplugin.h"
|
||||||
|
|
||||||
|
#ifdef BULD_QDS_COMPONENTS
|
||||||
|
|
||||||
|
Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ComponentsPlugin)
|
||||||
|
Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EffectsPlugin)
|
||||||
|
Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ApplicationPlugin)
|
||||||
|
Q_IMPORT_QML_PLUGIN(FlowViewPlugin)
|
||||||
|
Q_IMPORT_QML_PLUGIN(QtQuick_Studio_LogicHelperPlugin)
|
||||||
|
Q_IMPORT_QML_PLUGIN(QtQuick_Studio_MultiTextPlugin)
|
||||||
|
Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSimulatorPlugin)
|
||||||
|
Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSystemPlugin)
|
||||||
|
|
||||||
|
#endif
|
@@ -5,6 +5,7 @@
|
|||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
#include "app_environment.h"
|
#include "app_environment.h"
|
||||||
|
#include "import_qml_components_plugins.h"
|
||||||
#include "import_qml_plugins.h"
|
#include "import_qml_plugins.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@@ -0,0 +1,33 @@
|
|||||||
|
### This file is automatically generated by Qt Design Studio.
|
||||||
|
### Do not change
|
||||||
|
|
||||||
|
message("Building designer components.")
|
||||||
|
|
||||||
|
set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml")
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
ds
|
||||||
|
GIT_TAG qds-3.9
|
||||||
|
GIT_REPOSITORY https://code.qt.io/qt-labs/qtquickdesigner-components.git
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_GetProperties(ds)
|
||||||
|
FetchContent_Populate(ds)
|
||||||
|
|
||||||
|
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
|
||||||
|
QuickStudioComponentsplugin
|
||||||
|
QuickStudioEffectsplugin
|
||||||
|
QuickStudioApplicationplugin
|
||||||
|
FlowViewplugin
|
||||||
|
QuickStudioLogicHelperplugin
|
||||||
|
QuickStudioMultiTextplugin
|
||||||
|
QuickStudioEventSimulatorplugin
|
||||||
|
QuickStudioEventSystemplugin
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(${ds_SOURCE_DIR} ${ds_BINARY_DIR})
|
||||||
|
|
||||||
|
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
|
||||||
|
BULD_QDS_COMPONENTS=true
|
||||||
|
)
|
@@ -1,7 +1,7 @@
|
|||||||
### This file is automatically generated by Qt Design Studio.
|
### This file is automatically generated by Qt Design Studio.
|
||||||
### Do not change
|
### Do not change
|
||||||
|
|
||||||
qt6_add_qml_module(%{ProjectExecutableName}
|
qt6_add_qml_module(${CMAKE_PROJECT_NAME}
|
||||||
URI "Main"
|
URI "Main"
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
NO_PLUGIN
|
NO_PLUGIN
|
||||||
@@ -11,7 +11,7 @@ qt6_add_qml_module(%{ProjectExecutableName}
|
|||||||
add_subdirectory(content)
|
add_subdirectory(content)
|
||||||
add_subdirectory(imports)
|
add_subdirectory(imports)
|
||||||
|
|
||||||
target_link_libraries(%{ProjectExecutableName} PRIVATE
|
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
|
||||||
contentplugin
|
contentplugin
|
||||||
%{ProjectPluginName}
|
%{ProjectPluginName}
|
||||||
)
|
)
|
||||||
|
@@ -293,6 +293,10 @@
|
|||||||
"source": "../common/qmlmodules.tpl",
|
"source": "../common/qmlmodules.tpl",
|
||||||
"target": "%{ProjectDirectory}/qmlmodules"
|
"target": "%{ProjectDirectory}/qmlmodules"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/qmlcomponents.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/qmlcomponents"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/main.qml",
|
"source": "../common/main.qml",
|
||||||
"target": "%{ProjectDirectory}/main.qml"
|
"target": "%{ProjectDirectory}/main.qml"
|
||||||
@@ -313,6 +317,10 @@
|
|||||||
"source": "../common/import_qml_plugins.h.tpl",
|
"source": "../common/import_qml_plugins.h.tpl",
|
||||||
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/import_qml_components_plugins.h.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/src/import_qml_components_plugins.h"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/CMakeLists.content.txt.tpl",
|
"source": "../common/CMakeLists.content.txt.tpl",
|
||||||
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
||||||
|
@@ -252,6 +252,10 @@
|
|||||||
"source": "../common/qmlmodules.tpl",
|
"source": "../common/qmlmodules.tpl",
|
||||||
"target": "%{ProjectDirectory}/qmlmodules"
|
"target": "%{ProjectDirectory}/qmlmodules"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/qmlcomponents.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/qmlcomponents"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/main.qml",
|
"source": "../common/main.qml",
|
||||||
"target": "%{ProjectDirectory}/main.qml"
|
"target": "%{ProjectDirectory}/main.qml"
|
||||||
@@ -272,6 +276,10 @@
|
|||||||
"source": "../common/import_qml_plugins.h.tpl",
|
"source": "../common/import_qml_plugins.h.tpl",
|
||||||
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/import_qml_components_plugins.h.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/src/import_qml_components_plugins.h"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/CMakeLists.content.txt.tpl",
|
"source": "../common/CMakeLists.content.txt.tpl",
|
||||||
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
import QtQuick %{QtQuickVersion}
|
import QtQuick %{QtQuickVersion}
|
||||||
import QtQuick.Controls %{QtQuickVersion}
|
import QtQuick.Controls %{QtQuickVersion}
|
||||||
|
@if !%{IsQt6Project}
|
||||||
|
import QtQuick.Window %{QtQuickVersion}
|
||||||
|
@endif
|
||||||
import %{ImportModuleName} %{ImportModuleVersion}
|
import %{ImportModuleName} %{ImportModuleVersion}
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
|
@@ -249,6 +249,10 @@
|
|||||||
"source": "../common/qmlmodules.tpl",
|
"source": "../common/qmlmodules.tpl",
|
||||||
"target": "%{ProjectDirectory}/qmlmodules"
|
"target": "%{ProjectDirectory}/qmlmodules"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/qmlcomponents.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/qmlcomponents"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/main.qml",
|
"source": "../common/main.qml",
|
||||||
"target": "%{ProjectDirectory}/main.qml"
|
"target": "%{ProjectDirectory}/main.qml"
|
||||||
@@ -269,6 +273,10 @@
|
|||||||
"source": "../common/import_qml_plugins.h.tpl",
|
"source": "../common/import_qml_plugins.h.tpl",
|
||||||
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/import_qml_components_plugins.h.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/src/import_qml_components_plugins.h"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "CMakeLists.content.txt.tpl",
|
"source": "CMakeLists.content.txt.tpl",
|
||||||
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
import QtQuick %{QtQuickVersion}
|
import QtQuick %{QtQuickVersion}
|
||||||
import QtQuick.Controls %{QtQuickVersion}
|
import QtQuick.Controls %{QtQuickVersion}
|
||||||
|
@if !%{IsQt6Project}
|
||||||
|
import QtQuick.Window %{QtQuickVersion}
|
||||||
|
@endif
|
||||||
import %{ImportModuleName} %{ImportModuleVersion}
|
import %{ImportModuleName} %{ImportModuleVersion}
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
|
@@ -249,6 +249,10 @@
|
|||||||
"source": "../common/qmlmodules.tpl",
|
"source": "../common/qmlmodules.tpl",
|
||||||
"target": "%{ProjectDirectory}/qmlmodules"
|
"target": "%{ProjectDirectory}/qmlmodules"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/qmlcomponents.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/qmlcomponents"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "../common/main.qml",
|
"source": "../common/main.qml",
|
||||||
"target": "%{ProjectDirectory}/main.qml"
|
"target": "%{ProjectDirectory}/main.qml"
|
||||||
@@ -269,6 +273,10 @@
|
|||||||
"source": "../common/import_qml_plugins.h.tpl",
|
"source": "../common/import_qml_plugins.h.tpl",
|
||||||
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
"target": "%{ProjectDirectory}/src/import_qml_plugins.h"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "../common/import_qml_components_plugins.h.tpl",
|
||||||
|
"target": "%{ProjectDirectory}/src/import_qml_components_plugins.h"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "CMakeLists.content.txt.tpl",
|
"source": "CMakeLists.content.txt.tpl",
|
||||||
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
"target": "%{ProjectDirectory}/content/CMakeLists.txt"
|
||||||
|
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQuickDesignerTheme 1.0
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
|
PropertyEditorPane {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
signal toolBarAction(int action)
|
||||||
|
|
||||||
|
// Called from C++, dummy method to avoid warnings
|
||||||
|
function closeContextMenu() {}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: col
|
||||||
|
|
||||||
|
TextureEditorToolBar {
|
||||||
|
width: root.width
|
||||||
|
|
||||||
|
onToolBarAction: (action) => root.toolBarAction(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: root.width - 2 * col.padding
|
||||||
|
height: 150
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: {
|
||||||
|
if (!hasQuick3DImport)
|
||||||
|
qsTr("To use <b>Texture Editor</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
||||||
|
else if (!hasMaterialLibrary)
|
||||||
|
qsTr("<b>Texture Editor</b> is disabled inside a non-visual component.")
|
||||||
|
else
|
||||||
|
qsTr("There are no textures in this project.<br>Select '<b>+</b>' to create one.")
|
||||||
|
}
|
||||||
|
textFormat: Text.RichText
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
font.pixelSize: StudioTheme.Values.mediumFontSize
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: root.width
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuickDesignerTheme 1.0
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
|
||||||
|
PropertyEditorPane {
|
||||||
|
id: itemPane
|
||||||
|
|
||||||
|
signal toolBarAction(int action)
|
||||||
|
|
||||||
|
// invoked from C++ to refresh material preview image
|
||||||
|
function refreshPreview()
|
||||||
|
{
|
||||||
|
topSection.refreshPreview()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called also from C++ to close context menu on focus out
|
||||||
|
function closeContextMenu()
|
||||||
|
{
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureEditorTopSection {
|
||||||
|
id: topSection
|
||||||
|
|
||||||
|
onToolBarAction: (action) => itemPane.toolBarAction(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { width: 1; height: 10 }
|
||||||
|
|
||||||
|
DynamicPropertiesSection {
|
||||||
|
propertiesModel: TextureEditorDynamicPropertiesModel {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: specificsTwo
|
||||||
|
|
||||||
|
property string theSource: specificQmlData
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
visible: theSource !== ""
|
||||||
|
sourceComponent: specificQmlComponent
|
||||||
|
|
||||||
|
onTheSourceChanged: {
|
||||||
|
active = false
|
||||||
|
active = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: 1
|
||||||
|
height: 10
|
||||||
|
visible: specificsTwo.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: specificsOne
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
source: specificsUrl
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuickDesignerTheme 1.0
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
import TextureToolBarAction 1.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
color: StudioTheme.Values.themeSectionHeadBackground
|
||||||
|
width: row.width
|
||||||
|
height: 40
|
||||||
|
|
||||||
|
signal toolBarAction(int action)
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
leftPadding: 6
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.applyMaterialToSelected
|
||||||
|
|
||||||
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
|
buttonSize: root.height
|
||||||
|
enabled: hasTexture && hasSingleModelSelection && hasQuick3DImport && hasMaterialLibrary
|
||||||
|
onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
|
||||||
|
tooltip: qsTr("Apply texture to selected model's material.")
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.newMaterial
|
||||||
|
|
||||||
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
|
buttonSize: root.height
|
||||||
|
enabled: hasQuick3DImport && hasMaterialLibrary
|
||||||
|
onClicked: root.toolBarAction(ToolBarAction.AddNewTexture)
|
||||||
|
tooltip: qsTr("Create new texture.")
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.deleteMaterial
|
||||||
|
|
||||||
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
|
buttonSize: root.height
|
||||||
|
enabled: hasTexture && hasQuick3DImport && hasMaterialLibrary
|
||||||
|
onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentTexture)
|
||||||
|
tooltip: qsTr("Delete current texture.")
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.openMaterialBrowser
|
||||||
|
|
||||||
|
normalColor: StudioTheme.Values.themeSectionHeadBackground
|
||||||
|
iconSize: StudioTheme.Values.bigIconFontSize
|
||||||
|
buttonSize: root.height
|
||||||
|
enabled: hasQuick3DImport && hasMaterialLibrary
|
||||||
|
onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
|
||||||
|
tooltip: qsTr("Open material browser.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
signal toolBarAction(int action)
|
||||||
|
|
||||||
|
function refreshPreview()
|
||||||
|
{
|
||||||
|
texturePreview.source = ""
|
||||||
|
texturePreview.source = "image://qmldesigner_thumbnails/" + resolveResourcePath(backendValues.source.valueToString)
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
TextureEditorToolBar {
|
||||||
|
width: root.width
|
||||||
|
|
||||||
|
onToolBarAction: (action) => root.toolBarAction(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { width: 1; height: 10 } // spacer
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: previewRect
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: 152
|
||||||
|
height: 152
|
||||||
|
color: "#000000"
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: texturePreview
|
||||||
|
asynchronous: true
|
||||||
|
sourceSize.width: 150
|
||||||
|
sourceSize.height: 150
|
||||||
|
anchors.centerIn: parent
|
||||||
|
source: "image://qmldesigner_thumbnails/" + resolveResourcePath(backendValues.source.valueToString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -525,7 +525,7 @@ Export::Export(ImportKey exportName,
|
|||||||
|
|
||||||
bool Export::visibleInVContext(const ViewerContext &vContext) const
|
bool Export::visibleInVContext(const ViewerContext &vContext) const
|
||||||
{
|
{
|
||||||
return pathRequired.isEmpty() || vContext.paths.contains(pathRequired);
|
return pathRequired.isEmpty() || vContext.paths.count(pathRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreImport::CoreImport() : language(Dialect::Qml) { }
|
CoreImport::CoreImport() : language(Dialect::Qml) { }
|
||||||
|
@@ -126,7 +126,8 @@ Link::Link(const Snapshot &snapshot, const ViewerContext &vContext, const Librar
|
|||||||
{
|
{
|
||||||
d->m_valueOwner = new ValueOwner;
|
d->m_valueOwner = new ValueOwner;
|
||||||
d->m_snapshot = snapshot;
|
d->m_snapshot = snapshot;
|
||||||
d->m_importPaths = vContext.paths;
|
const QList<Utils::FilePath> list(vContext.paths.begin(), vContext.paths.end());
|
||||||
|
d->m_importPaths = list;
|
||||||
d->m_applicationDirectories = vContext.applicationDirectories;
|
d->m_applicationDirectories = vContext.applicationDirectories;
|
||||||
d->m_builtins = builtins;
|
d->m_builtins = builtins;
|
||||||
d->m_vContext = vContext;
|
d->m_vContext = vContext;
|
||||||
|
@@ -63,8 +63,8 @@ static const char *qtQuickUISuffix = "ui.qml";
|
|||||||
|
|
||||||
static void maybeAddPath(ViewerContext &context, const Utils::FilePath &path)
|
static void maybeAddPath(ViewerContext &context, const Utils::FilePath &path)
|
||||||
{
|
{
|
||||||
if (!path.isEmpty() && !context.paths.contains(path))
|
if (!path.isEmpty() && !(context.paths.count(path) > 0))
|
||||||
context.paths.append(path);
|
context.paths.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<Utils::FilePath> environmentImportPaths()
|
static QList<Utils::FilePath> environmentImportPaths()
|
||||||
|
@@ -188,6 +188,9 @@ public:
|
|||||||
void removeProjectInfo(ProjectExplorer::Project *project);
|
void removeProjectInfo(ProjectExplorer::Project *project);
|
||||||
void maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc);
|
void maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc);
|
||||||
|
|
||||||
|
QFuture<void> refreshSourceFiles(const QList<Utils::FilePath> &sourceFiles,
|
||||||
|
bool emitDocumentOnDiskChanged);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void documentUpdated(QmlJS::Document::Ptr doc);
|
void documentUpdated(QmlJS::Document::Ptr doc);
|
||||||
void documentChangedOnDisk(QmlJS::Document::Ptr doc);
|
void documentChangedOnDisk(QmlJS::Document::Ptr doc);
|
||||||
@@ -207,9 +210,6 @@ protected:
|
|||||||
virtual void addTaskInternal(const QFuture<void> &result, const QString &msg,
|
virtual void addTaskInternal(const QFuture<void> &result, const QString &msg,
|
||||||
const char *taskId) const;
|
const char *taskId) const;
|
||||||
|
|
||||||
QFuture<void> refreshSourceFiles(const QList<Utils::FilePath> &sourceFiles,
|
|
||||||
bool emitDocumentOnDiskChanged);
|
|
||||||
|
|
||||||
static void parseLoop(QSet<Utils::FilePath> &scannedPaths,
|
static void parseLoop(QSet<Utils::FilePath> &scannedPaths,
|
||||||
QSet<Utils::FilePath> &newLibraries,
|
QSet<Utils::FilePath> &newLibraries,
|
||||||
const WorkingCopy &workingCopyInternal,
|
const WorkingCopy &workingCopyInternal,
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace QmlJS {
|
namespace QmlJS {
|
||||||
|
|
||||||
struct QMLJS_EXPORT ViewerContext
|
struct QMLJS_EXPORT ViewerContext
|
||||||
@@ -21,7 +23,7 @@ struct QMLJS_EXPORT ViewerContext
|
|||||||
};
|
};
|
||||||
|
|
||||||
QStringList selectors;
|
QStringList selectors;
|
||||||
QList<Utils::FilePath> paths;
|
std::set<Utils::FilePath> paths;
|
||||||
QList<Utils::FilePath> applicationDirectories;
|
QList<Utils::FilePath> applicationDirectories;
|
||||||
Dialect language = Dialect::Qml;
|
Dialect language = Dialect::Qml;
|
||||||
Flags flags = AddAllPaths;
|
Flags flags = AddAllPaths;
|
||||||
|
@@ -421,6 +421,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/components/itemlibrary
|
${CMAKE_CURRENT_LIST_DIR}/components/itemlibrary
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/materialbrowser
|
${CMAKE_CURRENT_LIST_DIR}/components/materialbrowser
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/materialeditor
|
${CMAKE_CURRENT_LIST_DIR}/components/materialeditor
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/components/textureeditor
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/navigator
|
${CMAKE_CURRENT_LIST_DIR}/components/navigator
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor
|
${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/stateseditor
|
${CMAKE_CURRENT_LIST_DIR}/components/stateseditor
|
||||||
@@ -594,6 +595,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
PUBLIC_INCLUDES components
|
PUBLIC_INCLUDES components
|
||||||
DEFINES QMLDESIGNERCOMPONENTS_LIBRARY
|
DEFINES QMLDESIGNERCOMPONENTS_LIBRARY
|
||||||
SOURCES
|
SOURCES
|
||||||
|
createtexture.cpp createtexture.h
|
||||||
qmldesignercomponents_global.h
|
qmldesignercomponents_global.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -623,6 +625,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
selectioncontext.cpp selectioncontext.h
|
selectioncontext.cpp selectioncontext.h
|
||||||
theme.cpp theme.h
|
theme.cpp theme.h
|
||||||
zoomaction.cpp zoomaction.h
|
zoomaction.cpp zoomaction.h
|
||||||
|
anchoraction.cpp anchoraction.h
|
||||||
svgpasteaction.cpp svgpasteaction.h
|
svgpasteaction.cpp svgpasteaction.h
|
||||||
viewmanager.cpp viewmanager.h
|
viewmanager.cpp viewmanager.h
|
||||||
)
|
)
|
||||||
@@ -746,9 +749,6 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
assetslibrarywidget.cpp assetslibrarywidget.h
|
assetslibrarywidget.cpp assetslibrarywidget.h
|
||||||
assetslibrarymodel.cpp assetslibrarymodel.h
|
assetslibrarymodel.cpp assetslibrarymodel.h
|
||||||
assetslibraryiconprovider.cpp assetslibraryiconprovider.h
|
assetslibraryiconprovider.cpp assetslibraryiconprovider.h
|
||||||
assetslibrarydir.cpp assetslibrarydir.h
|
|
||||||
assetslibrarydirsmodel.cpp assetslibrarydirsmodel.h
|
|
||||||
assetslibraryfilesmodel.cpp assetslibraryfilesmodel.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
@@ -821,6 +821,17 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
materialeditor.qrc
|
materialeditor.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
extend_qtc_plugin(QmlDesigner
|
||||||
|
SOURCES_PREFIX components/textureeditor
|
||||||
|
SOURCES
|
||||||
|
textureeditorcontextobject.cpp textureeditorcontextobject.h
|
||||||
|
textureeditordynamicpropertiesproxymodel.cpp textureeditordynamicpropertiesproxymodel.h
|
||||||
|
textureeditorqmlbackend.cpp textureeditorqmlbackend.h
|
||||||
|
textureeditortransaction.cpp textureeditortransaction.h
|
||||||
|
textureeditorview.cpp textureeditorview.h
|
||||||
|
textureeditor.qrc
|
||||||
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
SOURCES_PREFIX components/materialbrowser
|
SOURCES_PREFIX components/materialbrowser
|
||||||
SOURCES
|
SOURCES
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/AssetsLibrary">
|
<qresource prefix="/AssetsLibrary">
|
||||||
<file>images/asset_default.png</file>
|
|
||||||
<file>images/asset_default@2x.png</file>
|
|
||||||
<file>images/asset_shader.png</file>
|
<file>images/asset_shader.png</file>
|
||||||
<file>images/asset_shader@2x.png</file>
|
<file>images/asset_shader@2x.png</file>
|
||||||
<file>images/asset_shader_128.png</file>
|
<file>images/asset_shader_128.png</file>
|
||||||
@@ -10,7 +8,16 @@
|
|||||||
<file>images/asset_sound_128.png</file>
|
<file>images/asset_sound_128.png</file>
|
||||||
<file>images/asset_video.png</file>
|
<file>images/asset_video.png</file>
|
||||||
<file>images/asset_video@2x.png</file>
|
<file>images/asset_video@2x.png</file>
|
||||||
|
<file>images/asset_effectClass.png</file>
|
||||||
|
<file>images/asset_effectClass@2x.png</file>
|
||||||
|
<file>images/asset_effectExported.png</file>
|
||||||
|
<file>images/asset_effectExported@2x.png</file>
|
||||||
<file>images/browse.png</file>
|
<file>images/browse.png</file>
|
||||||
<file>images/browse@2x.png</file>
|
<file>images/browse@2x.png</file>
|
||||||
|
<file>images/assets_default.png</file>
|
||||||
|
<file>images/assets_default@2x.png</file>
|
||||||
|
<file>images/assets_default_128.png</file>
|
||||||
|
<file>images/asset_effectClass_128.png</file>
|
||||||
|
<file>images/asset_effectExported_128.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -1,75 +0,0 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "assetslibrarydir.h"
|
|
||||||
#include "assetslibrarydirsmodel.h"
|
|
||||||
#include "assetslibraryfilesmodel.h"
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
AssetsLibraryDir::AssetsLibraryDir(const QString &path, int depth, bool expanded, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_dirPath(path)
|
|
||||||
, m_dirDepth(depth)
|
|
||||||
, m_dirExpanded(expanded)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AssetsLibraryDir::dirName() const { return m_dirPath.split('/').last(); }
|
|
||||||
QString AssetsLibraryDir::dirPath() const { return m_dirPath; }
|
|
||||||
int AssetsLibraryDir::dirDepth() const { return m_dirDepth; }
|
|
||||||
bool AssetsLibraryDir::dirExpanded() const { return m_dirExpanded; }
|
|
||||||
bool AssetsLibraryDir::dirVisible() const { return m_dirVisible; }
|
|
||||||
|
|
||||||
void AssetsLibraryDir::setDirExpanded(bool expand)
|
|
||||||
{
|
|
||||||
if (m_dirExpanded != expand) {
|
|
||||||
m_dirExpanded = expand;
|
|
||||||
emit dirExpandedChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsLibraryDir::setDirVisible(bool visible)
|
|
||||||
{
|
|
||||||
if (m_dirVisible != visible) {
|
|
||||||
m_dirVisible = visible;
|
|
||||||
emit dirVisibleChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QObject *AssetsLibraryDir::filesModel() const
|
|
||||||
{
|
|
||||||
return m_filesModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
QObject *AssetsLibraryDir::dirsModel() const
|
|
||||||
{
|
|
||||||
return m_dirsModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<AssetsLibraryDir *> AssetsLibraryDir::childAssetsDirs() const
|
|
||||||
{
|
|
||||||
if (m_dirsModel)
|
|
||||||
return m_dirsModel->assetsDirs();
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsLibraryDir::addDir(AssetsLibraryDir *assetsDir)
|
|
||||||
{
|
|
||||||
if (!m_dirsModel)
|
|
||||||
m_dirsModel = new AssetsLibraryDirsModel(this);
|
|
||||||
|
|
||||||
m_dirsModel->addDir(assetsDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsLibraryDir::addFile(const QString &filePath)
|
|
||||||
{
|
|
||||||
if (!m_filesModel)
|
|
||||||
m_filesModel = new AssetsLibraryFilesModel(this);
|
|
||||||
|
|
||||||
m_filesModel->addFile(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,63 +0,0 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
class AssetsLibraryDirsModel;
|
|
||||||
class AssetsLibraryFilesModel;
|
|
||||||
|
|
||||||
class AssetsLibraryDir : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
Q_PROPERTY(QString dirName READ dirName NOTIFY dirNameChanged)
|
|
||||||
Q_PROPERTY(QString dirPath READ dirPath NOTIFY dirPathChanged)
|
|
||||||
Q_PROPERTY(bool dirExpanded READ dirExpanded WRITE setDirExpanded NOTIFY dirExpandedChanged)
|
|
||||||
Q_PROPERTY(bool dirVisible READ dirVisible WRITE setDirVisible NOTIFY dirVisibleChanged)
|
|
||||||
Q_PROPERTY(int dirDepth READ dirDepth NOTIFY dirDepthChanged)
|
|
||||||
Q_PROPERTY(QObject *filesModel READ filesModel NOTIFY filesModelChanged)
|
|
||||||
Q_PROPERTY(QObject *dirsModel READ dirsModel NOTIFY dirsModelChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
AssetsLibraryDir(const QString &path, int depth, bool expanded = true, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
QString dirName() const;
|
|
||||||
QString dirPath() const;
|
|
||||||
int dirDepth() const;
|
|
||||||
|
|
||||||
bool dirExpanded() const;
|
|
||||||
bool dirVisible() const;
|
|
||||||
void setDirExpanded(bool expand);
|
|
||||||
void setDirVisible(bool visible);
|
|
||||||
|
|
||||||
QObject *filesModel() const;
|
|
||||||
QObject *dirsModel() const;
|
|
||||||
|
|
||||||
QList<AssetsLibraryDir *> childAssetsDirs() const;
|
|
||||||
|
|
||||||
void addDir(AssetsLibraryDir *assetsDir);
|
|
||||||
void addFile(const QString &filePath);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void dirNameChanged();
|
|
||||||
void dirPathChanged();
|
|
||||||
void dirDepthChanged();
|
|
||||||
void dirExpandedChanged();
|
|
||||||
void dirVisibleChanged();
|
|
||||||
void filesModelChanged();
|
|
||||||
void dirsModelChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_dirPath;
|
|
||||||
int m_dirDepth = 0;
|
|
||||||
bool m_dirExpanded = true;
|
|
||||||
bool m_dirVisible = true;
|
|
||||||
AssetsLibraryDirsModel *m_dirsModel = nullptr;
|
|
||||||
AssetsLibraryFilesModel *m_filesModel = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,71 +0,0 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "assetslibrarydirsmodel.h"
|
|
||||||
#include "assetslibrarymodel.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QMetaProperty>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
AssetsLibraryDirsModel::AssetsLibraryDirsModel(QObject *parent)
|
|
||||||
: QAbstractListModel(parent)
|
|
||||||
{
|
|
||||||
// add roles
|
|
||||||
const QMetaObject meta = AssetsLibraryDir::staticMetaObject;
|
|
||||||
for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
|
|
||||||
m_roleNames.insert(i, meta.property(i).name());
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant AssetsLibraryDirsModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid()) {
|
|
||||||
qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_roleNames.contains(role))
|
|
||||||
return m_dirs[index.row()]->property(m_roleNames[role]);
|
|
||||||
|
|
||||||
qWarning() << Q_FUNC_INFO << "Invalid role requested: " << QString::number(role);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetsLibraryDirsModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
||||||
{
|
|
||||||
// currently only dirExpanded property is updatable
|
|
||||||
if (index.isValid() && m_roleNames.contains(role)) {
|
|
||||||
QVariant currValue = m_dirs.at(index.row())->property(m_roleNames.value(role));
|
|
||||||
if (currValue != value) {
|
|
||||||
m_dirs.at(index.row())->setProperty(m_roleNames.value(role), value);
|
|
||||||
if (m_roleNames.value(role) == "dirExpanded")
|
|
||||||
AssetsLibraryModel::saveExpandedState(value.toBool(), m_dirs.at(index.row())->dirPath());
|
|
||||||
emit dataChanged(index, index, {role});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AssetsLibraryDirsModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return m_dirs.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> AssetsLibraryDirsModel::roleNames() const
|
|
||||||
{
|
|
||||||
return m_roleNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsLibraryDirsModel::addDir(AssetsLibraryDir *assetsDir)
|
|
||||||
{
|
|
||||||
m_dirs.append(assetsDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QList<AssetsLibraryDir *> AssetsLibraryDirsModel::assetsDirs() const
|
|
||||||
{
|
|
||||||
return m_dirs;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|