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

Conflicts: src/plugins/qmldesigner/CMakeLists.txt

Change-Id: I250c8e5284ddb0f335c440999b8920762419c89b
This commit is contained in:
Tim Jenssen
2024-05-28 18:10:03 +02: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_COMPAT "4.5.0") # The IDE Compatibility version.
set(IDE_VERSION_DISPLAY "4.5.0") # The IDE display version.
set(IDE_VERSION "4.6.0") # The IDE version.
set(IDE_VERSION_COMPAT "4.6.0") # The IDE Compatibility version.
set(IDE_VERSION_DISPLAY "4.6.0") # The IDE display version.
set(IDE_COPYRIGHT_YEAR "2024") # The IDE current copyright year.
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.

View File

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

View File

@@ -82,7 +82,7 @@
\uicontrol {Reset Code Model} to reset the code model.
\if defined(qtdesignstudio)
For more information about how to show the \uicontrol {Tools} menu, see
\l{Customizing the Menu}.
\l{Customizing the Menu Bar}.
\endif
\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="heading">
<a name="reference"></a>
<h2 id="reference">Qt Design Studio Manual</h2>
<h2>Getting Started</h2>
</div>
<div class="indexboxcont indexboxbar">
<ul>
<li><a href="qtdesignstudio-toc.html">All Topics</a></li>
<li><a href="studio-getting-started.html">Getting Started</a></li>
<li><a href="quick-uis.html">Wireframing</a></li>
<li><a href="qtquick-prototyping.html">Prototyping</a></li>
<li><a href="qtquick-motion-design.html">Motion Design</a></li>
<li><a href="studio-implementing-applications.html">Implementing Applications</a></li>
<li><a href="studio-advanced.html">Advanced Designer Topics</a></li>
<li><a href="studio-developer-topics.html">Developer Topics</a></li>
<li><a href="studio-help.html">Help</a></li>
<li><a href="studio-getting-started.html">Overview</a></li>
<li><a href="studio-installation.html">Installing Qt Design Studio</a></li>
<li><a href="gstutorials.html">Tutorials</a></li>
<li><a href="creator-quick-tour.html">User Interface</a></li>
<li><a href="studio-projects.html">Creating Projects</a></li>
<li><a href="studio-use-cases.html">Use Cases</a></li>
<li><a href="studio-terms.html">Concepts and Terms</a></li>
<li><a href="best-practices.html">Best Practices</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>
</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
\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
\image qtquick-designer-image-properties.png "Image properties"

View File

@@ -31,6 +31,7 @@
\li \l {UI Controls}
\li \l {Lists and Other Data Models}
\li \l {2D Effects}
\li \l {Design Effects}
\li \l {Logic Helpers}
\li \l Animations
\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
/*!
@@ -19,10 +19,6 @@
other files that are needed to implement the application logic and to
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
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.
@@ -31,58 +27,53 @@
\e CMakeLists.txt file as the project file. This enables you to share
your project as a fully working C++ application with developers.
If you use Git, you can clone an example project
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/playground/AuroraCluster0}
{here}.
To export a \QDS project for Qt Creator, you need:
\list
\li Qt Creator 13.0 or above.
\li \QDS 4.5 or above.
\endlist
\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
\li \l {Creating a Project} {Create} or open your \QDS project with \QDS 4.5 or above.
\list 1
\li Open the project you want to export in \QDS.
\li Select \uicontrol {File} > \uicontrol {Export Project} > \uicontrol {Generate CMake Build Files}.
\image studio-project-export.webp "Export the \QDS project for Qt Creator"
\note If you are creating a new project in \QDS, select the
\uicontrol {Target Qt Version} that is not higher than the Qt version
used in your Qt Creator.
\li Select \uicontrol {Details} to access the \uicontrol {Advanced Options}.
\image studio-project-export-advanced.webp "Access Advanced Options in the project exporter"
\li Go to \uicontrol {File} > \uicontrol {Export Project}
> \uicontrol {Enable Automatic CMake Generation}. This creates a
\e {CMakeLists.txt} file in your project folder.
\note The project exporter has default settings selected. This works better if the project
is combined with an existing Qt project.
\note Enabling this option tracks the changes made to the project in Qt Creator
and automatically updates in \QDS. The connection works unless you
deactivate the option.
\li Select all the options here. This allows to export the
complete project. So, it can be compiled as a stand-alone application.
\image studio-project-export-advanced-options.webp "Select all the options in the project exporter"
\image studio-project-export.webp "Exporting Qt Design Studio project"
\endlist
\note If you copy this export on top of the existing Qt Creator 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
\section1 Opening the \QDS Project in Qt Creator
\section1 Using the Exported Project in Qt Creator
Open the \e {CMakeLists.txt} file in Qt Creator. To open:
After exporting the project from the \QDS, you have to open it from Qt Creator.
\list 1
\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.
If you have used any version before \QDS 4.0 to create the project, manually include this code
in the \e {CMakeLists.txt} file so the exported project works in Qt Creator.
\image studio-project-cmake-generation.webp "Project folder after CMake generation"
\code
set(BUILD_QDS_COMPONENTS ON CACHE BOOL "Build design studio components")
\li Select the Qt version and then \uicontrol {Configure Project}.
set(CMAKE_INCLUDE_CURRENT_DIR ON)
if (${BUILD_QDS_COMPONENTS})
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents)
endif ()
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
\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.
\note If your \QDS project was created with a more updated Qt than the one
available in Qt Creator, the import doesn't work. Use
\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
accessible in the \uicontrol Projects view.
\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}.
\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.
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
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
// 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
Figma, you should follow the guidelines for working with Figma and
organizing your assets.
\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
/*!
@@ -25,4 +25,6 @@
\endlist
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
/*!
@@ -247,4 +247,6 @@
\uicontrol Home tab) to default values. This means that you
will lose all your changes to the settings.
\endtable
\include qtdesignstudio-qt-academy.qdocinc qt-academy-using-qt-bridge-for-figma
*/

View File

@@ -8,25 +8,25 @@
\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
\e {flow items} that represent the screens in the UI and \e {transition
lines} that connect them, thus illustrating the possible user pathways
through the UI. You use \e {action areas} as starting points for transition
lines. You can attach effects to transition lines, such as fade or push,
through the UI. \e {Action areas} are clickable starting points for transition
lines. Attach effects to transition lines, such as fade or push,
to determine what users see when one flow item changes into another.
You can use \e {flow decisions} to set up alternative pathways between
flow items in the UI. For example, if user input determines which flow item
should open next, you can test the different scenarios in the prototype
by having a dialog pop up where you can select which flow item to show next.
Use \e {flow decisions} to set up alternative pathways between flow items in the UI. For
example, if user input determines which flow item should open next, test the different
scenarios in the prototype with the decision dialog where you can select which flow item to
show next.
Especially on mobile and embedded platforms, the application might need to
react to external events from the platform, such as notifications or other
applications requiring the users' attention. You can use \e {flow wildcards}
to determine the priority of flow items by adding them to positive and
negative lists.
applications requiring the users' attention. Use \e {flow wildcards}
to determine the priority of flow items by adding them to allow and
block lists.
To design application flows:
@@ -40,14 +40,17 @@
\l{Adding Flow Items}.
\li Use context menu commands to add 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,
as described in \l{Applying Effects to Transitions}.
\li When you are ready for production, use the event list simulator
to replace transition lines with connections to real signals
from UI controls, as described in \l{Simulating Events}.
\li To set up alternative pathways between flow items, use
\uicontrol {Flow Decision} components from
\uicontrol Components > \uicontrol {Flow View}, as described in
\li Use the event list simulator to replace transition lines with connections to real
signals from UI controls, as described in \l{Simulating Events}.
\li Use \uicontrol {Flow Decision} components from \uicontrol Components > \uicontrol {Flow
View} to set up alternative pathways between flow items, as described in
\l{Simulating Conditions}.
\li Use \l{Working with States}{states} in flows to modify the appearance
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
to the other flow item. For example, to a button that opens another
flow item when clicked.
\li Double-click the action area and drag the transition line to the
flow item you want to connect to.
\li Double-click the action area and drag the transition line to the flow item you want 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
and transition line.
\endlist
@@ -376,13 +380,13 @@
\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 Flow Items}{flow items}. A fade effect makes the first
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
first flow item, while the push effect appears to make a flow item
push out the previous one. You can also design and use custom effects.
first flow item. The push effect makes a flow item appear to push out the previous one.
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
from: left, right, top, bottom. You can set the duration of the effect and
@@ -392,34 +396,42 @@
\list 1
\li Select a transition line in the \l {2D} view.
\li In the context menu, select \uicontrol {Flow} >
\uicontrol {Assign Flow Effects}, and then select the effect
to apply.
\li Right-click the transition line to open the context menu, select \uicontrol {Flow} >
\uicontrol {Flow Effects}, and then select the effect to apply.
\li In \l Properties, modify the properties of the effect.
\endlist
To edit effect properties later, select a transition, and then select
\uicontrol {Flow} > \uicontrol {Select Effect} in the context menu.
To edit effect properties later, select a transition, open the context menu, and then select
\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
You can specify basic properties for a \uicontrol {Flow Effect}
component in the \l Type and \l ID fields in the \uicontrol Component
section in the \uicontrol Properties view.
Specify basic properties for a \uicontrol {Flow Effect} component in the \l Type and
\l ID fields in the \uicontrol Component section in the \uicontrol Properties view.
\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
\li In the \uicontrol Duration field, specify the duration of the
effect.
\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.
\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"
@@ -431,7 +443,7 @@
\li In the \uicontrol {Incoming opacity} and
\uicontrol {Outgoing opacity} fields, specify the opacity of
the effect as a number between 0 and 1.
\li Select the \uicontrol Reveal check box to reveal the
\li Select the \uicontrol Reveal checkbox to reveal the
\uicontrol {Flow Item} where the transition starts.
\endlist
*/
@@ -453,7 +465,7 @@
keyboard shortcuts to simulate these events when you preview the UI.
When you use the wizard to create a \uicontrol {Flow View} component, select
the \uicontrol {Use event simulator} check box to add an event simulator to
the \uicontrol {Use event simulator} checkbox to add an event simulator to
the flow view.
You can create an event list where you assign keyboard shortcuts to events,
@@ -470,9 +482,8 @@
\li In the \uicontrol {Event List} dialog, select \inlineimage icons/plus.png
to add a keyboard shortcut for triggering an event to the list.
\image studio-flow-event-list.png "Event List dialog"
\li In the \uicontrol {Event ID} field, enter an identifier for the
event. You can search for existing events by entering search
criteria in the \uicontrol Filter field.
\li In the \uicontrol {Event ID} field, enter an identifier for the event. To search
for existing events, enter search criteria in the \uicontrol Filter field.
\li In the \uicontrol Description field, describe the keyboard shortcut.
\li In the \uicontrol Shortcut field, press the keyboard key that will
trigger the event, and then select \uicontrol R to record the
@@ -486,24 +497,22 @@
To assign events to actions:
\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 the context menu, select \uicontrol {Event List} >
\uicontrol {Assign Events to Actions}.
\image studio-flow-events-assign.png "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.
\image studio-flow-events-assign.webp "Assign Events to Actions dialog"
\li To connect an event, select \uicontrol Connect next to an event in
the list. To release a connected event, select \uicontrol Release.
\li Press \key {Alt+P} to preview the UI.
\li Select action areas in the preview, double-click events in the
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
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
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:
\list 1
\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.
\li Select the flow item where you want the application to start in
the \uicontrol Navigator or \uicontrol {2D} view, and then select
\uicontrol {Flow} > \uicontrol {Set Flow Start} in the context menu.
the \uicontrol Navigator or \uicontrol {2D} view. Then right-click the component
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
the component that will trigger the condition and connect it to the
flow decision.
@@ -546,10 +555,10 @@
title for the selection dialog that opens when the condition is
triggered.
\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
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 Select action areas in the preview, double-click events in the
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
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
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
\uicontrol Properties view. Specify properties for flow decisions in the
\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
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
:
@@ -582,14 +591,14 @@
component in the \l {2D} view.
\li In the \uicontrol {Label position} field, select the corner of
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
decision icon.
\li In the \uicontrol Radius field, specify the radius of the flow
decision icon corners.
\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
You can use \l{Working with States}{states} in flows to modify the appearance
of \l{glossary-component}{components} in flow items in response to user
interaction, for example. For this purpose, you use the
\uicontrol {Flow Item} components available in
\uicontrol Components > \uicontrol {Flow View}.
Use \l{Working with States}{states} in flows to modify how the \l{glossary-component}
{component} properties change in flow items. For this purpose, use the \uicontrol {Flow Item}
component available in \uicontrol Components > \uicontrol {Flow View}.
To apply states in flows:
\list 1
\li Select \uicontrol File > \uicontrol {New File} >
\uicontrol {Qt Quick Files} >
\uicontrol {Flow Item} to create a flow item.
\li In \l States, add states to the flow item.
\li 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 in the \l Navigator or \l {2D} view.
\li Drag an empty \uicontrol {Flow Item} component from
\uicontrol Components > \uicontrol {Flow View}
to the flow for each state that you added.
\li In \l Properties, in the \uicontrol {State change target}
field, select the flow item that you created using the wizard.
\image studio-flow-item-properties.png "Flow Item properties"
\li In the \uicontrol {Target state} field, select the state to
apply to the flow item.
\li In the \l States view, add states to the flow item.
\li In the \l Projects view, open the .ui.qml file that contains the \l{Adding Flow Views}
{flow view}, and drag the flow item from \uicontrol Components >
\uicontrol {My Components} to the flow view in the \l Navigator or \l 2D view.
\li From \uicontrol Components > \uicontrol {Flow View}, drag an empty
\uicontrol {Flow Item} component (1) to the flow view for each state that you added.
\image studio-flow-item-component.webp "Flow Item in the Components view."
\li In the \uicontrol Navigator or \uicontrol 2D view, select an empty
\uicontrol {Flow Item} to open the \l Properties view.
\li In the \uicontrol {State change target} field, select the flow item that you created
using the wizard.
\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
You can now add \l{Adding Action Areas and Transitions}{action areas} and
\l{Simulating Conditions}{flow decisions} to apply the different states.
To apply the different states to your application flow, add
\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
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
screens in your \l{Adding Flow Views}{flow view} using real or simulated
\l{Connecting and Releasing Signals}{signals} and \l{Simulating Conditions}
{conditions}. You can add \l{Adding Flow Items}{flow items} to a positive
list to prioritize them or to a negative list to stop some screens from
Use the \uicontrol {Flow Wildcard} component to model this type of
screens in your \l{Adding Flow Views}{flow view} using real or simulated events.
Add \l{Adding Flow Items}{flow items} to an \uicontrol {Allow
list} to prioritize them or to a \uicontrol {Block list} to stop some screens from
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
warning more important.
@@ -652,42 +662,46 @@
\list 1
\li Drag a \uicontrol {Flow Wildcard} component from
\uicontrol Components > \uicontrol {Flow View} to an
\l{Adding Action Areas and Transitions}{action area} in
the \l Navigator or \l {2D} view.
\li In \l Properties, select flow items to add them to the
positive and negative list of the action area.
\uicontrol Components > \uicontrol {Flow View} to the \l {2D} view.
\li To connect the wildcard to a flow item with a \l{Adding Action Areas and Transitions}
{transition line}, double-click the wildcard and drag the transition line to the flow
item.
\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
\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
\uicontrol Properties view. Specify properties for flow wildcards in the
\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
connect to, such as mouse, touch or keyboard events.
Select the \uicontrol {Global wildcard} check box to enable triggering
Select the \uicontrol {Global wildcard} checkbox to enable triggering
the wildcard from several flows.
To give flow items high priority, select them in the
\uicontrol {Allow list} field. To block flow items,
select them in the \uicontrol {Block list} field.
You can specify the following properties to change the appearance of the
wildcard icon \inlineimage icons/flow-wildcard-icon.png
:
Specify the following properties to change the appearance of the
wildcard icon \inlineimage icons/flow-wildcard-icon.png:
\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 Radius field, specify the radius of the wildcard
icon corners.
\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
/*!
@@ -56,4 +56,6 @@
If you would rather be shown things than read about them,
you can watch our extensive video tutorials.
\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
\previouspage studio-use-cases.html
\nextpage {Examples}
\nextpage best-practices.html
\title Concepts and Terms
@@ -170,7 +170,7 @@
example, if you create a 3D project, preset 3D components are added to it.
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:

View File

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

View File

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

View File

@@ -13,54 +13,28 @@
\brief Edit a 3D scene.
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
\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.
view.
When you import 3D scenes from files that you exported from 3D graphics
tools, you also import a \l{Cameras}{scene camera},
\l{Lights}{light}, \l{3D Models}{model}, and
\l {Materials and Shaders}{materials}. If your scene did not contain
them, you can add the corresponding \l {3D Components}{Qt Quick 3D}
\l{Lights}{light}, \l{3D Models}{model}, and \l {Materials and Shaders}{materials}.
If your scene does not contain them, add the corresponding \l {3D Components}{Qt Quick 3D}
components from \uicontrol Components > \inlineimage icons/plus.png
> \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D}.
You can use the toolbar buttons
to \e transform 3D components and manipulate the 3D scene. Transformation
refers to moving, rotating, or scaling of a component. The \e pivot of the
component is used as the origin for transformations. You can set a
\l{Managing 3D Transformations}{local pivot offset} for a component in
\uicontrol Properties to transform the component around a point other than
its local origin. A line is drawn in the \uicontrol{3D} view from the pivot
point to the center of the component to provide a visual connection between
them. Especially when working with complex scenes, it may be useful to use
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.
Use the \uicontrol 3D toolbar buttons to modify the \uicontrol 3D view,
manipulate the 3D scene, and to access functionalities to \e transform 3D
components. Transformation refers to moving, rotating, or scaling a
component. The \e pivot of the component is used as the origin for
transformations. Set a \l{Managing 3D Transformations}{local pivot offset}
for a component in \uicontrol Properties to transform the component around
a point other than its local origin. A line is drawn in the \uicontrol{3D}
view from the pivot point to the center of the component to provide a visual
connection between them.
Toggle between local and global orientation to determine whether the gizmos
affect only the local transformations of the component or whether they
transform with respect to the global space.
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"
\note To avoid transforming components by mistake while editing your scene,
use the \l {Showing and Hiding Components}{showing and hiding} or the
\l {Locking Components}{locking} features in \l Navigator.
To refresh the contents of the \uicontrol{3D} view, press \key P or
select the \inlineimage icons/reset.png
@@ -73,53 +47,76 @@
\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
\section2 Toggling Camera Mode
To switch to perspective camera mode, select
\inlineimage perspective_camera.png
(\uicontrol {Toggle Perspective/Orthographic Edit Camera}).
To switch to orthographic camera mode, select
\inlineimage orthographic_camera.png
. You can also Toggle the camera mode by using the keyboard shortcut \key T.
Change the projection of the view by switching between \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.
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
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:
\list
\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
view to slide the view around. Alternatively, press and hold \key {right mouse
button} and \key {left mouse button} and drag anywhere in the view to pan.
\li To orbit, press \key Alt and click and drag anywhere in the rendered
view to rotate the view.
wheel button to drag anywhere in the \uicontrol 3D view to
slide the view around. Alternatively, press and hold \key
{right mouse button} and \key {left mouse button} and drag
anywhere in the view to pan.
\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
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.
\endlist
To zoom and focus the 3D view camera on a selected component,
select \inlineimage fit_selected.png
(\uicontrol {Fit Selected}) or press \key F.
To zoom and focus the 3D view camera on a selected component, select
\inlineimage fit_selected.png (\uicontrol {Fit Selected}) or press \key F.
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
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
the camera zoom level.
selected, the camera is pointed at the world origin.
\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
specific angle in the \l {2D} view while editing scenes. Different types of
cameras are available in \uicontrol Components
> \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D}. For more information
about using cameras in the scene, the available camera types, and their
properties, see \l{Cameras}.
Use scene cameras (2) to view the \uicontrol View3D component from a
specific angle in the \l {2D} view while editing scenes. Drag a camera
component to your scene from \uicontrol Components > \uicontrol {Qt Quick 3D} >
\uicontrol {Qt Quick 3D}. For more information about using cameras in the
scene and the available camera types, see \l{Cameras}.
\section2 Using Split View
@@ -128,16 +125,16 @@
\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
independently. Navigate each split by panning, rotating, and zooming, as
described above.
\section2 Using Fly Mode
You can move around freely in the 3D scene with fly mode. To navigate the scene with
fly mode, keep the \key {right mouse button} pressed and use the listed keys to move
around the scene.
Use the fly mode to move around freely in the 3D scene. To navigate the scene with
fly mode, right-click and hold in the \uicontrol 3D view, and use the keyboard shortcuts
to move around the scene:
\table
\header
@@ -161,10 +158,20 @@
\row
\li \key Q or \key {Page 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
To adjust the movement speed, select \inlineimage icons/camera_speed.png in the
\uicontrol 3D view toolbar to open the configuration dialog.
To adjust the movement speed, right-click and hold in the \uicontrol 3D view, and rotate the
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:
\list
@@ -174,10 +181,8 @@
\section1 Using Global and Local Orientation
To switch between local and global orientation, select
\inlineimage global.png
(\uicontrol {Toggle Local/Global Orientation})
or press \key Y.
In \uicontrol 3D view, you view the scene in global or local orientation
mode.
In global orientation mode, transformation of a selected component is
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
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
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
or \inlineimage edit_light_off.png
(\uicontrol {Toggle Edit Light})
or press \key U.
or \inlineimage edit_light_off.png (\uicontrol {Toggle Edit Light}) or
press \key U.
For more information about the available scene light types and their
properties, see \l{Lights}.
For information about the available scene light types and their properties,
see \l{Lights}.
\section1 Baking Lights
Bake lights to light static elements in your scene. To bake lights,
select \inlineimage icons/bakelights.png to open the
\uicontrol {Lights Baking Setup} dialog. For more information, see
\l {Baking Lightmaps}.
Bake lights to light static elements in your scene. To bake lights, select
\inlineimage icons/bakelights.png to open the \uicontrol {Lights Baking Setup}
dialog. For more information, see \l {Baking Lightmaps}.
\section1 Selecting Components
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
you click them in the \uicontrol{3D} view:
first. Toggle the selection mode to determine how components are selected
when you click them in the \uicontrol{3D} view:
\list
\li In the \inlineimage select_item.png
(\uicontrol {Single Selection}) mode, a single component is selected.
\li In the \inlineimage select_group.png
(\uicontrol {Group Selection}) mode, the top level parent of the
component is selected. This enables you to move, rotate, or scale a
group of components.
\li Use the \inlineimage select_item.png (\uicontrol {Single Selection})
mode to select a single component.
\li Use the \inlineimage select_group.png (\uicontrol {Group Selection})
mode to select the top level parent of the component, so you can move
a group of components simultaneously.
\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.
@@ -241,16 +246,15 @@
y, or z axis or on the top, bottom, left, and right clip planes of the
the \uicontrol{3D} view.
To move components, select \inlineimage move_off.png
or press \key W:
To move components, select \inlineimage move_off.png or press \key W:
\list
\li To move components along the axes of the move gizmo, click 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.
\li To move components freely in the 3D view, click and drag the gray
handle at the center of the move gizmo.
\li To move components freely in the 3D view, drag the gray handle at the
center of the move gizmo.
\endlist
\section1 Rotating Components
@@ -261,29 +265,28 @@
or press \key E:
\list
\li To rotate a component around its rotation gizmo, click the axis ring
and drag in the direction you want to rotate the component in.
\li To freely rotate the component, click and drag the inner center
circle of the gizmo.
\li To rotate a component around its rotation gizmo, drag the axis ring
in the direction you want to rotate the component in.
\li To freely rotate the component, drag the inner center circle of the
gizmo.
\endlist
\section1 Scaling Components
\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,
depending on the handle.
To scale components, select \inlineimage scale_off.png
or press \key R:
To scale components, select \inlineimage scale_off.png or press \key R:
\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.
\li To adjust the scale across a plane, click the plane handle and drag
the component on the plane.
\li To uniformly scale a component across all axes, click and drag the
\li To adjust the scale across a plane, drag the plane handle of
the component.
\li To uniformly scale a component across all axes, drag the
gray handle at the center of the component.
\endlist
@@ -292,7 +295,7 @@
With snapping turned on, the objects in the \uicontrol 3D view snap to certain
intervals during transformation (move, rotate, scale).
You can toggle snapping in the following ways:
Toggle snapping in the following ways:
\list
\li Select \inlineimage icons/snapping-3d.png
@@ -300,7 +303,7 @@
\li Hold down the \key Ctrl key.
\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.
\section2 Configuring Snapping
@@ -327,78 +330,85 @@
To align a camera to the \uicontrol{3D} view:
\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
is aligned to the view.
\li In the \uicontrol{3D} view,
select \inlineimage icons/align-camera-on.png
.
\li In the \uicontrol{3D} view, select \inlineimage icons/align-camera-on.png.
\endlist
This moves and rotates the camera so that the camera shows the same view
as the current view in the \uicontrol{3D} view.
This moves and rotates the scene camera to show the same view as the current view
in the \uicontrol{3D} view.
To align the \uicontrol{3D} view to a camera:
\list 1
\li Select a camera in the \uicontrol{3D} view or \uicontrol {Navigator}.
\list 1
\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
selected camera.
\li In the \uicontrol{3D} view,
select \inlineimage icons/align-view-on.png
.
selected camera.
\li In the \uicontrol{3D} view, select \inlineimage icons/align-view-on.png.
\endlist
This copies the position as well as x and y rotation values from the
camera and applies them to the \uicontrol{3D} view.
This moves and rotates the 3D view to show the same view as the selected scene camera.
\section1 Toggling Visibility
To toggle the visibility of objects in the \uicontrol{3D} view, select
\inlineimage icons/visibilityon.png
in the toolbar. This opens a menu with the following options:
\inlineimage icons/visibilityon.png in the toolbar. This opens a menu with the
following options:
\table
\row
\li Show Grid
\li Toggles the visibility of the helper grid.
\row
\li Show Selection Boxes
\li Toggles the visibility of selection boxes for selected 3D objects.
\row
\li Show Icon Gizmos
\li Toggles the visibility of icon gizmos for object such as cameras,
lights, and particle systems.
\row
\li Always Show Camera Frustums
\li Toggles between always showing the camera frustum and showing it
only for cameras selected in the \uicontrol{3D} view.
\row
\li Always Show Particle Emitters and Attractors
\li Toggle between always showing the particle emitter and attractor
visualizations and only showing them when the emitter or attractor is
selected in the \uicontrol{3D} view.
\header
\li Action
\li Description
\li Keyboard Shortcut
\row
\li Show Grid
\li Toggles the visibility of the helper grid.
\li \key G
\row
\li Show Selection Boxes
\li Toggles the visibility of selection boxes for selected 3D objects.
\li \key B
\row
\li Show Icon Gizmos
\li Toggles the visibility of icon gizmos for object such as cameras,
lights, and particle systems.
\li \key I
\row
\li Always Show Camera Frustums
\li Toggles between always showing the camera frustum and showing it
only for cameras selected in the \uicontrol{3D} view.
\li \key C
\row
\li Always Show Particle Emitters and Attractors
\li Toggles between always showing the particle emitter and attractor
visualizations and only showing them when the emitter or attractor
is selected in the \uicontrol{3D} view.
\li \key M
\endtable
\section1 Changing Colors
To change the \uicontrol 3D view background or grid color, select
\inlineimage icons/3d-background-color.png
in the toolbar. This opens a menu with the following options:
\inlineimage icons/3d-background-color.png in the toolbar. This opens a menu
with the following options:
\table
\header
\li Action
\li Decription
\row
\li Select Background Color
\li Select a color for the background.
\row
\li Select Background Color
\li Select a color for the background.
\li Select Grid Color
\li Select a color for the grid.
\row
\li Select Grid Color
\li Select a color for the grid.
\li Use Scene Environment Color
\li Sets the 3D view to use the scene environment color as background
color.
\row
\li Use Scene Environment Color
\li Sets the 3D view to use the scene environment color as background
color.
\row
\li Reset Colors
\li Resets the background and grid colors to the default colors.
\li Reset Colors
\li Resets the background and grid colors to the default colors.
\endtable
\section1 Particle Editor
@@ -413,16 +423,14 @@
\li Select a particle system in the \uicontrol Navigator or
\uicontrol{3D} view.
\li In the \uicontrol{3D} view, select
\inlineimage icons/particle-animation-on.png
to activate particle animation. Now you can see the particle animation in
the \uicontrol{3D} view.
\inlineimage icons/particle-animation-on.png to activate particle animation.
Now you can see the particle animation in the \uicontrol{3D} view.
\endlist
You can pause the particle animation by selecting
\inlineimage icons/particle-pause.png
. When the animation is paused, you can use
\inlineimage icons/particles-seek.png
to manually seek forward or backward in the particle animation.
\inlineimage icons/particle-pause.png. When the animation is paused, use
\inlineimage icons/particles-seek.png to manually seek forward or backward in
the particle animation.
\section1 Using Viewport Shading

View File

@@ -142,7 +142,7 @@
\li From \uicontrol Components, drag a \uicontrol Sphere to \e _3DRepeater
in \uicontrol Navigator.
\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
next to \uicontrol Scale > \uicontrol X.
\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
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.
\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
\previouspage quick-2d-effects.html
\previouspage quick-design-effects.html
\nextpage quick-animations.html
\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
\previouspage quick-data-models.html
\nextpage quick-logic-helpers.html
\nextpage quick-property-effects.html
\title 2D Effects

View File

@@ -18,7 +18,7 @@
\image edit-list-model-model-editor.webp
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

View File

@@ -249,7 +249,7 @@ StudioControls.Menu {
StudioControls.MenuItem {
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
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
keepOpen: form.keepOpen
titleBar: Row {
spacing: 30 // TODO
anchors.fill: parent
@@ -43,6 +45,8 @@ StudioControls.PopupDialog {
ConnectionsDialogForm {
id: form
parentWindow: root.window
Connections {
target: root.backend
function onPopupShouldClose() {

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,8 +23,8 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => {
if (mouse.button === Qt.LeftButton && !ContentLibraryBackend.effectsModel.importerRunning)
ContentLibraryBackend.rootView.startDragEffect(modelData, mapToGlobal(mouse.x, mouse.y))
if (mouse.button === Qt.LeftButton && !ContentLibraryBackend.rootView.importerRunning)
ContentLibraryBackend.rootView.startDragItem(modelData, mapToGlobal(mouse.x, mouse.y))
else if (mouse.button === Qt.RightButton)
root.showContextMenu()
}
@@ -43,7 +43,7 @@ Item {
source: modelData.bundleItemIcon
cache: false
Rectangle { // circular indicator for imported bundle effect
Rectangle { // circular indicator for imported bundle item
width: 10
height: 10
radius: 5
@@ -57,7 +57,7 @@ Item {
ToolTip {
visible: indicatorMouseArea.containsMouse
text: qsTr("Effect is imported to project")
text: qsTr("Item is imported to the project")
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"
property string downloadState: modelData.isDownloaded() ? "downloaded" : ""
property bool importerRunning: false
signal showContextMenu()
signal addToProject()
@@ -32,7 +30,7 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => {
if (mouse.button === Qt.LeftButton && !root.importerRunning) {
if (mouse.button === Qt.LeftButton && !ContentLibraryBackend.rootView.importerRunning) {
if (root.downloadState === "downloaded")
ContentLibraryBackend.rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
} else if (mouse.button === Qt.RightButton && root.downloadState === "downloaded") {
@@ -74,7 +72,7 @@ Item {
color: "#00ff00"
border.color: "#555555"
border.width: 1
visible: modelData.bundleMaterialImported
visible: modelData.bundleItemImported
ToolTip {
visible: indicatorMouseArea.containsMouse
@@ -99,7 +97,7 @@ Item {
pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4)
anchors.right: img.right
anchors.bottom: img.bottom
enabled: !root.importerRunning
enabled: !ContentLibraryBackend.rootView.importerRunning
visible: root.downloadState === "downloaded"
&& (containsMouse || mouseArea.containsMouse)
@@ -186,7 +184,7 @@ Item {
baseUrl: modelData.bundleMaterialBaseWebUrl
files: modelData.bundleMaterialFiles
targetDirPath: modelData.bundleMaterialParentPath
targetDirPath: modelData.bundleMaterialDirPath
onDownloadStarting: {
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 {
ContentLibraryMaterialContextMenu {
ContentLibraryItemContextMenu {
id: ctxMenu
hasModelSelection: root.materialsModel.hasModelSelection
importerRunning: root.materialsModel.importerRunning
onApplyToSelected: (add) => root.materialsModel.applyToSelected(ctxMenu.targetItem, add)
onApplyToSelected: (add) => root.materialsModel.applyToSelected(ctxMenu.targetMaterial, add)
onUnimport: root.unimport(ctxMenu.targetMaterial)
onAddToProject: root.materialsModel.addToProject(ctxMenu.targetMaterial)
onUnimport: root.unimport(ctxMenu.targetItem)
onAddToProject: root.materialsModel.addToProject(ctxMenu.targetItem)
}
Repeater {
@@ -103,8 +100,6 @@ HelperWidgets.ScrollView {
width: root.cellWidth
height: root.cellHeight
importerRunning: root.materialsModel.importerRunning
onShowContextMenu: ctxMenu.popupMenu(modelData)
onAddToProject: root.materialsModel.addToProject(modelData)
}

View File

@@ -12,6 +12,7 @@ StudioControls.Menu {
property var targetTexture: null
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
@@ -32,13 +33,20 @@ StudioControls.Menu {
StudioControls.MenuItem {
text: qsTr("Add texture")
enabled: canUse3D
enabled: root.canUse3D
onTriggered: ContentLibraryBackend.rootView.addTexture(root.targetTexture)
}
StudioControls.MenuItem {
text: qsTr("Add light probe")
enabled: root.hasSceneEnv && canUse3D
enabled: root.hasSceneEnv && root.canUse3D
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
clip: true
interactive: !ctxMenuMaterial.opened && !ctxMenuTexture.opened
interactive: !ctxMenuItem.opened && !ctxMenuTexture.opened
&& !ContentLibraryBackend.rootView.isDragging && !HelperWidgets.Controller.contextMenuOpened
property real cellWidth: 100
@@ -31,9 +31,10 @@ HelperWidgets.ScrollView {
required property var searchBox
signal unimport(var bundleItem);
signal removeFromContentLib(var bundleItem);
function closeContextMenu() {
ctxMenuMaterial.close()
ctxMenuItem.close()
ctxMenuTexture.close()
}
@@ -46,21 +47,22 @@ HelperWidgets.ScrollView {
}
Column {
ContentLibraryMaterialContextMenu {
id: ctxMenuMaterial
ContentLibraryItemContextMenu {
id: ctxMenuItem
hasModelSelection: ContentLibraryBackend.userModel.hasModelSelection
importerRunning: ContentLibraryBackend.userModel.importerRunning
enableRemove: true
onApplyToSelected: (add) => ContentLibraryBackend.userModel.applyToSelected(ctxMenuMaterial.targetMaterial, add)
onApplyToSelected: (add) => ContentLibraryBackend.userModel.applyToSelected(ctxMenuItem.targetItem, add)
onUnimport: root.unimport(ctxMenuMaterial.targetMaterial)
onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenuMaterial.targetMaterial)
onUnimport: root.unimport(ctxMenuItem.targetItem)
onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenuItem.targetItem)
onRemoveFromContentLib: root.removeFromContentLib(ctxMenuItem.targetItem)
}
ContentLibraryTextureContextMenu {
id: ctxMenuTexture
enableRemove: true
hasSceneEnv: ContentLibraryBackend.texturesModel.hasSceneEnv
}
@@ -79,7 +81,7 @@ HelperWidgets.ScrollView {
bottomPadding: StudioTheme.Values.sectionPadding
caption: categoryName
visible: categoryVisible
visible: categoryVisible && infoText.text === ""
category: "ContentLib_User"
function expandSection() {
@@ -90,8 +92,6 @@ HelperWidgets.ScrollView {
onCountChanged: root.assignMaxCount()
property int numVisibleItem: 1 // initially, the tab is invisible so this will be 0
Grid {
width: section.width - section.leftPadding - section.rightPadding
spacing: StudioTheme.Values.sectionGridSpacing
@@ -110,14 +110,8 @@ HelperWidgets.ScrollView {
width: root.cellWidth
height: root.cellHeight
importerRunning: ContentLibraryBackend.userModel.importerRunning
onShowContextMenu: ctxMenuMaterial.popupMenu(modelData)
onShowContextMenu: ctxMenuItem.popupMenu(modelData)
onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData)
onVisibleChanged: {
section.numVisibleItem += visible ? 1 : -1
}
}
}
DelegateChoice {
@@ -129,6 +123,15 @@ HelperWidgets.ScrollView {
onShowContextMenu: ctxMenuTexture.popupMenu(modelData)
}
}
DelegateChoice {
roleValue: "item"
delegate: ContentLibraryItem {
width: root.cellWidth
height: root.cellHeight
onShowContextMenu: ctxMenuItem.popupMenu(modelData)
}
}
}
onCountChanged: root.assignMaxCount()
@@ -140,7 +143,7 @@ HelperWidgets.ScrollView {
color: StudioTheme.Values.themeTextColor
font.pixelSize: StudioTheme.Values.baseFontSize
leftPadding: 10
visible: !searchBox.isEmpty() && section.numVisibleItem === 0
visible: infoText.text === "" && !searchBox.isEmpty() && categoryNoMatch
}
}
}
@@ -148,9 +151,7 @@ HelperWidgets.ScrollView {
Text {
id: infoText
text: {
if (!ContentLibraryBackend.effectsModel.bundleExists)
qsTr("User bundle couldn't be found.")
else if (!ContentLibraryBackend.rootView.isQt6Project)
if (!ContentLibraryBackend.rootView.isQt6Project)
qsTr("<b>Content Library</b> is not supported in Qt5 projects.")
else if (!ContentLibraryBackend.rootView.hasQuick3DImport)
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
topPadding: 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
property var targetBundleItem
property var targetBundleLabel // "effect" or "material"
property var targetBundleModel
property string targetBundleLabel // "effect" or "material"
title: qsTr("Bundle %1 might be in use").arg(root.targetBundleLabel)
anchors.centerIn: parent

View File

@@ -89,8 +89,8 @@ Rectangle {
2. Adjust the effect nodes properties
3. Change the order of the effects, if you like
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