Merge "Merge remote-tracking branch 'origin/qds/dev'"

This commit is contained in:
The Qt Project
2024-05-29 08:10:42 +00:00
436 changed files with 16128 additions and 15947 deletions

View File

@@ -1,6 +1,6 @@
set(IDE_VERSION "4.5.0") # The IDE version. set(IDE_VERSION "4.6.0") # The IDE version.
set(IDE_VERSION_COMPAT "4.5.0") # The IDE Compatibility version. set(IDE_VERSION_COMPAT "4.6.0") # The IDE Compatibility version.
set(IDE_VERSION_DISPLAY "4.5.0") # The IDE display version. set(IDE_VERSION_DISPLAY "4.6.0") # The IDE display version.
set(IDE_COPYRIGHT_YEAR "2024") # The IDE current copyright year. set(IDE_COPYRIGHT_YEAR "2024") # The IDE current copyright year.
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.

View File

@@ -19,6 +19,7 @@ macro.ouml.HTML = "ö"
macro.B2Q = "Boot to Qt" macro.B2Q = "Boot to Qt"
macro.Q3DS = "Qt 3D Studio" macro.Q3DS = "Qt 3D Studio"
macro.QA = "Qt Assistant" macro.QA = "Qt Assistant"
macro.QAC = "Qt Academy"
macro.QB = "Qt Bridge" macro.QB = "Qt Bridge"
macro.QBPS = "Qt Bridge for Adobe Photoshop" macro.QBPS = "Qt Bridge for Adobe Photoshop"
macro.QBXD = "Qt Bridge for Adobe XD" macro.QBXD = "Qt Bridge for Adobe XD"

View File

@@ -82,7 +82,7 @@
\uicontrol {Reset Code Model} to reset the code model. \uicontrol {Reset Code Model} to reset the code model.
\if defined(qtdesignstudio) \if defined(qtdesignstudio)
For more information about how to show the \uicontrol {Tools} menu, see For more information about how to show the \uicontrol {Tools} menu, see
\l{Customizing the Menu}. \l{Customizing the Menu Bar}.
\endif \endif
\if defined(qtcreator) \if defined(qtcreator)

View File

@@ -1,18 +1,109 @@
<div class="sectionlist normallist">
<ul>
<li><a href="qtdesignstudio-toc.html">View All Topics</a></li>
</ul>
</div>
<div class="sectionlist normallist"> <div class="sectionlist normallist">
<div class="heading"> <div class="heading">
<a name="reference"></a> <h2>Getting Started</h2>
<h2 id="reference">Qt Design Studio Manual</h2>
</div> </div>
<div class="indexboxcont indexboxbar"> <div class="indexboxcont indexboxbar">
<ul> <ul>
<li><a href="qtdesignstudio-toc.html">All Topics</a></li> <li><a href="studio-getting-started.html">Overview</a></li>
<li><a href="studio-getting-started.html">Getting Started</a></li> <li><a href="studio-installation.html">Installing Qt Design Studio</a></li>
<li><a href="quick-uis.html">Wireframing</a></li> <li><a href="gstutorials.html">Tutorials</a></li>
<li><a href="qtquick-prototyping.html">Prototyping</a></li> <li><a href="creator-quick-tour.html">User Interface</a></li>
<li><a href="qtquick-motion-design.html">Motion Design</a></li> <li><a href="studio-projects.html">Creating Projects</a></li>
<li><a href="studio-implementing-applications.html">Implementing Applications</a></li> <li><a href="studio-use-cases.html">Use Cases</a></li>
<li><a href="studio-advanced.html">Advanced Designer Topics</a></li> <li><a href="studio-terms.html">Concepts and Terms</a></li>
<li><a href="studio-developer-topics.html">Developer Topics</a></li> <li><a href="best-practices.html">Best Practices</a></li>
<li><a href="studio-help.html">Help</a></li> <li><a href="studioexamples.html">Examples</a></li>
</ul>
</div>
</div>
<div class="sectionlist normallist">
<div class="heading">
<h2>Wireframing</h2>
</div>
<div class="indexboxcont indexboxbar">
<ul>
<li><a href="quick-uis.html">Overview</a></li>
<li><a href="studio-app-flows.html">Designing Application Flows</a></li>
<li><a href="quick-components.html">Using Components</a></li>
<li><a href="qtquick-properties.html">Specifying Component Properties</a></li>
<li><a href="qtquick-positioning.html">Scalable Layouts</a></li>
<li><a href="qtquick-annotations.html">Annotating Designs</a></li>
</ul>
</div>
</div>
<div class="sectionlist normallist">
<div class="heading">
<h2>Prototyping</h2>
</div>
<ul>
<li><a href="qtquick-prototyping.html">Overview</a></li>
<li><a href="qtquick-creating-ui-logic.html">Creating UI Logic</a></li>
<li><a href="studio-simulation-overview.html">Simulating Complex Experiences</a></li>
<li><a href="qtquick-adding-dynamics.html">Dynamic Behaviors</a></li>
<li><a href="creator-live-preview.html">Validating with Target Hardware</a></li>
<li><a href="studio-exporting-and-importing.html">Asset Creation with Other Tools</a></li>
</ul>
</div>
<div class="sectionlist normallist">
<div class="heading">
<h2>Motion Design</h2>
</div>
<ul>
<li><a href="qtquick-motion-design.html">Overview</a></li>
<li><a href="quick-animation-overview.html">Introduction to Animation Techniques</a></li>
<li><a href="studio-timeline.html">Creating Timeline Animations</a></li>
<li><a href="qtquick-editing-easing-curves.html">Editing Easing Curves</a></li>
<li><a href="qtquick-production-quality-animation.html">Production Quality</a></li>
<li><a href="qtquick-optimizing-designs.html">Optimizing Designs</a></li>
</ul>
</div>
<div class="sectionlist normallist">
<div class="heading">
<h2>Implementing Applications</h2>
</div>
<ul>
<li><a href="studio-implementing-applications.html">Overview</a></li>
<li><a href="studio-designer-developer-workflow.html">Designer-Developer Workflow</a></li>
<li><a href="qtquick-text-editor.html">Coding</a></li>
<li><a href="studio-debugging.html">Debugging and Profiling</a></li>
</ul>
</div>
<div class="sectionlist normallist">
<div class="heading">
<h2>Advanced Designer Topics</h2>
</div>
<ul>
<li><a href="studio-advanced.html">Overview</a></li>
<li><a href="creator-quick-ui-forms.html">UI Files</a></li>
<li><a href="creator-telemetry.html">Manage Data Collection</a></li>
<li><a href="studio-packaging.html">Packaging Applications</a></li>
</ul>
</div>
<div class="sectionlist normallist">
<div class="heading">
<h2>Developer Topics</h2>
</div>
<ul>
<li><a href="studio-developer-topics.html">Overview</a></li>
<li><a href="creator-vcs-git.html">Using Git</a></li>
<li><a href="studio-porting-projects.html">Converting Qt 5 Projects into Qt 6 Projects</a></li>
<li><a href="quick-converting-ui-projects.html">Converting UI Projects to Applications</a></li>
<li><a href="creator-editor-external.html">Using External Tools</a></li>
<li><a href="studio-on-mcus.html">Qt Design Studio on MCUs</a></li>
</ul>
</div>
<div class="sectionlist normallist">
<div class="heading">
<h2>Help</h2>
</div>
<ul>
<li><a href="studio-help.html">Overview</a></li>
<li><a href="creator-how-to-get-help.html">Getting Help</a></li>
<li><a href="studio-platforms.html">Supported Platforms</a></li>
</ul> </ul>
</div> </div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@@ -0,0 +1,200 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\previouspage best-practices.html
\page best-practices-glow.html
\nextpage {Examples}
\title Creating Glow and Bloom Effects
In \QDS, you can add a glow and bloom effect to your 3D scene using the
\uicontrol ExtendedSceneEnvironment component (available in Qt 6.5 and later). With this effect,
you can, for example, create glow around illuminated areas (such as material or skyboxes when
using image-based lighting) or add ambient light. Using the glow effect is one way to make your
scene more realistic.
\image glow-example.webp
\section1 Creating a Project with ExtendedSceneEnvironment
To create a project with \uicontrol ExtendedSceneEnvironment as the default
scene environment, use the \uicontrol {3D Extended} project preset.
For more information about creating projects, see \l{Creating Projects}.
\section1 Adding ExtendedSceneEnvironment to an Existing Project
To add \uicontrol {ExtendedSceneEnvironment} to an existing project, drag the
\uicontrol {ExtendedSceneEnvironment} component from \uicontrol Components to
the \uicontrol 2D or \uicontrol Navigator view.
\image ext-scene-env-navigator.webp
\section1 Enabling the Glow Effect
To enable the glow effect, select \e SceneEnvironment in the \uicontrol Navigator view and
then, in the \uicontrol Properties view, select \uicontrol Enabled in the
\uicontrol Glow section.
\image glow-properties.webp
\note When setting up or experimenting with the glow effect, use the \l {Blend Modes}{Replace}
blend mode to see the effect more clearly.
\section1 The Flashlight Example Project
The flashlight example used in this documentation is available from the \uicontrol Examples
section of the \QDS \uicontrol Welcome page.
You can use the project to experiment with the \uicontrol Glow properties. When you run the
project, you can control most properties with UI controls. Another way to experiment with
properties is to change them directly in the \uicontrol Properties view in \QDS and see the
changes live in the \uicontrol 2D view.
\image glow-example-project.webp
\section1 Basic Properties
Usually, the best way to achieve a realistic glow effect in your 3D scene is to adjust
the \uicontrol {Strength}, \uicontrol {Intensity}, and \uicontrol {Bloom}
properties together.
\section2 Strength
Sets the strength of the glow. If this property has a 0 value, the glow effect is disabled. The
strength is a scale factor (multiplier) applied per level. This means that
with more levels enabled in \l {Blur Levels}, a larger \uicontrol {strength} value has
a more pronounced effect.
\section2 Intensity
Sets the intensity of the glow. The intensity is effectively a scale factor (multiplier) for the
accumulated glow color (including all levels).
\section2 Bloom
Sets the overall illumination of the whole scene.
\section2 Lower Threshold
Sets the minimum level of brightness for the glow.
\section2 Upper Threshold
Sets the maximum level of brightness for the glow.
\section2 HDR Scale
Sets how much the glow bleeds (or extends) beyond the borders of bright areas
in the scene. The range for this property is 0-8. As seen in the example images below, a high
value gives a very modest bleed, while a low number results in a much more visible bleed.
\table
\header
\li HDR Scale
\li Example
\row
\li Bloom disabled
\li \image bleed-scale-no.webp
\row
\li 8
\li \image bleed-scale-8.webp
\row
\li 1
\li \image bleed-scale-1.webp
\endtable
\section1 Blur Levels
Sets which of the blur passes to apply to the glow effect.
The higher the level is, the more the glow effect spreads around the light source,
and the softer the glow is.
As seen in the example image below, lower blur levels produce an intense glow within a limited
area, while higher blur levels produce a softer glow in a more extensive area. Combine blur
levels to get the desired result.
\table
\header
\li Blur level
\li Example
\row
\li 1, 2, 3
\li \image glow_low_blur_levels.webp
\row
\li 5, 6, 7
\li \image glow_high_blur_levels.webp
\row
\li 1, 2, 3, 4, 5, 6, 7
\li \image glow_all_blur_levels.webp
\endtable
\section2 Blend Modes
The following blend modes are available:
\table
\header
\li Blend mode
\li Description
\li Example
\row
\li Additive
\li Often recommended for outdoor scenes with a visible sky or sun.
\li \image glow-additive-blend.webp
\row
\li Screen
\li Similar to \uicontrol {Additive}, but the result is less bright.
\li \image glow-screen-blend.webp
\row
\li SoftLight
\li Often recommended for in-door environments.
\li \image glow-softlight-blend.webp
\row
\li Replace
\li Does not perform any blending, but displays only the contribution
the glow effect would blend with the actual content. In practice, this is useful for
experimenting and troubleshooting when setting up the glow effect.
\li \image glow-replace-blend.webp
\endtable
\section1 Improvement Properties
The \uicontrol{High Quality} and \uicontrol{Bicubical Upsampling}
properties improve the quality of the glow blur by upsampling. Using these properties
may slow down the performance of the application. You can also try using the
\uicontrol Dithering property in the \uicontrol sceneEnvironment instead. In some cases,
\uicontrol Dithering renders a similar result but at a lower cost.
\section2 High Quality
Increases the samples used for the glow when downsampling to improve the quality of the glow
effect.
\section2 Bicubical Upsampling
Reduces the aliasing artifacts and boxing in the glow effect.
\section2 Examples
These examples show a zoomed-in image of each effect:
\table
\header
\li Effect
\li Example
\row
\li No effect
\li \image glow-no-enhancment.webp
\row
\li High Quality
\li \image glow-high-quality.webp
\row
\li Bicubic Upsampling
\li \image glow-bicubic.webp
\endtable
*/

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\previouspage studio-terms.html
\page best-practices.html
\nextpage best-practices-glow.html
\title Best Practices
\section1 Graphics
\list
\li \l {Creating Glow and Bloom Effects}
\endlist
\section1 Performance
\list
\li \l {Optimizing Designs}
\li \l {QML Performance Considerations And Suggestions}
\li \l {Creating Optimized 3D Scenes}
\li \l {Using Components Economically}
\endlist
\section1 Projects
\list
\li \l {Converting Qt 5 Projects into Qt 6 Projects}
\li \l {Converting UI Projects to Applications}
\endlist
\section1 Workflow
\list
\li \l {Designer-Developer Workflow}
\endlist
*/

View File

@@ -44,6 +44,9 @@
If you need to display animated images, such as GIFs, use the If you need to display animated images, such as GIFs, use the
\l {Animated Image} component. \l {Animated Image} component.
\note Currently, the supported image formats include JPEG, JPG, PNG, SVG,
HDR, KTX, BMP, TTF, TIFF, WEBP, and GIF.
\section1 Image Size \section1 Image Size
\image qtquick-designer-image-properties.png "Image properties" \image qtquick-designer-image-properties.png "Image properties"

View File

@@ -31,6 +31,7 @@
\li \l {UI Controls} \li \l {UI Controls}
\li \l {Lists and Other Data Models} \li \l {Lists and Other Data Models}
\li \l {2D Effects} \li \l {2D Effects}
\li \l {Design Effects}
\li \l {Logic Helpers} \li \l {Logic Helpers}
\li \l Animations \li \l Animations
\endlist \endlist

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! /*!
@@ -19,10 +19,6 @@
other files that are needed to implement the application logic and to other files that are needed to implement the application logic and to
prepare the application for production. prepare the application for production.
Use the \l{Using Git}{Git} version control system to ensure that changes
are not lost when files are passed back and forth between designers and
developers.
\QDS \l{Creating Projects}{projects} come with boilerplate code for a \QDS \l{Creating Projects}{projects} come with boilerplate code for a
working Qt 6 application that you can build and run in Qt Creator using working Qt 6 application that you can build and run in Qt Creator using
CMake. Therefore, you can open, build, and run the projects with Qt Creator. CMake. Therefore, you can open, build, and run the projects with Qt Creator.
@@ -31,58 +27,53 @@
\e CMakeLists.txt file as the project file. This enables you to share \e CMakeLists.txt file as the project file. This enables you to share
your project as a fully working C++ application with developers. your project as a fully working C++ application with developers.
If you use Git, you can clone an example project To export a \QDS project for Qt Creator, you need:
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/playground/AuroraCluster0}
{here}. \list
\li Qt Creator 13.0 or above.
\li \QDS 4.5 or above.
\endlist
\section1 Exporting a \QDS Project \section1 Exporting a \QDS Project
\QDS uses a different project format than Qt Creator. \QDS does not build the project,
it uses a pre-compiled \l{QML runtime} to run the project. To export a \QDS project for the
Qt Creator, follow the process:
\list 1 \list 1
\li Open the project you want to export in \QDS. \li \l {Creating a Project} {Create} or open your \QDS project with \QDS 4.5 or above.
\li Select \uicontrol {File} > \uicontrol {Export Project} > \uicontrol {Generate CMake Build Files}.
\image studio-project-export.webp "Export the \QDS project for Qt Creator"
\li Select \uicontrol {Details} to access the \uicontrol {Advanced Options}. \note If you are creating a new project in \QDS, select the
\image studio-project-export-advanced.webp "Access Advanced Options in the project exporter" \uicontrol {Target Qt Version} that is not higher than the Qt version
used in your Qt Creator.
\note The project exporter has default settings selected. This works better if the project \li Go to \uicontrol {File} > \uicontrol {Export Project}
is combined with an existing Qt project. > \uicontrol {Enable Automatic CMake Generation}. This creates a
\e {CMakeLists.txt} file in your project folder.
\li Select all the options here. This allows to export the \note Enabling this option tracks the changes made to the project in Qt Creator
complete project. So, it can be compiled as a stand-alone application. and automatically updates in \QDS. The connection works unless you
\image studio-project-export-advanced-options.webp "Select all the options in the project exporter" deactivate the option.
\note If you copy this export on top of the existing Qt Creator project \image studio-project-export.webp "Exporting Qt Design Studio project"
it overwrites the existing project. Hence, the default selected options in
the exporter only exports the QML-specific items. You get a list of
warnings at the bottom part of the exporter that denotes exactly which parts
of the project gets overwritten.
\endlist \endlist
\section1 Using the Exported Project in Qt Creator \section1 Opening the \QDS Project in Qt Creator
After exporting the project from the \QDS, you have to open it from Qt Creator. Open the \e {CMakeLists.txt} file in Qt Creator. To open:
If you have used any version before \QDS 4.0 to create the project, manually include this code \list 1
in the \e {CMakeLists.txt} file so the exported project works in Qt Creator. \li In Qt Creator, select \uicontrol File > \uicontrol {Open File or Project}.
\li Browse through your project directory and select the \e {CMakeLists.txt}.
Then select \uicontrol Open.
\code \image studio-project-cmake-generation.webp "Project folder after CMake generation"
set(BUILD_QDS_COMPONENTS ON CACHE BOOL "Build design studio components")
set(CMAKE_INCLUDE_CURRENT_DIR ON) \li Select the Qt version and then \uicontrol {Configure Project}.
if (${BUILD_QDS_COMPONENTS}) \note If your \QDS project was created with a more updated Qt than the one
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents) available in Qt Creator, the import doesn't work. Use
endif () \l {Get and Install Qt with Qt Online Installer} {Qt Online Installer}
to install the latest Qt version. If successfully opened, all the files are
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules) accessible in the \uicontrol Projects view.
\endcode
\note If you have created the project with the \QDS version 4.0 or above, you already have this code in
\e {CMakeLists.txt} by default.
\image qtcreator-qt-design-studio-project.webp "Qt Design studio projects in Qt Creator after successful import"
\li To run the project, select \uicontrol Run.
\endlist
*/ */

View File

@@ -24,9 +24,12 @@
\uicontrol {Preview File}. \uicontrol {Preview File}.
\endlist \endlist
To preview the whole UI, select \uicontrol {Live Preview} To preview the whole application, select \uicontrol {Live Preview}
when viewing the main QML file of the project. when viewing the main QML file of the project.
To preview the application in a different zoom level, right-click the \uicontrol {Live Preview}
button and select the zoom level.
\section1 Overriding the Preview Tool \section1 Overriding the Preview Tool
By default, the QML runtime is used for previewing. By default, the QML runtime is used for previewing.

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
// Note: The \page value is hard-coded as a link in Qt Bridge for Figma. // Note: The \page value is hard-coded as a link in Qt Bridge for Figma.
@@ -29,5 +29,9 @@
To get the best results when you use \QBF to export designs from To get the best results when you use \QBF to export designs from
Figma, you should follow the guidelines for working with Figma and Figma, you should follow the guidelines for working with Figma and
organizing your assets. organizing your assets.
\endlist \endlist
\include qtdesignstudio-qt-academy.qdocinc qt-academy-using-qt-bridge-for-figma
*/ */

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! /*!
@@ -25,4 +25,6 @@
\endlist \endlist
You can launch the installed Figma plugin from \uicontrol Plugins > \uicontrol {\QBF} in Figma. You can launch the installed Figma plugin from \uicontrol Plugins > \uicontrol {\QBF} in Figma.
\include qtdesignstudio-qt-academy.qdocinc qt-academy-using-qt-bridge-for-figma
*/ */

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! /*!
@@ -247,4 +247,6 @@
\uicontrol Home tab) to default values. This means that you \uicontrol Home tab) to default values. This means that you
will lose all your changes to the settings. will lose all your changes to the settings.
\endtable \endtable
\include qtdesignstudio-qt-academy.qdocinc qt-academy-using-qt-bridge-for-figma
*/ */

View File

@@ -8,25 +8,25 @@
\title Designing Application Flows \title Designing Application Flows
\image studio-flow-view.png "Application flow in the 2D view" \image studio-flow-view.webp "Application flow in the 2D view"
In \QDS, a \e {flow view} represents a schematic diagram. It consists of In \QDS, a \e {flow view} represents a schematic diagram. It consists of
\e {flow items} that represent the screens in the UI and \e {transition \e {flow items} that represent the screens in the UI and \e {transition
lines} that connect them, thus illustrating the possible user pathways lines} that connect them, thus illustrating the possible user pathways
through the UI. You use \e {action areas} as starting points for transition through the UI. \e {Action areas} are clickable starting points for transition
lines. You can attach effects to transition lines, such as fade or push, lines. Attach effects to transition lines, such as fade or push,
to determine what users see when one flow item changes into another. to determine what users see when one flow item changes into another.
You can use \e {flow decisions} to set up alternative pathways between Use \e {flow decisions} to set up alternative pathways between flow items in the UI. For
flow items in the UI. For example, if user input determines which flow item example, if user input determines which flow item should open next, test the different
should open next, you can test the different scenarios in the prototype scenarios in the prototype with the decision dialog where you can select which flow item to
by having a dialog pop up where you can select which flow item to show next. show next.
Especially on mobile and embedded platforms, the application might need to Especially on mobile and embedded platforms, the application might need to
react to external events from the platform, such as notifications or other react to external events from the platform, such as notifications or other
applications requiring the users' attention. You can use \e {flow wildcards} applications requiring the users' attention. Use \e {flow wildcards}
to determine the priority of flow items by adding them to positive and to determine the priority of flow items by adding them to allow and
negative lists. block lists.
To design application flows: To design application flows:
@@ -40,14 +40,17 @@
\l{Adding Flow Items}. \l{Adding Flow Items}.
\li Use context menu commands to add action areas and transitions, \li Use context menu commands to add action areas and transitions,
as described in \l{Adding Action Areas and Transitions}. as described in \l{Adding Action Areas and Transitions}.
\endlist
Additionally, to create a more advanced application flow:
\list
\li Use context menu commands to apply effects to transitions, \li Use context menu commands to apply effects to transitions,
as described in \l{Applying Effects to Transitions}. as described in \l{Applying Effects to Transitions}.
\li When you are ready for production, use the event list simulator \li Use the event list simulator to replace transition lines with connections to real
to replace transition lines with connections to real signals signals from UI controls, as described in \l{Simulating Events}.
from UI controls, as described in \l{Simulating Events}. \li Use \uicontrol {Flow Decision} components from \uicontrol Components > \uicontrol {Flow
\li To set up alternative pathways between flow items, use View} to set up alternative pathways between flow items, as described in
\uicontrol {Flow Decision} components from
\uicontrol Components > \uicontrol {Flow View}, as described in
\l{Simulating Conditions}. \l{Simulating Conditions}.
\li Use \l{Working with States}{states} in flows to modify the appearance \li Use \l{Working with States}{states} in flows to modify the appearance
of components on screens in response to user interaction, as of components on screens in response to user interaction, as
@@ -256,8 +259,9 @@
\li Drag the action area to the UI control that you want to connect \li Drag the action area to the UI control that you want to connect
to the other flow item. For example, to a button that opens another to the other flow item. For example, to a button that opens another
flow item when clicked. flow item when clicked.
\li Double-click the action area and drag the transition line to the \li Double-click the action area and drag the transition line to the flow item you want to
flow item you want to connect to. connect to. Alternatively, select the action area, right-click it to open the
context-menu, and then select \uicontrol Connect and the flow item from the list.
\li In \l Properties, modify the properties of the action area \li In \l Properties, modify the properties of the action area
and transition line. and transition line.
\endlist \endlist
@@ -376,13 +380,13 @@
\title Applying Effects to Transitions \title Applying Effects to Transitions
You can apply effects, such as fade, move, or push to You can apply effects, such as fade, move, or push, to
\l{Adding Action Areas and Transitions}{transitions} between \l{Adding Action Areas and Transitions}{transitions} between
\l{Adding Flow Items}{flow items}. A fade effect makes the first \l{Adding Flow Items}{flow items}. A fade effect makes the first
flow item appear to fade out, while the next flow item fades in. flow item appear to fade out, while the next flow item fades in.
A move effect makes the second flow item appear to move in over the A move effect makes the second flow item appear to move in over the
first flow item, while the push effect appears to make a flow item first flow item. The push effect makes a flow item appear to push out the previous one.
push out the previous one. You can also design and use custom effects. You can also use your own custom effects that you have created with some other tool.
The transition direction determines the direction the new flow item appears The transition direction determines the direction the new flow item appears
from: left, right, top, bottom. You can set the duration of the effect and from: left, right, top, bottom. You can set the duration of the effect and
@@ -392,34 +396,42 @@
\list 1 \list 1
\li Select a transition line in the \l {2D} view. \li Select a transition line in the \l {2D} view.
\li In the context menu, select \uicontrol {Flow} > \li Right-click the transition line to open the context menu, select \uicontrol {Flow} >
\uicontrol {Assign Flow Effects}, and then select the effect \uicontrol {Flow Effects}, and then select the effect to apply.
to apply.
\li In \l Properties, modify the properties of the effect. \li In \l Properties, modify the properties of the effect.
\endlist \endlist
To edit effect properties later, select a transition, and then select To edit effect properties later, select a transition, open the context menu, and then select
\uicontrol {Flow} > \uicontrol {Select Effect} in the context menu. \uicontrol {Flow} > \uicontrol {Select Effect}.
To use your own custom effects, select a transition, open the context menu, and then select
\uicontrol {Flow} > \uicontrol {Flow Effects} > \uicontrol {Assign Custom FlowEffect}.
Then specify the path to your custom effect file.
To remove the current effect from a transition, select a transition, open the context menu,
and then select \uicontrol {Flow} > \uicontrol {Flow Effects} >
\uicontrol {Assign FlowEffect None}.
\section1 Flow Effect Properties \section1 Flow Effect Properties
You can specify basic properties for a \uicontrol {Flow Effect} Specify basic properties for a \uicontrol {Flow Effect} component in the \l Type and
component in the \l Type and \l ID fields in the \uicontrol Component \l ID fields in the \uicontrol Component section in the \uicontrol Properties view.
section in the \uicontrol Properties view.
\image studio-flow-effect-properties.png "Flow Effect properties" \image studio-flow-effect-properties.png "Flow Effect properties"
You can set the duration and easing curve of all flow effects: Set the duration and easing curve of flow effects in the \uicontrol {Transition Effect}
section:
\list \list
\li In the \uicontrol Duration field, specify the duration of the \li In the \uicontrol Duration field, specify the duration of the
effect. effect.
\li Select the \inlineimage icons/curve_editor.png \li Select the \inlineimage icons/curve_editor.png
button to open \uicontrol {Easing Curve Editor} for attaching an button to open \uicontrol {Easing Curve Editor} to attach an
\l{Editing Easing Curves}{easing curve} to the effect. \l{Editing Easing Curves}{easing curve} to the effect.
\endlist \endlist
For a move or push effect, you can set some additional properties: Set some additional properties for a move or push effect in the \uicontrol {Push Effect}
or \uicontrol {Move Effect} section:
\image studio-flow-effect-push-properties.png "Flow Push Effect properties" \image studio-flow-effect-push-properties.png "Flow Push Effect properties"
@@ -470,9 +482,8 @@
\li In the \uicontrol {Event List} dialog, select \inlineimage icons/plus.png \li In the \uicontrol {Event List} dialog, select \inlineimage icons/plus.png
to add a keyboard shortcut for triggering an event to the list. to add a keyboard shortcut for triggering an event to the list.
\image studio-flow-event-list.png "Event List dialog" \image studio-flow-event-list.png "Event List dialog"
\li In the \uicontrol {Event ID} field, enter an identifier for the \li In the \uicontrol {Event ID} field, enter an identifier for the event. To search
event. You can search for existing events by entering search for existing events, enter search criteria in the \uicontrol Filter field.
criteria in the \uicontrol Filter field.
\li In the \uicontrol Description field, describe the keyboard shortcut. \li In the \uicontrol Description field, describe the keyboard shortcut.
\li In the \uicontrol Shortcut field, press the keyboard key that will \li In the \uicontrol Shortcut field, press the keyboard key that will
trigger the event, and then select \uicontrol R to record the trigger the event, and then select \uicontrol R to record the
@@ -486,24 +497,22 @@
To assign events to actions: To assign events to actions:
\list 1 \list 1
\li Select \uicontrol eventListSimulator in \uicontrol Navigator, and in
\uicontrol Properties > \uicontrol {Exposed Custom Properties}, select the
\uicontrol active checkbox. If \uicontrol eventListSimulator is not visible
in the \uicontrol Navigator, select \inlineimage icons/visibilityon.png.
\li In \uicontrol Navigator, select an action area or transition line. \li In \uicontrol Navigator, select an action area or transition line.
\li In the context menu, select \uicontrol {Event List} > \li In the context menu, select \uicontrol {Event List} >
\uicontrol {Assign Events to Actions}. \uicontrol {Assign Events to Actions}.
\image studio-flow-events-assign.png "Assign Events to Actions dialog" \image studio-flow-events-assign.webp "Assign Events to Actions dialog"
\li In the \uicontrol ID field, select a transition or an action area
\inlineimage icons/flow-action-icon.png
. You can search for events by entering search criteria in the
\uicontrol Filter field.
\li To connect an event, select \uicontrol Connect next to an event in \li To connect an event, select \uicontrol Connect next to an event in
the list. To release a connected event, select \uicontrol Release. the list. To release a connected event, select \uicontrol Release.
\li Press \key {Alt+P} to preview the UI. \li Press \key {Alt+P} to preview the UI.
\li Select action areas in the preview, double-click events in the \li Select action areas in the preview, double-click events in the
event list, or use the keyboard shortcuts to trigger events. event list, or use the keyboard shortcuts to trigger events.
\image studio-flow-decision-preview.png "Event list in preview" \image studio-flow-events-event-list.webp "Event list in Live Preview"
\endlist \endlist
If the event triggers a \l{Simulating Conditions}{flow decision}, you
can select the path to take to the next flow item.
*/ */
/*! /*!
@@ -525,17 +534,17 @@
controls, backend, or sensor data that will be required for the production controls, backend, or sensor data that will be required for the production
version. version.
\image studio-flow-decision.png "Flow Decision in the 2D view" \image studio-flow-decision.webp "Flow Decision in the 2D view"
To simulate conditions: To simulate conditions:
\list 1 \list 1
\li Drag a \uicontrol {Flow Decision} component from \li Drag a \uicontrol {Flow Decision} component from
\uicontrol Components \uicontrol {Flow View} to a \uicontrol Components > \uicontrol {Flow View} to a
\l{Adding Flow Views}{flow view} in the \l Navigator or \l {2D} view. \l{Adding Flow Views}{flow view} in the \l Navigator or \l {2D} view.
\li Select the flow item where you want the application to start in \li Select the flow item where you want the application to start in
the \uicontrol Navigator or \uicontrol {2D} view, and then select the \uicontrol Navigator or \uicontrol {2D} view. Then right-click the component
\uicontrol {Flow} > \uicontrol {Set Flow Start} in the context menu. to open the context menu, and select \uicontrol Flow > \uicontrol {Set Flow Start}.
\li Create an \l{Adding Action Areas and Transitions}{action area} for \li Create an \l{Adding Action Areas and Transitions}{action area} for
the component that will trigger the condition and connect it to the the component that will trigger the condition and connect it to the
flow decision. flow decision.
@@ -546,10 +555,10 @@
title for the selection dialog that opens when the condition is title for the selection dialog that opens when the condition is
triggered. triggered.
\li Select a transition line in the \uicontrol Navigator or \li Select a transition line in the \uicontrol Navigator or
\uicontrol {2D} view and add a descriptive text in the \uicontrol {2D} view, and add a descriptive text in the
\uicontrol {Question} field in \uicontrol Properties to represent \uicontrol {Question} field in \uicontrol Properties to represent
a choice in the selection dialog. a choice in the selection dialog.
\image studio-flow-transition-properties-question.png "Flow Transition properties" \image studio-flow-transition-properties-question.webp "Flow Transition properties"
\li Press \key {Alt+P} to preview the UI. \li Press \key {Alt+P} to preview the UI.
\li Select action areas in the preview, double-click events in the \li Select action areas in the preview, double-click events in the
event list, or use the keyboard shortcuts to trigger events. event list, or use the keyboard shortcuts to trigger events.
@@ -558,21 +567,21 @@
Flow decisions are listed in a dialog where you can select which condition Flow decisions are listed in a dialog where you can select which condition
is met to see the results. is met to see the results.
\image studio-flow-decision-preview.png "Selection dialog for flow decision" \image studio-flow-decision-preview.webp "Selection dialog for flow decision"
\section1 Flow Decision Properties \section1 Flow Decision Properties
You can specify basic properties for a \uicontrol {Flow Decision} component Specify basic properties for a \uicontrol {Flow Decision} component
in the \l Type and \l ID fields in the \uicontrol Component section in the in the \l Type and \l ID fields in the \uicontrol Component section in the
\uicontrol Properties view. Specify properties for flow decisions in the \uicontrol Properties view. Specify properties for flow decisions in the
\uicontrol {Flow Decision} section. \uicontrol {Flow Decision} section.
\image studio-flow-decision-properties.png "Flow Decision properties" \image studio-flow-decision-properties.webp "Flow Decision properties"
In the \uicontrol {Dialog title} field, enter a title for the selection In the \uicontrol {Dialog title} field, enter a title for the selection
dialog that opens when the condition is triggered. dialog that opens when the condition is triggered.
You can specify the following properties to change the appearance of the Specify the following properties to change the appearance of the
flow decision icon \inlineimage icons/flow-decision-icon.png flow decision icon \inlineimage icons/flow-decision-icon.png
: :
@@ -582,14 +591,14 @@
component in the \l {2D} view. component in the \l {2D} view.
\li In the \uicontrol {Label position} field, select the corner of \li In the \uicontrol {Label position} field, select the corner of
the flow decision icon to place the label in. the flow decision icon to place the label in.
\li Use the \l{Picking Colors}{color picker} to set \uicontrol {Outline color} and
\uicontrol {Fill color} of the flow decision icon.
\li In the \uicontrol Size field, specify the size of the flow \li In the \uicontrol Size field, specify the size of the flow
decision icon. decision icon.
\li In the \uicontrol Radius field, specify the radius of the flow \li In the \uicontrol Radius field, specify the radius of the flow
decision icon corners. decision icon corners.
\endlist \endlist
You can use the \l{Picking Colors}{color picker} to set the outline and
fill color of the flow decision icon.
*/ */
/*! /*!
@@ -599,32 +608,34 @@
\title Applying States in Flows \title Applying States in Flows
You can use \l{Working with States}{states} in flows to modify the appearance Use \l{Working with States}{states} in flows to modify how the \l{glossary-component}
of \l{glossary-component}{components} in flow items in response to user {component} properties change in flow items. For this purpose, use the \uicontrol {Flow Item}
interaction, for example. For this purpose, you use the component available in \uicontrol Components > \uicontrol {Flow View}.
\uicontrol {Flow Item} components available in
\uicontrol Components > \uicontrol {Flow View}. To apply states in flows:
\list 1 \list 1
\li Select \uicontrol File > \uicontrol {New File} > \li Select \uicontrol File > \uicontrol {New File} >
\uicontrol {Qt Quick Files} > \uicontrol {Qt Quick Files} >
\uicontrol {Flow Item} to create a flow item. \uicontrol {Flow Item} to create a flow item.
\li In \l States, add states to the flow item. \li In the \l States view, add states to the flow item.
\li Open the .ui.qml file that contains the \l{Adding Flow Views} \li In the \l Projects view, open the .ui.qml file that contains the \l{Adding Flow Views}
{flow view} in the \l {2D} view and drag the flow item to the {flow view}, and drag the flow item from \uicontrol Components >
flow view in the \l Navigator or \l {2D} view. \uicontrol {My Components} to the flow view in the \l Navigator or \l 2D view.
\li Drag an empty \uicontrol {Flow Item} component from \li From \uicontrol Components > \uicontrol {Flow View}, drag an empty
\uicontrol Components > \uicontrol {Flow View} \uicontrol {Flow Item} component (1) to the flow view for each state that you added.
to the flow for each state that you added. \image studio-flow-item-component.webp "Flow Item in the Components view."
\li In \l Properties, in the \uicontrol {State change target} \li In the \uicontrol Navigator or \uicontrol 2D view, select an empty
field, select the flow item that you created using the wizard. \uicontrol {Flow Item} to open the \l Properties view.
\image studio-flow-item-properties.png "Flow Item properties" \li In the \uicontrol {State change target} field, select the flow item that you created
\li In the \uicontrol {Target state} field, select the state to using the wizard.
apply to the flow item. \li In the \uicontrol {Target state} field, select the state to apply to the flow item.
\image studio-flow-states-item-properties.webp "Flow Item properties"
\endlist \endlist
You can now add \l{Adding Action Areas and Transitions}{action areas} and To apply the different states to your application flow, add
\l{Simulating Conditions}{flow decisions} to apply the different states. \l{Adding Action Areas and Transitions}{action areas} and
\l{Simulating Conditions}{flow decisions} to the flow items.
*/ */
/*! /*!
@@ -639,11 +650,10 @@
time, based on a conditional event. For example, push notifications time, based on a conditional event. For example, push notifications
appear on mobile devices and incoming call screens on a car's HMI. appear on mobile devices and incoming call screens on a car's HMI.
You can use the \uicontrol {Flow Wildcard} component to model this type of Use the \uicontrol {Flow Wildcard} component to model this type of
screens in your \l{Adding Flow Views}{flow view} using real or simulated screens in your \l{Adding Flow Views}{flow view} using real or simulated events.
\l{Connecting and Releasing Signals}{signals} and \l{Simulating Conditions} Add \l{Adding Flow Items}{flow items} to an \uicontrol {Allow
{conditions}. You can add \l{Adding Flow Items}{flow items} to a positive list} to prioritize them or to a \uicontrol {Block list} to stop some screens from
list to prioritize them or to a negative list to stop some screens from
appearing on others. For example, you could block the incoming call screen appearing on others. For example, you could block the incoming call screen
from appearing on a warning screen for the engine if you consider the from appearing on a warning screen for the engine if you consider the
warning more important. warning more important.
@@ -652,21 +662,26 @@
\list 1 \list 1
\li Drag a \uicontrol {Flow Wildcard} component from \li Drag a \uicontrol {Flow Wildcard} component from
\uicontrol Components > \uicontrol {Flow View} to an \uicontrol Components > \uicontrol {Flow View} to the \l {2D} view.
\l{Adding Action Areas and Transitions}{action area} in \li To connect the wildcard to a flow item with a \l{Adding Action Areas and Transitions}
the \l Navigator or \l {2D} view. {transition line}, double-click the wildcard and drag the transition line to the flow
\li In \l Properties, select flow items to add them to the item.
positive and negative list of the action area. \li To add logic to the \uicontrol {Flow Wildcard} component, use
\l{Simulating Events}{events}, \l{Simulating Conditions}{Flow Decision} components,
or \l{Connecting and Releasing Signals}{signals}.
\li To manage the priority of your flow items, add flow items to
\uicontrol {Allow list} or \uicontrol {Block list} in \l Properties.
\image studio-flow-wildcard.webp "The wildcard component in 2D view."
\endlist \endlist
\section1 Flow Wildcard Properties \section1 Flow Wildcard Properties
You can specify basic properties for a \uicontrol {Flow Wildcard} component Specify basic properties for a \uicontrol {Flow Wildcard} component
in the \l Type and \l ID fields in the \uicontrol Component section in the in the \l Type and \l ID fields in the \uicontrol Component section in the
\uicontrol Properties view. Specify properties for flow wildcards in the \uicontrol Properties view. Specify properties for flow wildcards in the
\uicontrol {Flow Wildcard} section. \uicontrol {Flow Wildcard} section.
\image studio-flow-wildcard-properties.png "Flow Wildcard properties" \image studio-flow-wildcard-properties.webp "Flow Wildcard properties"
In the \uicontrol {Event IDs} field, specify the IDs of the events to In the \uicontrol {Event IDs} field, specify the IDs of the events to
connect to, such as mouse, touch or keyboard events. connect to, such as mouse, touch or keyboard events.
@@ -678,16 +693,15 @@
\uicontrol {Allow list} field. To block flow items, \uicontrol {Allow list} field. To block flow items,
select them in the \uicontrol {Block list} field. select them in the \uicontrol {Block list} field.
You can specify the following properties to change the appearance of the Specify the following properties to change the appearance of the
wildcard icon \inlineimage icons/flow-wildcard-icon.png wildcard icon \inlineimage icons/flow-wildcard-icon.png:
:
\list \list
\li To set the outline and fill color of the wildcard icon, use the
\l{Picking Colors}{color picker}.
\li In the \uicontrol Size field, specify the size of the wildcard icon. \li In the \uicontrol Size field, specify the size of the wildcard icon.
\li In the \uicontrol Radius field, specify the radius of the wildcard \li In the \uicontrol Radius field, specify the radius of the wildcard
icon corners. icon corners.
\endlist \endlist
You can use the \l{Picking Colors}{color picker} to set the outline and
fill color of the wildcard icon.
*/ */

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! /*!
@@ -56,4 +56,6 @@
If you would rather be shown things than read about them, If you would rather be shown things than read about them,
you can watch our extensive video tutorials. you can watch our extensive video tutorials.
\endlist \endlist
\include qtdesignstudio-qt-academy.qdocinc qt-academy-getting-started-with-qt-design-studio
*/ */

View File

@@ -0,0 +1,22 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [qt-academy-using-qt-bridge-for-figma]
To learn the basics of \QBF, take the
\l {https://www.qt.io/academy/course-catalog#how-to-use-qt-bridge-for-figma}
{How to Use \QBF} course in \QAC.
//! [qt-academy-using-qt-bridge-for-figma]
//! [qt-academy-3D-with-qt-design-studio]
To learn the basics of using 3D in \QDS, take the
\l {https://www.qt.io/academy/course-catalog#3d-with-qt-design-studio}
{3D with \QDS} course in \QAC.
//! [qt-academy-3D-with-qt-design-studio]
//! [qt-academy-getting-started-with-qt-design-studio]
To learn the basics of using \QDS, take the
\l {https://www.qt.io/academy/course-catalog#getting-started-with-qt-design-studio}
{Getting Started with \QDS} course in \QAC.
//! [qt-academy-getting-started-with-qt-design-studio]
*/

View File

@@ -4,7 +4,7 @@
/*! /*!
\page studio-terms.html \page studio-terms.html
\previouspage studio-use-cases.html \previouspage studio-use-cases.html
\nextpage {Examples} \nextpage best-practices.html
\title Concepts and Terms \title Concepts and Terms
@@ -170,7 +170,7 @@
example, if you create a 3D project, preset 3D components are added to it. example, if you create a 3D project, preset 3D components are added to it.
You can add more preset components in \uicontrol {Components}. You can add more preset components in \uicontrol {Components}.
\image studio-project-wizards.png "New Project dialog" \image studio-project-wizards.webp "New Project dialog"
Read more about projects: Read more about projects:

View File

@@ -48,6 +48,7 @@
\li \l{Creating Projects} \li \l{Creating Projects}
\li \l{Use Cases} \li \l{Use Cases}
\li \l{Concepts and Terms} \li \l{Concepts and Terms}
\li \l{Best Practices}
\li \l{Examples} \li \l{Examples}
\endlist \endlist
\li \l{Wireframing} \li \l{Wireframing}
@@ -74,8 +75,9 @@
\li \l{UI Controls} \li \l{UI Controls}
\li \l{Lists and Other Data Models} \li \l{Lists and Other Data Models}
\li \l{2D Effects} \li \l{2D Effects}
\li \l{Design Effects}
\li \l{Logic Helpers} \li \l{Logic Helpers}
\li \l Animations \li \l{Animations}
\li \l{3D Views} \li \l{3D Views}
\li \l{Node} \li \l{Node}
\li \l{Group} \li \l{Group}

View File

@@ -31,6 +31,7 @@
\li \l{Creating Projects} \li \l{Creating Projects}
\li \l{Use Cases} \li \l{Use Cases}
\li \l{Concepts and Terms} \li \l{Concepts and Terms}
\li \l{Best Practices}
\li \l{Examples} \li \l{Examples}
\endlist \endlist
\li \b {\l{Wireframing}} \li \b {\l{Wireframing}}

View File

@@ -13,54 +13,28 @@
\brief Edit a 3D scene. \brief Edit a 3D scene.
When editing a 3D scene, you view the scene in the \uicontrol{3D} When editing a 3D scene, you view the scene in the \uicontrol{3D}
view. You can change the projection of the view by switching between view.
\e {perspective camera} and \e {orthographic camera} modes. When using the
perspective camera mode, components that are far from the camera appear
smaller than those nearby. In the orthographic camera mode, all components
appear at the same scale irrespective of their distance from the camera.
Both of them are free-form camera modes that you can use to orbit around
the scene.
When you import 3D scenes from files that you exported from 3D graphics When you import 3D scenes from files that you exported from 3D graphics
tools, you also import a \l{Cameras}{scene camera}, tools, you also import a \l{Cameras}{scene camera},
\l{Lights}{light}, \l{3D Models}{model}, and \l{Lights}{light}, \l{3D Models}{model}, and \l {Materials and Shaders}{materials}.
\l {Materials and Shaders}{materials}. If your scene did not contain If your scene does not contain them, add the corresponding \l {3D Components}{Qt Quick 3D}
them, you can add the corresponding \l {3D Components}{Qt Quick 3D}
components from \uicontrol Components > \inlineimage icons/plus.png components from \uicontrol Components > \inlineimage icons/plus.png
> \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D}. > \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D}.
You can use the toolbar buttons Use the \uicontrol 3D toolbar buttons to modify the \uicontrol 3D view,
to \e transform 3D components and manipulate the 3D scene. Transformation manipulate the 3D scene, and to access functionalities to \e transform 3D
refers to moving, rotating, or scaling of a component. The \e pivot of the components. Transformation refers to moving, rotating, or scaling a
component is used as the origin for transformations. You can set a component. The \e pivot of the component is used as the origin for
\l{Managing 3D Transformations}{local pivot offset} for a component in transformations. Set a \l{Managing 3D Transformations}{local pivot offset}
\uicontrol Properties to transform the component around a point other than for a component in \uicontrol Properties to transform the component around
its local origin. A line is drawn in the \uicontrol{3D} view from the pivot a point other than its local origin. A line is drawn in the \uicontrol{3D}
point to the center of the component to provide a visual connection between view from the pivot point to the center of the component to provide a visual
them. Especially when working with complex scenes, it may be useful to use connection between them.
the \l {Showing and Hiding Components}{showing and hiding} or the
\l {Locking Components}{locking} features in \l Navigator to avoid
transforming components by mistake while editing your scene.
Toggle between local and global orientation to determine whether the gizmos \note To avoid transforming components by mistake while editing your scene,
affect only the local transformations of the component or whether they use the \l {Showing and Hiding Components}{showing and hiding} or the
transform with respect to the global space. \l {Locking Components}{locking} features in \l Navigator.
Another helpful feature when editing 3D scenes is the \e {edit light},
which is a quick way to light the scene.
Additionally, you can toggle the visibility of the grid, selection boxes,
icon gizmos, and camera frustums in the 3D scene.
There is a context menu in the \uicontrol 3D view. To open it, right-click
in the \uicontrol 3D view. From the context menu you can:
\list
\li Create cameras, lights, and models.
\li Open \uicontrol {Material Editor} and edit materials.
\li Delete components
\endlist
\image 3d-view-context-menu.webp "The context menu in the 3D view"
To refresh the contents of the \uicontrol{3D} view, press \key P or To refresh the contents of the \uicontrol{3D} view, press \key P or
select the \inlineimage icons/reset.png select the \inlineimage icons/reset.png
@@ -73,53 +47,76 @@
\youtube SsFWyUeAA_4 \youtube SsFWyUeAA_4
\include qtdesignstudio-qt-academy.qdocinc qt-academy-3D-with-qt-design-studio
\section1 Using the Context Menu in the 3D View
There is a context menu in the \uicontrol 3D view. To open it, right-click
in the \uicontrol 3D view. From the context menu you can, for example:
\list
\li Create cameras, lights, and models.
\li Open \uicontrol {Material Editor} and edit materials.
\li Delete components.
\li Align camera views.
\endlist
\image 3d-view-context-menu.webp "The context menu in the 3D view"
\section1 Controlling the 3D View Camera \section1 Controlling the 3D View Camera
\section2 Toggling Camera Mode \section2 Toggling Camera Mode
To switch to perspective camera mode, select Change the projection of the view by switching between \e {perspective camera}
\inlineimage perspective_camera.png and \e {orthographic camera} modes. When using the perspective camera mode,
(\uicontrol {Toggle Perspective/Orthographic Edit Camera}). components that are far from the camera appear smaller than those nearby. In
To switch to orthographic camera mode, select the orthographic camera mode, all components appear at the same scale
\inlineimage orthographic_camera.png irrespective of their distance from the camera. Both of them are free-form
. You can also Toggle the camera mode by using the keyboard shortcut \key T. camera modes that you can use to orbit around the scene.
To toggle the camera mode, do one of the following:
\list
\li Select \inlineimage perspective_camera.png
(\uicontrol {Toggle Perspective/Orthographic Camera}) to use the
perspective camera mode.
\li Select \inlineimage orthographic_camera.png to use the orthographic
camera mode.
\endlist
You can also toggle the camera mode by using the keyboard shortcut \key T.
\section2 Navigating in the 3D Scene \section2 Navigating in the 3D Scene
You can navigate the scene by panning, rotating, and zooming the 3D view Navigate the scene by panning, rotating, and zooming the 3D view
camera: camera:
\list \list
\li To pan, press \key Alt (or \key Option on \macos) and use the \li To pan, press \key Alt (or \key Option on \macos) and use the
middle mouse button to click and drag anywhere in the rendered wheel button to drag anywhere in the \uicontrol 3D view to
view to slide the view around. Alternatively, press and hold \key {right mouse slide the view around. Alternatively, press and hold \key
button} and \key {left mouse button} and drag anywhere in the view to pan. {right mouse button} and \key {left mouse button} and drag
\li To orbit, press \key Alt and click and drag anywhere in the rendered anywhere in the view to pan.
view to rotate the view. \li To orbit, press \key Alt and and drag anywhere in the
\uicontrol 3D view to rotate the view.
\li To zoom, use the mouse wheel or press \key Alt and right-click \li To zoom, use the mouse wheel or press \key Alt and right-click
anywhere in the rendered view to zoom the view in or out as you drag anywhere in the \uicontrol 3D view to zoom the view in or out as you drag
up or down. up or down.
\endlist \endlist
To zoom and focus the 3D view camera on a selected component, To zoom and focus the 3D view camera on a selected component, select
select \inlineimage fit_selected.png \inlineimage fit_selected.png (\uicontrol {Fit Selected}) or press \key F.
(\uicontrol {Fit Selected}) or press \key F.
The world axis helper (1) shows the direction of the world axes in the view. The world axis helper (1) shows the direction of the world axes in the view.
To point the camera at the currently selected component in the direction of To point the 3D view camera at the currently selected component in the direction of
an axis, click the axis. Clicking the dot at the end of the axis will point an axis, click the axis. Clicking the dot at the end of the axis will point
the camera at the opposite direction of the axis. If no component is the camera at the opposite direction of the axis. If no component is
selected, the camera is pointed at the world origin. This does not affect selected, the camera is pointed at the world origin.
the camera zoom level.
\image studio-3d-editor-axis-helper.webp "Axis helper in the 3D view" \image studio-3d-editor-axis-helper.webp "Axis helper in the 3D view"
You can use scene cameras (2) to view the \uicontrol View3D component from a Use scene cameras (2) to view the \uicontrol View3D component from a
specific angle in the \l {2D} view while editing scenes. Different types of specific angle in the \l {2D} view while editing scenes. Drag a camera
cameras are available in \uicontrol Components component to your scene from \uicontrol Components > \uicontrol {Qt Quick 3D} >
> \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D}. For more information \uicontrol {Qt Quick 3D}. For more information about using cameras in the
about using cameras in the scene, the available camera types, and their scene and the available camera types, see \l{Cameras}.
properties, see \l{Cameras}.
\section2 Using Split View \section2 Using Split View
@@ -128,16 +125,16 @@
\image studio-3d-split-view.webp "Split view in the 3D view" \image studio-3d-split-view.webp "Split view in the 3D view"
To select one of the four panes, click on it. The selected pane is marked with To select one of the four panes, click the pane. The selected pane is marked with
a blue frame. Use the world axis helper to change the point of view for each pane a blue frame. Use the world axis helper to change the point of view for each pane
independently. Navigate each split by panning, rotating, and zooming, as independently. Navigate each split by panning, rotating, and zooming, as
described above. described above.
\section2 Using Fly Mode \section2 Using Fly Mode
You can move around freely in the 3D scene with fly mode. To navigate the scene with Use the fly mode to move around freely in the 3D scene. To navigate the scene with
fly mode, keep the \key {right mouse button} pressed and use the listed keys to move fly mode, right-click and hold in the \uicontrol 3D view, and use the keyboard shortcuts
around the scene. to move around the scene:
\table \table
\header \header
@@ -161,10 +158,20 @@
\row \row
\li \key Q or \key {Page down} \li \key Q or \key {Page down}
\li Move down. \li Move down.
\row
\li \key Shift
\li Move faster.
\row
\li \key Alt
\li Move slower.
\row
\li \key Spacebar
\li Move to an object in the crosshairs.
\endtable \endtable
To adjust the movement speed, select \inlineimage icons/camera_speed.png in the To adjust the movement speed, right-click and hold in the \uicontrol 3D view, and rotate the
\uicontrol 3D view toolbar to open the configuration dialog. mouse wheel. Alternatively, select \inlineimage icons/camera_speed.png in the \uicontrol 3D
view toolbar to open the configuration dialog.
In the configuration dialog, you can: In the configuration dialog, you can:
\list \list
@@ -174,10 +181,8 @@
\section1 Using Global and Local Orientation \section1 Using Global and Local Orientation
To switch between local and global orientation, select In \uicontrol 3D view, you view the scene in global or local orientation
\inlineimage global.png mode.
(\uicontrol {Toggle Local/Global Orientation})
or press \key Y.
In global orientation mode, transformation of a selected component is In global orientation mode, transformation of a selected component is
presented with respect to the global space. For example, while the move tool presented with respect to the global space. For example, while the move tool
@@ -191,40 +196,40 @@
the axes of global space. Dragging on the red arrow of the gizmo moves the the axes of global space. Dragging on the red arrow of the gizmo moves the
component in the local x direction in relation to the component. component in the local x direction in relation to the component.
To switch between local and global orientation, select \inlineimage global.png
(\uicontrol {Toggle Local/Global Orientation}) or press \key Y.
\section1 Using Edit Light \section1 Using Edit Light
The edit light is an extra point light that can be used to illuminate the The edit light is an extra point light that can be used to illuminate the
scene. To toggle the edit light on and off, select \inlineimage edit_light_on.png scene. To toggle the edit light on and off, select \inlineimage edit_light_on.png
or \inlineimage edit_light_off.png or \inlineimage edit_light_off.png (\uicontrol {Toggle Edit Light}) or
(\uicontrol {Toggle Edit Light}) press \key U.
or press \key U.
For more information about the available scene light types and their For information about the available scene light types and their properties,
properties, see \l{Lights}. see \l{Lights}.
\section1 Baking Lights \section1 Baking Lights
Bake lights to light static elements in your scene. To bake lights, Bake lights to light static elements in your scene. To bake lights, select
select \inlineimage icons/bakelights.png to open the \inlineimage icons/bakelights.png to open the \uicontrol {Lights Baking Setup}
\uicontrol {Lights Baking Setup} dialog. For more information, see dialog. For more information, see \l {Baking Lightmaps}.
\l {Baking Lightmaps}.
\section1 Selecting Components \section1 Selecting Components
To move, rotate, or scale components in the scene, you need to select them To move, rotate, or scale components in the scene, you need to select them
first. The selection mode buttons determine how components are selected when first. Toggle the selection mode to determine how components are selected
you click them in the \uicontrol{3D} view: when you click them in the \uicontrol{3D} view:
\list \list
\li In the \inlineimage select_item.png \li Use the \inlineimage select_item.png (\uicontrol {Single Selection})
(\uicontrol {Single Selection}) mode, a single component is selected. mode to select a single component.
\li In the \inlineimage select_group.png \li Use the \inlineimage select_group.png (\uicontrol {Group Selection})
(\uicontrol {Group Selection}) mode, the top level parent of the mode to select the top level parent of the component, so you can move
component is selected. This enables you to move, rotate, or scale a a group of components simultaneously.
group of components.
\endlist \endlist
To toggle the selection mode, press \key Q. Alternatively, press \key Q to toggle the selection mode.
To multiselect, hold \key Ctrl and click the components you wish to select. To multiselect, hold \key Ctrl and click the components you wish to select.
@@ -241,16 +246,15 @@
y, or z axis or on the top, bottom, left, and right clip planes of the y, or z axis or on the top, bottom, left, and right clip planes of the
the \uicontrol{3D} view. the \uicontrol{3D} view.
To move components, select \inlineimage move_off.png To move components, select \inlineimage move_off.png or press \key W:
or press \key W:
\list \list
\li To move components along the axes of the move gizmo, click the axis, \li To move components along the axes of the move gizmo, click the axis,
and drag the component along the axis. and drag the component along the axis.
\li To move components on a plane, click the plane handle and drag the \li To move components on a plane, drag the plane handle of the move
component on the plane. component on the plane.
\li To move components freely in the 3D view, click and drag the gray \li To move components freely in the 3D view, drag the gray handle at the
handle at the center of the move gizmo. center of the move gizmo.
\endlist \endlist
\section1 Rotating Components \section1 Rotating Components
@@ -261,29 +265,28 @@
or press \key E: or press \key E:
\list \list
\li To rotate a component around its rotation gizmo, click the axis ring \li To rotate a component around its rotation gizmo, drag the axis ring
and drag in the direction you want to rotate the component in. in the direction you want to rotate the component in.
\li To freely rotate the component, click and drag the inner center \li To freely rotate the component, drag the inner center circle of the
circle of the gizmo. gizmo.
\endlist \endlist
\section1 Scaling Components \section1 Scaling Components
\image studio-3d-editor-scale.webp "The 3D view in scale mode" \image studio-3d-editor-scale.webp "The 3D view in scale mode"
You can use the scale handles to adjust the local x, y, or z scale of a Úse the scale handles to adjust the local x, y, or z scale of a
component. You can adjust the scale across one, two, or three axes, component. You can adjust the scale across one, two, or three axes,
depending on the handle. depending on the handle.
To scale components, select \inlineimage scale_off.png To scale components, select \inlineimage scale_off.png or press \key R:
or press \key R:
\list \list
\li To adjust the scale across one axis, click and drag the scale handle \li To adjust the scale across one axis, drag the scale handle
attached to the axis. attached to the axis.
\li To adjust the scale across a plane, click the plane handle and drag \li To adjust the scale across a plane, drag the plane handle of
the component on the plane. the component.
\li To uniformly scale a component across all axes, click and drag the \li To uniformly scale a component across all axes, drag the
gray handle at the center of the component. gray handle at the center of the component.
\endlist \endlist
@@ -292,7 +295,7 @@
With snapping turned on, the objects in the \uicontrol 3D view snap to certain With snapping turned on, the objects in the \uicontrol 3D view snap to certain
intervals during transformation (move, rotate, scale). intervals during transformation (move, rotate, scale).
You can toggle snapping in the following ways: Toggle snapping in the following ways:
\list \list
\li Select \inlineimage icons/snapping-3d.png \li Select \inlineimage icons/snapping-3d.png
@@ -300,7 +303,7 @@
\li Hold down the \key Ctrl key. \li Hold down the \key Ctrl key.
\endlist \endlist
With snapping turned on, you can press and hold \key Shift to snap objects to one tenth of With snapping turned on, press and hold \key Shift to snap objects to one tenth of
the specified snap interval. the specified snap interval.
\section2 Configuring Snapping \section2 Configuring Snapping
@@ -327,65 +330,72 @@
To align a camera to the \uicontrol{3D} view: To align a camera to the \uicontrol{3D} view:
\list 1 \list 1
\li Select a camera in the \uicontrol{3D} or \uicontrol {Navigator} view. \li Select a scene camera in the \uicontrol{3D} or \uicontrol {Navigator} view.
\note If you don't have a camera selected, the most recently selected camera \note If you don't have a camera selected, the most recently selected camera
is aligned to the view. is aligned to the view.
\li In the \uicontrol{3D} view, \li In the \uicontrol{3D} view, select \inlineimage icons/align-camera-on.png.
select \inlineimage icons/align-camera-on.png
.
\endlist \endlist
This moves and rotates the camera so that the camera shows the same view This moves and rotates the scene camera to show the same view as the current view
as the current view in the \uicontrol{3D} view. in the \uicontrol{3D} view.
To align the \uicontrol{3D} view to a camera: To align the \uicontrol{3D} view to a camera:
\list 1 \list 1
\li Select a camera in the \uicontrol{3D} view or \uicontrol {Navigator}. \li Select a scene camera in the \uicontrol{3D} view or \uicontrol {Navigator}.
\note If you don't have a camera selected, the view is aligned to the most recently \note If you don't have a camera selected, the view is aligned to the most recently
selected camera. selected camera.
\li In the \uicontrol{3D} view, \li In the \uicontrol{3D} view, select \inlineimage icons/align-view-on.png.
select \inlineimage icons/align-view-on.png
.
\endlist \endlist
This copies the position as well as x and y rotation values from the This moves and rotates the 3D view to show the same view as the selected scene camera.
camera and applies them to the \uicontrol{3D} view.
\section1 Toggling Visibility \section1 Toggling Visibility
To toggle the visibility of objects in the \uicontrol{3D} view, select To toggle the visibility of objects in the \uicontrol{3D} view, select
\inlineimage icons/visibilityon.png \inlineimage icons/visibilityon.png in the toolbar. This opens a menu with the
in the toolbar. This opens a menu with the following options: following options:
\table \table
\header
\li Action
\li Description
\li Keyboard Shortcut
\row \row
\li Show Grid \li Show Grid
\li Toggles the visibility of the helper grid. \li Toggles the visibility of the helper grid.
\li \key G
\row \row
\li Show Selection Boxes \li Show Selection Boxes
\li Toggles the visibility of selection boxes for selected 3D objects. \li Toggles the visibility of selection boxes for selected 3D objects.
\li \key B
\row \row
\li Show Icon Gizmos \li Show Icon Gizmos
\li Toggles the visibility of icon gizmos for object such as cameras, \li Toggles the visibility of icon gizmos for object such as cameras,
lights, and particle systems. lights, and particle systems.
\li \key I
\row \row
\li Always Show Camera Frustums \li Always Show Camera Frustums
\li Toggles between always showing the camera frustum and showing it \li Toggles between always showing the camera frustum and showing it
only for cameras selected in the \uicontrol{3D} view. only for cameras selected in the \uicontrol{3D} view.
\li \key C
\row \row
\li Always Show Particle Emitters and Attractors \li Always Show Particle Emitters and Attractors
\li Toggle between always showing the particle emitter and attractor \li Toggles between always showing the particle emitter and attractor
visualizations and only showing them when the emitter or attractor is visualizations and only showing them when the emitter or attractor
selected in the \uicontrol{3D} view. is selected in the \uicontrol{3D} view.
\li \key M
\endtable \endtable
\section1 Changing Colors \section1 Changing Colors
To change the \uicontrol 3D view background or grid color, select To change the \uicontrol 3D view background or grid color, select
\inlineimage icons/3d-background-color.png \inlineimage icons/3d-background-color.png in the toolbar. This opens a menu
in the toolbar. This opens a menu with the following options: with the following options:
\table \table
\header
\li Action
\li Decription
\row \row
\li Select Background Color \li Select Background Color
\li Select a color for the background. \li Select a color for the background.
@@ -413,16 +423,14 @@
\li Select a particle system in the \uicontrol Navigator or \li Select a particle system in the \uicontrol Navigator or
\uicontrol{3D} view. \uicontrol{3D} view.
\li In the \uicontrol{3D} view, select \li In the \uicontrol{3D} view, select
\inlineimage icons/particle-animation-on.png \inlineimage icons/particle-animation-on.png to activate particle animation.
to activate particle animation. Now you can see the particle animation in Now you can see the particle animation in the \uicontrol{3D} view.
the \uicontrol{3D} view.
\endlist \endlist
You can pause the particle animation by selecting You can pause the particle animation by selecting
\inlineimage icons/particle-pause.png \inlineimage icons/particle-pause.png. When the animation is paused, use
. When the animation is paused, you can use \inlineimage icons/particles-seek.png to manually seek forward or backward in
\inlineimage icons/particles-seek.png the particle animation.
to manually seek forward or backward in the particle animation.
\section1 Using Viewport Shading \section1 Using Viewport Shading

View File

@@ -142,7 +142,7 @@
\li From \uicontrol Components, drag a \uicontrol Sphere to \e _3DRepeater \li From \uicontrol Components, drag a \uicontrol Sphere to \e _3DRepeater
in \uicontrol Navigator. in \uicontrol Navigator.
\image repeater3d-listmodel-navigator.png \image repeater3d-listmodel-navigator.png
\li Select \e sphere in \uicontrol Navigator and in the \Properties view, select \li Select \e sphere in \uicontrol Navigator and in the \uicontrol Properties view, select
\inlineimage icons/action-icon.png \inlineimage icons/action-icon.png
next to \uicontrol Scale > \uicontrol X. next to \uicontrol Scale > \uicontrol X.
\li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}. \li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}.

View File

@@ -17,7 +17,7 @@
To create a project with many complex effects, use the \uicontrol {Extended 3D} preset To create a project with many complex effects, use the \uicontrol {Extended 3D} preset
that creates a project with an \uicontrol {Extended View3D} component. that creates a project with an \uicontrol {Extended View3D} component.
The extended 3D view includes an {Extended Scene Environment} The extended 3D view includes an \uicontrol{Extended Scene Environment}
component that enables using various effects by defining them as properties. component that enables using various effects by defining them as properties.
\note The extended 3D view is available in projects created with Qt 6.5 \note The extended 3D view is available in projects created with Qt 6.5

View File

@@ -3,7 +3,7 @@
/*! /*!
\page quick-logic-helpers.html \page quick-logic-helpers.html
\previouspage quick-2d-effects.html \previouspage quick-design-effects.html
\nextpage quick-animations.html \nextpage quick-animations.html
\title Logic Helpers \title Logic Helpers

View File

@@ -0,0 +1,136 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page quick-design-effects.html
\previouspage quick-2d-effects.html
\nextpage quick-logic-helpers.html
\title Design Effects
\QDS provides a set of effects in the \uicontrol Properties view that you can apply
to the components.
\image studio-effects.webp "Design Effects in the Properties view"
\note This feature is a \e Beta release.
The available set of Design Effects applies to the \QDS components:
\list
\li \l {Applying Layer Blur on a Component} {Layer Blur}
\li \l {Applying Background Blur on a Component} {Background Blur}
\li \l {Applying Drop Shadow on a Component} {Drop Shadow}
\li \l {Applying Inner Shadow on a Component} {Inner Shadow}
\endlist
\section1 Applying Layer Blur on a Component
Use \uicontrol {Layer Blur} to make a component blurry. To apply \uicontrol {Layer Blur}
to a component, follow these steps:
\list 1
\li Select the component in the \uicontrol 2D or \uicontrol Navigator view.
\li Go to the \uicontrol {Properties} view > \uicontrol Effects
and select \uicontrol {Add Effects}.
\li Go to \uicontrol {Layer Blur} and enter the level of blurring you need
in \uicontrol {Blur}.
\image studio-effects-layer-blur.webp "Layer Blur Effects in Properties view"
\endlist
\note The level of \uicontrol {Layer Blur} is adjustable between zero and one hundred. \br
To remove the applied \uicontrol {Layer Blur}, select the component,
then go to \uicontrol {Properties} view > \uicontrol {Layer Blur}
> \uicontrol {Remove Effects}. This also removes all the other effects
applied to the component.
\section1 Applying Background Blur on a Component
Apply \uicontrol {Background Blur} to a component when you want to blur a selected
component behind it. There are a few essential conditions you should consider.
\list
\li Make the component partially transparent. With solid color,
the background component is not visible.
\li Use a solid color on the background component. On
a transparent background component the \uicontrol {Background Blur} does not
function properly.
\note Currently, the \uicontrol {Background Blur} functions on top of only one selected
background component. All the other components ignore the blurring.
\endlist
After fulfilling the above conditions, follow the next steps to apply the
\uicontrol {Background Blur} on a component.
\list 1
\li Select the component in the \uicontrol 2D or \uicontrol Navigator view.
\li Go to the \uicontrol {Properties} view > \uicontrol Effects
and select \uicontrol {Add Effects}.
\li Go to \uicontrol {Background Blur} and enter the level of blurring you need
in \uicontrol {Blur}.
\li In the \uicontrol Background dropdown menu, select another
components as the background component.
\li Drag the component on top of the background component. The area from the
component covering the component selected as \uicontrol Background gets
blurred. However, any other component behind the component doesn't blur.
\endlist
\image studio-effects-background-blur.webp "Applying Background Blur"
\section1 Applying Drop Shadow on a Component
Shadows can either fall outside or inside the component.
The shadow that falls outside is a drop shadow. To apply
a \uicontrol {Drop Shadow} to a component, follow the instructions below.
\list 1
\li Select the component in the \uicontrol 2D or \uicontrol Navigator view.
\li Go to the \uicontrol {Properties} view > \uicontrol Effects
and select \uicontrol {Add Effects}.
\endlist
This adds the default drop shadow to the component. To adjust this shadow,
follow these instructions.
\list 1
\li Select the component and go to the \uicontrol Properties view > \uicontrol Effects.
Then, select \inlineimage icons/particle-play.png next to the shadow type
selector dropdown menu.
\li Adjust \uicontrol Blur, \uicontrol Offset, \uicontrol Spread, and \uicontrol Color
to shape the shadow.
\endlist
\image studio-effects-drop-shadow.webp "Drop Shadow Effects in Properties view"
\note To stack multiple shadows, select \uicontrol {Add Shadow Effect} from the
\uicontrol Properties view. After adding multiple shadows, you can adjust them
separately from their expandable menu.
The \uicontrol {Show behind} feature in \uicontrol {Drop Shadow} only works when
the component is transparent. To use it:
\list 1
\li Select the component with a drop shadow.
\li Go to the \uicontrol Properties view > \uicontrol Effects.
Then, select \inlineimage icons/particle-play.png next to the shadow type
selector dropdown menu.
\li Select \uicontrol {Show Behind}.
\image studio-effects-show-shadow-behind.webp "Show drop shadow behind the component"
\endlist
\section1 Applying Inner Shadow on a Component
\uicontrol {Inner shadow} works inside a component. To apply \uicontrol {Inner Shadow},
do the following:
\list 1
\li Select the component in the \uicontrol 2D or \uicontrol Navigator view.
\li Go to the \uicontrol {Properties} view > \uicontrol Effects
and select \uicontrol {Add Effects}.
\li From the dropdown menu, select \uicontrol {Inner Shadow}.
\li Adjust \uicontrol Blur, \uicontrol Offset, \uicontrol Spread, and \uicontrol Color
to shape the shadow.
\image studio-effects-inner-shadow.webp "Inner shadow of the component"
\endlist
*/

View File

@@ -4,7 +4,7 @@
/*! /*!
\page quick-2d-effects.html \page quick-2d-effects.html
\previouspage quick-data-models.html \previouspage quick-data-models.html
\nextpage quick-logic-helpers.html \nextpage quick-property-effects.html
\title 2D Effects \title 2D Effects

View File

@@ -18,7 +18,7 @@
\image edit-list-model-model-editor.webp \image edit-list-model-model-editor.webp
For examples of how to use data models, see For examples of how to use data models, see
\l {Adding a Repeater3D Component with a List Model}. \l {Adding a Repeater3D Component with a Model}.
\section1 Creating a Data Model \section1 Creating a Data Model

View File

@@ -249,7 +249,7 @@ StudioControls.Menu {
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Add to Content Library") text: qsTr("Add to Content Library")
visible: root.rootView.userBundleEnabled() && root.__fileIndex && root.assetsModel.allFilePathsAreTextures(root.__selectedAssetPathsList) visible: root.__fileIndex && root.assetsModel.allFilePathsAreTextures(root.__selectedAssetPathsList)
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
onTriggered: root.rootView.addAssetsToContentLibrary(root.__selectedAssetPathsList) onTriggered: root.rootView.addAssetsToContentLibrary(root.__selectedAssetPathsList)
} }

View File

@@ -1,247 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import CollectionDetails 1.0 as CollectionDetails
import StudioControls 1.0 as StudioControls
import StudioHelpers as StudioHelpers
import StudioTheme 1.0 as StudioTheme
import QtQuick.Templates as T
Item {
id: root
required property var columnType
TableView.onCommit: {
if (editorLoader.changesAccepted && edit !== editorLoader.acceptedValue)
edit = editorLoader.acceptedValue
}
onActiveFocusChanged: {
if (root.activeFocus && !editorLoader.triggered && editorLoader.item) {
editorLoader.triggered = true
editorLoader.item.open()
}
// active focus should be checked again, because it might be affected by editorLoader.item
if (root.activeFocus && editorLoader.editor)
editorLoader.editor.forceActiveFocus()
}
Loader {
id: editorLoader
active: true
property var editor: editorLoader.item ? editorLoader.item.editor : null
property var editValue: editorLoader.editor ? editorLoader.editor.editValue : null
property var acceptedValue: null
property bool changesAccepted: true
property bool triggered: false
Connections {
id: modifierFocusConnection
target: editorLoader.editor
enabled: editorLoader.item !== undefined
function onActiveFocusChanged() {
if (!modifierFocusConnection.target.activeFocus) {
editorLoader.acceptedValue = editorLoader.editValue
root.TableView.commit()
}
}
}
Component {
id: textEditor
EditorPopup {
editor: textField
StudioControls.TextField {
id: textField
property alias editValue: textField.text
actionIndicator.visible: false
translationIndicatorVisible: false
onRejected: editorLoader.changesAccepted = false
}
}
}
Component {
id: realEditor
EditorPopup {
editor: realField
StudioControls.RealSpinBox {
id: realField
property alias editValue: realField.realValue
actionIndicator.visible: false
realFrom: -9e9
realTo: 9e9
realStepSize: 1.0
decimals: 6
trailingZeroes: false
onActiveFocusChanged: {
if (realField.activeFocus)
realField.contentItem.focus = true
}
textFromValue: function (value, locale) {
locale.numberOptions = Locale.OmitGroupSeparator
var decimals = realField.trailingZeroes ? realField.decimals : decimalCounter(realField.realValue)
if (decimals > 0) {
var text = Number(realField.realValue).toLocaleString(locale, 'f', decimals + 1)
return text.substring(0, text.length - 1)
}
return Number(realField.realValue).toLocaleString(locale, 'f', decimals)
}
}
}
}
Component {
id: integerEditor
EditorPopup {
editor: integerField
StudioControls.SpinBox {
id: integerField
property alias editValue: integerField.value
actionIndicatorVisible: false
spinBoxIndicatorVisible: true
from: -2147483647
to: 2147483647
decimals: 0
onActiveFocusChanged: {
if (integerField.activeFocus)
integerField.contentItem.focus = true
}
}
}
}
Component {
id: boolEditor
EditorPopup {
editor: boolField
StudioControls.CheckBox {
id: boolField
property alias editValue: boolField.checked
actionIndicatorVisible: false
}
}
}
}
component EditorPopup: T.Popup {
id: editorPopup
required property Item editor
implicitHeight: contentHeight
implicitWidth: contentWidth
focus: true
visible: false
Connections {
target: editorPopup.editor
function onActiveFocusChanged() {
if (!editorPopup.editor.activeFocus)
editorPopup.close()
else if (edit)
editorPopup.editor.editValue = edit
}
}
Connections {
target: editorPopup.editor.Keys
function onEscapePressed() {
editorLoader.changesAccepted = false
editorPopup.close()
}
function onReturnPressed() {
editorPopup.close()
}
function onEnterPressed() {
editorPopup.close()
}
}
}
states: [
State {
name: "default"
when: columnType !== CollectionDetails.DataType.Boolean
&& columnType !== CollectionDetails.DataType.Color
&& columnType !== CollectionDetails.DataType.Integer
&& columnType !== CollectionDetails.DataType.Real
PropertyChanges {
target: editorLoader
sourceComponent: textEditor
}
},
State {
name: "integer"
when: columnType === CollectionDetails.DataType.Integer
PropertyChanges {
target: editorLoader
sourceComponent: integerEditor
}
},
State {
name: "real"
when: columnType === CollectionDetails.DataType.Real
PropertyChanges {
target: editorLoader
sourceComponent: realEditor
}
},
State {
name: "bool"
when: columnType === CollectionDetails.DataType.Boolean
PropertyChanges {
target: editorLoader
sourceComponent: boolEditor
}
},
State {
name: "color"
when: columnType === CollectionDetails.DataType.Color
PropertyChanges {
target: editorLoader
sourceComponent: null
}
}
]
}

View File

@@ -1,291 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt.labs.platform as PlatformWidgets
import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
import CollectionDetails
import CollectionEditorBackend
Rectangle {
id: root
required property var model
required property var backend
property int selectedRow: -1
implicitHeight: StudioTheme.Values.toolbarHeight
color: StudioTheme.Values.themeToolbarBackground
function addNewColumn() {
addColumnDialog.popUp(root.model.columnCount())
}
function addNewRow() {
root.model.insertRow(root.model.rowCount())
}
function closeDialogs() {
addColumnDialog.reject()
fileDialog.reject()
}
RowLayout {
id: container
anchors.fill: parent
anchors.topMargin: StudioTheme.Values.toolbarVerticalMargin
anchors.bottomMargin: StudioTheme.Values.toolbarVerticalMargin
spacing: StudioTheme.Values.sectionRowSpacing
RowLayout {
id: leftSideToolbar
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.leftMargin: StudioTheme.Values.toolbarHorizontalMargin
spacing: StudioTheme.Values.sectionRowSpacing
IconButton {
id: addColumnLeftButton
buttonIcon: StudioTheme.Constants.addcolumnleft_medium
tooltip: qsTr("Add column left")
enabled: root.model.selectedColumn > -1
onClicked: addColumnDialog.popUp(root.model.selectedColumn)
}
IconButton {
id: addColumnRightButton
buttonIcon: StudioTheme.Constants.addcolumnright_medium
tooltip: qsTr("Add column right")
enabled: root.model.selectedColumn > -1
onClicked: addColumnDialog.popUp(root.model.selectedColumn + 1)
}
IconButton {
id: deleteColumnButton
buttonIcon: StudioTheme.Constants.deletecolumn_medium
tooltip: qsTr("Delete selected column")
enabled: root.model.selectedColumn > -1
onClicked: root.model.removeColumn(root.model.selectedColumn)
}
Item { // spacer
implicitWidth: StudioTheme.Values.toolbarSpacing
implicitHeight: 1
}
IconButton {
id: addRowBelowButton
buttonIcon: StudioTheme.Constants.addrowbelow_medium
tooltip: qsTr("Add row below")
enabled: root.model.selectedRow > -1
onClicked: root.model.insertRow(root.model.selectedRow + 1)
}
IconButton {
id: addRowAboveButton
buttonIcon: StudioTheme.Constants.addrowabove_medium
tooltip: qsTr("Add row above")
enabled: root.model.selectedRow > -1
onClicked: root.model.insertRow(root.model.selectedRow)
}
IconButton {
id: deleteSelectedRowButton
buttonIcon: StudioTheme.Constants.deleterow_medium
tooltip: qsTr("Delete selected row")
enabled: root.model.selectedRow > -1
onClicked: root.model.removeRow(root.model.selectedRow)
}
}
RowLayout {
id: rightSideToolbar
spacing: StudioTheme.Values.sectionRowSpacing
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: StudioTheme.Values.toolbarHorizontalMargin
IconButton {
id: saveCollectionButton
buttonIcon: StudioTheme.Constants.save_medium
tooltip: qsTr("Save changes")
enabled: root.model.collectionName !== "" && root.model.hasUnsavedChanges
onClicked: root.model.saveDataStoreCollections()
Rectangle {
width: StudioTheme.Values.smallStatusIndicatorDiameter
height: StudioTheme.Values.smallStatusIndicatorDiameter
radius: StudioTheme.Values.smallStatusIndicatorDiameter / 2
anchors.right: parent.right
anchors.top: parent.top
visible: root.model.hasUnsavedChanges
color: StudioTheme.Values.themeIconColorSelected
}
}
IconButton {
id: exportCollectionButton
buttonIcon: StudioTheme.Constants.export_medium
tooltip: qsTr("Export model")
enabled: root.model.collectionName !== ""
onClicked: fileDialog.open()
}
}
}
PlatformWidgets.FileDialog {
id: fileDialog
fileMode: PlatformWidgets.FileDialog.SaveFile
nameFilters: ["JSON Files (*.json)",
"Comma-Separated Values (*.csv)"
]
selectedNameFilter.index: 0
onAccepted: {
let filePath = fileDialog.file.toString()
root.model.exportCollection(filePath)
}
}
component IconButton: HelperWidgets.AbstractButton {
style: StudioTheme.Values.viewBarButtonStyle
}
component Spacer: Item {
implicitWidth: 1
implicitHeight: StudioTheme.Values.columnGap
}
RegularExpressionValidator {
id: nameValidator
regularExpression: /^\w+$/
}
StudioControls.Dialog {
id: addColumnDialog
property int clickedIndex: -1
property bool nameIsValid
title: qsTr("Add Column")
function popUp(index)
{
addColumnDialog.clickedIndex = index
columnName.text = ""
columnName.forceActiveFocus()
addedPropertyType.currentIndex = addedPropertyType.find("String")
addColumnDialog.open()
}
function addColumnName() {
if (addColumnDialog.nameIsValid) {
root.model.addColumn(addColumnDialog.clickedIndex, columnName.text, addedPropertyType.currentText)
addColumnDialog.accept()
} else {
addColumnDialog.reject()
}
}
contentItem: ColumnLayout {
spacing: 2
Text {
text: qsTr("Column name:")
color: StudioTheme.Values.themeTextColor
}
StudioControls.TextField {
id: columnName
Layout.fillWidth: true
actionIndicator.visible: false
translationIndicator.visible: false
validator: nameValidator
Keys.onEnterPressed: addColumnDialog.addColumnName()
Keys.onReturnPressed: addColumnDialog.addColumnName()
Keys.onEscapePressed: addColumnDialog.reject()
onTextChanged: {
addColumnDialog.nameIsValid = (columnName.text !== ""
&& !root.model.isPropertyAvailable(columnName.text))
}
}
Spacer { implicitHeight: StudioTheme.Values.controlLabelGap }
Label {
Layout.fillWidth: true
text: qsTr("The model already contains \"%1\"!").arg(columnName.text)
visible: columnName.text !== "" && !addColumnDialog.nameIsValid
color: StudioTheme.Values.themeTextColor
wrapMode: Label.WordWrap
padding: 5
background: Rectangle {
color: "transparent"
border.width: StudioTheme.Values.border
border.color: StudioTheme.Values.themeWarning
}
}
Spacer {}
Text {
text: qsTr("Type:")
color: StudioTheme.Values.themeTextColor
}
StudioControls.ComboBox {
id: addedPropertyType
Layout.fillWidth: true
model: CollectionDataTypeModel{}
textRole: "display"
tooltipRole: "toolTip"
actionIndicatorVisible: false
}
Spacer {}
RowLayout {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
spacing: StudioTheme.Values.sectionRowSpacing
HelperWidgets.Button {
enabled: addColumnDialog.nameIsValid
text: qsTr("Add")
onClicked: addColumnDialog.addColumnName()
}
HelperWidgets.Button {
text: qsTr("Cancel")
onClicked: addColumnDialog.reject()
}
}
}
}
}

View File

@@ -1,727 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import CollectionDetails 1.0 as CollectionDetails
import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
Rectangle {
id: root
required property var model
required property var backend
required property var sortedModel
implicitWidth: 300
implicitHeight: 400
color: StudioTheme.Values.themeControlBackground
function closeDialogs() {
editPropertyDialog.reject()
deleteColumnDialog.reject()
toolbar.closeDialogs()
}
MouseArea {
anchors.fill: parent
onClicked: tableView.model.deselectAll()
}
Column {
id: topRow
readonly property real maxAvailableHeight: root.height
visible: root.model.collectionName !== ""
width: parent.width
spacing: 10
CollectionDetailsToolbar {
id: toolbar
model: root.model
backend: root.backend
width: parent.width
}
GridLayout {
id: gridLayout
readonly property real maxAvailableHeight: topRow.maxAvailableHeight
- topRow.spacing
- toolbar.height
columns: 3
rowSpacing: 1
columnSpacing: 1
width: parent.width
anchors {
left: parent.left
leftMargin: StudioTheme.Values.collectionTableHorizontalMargin
}
Rectangle {
id: tableTopLeftCorner
clip: true
visible: !tableView.model.isEmpty
color: StudioTheme.Values.themeControlBackgroundInteraction
border.color: StudioTheme.Values.themeControlBackgroundInteraction
border.width: 2
Layout.preferredWidth: rowIdView.width
Layout.preferredHeight: headerView.height
Layout.minimumWidth: rowIdView.width
Layout.minimumHeight: headerView.height
Text {
anchors.fill: parent
font: headerTextMetrics.font
text: "#"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: StudioTheme.Values.themeTextColor
}
}
HorizontalHeaderView {
id: headerView
property real topPadding: 5
property real bottomPadding: 5
Layout.preferredHeight: headerTextMetrics.height + topPadding + bottomPadding
Layout.columnSpan: 2
syncView: tableView
clip: true
delegate: HeaderDelegate {
selectedItem: tableView.model.selectedColumn
color: StudioTheme.Values.themeControlBackgroundInteraction
MouseArea {
id: topHeaderMouseArea
anchors.fill: parent
anchors.leftMargin: StudioTheme.Values.borderHover
anchors.rightMargin: StudioTheme.Values.borderHover
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
onClicked: (mouse) => {
tableView.model.selectColumn(index)
if (mouse.button === Qt.RightButton) {
let posX = index === root.model.columnCount() - 1 ? parent.width - editPropertyDialog.width : 0
headerMenu.clickedHeaderIndex = index
headerMenu.dialogPos = parent.mapToGlobal(posX, parent.height)
headerMenu.popup()
} else {
headerMenu.close()
}
}
}
ToolTip {
id: topHeaderToolTip
property bool expectedToBeShown: topHeaderMouseArea.containsMouse
visible: expectedToBeShown && text !== ""
delay: 1000
onExpectedToBeShownChanged: {
if (expectedToBeShown)
text = root.model.propertyType(index)
}
}
}
StudioControls.Menu {
id: headerMenu
property int clickedHeaderIndex: -1
property point dialogPos
onClosed: {
headerMenu.clickedHeaderIndex = -1
}
StudioControls.MenuItem {
text: qsTr("Edit")
onTriggered: editPropertyDialog.openDialog(headerMenu.clickedHeaderIndex,
headerMenu.dialogPos)
}
StudioControls.MenuItem {
text: qsTr("Delete")
onTriggered: deleteColumnDialog.popUp(headerMenu.clickedHeaderIndex)
}
StudioControls.MenuItem {
text: qsTr("Sort Ascending")
onTriggered: {
tableView.closeEditor()
tableView.model.sort(headerMenu.clickedHeaderIndex, Qt.AscendingOrder)
}
}
StudioControls.MenuItem {
text: qsTr("Sort Descending")
onTriggered: {
tableView.closeEditor()
tableView.model.sort(headerMenu.clickedHeaderIndex, Qt.DescendingOrder)
}
}
}
}
VerticalHeaderView {
id: rowIdView
syncView: tableView
clip: true
Layout.preferredHeight: tableView.height
Layout.rowSpan: 2
Layout.alignment: Qt.AlignTop + Qt.AlignLeft
width: implicitWidth // suppresses GridLayout warnings when resizing
delegate: HeaderDelegate {
selectedItem: tableView.model.selectedRow
color: StudioTheme.Values.themeControlBackgroundHover
MouseArea {
anchors.fill: parent
anchors.topMargin: StudioTheme.Values.borderHover
anchors.bottomMargin: StudioTheme.Values.borderHover
acceptedButtons: Qt.LeftButton
onClicked: tableView.model.selectRow(index)
}
}
}
TableView {
id: tableView
model: root.sortedModel
clip: true
readonly property real maxAvailableHeight: gridLayout.maxAvailableHeight
- addRowButton.height
- headerView.height
- (2 * gridLayout.rowSpacing)
readonly property real maxAvailableWidth: gridLayout.width
- StudioTheme.Values.collectionTableHorizontalMargin
- rowIdView.width
- addColumnButton.width
- gridLayout.columnSpacing
property real childrenWidth: tableView.contentItem.childrenRect.width
property real childrenHeight: tableView.contentItem.childrenRect.height
property int targetRow
property int targetColumn
Layout.alignment: Qt.AlignTop + Qt.AlignLeft
Layout.preferredWidth: tableView.contentWidth
Layout.preferredHeight: tableView.contentHeight
Layout.minimumWidth: 100
Layout.minimumHeight: 20
Layout.maximumWidth: maxAvailableWidth
Layout.maximumHeight: maxAvailableHeight
columnWidthProvider: function(column) {
if (!isColumnLoaded(column))
return -1
let w = explicitColumnWidth(column)
if (w < 0)
w = implicitColumnWidth(column)
return Math.max(w, StudioTheme.Values.collectionCellMinimumWidth)
}
rowHeightProvider: function(row) {
if (!isRowLoaded(row))
return -1
let h = explicitRowHeight(row)
if (h < 0)
h = implicitRowHeight(row)
return Math.max(h, StudioTheme.Values.collectionCellMinimumHeight)
}
function ensureRowIsVisible(row) {
let rows = tableView.model.rowCount()
let rowIsLoaded = tableView.isRowLoaded(row)
if (row < 0 || row >= rows || rowIsLoaded) {
if (rowIsLoaded)
tableView.positionViewAtRow(row, Qt.AlignLeft | Qt.AlignTop)
tableView.targetRow = -1
return
}
tableView.targetRow = row
tableView.positionViewAtRow(row, Qt.AlignLeft | Qt.AlignTop)
ensureTimer.start()
}
function ensureColumnIsVisible(column) {
let columns = tableView.model.columnCount()
let columnIsLoaded = tableView.isColumnLoaded(column)
if (column < 0 || column >= columns || columnIsLoaded) {
if (columnIsLoaded)
tableView.positionViewAtColumn(column, Qt.AlignLeft | Qt.AlignTop)
tableView.targetColumn = -1
return
}
tableView.targetColumn = column
tableView.positionViewAtColumn(column, Qt.AlignLeft | Qt.AlignTop)
ensureTimer.start()
}
onMaxAvailableHeightChanged: resetSizeTimer.start()
onMaxAvailableWidthChanged: resetSizeTimer.start()
onChildrenWidthChanged: resetSizeTimer.start()
onChildrenHeightChanged: resetSizeTimer.start()
delegate: Rectangle {
id: itemCell
clip: true
implicitWidth: 100
implicitHeight: StudioTheme.Values.baseHeight
color: itemSelected ? StudioTheme.Values.themeControlBackgroundInteraction
: StudioTheme.Values.themeControlBackground
border.width: 1
border.color: {
if (dataTypeWarning !== CollectionDetails.Warning.None)
return StudioTheme.Values.themeWarning
if (itemSelected)
return StudioTheme.Values.themeControlOutlineInteraction
return StudioTheme.Values.themeControlBackgroundInteraction
}
HelperWidgets.ToolTipArea {
anchors.fill: parent
text: root.model.warningToString(dataTypeWarning)
enabled: dataTypeWarning !== CollectionDetails.Warning.None && text !== ""
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: (mouse) => {
let row = index % tableView.model.rowCount()
tableView.model.selectRow(row)
cellContextMenu.showMenu(row)
}
}
Loader {
id: cellContentLoader
property int cellColumnType: columnType ? columnType : 0
Component {
id: cellText
Text {
text: display ?? ""
color: itemSelected ? StudioTheme.Values.themeInteraction
: StudioTheme.Values.themeTextColor
leftPadding: 5
topPadding: 3
bottomPadding: 3
font.pixelSize: StudioTheme.Values.baseFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
Component {
id: colorEditorComponent
ColorViewDelegate {}
}
function resetSource() {
if (columnType === CollectionDetails.DataType.Color)
cellContentLoader.sourceComponent = colorEditorComponent
else
cellContentLoader.sourceComponent = cellText
}
Component.onCompleted: resetSource()
onCellColumnTypeChanged: resetSource()
}
TableView.editDelegate: CollectionDetailsEditDelegate {
anchors {
top: itemCell.top
left: itemCell.left
}
Component.onCompleted: tableView.model.deselectAll()
}
}
Timer {
id: resetSizeTimer
interval: 100
repeat: false
onTriggered: {
let cWidth = Math.min(tableView.maxAvailableWidth, tableView.childrenWidth)
let cHeight = Math.min(tableView.maxAvailableHeight, tableView.childrenHeight)
if (tableView.contentWidth !== cWidth || tableView.contentHeight !== cHeight)
tableView.returnToBounds()
}
}
Timer {
id: ensureTimer
interval: 100
repeat: false
onTriggered: {
tableView.ensureRowIsVisible(tableView.targetRow)
tableView.ensureColumnIsVisible(tableView.targetColumn)
}
}
Connections {
target: tableView.model
function onModelReset() {
root.closeDialogs()
tableView.clearColumnWidths()
tableView.clearRowHeights()
}
function onRowsInserted(parent, first, last) {
tableView.closeEditor()
tableView.model.selectRow(first)
tableView.ensureRowIsVisible(first)
}
function onColumnsInserted(parent, first, last) {
tableView.closeEditor()
tableView.model.selectColumn(first)
tableView.ensureColumnIsVisible(first)
}
function onRowsRemoved(parent, first, last) {
let nextRow = first - 1
if (nextRow < 0 && tableView.model.rowCount(parent) > 0)
nextRow = 0
tableView.model.selectRow(nextRow)
}
function onColumnsRemoved(parent, first, last) {
let nextColumn = first - 1
if (nextColumn < 0 && tableView.model.columnCount(parent) > 0)
nextColumn = 0
tableView.model.selectColumn(nextColumn)
}
}
HoverHandler { id: hoverHandler }
ScrollBar.horizontal: StudioControls.TransientScrollBar {
id: horizontalScrollBar
style: StudioTheme.Values.viewStyle
orientation: Qt.Horizontal
show: (hoverHandler.hovered || tableView.focus || horizontalScrollBar.inUse)
&& horizontalScrollBar.isNeeded
}
ScrollBar.vertical: StudioControls.TransientScrollBar {
id: verticalScrollBar
style: StudioTheme.Values.viewStyle
orientation: Qt.Vertical
show: (hoverHandler.hovered || tableView.focus || verticalScrollBar.inUse)
&& verticalScrollBar.isNeeded
}
}
HelperWidgets.IconButton {
id: addColumnButton
iconSize:16
Layout.preferredWidth: 24
Layout.preferredHeight: tableView.height
Layout.minimumHeight: 24
Layout.alignment: Qt.AlignLeft + Qt.AlignVCenter
icon: StudioTheme.Constants.create_medium
tooltip: "Add Column"
onClicked: toolbar.addNewColumn()
}
HelperWidgets.IconButton {
id: addRowButton
iconSize:16
Layout.preferredWidth: tableView.width
Layout.preferredHeight: 24
Layout.minimumWidth: 24
Layout.alignment: Qt.AlignTop + Qt.AlignHCenter
icon: StudioTheme.Constants.create_medium
tooltip: "Add Row"
onClicked: toolbar.addNewRow()
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
ColumnLayout {
id: importsProblem
visible: !topRow.visible && rootView.dataStoreExists && !rootView.projectImportExists
width: parent.width
anchors.verticalCenter: parent.verticalCenter
clip: true
Text {
text: qsTr("Import the project to your design document to make the Model Editor enabled.")
Layout.alignment: Qt.AlignCenter
Layout.maximumWidth: parent.width
leftPadding: StudioTheme.Values.collectionItemTextPadding
rightPadding: StudioTheme.Values.collectionItemTextPadding
color: StudioTheme.Values.themeTextColor
font.pixelSize: StudioTheme.Values.mediumFontSize
wrapMode: Text.Wrap
}
HelperWidgets.Button {
text: qsTr("Enable DataStore (This will add the required import)")
Layout.alignment: Qt.AlignCenter
onClicked: rootView.addProjectImport()
leftPadding: StudioTheme.Values.collectionItemTextPadding
rightPadding: StudioTheme.Values.collectionItemTextPadding
}
}
Text {
anchors.centerIn: parent
text: qsTr("There are no models in this project.\nAdd or import a model.")
visible: !topRow.visible && !importsProblem.visible
color: StudioTheme.Values.themeTextColor
font.pixelSize: StudioTheme.Values.mediumFontSize
}
TextMetrics {
id: headerTextMetrics
font.pixelSize: StudioTheme.Values.baseFontSize
text: "Xq"
}
StudioControls.Menu {
id: cellContextMenu
property int rowIndex: -1
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
function showMenu(rowIndex) {
cellContextMenu.rowIndex = rowIndex
cellContextMenu.popup()
}
CellContextMenuItem {
id: addRowAboveCellMenuItem
itemText: qsTr("Add row above")
itemIcon: StudioTheme.Constants.addrowabove_medium
onTriggered: root.model.insertRow(cellContextMenu.rowIndex)
}
CellContextMenuItem {
id: addRowBelowCellMenuItem
itemText: qsTr("Add row below")
itemIcon: StudioTheme.Constants.addrowbelow_medium
onTriggered: root.model.insertRow(cellContextMenu.rowIndex + 1)
}
CellContextMenuItem {
id: deleteRowCellMenuItem
itemText: qsTr("Delete row")
itemIcon: StudioTheme.Constants.deleterow_medium
onTriggered: root.model.removeRows(cellContextMenu.rowIndex, 1)
}
}
component HeaderDelegate: Rectangle {
id: headerItem
required property int selectedItem
property alias horizontalAlignment: headerText.horizontalAlignment
property alias verticalAlignment: headerText.verticalAlignment
implicitWidth: headerText.implicitWidth
implicitHeight: headerText.implicitHeight
border.width: 1
clip: true
Text {
id: headerText
topPadding: headerView.topPadding
bottomPadding: headerView.bottomPadding
leftPadding: 5
rightPadding: 5
text: display
font: headerTextMetrics.font
color: StudioTheme.Values.themeTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
states: [
State {
name: "default"
when: index !== selectedItem
PropertyChanges {
target: headerItem
border.color: StudioTheme.Values.themeControlBackgroundInteraction
}
PropertyChanges {
target: headerText
font.bold: false
}
},
State {
name: "selected"
when: index === selectedItem
PropertyChanges {
target: headerItem
border.color: StudioTheme.Values.themeControlBackground
}
PropertyChanges {
target: headerText
font.bold: true
}
}
]
}
component CellContextMenuItem: StudioControls.MenuItem {
id: cellContextMenuItemComponent
property alias itemText: cellContextMenuText.text
property alias itemIcon: cellContextMenuIcon.text
text: ""
implicitWidth: cellContextMenuRow.width
implicitHeight: cellContextMenuRow.height
Row {
id: cellContextMenuRow
property color textColor : cellContextMenuItemComponent.enabled
? cellContextMenuItemComponent.highlighted
? cellContextMenuItemComponent.style.text.selectedText
: cellContextMenuItemComponent.style.text.idle
: cellContextMenuItemComponent.style.text.disabled
spacing: 2 * StudioTheme.Values.contextMenuHorizontalPadding
height: StudioTheme.Values.defaultControlHeight
leftPadding: StudioTheme.Values.contextMenuHorizontalPadding
rightPadding: StudioTheme.Values.contextMenuHorizontalPadding
Text {
id: cellContextMenuIcon
color: cellContextMenuRow.textColor
text: StudioTheme.Constants.addrowabove_medium
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.myIconFontSize
anchors.verticalCenter: parent.verticalCenter
}
Text {
id: cellContextMenuText
color: cellContextMenuRow.textColor
anchors.verticalCenter: parent.verticalCenter
}
}
}
EditPropertyDialog {
id: editPropertyDialog
model: root.model
}
StudioControls.Dialog {
id: deleteColumnDialog
property int clickedIndex: -1
title: qsTr("Delete Column")
width: 400
onAccepted: {
root.model.removeColumn(clickedIndex)
}
function popUp(index)
{
deleteColumnDialog.clickedIndex = index
deleteColumnDialog.open()
}
contentItem: ColumnLayout {
spacing: StudioTheme.Values.sectionColumnSpacing
Text {
text: qsTr("Are you sure that you want to delete column \"%1\"?").arg(
root.model.headerData(
deleteColumnDialog.clickedIndex, Qt.Horizontal))
color: StudioTheme.Values.themeTextColor
}
RowLayout {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
spacing: StudioTheme.Values.sectionRowSpacing
HelperWidgets.Button {
text: qsTr("Delete")
onClicked: deleteColumnDialog.accept()
}
HelperWidgets.Button {
text: qsTr("Cancel")
onClicked: deleteColumnDialog.reject()
}
}
}
}
}

View File

@@ -1,154 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme as StudioTheme
import CollectionEditorBackend
Item {
id: root
implicitWidth: 300
implicitHeight: boundingRect.height + 3
property color textColor
readonly property string name: collectionName ?? ""
readonly property bool isSelected: collectionIsSelected
readonly property int id: index
function rename(newName) {
collectionName = newName
}
signal selectItem(int itemIndex)
signal deleteItem()
signal contextMenuRequested()
Item {
id: boundingRect
width: parent.width
height: itemLayout.height
clip: true
MouseArea {
id: itemMouse
anchors.fill: parent
acceptedButtons: Qt.LeftButton
propagateComposedEvents: true
hoverEnabled: true
onClicked: (event) => {
if (!collectionIsSelected) {
collectionIsSelected = true
event.accepted = true
}
}
}
Rectangle {
id: innerRect
anchors.fill: parent
}
RowLayout {
id: itemLayout
width: parent.width
Text {
id: nameHolder
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.leftMargin: StudioTheme.Values.collectionItemTextSideMargin
Layout.topMargin: StudioTheme.Values.collectionItemTextMargin
Layout.bottomMargin: StudioTheme.Values.collectionItemTextMargin
text: collectionName
font.pixelSize: StudioTheme.Values.baseFontSize
color: root.textColor
topPadding: StudioTheme.Values.collectionItemTextPadding
bottomPadding: StudioTheme.Values.collectionItemTextPadding
elide: Text.ElideMiddle
verticalAlignment: Text.AlignVCenter
}
Text {
id: threeDots
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.topMargin: StudioTheme.Values.collectionItemTextMargin
Layout.bottomMargin: StudioTheme.Values.collectionItemTextMargin
Layout.rightMargin: StudioTheme.Values.collectionItemTextSideMargin
text: StudioTheme.Constants.more_medium
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.baseIconFontSize
color: root.textColor
padding: StudioTheme.Values.collectionItemTextPadding
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
onClicked: contextMenuRequested()
}
}
}
}
states: [
State {
name: "default"
when: !collectionIsSelected && !itemMouse.containsMouse
PropertyChanges {
target: innerRect
opacity: 0.6
color: StudioTheme.Values.themeControlBackground
}
PropertyChanges {
target: root
textColor: StudioTheme.Values.themeTextColor
}
},
State {
name: "hovered"
when: !collectionIsSelected && itemMouse.containsMouse
PropertyChanges {
target: innerRect
opacity: 0.8
color: StudioTheme.Values.themeControlBackgroundHover
}
PropertyChanges {
target: root
textColor: StudioTheme.Values.themeTextColor
}
},
State {
name: "selected"
when: collectionIsSelected
PropertyChanges {
target: innerRect
opacity: 1
color: StudioTheme.Values.themeIconColorSelected
}
PropertyChanges {
target: root
textColor: StudioTheme.Values.themeTextSelectedTextColor
}
}
]
}

View File

@@ -1,215 +0,0 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme as StudioTheme
import CollectionEditorBackend
ListView {
id: root
model: CollectionEditorBackend.model
clip: true
function closeDialogs() {
currentCollection.dereference()
collectionMenu.close()
deleteDialog.reject()
renameDialog.reject()
}
delegate: CollectionItem {
implicitWidth: root.width
onDeleteItem: root.model.removeRow(index)
onContextMenuRequested: collectionMenu.openMenu(this)
}
QtObject {
id: currentCollection
property CollectionItem item
readonly property string name: item ? item.name : ""
readonly property bool selected: item ? item.isSelected : false
readonly property int index: item ? item.id : -1
function rename(newName) {
if (item)
item.rename(newName)
}
function deleteItem() {
if (item)
item.deleteItem()
}
function dereference() {
item = null
}
}
StudioControls.Menu {
id: collectionMenu
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
function openMenu(item) {
currentCollection.item = item
popup()
}
StudioControls.MenuItem {
text: qsTr("Delete")
shortcut: StandardKey.Delete
onTriggered: deleteDialog.open()
}
StudioControls.MenuItem {
text: qsTr("Rename")
shortcut: StandardKey.Replace
onTriggered: renameDialog.open()
}
StudioControls.MenuItem {
text: qsTr("Assign to the selected node")
enabled: CollectionEditorBackend.rootView.targetNodeSelected
onTriggered: rootView.assignCollectionToSelectedNode(currentCollection.name)
}
}
StudioControls.Dialog {
id: deleteDialog
title: qsTr("Deleting the model")
clip: true
onAccepted: currentCollection.deleteItem()
contentItem: ColumnLayout {
id: deleteDialogContent // Keep the id here even if it's not used, because the dialog might lose implicitSize
width: 300
spacing: 2
Text {
Layout.fillWidth: true
wrapMode: Text.WordWrap
color: StudioTheme.Values.themeTextColor
text: qsTr("Are you sure that you want to delete model \"%1\"?"
+ "\nThe model will be deleted permanently.").arg(currentCollection.name)
}
Spacer {}
RowLayout {
spacing: StudioTheme.Values.sectionRowSpacing
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.fillWidth: true
Layout.preferredHeight: 40
HelperWidgets.Button {
text: qsTr("Delete")
onClicked: deleteDialog.accept()
}
HelperWidgets.Button {
text: qsTr("Cancel")
onClicked: deleteDialog.reject()
}
}
}
}
StudioControls.Dialog {
id: renameDialog
title: qsTr("Rename model")
onAccepted: {
if (newNameField.text !== "")
currentCollection.rename(newNameField.text)
}
onOpened: {
newNameField.text = currentCollection.name
}
contentItem: ColumnLayout {
spacing: 2
Text {
text: qsTr("Previous name: " + currentCollection.name)
color: StudioTheme.Values.themeTextColor
}
Spacer {}
Text {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
text: qsTr("New name:")
color: StudioTheme.Values.themeTextColor
}
StudioControls.TextField {
id: newNameField
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
actionIndicator.visible: false
translationIndicator.visible: false
validator: newNameValidator
Keys.onEnterPressed: renameDialog.accept()
Keys.onReturnPressed: renameDialog.accept()
Keys.onEscapePressed: renameDialog.reject()
onTextChanged: {
btnRename.enabled = newNameField.text !== ""
}
}
Spacer {}
RowLayout {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
spacing: StudioTheme.Values.sectionRowSpacing
HelperWidgets.Button {
id: btnRename
text: qsTr("Rename")
onClicked: renameDialog.accept()
}
HelperWidgets.Button {
text: qsTr("Cancel")
onClicked: renameDialog.reject()
}
}
}
}
Connections {
target: root.model
function onModelReset() {
root.closeDialogs()
}
}
RegularExpressionValidator {
id: newNameValidator
regularExpression: /^\w+$/
}
component Spacer: Item {
implicitWidth: 1
implicitHeight: StudioTheme.Values.columnGap
}
}

View File

@@ -1,206 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import HelperWidgets as HelperWidgets
import StudioTheme as StudioTheme
import CollectionEditorBackend
Item {
id: root
focus: true
property var rootView: CollectionEditorBackend.rootView
property var model: CollectionEditorBackend.model
property var collectionDetailsModel: CollectionEditorBackend.collectionDetailsModel
property var collectionDetailsSortFilterModel: CollectionEditorBackend.collectionDetailsSortFilterModel
function showWarning(title, message) {
warningDialog.title = title
warningDialog.message = message
warningDialog.open()
}
// called from C++ when using the delete key
function deleteSelectedCollection() {
print("TODO: deleteSelectedCollection")
}
function closeDialogs() {
importDialog.reject()
newCollection.reject()
warningDialog.reject()
}
ImportDialog {
id: importDialog
backendValue: root.rootView
anchors.centerIn: parent
}
NewCollectionDialog {
id: newCollection
anchors.centerIn: parent
}
Message {
id: warningDialog
title: ""
message: ""
}
Rectangle {
// Covers the toolbar color on top to prevent the background
// color for the margin of splitter
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: topToolbar.height
color: topToolbar.color
}
SplitView {
id: splitView
readonly property bool isHorizontal: splitView.orientation === Qt.Horizontal
orientation: width >= 500 ? Qt.Horizontal : Qt.Vertical
anchors.fill: parent
onOrientationChanged: detailsView.closeDialogs()
handle: Item {
id: handleDelegate
property color color: SplitHandle.pressed ? StudioTheme.Values.themeControlOutlineInteraction
: SplitHandle.hovered ? StudioTheme.Values.themeControlOutlineHover
: StudioTheme.Values.themeControlOutline
implicitWidth: 1
implicitHeight: 1
Rectangle {
id: handleRect
property real verticalMargin: splitView.isHorizontal ? StudioTheme.Values.splitterMargin : 0
property real horizontalMargin: splitView.isHorizontal ? 0 : StudioTheme.Values.splitterMargin
anchors.fill: parent
anchors.topMargin: handleRect.verticalMargin
anchors.bottomMargin: handleRect.verticalMargin
anchors.leftMargin: handleRect.horizontalMargin
anchors.rightMargin: handleRect.horizontalMargin
color: handleDelegate.color
}
containmentMask: Item {
x: splitView.isHorizontal ? ((handleDelegate.width - width) / 2) : 0
y: splitView.isHorizontal ? 0 : ((handleDelegate.height - height) / 2)
height: splitView.isHorizontal ? handleDelegate.height : StudioTheme.Values.borderHover
width: splitView.isHorizontal ? StudioTheme.Values.borderHover : handleDelegate.width
}
}
ColumnLayout {
id: collectionsSideBar
spacing: 0
SplitView.minimumWidth: 200
SplitView.maximumWidth: 450
SplitView.minimumHeight: 200
SplitView.maximumHeight: 400
SplitView.fillWidth: !splitView.isHorizontal
SplitView.fillHeight: splitView.isHorizontal
Rectangle {
id: topToolbar
color: StudioTheme.Values.themeToolbarBackground
Layout.preferredHeight: StudioTheme.Values.toolbarHeight
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: StudioTheme.Values.toolbarHorizontalMargin
text: qsTr("Data Models")
font.pixelSize: StudioTheme.Values.baseFontSize
color: StudioTheme.Values.themeTextColor
}
HelperWidgets.AbstractButton {
id: importCollectionButton
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: StudioTheme.Values.toolbarHorizontalMargin
style: StudioTheme.Values.viewBarButtonStyle
buttonIcon: StudioTheme.Constants.import_medium
tooltip: qsTr("Import a model")
onClicked: importDialog.open()
}
}
CollectionListView { // Model Groups
id: collectionListView
Layout.fillWidth: true
Layout.minimumHeight: bottomSpacer.isExpanded ? 150 : 0
Layout.fillHeight: !bottomSpacer.isExpanded
Layout.preferredHeight: contentHeight
Layout.maximumHeight: contentHeight
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
}
HelperWidgets.IconButton {
id: addCollectionButton
iconSize: 16
Layout.fillWidth: true
Layout.minimumWidth: 24
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
tooltip: qsTr("Add a new model")
icon: StudioTheme.Constants.create_medium
onClicked: newCollection.open()
}
Item {
id: bottomSpacer
readonly property bool isExpanded: height > 0
Layout.minimumWidth: 1
Layout.fillHeight: true
}
}
CollectionDetailsView {
id: detailsView
model: root.collectionDetailsModel
backend: root.model
sortedModel: root.collectionDetailsSortFilterModel
SplitView.fillHeight: true
SplitView.fillWidth: true
}
}
Connections {
target: root.model
function onModelReset() {
root.closeDialogs()
}
}
}

View File

@@ -1,296 +0,0 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes
import QtQuick.Templates as T
import HelperWidgets 2.0 as HelperWidgets
import StudioTheme as StudioTheme
import StudioControls as StudioControls
import QtQuickDesignerTheme
import QtQuickDesignerColorPalette
Row {
id: colorEditor
property color color
property bool supportGradient: false
property QtObject backendValue: QtObject {
property color value: edit
readonly property color editColor: edit
function resetValue() {
if (value)
value = ""
}
onValueChanged: {
if (editColor !== value)
edit = value
}
}
property variant value: {
if (!colorEditor.backendValue || !colorEditor.backendValue.value)
return "white" // default color for Rectangle
if (colorEditor.isVector3D) {
return Qt.rgba(colorEditor.backendValue.value.x,
colorEditor.backendValue.value.y,
colorEditor.backendValue.value.z, 1)
}
return colorEditor.backendValue.value
}
property alias gradientPropertyName: popupDialog.gradientPropertyName
property alias gradientThumbnail: gradientThumbnail
property alias shapeGradientThumbnail: shapeGradientThumbnail
property bool shapeGradients: false
property bool isVector3D: false
property color originalColor
property bool __block: false
function resetShapeColor() {
colorEditor.backendValue.resetValue()
}
function writeColor() {
if (colorEditor.isVector3D) {
colorEditor.backendValue.value = Qt.vector3d(colorEditor.color.r,
colorEditor.color.g,
colorEditor.color.b)
} else {
colorEditor.backendValue.value = colorEditor.color
}
}
function initEditor() {
colorEditor.syncColor()
}
// Syncing color from backend to frontend and block reflection
function syncColor() {
colorEditor.__block = true
colorEditor.color = colorEditor.value
hexTextField.syncColor()
colorEditor.__block = false
}
Connections {
id: backendConnection
target: colorEditor
function onValueChanged() {
if (popupDialog.isSolid())
colorEditor.syncColor()
}
function onBackendValueChanged() {
if (popupDialog.isSolid())
colorEditor.syncColor()
}
}
Timer {
id: colorEditorTimer
repeat: false
interval: 100
running: false
onTriggered: {
backendConnection.enabled = false
colorEditor.writeColor()
hexTextField.syncColor()
backendConnection.enabled = true
}
}
onColorChanged: {
if (colorEditor.__block)
return
if (!popupDialog.isInValidState)
return
popupDialog.commitToGradient()
// Delay setting the color to keep ui responsive
if (popupDialog.isSolid())
colorEditorTimer.restart()
}
Rectangle {
id: preview
implicitWidth: StudioTheme.Values.twoControlColumnWidth
implicitHeight: StudioTheme.Values.height
color: colorEditor.color
border.color: StudioTheme.Values.themeControlOutline
border.width: StudioTheme.Values.border
Rectangle {
id: gradientThumbnail
anchors.fill: parent
anchors.margins: StudioTheme.Values.border
visible: !popupDialog.isSolid()
&& !colorEditor.shapeGradients
&& popupDialog.isLinearGradient()
}
Shape {
id: shape
anchors.fill: parent
anchors.margins: StudioTheme.Values.border
visible: !popupDialog.isSolid() && colorEditor.shapeGradients
ShapePath {
id: shapeGradientThumbnail
startX: shape.x - 1
startY: shape.y - 1
strokeWidth: -1
strokeColor: "green"
PathLine {
x: shape.x - 1
y: shape.height
}
PathLine {
x: shape.width
y: shape.height
}
PathLine {
x: shape.width
y: shape.y - 1
}
}
}
Image {
anchors.fill: parent
source: "qrc:/navigator/icon/checkers.png"
fillMode: Image.Tile
z: -1
}
MouseArea {
anchors.fill: parent
onClicked: {
popupDialog.visibility ? popupDialog.close() : popupDialog.open()
forceActiveFocus()
}
}
StudioControls.PopupDialog {
id: popupDialog
property bool isInValidState: loader.active ? popupDialog.loaderItem.isInValidState : true
property QtObject loaderItem: loader.item
property string gradientPropertyName
keepOpen: loader.item?.eyeDropperActive ?? false
width: 260
function commitToGradient() {
if (!loader.active)
return
if (colorEditor.supportGradient && popupDialog.loaderItem.gradientModel.hasGradient) {
var hexColor = convertColorToString(colorEditor.color)
hexTextField.text = hexColor
colorEditor.backendValue.value = hexColor
popupDialog.loaderItem.commitGradientColor()
}
}
function isSolid() {
if (!loader.active)
return true
return popupDialog.loaderItem.isSolid()
}
function isLinearGradient(){
if (!loader.active)
return false
return popupDialog.loaderItem.isLinearGradient()
}
function ensureLoader() {
if (!loader.active)
loader.active = true
}
function open() {
popupDialog.ensureLoader()
popupDialog.loaderItem.initEditor()
popupDialog.show(preview)
}
function determineActiveColorMode() {
if (loader.active && popupDialog.loaderItem)
popupDialog.loaderItem.determineActiveColorMode()
else
colorEditor.syncColor()
}
Loader {
id: loader
active: colorEditor.supportGradient
sourceComponent: HelperWidgets.ColorEditorPopup {
shapeGradients: colorEditor.shapeGradients
supportGradient: colorEditor.supportGradient
width: popupDialog.contentWidth
}
onLoaded: {
popupDialog.loaderItem.initEditor()
popupDialog.titleBar = loader.item.titleBarContent
}
}
}
}
HelperWidgets.LineEdit {
id: hexTextField
implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
width: hexTextField.implicitWidth
enabled: popupDialog.isSolid()
writeValueManually: true
validator: RegularExpressionValidator {
regularExpression: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g
}
showTranslateCheckBox: false
showExtendedFunctionButton: false
indicatorVisible: false
onAccepted: colorEditor.color = hexTextField.text
onCommitData: {
colorEditor.color = hexTextField.text
if (popupDialog.isSolid())
colorEditor.writeColor()
}
function syncColor() {
hexTextField.text = colorEditor.color
}
}
Component.onCompleted: popupDialog.determineActiveColorMode()
onBackendValueChanged: popupDialog.determineActiveColorMode()
}

View File

@@ -1,158 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import StudioTheme 1.0 as StudioTheme
import StudioControls 1.0 as StudioControls
import HelperWidgets 2.0 as HelperWidgets
import CollectionDetails
StudioControls.Dialog {
id: root
required property var model
property int __propertyIndex: -1
property string __currentName
title: qsTr("Edit Column")
function openDialog(index, initialPosition) {
root.__propertyIndex = index
if (root.__propertyIndex < 0)
return
root.__currentName = root.model.propertyName(root.__propertyIndex)
nameTextField.text = root.__currentName
nameTextField.selectAll()
nameTextField.forceActiveFocus()
typeComboBox.initialType = root.model.propertyType(root.__propertyIndex)
typeComboBox.currentIndex = typeComboBox.find(typeComboBox.initialType)
let newPoint = mapFromGlobal(initialPosition.x, initialPosition.y)
x = newPoint.x
y = newPoint.y
root.open()
}
onWidthChanged: {
if (visible && x > parent.width)
root.close()
}
onAccepted: {
if (nameTextField.text !== "" && nameTextField.text !== root.__currentName)
root.model.renameColumn(root.__propertyIndex, nameTextField.text)
if (typeComboBox.initialType !== typeComboBox.currentText)
root.model.setPropertyType(root.__propertyIndex, typeComboBox.currentText)
}
contentItem: Column {
spacing: 5
Grid {
columns: 2
rows: 2
rowSpacing: 2
columnSpacing: 25
verticalItemAlignment: Grid.AlignVCenter
Text {
text: qsTr("Name")
color: StudioTheme.Values.themeTextColor
verticalAlignment: Text.AlignVCenter
}
StudioControls.TextField {
id: nameTextField
actionIndicator.visible: false
translationIndicator.visible: false
Keys.onEnterPressed: root.accept()
Keys.onReturnPressed: root.accept()
Keys.onEscapePressed: root.reject()
validator: RegularExpressionValidator {
regularExpression: /^\w+$/
}
}
Text {
text: qsTr("Type")
color: StudioTheme.Values.themeTextColor
}
StudioControls.ComboBox {
id: typeComboBox
property string initialType
model: CollectionDataTypeModel{}
textRole: "display"
tooltipRole: "toolTip"
actionIndicatorVisible: false
}
}
Rectangle {
id: warningBox
visible: typeComboBox.initialType !== typeComboBox.currentText
color: "transparent"
clip: true
border.color: StudioTheme.Values.themeWarning
width: parent.width
height: warning.height
Row {
id: warning
padding: 5
spacing: 5
HelperWidgets.IconLabel {
icon: StudioTheme.Constants.warning_medium
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: qsTr("Conversion from %1 to %2 may lead to data loss")
.arg(typeComboBox.initialType)
.arg(typeComboBox.currentText)
width: warningBox.width - 20
color: StudioTheme.Values.themeTextColor
wrapMode: Text.WordWrap
}
}
}
Row {
height: 40
spacing: 5
HelperWidgets.Button {
id: editButton
text: qsTr("Apply")
enabled: nameTextField.text !== ""
anchors.bottom: parent.bottom
onClicked: root.accept()
}
HelperWidgets.Button {
text: qsTr("Cancel")
anchors.bottom: parent.bottom
onClicked: root.reject()
}
}
}
}

View File

@@ -1,97 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import StudioTheme as StudioTheme
Rectangle {
id: root
required property string text
required property string icon
property alias tooltip: toolTip.text
property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
property int fontSize: StudioTheme.Values.baseFontSize
implicitHeight: style.squareControlSize.height
implicitWidth: rowAlign.width
signal clicked()
RowLayout {
id: rowAlign
anchors.verticalCenter: parent.verticalCenter
spacing: StudioTheme.Values.inputHorizontalPadding
Text {
id: iconItem
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
text: root.icon
color: StudioTheme.Values.themeTextColor
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.bigFont
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
leftPadding: StudioTheme.Values.inputHorizontalPadding
}
Text {
id: textItem
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
text: root.text
color: StudioTheme.Values.themeTextColor
font.family: StudioTheme.Constants.font.family
font.pixelSize: StudioTheme.Values.baseFontSize
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
rightPadding: StudioTheme.Values.inputHorizontalPadding
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked()
}
ToolTip {
id: toolTip
visible: mouseArea.containsMouse && text !== ""
delay: 1000
}
states: [
State {
name: "default"
when: !mouseArea.pressed && !mouseArea.containsMouse
PropertyChanges {
target: root
color: StudioTheme.Values.themeControlBackground
}
},
State {
name: "Pressed"
when: mouseArea.pressed
PropertyChanges {
target: root
color: StudioTheme.Values.themeControlBackgroundInteraction
}
},
State {
name: "Hovered"
when: !mouseArea.pressed && mouseArea.containsMouse
PropertyChanges {
target: root
color: StudioTheme.Values.themeControlBackgroundHover
}
}
]
}

View File

@@ -1,225 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt.labs.platform as PlatformWidgets
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
StudioControls.Dialog {
id: root
title: qsTr("Import a model")
anchors.centerIn: parent
closePolicy: Popup.CloseOnEscape
modal: true
required property var backendValue
property bool fileExists: false
onOpened: {
collectionName.text = "Model"
fileName.text = qsTr("Model path")
fileName.selectAll()
fileName.forceActiveFocus()
}
onRejected: {
fileName.text = ""
}
function acceptIfIsValid() {
if (btnImport.enabled)
btnImport.onClicked()
}
RegularExpressionValidator {
id: fileNameValidator
regularExpression: /^(\w[^*><?|]*)[^/\\:*><?|]$/
}
PlatformWidgets.FileDialog {
id: fileDialog
nameFilters : ["All Model Files (*.json *.csv)",
"JSON Files (*.json)",
"Comma-Separated Values (*.csv)"]
title: qsTr("Select a model file")
fileMode: PlatformWidgets.FileDialog.OpenFile
acceptLabel: qsTr("Open")
onAccepted: fileName.text = fileDialog.file
}
Message {
id: creationFailedDialog
title: qsTr("Could not load the file")
message: qsTr("An error occurred while trying to load the file.")
onClosed: root.reject()
}
component Spacer: Item {
implicitWidth: 1
implicitHeight: StudioTheme.Values.columnGap
}
contentItem: ColumnLayout {
spacing: 2
Keys.onEnterPressed: root.acceptIfIsValid()
Keys.onReturnPressed: root.acceptIfIsValid()
Keys.onEscapePressed: root.reject()
Text {
text: qsTr("File name")
color: StudioTheme.Values.themeTextColor
}
RowLayout {
spacing: StudioTheme.Values.sectionRowSpacing
Layout.fillWidth: true
StudioControls.TextField {
id: fileName
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
actionIndicator.visible: false
translationIndicator.visible: false
validator: fileNameValidator
onTextChanged: root.fileExists = root.backendValue.isValidUrlToImport(fileName.text)
}
HelperWidgets.Button {
id: fileDialogButton
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
text: qsTr("Open")
onClicked: fileDialog.open()
}
}
Spacer {}
Text {
text: qsTr("The model name")
color: StudioTheme.Values.themeTextColor
}
StudioControls.TextField {
id: collectionName
Layout.fillWidth: true
actionIndicator.visible: false
translationIndicator.visible: false
validator: RegularExpressionValidator {
regularExpression: /^[\w ]+$/
}
}
Spacer { implicitHeight: StudioTheme.Values.controlLabelGap }
Label {
id: fieldErrorText
Layout.fillWidth: true
color: StudioTheme.Values.themeTextColor
wrapMode: Label.WordWrap
padding: 5
background: Rectangle {
color: "transparent"
border.width: StudioTheme.Values.border
border.color: StudioTheme.Values.themeWarning
}
states: [
State {
name: "default"
when: fileName.text !== "" && collectionName.text !== ""
PropertyChanges {
target: fieldErrorText
text: ""
visible: false
}
},
State {
name: "fileError"
when: fileName.text === ""
PropertyChanges {
target: fieldErrorText
text: qsTr("File name can not be empty")
visible: true
}
},
State {
name: "collectionNameError"
when: collectionName.text === ""
PropertyChanges {
target: fieldErrorText
text: qsTr("The model name can not be empty")
visible: true
}
}
]
}
Spacer {}
StudioControls.CheckBox {
id: csvFirstRowIsHeader
visible: root.fileExists && fileName.text.endsWith(".csv")
text: qsTr("Consider first row as headers")
checked: true
actionIndicatorVisible: false
}
Spacer {}
RowLayout {
spacing: StudioTheme.Values.sectionRowSpacing
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
HelperWidgets.Button {
id: btnImport
text: qsTr("Import")
enabled: root.fileExists && collectionName.text !== ""
onClicked: {
let collectionImported = root.backendValue.importFile(
collectionName.text,
fileName.text,
csvFirstRowIsHeader.checked)
if (collectionImported)
root.accept()
else
creationFailedDialog.open()
}
}
HelperWidgets.Button {
text: qsTr("Cancel")
onClicked: root.reject()
}
}
}
}

View File

@@ -1,42 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme as StudioTheme
StudioControls.Dialog {
id: root
required property string message
anchors.centerIn: parent
closePolicy: Popup.CloseOnEscape
implicitWidth: 300
modal: true
contentItem: ColumnLayout {
spacing: StudioTheme.Values.sectionColumnSpacing
Text {
Layout.fillWidth: true
text: root.message
color: StudioTheme.Values.themeTextColor
wrapMode: Text.WordWrap
leftPadding: 10
rightPadding: 10
}
HelperWidgets.Button {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
text: qsTr("Close")
onClicked: root.reject()
}
}
onOpened: root.forceActiveFocus()
}

View File

@@ -1,111 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
import CollectionEditorBackend
StudioControls.Dialog {
id: root
property bool nameExists: false
readonly property bool isValid: collectionName.text !== "" && !root.nameExists
title: qsTr("Add a new model")
closePolicy: Popup.CloseOnEscape
modal: true
onOpened: {
collectionName.text = CollectionEditorBackend.model.getUniqueCollectionName()
}
onRejected: {
collectionName.text = ""
}
onAccepted: {
if (root.isValid)
root.CollectionEditorBackend.rootView.addCollectionToDataStore(collectionName.text);
}
ColumnLayout {
spacing: 5
NameField {
text: qsTr("Name")
}
StudioControls.TextField {
id: collectionName
Layout.fillWidth: true
actionIndicator.visible: false
translationIndicator.visible: false
validator: RegularExpressionValidator {
regularExpression: /^[\w ]+$/
}
Keys.onEnterPressed: btnCreate.onClicked()
Keys.onReturnPressed: btnCreate.onClicked()
Keys.onEscapePressed: root.reject()
onTextChanged: {
root.nameExists = CollectionEditorBackend.model.collectionExists(collectionName.text)
}
}
ErrorField {
id: errorField
text: {
if (collectionName.text === "")
return qsTr("Name can not be empty")
else if (root.nameExists)
return qsTr("Name '%1' already exists").arg(collectionName.text)
else
return ""
}
}
Spacer {}
Row {
spacing: StudioTheme.Values.sectionRowSpacing
HelperWidgets.Button {
id: btnCreate
text: qsTr("Create")
enabled: root.isValid
onClicked: root.accept()
}
HelperWidgets.Button {
text: qsTr("Cancel")
onClicked: root.reject()
}
}
}
component NameField: Text {
color: StudioTheme.Values.themeTextColor
font.family: StudioTheme.Constants.font.family
font.pixelSize: StudioTheme.Values.baseIconFontSize
}
component ErrorField: Text {
color: StudioTheme.Values.themeError
font.family: StudioTheme.Constants.font.family
font.pixelSize: StudioTheme.Values.baseIconFontSize
}
component Spacer: Item {
width: 1
height: StudioTheme.Values.columnGap
}
}

View File

@@ -11,6 +11,8 @@ StudioControls.PopupDialog {
property alias backend: form.backend property alias backend: form.backend
keepOpen: form.keepOpen
titleBar: Row { titleBar: Row {
spacing: 30 // TODO spacing: 30 // TODO
anchors.fill: parent anchors.fill: parent
@@ -43,6 +45,8 @@ StudioControls.PopupDialog {
ConnectionsDialogForm { ConnectionsDialogForm {
id: form id: form
parentWindow: root.window
Connections { Connections {
target: root.backend target: root.backend
function onPopupShouldClose() { function onPopupShouldClose() {

View File

@@ -16,6 +16,9 @@ Column {
property var backend property var backend
property bool keepOpen: expressionDialogLoader.visible
property Window parentWindow: null
width: parent.width width: parent.width
spacing: root.verticalSpacing spacing: root.verticalSpacing
@@ -267,10 +270,8 @@ Column {
horizontalAlignment: code.lineCount === 1 ? Text.AlignHCenter : Text.AlignLeft horizontalAlignment: code.lineCount === 1 ? Text.AlignHCenter : Text.AlignLeft
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight elide: Text.ElideRight
} }
Loader { Loader {
id: expressionDialogLoader id: expressionDialogLoader
parent: editor parent: editor
@@ -297,19 +298,19 @@ Column {
id: bindingEditor id: bindingEditor
onRejected: { onRejected: {
hideWidget() bindingEditor.hideWidget()
expressionDialogLoader.visible = false expressionDialogLoader.visible = false
} }
onAccepted: { onAccepted: {
backend.setNewSource(bindingEditor.text) backend.setNewSource(bindingEditor.text)
hideWidget() bindingEditor.hideWidget()
expressionDialogLoader.visible = false expressionDialogLoader.visible = false
} }
} }
} }
} // loader }
} // rect }
} //col 2 }
}//col1 }

View File

@@ -115,25 +115,25 @@ Item {
width: parent.width width: parent.width
height: StudioTheme.Values.toolbarHeight height: StudioTheme.Values.toolbarHeight
Component.onCompleted: { tabsModel: [
var tabs = [
{ name: qsTr("Materials"), icon: StudioTheme.Constants.material_medium }, { name: qsTr("Materials"), icon: StudioTheme.Constants.material_medium },
{ name: qsTr("Textures"), icon: StudioTheme.Constants.textures_medium }, { name: qsTr("Textures"), icon: StudioTheme.Constants.textures_medium },
{ name: qsTr("Environments"), icon: StudioTheme.Constants.languageList_medium }, { name: qsTr("Environments"), icon: StudioTheme.Constants.languageList_medium },
{ name: qsTr("Effects"), icon: StudioTheme.Constants.effects } { name: qsTr("Effects"), icon: StudioTheme.Constants.effects },
]; { name: qsTr("User Assets"), icon: StudioTheme.Constants.effects } // TODO: update icon
if (ContentLibraryBackend.rootView.userBundleEnabled()) ]
tabs.push({ name: qsTr("User Assets"), icon: StudioTheme.Constants.effects });
tabBar.tabsModel = tabs;
}
} }
} }
} }
UnimportBundleMaterialDialog { UnimportBundleItemDialog {
id: confirmUnimportDialog id: confirmUnimportDialog
} }
DeleteBundleItemDialog {
id: confirmDeleteDialog
}
StackLayout { StackLayout {
id: stackLayout id: stackLayout
width: root.width width: root.width
@@ -246,6 +246,12 @@ Item {
confirmUnimportDialog.open() confirmUnimportDialog.open()
} }
onRemoveFromContentLib: (bundleItem) => {
confirmDeleteDialog.targetBundleItem = bundleItem
confirmDeleteDialog.targetBundleLabel = "material"
confirmDeleteDialog.open()
}
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height) onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
} }
} }

View File

@@ -12,7 +12,7 @@ StudioControls.Menu {
property var targetItem: null property var targetItem: null
readonly property bool targetAvailable: targetItem && !ContentLibraryBackend.effectsModel.importerRunning readonly property bool targetAvailable: targetItem && !ContentLibraryBackend.rootView.importerRunning
signal unimport(var bundleEff); signal unimport(var bundleEff);

View File

@@ -91,7 +91,7 @@ HelperWidgets.ScrollView {
id: repeater id: repeater
model: bundleCategoryItems model: bundleCategoryItems
delegate: ContentLibraryEffect { delegate: ContentLibraryItem {
width: root.cellWidth width: root.cellWidth
height: root.cellHeight height: root.cellHeight

View File

@@ -23,8 +23,8 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => { onPressed: (mouse) => {
if (mouse.button === Qt.LeftButton && !ContentLibraryBackend.effectsModel.importerRunning) if (mouse.button === Qt.LeftButton && !ContentLibraryBackend.rootView.importerRunning)
ContentLibraryBackend.rootView.startDragEffect(modelData, mapToGlobal(mouse.x, mouse.y)) ContentLibraryBackend.rootView.startDragItem(modelData, mapToGlobal(mouse.x, mouse.y))
else if (mouse.button === Qt.RightButton) else if (mouse.button === Qt.RightButton)
root.showContextMenu() root.showContextMenu()
} }
@@ -43,7 +43,7 @@ Item {
source: modelData.bundleItemIcon source: modelData.bundleItemIcon
cache: false cache: false
Rectangle { // circular indicator for imported bundle effect Rectangle { // circular indicator for imported bundle item
width: 10 width: 10
height: 10 height: 10
radius: 5 radius: 5
@@ -57,7 +57,7 @@ Item {
ToolTip { ToolTip {
visible: indicatorMouseArea.containsMouse visible: indicatorMouseArea.containsMouse
text: qsTr("Effect is imported to project") text: qsTr("Item is imported to the project")
delay: 1000 delay: 1000
} }

View File

@@ -0,0 +1,71 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import StudioControls as StudioControls
import StudioTheme as StudioTheme
import ContentLibraryBackend
StudioControls.Menu {
id: root
property var targetItem: null
property bool enableRemove: false // true: adds an option to remove targetItem
readonly property bool targetAvailable: targetItem && !ContentLibraryBackend.rootView.importerRunning
signal unimport();
signal addToProject()
signal applyToSelected(bool add)
signal removeFromContentLib()
function popupMenu(item = null)
{
root.targetItem = item
let isMaterial = root.targetItem.itemType === "material"
applyToSelectedReplace.visible = isMaterial
applyToSelectedAdd.visible = isMaterial
popup()
}
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
StudioControls.MenuItem {
id: applyToSelectedReplace
text: qsTr("Apply to selected (replace)")
height: visible ? implicitHeight : 0
enabled: root.targetAvailable && ContentLibraryBackend.rootView.hasModelSelection
onTriggered: root.applyToSelected(false)
}
StudioControls.MenuItem {
id: applyToSelectedAdd
text: qsTr("Apply to selected (add)")
height: visible ? implicitHeight : 0
enabled: root.targetAvailable && ContentLibraryBackend.rootView.hasModelSelection
onTriggered: root.applyToSelected(true)
}
StudioControls.MenuSeparator {}
StudioControls.MenuItem {
enabled: root.targetAvailable
text: qsTr("Add an instance to project")
onTriggered: root.addToProject()
}
StudioControls.MenuItem {
enabled: root.targetAvailable && root.targetItem.bundleItemImported
text: qsTr("Remove from project")
onTriggered: root.unimport()
}
StudioControls.MenuItem {
text: qsTr("Remove from Content Library")
visible: root.enableRemove && root.targetAvailable
height: visible ? implicitHeight : 0
onTriggered: root.removeFromContentLib()
}
}

View File

@@ -16,8 +16,6 @@ Item {
// "failed" // "failed"
property string downloadState: modelData.isDownloaded() ? "downloaded" : "" property string downloadState: modelData.isDownloaded() ? "downloaded" : ""
property bool importerRunning: false
signal showContextMenu() signal showContextMenu()
signal addToProject() signal addToProject()
@@ -32,7 +30,7 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => { onPressed: (mouse) => {
if (mouse.button === Qt.LeftButton && !root.importerRunning) { if (mouse.button === Qt.LeftButton && !ContentLibraryBackend.rootView.importerRunning) {
if (root.downloadState === "downloaded") if (root.downloadState === "downloaded")
ContentLibraryBackend.rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y)) ContentLibraryBackend.rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
} else if (mouse.button === Qt.RightButton && root.downloadState === "downloaded") { } else if (mouse.button === Qt.RightButton && root.downloadState === "downloaded") {
@@ -74,7 +72,7 @@ Item {
color: "#00ff00" color: "#00ff00"
border.color: "#555555" border.color: "#555555"
border.width: 1 border.width: 1
visible: modelData.bundleMaterialImported visible: modelData.bundleItemImported
ToolTip { ToolTip {
visible: indicatorMouseArea.containsMouse visible: indicatorMouseArea.containsMouse
@@ -99,7 +97,7 @@ Item {
pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4) pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4)
anchors.right: img.right anchors.right: img.right
anchors.bottom: img.bottom anchors.bottom: img.bottom
enabled: !root.importerRunning enabled: !ContentLibraryBackend.rootView.importerRunning
visible: root.downloadState === "downloaded" visible: root.downloadState === "downloaded"
&& (containsMouse || mouseArea.containsMouse) && (containsMouse || mouseArea.containsMouse)
@@ -186,7 +184,7 @@ Item {
baseUrl: modelData.bundleMaterialBaseWebUrl baseUrl: modelData.bundleMaterialBaseWebUrl
files: modelData.bundleMaterialFiles files: modelData.bundleMaterialFiles
targetDirPath: modelData.bundleMaterialParentPath targetDirPath: modelData.bundleMaterialDirPath
onDownloadStarting: { onDownloadStarting: {
root.downloadState = "downloading" root.downloadState = "downloading"

View File

@@ -1,59 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick 2.15
import HelperWidgets 2.0
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
StudioControls.Menu {
id: root
property var targetMaterial: null
property bool hasModelSelection: false
property bool importerRunning: false
readonly property bool targetAvailable: targetMaterial && !importerRunning
signal unimport();
signal addToProject()
signal applyToSelected(bool add)
function popupMenu(targetMaterial = null)
{
this.targetMaterial = targetMaterial
popup()
}
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
StudioControls.MenuItem {
text: qsTr("Apply to selected (replace)")
enabled: root.targetAvailable && root.hasModelSelection
onTriggered: root.applyToSelected(false)
}
StudioControls.MenuItem {
text: qsTr("Apply to selected (add)")
enabled: root.targetAvailable && root.hasModelSelection
onTriggered: root.applyToSelected(true)
}
StudioControls.MenuSeparator {}
StudioControls.MenuItem {
enabled: root.targetAvailable
text: qsTr("Add an instance to project")
onTriggered: {
root.addToProject()
}
}
StudioControls.MenuItem {
enabled: root.targetAvailable && root.targetMaterial.bundleMaterialImported
text: qsTr("Remove from project")
onTriggered: root.unimport()
}
}

View File

@@ -46,16 +46,13 @@ HelperWidgets.ScrollView {
} }
Column { Column {
ContentLibraryMaterialContextMenu { ContentLibraryItemContextMenu {
id: ctxMenu id: ctxMenu
hasModelSelection: root.materialsModel.hasModelSelection onApplyToSelected: (add) => root.materialsModel.applyToSelected(ctxMenu.targetItem, add)
importerRunning: root.materialsModel.importerRunning
onApplyToSelected: (add) => root.materialsModel.applyToSelected(ctxMenu.targetMaterial, add) onUnimport: root.unimport(ctxMenu.targetItem)
onAddToProject: root.materialsModel.addToProject(ctxMenu.targetItem)
onUnimport: root.unimport(ctxMenu.targetMaterial)
onAddToProject: root.materialsModel.addToProject(ctxMenu.targetMaterial)
} }
Repeater { Repeater {
@@ -103,8 +100,6 @@ HelperWidgets.ScrollView {
width: root.cellWidth width: root.cellWidth
height: root.cellHeight height: root.cellHeight
importerRunning: root.materialsModel.importerRunning
onShowContextMenu: ctxMenu.popupMenu(modelData) onShowContextMenu: ctxMenu.popupMenu(modelData)
onAddToProject: root.materialsModel.addToProject(modelData) onAddToProject: root.materialsModel.addToProject(modelData)
} }

View File

@@ -12,6 +12,7 @@ StudioControls.Menu {
property var targetTexture: null property var targetTexture: null
property bool hasSceneEnv: false property bool hasSceneEnv: false
property bool enableRemove: false // true: adds an option to remove targetTexture
property bool canUse3D: targetTexture && ContentLibraryBackend.rootView.hasQuick3DImport && ContentLibraryBackend.rootView.hasMaterialLibrary property bool canUse3D: targetTexture && ContentLibraryBackend.rootView.hasQuick3DImport && ContentLibraryBackend.rootView.hasMaterialLibrary
@@ -32,13 +33,20 @@ StudioControls.Menu {
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Add texture") text: qsTr("Add texture")
enabled: canUse3D enabled: root.canUse3D
onTriggered: ContentLibraryBackend.rootView.addTexture(root.targetTexture) onTriggered: ContentLibraryBackend.rootView.addTexture(root.targetTexture)
} }
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Add light probe") text: qsTr("Add light probe")
enabled: root.hasSceneEnv && canUse3D enabled: root.hasSceneEnv && root.canUse3D
onTriggered: ContentLibraryBackend.rootView.addLightProbe(root.targetTexture) onTriggered: ContentLibraryBackend.rootView.addLightProbe(root.targetTexture)
} }
StudioControls.MenuItem {
text: qsTr("Remove from Content Library")
visible: root.targetTexture && root.enableRemove
height: visible ? implicitHeight : 0
onTriggered: ContentLibraryBackend.userModel.removeTexture(root.targetTexture)
}
} }

View File

@@ -12,7 +12,7 @@ HelperWidgets.ScrollView {
id: root id: root
clip: true clip: true
interactive: !ctxMenuMaterial.opened && !ctxMenuTexture.opened interactive: !ctxMenuItem.opened && !ctxMenuTexture.opened
&& !ContentLibraryBackend.rootView.isDragging && !HelperWidgets.Controller.contextMenuOpened && !ContentLibraryBackend.rootView.isDragging && !HelperWidgets.Controller.contextMenuOpened
property real cellWidth: 100 property real cellWidth: 100
@@ -31,9 +31,10 @@ HelperWidgets.ScrollView {
required property var searchBox required property var searchBox
signal unimport(var bundleItem); signal unimport(var bundleItem);
signal removeFromContentLib(var bundleItem);
function closeContextMenu() { function closeContextMenu() {
ctxMenuMaterial.close() ctxMenuItem.close()
ctxMenuTexture.close() ctxMenuTexture.close()
} }
@@ -46,21 +47,22 @@ HelperWidgets.ScrollView {
} }
Column { Column {
ContentLibraryMaterialContextMenu { ContentLibraryItemContextMenu {
id: ctxMenuMaterial id: ctxMenuItem
hasModelSelection: ContentLibraryBackend.userModel.hasModelSelection enableRemove: true
importerRunning: ContentLibraryBackend.userModel.importerRunning
onApplyToSelected: (add) => ContentLibraryBackend.userModel.applyToSelected(ctxMenuMaterial.targetMaterial, add) onApplyToSelected: (add) => ContentLibraryBackend.userModel.applyToSelected(ctxMenuItem.targetItem, add)
onUnimport: root.unimport(ctxMenuMaterial.targetMaterial) onUnimport: root.unimport(ctxMenuItem.targetItem)
onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenuMaterial.targetMaterial) onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenuItem.targetItem)
onRemoveFromContentLib: root.removeFromContentLib(ctxMenuItem.targetItem)
} }
ContentLibraryTextureContextMenu { ContentLibraryTextureContextMenu {
id: ctxMenuTexture id: ctxMenuTexture
enableRemove: true
hasSceneEnv: ContentLibraryBackend.texturesModel.hasSceneEnv hasSceneEnv: ContentLibraryBackend.texturesModel.hasSceneEnv
} }
@@ -79,7 +81,7 @@ HelperWidgets.ScrollView {
bottomPadding: StudioTheme.Values.sectionPadding bottomPadding: StudioTheme.Values.sectionPadding
caption: categoryName caption: categoryName
visible: categoryVisible visible: categoryVisible && infoText.text === ""
category: "ContentLib_User" category: "ContentLib_User"
function expandSection() { function expandSection() {
@@ -90,8 +92,6 @@ HelperWidgets.ScrollView {
onCountChanged: root.assignMaxCount() onCountChanged: root.assignMaxCount()
property int numVisibleItem: 1 // initially, the tab is invisible so this will be 0
Grid { Grid {
width: section.width - section.leftPadding - section.rightPadding width: section.width - section.leftPadding - section.rightPadding
spacing: StudioTheme.Values.sectionGridSpacing spacing: StudioTheme.Values.sectionGridSpacing
@@ -110,14 +110,8 @@ HelperWidgets.ScrollView {
width: root.cellWidth width: root.cellWidth
height: root.cellHeight height: root.cellHeight
importerRunning: ContentLibraryBackend.userModel.importerRunning onShowContextMenu: ctxMenuItem.popupMenu(modelData)
onShowContextMenu: ctxMenuMaterial.popupMenu(modelData)
onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData) onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData)
onVisibleChanged: {
section.numVisibleItem += visible ? 1 : -1
}
} }
} }
DelegateChoice { DelegateChoice {
@@ -129,6 +123,15 @@ HelperWidgets.ScrollView {
onShowContextMenu: ctxMenuTexture.popupMenu(modelData) onShowContextMenu: ctxMenuTexture.popupMenu(modelData)
} }
} }
DelegateChoice {
roleValue: "item"
delegate: ContentLibraryItem {
width: root.cellWidth
height: root.cellHeight
onShowContextMenu: ctxMenuItem.popupMenu(modelData)
}
}
} }
onCountChanged: root.assignMaxCount() onCountChanged: root.assignMaxCount()
@@ -140,7 +143,7 @@ HelperWidgets.ScrollView {
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
font.pixelSize: StudioTheme.Values.baseFontSize font.pixelSize: StudioTheme.Values.baseFontSize
leftPadding: 10 leftPadding: 10
visible: !searchBox.isEmpty() && section.numVisibleItem === 0 visible: infoText.text === "" && !searchBox.isEmpty() && categoryNoMatch
} }
} }
} }
@@ -148,9 +151,7 @@ HelperWidgets.ScrollView {
Text { Text {
id: infoText id: infoText
text: { text: {
if (!ContentLibraryBackend.effectsModel.bundleExists) if (!ContentLibraryBackend.rootView.isQt6Project)
qsTr("User bundle couldn't be found.")
else if (!ContentLibraryBackend.rootView.isQt6Project)
qsTr("<b>Content Library</b> is not supported in Qt5 projects.") qsTr("<b>Content Library</b> is not supported in Qt5 projects.")
else if (!ContentLibraryBackend.rootView.hasQuick3DImport) else if (!ContentLibraryBackend.rootView.hasQuick3DImport)
qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> view.") qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> view.")
@@ -163,7 +164,7 @@ HelperWidgets.ScrollView {
font.pixelSize: StudioTheme.Values.baseFontSize font.pixelSize: StudioTheme.Values.baseFontSize
topPadding: 10 topPadding: 10
leftPadding: 10 leftPadding: 10
visible: ContentLibraryBackend.effectsModel.isEmpty visible: infoText.text !== ""
} }
} }
} }

View File

@@ -0,0 +1,65 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
import ContentLibraryBackend
StudioControls.Dialog {
id: root
property var targetBundleItem
property var targetBundleModel
property string targetBundleLabel // "effect" or "material"
title: qsTr("Remove bundle %1").arg(root.targetBundleLabel)
anchors.centerIn: parent
closePolicy: Popup.CloseOnEscape
implicitWidth: 300
modal: true
onOpened: warningText.forceActiveFocus()
contentItem: Column {
spacing: 20
width: parent.width
Text {
id: warningText
text: qsTr("Are you sure you? The action cannot be undone")
color: StudioTheme.Values.themeTextColor
wrapMode: Text.WordWrap
anchors.right: parent.right
anchors.left: parent.left
leftPadding: 10
rightPadding: 10
Keys.onEnterPressed: btnRemove.onClicked()
Keys.onReturnPressed: btnRemove.onClicked()
}
Row {
anchors.right: parent.right
Button {
id: btnRemove
text: qsTr("Remove")
onClicked: {
ContentLibraryBackend.userModel.removeFromContentLib(root.targetBundleItem)
root.accept()
}
}
Button {
text: qsTr("Cancel")
onClicked: root.reject()
}
}
}
}

View File

@@ -13,8 +13,8 @@ StudioControls.Dialog {
id: root id: root
property var targetBundleItem property var targetBundleItem
property var targetBundleLabel // "effect" or "material"
property var targetBundleModel property var targetBundleModel
property string targetBundleLabel // "effect" or "material"
title: qsTr("Bundle %1 might be in use").arg(root.targetBundleLabel) title: qsTr("Bundle %1 might be in use").arg(root.targetBundleLabel)
anchors.centerIn: parent anchors.centerIn: parent

View File

@@ -89,8 +89,8 @@ Rectangle {
2. Adjust the effect nodes properties 2. Adjust the effect nodes properties
3. Change the order of the effects, if you like 3. Change the order of the effects, if you like
4. See the preview 4. See the preview
5. Save in the library, if you wish to reuse the effect later") // TODO: revise with doc engineer 5. Save in the assets library, if you wish to reuse the effect later")
onClicked: Qt.openUrlExternally("https://doc.qt.io/qtdesignstudio/qt-using-effect-maker-effects.html") onClicked: Qt.openUrlExternally("https://doc.qt.io/qtdesignstudio/qtquick-effect-composer-view.html")
} }
} }

Some files were not shown because too many files have changed in this diff Show More