Merge remote-tracking branch 'origin/qds/dev'
Conflicts: src/plugins/qmldesigner/CMakeLists.txt Change-Id: I250c8e5284ddb0f335c440999b8920762419c89b
@@ -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.
|
||||
|
@@ -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"
|
||||
|
@@ -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)
|
||||
|
@@ -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>
|
||||
|
BIN
doc/qtdesignstudio/images/bleed-scale-1.webp
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
doc/qtdesignstudio/images/bleed-scale-8.webp
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
doc/qtdesignstudio/images/bleed-scale-no.webp
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
doc/qtdesignstudio/images/ext-scene-env-navigator.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
doc/qtdesignstudio/images/glow-additive-blend.webp
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
doc/qtdesignstudio/images/glow-bicubic.webp
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
doc/qtdesignstudio/images/glow-example-project.webp
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
doc/qtdesignstudio/images/glow-example.webp
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
doc/qtdesignstudio/images/glow-high-quality.webp
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
doc/qtdesignstudio/images/glow-no-enhancment.webp
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
doc/qtdesignstudio/images/glow-properties.webp
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
doc/qtdesignstudio/images/glow-replace-blend.webp
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
doc/qtdesignstudio/images/glow-screen-blend.webp
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
doc/qtdesignstudio/images/glow-softlight-blend.webp
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
doc/qtdesignstudio/images/glow_all_blur_levels.webp
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
doc/qtdesignstudio/images/glow_high_blur_levels.webp
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
doc/qtdesignstudio/images/glow_low_blur_levels.webp
Normal file
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 8.2 KiB |
BIN
doc/qtdesignstudio/images/studio-effects-background-blur.webp
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
doc/qtdesignstudio/images/studio-effects-drop-shadow.webp
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
doc/qtdesignstudio/images/studio-effects-inner-shadow.webp
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
doc/qtdesignstudio/images/studio-effects-layer-blur.webp
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
doc/qtdesignstudio/images/studio-effects-show-shadow-behind.webp
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
doc/qtdesignstudio/images/studio-effects.webp
Normal file
After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 12 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-decision-preview.webp
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-decision-properties.webp
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 36 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-decision.webp
Normal file
After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 15 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-events-assign.webp
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-events-event-list.webp
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-item-component.webp
Normal file
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 57 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-view.webp
Normal file
After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 11 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-wildcard-properties.webp
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
doc/qtdesignstudio/images/studio-flow-wildcard.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
doc/qtdesignstudio/images/studio-project-cmake-generation.webp
Normal file
After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.8 KiB |
200
doc/qtdesignstudio/src/best practices/best-practices-glow.qdoc
Normal 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
|
||||
|
||||
|
||||
*/
|
38
doc/qtdesignstudio/src/best-practices.qdoc
Normal 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
|
||||
*/
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
||||
*/
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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
|
||||
*/
|
||||
|
22
doc/qtdesignstudio/src/qtdesignstudio-qt-academy.qdocinc
Normal 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]
|
||||
|
||||
*/
|
@@ -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:
|
||||
|
||||
|
@@ -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}
|
||||
|
@@ -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}}
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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}.
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
||||
*/
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@@ -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()
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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()
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
@@ -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() {
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -91,7 +91,7 @@ HelperWidgets.ScrollView {
|
||||
id: repeater
|
||||
model: bundleCategoryItems
|
||||
|
||||
delegate: ContentLibraryEffect {
|
||||
delegate: ContentLibraryItem {
|
||||
width: root.cellWidth
|
||||
height: root.cellHeight
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
@@ -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"
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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 !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
@@ -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")
|
||||
}
|
||||
}
|
||||
|