forked from qt-creator/qt-creator
Merge "Merge remote-tracking branch 'origin/qds/dev'"
This commit is contained in:
@@ -61,7 +61,7 @@ function(setup_dependencies_component)
|
|||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(configure_qml_designer Qt6_VERSION)
|
function(configure_qml_designer Qt6_VERSION)
|
||||||
set(QMLDESIGNER_QT6_REQUIRED_VERSION 6.5.4)
|
set(QMLDESIGNER_QT6_REQUIRED_VERSION 6.7.3)
|
||||||
set(QMLDESIGNER_GCC_REQUIRED_VERSION 10.0)
|
set(QMLDESIGNER_GCC_REQUIRED_VERSION 10.0)
|
||||||
set(QMLDESIGNER_CLANG_REQUIRED_VERSION 13.0)
|
set(QMLDESIGNER_CLANG_REQUIRED_VERSION 13.0)
|
||||||
set(QMLDESIGNER_APPLECLANG_REQUIRED_VERSION 15.0)
|
set(QMLDESIGNER_APPLECLANG_REQUIRED_VERSION 15.0)
|
||||||
|
@@ -32,6 +32,7 @@ set(DESIGNSTUDIO_PLUGINS
|
|||||||
DiffEditor
|
DiffEditor
|
||||||
EffectComposer
|
EffectComposer
|
||||||
FakeVim
|
FakeVim
|
||||||
|
Git
|
||||||
Help
|
Help
|
||||||
Insight
|
Insight
|
||||||
LanguageClient
|
LanguageClient
|
||||||
|
@@ -105,6 +105,10 @@
|
|||||||
\externalpage https://doc.qt.io/qt/linguist-id-based-i18n.html
|
\externalpage https://doc.qt.io/qt/linguist-id-based-i18n.html
|
||||||
\title Text ID based translations
|
\title Text ID based translations
|
||||||
*/
|
*/
|
||||||
|
/*!
|
||||||
|
\externalpage https://www.qt.io/blog/qt-design-studio-4.6-released
|
||||||
|
\title Qt Design Studio 4.6 released
|
||||||
|
*/
|
||||||
/*!
|
/*!
|
||||||
\externalpage https://www.qt.io/blog/qt-design-studio-4.5.1-released
|
\externalpage https://www.qt.io/blog/qt-design-studio-4.5.1-released
|
||||||
\title Qt Design Studio 4.5.1 released
|
\title Qt Design Studio 4.5.1 released
|
||||||
|
@@ -12,103 +12,444 @@
|
|||||||
<div class="heading">
|
<div class="heading">
|
||||||
<h2>Getting Started</h2>
|
<h2>Getting Started</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="indexboxcont indexboxbar">
|
<ul>
|
||||||
<ul>
|
<li><a href="studio-getting-started.html">Overview</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="studio-installation.html">Installing Qt Design Studio</a></li>
|
<li><a href="studio-projects.html">Creating Projects</a></li>
|
||||||
<li><a href="gstutorials.html">Tutorials</a></li>
|
<li><a href="creator-quick-tour.html">User Interface</a></li>
|
||||||
<li><a href="creator-quick-tour.html">User Interface</a></li>
|
</ul>
|
||||||
<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>
|
||||||
<div class="sectionlist normallist">
|
<div class="sectionlist normallist">
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
<h2>Wireframing</h2>
|
<h2>Key Concepts</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>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="qtquick-prototyping.html">Overview</a></li>
|
<li><a href="quick-animation-overview.html">Animation Techniques</a></li>
|
||||||
|
<li><a href="studio-exporting-and-importing.html">Creating Assets with Other Tools</a></li>
|
||||||
<li><a href="qtquick-creating-ui-logic.html">Creating UI Logic</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="quick-components.html">Components</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="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>
|
<li><a href="studio-on-mcus.html">Qt Design Studio on MCUs</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<!--Working With-->
|
||||||
<div class="sectionlist normallist">
|
<div class="sectionlist normallist">
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
<h2>Help</h2>
|
<h2>Working with</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="studio-help.html">Overview</a></li>
|
<li><a>2D Assets</a>
|
||||||
<li><a href="creator-how-to-get-help.html">Getting Help</a></li>
|
<ul>
|
||||||
<li><a href="studio-platforms.html">Supported Platforms</a></li>
|
<li><a href="qtbridge-ai.html">Adobe Illustrator Assets</a></li>
|
||||||
|
<li><a href="psqtbridge.html">Adobe Photoshop Assets</a></li>
|
||||||
|
<li><a href="xdqtbridge.html">Adobe XD Assets</a></li>
|
||||||
|
<li><a href="figmaqtbridge.html">Figma Assets</a></li>
|
||||||
|
<li><a href="qtbridge-figma-template.html">Figma Bridge Template</a></li>
|
||||||
|
<li><a href="quick-images.html">Images</a></li>
|
||||||
|
<li><a href="studio-importing-2d.html">Importing 2D Assets</a></li>
|
||||||
|
<li><a href="sketchqtbridge.html">Sketch Assets</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>3D Assets</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="exporting-3d-assets.html">Exporting 3D Assets</a></li>
|
||||||
|
<li><a href="exporting-from-blender.html">Exporting from Blender</a></li>
|
||||||
|
<li><a href="exporting-from-maya.html">Exporting from Maya</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>3D Scenes</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-3d-camera.html">Cameras</a></li>
|
||||||
|
<li><a href="studio-3d-lights.html">Lights</a></li>
|
||||||
|
<li><a href="studio-3d-scene-environment.html">Scene Environments</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Animations</a>
|
||||||
|
<ul>
|
||||||
|
<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="studio-3d-morph-target.html">Morph Animations</a></li>
|
||||||
|
<li><a href="studio-skeletal-components.html">Skeletal Animations</a></li>
|
||||||
|
<li><a href="qtquick-transition-editor.html#animating-transitions-between-states">Transitions between States</a></li>
|
||||||
|
<li><a href="qtquick-curve-editor.html#editing-animation-curves">Editing Animation Curves</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Code</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="qtquick-text-editor.html">Code</a></li>
|
||||||
|
<li><a href="creator-jump-to-the-code.html">Jump to Code</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Components</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-components.html">Overview</a></li>
|
||||||
|
<li><a href="qtquick-annotations.html">Annotating Designs</a></li>
|
||||||
|
<li><a href="quick-components-view.html#adding-and-removing-modules">Adding and Removing Modules</a></li>
|
||||||
|
<li><a href="quick-component-instances.html">Creating Component Instances</a></li>
|
||||||
|
<li><a href="quick-components-creating.html">Creating Custom Components</a></li>
|
||||||
|
<li><a href="studio-3d-group.html">Grouping Components</a></li>
|
||||||
|
<li><a href="qtquick-properties.html">Specifying Component Properties</a></li>
|
||||||
|
<li><a href="quick-dynamic-properties.html">Specifying Custom Properties</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Connections</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-property-bindings.html">Adding Bindings Between Properties</a></li>
|
||||||
|
<li><a href="quick-signals.html">Connecting Components to Signals</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Data</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-model-editor.html">Data Models</a></li>
|
||||||
|
<li><a href="quick-data-models.html">Lists and Other Data Models</a></li>
|
||||||
|
<li><a href="qtquick-placeholder-data.html">Loading Placeholder Data</a></li>
|
||||||
|
<li><a href="studio-javascript.html">Simulating Application Logic</a></li>
|
||||||
|
<li><a href="studio-simulink.html">Simulating Dynamic Systems</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Debugging and Profiling</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="creator-qml-debugging-example.html">Debugging Qt Quick Applications</a></li>
|
||||||
|
<li><a href="creator-debugging-qml.html">Debugging Qt Quick Projects</a></li>
|
||||||
|
<li><a href="creator-qml-performance-monitor.html">Profiling QML Applications</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Effects</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="working-with-effects.html">Overview</a></li>
|
||||||
|
<li><a href="quick-2d-effects.html">2D Effects</a></li>
|
||||||
|
<li><a href="studio-3d-effects.html">3D Effects</a></li>
|
||||||
|
<li><a href="studio-3d-custom-effects-materials.html">Custom Effects and Materials</a></li>
|
||||||
|
<li><a href="quick-design-effects.html">Design Effects</a></li>
|
||||||
|
<li><a href="qtquick-effect-composer-view.html">Effect Composer</a></li>
|
||||||
|
<li><a href="studio-3d-particles.html">Particles</a></li>
|
||||||
|
<li><a href="studio-content-library.html#adding-an-effect-to-your-project">Using Content Library Effects</a></li>
|
||||||
|
<li><a href="qt-using-effect-maker-effects.html">Using Qt Quick Effect Maker Effects</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>External Tools</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="creator-editor-external.html">Using External Tools</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Git</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="creator-vcs-git.html">Using Git</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Internationalization</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-translations.html#importing-and-exporting-translations">Translations</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Layouts</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="qtquick-positioning.html">Scalable Layouts</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Logical Helpers</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-logic-helpers.html">Logical Helpers</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Materials</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-3d-custom-effects-materials.html">Custom Effects and Materials</a></li>
|
||||||
|
<li><a href="studio-material-editor.html">Materials</a></li>
|
||||||
|
<li><a href="studio-3d-materials.html">Materials and Shaders</a></li>
|
||||||
|
<li><a href="studio-content-library.html#adding-a-material-to-your-project">Using Content Library Materials</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Previewing</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-live-preview-desktop.html">Previewing on Desktop</a></li>
|
||||||
|
<li><a href="creator-live-preview-devices.html">Previewing on Devices</a></li>
|
||||||
|
<li><a href="qt-design-viewer.html">Sharing Applications Online</a></li>
|
||||||
|
<li><a href="qt-ui-viewer.html">Viewing Applications on Android</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Projects</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-projects.html">Creating Projects</a></li>
|
||||||
|
<li><a href="studio-designer-developer-workflow.html">Designer-Developer Workflow</a></li>
|
||||||
|
<li><a href="studio-packaging.html">Packaging Applications</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Qt Design Studio on MCUs</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-on-mcus.html">Overview</li>
|
||||||
|
<li><a href="studio-connecting-mcus-with-creator.html">Connecting MCUs with Qt Creator</a></li>
|
||||||
|
<li><a href="studio-projects-for-mcus.html">Creating Projects for MCUs</a></li>
|
||||||
|
<li><a href="studio-creating-uis-for-mcus.html">Creating UIs for MCUs</a></li>
|
||||||
|
<li><a href="studio-developing-apps-for-mcus.html">Developing Applications for MCUs</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Rendering</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-3d-instancing.html">Instanced Rendering</a></li>
|
||||||
|
<li><a href="studio-3d-repeater-3d.html">The Repeater3D Component</a></li>
|
||||||
|
<li><a href="studio-3d-loader-3d.html">The Loader3D Component</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Shaders</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-3d-custom-shaders.html">Custom Shaders</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>States</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-states.html">States</li>
|
||||||
|
<li><a href="qtquick-transition-editor.html#animating-transitions-between-states">Transition between states</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Textures</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-texture-editor.html">Textures</a></li>
|
||||||
|
<li><a href="studio-3d-texture.html">The Texture Component</a></li>
|
||||||
|
<li><a href="studio-content-library.html#adding-a-texture-or-environment-to-your-project">Using Content Library Textures</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>UI Controls and Elements</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-shapes.html">Shapes</a></li>
|
||||||
|
<li><a href="quick-text.html">Text</a></li>
|
||||||
|
<li><a href="quick-controls.html">UI Controls</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>User Data</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="collecting-usage-statistics.html">Collecting Usage Statistics</a></li>
|
||||||
|
<li><a href="studio-user-feedback.html">Collecting User Feedback</a></li>
|
||||||
|
<li><a href="creator-telemetry.html">Managing Data Collection</a></li>
|
||||||
|
<li><a href="studio-crashpad.html">Reporting Crashes</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>User Interaction</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-user-interaction-methods.html">User Interaction Methods</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="sectionlist normallist">
|
||||||
|
<div class="heading">
|
||||||
|
<h2>Best Practices</h2>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li><a>Graphics</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="best-practices-glow.html">Creating Glow and Bloom Effects</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Performance</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-optimized-3d-scenes.html">Creating an Optimized 3D Scenes</a></li>
|
||||||
|
<li><a href="qtquick-optimizing-designs.html">Optimizing Designs</a></li>
|
||||||
|
<li><a href="qtquick-production-quality-animation.html">Production Quality</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Projects</a>
|
||||||
|
<ul>
|
||||||
|
<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>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sectionlist normallist">
|
||||||
|
<div class="heading">
|
||||||
|
<h2>Tutorials</h2>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li><a href="gstutorials.html">Overview</a></li>
|
||||||
|
<li><a href="multilanguage-tutorial.html">Adding Multi-lanugage support to Your Project</a></li>
|
||||||
|
<li><a href="state-transition-animations.html">Animated State Transitions</a></li>
|
||||||
|
<li><a href="robotarm-example.html">Creating a C++ Backend for a Qt Design Studio Application</a></li>
|
||||||
|
<li><a href="qtdesignstudio-loginui1-example.html">Log In UI - Components</a></li>
|
||||||
|
<li><a href="qtdesignstudio-loginui2-example.html">Log In UI - Positioning</a></li>
|
||||||
|
<li><a href="qtdesignstudio-loginui3-example.html">Log In UI - States</a></li>
|
||||||
|
<li><a href="qtdesignstudio-loginui4-example.html">Log In UI - Timeline</a></li>
|
||||||
|
<li><a href="fire-particle-effect.html">Particle System: Fire Effect</a></li>
|
||||||
|
<li><a href="rain-snow-particle-effect.html">Particle System: Rain and Snow Effect</a></li>
|
||||||
|
<li><a href="3d-scene-tutorial.html">Setting up a 3D Scene</a></li>
|
||||||
|
<li><a href="animation-tutorial.html">Timeline Animation Tutorial</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sectionlist normallist">
|
||||||
|
<div class="heading">
|
||||||
|
<h2>Examples</h2>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studioexamples.html">Overview</a></li>
|
||||||
|
<li><a href="qtdesignstudio-coffeemachine-example.html">Coffee Machine</a></li>
|
||||||
|
<li><a href="qtdesignstudio-ebikedesign-example.html">E-Bike Design</a></li>
|
||||||
|
<li><a href="effect-composer-example.html">Effect Composer Example</a></li>
|
||||||
|
<li><a href="fresnel-effect-example.html">Fresnel Example</a></li>
|
||||||
|
<li><a href="material-bundle-example.html">Material Bundle</a></li>
|
||||||
|
<li><a href="qtdesignstudio-optimal3dscene-example.html">Optimal 3D Scene</a></li>
|
||||||
|
<li><a href="qtdesignstudio-progressbar-example.html">Progress Bar</a></li>
|
||||||
|
<li><a href="qtdesignstudio-sidemenu-example.html">Side Menu</a></li>
|
||||||
|
<li><a href="qtdesignstudio-simplekeyboard-example.html">Simple Keyboard</a></li>
|
||||||
|
<li><a href="qtdesignstudio-washingmachineui-example.html">Washing Machine UI</a></li>
|
||||||
|
<li><a href="qtdesignstudio-webinardemo-example.html">Webinar Demo</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sectionlist normallist">
|
||||||
|
<div class="heading">
|
||||||
|
<h2>Reference</h2>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li><a>2D Components</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-preset-components.html#2d-components">Overview</a></li>
|
||||||
|
<li><a href="quick-animations.html">Animations</a></li>
|
||||||
|
<li><a href="quick-design-effects.html">Design Effects</a></li>
|
||||||
|
<li><a href="quick-2d-effects.html">Effects</a></li>
|
||||||
|
<li><a href="quick-images.html">Images</a></li>
|
||||||
|
<li><a href="quick-data-models.html">Lists and Other Data Models</a></li>
|
||||||
|
<li><a href="quick-logic-helpers.html">Logical Helpers</a></li>
|
||||||
|
<li><a href="quick-shapes.html">Shapes</a></li>
|
||||||
|
<li><a href="quick-text.html">Text</a></li>
|
||||||
|
<li><a href="quick-user-interaction-methods.html">User Interaction Methods</a></li>
|
||||||
|
<li><a href="quick-controls.html">UI Controls</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>3D Components</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="quick-preset-components.html#3d-components">Overview</a></li>
|
||||||
|
<li><a href="studio-3d-camera.html">Cameras</a></li>
|
||||||
|
<li><a href="studio-3d-custom-effects-materials.html">Custom Effects and Materials</a></li>
|
||||||
|
<li><a href="studio-3d-custom-shaders.html">Custom Shaders</a></li>
|
||||||
|
<li><a href="studio-3d-effects.html">Effects</a></li>
|
||||||
|
<li><a href="studio-3d-group.html">Group</a></li>
|
||||||
|
<li><a href="studio-3d-instancing.html">Instanced Rendering</a></li>
|
||||||
|
<li><a href="studio-3d-lights.html">Lights</a></li>
|
||||||
|
<li><a href="studio-3d-loader-3d.html">Loader3D</a></li>
|
||||||
|
<li><a href="studio-3d-materials-types.html">Materials</a></li>
|
||||||
|
<li><a href="studio-3d-materials.html">Materials and Shaders</a></li>
|
||||||
|
<li><a href="studio-3d-model.html">Models</a></li>
|
||||||
|
<li><a href="studio-3d-morph-target.html">Morph Target</a></li>
|
||||||
|
<li><a href="studio-3d-view.html">Views</a></li>
|
||||||
|
<li><a href="studio-3d-node.html">Node</a></li>
|
||||||
|
<li><a href="studio-3d-particles.html">Particles</a></li>
|
||||||
|
<li><a href="studio-3d-repeater-3d.html">Repeater3D</a></li>
|
||||||
|
<li><a href="studio-3d-scene-environment.html">Scene Environments</a></li>
|
||||||
|
<li><a href="studio-skeletal-components.html">Skeletal Animation</a></li>
|
||||||
|
<li><a href="studio-3d-texture.html">Textures</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Files</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="creator-quick-ui-forms.html">UI Files</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Help</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-terms.html">Concept and Terms</a></li>
|
||||||
|
<li><a href="studio-keyboard-shortcuts.html">Keyboard Shortcuts</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>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Qt Design Studio on MCUs</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="studio-features-on-mcu-projects.html">Supported Features</a></li>
|
||||||
|
<li><a href="studio-compatibility-with-mcu-sdks.html">Version Compatibility</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a>Views</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="creator-using-qt-quick-designer.html">Overview</a></li>
|
||||||
|
<li><a href="qtquick-form-editor.html">2D</a></li>
|
||||||
|
<li><a href="studio-3d-editor.html">3D</a></li>
|
||||||
|
<li><a href="quick-assets.html">Assets</a></li>
|
||||||
|
<li><a href="qtquick-text-editor.html">Code</a></li>
|
||||||
|
<li><a href="quick-components-view.html">Components</a></li>
|
||||||
|
<li><a href="qtquick-connection-view.html">Connections</a></li>
|
||||||
|
<li><a href="studio-content-library.html">Content Library</a></li>
|
||||||
|
<li><a href="qtquick-curve-editor.html">Curves</a></li>
|
||||||
|
<li><a href="qtquick-effect-composer-view.html">Effect Composer</a></li>
|
||||||
|
<li><a href="creator-file-system-view.html">File System</a></li>
|
||||||
|
<li><a href="studio-material-editor.html">Material Editor and Browser</a></li>
|
||||||
|
<li><a href="qtquick-navigator.html">Navigator</a></li>
|
||||||
|
<li><a href="creator-open-documents-view.html">Open Documents</a></li>
|
||||||
|
<li><a href="creator-projects-view.html">Projects</a></li>
|
||||||
|
<li><a href="qtquick-properties-view.html">Properties</a></li>
|
||||||
|
<li><a href="studio-qt-insight.html">Qt Insight</a></li>
|
||||||
|
<li><a href="qtquick-states-view.html">States</a></li>
|
||||||
|
<li><a href="studio-texture-editor.html">Texture Editor</a></li>
|
||||||
|
<li><a href="qtquick-timeline-view.html">Timeline</a></li>
|
||||||
|
<li><a href="qtquick-transition-editor.html">Transitions</a></li>
|
||||||
|
<li><a href="studio-translations.html">Translations</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
BIN
doc/qtdesignstudio/images/studio-edit-list-model.webp
Normal file
BIN
doc/qtdesignstudio/images/studio-edit-list-model.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
doc/qtdesignstudio/images/studio-feedback-popup-material.png
Normal file
BIN
doc/qtdesignstudio/images/studio-feedback-popup-material.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.8 KiB |
@@ -1,9 +1,9 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\page quick-components.html
|
\page quick-components.html
|
||||||
\previouspage studio-flow-external-events.html
|
\previouspage quick-uis.html
|
||||||
\nextpage quick-preset-components.html
|
\nextpage quick-preset-components.html
|
||||||
|
|
||||||
\title Using Components
|
\title Using Components
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -147,12 +147,12 @@
|
|||||||
\uicontrol {Default Components} > \uicontrol Views to the
|
\uicontrol {Default Components} > \uicontrol Views to the
|
||||||
\uicontrol Navigator or \uicontrol {2D} view.
|
\uicontrol Navigator or \uicontrol {2D} view.
|
||||||
\li Right-click the view in \uicontrol Navigator, and select
|
\li Right-click the view in \uicontrol Navigator, and select
|
||||||
\uicontrol {Edit Model} in the context-menu to open the
|
\uicontrol {Edit List Model} in the context-menu to open
|
||||||
\uicontrol {Model Editor} view.
|
the list model editor.
|
||||||
\image edit-list-model-model-editor.webp "List view in Model Editor"
|
\image studio-edit-list-model.webp "List view in the list model editor"
|
||||||
\li Double-click a cell to edit its value.
|
\li Double-click the column headings and cells to change their values.
|
||||||
\li Use the toolbar buttons to add or remove rows and columns.
|
\li Use the toolbar buttons to add, remove, or move rows and columns.
|
||||||
In a list, each column represents a property, and each row adds a
|
In a list, each column represents a property and each row adds a
|
||||||
list item.
|
list item.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
|
@@ -39,6 +39,9 @@
|
|||||||
\list
|
\list
|
||||||
\li Qt Creator 13.0 or above.
|
\li Qt Creator 13.0 or above.
|
||||||
\li \QDS 4.5 or above.
|
\li \QDS 4.5 or above.
|
||||||
|
\li Git.
|
||||||
|
|
||||||
|
\note Learn more about getting Git \l {https://wiki.qt.io/Git_Installation} {here}.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\list 1
|
\list 1
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
\list
|
\list
|
||||||
\li Common motion design techniques for 2D and 3D
|
\li Common motion design techniques for 2D and 3D
|
||||||
\li Screen-to-screen or state-to-state animations
|
\li State-to-state animations
|
||||||
\li Data-driven UI logic animations
|
\li Data-driven UI logic animations
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
\section2 Animation Curves
|
\section2 Animation Curves
|
||||||
|
|
||||||
While easing curves work well for most simple UI animations, more complex
|
While easing curves work well for most simple UI animations, more complex
|
||||||
3D animations require several keyframes so it becomes necessary to visualize
|
3D animations require several keyframes, so it becomes necessary to visualize
|
||||||
the value and the interpolation of a keyframe simultaneously. The
|
the value and the interpolation of a keyframe simultaneously. The
|
||||||
\l {Curves} view visualizes the whole animation of a property at once and
|
\l {Curves} view visualizes the whole animation of a property at once and
|
||||||
shows the effective values of a keyframe together with the interpolation
|
shows the effective values of a keyframe together with the interpolation
|
||||||
@@ -78,36 +78,11 @@
|
|||||||
simultaneously so that you can see the animation for the x position
|
simultaneously so that you can see the animation for the x position
|
||||||
and the animation for the y position side-by-side.
|
and the animation for the y position side-by-side.
|
||||||
|
|
||||||
\section1 Screen-to-Screen or State-to-State Animations
|
\section1 State-to-State Animations
|
||||||
|
|
||||||
The following table summarizes techniques used for navigating between
|
To navigate between UI states, use transitions between different states of the UI
|
||||||
screens and UI states.
|
using a transition timeline that is based on keyframes. You can apply easing
|
||||||
|
curves to the keyframes.
|
||||||
\table
|
|
||||||
\header
|
|
||||||
\li Technique
|
|
||||||
\li Use Case
|
|
||||||
\row
|
|
||||||
\li \l{Designing Application Flows}{Application flows}
|
|
||||||
\li An interactive prototype that can be clicked through to simulate
|
|
||||||
the user experience of the application.
|
|
||||||
\row
|
|
||||||
\li \l{Transitions}{Transitions between states}
|
|
||||||
\li Transitions between different states of the UI using a transition
|
|
||||||
timeline that is based on keyframes. You can apply easing curves
|
|
||||||
to the keyframes.
|
|
||||||
\endtable
|
|
||||||
|
|
||||||
\section2 Application Flows
|
|
||||||
|
|
||||||
You can design an application in the form of a \e {schematic diagram}
|
|
||||||
that shows all the significant components of the application UI and their
|
|
||||||
interconnections by means of symbols. This results in an interactive
|
|
||||||
prototype that can be clicked through to simulate the user experience of
|
|
||||||
the application. Code is created in the background and can be used
|
|
||||||
as the base of the production version of the application.
|
|
||||||
|
|
||||||
For more information, see \l{Designing Application Flows}.
|
|
||||||
|
|
||||||
\section2 Transitions Between States
|
\section2 Transitions Between States
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
\li You can use different animation techniques for different
|
\li You can use different animation techniques for different
|
||||||
purposes. \QDS supports common motion design techniques,
|
purposes. \QDS supports common motion design techniques,
|
||||||
such as timeline and keyframe based animation and easing
|
such as timeline and keyframe based animation and easing
|
||||||
curves, as well as screen-to-screen or state-to-state
|
curves, as well as state-to-state application flows and
|
||||||
application flows and data-driven UI logic animation.
|
data-driven UI logic animation.
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
\list
|
\list
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\page quick-uis.html
|
\page quick-uis.html
|
||||||
\previouspage {Examples}
|
\previouspage {Examples}
|
||||||
\nextpage studio-app-flows.html
|
\nextpage quick-components.html
|
||||||
|
|
||||||
\title Wireframing
|
\title Wireframing
|
||||||
|
|
||||||
@@ -38,15 +38,6 @@
|
|||||||
the developer documentation by pressing \key F1.
|
the developer documentation by pressing \key F1.
|
||||||
|
|
||||||
\list
|
\list
|
||||||
|
|
||||||
\li \l {Designing Application Flows}
|
|
||||||
|
|
||||||
You can design an application in the form of a \e {schematic diagram}
|
|
||||||
that shows all significant components of an application UI and their
|
|
||||||
interconnections by means of symbols. This results in an
|
|
||||||
interactive prototype that can be clicked through to simulate
|
|
||||||
the user experience of the application.
|
|
||||||
|
|
||||||
\li \l {Using Components}
|
\li \l {Using Components}
|
||||||
|
|
||||||
\QDS comes with \e {preset components} that you can use in
|
\QDS comes with \e {preset components} that you can use in
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
\uicontrol Skip or \uicontrol Submit, the pop-up survey will not appear for
|
\uicontrol Skip or \uicontrol Submit, the pop-up survey will not appear for
|
||||||
the same feature again.
|
the same feature again.
|
||||||
|
|
||||||
\image studio-feedback-popup.png "User feedback pop-up survey for Flow Editor"
|
\image studio-feedback-popup-material.png "User feedback pop-up survey for Material Browser"
|
||||||
|
|
||||||
For the pop-up survey to appear, you must enable collecting statistics, and
|
For the pop-up survey to appear, you must enable collecting statistics, and
|
||||||
also allow collecting \uicontrol {4 - Detailed usage statistics} in
|
also allow collecting \uicontrol {4 - Detailed usage statistics} in
|
||||||
|
@@ -1,707 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-app-flows.html
|
|
||||||
\previouspage quick-uis.html
|
|
||||||
\nextpage studio-flow-view.html
|
|
||||||
|
|
||||||
\title Designing Application Flows
|
|
||||||
|
|
||||||
\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. \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.
|
|
||||||
|
|
||||||
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. Use \e {flow wildcards}
|
|
||||||
to determine the priority of flow items by adding them to allow and
|
|
||||||
block lists.
|
|
||||||
|
|
||||||
To design application flows:
|
|
||||||
|
|
||||||
\image studio-flow-steps.png "Designing application flows"
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Use a project wizard template to add a \uicontrol {Flow View}
|
|
||||||
component, as described in \l{Adding Flow Views}.
|
|
||||||
\li Use a project wizard template to add a \uicontrol {Flow Item}
|
|
||||||
component for each screen in the UI, as described in
|
|
||||||
\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 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
|
|
||||||
described in \l{Applying States in Flows}.
|
|
||||||
\li Use \uicontrol {Flow Wildcard} components from
|
|
||||||
\uicontrol Components > \uicontrol {Flow View} to prioritize events
|
|
||||||
from other applications and to stop some screens from appearing on
|
|
||||||
others, as described in \l{Reacting to External Events}.
|
|
||||||
\endlist
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-view.html
|
|
||||||
\previouspage studio-app-flows.html
|
|
||||||
\nextpage studio-flow-item.html
|
|
||||||
|
|
||||||
\title Adding Flow Views
|
|
||||||
|
|
||||||
A flow view is the base component of the flow diagram that you can use to wireframe
|
|
||||||
the UI of your application. For more information, see \l{Designing Application Flows}.
|
|
||||||
|
|
||||||
Add a flow view to an existing project or create a new project for it, as described in
|
|
||||||
\l {Creating Projects}.
|
|
||||||
|
|
||||||
To create the flow view, select \uicontrol File >
|
|
||||||
\uicontrol {New File} >
|
|
||||||
\uicontrol {Qt Quick Files} > \uicontrol {Flow View}
|
|
||||||
and follow the instructions of the wizard.
|
|
||||||
|
|
||||||
\image studio-flow-view-create.png "Create Flow View wizard template"
|
|
||||||
|
|
||||||
If you want to add an event simulator to the flow view, select the
|
|
||||||
\uicontrol {Use Event Simulator} checkbox. In this case, select also the
|
|
||||||
\uicontrol {Use Application Import} checkbox to import the project to the flow view
|
|
||||||
as the event simulator requires it to work correctly. You need the
|
|
||||||
import also for access to the project \c Constants.qml file that contains
|
|
||||||
global settings for the project. For more information, see \l {Simulating Events}.
|
|
||||||
|
|
||||||
You can adjust the appearance of all the items in the flow: action areas,
|
|
||||||
transition lines, decisions, and wildcards. Change the global settings for all items
|
|
||||||
by editing the flow view properties. To add additional semantics to the flow diagram
|
|
||||||
design, select an individual action area or transition line and change the appearance
|
|
||||||
of just that component.
|
|
||||||
|
|
||||||
\section1 Flow View Properties
|
|
||||||
|
|
||||||
You can specify basic properties for a \uicontrol {Flow View} component
|
|
||||||
in the \l {Type}{Component}, \l {2D Geometry}{Geometry - 2D}, and
|
|
||||||
\l Visibility sections in the \l Properties view. Specify flow view
|
|
||||||
properties in the \uicontrol {Flow View} section.
|
|
||||||
|
|
||||||
\image studio-flow-view-properties.webp "Flow View component properties"
|
|
||||||
|
|
||||||
To specify the \uicontrol {Flow Item} that is currently visible in the
|
|
||||||
flow view, set its index in the \uicontrol {Current index} field.
|
|
||||||
|
|
||||||
Use the \l{Picking Colors}{color picker} to set colors for:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li Transition lines
|
|
||||||
\li Area outlines
|
|
||||||
\li Area fills
|
|
||||||
\li Block items
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
You can set some additional global properties for drawing transition lines:
|
|
||||||
|
|
||||||
\image studio-flow-view-properties-transition.png "Flow View transition properties"
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li In the \uicontrol {Type} field, select \uicontrol Bezier to draw
|
|
||||||
transition lines as bezier curves.
|
|
||||||
\li In the \uicontrol {Radius} field, specify the corner radius for
|
|
||||||
default curves.
|
|
||||||
\li In the \uicontrol {Bezier factor} field, specify the factor that
|
|
||||||
modifies the positions of the control points used for bezier curves.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
For more information about changing the appearance of a particular action
|
|
||||||
area or transition line, see \l{Flow Action Area Properties} and
|
|
||||||
\l{Flow Transition Properties}.
|
|
||||||
|
|
||||||
In the \uicontrol Advanced section, you can manage the more
|
|
||||||
\l{Specifying Developer Properties}{advanced properties}
|
|
||||||
of components.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-item.html
|
|
||||||
\previouspage studio-flow-view.html
|
|
||||||
\nextpage studio-flow-action-area.html
|
|
||||||
|
|
||||||
\title Adding Flow Items
|
|
||||||
|
|
||||||
After you create a \l{Adding Flow Views}{Flow View} component, use a project wizard
|
|
||||||
template to add a \uicontrol {Flow Item} component for each screen in the UI.
|
|
||||||
|
|
||||||
If you \l{Importing 2D Assets}{imported} your screen designs from a
|
|
||||||
design tool as individual \l{glossary-component}{components}
|
|
||||||
(\e {.ui.qml} files), you can use them as content for flow items like any other components.
|
|
||||||
The imported components are listed in \uicontrol Components
|
|
||||||
> \uicontrol {My Components}.
|
|
||||||
|
|
||||||
If you are building your UI from scratch in \QDS, add components to the flow items
|
|
||||||
first to create the screens as you would any components. For more information, see
|
|
||||||
\l {Using Components}. The flow items that you attach the components to are listed under
|
|
||||||
\uicontrol {My Components}.
|
|
||||||
|
|
||||||
\image studio-flow-item.webp "Custom Flow Item in Components"
|
|
||||||
|
|
||||||
\note You must use the wizard to create the flow items. After you create
|
|
||||||
a flow view, the \uicontrol {Flow View} module is added to
|
|
||||||
\uicontrol Components. It contains the \uicontrol {Flow Item} component for
|
|
||||||
\l{Applying States in Flows}{applying states to flow items}, and solely for that purpose.
|
|
||||||
|
|
||||||
To add flow items:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Select \uicontrol File > \uicontrol {New File} >
|
|
||||||
\uicontrol {Qt Quick Files} >
|
|
||||||
\uicontrol {Flow Item} and follow the instructions of the wizard
|
|
||||||
to create flow items for each screen in the UI.
|
|
||||||
\li Add content to the flow item in one of the following ways:
|
|
||||||
\list
|
|
||||||
\li Drag components from \uicontrol Components to a
|
|
||||||
flow item in the \l {2D} view or \l Navigator.
|
|
||||||
\li Drag a screen from \uicontrol Components
|
|
||||||
> \uicontrol {My Components} to a flow item in
|
|
||||||
the \uicontrol {2D} view or \uicontrol Navigator.
|
|
||||||
\endlist
|
|
||||||
\li In \l Properties, edit the properties of each flow item.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
Now, drag the flow items from \uicontrol Components > \uicontrol {My Components} to the
|
|
||||||
flow view in the \uicontrol {2D} or \uicontrol Navigator view. When you have all the flow
|
|
||||||
items in place, \l{Adding Action Areas and Transitions}{add action areas} to them to create
|
|
||||||
transitions between them.
|
|
||||||
|
|
||||||
\section1 Flow Item Properties
|
|
||||||
|
|
||||||
You can specify basic properties for a \uicontrol {Flow Item} component
|
|
||||||
in the \l {Type}{Component}, \l {2D Geometry}{Geometry - 2D}, and
|
|
||||||
\l Visibility sections in the \uicontrol Properties view. Specify flow item
|
|
||||||
properties in the \uicontrol {Flow Item} section.
|
|
||||||
|
|
||||||
\image studio-flow-item-properties.png "Flow Item properties"
|
|
||||||
|
|
||||||
The \uicontrol {State change target} and \uicontrol {Target state}
|
|
||||||
properties are used to \l{Applying States in Flows}{apply states}
|
|
||||||
in flows.
|
|
||||||
|
|
||||||
To include another flow view as a flow item into a flow view, select the UI file (.ui.qml)
|
|
||||||
that specifies the flow view in the \uicontrol {Loader source} field.
|
|
||||||
|
|
||||||
Usually, a flow item is inactive and invisible when it is not currently
|
|
||||||
selected in the flow. Especially, all events from the flow item are ignored.
|
|
||||||
To make a flow item always active, so that another flow item within it
|
|
||||||
can respond to events and trigger the opening of a dialog, for example,
|
|
||||||
select the \uicontrol {Force active} checkbox.
|
|
||||||
|
|
||||||
In the flow view, transitions are drawn from action areas to the target flow item by default.
|
|
||||||
To draw the transitions from the edges of flow items instead, select the
|
|
||||||
\uicontrol {Join lines} checkbox in the \uicontrol {Transition Lines}
|
|
||||||
section.
|
|
||||||
|
|
||||||
In the \uicontrol Advanced section, you can manage the more
|
|
||||||
\l{Specifying Developer Properties}{advanced properties} of components.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-action-area.html
|
|
||||||
\previouspage studio-flow-item.html
|
|
||||||
\nextpage studio-flow-effects.html
|
|
||||||
|
|
||||||
\title Adding Action Areas and Transitions
|
|
||||||
|
|
||||||
\e {Action areas} are clickable areas that initiate transitions between flow items or
|
|
||||||
\l{Connecting and Releasing Signals}{create connections} to any signal from any component in a
|
|
||||||
\l{Adding Flow Items}{flow item}. For example, you could connect an
|
|
||||||
action to the \c onPressed signal of a button in your flow item to
|
|
||||||
determine what should happen when users press the button.
|
|
||||||
|
|
||||||
\image studio-flow-action-area.webp "Flow Action Area in the 2D view"
|
|
||||||
|
|
||||||
Select the type of the mouse or touch input to use for triggering
|
|
||||||
events, such as click, double-click, flick, pinch, or long press.
|
|
||||||
|
|
||||||
Typically, a flow item is connected to several other flow items in the
|
|
||||||
flow with two-way connections. To avoid clutter, set an action area
|
|
||||||
as \e {go back} instead of adding explicit transition lines to and from
|
|
||||||
every potentially connected flow item. When the \uicontrol {Go back} option
|
|
||||||
is enabled, the transition will always take the user back to the previous
|
|
||||||
flow item.
|
|
||||||
|
|
||||||
You can specify the appearance of each action area or transition line,
|
|
||||||
including the color, line thickness, dotted or solid lines, and even
|
|
||||||
the curve of the transition lines. You can change some of these properties
|
|
||||||
globally, as instructed in \l{Flow View Properties}.
|
|
||||||
|
|
||||||
To create action areas:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Select the flow item in the \l {2D} view, then right-click it, and select
|
|
||||||
\uicontrol {Flow} > \uicontrol {Create Flow Action} in
|
|
||||||
the context menu.
|
|
||||||
\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. 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
|
|
||||||
|
|
||||||
To preview the flow, select the
|
|
||||||
\uicontrol {Live Preview} button on the top toolbar or press \key Alt +
|
|
||||||
\key P.
|
|
||||||
|
|
||||||
\section1 Common Properties
|
|
||||||
|
|
||||||
Specify basic properties for \uicontrol {Flow Action Area}
|
|
||||||
and \uicontrol {Flow Transition} components in the \l {Type}{Component},
|
|
||||||
\l {2D Geometry}{Geometry - 2D}, and \l Visibility sections in the
|
|
||||||
\uicontrol Properties view.
|
|
||||||
|
|
||||||
Use \l{Setting Anchors and Margins}{anchors} in the \uicontrol Layout tab to position
|
|
||||||
the component.
|
|
||||||
|
|
||||||
Manage the more \l{Specifying Developer Properties}{advanced properties} of components
|
|
||||||
in the \uicontrol Advanced section.
|
|
||||||
|
|
||||||
\section1 Flow Action Area Properties
|
|
||||||
|
|
||||||
Use the \l{Picking Colors}{color picker} in the \uicontrol {Flow Action Area} section
|
|
||||||
to set line and fill color.
|
|
||||||
|
|
||||||
\image studio-flow-action-area-properties.webp "Flow Action Area properties"
|
|
||||||
|
|
||||||
Specify additional properties for action areas in the \uicontrol {Flow Action} and
|
|
||||||
\uicontrol {Action Area} sections:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li Select the \uicontrol {Go back} checkbox to specify that the
|
|
||||||
transition will always take the user back to the previous flow item.
|
|
||||||
\li In the \uicontrol {Event IDs} field, specify the IDs of the
|
|
||||||
events to connect to, such as mouse, touch or keyboard events.
|
|
||||||
\li In the \uicontrol {Action type} field, select the type of the
|
|
||||||
mouse or touch input to use for triggering events.
|
|
||||||
\li In the \uicontrol {Line width} field, set the width of the
|
|
||||||
action area outline.
|
|
||||||
\li Select the \uicontrol {Dashed line} checkbox to draw a dashed
|
|
||||||
action area outline.
|
|
||||||
\li Select the \uicontrol Enabled checkbox to enable interaction
|
|
||||||
with the action area during preview.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\section1 Flow Transition Properties
|
|
||||||
|
|
||||||
Specify additional properties for transitions between \l{Adding Flow Items}{flow items}
|
|
||||||
in the \uicontrol Transition section:
|
|
||||||
|
|
||||||
\image studio-flow-transition-properties.webp "Flow Transition properties"
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li Select the \uicontrol Condition checkbox to activate the
|
|
||||||
transition. Select \inlineimage icons/action-icon.png
|
|
||||||
to \l{Adding Bindings Between Properties}{bind} a condition
|
|
||||||
to the transition.
|
|
||||||
\li In the \uicontrol Question field, enter the text that will appear
|
|
||||||
next to the transition line. If the transition represents the
|
|
||||||
connection to a \uicontrol {Flow Decision} component, the
|
|
||||||
text will also be visible in the selection dialog that opens when
|
|
||||||
the \l{Simulating Conditions}{condition} is triggered.
|
|
||||||
\li In the \uicontrol {Event IDs} field, specify the IDs of the
|
|
||||||
events to connect to, such as mouse, touch or keyboard events.
|
|
||||||
\li In the \uicontrol From and \uicontrol To fields, select the
|
|
||||||
flow item where the transition starts and the one where it
|
|
||||||
ends.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
Specify the following properties to change the appearance of transition lines in
|
|
||||||
the \uicontrol {2D} view:
|
|
||||||
|
|
||||||
\image studio-flow-transition-line-properties.webp "Flow Transition Line properties"
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li In the \uicontrol {Line width} field, set the width of the
|
|
||||||
transition line.
|
|
||||||
\li In the \uicontrol {Offset} and \uicontrol {Break offset} fields, set
|
|
||||||
the start point (\uicontrol Out) or end point (\uicontrol In) of a
|
|
||||||
transition line or a break to the specified offset. This enables
|
|
||||||
you to move them up and down or left and right.
|
|
||||||
\li Select the \uicontrol {Dashed line} checkbox to draw a dashed line.
|
|
||||||
\li In the \uicontrol Type field, select \uicontrol Bezier to draw
|
|
||||||
transition lines as bezier curves.
|
|
||||||
\li In the \uicontrol Radius field, specify the corner radius for
|
|
||||||
default curves.
|
|
||||||
\li In the \uicontrol {Bezier factor} field, specify the factor that
|
|
||||||
modifies the positions of the control points used for a bezier
|
|
||||||
curve.
|
|
||||||
\li In the \uicontrol {Label position} field, set the position of
|
|
||||||
the value of the \uicontrol Question field in respect to the
|
|
||||||
transition start point.
|
|
||||||
\li Select the \uicontrol {Label flip side} checkbox to move the
|
|
||||||
\uicontrol Question value to the opposite side of the transition
|
|
||||||
line.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\section1 Connecting and Releasing Signals
|
|
||||||
|
|
||||||
To connect components to \l{Connecting Components to Signals}{signals}, export the
|
|
||||||
components first as \l{Adding Property Aliases}{aliases} in \l Navigator. To create
|
|
||||||
and release connections, select \uicontrol {Open Signal Dialog} in the context menu.
|
|
||||||
The \uicontrol {Signal List} dialog displays the signals for all components.
|
|
||||||
|
|
||||||
\image studio-flow-signal-list.webp "Signal List dialog"
|
|
||||||
|
|
||||||
To connect a component to a signal, select \uicontrol Connect next to one
|
|
||||||
in the list. To release a connected signal, select \uicontrol Release.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-effects.html
|
|
||||||
\previouspage studio-flow-action-area.html
|
|
||||||
\nextpage studio-flow-events.html
|
|
||||||
|
|
||||||
\title Applying Effects to Transitions
|
|
||||||
|
|
||||||
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. 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
|
|
||||||
\l{Editing Easing Curves}{attach an easing curve} to the effect.
|
|
||||||
|
|
||||||
To add effects:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Select a transition line in the \l {2D} view.
|
|
||||||
\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, 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
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
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} to attach an
|
|
||||||
\l{Editing Easing Curves}{easing curve} to the effect.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li In the \uicontrol Direction field, specify the direction that
|
|
||||||
the target \uicontrol {Flow Item} appears from: left, right, top,
|
|
||||||
or bottom.
|
|
||||||
\li In the \uicontrol Scale field, set scaling for the effect.
|
|
||||||
\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 checkbox to reveal the
|
|
||||||
\uicontrol {Flow Item} where the transition starts.
|
|
||||||
\endlist
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-events.html
|
|
||||||
\previouspage studio-flow-effects.html
|
|
||||||
\nextpage studio-flow-conditions.html
|
|
||||||
|
|
||||||
\title Simulating Events
|
|
||||||
|
|
||||||
While \l{Adding Action Areas and Transitions}{transition lines}
|
|
||||||
are useful for prototyping, in production you need to use the real
|
|
||||||
\l{Connecting and Releasing Signals}{signals} from UI
|
|
||||||
\l{glossary-component}{components} to control the flow of the application.
|
|
||||||
For this purpose, you can use action areas in a more advanced way, by
|
|
||||||
having them listen to signals from flow items or the controls in them and
|
|
||||||
by connecting these to the \l{Adding Flow Views}{flow view}. You can use
|
|
||||||
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} checkbox to add an event simulator to
|
|
||||||
the flow view.
|
|
||||||
|
|
||||||
You can create an event list where you assign keyboard shortcuts to events,
|
|
||||||
and then use context-menu commands to attach the events to action areas or
|
|
||||||
transition lines.
|
|
||||||
|
|
||||||
\section1 Creating Event Lists
|
|
||||||
|
|
||||||
To create an event list:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Right-click in the \uicontrol 2D or \uicontrol Navigator view and select
|
|
||||||
\uicontrol {Event List} > \uicontrol {Show Event List}.
|
|
||||||
\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. 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
|
|
||||||
keyboard shortcut. The key identifier appears in the field.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
You can now assign the events to action areas and transitions.
|
|
||||||
|
|
||||||
\section1 Assigning Events to Actions
|
|
||||||
|
|
||||||
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.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-events-event-list.webp "Event list in Live Preview"
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-conditions.html
|
|
||||||
\previouspage studio-flow-events.html
|
|
||||||
\nextpage studio-flow-states.html
|
|
||||||
|
|
||||||
\title Simulating Conditions
|
|
||||||
|
|
||||||
Part of any complex UI is the conditional logic it uses to present its
|
|
||||||
state to users or to collect and process data from various sources. Data
|
|
||||||
can be produced by user interaction from a variety of inputs, such as
|
|
||||||
buttons and controls, sensor readings from arrays of equipment, or general
|
|
||||||
values received from backend or service APIs.
|
|
||||||
|
|
||||||
The \uicontrol {Flow Decision} component simulates conditions by displaying a
|
|
||||||
list of options you can choose from when you preview the flow. This enables
|
|
||||||
you to prototype complex interactions before you have access to the physical
|
|
||||||
controls, backend, or sensor data that will be required for the production
|
|
||||||
version.
|
|
||||||
|
|
||||||
\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
|
|
||||||
\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. 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.
|
|
||||||
\li Select the flow decision, and then select \uicontrol Connect in the
|
|
||||||
context menu to create connections to the flow items that will open
|
|
||||||
depending on whether the condition is met.
|
|
||||||
\li In the \l Properties view, \uicontrol {Dialog title} field, enter a
|
|
||||||
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 {Question} field in \uicontrol Properties to represent
|
|
||||||
a choice in the selection dialog.
|
|
||||||
\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.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
Flow decisions are listed in a dialog where you can select which condition
|
|
||||||
is met to see the results.
|
|
||||||
|
|
||||||
\image studio-flow-decision-preview.webp "Selection dialog for flow decision"
|
|
||||||
|
|
||||||
\section1 Flow Decision Properties
|
|
||||||
|
|
||||||
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.webp "Flow Decision properties"
|
|
||||||
|
|
||||||
In the \uicontrol {Dialog title} field, enter a title for the selection
|
|
||||||
dialog that opens when the condition is triggered.
|
|
||||||
|
|
||||||
Specify the following properties to change the appearance of the
|
|
||||||
flow decision icon \inlineimage icons/flow-decision-icon.png
|
|
||||||
:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li Select \inlineimage icons/visibility-off.png
|
|
||||||
to display the ID of the \uicontrol {Flow Decision}
|
|
||||||
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
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-states.html
|
|
||||||
\previouspage studio-flow-conditions.html
|
|
||||||
\nextpage studio-flow-external-events.html
|
|
||||||
|
|
||||||
\title Applying States in Flows
|
|
||||||
|
|
||||||
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 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
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-flow-external-events.html
|
|
||||||
\previouspage studio-flow-states.html
|
|
||||||
\nextpage quick-components.html
|
|
||||||
|
|
||||||
\title Reacting to External Events
|
|
||||||
|
|
||||||
On mobile and embedded platforms, applications are usually integrated into
|
|
||||||
the platform and therefore screens might pop-up from anywhere or at any
|
|
||||||
time, based on a conditional event. For example, push notifications
|
|
||||||
appear on mobile devices and incoming call screens on a car's HMI.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
To use wildcards:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Drag a \uicontrol {Flow Wildcard} component from
|
|
||||||
\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
|
|
||||||
|
|
||||||
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.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} 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.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
*/
|
|
@@ -247,11 +247,7 @@
|
|||||||
\li Wizard Template
|
\li Wizard Template
|
||||||
\li Purpose
|
\li Purpose
|
||||||
\row
|
\row
|
||||||
\li {1,5} Qt Quick Files
|
\li {1,4} Qt Quick Files
|
||||||
\li Flow Item and Flow View
|
|
||||||
\li Generate components that you can use to design the
|
|
||||||
\l{Designing Application Flows}{application flow}.
|
|
||||||
\row
|
|
||||||
\li Qt Quick File
|
\li Qt Quick File
|
||||||
\li Generates a component with one of the following default components
|
\li Generates a component with one of the following default components
|
||||||
or \l{Using Positioners}{positioners} as the root component:
|
or \l{Using Positioners}{positioners} as the root component:
|
||||||
|
@@ -29,7 +29,6 @@
|
|||||||
\li \l{Effect Composer}
|
\li \l{Effect Composer}
|
||||||
\li \l{File System}
|
\li \l{File System}
|
||||||
\li \l{Material Editor and Browser}
|
\li \l{Material Editor and Browser}
|
||||||
\li \l{Model Editor}
|
|
||||||
\li \l{Navigator}
|
\li \l{Navigator}
|
||||||
\li \l{Open Documents}
|
\li \l{Open Documents}
|
||||||
\li \l{Projects}
|
\li \l{Projects}
|
||||||
@@ -53,17 +52,6 @@
|
|||||||
\endlist
|
\endlist
|
||||||
\li \l{Wireframing}
|
\li \l{Wireframing}
|
||||||
\list
|
\list
|
||||||
\li \l{Designing Application Flows}
|
|
||||||
\list
|
|
||||||
\li \l{Adding Flow Views}
|
|
||||||
\li \l{Adding Flow Items}
|
|
||||||
\li \l{Adding Action Areas and Transitions}
|
|
||||||
\li \l{Applying Effects to Transitions}
|
|
||||||
\li \l{Simulating Events}
|
|
||||||
\li \l{Simulating Conditions}
|
|
||||||
\li \l{Applying States in Flows}
|
|
||||||
\li \l{Reacting to External Events}
|
|
||||||
\endlist
|
|
||||||
\li \l {Using Components}
|
\li \l {Using Components}
|
||||||
\list
|
\list
|
||||||
\li \l{Preset Components}
|
\li \l{Preset Components}
|
||||||
@@ -134,7 +122,6 @@
|
|||||||
\li\l{Connecting Components to Signals}
|
\li\l{Connecting Components to Signals}
|
||||||
\li\l{Adding Bindings Between Properties}
|
\li\l{Adding Bindings Between Properties}
|
||||||
\li\l{Specifying Custom Properties}
|
\li\l{Specifying Custom Properties}
|
||||||
\li\l{Connecting Properties to JSON Data Source}
|
|
||||||
\endlist
|
\endlist
|
||||||
\li \l{Working with States}
|
\li \l{Working with States}
|
||||||
\endlist
|
\endlist
|
||||||
|
@@ -48,8 +48,8 @@
|
|||||||
click-through mockup. Test, preview, and fine-tune your designs to pixel-perfection,
|
click-through mockup. Test, preview, and fine-tune your designs to pixel-perfection,
|
||||||
live on target devices.
|
live on target devices.
|
||||||
|
|
||||||
A single unified framework, one common language, fewer feedback loops, and faster iterations,
|
With a single unified framework, one common language, fewer feedback loops, and faster
|
||||||
\QDS closes the gap between designers and developers.
|
iterations, \QDS closes the gap between designers and developers.
|
||||||
|
|
||||||
\b {LEARN MORE}
|
\b {LEARN MORE}
|
||||||
|
|
||||||
@@ -87,11 +87,11 @@
|
|||||||
\endlist
|
\endlist
|
||||||
\li Online Courses
|
\li Online Courses
|
||||||
\list
|
\list
|
||||||
\li \l{https://qurious.qt.io/enrollments/197683855/details}{Getting Started}
|
\li \l{https://www.qt.io/academy/course-catalog#getting-started-with-qt-design-studio}{Getting Started}
|
||||||
\li \l{https://qurious.qt.io/catalog/courses/3910783}{Creating Your First App}
|
\li \l{https://www.qt.io/academy/course-catalog#creating-your-first-app-with-qt-design-studio}{Creating Your First App}
|
||||||
\li \l{https://qurious.qt.io/enrollments/154647839/details}{Introduction to 2D UI Design}
|
\li \l{https://www.qt.io/academy/course-catalog#2d-with-qt-design-studio}{2D with Qt Design Studio}
|
||||||
\li \l{https://qurious.qt.io/enrollments/167005403/details}{Introduction to 3D Design}
|
\li \l{https://www.qt.io/academy/course-catalog#3d-with-qt-design-studio}{3D with Qt Design Studio}
|
||||||
\li \l{https://qurious.qt.io/catalog/courses/3910791}{Using Qt Bridge for Figma}
|
\li \l{https://www.qt.io/academy/course-catalog#qt-design-studio:-blur-effect}{Creating a Blur Effect}
|
||||||
\endlist
|
\endlist
|
||||||
\endtable
|
\endtable
|
||||||
\enddiv
|
\enddiv
|
||||||
|
@@ -96,44 +96,75 @@
|
|||||||
\endlist
|
\endlist
|
||||||
\image repeater3d-numeric-model.webp
|
\image repeater3d-numeric-model.webp
|
||||||
|
|
||||||
\section1 Adding a Repeater3D Component with a Model
|
\section1 Adding a Repeater3D Component with a List Model
|
||||||
|
|
||||||
This section explains how to add a \uicontrol Repeater3D component with
|
This section explains how to add a \uicontrol Repeater3D component with
|
||||||
a model to your \QDS project:
|
a list model to your \QDS project:
|
||||||
|
|
||||||
To add a \uicontrol Repeater3D component:
|
To add a \uicontrol Repeater3D component:
|
||||||
|
|
||||||
\list 1
|
\list 1
|
||||||
\li Drag a \uicontrol Repeater3D component from \uicontrol Components to
|
\li Drag a \uicontrol Repeater3D component from \uicontrol Components to
|
||||||
\e scene in \uicontrol Navigator.
|
\e scene in \uicontrol Navigator.
|
||||||
\li Go to \uicontrol {Model Editor} and create a new model with the name
|
\li You need to enter the QML code for the \uicontrol ListModel manually.
|
||||||
\e planetModel.
|
Go to the \uicontrol {Code} view and enter the following code somewhere
|
||||||
\li Add the following columns and data to the model.
|
inside the root object:
|
||||||
\raw HTML
|
\code qml
|
||||||
<table>
|
ListModel {
|
||||||
<tr>
|
id: planetModel
|
||||||
<th>name (<i>String</i>)</th>
|
ListElement {
|
||||||
<th>radius (<i>Real</i>)</th>
|
name: "Mars"
|
||||||
</tr>
|
radius: 3.39
|
||||||
<tr>
|
}
|
||||||
<td>Mars</td>
|
ListElement {
|
||||||
<td>3.39</td>
|
name: "Earth"
|
||||||
</tr>
|
radius: 6.37
|
||||||
<tr>
|
}
|
||||||
<td>Earth</td>
|
ListElement {
|
||||||
<td>6.37</td>
|
name: "Venus"
|
||||||
</tr>
|
radius: 6.05
|
||||||
<tr>
|
}
|
||||||
<td>Venus</td>
|
}
|
||||||
<td>6.05</td>
|
\endcode
|
||||||
</tr>
|
The default root object for a \QDS project is \uicontrol Rectangle, so
|
||||||
</table>
|
you can paste the \uicontrol ListModel code, for example, like this:
|
||||||
\endraw
|
\code qml
|
||||||
\note You can also import a model in JSON or CSV format. See \l {Importing a Data Model}.
|
Rectangle {
|
||||||
\image repeater3d-model-editor.webp
|
width: Constants.width
|
||||||
\li In \uicontrol Navigator, select \e{_3DRepeater}.
|
height: Constants.height
|
||||||
\li In \uicontrol Properties, set \uicontrol Model to \e {DataStore.planetModel}.
|
color: Constants.backgroundColor
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: planetModel
|
||||||
|
ListElement {
|
||||||
|
name: "Mars"
|
||||||
|
radius: 3.39
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Earth"
|
||||||
|
radius: 6.37
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Venus"
|
||||||
|
radius: 6.05
|
||||||
|
}
|
||||||
|
}
|
||||||
|
View3D {
|
||||||
|
id: view3D
|
||||||
|
anchors.fill: parent
|
||||||
|
...
|
||||||
|
\endcode
|
||||||
|
\li In the \uicontrol {Code} view, add \c {model: planetModel} to the
|
||||||
|
\uicontrol Repeater3D object to tell that you want to use your
|
||||||
|
\uicontrol ListModel as the model for the \uicontrol Repeater3D object.
|
||||||
\endlist
|
\endlist
|
||||||
|
\code qml
|
||||||
|
Repeater3D {
|
||||||
|
id: repeater3D
|
||||||
|
model: planetModel
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
Now, you have set up the \uicontrol Repeater3D component to use a
|
Now, you have set up the \uicontrol Repeater3D component to use a
|
||||||
\uicontrol ListModel to draw the items. Next, you need to add the
|
\uicontrol ListModel to draw the items. Next, you need to add the
|
||||||
item to draw. In this example, you are using a \uicontrol Sphere.
|
item to draw. In this example, you are using a \uicontrol Sphere.
|
||||||
@@ -147,7 +178,7 @@
|
|||||||
next to \uicontrol Scale > \uicontrol X.
|
next to \uicontrol Scale > \uicontrol X.
|
||||||
\li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}.
|
\li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}.
|
||||||
\li In the binding editor, enter \c{radius}. This sets the X
|
\li In the binding editor, enter \c{radius}. This sets the X
|
||||||
scale to the radius value defined in the model for each of the sphere
|
scale to the radius value defined in the list model for each of the sphere
|
||||||
instances.
|
instances.
|
||||||
\image repeater3d-radius-binding.png
|
\image repeater3d-radius-binding.png
|
||||||
\li Select \uicontrol OK.
|
\li Select \uicontrol OK.
|
||||||
@@ -170,6 +201,6 @@
|
|||||||
result. You need to zoom out to see all the spheres.
|
result. You need to zoom out to see all the spheres.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\image repeater3d-list-model.webp
|
\image repeater3d-list-model.webp "Spheres in Repeater3D with a ListModel"
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@@ -1,63 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page quick-json-data-properties.html
|
|
||||||
\previouspage quick-dynamic-properties.html
|
|
||||||
\nextpage quick-states.html
|
|
||||||
|
|
||||||
\title Connecting Properties to JSON Data Source
|
|
||||||
|
|
||||||
Connect properties to data from a JSON file. You need two files in your project to do this:
|
|
||||||
|
|
||||||
\table
|
|
||||||
\row
|
|
||||||
\li \c {data.json}
|
|
||||||
\li A data file.
|
|
||||||
\row
|
|
||||||
\li \c {JsonData.qml}
|
|
||||||
\li A singleton that reads data from \c {data.json}.
|
|
||||||
\endtable
|
|
||||||
|
|
||||||
To create these files, you need to create a new data model:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li In \uicontrol {Model Editor}, select \inlineimage {icons/zoomIn.png}.
|
|
||||||
\li Select \uicontrol{Create}.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
The files are created in the \e {/imports/<projectName>/} folder of the project.
|
|
||||||
|
|
||||||
\section1 Connecting a Text Property to a Data Source
|
|
||||||
|
|
||||||
To connect a text property to a corresponding field in a JSON file:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li In the \uicontrol Navigator or \uicontrol 2D view, select a component
|
|
||||||
that has a text property, for example, a text field.
|
|
||||||
\li In the \uicontrol Connections view, go to the \uicontrol Bindings
|
|
||||||
tab.
|
|
||||||
\li Select \inlineimage {icons/plus.png}.
|
|
||||||
\li In the first \uicontrol From field, select \uicontrol {DataStore}, and in the second field,
|
|
||||||
select the JSON entry you want to use. In this example, \uicontrol {backend.name} is
|
|
||||||
selected. This corresponds to the \e name entry in \c {data.json}.
|
|
||||||
\li In the \uicontrol To field, ensure that \uicontrol text is selected.
|
|
||||||
\image json-text-binding.webp
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
Now, the text field is populated with data from the JSON file.
|
|
||||||
|
|
||||||
\section1 Adding Data Fields to the JSON File
|
|
||||||
|
|
||||||
If you add data fields to the JSON file, you need to manually do the same
|
|
||||||
updates to \c {JsonData.qml}.
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Go to the \uicontrol Projects view and open \c {JsonData.qml}.
|
|
||||||
\image project-jasondata.webp
|
|
||||||
\li In the \uicontrol Properties view, create a new local custom property.
|
|
||||||
\image json-new-property.webp
|
|
||||||
\li Ensure that the name of the property matches the data entry in the JSON file.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
*/
|
|
@@ -32,11 +32,6 @@
|
|||||||
can specify values for. You can add custom properties that would
|
can specify values for. You can add custom properties that would
|
||||||
not otherwise exist for a particular \l{Component Types}
|
not otherwise exist for a particular \l{Component Types}
|
||||||
{component type} or your custom components.
|
{component type} or your custom components.
|
||||||
|
|
||||||
\li \l{Connecting Properties to JSON Data Source}
|
|
||||||
|
|
||||||
You can add bindings between properties and data from a JSON file.
|
|
||||||
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
For an example of using properties, bindings, and connections to create a
|
For an example of using properties, bindings, and connections to create a
|
||||||
|
@@ -1,62 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page studio-model-editor.html
|
|
||||||
\previouspage qtquick-effect-composer-view.html
|
|
||||||
\nextpage creator-project-managing-workspaces.html
|
|
||||||
|
|
||||||
\ingroup studio-views
|
|
||||||
|
|
||||||
\title Model Editor
|
|
||||||
|
|
||||||
\brief Create, manage, import, and export data models.
|
|
||||||
|
|
||||||
In the \uicontrol {Model Editor} view, you can create, manage, import, and export
|
|
||||||
data models. With data models, you can, for example, populate views with data.
|
|
||||||
|
|
||||||
\image edit-list-model-model-editor.webp
|
|
||||||
|
|
||||||
For examples of how to use data models, see
|
|
||||||
\l {Adding a Repeater3D Component with a Model}.
|
|
||||||
|
|
||||||
\section1 Creating a Data Model
|
|
||||||
|
|
||||||
To create a data model:
|
|
||||||
\list 1
|
|
||||||
\li In \uicontrol {Model Editor}, select \inlineimage {icons/zoomIn.png}.
|
|
||||||
\li Enter a name and select \uicontrol {Create}.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
This creates a single-cell table.
|
|
||||||
|
|
||||||
\image model-editor-new-model.webp
|
|
||||||
|
|
||||||
Next, add columns, rows, and data to the model.
|
|
||||||
|
|
||||||
\note You must manually save the table after you have made changes. To do this,
|
|
||||||
select \inlineimage {icons/save-effect-composer.png}.
|
|
||||||
|
|
||||||
\section1 Editing a Data Model
|
|
||||||
|
|
||||||
Edit a data model in one of the following ways:
|
|
||||||
\list
|
|
||||||
\li Right-click a column name to edit its name and type, delete, or sort it.
|
|
||||||
\li Double-click a cell to edit its content.
|
|
||||||
\li Use the toolbar to add and remove columns and rows.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\note You must manually save the table after you have made changes. To do this,
|
|
||||||
select \inlineimage {icons/save-effect-composer.png}.
|
|
||||||
|
|
||||||
\section1 Importing a Data Model
|
|
||||||
|
|
||||||
Import data models from JSON or CSV files. To do this, select \inlineimage {icons/import.png}
|
|
||||||
in \uicontrol {Model Editor}.
|
|
||||||
|
|
||||||
\section1 Exporting a Data Model
|
|
||||||
|
|
||||||
Export data models to JSON or CSV files. To do this, select \inlineimage {icons/export.png}
|
|
||||||
in \uicontrol {Model Editor}.
|
|
||||||
|
|
||||||
*/
|
|
@@ -14,6 +14,7 @@
|
|||||||
\section2 \QDS 4
|
\section2 \QDS 4
|
||||||
|
|
||||||
\list
|
\list
|
||||||
|
\li \l{Qt Design Studio 4.6 released}
|
||||||
\li \l{Qt Design Studio 4.5.1 released}
|
\li \l{Qt Design Studio 4.5.1 released}
|
||||||
\li \l{Qt Design Studio 4.5 released}
|
\li \l{Qt Design Studio 4.5 released}
|
||||||
\li \l{Qt Design Studio 4.4 released}
|
\li \l{Qt Design Studio 4.4 released}
|
||||||
|
@@ -101,7 +101,7 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (assetsModel.hasFiles) {
|
if (!assetsModel.isEmpty) {
|
||||||
function onFolderCreated(path) {
|
function onFolderCreated(path) {
|
||||||
assetsView.addCreatedFolder(path)
|
assetsView.addCreatedFolder(path)
|
||||||
}
|
}
|
||||||
@@ -189,13 +189,13 @@ Item {
|
|||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: StudioTheme.Values.baseFont
|
font.pixelSize: StudioTheme.Values.baseFont
|
||||||
visible: !assetsModel.hasFiles && !root.__searchBoxEmpty
|
visible: assetsModel.isEmpty && !root.__searchBoxEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // placeholder when the assets library is empty
|
Item { // placeholder when the assets library is empty
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - toolbar.height - column.spacing
|
height: parent.height - toolbar.height - column.spacing
|
||||||
visible: !assetsModel.hasFiles && root.__searchBoxEmpty
|
visible: assetsModel.isEmpty && root.__searchBoxEmpty
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
MouseArea { // right clicking the empty area of the view
|
MouseArea { // right clicking the empty area of the view
|
||||||
|
@@ -192,7 +192,7 @@ StudioControls.Menu {
|
|||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("New Folder")
|
text: qsTr("New Folder")
|
||||||
visible: root.assetsModel.hasFiles
|
visible: !root.assetsModel.isEmpty
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
|
|
||||||
NewFolderDialog {
|
NewFolderDialog {
|
||||||
|
@@ -70,9 +70,9 @@ TreeView {
|
|||||||
model: assetsModel
|
model: assetsModel
|
||||||
|
|
||||||
onRowsChanged: {
|
onRowsChanged: {
|
||||||
if (root.rows > root.rootPathRow + 1 && !assetsModel.hasFiles ||
|
if (root.rows > root.rootPathRow + 1 && assetsModel.isEmpty ||
|
||||||
root.rows <= root.rootPathRow + 1 && assetsModel.hasFiles) {
|
root.rows <= root.rootPathRow + 1 && !assetsModel.isEmpty) {
|
||||||
assetsModel.syncHasFiles()
|
assetsModel.syncIsEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
root.updateRows()
|
root.updateRows()
|
||||||
@@ -328,7 +328,7 @@ TreeView {
|
|||||||
|
|
||||||
function moveSelection(amount)
|
function moveSelection(amount)
|
||||||
{
|
{
|
||||||
if (!assetsModel.hasFiles || !amount)
|
if (assetsModel.isEmpty || !amount)
|
||||||
return
|
return
|
||||||
|
|
||||||
let index = root.currentFilePath ? assetsModel.indexForPath(root.currentFilePath)
|
let index = root.currentFilePath ? assetsModel.indexForPath(root.currentFilePath)
|
||||||
|
@@ -133,6 +133,8 @@ HelperWidgets.ScrollView {
|
|||||||
topPadding: 10
|
topPadding: 10
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
visible: root.materialsModel.isEmpty
|
visible: root.materialsModel.isEmpty
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: root.width - x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,11 +2,12 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
import HelperWidgets 2.0 as HelperWidgets
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
import StudioControls 1.0 as StudioControls
|
import StudioControls 1.0 as StudioControls
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property int currIndex: 0
|
property int currIndex: 0
|
||||||
@@ -24,6 +25,7 @@ Row {
|
|||||||
icon: modelData.icon
|
icon: modelData.icon
|
||||||
selected: root.currIndex === index
|
selected: root.currIndex === index
|
||||||
onClicked: root.currIndex = index
|
onClicked: root.currIndex = index
|
||||||
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
import HelperWidgets 2.0 as HelperWidgets
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
import StudioControls 1.0 as StudioControls
|
import StudioControls 1.0 as StudioControls
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme 1.0 as StudioTheme
|
||||||
@@ -16,7 +17,6 @@ Rectangle {
|
|||||||
property bool selected: false
|
property bool selected: false
|
||||||
|
|
||||||
height: button.height
|
height: button.height
|
||||||
width: button.width + label.width + contentRow.spacing + 6
|
|
||||||
color: StudioTheme.Values.themeToolbarBackground
|
color: StudioTheme.Values.themeToolbarBackground
|
||||||
radius: StudioTheme.Values.smallRadius
|
radius: StudioTheme.Values.smallRadius
|
||||||
|
|
||||||
@@ -43,9 +43,9 @@ Rectangle {
|
|||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
text: qsTr("Materials")
|
text: qsTr("Materials")
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
width: root.width - x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +56,12 @@ Rectangle {
|
|||||||
onClicked: root.clicked()
|
onClicked: root.clicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StudioControls.ToolTip {
|
||||||
|
visible: mouseArea.containsMouse
|
||||||
|
text: label.text
|
||||||
|
delay: 1000
|
||||||
|
}
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "default"
|
name: "default"
|
||||||
|
@@ -241,6 +241,9 @@
|
|||||||
"LocalOrientIcon": {
|
"LocalOrientIcon": {
|
||||||
"iconName": "localOrient_medium"
|
"iconName": "localOrient_medium"
|
||||||
},
|
},
|
||||||
|
"LiveUpdateIcon": {
|
||||||
|
"iconName": "restartParticles_medium"
|
||||||
|
},
|
||||||
"MoveToolIcon": {
|
"MoveToolIcon": {
|
||||||
"iconName": "move_medium"
|
"iconName": "move_medium"
|
||||||
},
|
},
|
||||||
@@ -276,6 +279,9 @@
|
|||||||
"SplitViewIcon": {
|
"SplitViewIcon": {
|
||||||
"iconName": "splitScreen_medium"
|
"iconName": "splitScreen_medium"
|
||||||
},
|
},
|
||||||
|
"SyncIcon": {
|
||||||
|
"iconName": "updateContent_medium"
|
||||||
|
},
|
||||||
"ToggleGroupIcon": {
|
"ToggleGroupIcon": {
|
||||||
"Off": {
|
"Off": {
|
||||||
"iconName": "selectOutline_medium"
|
"iconName": "selectOutline_medium"
|
||||||
|
@@ -195,6 +195,10 @@ Item {
|
|||||||
onAssignToSelectedClicked: {
|
onAssignToSelectedClicked: {
|
||||||
root.backendModel.assignToSelected()
|
root.backendModel.assignToSelected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOpenShadersCodeEditor: {
|
||||||
|
root.backendModel.openMainShadersCodeEditor()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitView {
|
SplitView {
|
||||||
@@ -366,6 +370,8 @@ Item {
|
|||||||
expanded = wasExpanded
|
expanded = wasExpanded
|
||||||
dragAnimation.enabled = true
|
dragAnimation.enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOpenShadersCodeEditor: (idx) => root.backendModel.openShadersCodeEditor(idx)
|
||||||
}
|
}
|
||||||
} // Repeater
|
} // Repeater
|
||||||
} // Column
|
} // Column
|
||||||
|
@@ -19,6 +19,7 @@ Rectangle {
|
|||||||
signal saveClicked
|
signal saveClicked
|
||||||
signal saveAsClicked
|
signal saveAsClicked
|
||||||
signal assignToSelectedClicked
|
signal assignToSelectedClicked
|
||||||
|
signal openShadersCodeEditor
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: 5
|
spacing: 5
|
||||||
@@ -48,12 +49,24 @@ Rectangle {
|
|||||||
style: StudioTheme.Values.viewBarButtonStyle
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.saveAs_medium
|
buttonIcon: StudioTheme.Constants.saveAs_medium
|
||||||
tooltip: qsTr("Save current composition with a new name")
|
tooltip: qsTr("Save current composition with a new name")
|
||||||
enabled: root.backendModel ? root.backendModel.isEnabled && root.backendModel.currentComposition !== ""
|
enabled: root.backendModel ? root.backendModel.isEnabled
|
||||||
|
&& root.backendModel.currentComposition !== ""
|
||||||
: false
|
: false
|
||||||
|
|
||||||
onClicked: root.saveAsClicked()
|
onClicked: root.saveAsClicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HelperWidgets.AbstractButton {
|
||||||
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
|
buttonIcon: StudioTheme.Constants.codeEditor_medium
|
||||||
|
tooltip: qsTr("Open Code")
|
||||||
|
enabled: root.backendModel ? root.backendModel.isEnabled
|
||||||
|
&& root.backendModel.currentComposition !== ""
|
||||||
|
: false
|
||||||
|
|
||||||
|
onClicked: root.openShadersCodeEditor()
|
||||||
|
}
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.assignTo_medium
|
buttonIcon: StudioTheme.Constants.assignTo_medium
|
||||||
|
@@ -30,10 +30,34 @@ HelperWidgets.Section {
|
|||||||
eyeEnabled: nodeEnabled
|
eyeEnabled: nodeEnabled
|
||||||
eyeButtonToolTip: qsTr("Enable/Disable Node")
|
eyeButtonToolTip: qsTr("Enable/Disable Node")
|
||||||
|
|
||||||
|
signal openShadersCodeEditor(index: int)
|
||||||
|
|
||||||
onEyeButtonClicked: {
|
onEyeButtonClicked: {
|
||||||
nodeEnabled = root.eyeEnabled
|
nodeEnabled = root.eyeEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icons: HelperWidgets.IconButton {
|
||||||
|
icon: StudioTheme.Constants.codeEditor_medium
|
||||||
|
transparentBg: true
|
||||||
|
buttonSize: 21
|
||||||
|
iconSize: StudioTheme.Values.smallIconFontSize
|
||||||
|
iconColor: StudioTheme.Values.themeTextColor
|
||||||
|
iconScale: containsMouse ? 1.2 : 1
|
||||||
|
implicitWidth: width
|
||||||
|
onClicked: root.openShadersCodeEditor(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
content: Label {
|
||||||
|
text: root.caption
|
||||||
|
color: root.labelColor
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pixelSize: root.sectionFontSize
|
||||||
|
font.capitalization: root.labelCapitalization
|
||||||
|
anchors.verticalCenter: parent?.verticalCenter
|
||||||
|
textFormat: Text.RichText
|
||||||
|
leftPadding: StudioTheme.Values.toolbarSpacing
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Controls.impl
|
||||||
import HelperWidgets
|
import HelperWidgets
|
||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
@@ -22,12 +22,17 @@ StudioControls.ComboBox {
|
|||||||
|
|
||||||
required property Item mainRoot
|
required property Item mainRoot
|
||||||
|
|
||||||
property var images: ["images/preview0.png",
|
property var images: [Qt.url(""),
|
||||||
"images/preview1.png",
|
Qt.url("images/preview0.png"),
|
||||||
"images/preview2.png",
|
Qt.url("images/preview1.png"),
|
||||||
"images/preview3.png",
|
Qt.url("images/preview2.png"),
|
||||||
"images/preview4.png"]
|
Qt.url("images/preview3.png"),
|
||||||
property string selectedImage: images[0]
|
Qt.url("images/preview4.png")]
|
||||||
|
property url selectedImage: EffectComposerBackend.effectComposerModel.currentPreviewImage != Qt.url("")
|
||||||
|
? EffectComposerBackend.effectComposerModel.currentPreviewImage
|
||||||
|
: images[1]
|
||||||
|
|
||||||
|
Component.onCompleted: EffectComposerBackend.effectComposerModel.currentPreviewImage = images[1]
|
||||||
|
|
||||||
readonly property int popupHeight: Math.min(800, col.height + 2)
|
readonly property int popupHeight: Math.min(800, col.height + 2)
|
||||||
|
|
||||||
@@ -122,45 +127,80 @@ StudioControls.ComboBox {
|
|||||||
border.width: 1
|
border.width: 1
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
HelperWidgets.ScrollView {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 1
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
Column {
|
Item {
|
||||||
id: col
|
id: setCustomItem
|
||||||
|
width: parent.width
|
||||||
|
height: 50
|
||||||
|
|
||||||
padding: 10
|
HelperWidgets.Button {
|
||||||
spacing: 10
|
anchors.fill: parent
|
||||||
|
anchors.bottomMargin: 2
|
||||||
|
anchors.topMargin: col.padding
|
||||||
|
anchors.leftMargin: col.padding
|
||||||
|
anchors.rightMargin: col.padding
|
||||||
|
text: qsTr("Set Custom Image")
|
||||||
|
onClicked: {
|
||||||
|
EffectComposerBackend.effectComposerModel.chooseCustomPreviewImage()
|
||||||
|
root.popup.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: root.images
|
|
||||||
|
|
||||||
Rectangle {
|
HelperWidgets.ScrollView {
|
||||||
required property int index
|
width: parent.width - 2
|
||||||
required property var modelData
|
height: parent.height - setCustomItem.height
|
||||||
|
|
||||||
color: "transparent"
|
clip: true
|
||||||
border.color: root.selectedImage === modelData ? StudioTheme.Values.themeInteraction
|
|
||||||
: "transparent"
|
|
||||||
|
|
||||||
width: 200
|
Column {
|
||||||
height: 200
|
id: col
|
||||||
|
|
||||||
Image {
|
padding: 10
|
||||||
source: modelData
|
spacing: 10
|
||||||
anchors.fill: parent
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
smooth: true
|
|
||||||
anchors.margins: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
Repeater {
|
||||||
anchors.fill: parent
|
model: root.images
|
||||||
|
|
||||||
onClicked: {
|
Rectangle {
|
||||||
root.selectedImage = root.images[index]
|
required property int index
|
||||||
root.popup.close()
|
required property var modelData
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
border.color: root.selectedImage === modelData ? StudioTheme.Values.themeInteraction
|
||||||
|
: "transparent"
|
||||||
|
|
||||||
|
width: 200
|
||||||
|
height: 200
|
||||||
|
visible: index > 0
|
||||||
|
|| EffectComposerBackend.effectComposerModel.customPreviewImage !== Qt.url("")
|
||||||
|
|
||||||
|
Image {
|
||||||
|
source: index > 0
|
||||||
|
? parent.modelData
|
||||||
|
: EffectComposerBackend.effectComposerModel.customPreviewImage
|
||||||
|
anchors.fill: parent
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
smooth: true
|
||||||
|
anchors.margins: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (parent.index > 0) {
|
||||||
|
EffectComposerBackend.effectComposerModel.currentPreviewImage
|
||||||
|
= root.images[index]
|
||||||
|
} else {
|
||||||
|
EffectComposerBackend.effectComposerModel.currentPreviewImage
|
||||||
|
= EffectComposerBackend.effectComposerModel.customPreviewImage
|
||||||
|
}
|
||||||
|
root.popup.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -391,6 +391,21 @@ Item {
|
|||||||
visible: BackendApi.haveVirtualKeyboard
|
visible: BackendApi.haveVirtualKeyboard
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StudioControls.CheckBox {
|
||||||
|
id: enableCMakeGeneration
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
text: qsTr("Enable Cmake Generation")
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
checked: BackendApi.enableCMakeGeneration
|
||||||
|
visible: BackendApi.hasCMakeGeneration
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: BackendApi
|
||||||
|
property: "enableCMakeGeneration"
|
||||||
|
value: enableCMakeGeneration.checked
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout { // Target Qt Version
|
RowLayout { // Target Qt Version
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: BackendApi.haveTargetQtVersion
|
visible: BackendApi.haveTargetQtVersion
|
||||||
|
@@ -39,6 +39,8 @@ Item {
|
|||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property Item icons
|
||||||
|
|
||||||
property int leftPadding: StudioTheme.Values.sectionLeftPadding
|
property int leftPadding: StudioTheme.Values.sectionLeftPadding
|
||||||
property int rightPadding: 0
|
property int rightPadding: 0
|
||||||
property int topPadding: StudioTheme.Values.sectionHeadSpacerHeight
|
property int topPadding: StudioTheme.Values.sectionHeadSpacerHeight
|
||||||
@@ -214,6 +216,13 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: iconsContent
|
||||||
|
height: header.height
|
||||||
|
children: [ section.icons ]
|
||||||
|
Layout.preferredWidth: childrenRect.width
|
||||||
|
}
|
||||||
|
|
||||||
IconButton {
|
IconButton {
|
||||||
id: arrow
|
id: arrow
|
||||||
icon: StudioTheme.Constants.sectionToggle
|
icon: StudioTheme.Constants.sectionToggle
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
|
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
|
||||||
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
|
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
|
||||||
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
|
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
|
||||||
|
{ "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" },
|
||||||
{ "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" }
|
{ "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" }
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -208,6 +209,15 @@
|
|||||||
"checked": "%{UseVirtualKeyboardDefault}"
|
"checked": "%{UseVirtualKeyboardDefault}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "EnableCMakeGeneration",
|
||||||
|
"trDisplayName": "Enable CMake Genertion",
|
||||||
|
"type": "CheckBox",
|
||||||
|
"data":
|
||||||
|
{
|
||||||
|
"checked": "%{EnableCMakeGenerationDefault}"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "CustomScreenWidth",
|
"name": "CustomScreenWidth",
|
||||||
"trDisplayName": "Custom screen width:",
|
"trDisplayName": "Custom screen width:",
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
|
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
|
||||||
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
|
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
|
||||||
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
|
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
|
||||||
|
{ "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" },
|
||||||
{ "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" }
|
{ "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" }
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -208,6 +209,15 @@
|
|||||||
"checked": "%{UseVirtualKeyboardDefault}"
|
"checked": "%{UseVirtualKeyboardDefault}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "EnableCMakeGeneration",
|
||||||
|
"trDisplayName": "Enable CMake Genertion",
|
||||||
|
"type": "CheckBox",
|
||||||
|
"data":
|
||||||
|
{
|
||||||
|
"checked": "%{EnableCMakeGenerationDefault}"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "CustomScreenWidth",
|
"name": "CustomScreenWidth",
|
||||||
"trDisplayName": "Custom screen width:",
|
"trDisplayName": "Custom screen width:",
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
|
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
|
||||||
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
|
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
|
||||||
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
|
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
|
||||||
|
{ "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" },
|
||||||
{ "key": "DefaultStyle", "value": "Basic" }
|
{ "key": "DefaultStyle", "value": "Basic" }
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -207,6 +208,15 @@
|
|||||||
"checked": "%{UseVirtualKeyboardDefault}"
|
"checked": "%{UseVirtualKeyboardDefault}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "EnableCMakeGeneration",
|
||||||
|
"trDisplayName": "Enable CMake Genertion",
|
||||||
|
"type": "CheckBox",
|
||||||
|
"data":
|
||||||
|
{
|
||||||
|
"checked": "%{EnableCMakeGenerationDefault}"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "CustomScreenWidth",
|
"name": "CustomScreenWidth",
|
||||||
"trDisplayName": "Custom screen width:",
|
"trDisplayName": "Custom screen width:",
|
||||||
|
@@ -22,7 +22,7 @@ Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JavaScriptFiles {
|
JavaScriptFiles {
|
||||||
directory: "%{ProjectName}"
|
directory: "%{ContentDir}"
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageFiles {
|
ImageFiles {
|
||||||
@@ -103,6 +103,10 @@ Project {
|
|||||||
/* Required for deployment */
|
/* Required for deployment */
|
||||||
targetDirectory: "/opt/%{ProjectName}"
|
targetDirectory: "/opt/%{ProjectName}"
|
||||||
|
|
||||||
|
@if %{EnableCMakeGeneration}
|
||||||
|
enableCMakeGeneration: true
|
||||||
|
@endif
|
||||||
|
|
||||||
qdsVersion: "4.6"
|
qdsVersion: "4.6"
|
||||||
|
|
||||||
quickVersion: "%{QtQuickVersion}"
|
quickVersion: "%{QtQuickVersion}"
|
||||||
|
@@ -32,6 +32,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
visible: !Constants.projectModel.liteDesignerEnabled
|
||||||
id: brandLabel
|
id: brandLabel
|
||||||
color: Constants.currentBrand
|
color: Constants.currentBrand
|
||||||
text: qsTr("Qt Design Studio")
|
text: qsTr("Qt Design Studio")
|
||||||
@@ -44,6 +45,20 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
visible: Constants.projectModel.liteDesignerEnabled
|
||||||
|
id: brandLabelLite
|
||||||
|
color: Constants.currentBrand
|
||||||
|
text: qsTr("Lite QML Designer")
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: welcomeTo.right
|
||||||
|
anchors.leftMargin: 8
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
font.pixelSize: 36
|
||||||
|
font.family: "titillium web"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: !Constants.projectModel.liteDesignerEnabled
|
||||||
width: 291
|
width: 291
|
||||||
height: 55
|
height: 55
|
||||||
color: Constants.currentGlobalText
|
color: Constants.currentGlobalText
|
||||||
|
@@ -56,6 +56,8 @@ using namespace Utils;
|
|||||||
namespace Core {
|
namespace Core {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
bool optionsPageLessThan(const IOptionsPage *p1, const IOptionsPage *p2)
|
bool optionsPageLessThan(const IOptionsPage *p1, const IOptionsPage *p2)
|
||||||
{
|
{
|
||||||
if (p1->category() != p2->category())
|
if (p1->category() != p2->category())
|
||||||
@@ -127,7 +129,7 @@ CategoryModel::~CategoryModel()
|
|||||||
|
|
||||||
int CategoryModel::rowCount(const QModelIndex &parent) const
|
int CategoryModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : m_categories.size();
|
return parent.isValid() ? 0 : static_cast<int>(m_categories.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant CategoryModel::data(const QModelIndex &index, int role) const
|
QVariant CategoryModel::data(const QModelIndex &index, int role) const
|
||||||
@@ -249,7 +251,7 @@ protected:
|
|||||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool categoryVisible(const Id &id)
|
static bool categoryVisible([[maybe_unused]] const Id &id)
|
||||||
{
|
{
|
||||||
#ifdef QT_NO_DEBUG
|
#ifdef QT_NO_DEBUG
|
||||||
|
|
||||||
@@ -806,6 +808,8 @@ bool SettingsDialog::execDialog()
|
|||||||
return m_applied;
|
return m_applied;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
bool executeSettingsDialog(QWidget *parent, Id initialPage)
|
bool executeSettingsDialog(QWidget *parent, Id initialPage)
|
||||||
{
|
{
|
||||||
if (!ExtensionSystem::PluginManager::isInitializationDone()) {
|
if (!ExtensionSystem::PluginManager::isInitializationDone()) {
|
||||||
|
@@ -6,12 +6,14 @@ add_qtc_plugin(EffectComposer
|
|||||||
Qt::Core Qt::CorePrivate Qt::Widgets Qt::Qml Qt::QmlPrivate Qt::Quick
|
Qt::Core Qt::CorePrivate Qt::Widgets Qt::Qml Qt::QmlPrivate Qt::Quick
|
||||||
QtCreator::Utils
|
QtCreator::Utils
|
||||||
SOURCES
|
SOURCES
|
||||||
|
effectcodeeditorwidget.cpp effectcodeeditorwidget.h
|
||||||
effectcomposerplugin.cpp
|
effectcomposerplugin.cpp
|
||||||
effectcomposerwidget.cpp effectcomposerwidget.h
|
effectcomposerwidget.cpp effectcomposerwidget.h
|
||||||
effectcomposerview.cpp effectcomposerview.h
|
effectcomposerview.cpp effectcomposerview.h
|
||||||
effectcomposermodel.cpp effectcomposermodel.h
|
effectcomposermodel.cpp effectcomposermodel.h
|
||||||
effectcomposernodesmodel.cpp effectcomposernodesmodel.h
|
effectcomposernodesmodel.cpp effectcomposernodesmodel.h
|
||||||
effectcomposeruniformsmodel.cpp effectcomposeruniformsmodel.h
|
effectcomposeruniformsmodel.cpp effectcomposeruniformsmodel.h
|
||||||
|
effectshaderscodeeditor.cpp effectshaderscodeeditor.h
|
||||||
effectnode.cpp effectnode.h
|
effectnode.cpp effectnode.h
|
||||||
effectnodescategory.cpp effectnodescategory.h
|
effectnodescategory.cpp effectnodescategory.h
|
||||||
compositionnode.cpp compositionnode.h
|
compositionnode.cpp compositionnode.h
|
||||||
|
@@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
#include "compositionnode.h"
|
#include "compositionnode.h"
|
||||||
|
|
||||||
#include "effectutils.h"
|
|
||||||
#include "effectcomposeruniformsmodel.h"
|
#include "effectcomposeruniformsmodel.h"
|
||||||
|
#include "effectshaderscodeeditor.h"
|
||||||
|
#include "effectutils.h"
|
||||||
#include "propertyhandler.h"
|
#include "propertyhandler.h"
|
||||||
#include "uniform.h"
|
#include "uniform.h"
|
||||||
|
|
||||||
@@ -44,6 +45,8 @@ CompositionNode::CompositionNode(const QString &effectName, const QString &qenPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompositionNode::~CompositionNode() = default;
|
||||||
|
|
||||||
QString CompositionNode::fragmentCode() const
|
QString CompositionNode::fragmentCode() const
|
||||||
{
|
{
|
||||||
return m_fragmentCode;
|
return m_fragmentCode;
|
||||||
@@ -110,8 +113,8 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c
|
|||||||
|
|
||||||
m_name = json.value("name").toString();
|
m_name = json.value("name").toString();
|
||||||
m_description = json.value("description").toString();
|
m_description = json.value("description").toString();
|
||||||
m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray());
|
setFragmentCode(EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray()));
|
||||||
m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray());
|
setVertexCode(EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray()));
|
||||||
|
|
||||||
if (json.contains("extraMargin"))
|
if (json.contains("extraMargin"))
|
||||||
m_extraMargin = json.value("extraMargin").toInt();
|
m_extraMargin = json.value("extraMargin").toInt();
|
||||||
@@ -154,6 +157,36 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompositionNode::ensureShadersCodeEditor()
|
||||||
|
{
|
||||||
|
if (m_shadersCodeEditor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr<EffectShadersCodeEditor>(name());
|
||||||
|
m_shadersCodeEditor->setFragmentValue(fragmentCode());
|
||||||
|
m_shadersCodeEditor->setVertexValue(vertexCode());
|
||||||
|
|
||||||
|
connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] {
|
||||||
|
setVertexCode(m_shadersCodeEditor->vertexValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] {
|
||||||
|
setFragmentCode(m_shadersCodeEditor->fragmentValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(
|
||||||
|
m_shadersCodeEditor.get(),
|
||||||
|
&EffectShadersCodeEditor::rebakeRequested,
|
||||||
|
this,
|
||||||
|
&CompositionNode::rebakeRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompositionNode::requestRebakeIfLiveUpdateMode()
|
||||||
|
{
|
||||||
|
if (m_shadersCodeEditor && m_shadersCodeEditor->liveUpdate())
|
||||||
|
emit rebakeRequested();
|
||||||
|
}
|
||||||
|
|
||||||
QList<Uniform *> CompositionNode::uniforms() const
|
QList<Uniform *> CompositionNode::uniforms() const
|
||||||
{
|
{
|
||||||
return m_uniforms;
|
return m_uniforms;
|
||||||
@@ -189,6 +222,34 @@ void CompositionNode::setRefCount(int count)
|
|||||||
emit isDepencyChanged();
|
emit isDepencyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompositionNode::setFragmentCode(const QString &fragmentCode)
|
||||||
|
{
|
||||||
|
if (m_fragmentCode == fragmentCode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_fragmentCode = fragmentCode;
|
||||||
|
emit fragmentCodeChanged();
|
||||||
|
|
||||||
|
requestRebakeIfLiveUpdateMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompositionNode::setVertexCode(const QString &vertexCode)
|
||||||
|
{
|
||||||
|
if (m_vertexCode == vertexCode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_vertexCode = vertexCode;
|
||||||
|
emit vertexCodeChanged();
|
||||||
|
|
||||||
|
requestRebakeIfLiveUpdateMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompositionNode::openShadersCodeEditor()
|
||||||
|
{
|
||||||
|
ensureShadersCodeEditor();
|
||||||
|
m_shadersCodeEditor->showWidget();
|
||||||
|
}
|
||||||
|
|
||||||
QString CompositionNode::name() const
|
QString CompositionNode::name() const
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
|
@@ -5,11 +5,15 @@
|
|||||||
|
|
||||||
#include "effectcomposeruniformsmodel.h"
|
#include "effectcomposeruniformsmodel.h"
|
||||||
|
|
||||||
|
#include <utils/uniqueobjectptr.h>
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
namespace EffectComposer {
|
namespace EffectComposer {
|
||||||
|
|
||||||
|
class EffectShadersCodeEditor;
|
||||||
|
|
||||||
class CompositionNode : public QObject
|
class CompositionNode : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -18,6 +22,12 @@ class CompositionNode : public QObject
|
|||||||
Q_PROPERTY(bool nodeEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged)
|
Q_PROPERTY(bool nodeEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged)
|
||||||
Q_PROPERTY(bool isDependency READ isDependency NOTIFY isDepencyChanged)
|
Q_PROPERTY(bool isDependency READ isDependency NOTIFY isDepencyChanged)
|
||||||
Q_PROPERTY(QObject *nodeUniformsModel READ uniformsModel NOTIFY uniformsModelChanged)
|
Q_PROPERTY(QObject *nodeUniformsModel READ uniformsModel NOTIFY uniformsModelChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
QString fragmentCode
|
||||||
|
READ fragmentCode
|
||||||
|
WRITE setFragmentCode
|
||||||
|
NOTIFY fragmentCodeChanged)
|
||||||
|
Q_PROPERTY(QString vertexCode READ vertexCode WRITE setVertexCode NOTIFY vertexCodeChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum NodeType {
|
enum NodeType {
|
||||||
@@ -27,6 +37,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
CompositionNode(const QString &effectName, const QString &qenPath, const QJsonObject &json = {});
|
CompositionNode(const QString &effectName, const QString &qenPath, const QJsonObject &json = {});
|
||||||
|
virtual ~CompositionNode();
|
||||||
|
|
||||||
QString fragmentCode() const;
|
QString fragmentCode() const;
|
||||||
QString vertexCode() const;
|
QString vertexCode() const;
|
||||||
@@ -54,14 +65,23 @@ public:
|
|||||||
|
|
||||||
int extraMargin() const { return m_extraMargin; }
|
int extraMargin() const { return m_extraMargin; }
|
||||||
|
|
||||||
|
void setFragmentCode(const QString &fragmentCode);
|
||||||
|
void setVertexCode(const QString &vertexCode);
|
||||||
|
|
||||||
|
void openShadersCodeEditor();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void uniformsModelChanged();
|
void uniformsModelChanged();
|
||||||
void isEnabledChanged();
|
void isEnabledChanged();
|
||||||
void isDepencyChanged();
|
void isDepencyChanged();
|
||||||
void rebakeRequested();
|
void rebakeRequested();
|
||||||
|
void fragmentCodeChanged();
|
||||||
|
void vertexCodeChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parse(const QString &effectName, const QString &qenPath, const QJsonObject &json);
|
void parse(const QString &effectName, const QString &qenPath, const QJsonObject &json);
|
||||||
|
void ensureShadersCodeEditor();
|
||||||
|
void requestRebakeIfLiveUpdateMode();
|
||||||
|
|
||||||
QString m_name;
|
QString m_name;
|
||||||
NodeType m_type = CustomNode;
|
NodeType m_type = CustomNode;
|
||||||
@@ -77,6 +97,7 @@ private:
|
|||||||
QList<Uniform *> m_uniforms;
|
QList<Uniform *> m_uniforms;
|
||||||
|
|
||||||
EffectComposerUniformsModel m_unifomrsModel;
|
EffectComposerUniformsModel m_unifomrsModel;
|
||||||
|
Utils::UniqueObjectLatePtr<EffectShadersCodeEditor> m_shadersCodeEditor;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace EffectComposer
|
} // namespace EffectComposer
|
||||||
|
142
src/plugins/effectcomposer/effectcodeeditorwidget.cpp
Normal file
142
src/plugins/effectcomposer/effectcodeeditorwidget.cpp
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "effectcodeeditorwidget.h"
|
||||||
|
|
||||||
|
#include <qmldesigner/textmodifier/indentingtexteditormodifier.h>
|
||||||
|
|
||||||
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
|
#include <coreplugin/coreplugintr.h>
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
|
#include <qmljseditor/qmljsautocompleter.h>
|
||||||
|
#include <qmljseditor/qmljscompletionassist.h>
|
||||||
|
#include <qmljseditor/qmljshighlighter.h>
|
||||||
|
#include <qmljseditor/qmljshoverhandler.h>
|
||||||
|
#include <qmljseditor/qmljssemantichighlighter.h>
|
||||||
|
|
||||||
|
#include <qmljstools/qmljsindenter.h>
|
||||||
|
|
||||||
|
#include <utils/mimeconstants.h>
|
||||||
|
#include <utils/transientscroll.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
|
namespace EffectComposer {
|
||||||
|
|
||||||
|
constexpr char EFFECTEDITOR_CONTEXT_ID[] = "EffectEditor.EffectEditorContext";
|
||||||
|
|
||||||
|
EffectCodeEditorWidget::EffectCodeEditorWidget()
|
||||||
|
: m_context(new Core::IContext(this))
|
||||||
|
{
|
||||||
|
Core::Context context(EFFECTEDITOR_CONTEXT_ID, ProjectExplorer::Constants::QMLJS_LANGUAGE_ID);
|
||||||
|
|
||||||
|
m_context->setWidget(this);
|
||||||
|
m_context->setContext(context);
|
||||||
|
Core::ICore::addContextObject(m_context);
|
||||||
|
|
||||||
|
Utils::TransientScrollAreaSupport::support(this);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have to register our own active auto completion shortcut, because the original shortcut will
|
||||||
|
* use the cursor position of the original editor in the editor manager.
|
||||||
|
*/
|
||||||
|
m_completionAction = new QAction(tr("Trigger Completion"), this);
|
||||||
|
|
||||||
|
Core::Command *command = Core::ActionManager::registerAction(
|
||||||
|
m_completionAction, TextEditor::Constants::COMPLETE_THIS, context);
|
||||||
|
command->setDefaultKeySequence(QKeySequence(
|
||||||
|
Core::useMacShortcuts
|
||||||
|
? tr("Meta+Space")
|
||||||
|
: tr("Ctrl+Space")));
|
||||||
|
|
||||||
|
connect(m_completionAction, &QAction::triggered, this, [this] {
|
||||||
|
invokeAssist(TextEditor::Completion);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectCodeEditorWidget::~EffectCodeEditorWidget()
|
||||||
|
{
|
||||||
|
unregisterAutoCompletion();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectCodeEditorWidget::unregisterAutoCompletion()
|
||||||
|
{
|
||||||
|
if (m_completionAction) {
|
||||||
|
Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS);
|
||||||
|
delete m_completionAction;
|
||||||
|
m_completionAction = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectCodeEditorWidget::setEditorTextWithIndentation(const QString &text)
|
||||||
|
{
|
||||||
|
auto *doc = document();
|
||||||
|
doc->setPlainText(text);
|
||||||
|
|
||||||
|
// We don't need to indent an empty text but is also needed for safer text.length()-1 below
|
||||||
|
if (text.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto modifier = std::make_unique<QmlDesigner::IndentingTextEditModifier>(doc, QTextCursor{doc});
|
||||||
|
modifier->indent(0, text.length()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectDocument::EffectDocument()
|
||||||
|
: QmlJSEditor::QmlJSEditorDocument(EFFECTEDITOR_CONTEXT_ID)
|
||||||
|
, m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this))
|
||||||
|
{}
|
||||||
|
|
||||||
|
EffectDocument::~EffectDocument()
|
||||||
|
{
|
||||||
|
delete m_semanticHighlighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectDocument::applyFontSettings()
|
||||||
|
{
|
||||||
|
TextDocument::applyFontSettings();
|
||||||
|
m_semanticHighlighter->updateFontSettings(fontSettings());
|
||||||
|
if (!isSemanticInfoOutdated() && semanticInfo().isValid())
|
||||||
|
m_semanticHighlighter->rerun(semanticInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectDocument::triggerPendingUpdates()
|
||||||
|
{
|
||||||
|
TextDocument::triggerPendingUpdates(); // Calls applyFontSettings if necessary
|
||||||
|
if (!isSemanticInfoOutdated() && semanticInfo().isValid())
|
||||||
|
m_semanticHighlighter->rerun(semanticInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectCodeEditorFactory::EffectCodeEditorFactory()
|
||||||
|
{
|
||||||
|
setId(EFFECTEDITOR_CONTEXT_ID);
|
||||||
|
setDisplayName(::Core::Tr::tr("Effect Code Editor"));
|
||||||
|
addMimeType(EFFECTEDITOR_CONTEXT_ID);
|
||||||
|
addMimeType(Utils::Constants::QML_MIMETYPE);
|
||||||
|
addMimeType(Utils::Constants::QMLTYPES_MIMETYPE);
|
||||||
|
addMimeType(Utils::Constants::JS_MIMETYPE);
|
||||||
|
|
||||||
|
setDocumentCreator([]() { return new EffectDocument; });
|
||||||
|
setEditorWidgetCreator([]() { return new EffectCodeEditorWidget; });
|
||||||
|
setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; });
|
||||||
|
setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; });
|
||||||
|
setCommentDefinition(Utils::CommentDefinition::CppStyle);
|
||||||
|
setParenthesesMatchingEnabled(true);
|
||||||
|
setCodeFoldingSupported(true);
|
||||||
|
|
||||||
|
addHoverHandler(new QmlJSEditor::QmlJSHoverHandler);
|
||||||
|
setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectCodeEditorFactory::decorateEditor(TextEditor::TextEditorWidget *editor)
|
||||||
|
{
|
||||||
|
editor->textDocument()->resetSyntaxHighlighter(
|
||||||
|
[] { return new QmlJSEditor::QmlJSHighlighter(); });
|
||||||
|
editor->textDocument()->setIndenter(QmlJSEditor::createQmlJsIndenter(
|
||||||
|
editor->textDocument()->document()));
|
||||||
|
editor->setAutoCompleter(new QmlJSEditor::AutoCompleter);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace EffectComposer
|
63
src/plugins/effectcomposer/effectcodeeditorwidget.h
Normal file
63
src/plugins/effectcomposer/effectcodeeditorwidget.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qmljseditor/qmljseditor.h>
|
||||||
|
#include <qmljseditor/qmljseditordocument.h>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QAction)
|
||||||
|
|
||||||
|
namespace QmlJSEditor {
|
||||||
|
class SemanticHighlighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class IContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace EffectComposer {
|
||||||
|
|
||||||
|
class EffectCodeEditorWidget : public QmlJSEditor::QmlJSEditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
EffectCodeEditorWidget();
|
||||||
|
~EffectCodeEditorWidget() override;
|
||||||
|
|
||||||
|
void unregisterAutoCompletion();
|
||||||
|
void setEditorTextWithIndentation(const QString &text);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void returnKeyClicked();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Core::IContext *m_context = nullptr;
|
||||||
|
QAction *m_completionAction = nullptr;
|
||||||
|
bool m_isMultiline = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectDocument : public QmlJSEditor::QmlJSEditorDocument
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EffectDocument();
|
||||||
|
~EffectDocument();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void applyFontSettings() final;
|
||||||
|
void triggerPendingUpdates() final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QmlJSEditor::SemanticHighlighter *m_semanticHighlighter = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectCodeEditorFactory : public TextEditor::TextEditorFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EffectCodeEditorFactory();
|
||||||
|
|
||||||
|
static void decorateEditor(TextEditor::TextEditorWidget *editor);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace EffectComposer
|
@@ -168,11 +168,11 @@ int EffectComposerContextObject::devicePixelRatio()
|
|||||||
|
|
||||||
QStringList EffectComposerContextObject::allStatesForId(const QString &id)
|
QStringList EffectComposerContextObject::allStatesForId(const QString &id)
|
||||||
{
|
{
|
||||||
if (m_model && m_model->rewriterView()) {
|
if (m_model) {
|
||||||
const QmlDesigner::QmlObjectNode node = m_model->rewriterView()->modelNodeForId(id);
|
const QmlDesigner::QmlObjectNode node = m_model->modelNodeForId(id);
|
||||||
if (node.isValid())
|
if (node.isValid())
|
||||||
return node.allStateNames();
|
return node.allStateNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@@ -4,27 +4,36 @@
|
|||||||
#include "effectcomposermodel.h"
|
#include "effectcomposermodel.h"
|
||||||
|
|
||||||
#include "compositionnode.h"
|
#include "compositionnode.h"
|
||||||
|
#include "effectshaderscodeeditor.h"
|
||||||
#include "effectutils.h"
|
#include "effectutils.h"
|
||||||
#include "propertyhandler.h"
|
#include "propertyhandler.h"
|
||||||
#include "syntaxhighlighterdata.h"
|
#include "syntaxhighlighterdata.h"
|
||||||
#include "uniform.h"
|
#include "uniform.h"
|
||||||
|
|
||||||
|
#include <asset.h>
|
||||||
|
#include <designdocument.h>
|
||||||
|
#include <modelnodeoperations.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <uniquename.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <projectexplorer/projecttree.h>
|
#include <projectexplorer/projecttree.h>
|
||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
|
|
||||||
#include <qtsupport/qtkitaspect.h>
|
#include <qtsupport/qtkitaspect.h>
|
||||||
|
|
||||||
#include <uniquename.h>
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <modelnodeoperations.h>
|
|
||||||
|
|
||||||
#include <QByteArrayView>
|
#include <QByteArrayView>
|
||||||
|
#include <QFileDialog>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
|
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
namespace EffectComposer {
|
namespace EffectComposer {
|
||||||
|
|
||||||
enum class FileType
|
enum class FileType
|
||||||
@@ -58,11 +67,12 @@ EffectComposerModel::EffectComposerModel(QObject *parent)
|
|||||||
|
|
||||||
QHash<int, QByteArray> EffectComposerModel::roleNames() const
|
QHash<int, QByteArray> EffectComposerModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roles;
|
static const QHash<int, QByteArray> roles = {
|
||||||
roles[NameRole] = "nodeName";
|
{NameRole, "nodeName"},
|
||||||
roles[EnabledRole] = "nodeEnabled";
|
{EnabledRole, "nodeEnabled"},
|
||||||
roles[UniformsRole] = "nodeUniformsModel";
|
{UniformsRole, "nodeUniformsModel"},
|
||||||
roles[Dependency] = "isDependency";
|
{Dependency, "isDependency"},
|
||||||
|
};
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +216,8 @@ void EffectComposerModel::clear(bool clearName)
|
|||||||
if (clearName) {
|
if (clearName) {
|
||||||
setCurrentComposition("");
|
setCurrentComposition("");
|
||||||
setCompositionPath("");
|
setCompositionPath("");
|
||||||
|
resetRootFragmentShader();
|
||||||
|
resetRootVertexShader();
|
||||||
}
|
}
|
||||||
|
|
||||||
setHasUnsavedChanges(!m_currentComposition.isEmpty());
|
setHasUnsavedChanges(!m_currentComposition.isEmpty());
|
||||||
@@ -241,6 +253,47 @@ bool EffectComposerModel::nameExists(const QString &name) const
|
|||||||
return QFile::exists(path.arg(name));
|
return QFile::exists(path.arg(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::chooseCustomPreviewImage()
|
||||||
|
{
|
||||||
|
QTimer::singleShot(0, this, [&]() {
|
||||||
|
using Utils::FilePath;
|
||||||
|
static FilePath lastDir;
|
||||||
|
const QStringList &suffixes = QmlDesigner::Asset::supportedImageSuffixes();
|
||||||
|
QmlDesigner::DesignDocument *document = QmlDesigner::QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||||
|
const FilePath currentDir = lastDir.isEmpty() ? document->fileName().parentDir()
|
||||||
|
: lastDir;
|
||||||
|
const QStringList fileNames = QFileDialog::getOpenFileNames(Core::ICore::dialogParent(),
|
||||||
|
tr("Select custom effect background image"),
|
||||||
|
currentDir.toFSPathString(),
|
||||||
|
tr("Image Files (%1)").arg(suffixes.join(" ")));
|
||||||
|
|
||||||
|
if (!fileNames.isEmpty()) {
|
||||||
|
FilePath imageFile = FilePath::fromString(fileNames.first());
|
||||||
|
lastDir = imageFile.absolutePath();
|
||||||
|
if (imageFile.exists()) {
|
||||||
|
FilePath projDir = QmlDesigner::QmlDesignerPlugin::instance()->documentManager()
|
||||||
|
.currentProjectDirPath();
|
||||||
|
if (!imageFile.isChildOf(projDir)) {
|
||||||
|
FilePath imagesDir = QmlDesigner::ModelNodeOperations::getImagesDefaultDirectory();
|
||||||
|
FilePath targetFile = imagesDir.pathAppended(imageFile.fileName());
|
||||||
|
if (!targetFile.exists())
|
||||||
|
imageFile.copyFile(targetFile);
|
||||||
|
if (targetFile.exists())
|
||||||
|
imageFile = targetFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_customPreviewImage = QUrl::fromLocalFile(imageFile.toFSPathString());
|
||||||
|
m_currentPreviewImage = m_customPreviewImage;
|
||||||
|
|
||||||
|
setHasUnsavedChanges(true);
|
||||||
|
|
||||||
|
emit currentPreviewImageChanged();
|
||||||
|
emit customPreviewImageChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QString EffectComposerModel::fragmentShader() const
|
QString EffectComposerModel::fragmentShader() const
|
||||||
{
|
{
|
||||||
return m_fragmentShader;
|
return m_fragmentShader;
|
||||||
@@ -267,6 +320,40 @@ void EffectComposerModel::setVertexShader(const QString &newVertexShader)
|
|||||||
m_vertexShader = newVertexShader;
|
m_vertexShader = newVertexShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::setRootFragmentShader(const QString &shader)
|
||||||
|
{
|
||||||
|
m_rootFragmentShader = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::resetRootFragmentShader()
|
||||||
|
{
|
||||||
|
static const QString defaultRootFragmentShader = {
|
||||||
|
"void main() {\n"
|
||||||
|
" fragColor = texture(iSource, texCoord);\n"
|
||||||
|
" @nodes\n"
|
||||||
|
" fragColor = fragColor * qt_Opacity;\n"
|
||||||
|
"}\n"};
|
||||||
|
setRootFragmentShader(defaultRootFragmentShader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::setRootVertexShader(const QString &shader)
|
||||||
|
{
|
||||||
|
m_rootVertexShader = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::resetRootVertexShader()
|
||||||
|
{
|
||||||
|
static const QString defaultRootVertexShader = {
|
||||||
|
"void main() {\n"
|
||||||
|
" texCoord = qt_MultiTexCoord0;\n"
|
||||||
|
" fragCoord = qt_Vertex.xy;\n"
|
||||||
|
" vec2 vertCoord = qt_Vertex.xy;\n"
|
||||||
|
" @nodes\n"
|
||||||
|
" gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);\n"
|
||||||
|
"}\n"};
|
||||||
|
setRootVertexShader(defaultRootVertexShader);
|
||||||
|
}
|
||||||
|
|
||||||
QString EffectComposerModel::qmlComponentString() const
|
QString EffectComposerModel::qmlComponentString() const
|
||||||
{
|
{
|
||||||
return m_qmlComponentString;
|
return m_qmlComponentString;
|
||||||
@@ -960,11 +1047,26 @@ void EffectComposerModel::saveComposition(const QString &name)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Utils::FilePath compositionPath = Utils::FilePath::fromString(path);
|
||||||
|
const Utils::FilePath compositionDir = compositionPath.absolutePath();
|
||||||
|
|
||||||
updateExtraMargin();
|
updateExtraMargin();
|
||||||
|
|
||||||
QJsonObject json;
|
QJsonObject json;
|
||||||
// File format version
|
// File format version
|
||||||
json.insert("version", 1);
|
json.insert("version", 1);
|
||||||
|
json.insert("tool", "EffectComposer");
|
||||||
|
|
||||||
|
Utils::FilePath customPreviewPath = Utils::FilePath::fromUrl(m_customPreviewImage);
|
||||||
|
if (m_customPreviewImage.isLocalFile())
|
||||||
|
customPreviewPath = customPreviewPath.relativePathFrom(compositionDir);
|
||||||
|
json.insert("customPreviewImage", customPreviewPath.toUrl().toString());
|
||||||
|
|
||||||
|
QUrl previewUrl = m_currentPreviewImage;
|
||||||
|
if (m_currentPreviewImage == m_customPreviewImage)
|
||||||
|
previewUrl = customPreviewPath.toUrl();
|
||||||
|
|
||||||
|
json.insert("previewImage", previewUrl.toString());
|
||||||
|
|
||||||
// Add nodes
|
// Add nodes
|
||||||
QJsonArray nodesArray;
|
QJsonArray nodesArray;
|
||||||
@@ -973,9 +1075,18 @@ void EffectComposerModel::saveComposition(const QString &name)
|
|||||||
nodesArray.append(nodeObject);
|
nodesArray.append(nodeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto toJsonArray = [](const QString &code) -> QJsonArray {
|
||||||
|
if (code.isEmpty())
|
||||||
|
return {};
|
||||||
|
return QJsonArray::fromStringList(code.split('\n'));
|
||||||
|
};
|
||||||
|
|
||||||
if (!nodesArray.isEmpty())
|
if (!nodesArray.isEmpty())
|
||||||
json.insert("nodes", nodesArray);
|
json.insert("nodes", nodesArray);
|
||||||
|
|
||||||
|
json.insert("vertexCode", toJsonArray(m_rootVertexShader));
|
||||||
|
json.insert("fragmentCode", toJsonArray(m_rootFragmentShader));
|
||||||
|
|
||||||
QJsonObject rootJson;
|
QJsonObject rootJson;
|
||||||
rootJson.insert("QEP", json);
|
rootJson.insert("QEP", json);
|
||||||
QJsonDocument jsonDoc(rootJson);
|
QJsonDocument jsonDoc(rootJson);
|
||||||
@@ -984,20 +1095,60 @@ void EffectComposerModel::saveComposition(const QString &name)
|
|||||||
saveFile.close();
|
saveFile.close();
|
||||||
|
|
||||||
setCurrentComposition(name);
|
setCurrentComposition(name);
|
||||||
setCompositionPath(Utils::FilePath::fromString(path));
|
setCompositionPath(compositionPath);
|
||||||
|
|
||||||
saveResources(name);
|
saveResources(name);
|
||||||
setHasUnsavedChanges(false);
|
setHasUnsavedChanges(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::openShadersCodeEditor(int idx)
|
||||||
|
{
|
||||||
|
if (m_nodes.size() < idx || idx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CompositionNode *node = m_nodes.at(idx);
|
||||||
|
node->openShadersCodeEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::openMainShadersCodeEditor()
|
||||||
|
{
|
||||||
|
if (!m_shadersCodeEditor) {
|
||||||
|
m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr<EffectShadersCodeEditor>(
|
||||||
|
currentComposition());
|
||||||
|
m_shadersCodeEditor->setFragmentValue(m_rootFragmentShader);
|
||||||
|
m_shadersCodeEditor->setVertexValue(m_rootVertexShader);
|
||||||
|
|
||||||
|
connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] {
|
||||||
|
setRootVertexShader(m_shadersCodeEditor->vertexValue());
|
||||||
|
setHasUnsavedChanges(true);
|
||||||
|
rebakeIfLiveUpdateMode();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(
|
||||||
|
m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] {
|
||||||
|
setRootFragmentShader(m_shadersCodeEditor->fragmentValue());
|
||||||
|
setHasUnsavedChanges(true);
|
||||||
|
rebakeIfLiveUpdateMode();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(
|
||||||
|
m_shadersCodeEditor.get(),
|
||||||
|
&EffectShadersCodeEditor::rebakeRequested,
|
||||||
|
this,
|
||||||
|
&EffectComposerModel::startRebakeTimer);
|
||||||
|
}
|
||||||
|
m_shadersCodeEditor->showWidget();
|
||||||
|
}
|
||||||
|
|
||||||
void EffectComposerModel::openComposition(const QString &path)
|
void EffectComposerModel::openComposition(const QString &path)
|
||||||
{
|
{
|
||||||
clear(true);
|
clear(true);
|
||||||
|
|
||||||
const QString effectName = QFileInfo(path).baseName();
|
Utils::FilePath effectPath = Utils::FilePath::fromString(path);
|
||||||
|
const QString effectName = effectPath.baseName();
|
||||||
|
|
||||||
setCurrentComposition(effectName);
|
setCurrentComposition(effectName);
|
||||||
setCompositionPath(Utils::FilePath::fromString(path));
|
setCompositionPath(effectPath);
|
||||||
|
|
||||||
QFile compFile(path);
|
QFile compFile(path);
|
||||||
if (!compFile.open(QIODevice::ReadOnly)) {
|
if (!compFile.open(QIODevice::ReadOnly)) {
|
||||||
@@ -1030,6 +1181,18 @@ void EffectComposerModel::openComposition(const QString &path)
|
|||||||
|
|
||||||
QJsonObject json = rootJson["QEP"].toObject();
|
QJsonObject json = rootJson["QEP"].toObject();
|
||||||
|
|
||||||
|
const QString toolName = json.contains("tool") ? json["tool"].toString()
|
||||||
|
: json.contains("QQEM") ? "QQEM"_L1
|
||||||
|
: ""_L1;
|
||||||
|
|
||||||
|
if (!toolName.isEmpty() && toolName != "EffectComposer") {
|
||||||
|
const QString error
|
||||||
|
= tr("Error: '%1' effects are not compatible with 'Effect Composer'").arg(toolName);
|
||||||
|
qWarning() << error;
|
||||||
|
setEffectError(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int version = -1;
|
int version = -1;
|
||||||
if (json.contains("version"))
|
if (json.contains("version"))
|
||||||
version = json["version"].toInt(-1);
|
version = json["version"].toInt(-1);
|
||||||
@@ -1041,6 +1204,63 @@ void EffectComposerModel::openComposition(const QString &path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto toCodeBlock = [](const QJsonValue &jsonValue) -> QString {
|
||||||
|
if (!jsonValue.isArray())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QString code;
|
||||||
|
const QJsonArray array = jsonValue.toArray();
|
||||||
|
for (const QJsonValue &lineValue : array) {
|
||||||
|
if (lineValue.isString())
|
||||||
|
code += lineValue.toString() + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (json.contains("vertexCode"))
|
||||||
|
setRootVertexShader(toCodeBlock(json["vertexCode"]));
|
||||||
|
else
|
||||||
|
resetRootVertexShader();
|
||||||
|
|
||||||
|
if (json.contains("fragmentCode"))
|
||||||
|
setRootFragmentShader(toCodeBlock(json["fragmentCode"]));
|
||||||
|
else
|
||||||
|
resetRootFragmentShader();
|
||||||
|
|
||||||
|
m_currentPreviewImage.clear();
|
||||||
|
if (json.contains("previewImage")) {
|
||||||
|
const QString imageStr = json["previewImage"].toString();
|
||||||
|
if (!imageStr.isEmpty()) {
|
||||||
|
const QUrl imageUrl{imageStr};
|
||||||
|
Utils::FilePath imagePath = Utils::FilePath::fromUrl(imageUrl);
|
||||||
|
if (imageStr.startsWith("images/preview")) { // built-in preview image
|
||||||
|
m_currentPreviewImage = imageUrl;
|
||||||
|
} else if (imagePath.isAbsolutePath()) {
|
||||||
|
if (imagePath.exists())
|
||||||
|
m_currentPreviewImage = imageUrl;
|
||||||
|
} else {
|
||||||
|
imagePath = effectPath.absolutePath().resolvePath(imagePath);
|
||||||
|
if (imagePath.exists())
|
||||||
|
m_currentPreviewImage = imagePath.toUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_customPreviewImage.clear();
|
||||||
|
if (json.contains("customPreviewImage")) {
|
||||||
|
QUrl imageUrl{json["customPreviewImage"].toString()};
|
||||||
|
Utils::FilePath imagePath = Utils::FilePath::fromUrl(imageUrl);
|
||||||
|
if (imagePath.isAbsolutePath()) {
|
||||||
|
if (imagePath.exists())
|
||||||
|
m_customPreviewImage = imageUrl;
|
||||||
|
} else {
|
||||||
|
imagePath = effectPath.absolutePath().resolvePath(imagePath);
|
||||||
|
if (imagePath.exists())
|
||||||
|
m_customPreviewImage = imagePath.toUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (json.contains("nodes") && json["nodes"].isArray()) {
|
if (json.contains("nodes") && json["nodes"].isArray()) {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
QHash<QString, int> refCounts;
|
QHash<QString, int> refCounts;
|
||||||
@@ -1069,6 +1289,8 @@ void EffectComposerModel::openComposition(const QString &path)
|
|||||||
|
|
||||||
setHasUnsavedChanges(false);
|
setHasUnsavedChanges(false);
|
||||||
emit nodesChanged();
|
emit nodesChanged();
|
||||||
|
emit currentPreviewImageChanged();
|
||||||
|
emit customPreviewImageChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectComposerModel::saveResources(const QString &name)
|
void EffectComposerModel::saveResources(const QString &name)
|
||||||
@@ -1354,8 +1576,6 @@ QString EffectComposerModel::valueAsVariable(const Uniform &uniform)
|
|||||||
// Return name for the image property Image element
|
// Return name for the image property Image element
|
||||||
QString EffectComposerModel::getImageElementName(const Uniform &uniform, bool localFiles)
|
QString EffectComposerModel::getImageElementName(const Uniform &uniform, bool localFiles)
|
||||||
{
|
{
|
||||||
if (localFiles && uniform.value().toString().isEmpty())
|
|
||||||
return QStringLiteral("null");
|
|
||||||
QString simplifiedName = uniform.name().simplified();
|
QString simplifiedName = uniform.name().simplified();
|
||||||
simplifiedName = simplifiedName.remove(' ');
|
simplifiedName = simplifiedName.remove(' ');
|
||||||
return QStringLiteral("imageItem") + simplifiedName;
|
return QStringLiteral("imageItem") + simplifiedName;
|
||||||
@@ -1439,32 +1659,6 @@ QString EffectComposerModel::processFragmentRootLine(const QString &line)
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList EffectComposerModel::getDefaultRootVertexShader()
|
|
||||||
{
|
|
||||||
if (m_defaultRootVertexShader.isEmpty()) {
|
|
||||||
m_defaultRootVertexShader << "void main() {";
|
|
||||||
m_defaultRootVertexShader << " texCoord = qt_MultiTexCoord0;";
|
|
||||||
m_defaultRootVertexShader << " fragCoord = qt_Vertex.xy;";
|
|
||||||
m_defaultRootVertexShader << " vec2 vertCoord = qt_Vertex.xy;";
|
|
||||||
m_defaultRootVertexShader << " @nodes";
|
|
||||||
m_defaultRootVertexShader << " gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);";
|
|
||||||
m_defaultRootVertexShader << "}";
|
|
||||||
}
|
|
||||||
return m_defaultRootVertexShader;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList EffectComposerModel::getDefaultRootFragmentShader()
|
|
||||||
{
|
|
||||||
if (m_defaultRootFragmentShader.isEmpty()) {
|
|
||||||
m_defaultRootFragmentShader << "void main() {";
|
|
||||||
m_defaultRootFragmentShader << " fragColor = texture(iSource, texCoord);";
|
|
||||||
m_defaultRootFragmentShader << " @nodes";
|
|
||||||
m_defaultRootFragmentShader << " fragColor = fragColor * qt_Opacity;";
|
|
||||||
m_defaultRootFragmentShader << "}";
|
|
||||||
}
|
|
||||||
return m_defaultRootFragmentShader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove all post-processing tags ("@tag") from the code.
|
// Remove all post-processing tags ("@tag") from the code.
|
||||||
// Except "@nodes" tag as that is handled later.
|
// Except "@nodes" tag as that is handled later.
|
||||||
QStringList EffectComposerModel::removeTagsFromCode(const QStringList &codeLines)
|
QStringList EffectComposerModel::removeTagsFromCode(const QStringList &codeLines)
|
||||||
@@ -1527,7 +1721,7 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms)
|
|||||||
// split to root and main parts
|
// split to root and main parts
|
||||||
QString s_root;
|
QString s_root;
|
||||||
QString s_main;
|
QString s_main;
|
||||||
QStringList s_sourceCode;
|
QStringList s_sourceCode = m_rootVertexShader.split('\n');
|
||||||
m_shaderVaryingVariables.clear();
|
m_shaderVaryingVariables.clear();
|
||||||
for (const CompositionNode *n : std::as_const(m_nodes)) {
|
for (const CompositionNode *n : std::as_const(m_nodes)) {
|
||||||
if (!n->vertexCode().isEmpty() && n->isEnabled()) {
|
if (!n->vertexCode().isEmpty() && n->isEnabled()) {
|
||||||
@@ -1544,11 +1738,6 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_sourceCode.isEmpty()) {
|
|
||||||
// If source nodes doesn't contain any code, use default one
|
|
||||||
s_sourceCode << getDefaultRootVertexShader();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removeTags) {
|
if (removeTags) {
|
||||||
s_sourceCode = removeTagsFromCode(s_sourceCode);
|
s_sourceCode = removeTagsFromCode(s_sourceCode);
|
||||||
s_root = removeTagsFromCode(s_root);
|
s_root = removeTagsFromCode(s_root);
|
||||||
@@ -1583,7 +1772,7 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms)
|
|||||||
// split to root and main parts
|
// split to root and main parts
|
||||||
QString s_root;
|
QString s_root;
|
||||||
QString s_main;
|
QString s_main;
|
||||||
QStringList s_sourceCode;
|
QStringList s_sourceCode = m_rootFragmentShader.split('\n');
|
||||||
for (const CompositionNode *n : std::as_const(m_nodes)) {
|
for (const CompositionNode *n : std::as_const(m_nodes)) {
|
||||||
if (!n->fragmentCode().isEmpty() && n->isEnabled()) {
|
if (!n->fragmentCode().isEmpty() && n->isEnabled()) {
|
||||||
const QStringList fragmentCode = n->fragmentCode().split('\n');
|
const QStringList fragmentCode = n->fragmentCode().split('\n');
|
||||||
@@ -1599,11 +1788,6 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_sourceCode.isEmpty()) {
|
|
||||||
// If source nodes doesn't contain any code, use default one
|
|
||||||
s_sourceCode << getDefaultRootFragmentShader();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removeTags) {
|
if (removeTags) {
|
||||||
s_sourceCode = removeTagsFromCode(s_sourceCode);
|
s_sourceCode = removeTagsFromCode(s_sourceCode);
|
||||||
s_root = removeTagsFromCode(s_root);
|
s_root = removeTagsFromCode(s_root);
|
||||||
@@ -1828,7 +2012,6 @@ void EffectComposerModel::bakeShaders()
|
|||||||
|
|
||||||
runQsb(qsbPath, outPaths, false);
|
runQsb(qsbPath, outPaths, false);
|
||||||
runQsb(qsbPrevPath, outPrevPaths, true);
|
runQsb(qsbPrevPath, outPrevPaths, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectComposerModel::shadersUpToDate() const
|
bool EffectComposerModel::shadersUpToDate() const
|
||||||
@@ -1877,11 +2060,7 @@ QString EffectComposerModel::getQmlImagesString(bool localFiles)
|
|||||||
for (Uniform *uniform : uniforms) {
|
for (Uniform *uniform : uniforms) {
|
||||||
if (uniform->type() == Uniform::Type::Sampler) {
|
if (uniform->type() == Uniform::Type::Sampler) {
|
||||||
QString imagePath = uniform->value().toString();
|
QString imagePath = uniform->value().toString();
|
||||||
// For preview, generate image element even if path is empty, as changing uniform values
|
|
||||||
// will not trigger qml code regeneration
|
|
||||||
if (localFiles) {
|
if (localFiles) {
|
||||||
if (imagePath.isEmpty())
|
|
||||||
continue;
|
|
||||||
QFileInfo fi(imagePath);
|
QFileInfo fi(imagePath);
|
||||||
imagePath = fi.fileName();
|
imagePath = fi.fileName();
|
||||||
imagesString += QString(" property url %1Url: \"%2\"\n")
|
imagesString += QString(" property url %1Url: \"%2\"\n")
|
||||||
@@ -2003,14 +2182,16 @@ QString EffectComposerModel::getQmlComponentString(bool localFiles)
|
|||||||
|
|
||||||
void EffectComposerModel::connectCompositionNode(CompositionNode *node)
|
void EffectComposerModel::connectCompositionNode(CompositionNode *node)
|
||||||
{
|
{
|
||||||
connect(qobject_cast<EffectComposerUniformsModel *>(node->uniformsModel()),
|
auto setUnsaved = std::bind(&EffectComposerModel::setHasUnsavedChanges, this, true);
|
||||||
&EffectComposerUniformsModel::dataChanged, this, [this] {
|
connect(
|
||||||
setHasUnsavedChanges(true);
|
qobject_cast<EffectComposerUniformsModel *>(node->uniformsModel()),
|
||||||
});
|
&EffectComposerUniformsModel::dataChanged,
|
||||||
connect(node, &CompositionNode::rebakeRequested, this, [this] {
|
this,
|
||||||
// This can come multiple times in a row in response to property changes, so let's buffer it
|
setUnsaved);
|
||||||
m_rebakeTimer.start(200);
|
|
||||||
});
|
connect(node, &CompositionNode::rebakeRequested, this, &EffectComposerModel::startRebakeTimer);
|
||||||
|
connect(node, &CompositionNode::fragmentCodeChanged, this, setUnsaved);
|
||||||
|
connect(node, &CompositionNode::vertexCodeChanged, this, setUnsaved);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectComposerModel::updateExtraMargin()
|
void EffectComposerModel::updateExtraMargin()
|
||||||
@@ -2020,6 +2201,18 @@ void EffectComposerModel::updateExtraMargin()
|
|||||||
m_extraMargin = qMax(node->extraMargin(), m_extraMargin);
|
m_extraMargin = qMax(node->extraMargin(), m_extraMargin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::startRebakeTimer()
|
||||||
|
{
|
||||||
|
// This can come multiple times in a row in response to property changes, so let's buffer it
|
||||||
|
m_rebakeTimer.start(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::rebakeIfLiveUpdateMode()
|
||||||
|
{
|
||||||
|
if (m_shadersCodeEditor && m_shadersCodeEditor->liveUpdate())
|
||||||
|
startRebakeTimer();
|
||||||
|
}
|
||||||
|
|
||||||
QSet<QByteArray> EffectComposerModel::getExposedProperties(const QByteArray &qmlContent)
|
QSet<QByteArray> EffectComposerModel::getExposedProperties(const QByteArray &qmlContent)
|
||||||
{
|
{
|
||||||
QSet<QByteArray> returnSet;
|
QSet<QByteArray> returnSet;
|
||||||
@@ -2051,6 +2244,30 @@ void EffectComposerModel::setCurrentComposition(const QString &newCurrentComposi
|
|||||||
|
|
||||||
m_currentComposition = newCurrentComposition;
|
m_currentComposition = newCurrentComposition;
|
||||||
emit currentCompositionChanged();
|
emit currentCompositionChanged();
|
||||||
|
|
||||||
|
m_shadersCodeEditor.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl EffectComposerModel::customPreviewImage() const
|
||||||
|
{
|
||||||
|
return m_customPreviewImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl EffectComposerModel::currentPreviewImage() const
|
||||||
|
{
|
||||||
|
return m_currentPreviewImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerModel::setCurrentPreviewImage(const QUrl &path)
|
||||||
|
{
|
||||||
|
if (m_currentPreviewImage == path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_nodes.isEmpty())
|
||||||
|
setHasUnsavedChanges(true);
|
||||||
|
|
||||||
|
m_currentPreviewImage = path;
|
||||||
|
emit currentPreviewImageChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::FilePath EffectComposerModel::compositionPath() const
|
Utils::FilePath EffectComposerModel::compositionPath() const
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "shaderfeatures.h"
|
#include "shaderfeatures.h"
|
||||||
|
|
||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
|
#include <utils/uniqueobjectptr.h>
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
class Target;
|
class Target;
|
||||||
@@ -26,6 +28,7 @@ class Process;
|
|||||||
namespace EffectComposer {
|
namespace EffectComposer {
|
||||||
|
|
||||||
class CompositionNode;
|
class CompositionNode;
|
||||||
|
class EffectShadersCodeEditor;
|
||||||
class Uniform;
|
class Uniform;
|
||||||
|
|
||||||
struct EffectError {
|
struct EffectError {
|
||||||
@@ -51,6 +54,8 @@ class EffectComposerModel : public QAbstractListModel
|
|||||||
Q_PROPERTY(bool isEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged)
|
Q_PROPERTY(bool isEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged)
|
||||||
Q_PROPERTY(bool hasValidTarget READ hasValidTarget WRITE setHasValidTarget NOTIFY hasValidTargetChanged)
|
Q_PROPERTY(bool hasValidTarget READ hasValidTarget WRITE setHasValidTarget NOTIFY hasValidTargetChanged)
|
||||||
Q_PROPERTY(QString currentComposition READ currentComposition WRITE setCurrentComposition NOTIFY currentCompositionChanged)
|
Q_PROPERTY(QString currentComposition READ currentComposition WRITE setCurrentComposition NOTIFY currentCompositionChanged)
|
||||||
|
Q_PROPERTY(QUrl currentPreviewImage READ currentPreviewImage WRITE setCurrentPreviewImage NOTIFY currentPreviewImageChanged)
|
||||||
|
Q_PROPERTY(QUrl customPreviewImage READ customPreviewImage NOTIFY customPreviewImageChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EffectComposerModel(QObject *parent = nullptr);
|
EffectComposerModel(QObject *parent = nullptr);
|
||||||
@@ -75,6 +80,7 @@ public:
|
|||||||
Q_INVOKABLE void assignToSelected();
|
Q_INVOKABLE void assignToSelected();
|
||||||
Q_INVOKABLE QString getUniqueEffectName() const;
|
Q_INVOKABLE QString getUniqueEffectName() const;
|
||||||
Q_INVOKABLE bool nameExists(const QString &name) const;
|
Q_INVOKABLE bool nameExists(const QString &name) const;
|
||||||
|
Q_INVOKABLE void chooseCustomPreviewImage();
|
||||||
|
|
||||||
bool shadersUpToDate() const;
|
bool shadersUpToDate() const;
|
||||||
void setShadersUpToDate(bool newShadersUpToDate);
|
void setShadersUpToDate(bool newShadersUpToDate);
|
||||||
@@ -91,6 +97,12 @@ public:
|
|||||||
QString vertexShader() const;
|
QString vertexShader() const;
|
||||||
void setVertexShader(const QString &newVertexShader);
|
void setVertexShader(const QString &newVertexShader);
|
||||||
|
|
||||||
|
void setRootFragmentShader(const QString &shader);
|
||||||
|
void resetRootFragmentShader();
|
||||||
|
|
||||||
|
void setRootVertexShader(const QString &shader);
|
||||||
|
void resetRootVertexShader();
|
||||||
|
|
||||||
Q_INVOKABLE QString qmlComponentString() const;
|
Q_INVOKABLE QString qmlComponentString() const;
|
||||||
|
|
||||||
Q_INVOKABLE void updateQmlComponent();
|
Q_INVOKABLE void updateQmlComponent();
|
||||||
@@ -100,11 +112,18 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void saveComposition(const QString &name);
|
Q_INVOKABLE void saveComposition(const QString &name);
|
||||||
|
|
||||||
|
Q_INVOKABLE void openShadersCodeEditor(int idx);
|
||||||
|
Q_INVOKABLE void openMainShadersCodeEditor();
|
||||||
|
|
||||||
void openComposition(const QString &path);
|
void openComposition(const QString &path);
|
||||||
|
|
||||||
QString currentComposition() const;
|
QString currentComposition() const;
|
||||||
void setCurrentComposition(const QString &newCurrentComposition);
|
void setCurrentComposition(const QString &newCurrentComposition);
|
||||||
|
|
||||||
|
QUrl customPreviewImage() const;
|
||||||
|
QUrl currentPreviewImage() const;
|
||||||
|
void setCurrentPreviewImage(const QUrl &path);
|
||||||
|
|
||||||
Utils::FilePath compositionPath() const;
|
Utils::FilePath compositionPath() const;
|
||||||
void setCompositionPath(const Utils::FilePath &newCompositionPath);
|
void setCompositionPath(const Utils::FilePath &newCompositionPath);
|
||||||
|
|
||||||
@@ -129,6 +148,8 @@ signals:
|
|||||||
void hasUnsavedChangesChanged();
|
void hasUnsavedChangesChanged();
|
||||||
void assignToSelectedTriggered(const QString &effectPath);
|
void assignToSelectedTriggered(const QString &effectPath);
|
||||||
void removePropertiesFromScene(QSet<QByteArray> props, const QString &typeName);
|
void removePropertiesFromScene(QSet<QByteArray> props, const QString &typeName);
|
||||||
|
void currentPreviewImageChanged();
|
||||||
|
void customPreviewImageChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
@@ -167,8 +188,6 @@ private:
|
|||||||
int getTagIndex(const QStringList &code, const QString &tag);
|
int getTagIndex(const QStringList &code, const QString &tag);
|
||||||
QString processVertexRootLine(const QString &line);
|
QString processVertexRootLine(const QString &line);
|
||||||
QString processFragmentRootLine(const QString &line);
|
QString processFragmentRootLine(const QString &line);
|
||||||
QStringList getDefaultRootVertexShader();
|
|
||||||
QStringList getDefaultRootFragmentShader();
|
|
||||||
QStringList removeTagsFromCode(const QStringList &codeLines);
|
QStringList removeTagsFromCode(const QStringList &codeLines);
|
||||||
QString removeTagsFromCode(const QString &code);
|
QString removeTagsFromCode(const QString &code);
|
||||||
QString getCustomShaderVaryings(bool outState);
|
QString getCustomShaderVaryings(bool outState);
|
||||||
@@ -190,6 +209,8 @@ private:
|
|||||||
|
|
||||||
void connectCompositionNode(CompositionNode *node);
|
void connectCompositionNode(CompositionNode *node);
|
||||||
void updateExtraMargin();
|
void updateExtraMargin();
|
||||||
|
void startRebakeTimer();
|
||||||
|
void rebakeIfLiveUpdateMode();
|
||||||
QSet<QByteArray> getExposedProperties(const QByteArray &qmlContent);
|
QSet<QByteArray> getExposedProperties(const QByteArray &qmlContent);
|
||||||
|
|
||||||
QList<CompositionNode *> m_nodes;
|
QList<CompositionNode *> m_nodes;
|
||||||
@@ -205,8 +226,8 @@ private:
|
|||||||
QStringList m_shaderVaryingVariables;
|
QStringList m_shaderVaryingVariables;
|
||||||
QString m_fragmentShader;
|
QString m_fragmentShader;
|
||||||
QString m_vertexShader;
|
QString m_vertexShader;
|
||||||
QStringList m_defaultRootVertexShader;
|
QString m_rootVertexShader;
|
||||||
QStringList m_defaultRootFragmentShader;
|
QString m_rootFragmentShader;
|
||||||
// Temp files to store shaders sources and binary data
|
// Temp files to store shaders sources and binary data
|
||||||
QTemporaryDir m_shaderDir;
|
QTemporaryDir m_shaderDir;
|
||||||
QString m_fragmentSourceFilename;
|
QString m_fragmentSourceFilename;
|
||||||
@@ -230,6 +251,9 @@ private:
|
|||||||
int m_extraMargin = 0;
|
int m_extraMargin = 0;
|
||||||
QString m_effectTypePrefix;
|
QString m_effectTypePrefix;
|
||||||
Utils::FilePath m_compositionPath;
|
Utils::FilePath m_compositionPath;
|
||||||
|
Utils::UniqueObjectLatePtr<EffectShadersCodeEditor> m_shadersCodeEditor;
|
||||||
|
QUrl m_currentPreviewImage;
|
||||||
|
QUrl m_customPreviewImage;
|
||||||
|
|
||||||
const QRegularExpression m_spaceReg = QRegularExpression("\\s+");
|
const QRegularExpression m_spaceReg = QRegularExpression("\\s+");
|
||||||
};
|
};
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "effectcomposermodel.h"
|
#include "effectcomposermodel.h"
|
||||||
#include "effectcomposernodesmodel.h"
|
#include "effectcomposernodesmodel.h"
|
||||||
#include "effectcomposerwidget.h"
|
#include "effectcomposerwidget.h"
|
||||||
|
#include "studioquickwidget.h"
|
||||||
|
|
||||||
#include <designermcumanager.h>
|
#include <designermcumanager.h>
|
||||||
#include <documentmanager.h>
|
#include <documentmanager.h>
|
||||||
@@ -218,4 +219,27 @@ void EffectComposerView::removeUnusedEffectImports()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectComposerView::highlightSupportedProperties(bool highlight, const QString &suffix)
|
||||||
|
{
|
||||||
|
QQmlContext *ctxObj = m_widget->quickWidget()->rootContext();
|
||||||
|
ctxObj->setContextProperty("activeDragSuffix", suffix);
|
||||||
|
ctxObj->setContextProperty("hasActiveDrag", highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerView::dragStarted(QMimeData *mimeData)
|
||||||
|
{
|
||||||
|
if (mimeData->hasFormat(QmlDesigner::Constants::MIME_TYPE_ASSETS)) {
|
||||||
|
QString format = mimeData->formats()[0];
|
||||||
|
const QString assetPath = QString::fromUtf8(mimeData->data(format)).split(',')[0];
|
||||||
|
const QString suffix = "*." + assetPath.split('.').last().toLower();
|
||||||
|
|
||||||
|
highlightSupportedProperties(true, suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectComposerView::dragEnded()
|
||||||
|
{
|
||||||
|
highlightSupportedProperties(false);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace EffectComposer
|
} // namespace EffectComposer
|
||||||
|
@@ -31,6 +31,11 @@ public:
|
|||||||
const QList<QmlDesigner::ModelNode> &lastSelectedNodeList) override;
|
const QList<QmlDesigner::ModelNode> &lastSelectedNodeList) override;
|
||||||
void nodeAboutToBeRemoved(const QmlDesigner::ModelNode &removedNode) override;
|
void nodeAboutToBeRemoved(const QmlDesigner::ModelNode &removedNode) override;
|
||||||
|
|
||||||
|
void dragStarted(QMimeData *mimeData) override;
|
||||||
|
void dragEnded() override;
|
||||||
|
|
||||||
|
void highlightSupportedProperties(bool highlight, const QString &suffix = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void customNotification(const AbstractView *view, const QString &identifier,
|
void customNotification(const AbstractView *view, const QString &identifier,
|
||||||
const QList<QmlDesigner::ModelNode> &nodeList, const QList<QVariant> &data) override;
|
const QList<QmlDesigner::ModelNode> &nodeList, const QList<QVariant> &data) override;
|
||||||
|
226
src/plugins/effectcomposer/effectshaderscodeeditor.cpp
Normal file
226
src/plugins/effectcomposer/effectshaderscodeeditor.cpp
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "effectshaderscodeeditor.h"
|
||||||
|
#include "effectcodeeditorwidget.h"
|
||||||
|
|
||||||
|
#include <texteditor/textdocument.h>
|
||||||
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
|
#include <componentcore/designeractionmanager.h>
|
||||||
|
#include <componentcore/designericons.h>
|
||||||
|
#include <componentcore/theme.h>
|
||||||
|
|
||||||
|
#include <qmldesigner/qmldesignerplugin.h>
|
||||||
|
#include <qmljseditor/qmljseditor.h>
|
||||||
|
#include <qmljseditor/qmljseditordocument.h>
|
||||||
|
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using IconId = QmlDesigner::DesignerIcons::IconId;
|
||||||
|
|
||||||
|
inline constexpr char EFFECTCOMPOSER_LIVE_UPDATE_KEY[] = "EffectComposer/CodeEditor/LiveUpdate";
|
||||||
|
|
||||||
|
QIcon toolbarIcon(IconId iconId)
|
||||||
|
{
|
||||||
|
return QmlDesigner::DesignerActionManager::instance().toolbarIcon(iconId);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace EffectComposer {
|
||||||
|
|
||||||
|
EffectShadersCodeEditor::EffectShadersCodeEditor(const QString &title, QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_settings(new QSettings(qApp->organizationName(), qApp->applicationName(), this))
|
||||||
|
{
|
||||||
|
setWindowFlag(Qt::Tool, true);
|
||||||
|
setWindowTitle(title);
|
||||||
|
|
||||||
|
m_fragmentEditor = createJSEditor();
|
||||||
|
m_vertexEditor = createJSEditor();
|
||||||
|
|
||||||
|
connect(
|
||||||
|
m_fragmentEditor,
|
||||||
|
&QPlainTextEdit::textChanged,
|
||||||
|
this,
|
||||||
|
&EffectShadersCodeEditor::fragmentValueChanged);
|
||||||
|
connect(
|
||||||
|
m_vertexEditor,
|
||||||
|
&QPlainTextEdit::textChanged,
|
||||||
|
this,
|
||||||
|
&EffectShadersCodeEditor::vertexValueChanged);
|
||||||
|
|
||||||
|
setupUIComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectShadersCodeEditor::~EffectShadersCodeEditor()
|
||||||
|
{
|
||||||
|
m_fragmentEditor->deleteLater();
|
||||||
|
m_vertexEditor->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::showWidget()
|
||||||
|
{
|
||||||
|
readAndApplyLiveUpdateSettings();
|
||||||
|
show();
|
||||||
|
raise();
|
||||||
|
m_vertexEditor->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::showWidget(int x, int y)
|
||||||
|
{
|
||||||
|
showWidget();
|
||||||
|
move(QPoint(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString EffectShadersCodeEditor::fragmentValue() const
|
||||||
|
{
|
||||||
|
if (!m_fragmentEditor)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return m_fragmentEditor->document()->toPlainText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::setFragmentValue(const QString &text)
|
||||||
|
{
|
||||||
|
if (m_fragmentEditor)
|
||||||
|
m_fragmentEditor->setEditorTextWithIndentation(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString EffectShadersCodeEditor::vertexValue() const
|
||||||
|
{
|
||||||
|
if (!m_vertexEditor)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return m_vertexEditor->document()->toPlainText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::setVertexValue(const QString &text)
|
||||||
|
{
|
||||||
|
if (m_vertexEditor)
|
||||||
|
m_vertexEditor->setEditorTextWithIndentation(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EffectShadersCodeEditor::liveUpdate() const
|
||||||
|
{
|
||||||
|
return m_liveUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::setLiveUpdate(bool liveUpdate)
|
||||||
|
{
|
||||||
|
if (m_liveUpdate == liveUpdate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_liveUpdate = liveUpdate;
|
||||||
|
writeLiveUpdateSettings();
|
||||||
|
|
||||||
|
emit liveUpdateChanged(m_liveUpdate);
|
||||||
|
|
||||||
|
if (m_liveUpdate)
|
||||||
|
emit rebakeRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectCodeEditorWidget *EffectShadersCodeEditor::createJSEditor()
|
||||||
|
{
|
||||||
|
static EffectCodeEditorFactory f;
|
||||||
|
TextEditor::BaseTextEditor *editor = qobject_cast<TextEditor::BaseTextEditor *>(
|
||||||
|
f.createEditor());
|
||||||
|
Q_ASSERT(editor);
|
||||||
|
|
||||||
|
editor->setParent(this);
|
||||||
|
|
||||||
|
EffectCodeEditorWidget *editorWidget = qobject_cast<EffectCodeEditorWidget *>(
|
||||||
|
editor->editorWidget());
|
||||||
|
Q_ASSERT(editorWidget);
|
||||||
|
|
||||||
|
editorWidget->setLineNumbersVisible(false);
|
||||||
|
editorWidget->setMarksVisible(false);
|
||||||
|
editorWidget->setCodeFoldingSupported(false);
|
||||||
|
editorWidget->setTabChangesFocus(true);
|
||||||
|
editorWidget->unregisterAutoCompletion();
|
||||||
|
editorWidget->setParent(this);
|
||||||
|
editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
|
||||||
|
|
||||||
|
return editorWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::setupUIComponents()
|
||||||
|
{
|
||||||
|
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
|
||||||
|
QTabWidget *tabWidget = new QTabWidget(this);
|
||||||
|
|
||||||
|
tabWidget->addTab(m_fragmentEditor, tr("Fragment Shader"));
|
||||||
|
tabWidget->addTab(m_vertexEditor, tr("Vertex Shader"));
|
||||||
|
|
||||||
|
verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
verticalLayout->addWidget(createToolbar());
|
||||||
|
verticalLayout->addWidget(tabWidget);
|
||||||
|
|
||||||
|
this->resize(660, 240);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::closeEvent(event);
|
||||||
|
|
||||||
|
if (!liveUpdate())
|
||||||
|
emit rebakeRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::writeLiveUpdateSettings()
|
||||||
|
{
|
||||||
|
m_settings->setValue(EFFECTCOMPOSER_LIVE_UPDATE_KEY, m_liveUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectShadersCodeEditor::readAndApplyLiveUpdateSettings()
|
||||||
|
{
|
||||||
|
bool liveUpdateStatus = m_settings->value(EFFECTCOMPOSER_LIVE_UPDATE_KEY, false).toBool();
|
||||||
|
|
||||||
|
setLiveUpdate(liveUpdateStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolBar *EffectShadersCodeEditor::createToolbar()
|
||||||
|
{
|
||||||
|
using QmlDesigner::Theme;
|
||||||
|
|
||||||
|
QToolBar *toolbar = new QToolBar(this);
|
||||||
|
|
||||||
|
toolbar->setFixedHeight(Theme::toolbarSize());
|
||||||
|
toolbar->setFloatable(false);
|
||||||
|
toolbar->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
toolbar->setStyleSheet(Theme::replaceCssColors(
|
||||||
|
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
|
||||||
|
|
||||||
|
QAction *liveUpdateButton
|
||||||
|
= toolbar->addAction(toolbarIcon(IconId::LiveUpdateIcon), tr("Live Update"));
|
||||||
|
liveUpdateButton->setCheckable(true);
|
||||||
|
connect(liveUpdateButton, &QAction::toggled, this, &EffectShadersCodeEditor::setLiveUpdate);
|
||||||
|
|
||||||
|
QAction *applyAction = toolbar->addAction(toolbarIcon(IconId::SyncIcon), tr("Apply"));
|
||||||
|
connect(applyAction, &QAction::triggered, this, &EffectShadersCodeEditor::rebakeRequested);
|
||||||
|
|
||||||
|
auto syncLive = [liveUpdateButton, applyAction](bool liveState) {
|
||||||
|
liveUpdateButton->setChecked(liveState);
|
||||||
|
applyAction->setDisabled(liveState);
|
||||||
|
};
|
||||||
|
|
||||||
|
connect(this, &EffectShadersCodeEditor::liveUpdateChanged, this, syncLive);
|
||||||
|
syncLive(liveUpdate());
|
||||||
|
|
||||||
|
toolbar->addAction(liveUpdateButton);
|
||||||
|
toolbar->addAction(applyAction);
|
||||||
|
|
||||||
|
return toolbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace EffectComposer
|
61
src/plugins/effectcomposer/effectshaderscodeeditor.h
Normal file
61
src/plugins/effectcomposer/effectshaderscodeeditor.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QSettings)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QToolBar)
|
||||||
|
|
||||||
|
namespace EffectComposer {
|
||||||
|
|
||||||
|
class EffectCodeEditorWidget;
|
||||||
|
|
||||||
|
class EffectShadersCodeEditor : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool liveUpdate READ liveUpdate WRITE setLiveUpdate NOTIFY liveUpdateChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
EffectShadersCodeEditor(const QString &title = tr("Untitled Editor"), QWidget *parent = nullptr);
|
||||||
|
~EffectShadersCodeEditor() override;
|
||||||
|
|
||||||
|
void showWidget();
|
||||||
|
void showWidget(int x, int y);
|
||||||
|
|
||||||
|
QString fragmentValue() const;
|
||||||
|
void setFragmentValue(const QString &text);
|
||||||
|
|
||||||
|
QString vertexValue() const;
|
||||||
|
void setVertexValue(const QString &text);
|
||||||
|
|
||||||
|
bool liveUpdate() const;
|
||||||
|
void setLiveUpdate(bool liveUpdate);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void liveUpdateChanged(bool);
|
||||||
|
void fragmentValueChanged();
|
||||||
|
void vertexValueChanged();
|
||||||
|
void rebakeRequested();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using QWidget::show;
|
||||||
|
EffectCodeEditorWidget *createJSEditor();
|
||||||
|
void setupUIComponents();
|
||||||
|
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeLiveUpdateSettings();
|
||||||
|
void readAndApplyLiveUpdateSettings();
|
||||||
|
QToolBar *createToolbar();
|
||||||
|
|
||||||
|
QSettings *m_settings = nullptr;
|
||||||
|
QPointer<EffectCodeEditorWidget> m_fragmentEditor;
|
||||||
|
QPointer<EffectCodeEditorWidget> m_vertexEditor;
|
||||||
|
|
||||||
|
bool m_liveUpdate = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace EffectComposer
|
@@ -57,6 +57,14 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS
|
|||||||
|
|
||||||
m_backendValue = new QmlDesigner::PropertyEditorValue(this);
|
m_backendValue = new QmlDesigner::PropertyEditorValue(this);
|
||||||
m_backendValue->setValue(value);
|
m_backendValue->setValue(value);
|
||||||
|
|
||||||
|
connect(m_backendValue, &QmlDesigner::PropertyEditorValue::dropCommitted,
|
||||||
|
this, [this](const QString &dropData) {
|
||||||
|
m_backendValue->setValue(dropData);
|
||||||
|
auto *model = QmlDesigner::QmlDesignerPlugin::instance()
|
||||||
|
->currentDesignDocument()->currentModel();
|
||||||
|
model->endDrag();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Uniform::Type Uniform::type() const
|
Uniform::Type Uniform::type() const
|
||||||
|
@@ -7,9 +7,10 @@
|
|||||||
#include <auxiliarydataproperties.h>
|
#include <auxiliarydataproperties.h>
|
||||||
#include <externaldependenciesinterface.h>
|
#include <externaldependenciesinterface.h>
|
||||||
#include <plaintexteditmodifier.h>
|
#include <plaintexteditmodifier.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <qmldesignerprojectmanager.h>
|
||||||
#include <rewriterview.h>
|
#include <rewriterview.h>
|
||||||
#include <signalhandlerproperty.h>
|
#include <signalhandlerproperty.h>
|
||||||
#include <qmldesignerplugin.h>
|
|
||||||
|
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/projectmanager.h>
|
#include <projectexplorer/projectmanager.h>
|
||||||
@@ -192,7 +193,9 @@ Qt::CheckState checkState(const std::vector<std::string> &a, const std::vector<s
|
|||||||
|
|
||||||
struct ModelBuilder
|
struct ModelBuilder
|
||||||
{
|
{
|
||||||
ModelBuilder(const QString &filePath, ExternalDependenciesInterface &externalDependencies)
|
ModelBuilder(const QString &filePath,
|
||||||
|
ExternalDependenciesInterface &externalDependencies,
|
||||||
|
[[maybe_unused]] ProjectStorageDependencies projectStorageDependencies)
|
||||||
{
|
{
|
||||||
const QString fileContent = fileToString(filePath);
|
const QString fileContent = fileToString(filePath);
|
||||||
if (fileContent.isEmpty()) {
|
if (fileContent.isEmpty()) {
|
||||||
@@ -209,7 +212,14 @@ struct ModelBuilder
|
|||||||
rewriter->setCheckLinkErrors(false);
|
rewriter->setCheckLinkErrors(false);
|
||||||
rewriter->setTextModifier(modifier.get());
|
rewriter->setTextModifier(modifier.get());
|
||||||
|
|
||||||
|
#ifdef QDS_USE_PROJECTSTORAGE
|
||||||
|
model = QmlDesigner::Model::create(projectStorageDependencies,
|
||||||
|
"Item",
|
||||||
|
{Import::createLibraryImport("QtQuick")},
|
||||||
|
filePath);
|
||||||
|
#else
|
||||||
model = QmlDesigner::Model::create("QtQuick.Item", 2, 1);
|
model = QmlDesigner::Model::create("QtQuick.Item", 2, 1);
|
||||||
|
#endif
|
||||||
model->setRewriterView(rewriter.get());
|
model->setRewriterView(rewriter.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,9 +231,12 @@ struct ModelBuilder
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
InsightModel::InsightModel(InsightView *view, ExternalDependenciesInterface &externalDependencies)
|
InsightModel::InsightModel(InsightView *view,
|
||||||
|
ExternalDependenciesInterface &externalDependencies,
|
||||||
|
QmlDesignerProjectManager &projectManager)
|
||||||
: m_insightView(view)
|
: m_insightView(view)
|
||||||
, m_externalDependencies(externalDependencies)
|
, m_externalDependencies(externalDependencies)
|
||||||
|
, m_projectManager(projectManager)
|
||||||
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
|
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
|
||||||
{
|
{
|
||||||
QObject::connect(ProjectExplorer::ProjectManager::instance(),
|
QObject::connect(ProjectExplorer::ProjectManager::instance(),
|
||||||
@@ -446,7 +459,9 @@ void InsightModel::setEnabled(bool value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies);
|
ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(),
|
||||||
|
m_externalDependencies,
|
||||||
|
m_projectManager.projectStorageDependencies());
|
||||||
|
|
||||||
if (!builder.model) {
|
if (!builder.model) {
|
||||||
qWarning() << "Could not create model" << m_mainQmlInfo.absoluteFilePath();
|
qWarning() << "Could not create model" << m_mainQmlInfo.absoluteFilePath();
|
||||||
@@ -613,7 +628,9 @@ int InsightModel::devicePixelRatio()
|
|||||||
|
|
||||||
void InsightModel::parseMainQml()
|
void InsightModel::parseMainQml()
|
||||||
{
|
{
|
||||||
ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies);
|
ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(),
|
||||||
|
m_externalDependencies,
|
||||||
|
m_projectManager.projectStorageDependencies());
|
||||||
|
|
||||||
if (!builder.model)
|
if (!builder.model)
|
||||||
return;
|
return;
|
||||||
|
@@ -39,7 +39,9 @@ class InsightModel : public QAbstractListModel
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InsightModel(InsightView *view, class ExternalDependenciesInterface &externalDependencies);
|
InsightModel(InsightView *view,
|
||||||
|
class ExternalDependenciesInterface &externalDependencies,
|
||||||
|
class QmlDesignerProjectManager &projectManager);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
@@ -109,6 +111,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
QPointer<InsightView> m_insightView;
|
QPointer<InsightView> m_insightView;
|
||||||
ExternalDependenciesInterface &m_externalDependencies;
|
ExternalDependenciesInterface &m_externalDependencies;
|
||||||
|
QmlDesignerProjectManager &m_projectManager;
|
||||||
|
|
||||||
Utils::FileSystemWatcher *m_fileSystemWatcher;
|
Utils::FileSystemWatcher *m_fileSystemWatcher;
|
||||||
|
|
||||||
|
@@ -20,7 +20,8 @@ class InsightPlugin final : public ExtensionSystem::IPlugin
|
|||||||
auto *designerPlugin = QmlDesignerPlugin::instance();
|
auto *designerPlugin = QmlDesignerPlugin::instance();
|
||||||
auto &viewManager = designerPlugin->viewManager();
|
auto &viewManager = designerPlugin->viewManager();
|
||||||
viewManager.registerView(std::make_unique<InsightView>(
|
viewManager.registerView(std::make_unique<InsightView>(
|
||||||
QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly()));
|
QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly(),
|
||||||
|
QmlDesignerPlugin::projectManagerForPluginInitializationOnly()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -14,9 +14,10 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
InsightView::InsightView(ExternalDependenciesInterface &externalDependencies)
|
InsightView::InsightView(ExternalDependenciesInterface &externalDependencies,
|
||||||
|
QmlDesignerProjectManager &projectManager)
|
||||||
: AbstractView(externalDependencies)
|
: AbstractView(externalDependencies)
|
||||||
, m_insightModel(std::make_unique<InsightModel>(this, externalDependencies))
|
, m_insightModel(std::make_unique<InsightModel>(this, externalDependencies, projectManager))
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_insightModel);
|
Q_ASSERT(m_insightModel);
|
||||||
}
|
}
|
||||||
|
@@ -15,13 +15,15 @@ namespace QmlDesigner {
|
|||||||
|
|
||||||
class InsightModel;
|
class InsightModel;
|
||||||
class InsightWidget;
|
class InsightWidget;
|
||||||
|
class QmlDesignerProjectManager;
|
||||||
|
|
||||||
class InsightView : public AbstractView
|
class InsightView : public AbstractView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit InsightView(ExternalDependenciesInterface &externalDependencies);
|
explicit InsightView(ExternalDependenciesInterface &externalDependencies,
|
||||||
|
QmlDesignerProjectManager &projectManager);
|
||||||
~InsightView() override;
|
~InsightView() override;
|
||||||
|
|
||||||
// AbstractView
|
// AbstractView
|
||||||
|
@@ -52,13 +52,14 @@ add_qtc_plugin(QmlDesigner
|
|||||||
QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
|
QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
|
||||||
Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg Sqlite Zip Qt::GuiPrivate
|
Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg Sqlite Zip Qt::GuiPrivate
|
||||||
PUBLIC_DEPENDS
|
PUBLIC_DEPENDS
|
||||||
QmlDesignerUtils QmlPuppetCommunication QmlDesignerCore
|
QmlDesignerUtils QmlPuppetCommunication QmlDesignerCore DesignSystem
|
||||||
DEFINES
|
DEFINES
|
||||||
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
|
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
|
||||||
SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner"
|
SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner"
|
||||||
$<$<BOOL:${USE_PROJECTSTORAGE}>:QDS_USE_PROJECTSTORAGE>
|
|
||||||
$<$<BOOL:${QTC_USE_QML_DESIGNER_LITE}>:QTC_USE_QML_DESIGNER_LITE>
|
$<$<BOOL:${QTC_USE_QML_DESIGNER_LITE}>:QTC_USE_QML_DESIGNER_LITE>
|
||||||
$<$<BOOL:${DETACH_DISABLED_VIEWS}>:DETACH_DISABLED_VIEWS>
|
$<$<BOOL:${DETACH_DISABLED_VIEWS}>:DETACH_DISABLED_VIEWS>
|
||||||
|
PUBLIC_DEFINES
|
||||||
|
$<$<BOOL:${USE_PROJECTSTORAGE}>:QDS_USE_PROJECTSTORAGE>
|
||||||
INCLUDES
|
INCLUDES
|
||||||
${CMAKE_CURRENT_LIST_DIR}/libs
|
${CMAKE_CURRENT_LIST_DIR}/libs
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components
|
${CMAKE_CURRENT_LIST_DIR}/components
|
||||||
@@ -725,14 +726,6 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
messagemodel.h
|
messagemodel.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
|
||||||
SOURCES_PREFIX components/designsystem
|
|
||||||
SOURCES
|
|
||||||
dsconstants.h
|
|
||||||
dsthememanager.h dsthememanager.cpp
|
|
||||||
dsthemegroup.cpp dsthemegroup.h
|
|
||||||
)
|
|
||||||
|
|
||||||
add_qtc_plugin(assetexporterplugin
|
add_qtc_plugin(assetexporterplugin
|
||||||
PLUGIN_CLASS AssetExporterPlugin
|
PLUGIN_CLASS AssetExporterPlugin
|
||||||
CONDITION TARGET QmlDesigner
|
CONDITION TARGET QmlDesigner
|
||||||
|
@@ -85,13 +85,13 @@ private:
|
|||||||
std::atomic<bool> m_quitDumper;
|
std::atomic<bool> m_quitDumper;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AssetExporter::AssetExporter(AssetExporterView *view,
|
||||||
|
ProjectExplorer::Project *project,
|
||||||
AssetExporter::AssetExporter(AssetExporterView *view, ProjectExplorer::Project *project, QObject *parent) :
|
ProjectStorageDependencies projectStorageDependencies)
|
||||||
QObject(parent),
|
: m_currentState(*this)
|
||||||
m_currentState(*this),
|
, m_project(project)
|
||||||
m_project(project),
|
, m_view(view)
|
||||||
m_view(view)
|
, m_projectStorageDependencies{projectStorageDependencies}
|
||||||
{
|
{
|
||||||
connect(m_view, &AssetExporterView::loadingFinished, this, &AssetExporter::onQmlFileLoaded);
|
connect(m_view, &AssetExporterView::loadingFinished, this, &AssetExporter::onQmlFileLoaded);
|
||||||
connect(m_view, &AssetExporterView::loadingError, this, &AssetExporter::notifyLoadError);
|
connect(m_view, &AssetExporterView::loadingError, this, &AssetExporter::notifyLoadError);
|
||||||
@@ -260,7 +260,14 @@ void AssetExporter::preprocessQmlFile(const Utils::FilePath &path)
|
|||||||
{
|
{
|
||||||
// Load the QML file and assign UUIDs to items having none.
|
// Load the QML file and assign UUIDs to items having none.
|
||||||
// Meanwhile cache the Component UUIDs as well
|
// Meanwhile cache the Component UUIDs as well
|
||||||
ModelPointer model(Model::create("Item", 2, 7));
|
#ifdef QDS_USE_PROJECTSTORAGE
|
||||||
|
ModelPointer model = Model::create(m_projectStorageDependencies,
|
||||||
|
"Item",
|
||||||
|
{Import::createLibraryImport("QtQuick")},
|
||||||
|
path.path());
|
||||||
|
#else
|
||||||
|
ModelPointer model = Model::create("Item", 2, 7);
|
||||||
|
#endif
|
||||||
Utils::FileReader reader;
|
Utils::FileReader reader;
|
||||||
if (!reader.fetch(path)) {
|
if (!reader.fetch(path)) {
|
||||||
ExportNotification::addError(tr("Cannot preprocess file: %1. Error %2")
|
ExportNotification::addError(tr("Cannot preprocess file: %1. Error %2")
|
||||||
|
@@ -32,8 +32,9 @@ public:
|
|||||||
ExportingDone
|
ExportingDone
|
||||||
};
|
};
|
||||||
|
|
||||||
AssetExporter(AssetExporterView *view, ProjectExplorer::Project *project,
|
AssetExporter(AssetExporterView *view,
|
||||||
QObject *parent = nullptr);
|
ProjectExplorer::Project *project,
|
||||||
|
ProjectStorageDependencies projectStorageDependencies);
|
||||||
~AssetExporter();
|
~AssetExporter();
|
||||||
|
|
||||||
void exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath,
|
void exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath,
|
||||||
@@ -89,6 +90,7 @@ private:
|
|||||||
QHash<QString, QString> m_componentUuidCache;
|
QHash<QString, QString> m_componentUuidCache;
|
||||||
QSet<QByteArray> m_usedHashes;
|
QSet<QByteArray> m_usedHashes;
|
||||||
QHash<QString, QPixmap> m_assets;
|
QHash<QString, QPixmap> m_assets;
|
||||||
|
ProjectStorageDependencies m_projectStorageDependencies;
|
||||||
std::unique_ptr<AssetDumper> m_assetDumper;
|
std::unique_ptr<AssetDumper> m_assetDumper;
|
||||||
bool m_cancelled = false;
|
bool m_cancelled = false;
|
||||||
};
|
};
|
||||||
|
@@ -3,12 +3,13 @@
|
|||||||
|
|
||||||
#include "assetexporterplugin.h"
|
#include "assetexporterplugin.h"
|
||||||
|
|
||||||
#include "assetexportpluginconstants.h"
|
|
||||||
#include "assetexportdialog.h"
|
#include "assetexportdialog.h"
|
||||||
#include "assetexporter.h"
|
#include "assetexporter.h"
|
||||||
#include "assetexporterview.h"
|
#include "assetexporterview.h"
|
||||||
#include "filepathmodel.h"
|
#include "assetexportpluginconstants.h"
|
||||||
#include "componentexporter.h"
|
#include "componentexporter.h"
|
||||||
|
#include "filepathmodel.h"
|
||||||
|
#include <qmldesignerprojectmanager.h>
|
||||||
|
|
||||||
#include "dumpers/itemnodedumper.h"
|
#include "dumpers/itemnodedumper.h"
|
||||||
#include "dumpers/textnodedumper.h"
|
#include "dumpers/textnodedumper.h"
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
AssetExporterPlugin::AssetExporterPlugin()
|
AssetExporterPlugin::AssetExporterPlugin()
|
||||||
|
: m_projectManager{QmlDesigner::QmlDesignerPlugin::projectManagerForPluginInitializationOnly()}
|
||||||
{
|
{
|
||||||
ProjectExplorer::TaskHub::addCategory({Constants::TASK_CATEGORY_ASSET_EXPORT,
|
ProjectExplorer::TaskHub::addCategory({Constants::TASK_CATEGORY_ASSET_EXPORT,
|
||||||
tr("Asset Export"),
|
tr("Asset Export"),
|
||||||
@@ -44,6 +46,7 @@ AssetExporterPlugin::AssetExporterPlugin()
|
|||||||
false});
|
false});
|
||||||
|
|
||||||
auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance();
|
auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance();
|
||||||
|
|
||||||
auto &viewManager = designerPlugin->viewManager();
|
auto &viewManager = designerPlugin->viewManager();
|
||||||
m_view = viewManager.registerView(std::make_unique<AssetExporterView>(
|
m_view = viewManager.registerView(std::make_unique<AssetExporterView>(
|
||||||
designerPlugin->externalDependenciesForPluginInitializationOnly()));
|
designerPlugin->externalDependenciesForPluginInitializationOnly()));
|
||||||
@@ -79,7 +82,7 @@ void AssetExporterPlugin::onExport()
|
|||||||
if (!exportDir.parentDir().isEmpty())
|
if (!exportDir.parentDir().isEmpty())
|
||||||
exportDir = exportDir.parentDir();
|
exportDir = exportDir.parentDir();
|
||||||
exportDir = exportDir.pathAppended(startupProject->displayName() + "_export");
|
exportDir = exportDir.pathAppended(startupProject->displayName() + "_export");
|
||||||
AssetExporter assetExporter(m_view, startupProject);
|
AssetExporter assetExporter(m_view, startupProject, m_projectManager.projectStorageDependencies());
|
||||||
AssetExportDialog assetExporterDialog(exportDir, assetExporter, model);
|
AssetExportDialog assetExporterDialog(exportDir, assetExporter, model);
|
||||||
assetExporterDialog.exec();
|
assetExporterDialog.exec();
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,7 @@ private:
|
|||||||
void updateActions();
|
void updateActions();
|
||||||
|
|
||||||
AssetExporterView *m_view = nullptr;
|
AssetExporterView *m_view = nullptr;
|
||||||
|
class QmlDesignerProjectManager &m_projectManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -21,19 +21,6 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Q_LOGGING_CATEGORY(loggerInfo, "qtc.designer.assetExportPlugin.modelExporter", QtInfoMsg)
|
Q_LOGGING_CATEGORY(loggerInfo, "qtc.designer.assetExportPlugin.modelExporter", QtInfoMsg)
|
||||||
|
|
||||||
static QByteArrayList populateLineage(const QmlDesigner::ModelNode &node)
|
|
||||||
{
|
|
||||||
QByteArrayList lineage;
|
|
||||||
if (!node.isValid() || node.type().isEmpty())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
for (auto &info : node.metaInfo().prototypes())
|
|
||||||
lineage.append(info.typeName());
|
|
||||||
|
|
||||||
return lineage;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
@@ -78,10 +65,9 @@ const QString &Component::name() const
|
|||||||
|
|
||||||
NodeDumper *Component::createNodeDumper(const ModelNode &node) const
|
NodeDumper *Component::createNodeDumper(const ModelNode &node) const
|
||||||
{
|
{
|
||||||
QByteArrayList lineage = populateLineage(node);
|
|
||||||
std::unique_ptr<NodeDumper> reader;
|
std::unique_ptr<NodeDumper> reader;
|
||||||
for (auto &dumperCreator: m_readers) {
|
for (auto &dumperCreator: m_readers) {
|
||||||
std::unique_ptr<NodeDumper> r(dumperCreator->instance(lineage, node));
|
std::unique_ptr<NodeDumper> r(dumperCreator->instance(node));
|
||||||
if (r->isExportable()) {
|
if (r->isExportable()) {
|
||||||
if (reader) {
|
if (reader) {
|
||||||
if (reader->priority() < r->priority())
|
if (reader->priority() < r->priority())
|
||||||
|
@@ -27,7 +27,7 @@ class NodeDumperCreatorBase
|
|||||||
public:
|
public:
|
||||||
virtual ~NodeDumperCreatorBase() {}
|
virtual ~NodeDumperCreatorBase() {}
|
||||||
protected:
|
protected:
|
||||||
virtual NodeDumper *instance(const QByteArrayList &, const ModelNode &) const = 0;
|
virtual NodeDumper *instance(const ModelNode &) const = 0;
|
||||||
friend Component;
|
friend Component;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,9 +39,7 @@ public:
|
|||||||
~NodeDumperCreator() = default;
|
~NodeDumperCreator() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NodeDumper *instance(const QByteArrayList &lineage, const ModelNode &node) const {
|
NodeDumper *instance(const ModelNode &node) const { return new T(node); }
|
||||||
return new T(lineage, node);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} //Internal
|
} //Internal
|
||||||
|
|
||||||
|
@@ -14,18 +14,18 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
using namespace Constants;
|
using namespace Constants;
|
||||||
AssetNodeDumper::AssetNodeDumper(const QByteArrayList &lineage, const ModelNode &node) :
|
|
||||||
ItemNodeDumper(lineage, node)
|
AssetNodeDumper::AssetNodeDumper(const ModelNode &node)
|
||||||
|
: ItemNodeDumper(node)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetNodeDumper::isExportable() const
|
bool AssetNodeDumper::isExportable() const
|
||||||
{
|
{
|
||||||
auto hasType = [this](const QByteArray &type) {
|
auto qtQuickImageMetaInfo = model()->qtQuickImageMetaInfo();
|
||||||
return lineage().contains(type);
|
auto qtQuickRectangleMetaInfo = model()->qtQuickRectangleMetaInfo();
|
||||||
};
|
return metaInfo().isBasedOn(qtQuickImageMetaInfo, qtQuickRectangleMetaInfo);
|
||||||
return hasType("QtQuick.Image") || hasType("QtQuick.Rectangle");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject AssetNodeDumper::json(Component &component) const
|
QJsonObject AssetNodeDumper::json(Component &component) const
|
||||||
|
@@ -10,7 +10,7 @@ class Component;
|
|||||||
class AssetNodeDumper : public ItemNodeDumper
|
class AssetNodeDumper : public ItemNodeDumper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AssetNodeDumper(const QByteArrayList &lineage, const ModelNode &node);
|
AssetNodeDumper(const ModelNode &node);
|
||||||
~AssetNodeDumper() override = default;
|
~AssetNodeDumper() override = default;
|
||||||
|
|
||||||
bool isExportable() const override;
|
bool isExportable() const override;
|
||||||
|
@@ -22,16 +22,16 @@ static QString capitalize(const QString &str)
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
using namespace Constants;
|
using namespace Constants;
|
||||||
ItemNodeDumper::ItemNodeDumper(const QByteArrayList &lineage,
|
|
||||||
const ModelNode &node) :
|
ItemNodeDumper::ItemNodeDumper(const ModelNode &node)
|
||||||
NodeDumper(lineage, node)
|
: NodeDumper(node)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QmlDesigner::ItemNodeDumper::isExportable() const
|
bool QmlDesigner::ItemNodeDumper::isExportable() const
|
||||||
{
|
{
|
||||||
return lineage().contains("QtQuick.Item");
|
return metaInfo().isQtQuickItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject QmlDesigner::ItemNodeDumper::json([[maybe_unused]] QmlDesigner::Component &component) const
|
QJsonObject QmlDesigner::ItemNodeDumper::json([[maybe_unused]] QmlDesigner::Component &component) const
|
||||||
|
@@ -11,7 +11,7 @@ class Component;
|
|||||||
class ItemNodeDumper : public NodeDumper
|
class ItemNodeDumper : public NodeDumper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ItemNodeDumper(const QByteArrayList &lineage, const ModelNode &node);
|
ItemNodeDumper(const ModelNode &node);
|
||||||
|
|
||||||
~ItemNodeDumper() override = default;
|
~ItemNodeDumper() override = default;
|
||||||
|
|
||||||
|
@@ -6,10 +6,11 @@
|
|||||||
#include <auxiliarydataproperties.h>
|
#include <auxiliarydataproperties.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
NodeDumper::NodeDumper(const QByteArrayList &lineage, const ModelNode &node) :
|
NodeDumper::NodeDumper(const ModelNode &node)
|
||||||
m_node(node),
|
: m_node(node)
|
||||||
m_objectNode(node),
|
, m_objectNode(node)
|
||||||
m_lineage(lineage)
|
, m_metaInfo(node.metaInfo())
|
||||||
|
, m_model{node.model()}
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ class ModelNode;
|
|||||||
class NodeDumper
|
class NodeDumper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodeDumper(const QByteArrayList &lineage, const ModelNode &node);
|
NodeDumper(const ModelNode &node);
|
||||||
|
|
||||||
virtual ~NodeDumper() = default;
|
virtual ~NodeDumper() = default;
|
||||||
|
|
||||||
@@ -22,16 +22,19 @@ public:
|
|||||||
virtual bool isExportable() const = 0;
|
virtual bool isExportable() const = 0;
|
||||||
virtual QJsonObject json(Component& component) const = 0;
|
virtual QJsonObject json(Component& component) const = 0;
|
||||||
|
|
||||||
const QByteArrayList& lineage() const { return m_lineage; }
|
const NodeMetaInfo &metaInfo() const { return m_metaInfo; }
|
||||||
const QmlObjectNode& objectNode() const { return m_objectNode; }
|
const QmlObjectNode& objectNode() const { return m_objectNode; }
|
||||||
QVariant propertyValue(const PropertyName &name) const;
|
QVariant propertyValue(const PropertyName &name) const;
|
||||||
QString uuid() const;
|
QString uuid() const;
|
||||||
|
|
||||||
|
Model *model() const { return m_model; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const ModelNode &m_node;
|
const ModelNode &m_node;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QmlObjectNode m_objectNode;
|
QmlObjectNode m_objectNode;
|
||||||
QByteArrayList m_lineage;
|
NodeMetaInfo m_metaInfo;
|
||||||
|
Model *m_model = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,8 @@
|
|||||||
#include "textnodedumper.h"
|
#include "textnodedumper.h"
|
||||||
#include "assetexportpluginconstants.h"
|
#include "assetexportpluginconstants.h"
|
||||||
|
|
||||||
|
#include <model.h>
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QFontInfo>
|
#include <QFontInfo>
|
||||||
#include <QFontMetricsF>
|
#include <QFontMetricsF>
|
||||||
@@ -35,18 +37,18 @@ QString toJsonAlignEnum(QString value) {
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
using namespace Constants;
|
using namespace Constants;
|
||||||
TextNodeDumper::TextNodeDumper(const QByteArrayList &lineage, const ModelNode &node) :
|
|
||||||
ItemNodeDumper(lineage, node)
|
TextNodeDumper::TextNodeDumper(const ModelNode &node)
|
||||||
|
: ItemNodeDumper(node)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextNodeDumper::isExportable() const
|
bool TextNodeDumper::isExportable() const
|
||||||
{
|
{
|
||||||
const QByteArrayList &baseClasses = lineage();
|
auto qtQuickTextMetaInfo = model()->qtQuickTextMetaInfo();
|
||||||
return std::any_of(baseClasses.cbegin(), baseClasses.cend(), [](const QByteArray &type) {
|
auto qtQuickControlsLabelMetaInfo = model()->qtQuickControlsLabelMetaInfo();
|
||||||
return type == "QtQuick.Text" || type == "QtQuick.Controls.Label";
|
return metaInfo().isBasedOn(qtQuickTextMetaInfo, qtQuickControlsLabelMetaInfo);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject TextNodeDumper::json([[maybe_unused]] Component &component) const
|
QJsonObject TextNodeDumper::json([[maybe_unused]] Component &component) const
|
||||||
|
@@ -10,7 +10,7 @@ class Component;
|
|||||||
class TextNodeDumper : public ItemNodeDumper
|
class TextNodeDumper : public ItemNodeDumper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextNodeDumper(const QByteArrayList &lineage, const ModelNode &node);
|
TextNodeDumper(const ModelNode &node);
|
||||||
~TextNodeDumper() override = default;
|
~TextNodeDumper() override = default;
|
||||||
|
|
||||||
bool isExportable() const override;
|
bool isExportable() const override;
|
||||||
|
@@ -41,7 +41,7 @@ void AssetsLibraryModel::createBackendModel()
|
|||||||
|
|
||||||
QObject::connect(m_sourceFsModel, &QFileSystemModel::directoryLoaded, this,
|
QObject::connect(m_sourceFsModel, &QFileSystemModel::directoryLoaded, this,
|
||||||
[this]([[maybe_unused]] const QString &dir) {
|
[this]([[maybe_unused]] const QString &dir) {
|
||||||
syncHasFiles();
|
syncIsEmpty();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_fileWatcher = new Utils::FileSystemWatcher(parent());
|
m_fileWatcher = new Utils::FileSystemWatcher(parent());
|
||||||
@@ -202,7 +202,7 @@ bool AssetsLibraryModel::isSameOrDescendantPath(const QUrl &source, const QStrin
|
|||||||
Utils::FilePath srcPath = Utils::FilePath::fromUrl(source);
|
Utils::FilePath srcPath = Utils::FilePath::fromUrl(source);
|
||||||
Utils::FilePath targetPath = Utils::FilePath::fromString(target);
|
Utils::FilePath targetPath = Utils::FilePath::fromString(target);
|
||||||
|
|
||||||
return targetPath.isChildOf(srcPath);
|
return srcPath == targetPath || targetPath.isChildOf(srcPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
@@ -224,41 +224,20 @@ bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetsLibraryModel::checkHasFiles(const QModelIndex &parentIdx) const
|
void AssetsLibraryModel::setIsEmpty(bool value)
|
||||||
{
|
{
|
||||||
if (!parentIdx.isValid())
|
if (m_isEmpty != value) {
|
||||||
return false;
|
m_isEmpty = value;
|
||||||
|
emit isEmptyChanged();
|
||||||
const int rowCount = this->rowCount(parentIdx);
|
|
||||||
for (int i = 0; i < rowCount; ++i) {
|
|
||||||
auto newIdx = this->index(i, 0, parentIdx);
|
|
||||||
if (!isDirectory(newIdx))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (checkHasFiles(newIdx))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsLibraryModel::setHasFiles(bool value)
|
|
||||||
{
|
|
||||||
if (m_hasFiles != value) {
|
|
||||||
m_hasFiles = value;
|
|
||||||
emit hasFilesChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetsLibraryModel::checkHasFiles() const
|
void AssetsLibraryModel::syncIsEmpty()
|
||||||
{
|
{
|
||||||
auto rootIdx = indexForPath(m_rootPath);
|
QModelIndex rootIdx = indexForPath(m_rootPath);
|
||||||
return checkHasFiles(rootIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsLibraryModel::syncHasFiles()
|
bool hasContent = rowCount(rootIdx);
|
||||||
{
|
setIsEmpty(!hasContent);
|
||||||
setHasFiles(checkHasFiles());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsLibraryModel::setRootPath(const QString &newPath)
|
void AssetsLibraryModel::setRootPath(const QString &newPath)
|
||||||
|
@@ -23,7 +23,7 @@ public:
|
|||||||
void setRootPath(const QString &newPath);
|
void setRootPath(const QString &newPath);
|
||||||
void setSearchText(const QString &searchText);
|
void setSearchText(const QString &searchText);
|
||||||
|
|
||||||
Q_PROPERTY(bool hasFiles READ hasFiles NOTIFY hasFilesChanged)
|
Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged)
|
||||||
|
|
||||||
Q_INVOKABLE QString rootPath() const;
|
Q_INVOKABLE QString rootPath() const;
|
||||||
Q_INVOKABLE QString filePath(const QModelIndex &index) const;
|
Q_INVOKABLE QString filePath(const QModelIndex &index) const;
|
||||||
@@ -36,7 +36,7 @@ public:
|
|||||||
Q_INVOKABLE QModelIndex parentDirIndex(const QString &path) const;
|
Q_INVOKABLE QModelIndex parentDirIndex(const QString &path) const;
|
||||||
Q_INVOKABLE QModelIndex parentDirIndex(const QModelIndex &index) const;
|
Q_INVOKABLE QModelIndex parentDirIndex(const QModelIndex &index) const;
|
||||||
Q_INVOKABLE QString parentDirPath(const QString &path) const;
|
Q_INVOKABLE QString parentDirPath(const QString &path) const;
|
||||||
Q_INVOKABLE void syncHasFiles();
|
Q_INVOKABLE void syncIsEmpty();
|
||||||
|
|
||||||
Q_INVOKABLE QList<QModelIndex> parentIndices(const QModelIndex &index) const;
|
Q_INVOKABLE QList<QModelIndex> parentIndices(const QModelIndex &index) const;
|
||||||
Q_INVOKABLE bool indexIsValid(const QModelIndex &index) const;
|
Q_INVOKABLE bool indexIsValid(const QModelIndex &index) const;
|
||||||
@@ -58,29 +58,27 @@ public:
|
|||||||
return std::min(result, 1);
|
return std::min(result, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasFiles() const { return m_hasFiles; }
|
bool isEmpty() const { return m_isEmpty; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void directoryLoaded(const QString &path);
|
void directoryLoaded(const QString &path);
|
||||||
void rootPathChanged();
|
void rootPathChanged();
|
||||||
void hasFilesChanged();
|
void isEmptyChanged();
|
||||||
void fileChanged(const QString &path);
|
void fileChanged(const QString &path);
|
||||||
void effectsDeleted(const QStringList &effectNames);
|
void effectsDeleted(const QStringList &effectNames);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setHasFiles(bool value);
|
void setIsEmpty(bool value);
|
||||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
void resetModel();
|
void resetModel();
|
||||||
void createBackendModel();
|
void createBackendModel();
|
||||||
void destroyBackendModel();
|
void destroyBackendModel();
|
||||||
bool checkHasFiles(const QModelIndex &parentIdx) const;
|
|
||||||
bool checkHasFiles() const;
|
|
||||||
|
|
||||||
QString m_searchText;
|
QString m_searchText;
|
||||||
QString m_rootPath;
|
QString m_rootPath;
|
||||||
QFileSystemModel *m_sourceFsModel = nullptr;
|
QFileSystemModel *m_sourceFsModel = nullptr;
|
||||||
bool m_hasFiles = false;
|
bool m_isEmpty = true;
|
||||||
Utils::FileSystemWatcher *m_fileWatcher = nullptr;
|
Utils::FileSystemWatcher *m_fileWatcher = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
#include "assetslibrarymodel.h"
|
#include "assetslibrarymodel.h"
|
||||||
#include "assetslibraryview.h"
|
#include "assetslibraryview.h"
|
||||||
|
|
||||||
|
#include <createtexture.h>
|
||||||
#include <designeractionmanager.h>
|
#include <designeractionmanager.h>
|
||||||
#include <designerpaths.h>
|
#include <designerpaths.h>
|
||||||
#include <designmodewidget.h>
|
#include <designmodewidget.h>
|
||||||
@@ -102,7 +103,6 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
|
|||||||
, m_assetsIconProvider{new AssetsLibraryIconProvider(synchronousFontImageCache)}
|
, m_assetsIconProvider{new AssetsLibraryIconProvider(synchronousFontImageCache)}
|
||||||
, m_assetsModel{new AssetsLibraryModel(this)}
|
, m_assetsModel{new AssetsLibraryModel(this)}
|
||||||
, m_assetsView{view}
|
, m_assetsView{view}
|
||||||
, m_createTextures{view}
|
|
||||||
, m_assetsWidget{Utils::makeUniqueObjectPtr<StudioQuickWidget>(this)}
|
, m_assetsWidget{Utils::makeUniqueObjectPtr<StudioQuickWidget>(this)}
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Assets Library", "Title of assets library widget"));
|
setWindowTitle(tr("Assets Library", "Title of assets library widget"));
|
||||||
@@ -237,18 +237,20 @@ int AssetsLibraryWidget::qtVersion() const
|
|||||||
void AssetsLibraryWidget::addTextures(const QStringList &filePaths)
|
void AssetsLibraryWidget::addTextures(const QStringList &filePaths)
|
||||||
{
|
{
|
||||||
m_assetsView->executeInTransaction(__FUNCTION__, [&] {
|
m_assetsView->executeInTransaction(__FUNCTION__, [&] {
|
||||||
m_createTextures.execute(filePaths,
|
CreateTexture(m_assetsView)
|
||||||
AddTextureMode::Texture,
|
.execute(filePaths,
|
||||||
Utils3D::active3DSceneId(m_assetsView->model()));
|
AddTextureMode::Texture,
|
||||||
|
Utils3D::active3DSceneId(m_assetsView->model()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsLibraryWidget::addLightProbe(const QString &filePath)
|
void AssetsLibraryWidget::addLightProbe(const QString &filePath)
|
||||||
{
|
{
|
||||||
m_assetsView->executeInTransaction(__FUNCTION__, [&] {
|
m_assetsView->executeInTransaction(__FUNCTION__, [&] {
|
||||||
m_createTextures.execute({filePath},
|
CreateTexture(m_assetsView)
|
||||||
AddTextureMode::LightProbe,
|
.execute(filePath,
|
||||||
Utils3D::active3DSceneId(m_assetsView->model()));
|
AddTextureMode::LightProbe,
|
||||||
|
Utils3D::active3DSceneId(m_assetsView->model()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,8 +259,9 @@ void AssetsLibraryWidget::updateContextMenuActionsEnableState()
|
|||||||
setHasMaterialLibrary(Utils3D::materialLibraryNode(m_assetsView).isValid()
|
setHasMaterialLibrary(Utils3D::materialLibraryNode(m_assetsView).isValid()
|
||||||
&& m_assetsView->model()->hasImport("QtQuick3D"));
|
&& m_assetsView->model()->hasImport("QtQuick3D"));
|
||||||
|
|
||||||
ModelNode activeSceneEnv = m_createTextures.resolveSceneEnv(
|
ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(m_assetsView,
|
||||||
Utils3D::active3DSceneId(m_assetsView->model()));
|
Utils3D::active3DSceneId(
|
||||||
|
m_assetsView->model()));
|
||||||
setHasSceneEnv(activeSceneEnv.isValid());
|
setHasSceneEnv(activeSceneEnv.isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,11 +397,11 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList<QUrl> &urls, const QStrin
|
|||||||
if (destDir.isFile())
|
if (destDir.isFile())
|
||||||
destDir = destDir.parentDir();
|
destDir = destDir.parentDir();
|
||||||
|
|
||||||
QMessageBox mb;
|
QMessageBox msgBox;
|
||||||
mb.setInformativeText("What would you like to do with the existing asset?");
|
msgBox.setInformativeText("What would you like to do with the existing asset?");
|
||||||
mb.addButton("Keep Both", QMessageBox::AcceptRole);
|
msgBox.addButton("Keep Both", QMessageBox::AcceptRole);
|
||||||
mb.addButton("Replace", QMessageBox::ResetRole);
|
msgBox.addButton("Replace", QMessageBox::ResetRole);
|
||||||
mb.addButton("Cancel", QMessageBox::RejectRole);
|
msgBox.addButton("Cancel", QMessageBox::RejectRole);
|
||||||
|
|
||||||
for (const QUrl &url : urls) {
|
for (const QUrl &url : urls) {
|
||||||
Utils::FilePath src = Utils::FilePath::fromUrl(url);
|
Utils::FilePath src = Utils::FilePath::fromUrl(url);
|
||||||
@@ -408,9 +411,9 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList<QUrl> &urls, const QStrin
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (dest.exists()) {
|
if (dest.exists()) {
|
||||||
mb.setText("An asset named " + dest.fileName() + " already exists.");
|
msgBox.setText("An asset named " + dest.fileName() + " already exists.");
|
||||||
mb.exec();
|
msgBox.exec();
|
||||||
int userAction = mb.buttonRole(mb.clickedButton());
|
int userAction = msgBox.buttonRole(msgBox.clickedButton());
|
||||||
|
|
||||||
if (userAction == QMessageBox::AcceptRole) { // "Keep Both"
|
if (userAction == QMessageBox::AcceptRole) { // "Keep Both"
|
||||||
dest = Utils::FilePath::fromString(UniqueName::generatePath(dest.toString()));
|
dest = Utils::FilePath::fromString(UniqueName::generatePath(dest.toString()));
|
||||||
@@ -424,8 +427,13 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList<QUrl> &urls, const QStrin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!src.renameFile(dest))
|
if (!src.renameFile(dest) && src.isDir()) {
|
||||||
qWarning() << __FUNCTION__ << "Failed to move asset from" << src << "to" << dest;
|
QMessageBox errBox;
|
||||||
|
QString message = QString("Failed to move folder \"%1\".\nThe folder might contain subfolders or one of its files is in use.")
|
||||||
|
.arg(src.fileName());
|
||||||
|
errBox.setInformativeText(message);
|
||||||
|
errBox.exec();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_assetsView->model())
|
if (m_assetsView->model())
|
||||||
@@ -439,7 +447,7 @@ QList<QToolButton *> AssetsLibraryWidget::createToolBarWidgets()
|
|||||||
|
|
||||||
void AssetsLibraryWidget::handleSearchFilterChanged(const QString &filterText)
|
void AssetsLibraryWidget::handleSearchFilterChanged(const QString &filterText)
|
||||||
{
|
{
|
||||||
if (filterText == m_filterText || (!m_assetsModel->hasFiles()
|
if (filterText == m_filterText || (m_assetsModel->isEmpty()
|
||||||
&& filterText.contains(m_filterText, Qt::CaseInsensitive)))
|
&& filterText.contains(m_filterText, Qt::CaseInsensitive)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "createtexture.h"
|
|
||||||
#include "previewtooltipbackend.h"
|
#include "previewtooltipbackend.h"
|
||||||
|
|
||||||
#include <coreplugin/icontext.h>
|
#include <coreplugin/icontext.h>
|
||||||
@@ -135,7 +134,6 @@ private:
|
|||||||
AssetsLibraryIconProvider *m_assetsIconProvider = nullptr;
|
AssetsLibraryIconProvider *m_assetsIconProvider = nullptr;
|
||||||
AssetsLibraryModel *m_assetsModel = nullptr;
|
AssetsLibraryModel *m_assetsModel = nullptr;
|
||||||
AssetsLibraryView *m_assetsView = nullptr;
|
AssetsLibraryView *m_assetsView = nullptr;
|
||||||
CreateTextures m_createTextures = nullptr;
|
|
||||||
|
|
||||||
Utils::UniqueObjectPtr<StudioQuickWidget> m_assetsWidget;
|
Utils::UniqueObjectPtr<StudioQuickWidget> m_assetsWidget;
|
||||||
std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
|
std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
|
||||||
|
@@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include <qmljstools/qmljsindenter.h>
|
#include <qmljstools/qmljsindenter.h>
|
||||||
|
|
||||||
#include <utils/fancylineedit.h>
|
|
||||||
#include <utils/mimeconstants.h>
|
#include <utils/mimeconstants.h>
|
||||||
#include <utils/transientscroll.h>
|
#include <utils/transientscroll.h>
|
||||||
|
|
||||||
|
@@ -77,6 +77,7 @@ void BundleHelper::createImporter()
|
|||||||
newNode.simplifiedTypeName(), "node"));
|
newNode.simplifiedTypeName(), "node"));
|
||||||
m_view->clearSelectedModelNodes();
|
m_view->clearSelectedModelNodes();
|
||||||
m_view->selectModelNode(newNode);
|
m_view->selectModelNode(newNode);
|
||||||
|
m_view->resetPuppet();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -104,6 +105,7 @@ void BundleHelper::createImporter()
|
|||||||
newNode.simplifiedTypeName(), "node"));
|
newNode.simplifiedTypeName(), "node"));
|
||||||
m_view->clearSelectedModelNodes();
|
m_view->clearSelectedModelNodes();
|
||||||
m_view->selectModelNode(newNode);
|
m_view->selectModelNode(newNode);
|
||||||
|
m_view->resetPuppet();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -135,8 +137,16 @@ void BundleHelper::importBundleToProject()
|
|||||||
" of Qt Design Studio"));
|
" of Qt Design Studio"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString bundleId = importedJsonObj.value("id").toString();
|
QString bundleId = importedJsonObj.value("id").toString();
|
||||||
|
|
||||||
|
bool hasQuick3DImport = m_view->model()->hasImport("QtQuick3D");
|
||||||
|
|
||||||
|
if (!hasQuick3DImport) {
|
||||||
|
Import import = Import::createLibraryImport("QtQuick3D");
|
||||||
|
m_view->model()->changeImports({import}, {});
|
||||||
|
}
|
||||||
|
|
||||||
QTemporaryDir tempDir;
|
QTemporaryDir tempDir;
|
||||||
QTC_ASSERT(tempDir.isValid(), return);
|
QTC_ASSERT(tempDir.isValid(), return);
|
||||||
auto bundlePath = Utils::FilePath::fromString(tempDir.path());
|
auto bundlePath = Utils::FilePath::fromString(tempDir.path());
|
||||||
|
@@ -114,10 +114,10 @@ ModelNode CreateTexture::execute(const QString &filePath, AddTextureMode mode, i
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (mode == AddTextureMode::LightProbe && sceneId != -1)
|
if (mode == AddTextureMode::LightProbe && sceneId != -1)
|
||||||
assignTextureAsLightProbe(texture, sceneId);
|
Utils3D::assignTextureAsLightProbe(m_view, texture, sceneId);
|
||||||
|
|
||||||
QTimer::singleShot(0, m_view, [this, texture]() {
|
QTimer::singleShot(0, m_view, [view = m_view, texture]() {
|
||||||
if (m_view->model() && texture.isValid()) {
|
if (view && view->model() && texture.isValid()) {
|
||||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser");
|
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser");
|
||||||
Utils3D::selectTexture(texture);
|
Utils3D::selectTexture(texture);
|
||||||
}
|
}
|
||||||
@@ -210,6 +210,12 @@ ModelNode CreateTexture::execute(const ModelNode &texture)
|
|||||||
return duplicateTextureNode;
|
return duplicateTextureNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreateTexture::execute(const QStringList &filePaths, AddTextureMode mode, int sceneId)
|
||||||
|
{
|
||||||
|
for (const QString &path : filePaths)
|
||||||
|
execute(path, mode, sceneId);
|
||||||
|
}
|
||||||
|
|
||||||
bool CreateTexture::addFileToProject(const QString &filePath)
|
bool CreateTexture::addFileToProject(const QString &filePath)
|
||||||
{
|
{
|
||||||
AddFilesResult result = ModelNodeOperations::addImageToProject(
|
AddFilesResult result = ModelNodeOperations::addImageToProject(
|
||||||
@@ -260,48 +266,4 @@ ModelNode CreateTexture::createTextureFromImage(const Utils::FilePath &assetPat
|
|||||||
return newTexNode;
|
return newTexNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTexture::assignTextureAsLightProbe(const ModelNode &texture, int sceneId)
|
|
||||||
{
|
|
||||||
ModelNode sceneEnvNode = resolveSceneEnv(sceneId);
|
|
||||||
QmlObjectNode sceneEnv = sceneEnvNode;
|
|
||||||
if (sceneEnv.isValid()) {
|
|
||||||
sceneEnv.setBindingProperty("lightProbe", texture.id());
|
|
||||||
sceneEnv.setVariantProperty("backgroundMode",
|
|
||||||
QVariant::fromValue(Enumeration("SceneEnvironment",
|
|
||||||
"SkyBox")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelNode CreateTexture::resolveSceneEnv(int sceneId)
|
|
||||||
{
|
|
||||||
ModelNode activeSceneEnv;
|
|
||||||
ModelNode selectedNode = m_view->firstSelectedModelNode();
|
|
||||||
|
|
||||||
if (selectedNode.metaInfo().isQtQuick3DSceneEnvironment()) {
|
|
||||||
activeSceneEnv = selectedNode;
|
|
||||||
} else if (sceneId != -1) {
|
|
||||||
ModelNode activeScene = Utils3D::active3DSceneNode(m_view);
|
|
||||||
if (activeScene.isValid()) {
|
|
||||||
QmlObjectNode view3D;
|
|
||||||
if (activeScene.metaInfo().isQtQuick3DView3D()) {
|
|
||||||
view3D = activeScene;
|
|
||||||
} else {
|
|
||||||
ModelNode sceneParent = activeScene.parentProperty().parentModelNode();
|
|
||||||
if (sceneParent.metaInfo().isQtQuick3DView3D())
|
|
||||||
view3D = sceneParent;
|
|
||||||
}
|
|
||||||
if (view3D.isValid())
|
|
||||||
activeSceneEnv = m_view->modelNodeForId(view3D.expression("environment"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return activeSceneEnv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateTextures::execute(const QStringList &filePaths, AddTextureMode mode, int sceneId)
|
|
||||||
{
|
|
||||||
for (const QString &path : filePaths)
|
|
||||||
CreateTexture::execute(path, mode, sceneId);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QStringList>
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
class FilePath;
|
class FilePath;
|
||||||
@@ -16,10 +16,8 @@ class ModelNode;
|
|||||||
|
|
||||||
enum class AddTextureMode { Image, Texture, LightProbe };
|
enum class AddTextureMode { Image, Texture, LightProbe };
|
||||||
|
|
||||||
class CreateTexture : public QObject
|
class CreateTexture
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CreateTexture(AbstractView *view);
|
CreateTexture(AbstractView *view);
|
||||||
|
|
||||||
@@ -28,8 +26,7 @@ public:
|
|||||||
AddTextureMode mode = AddTextureMode::Texture,
|
AddTextureMode mode = AddTextureMode::Texture,
|
||||||
int sceneId = -1);
|
int sceneId = -1);
|
||||||
ModelNode execute(const ModelNode &texture);
|
ModelNode execute(const ModelNode &texture);
|
||||||
ModelNode resolveSceneEnv(int sceneId);
|
void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId = -1);
|
||||||
void assignTextureAsLightProbe(const ModelNode &texture, int sceneId);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool addFileToProject(const QString &filePath);
|
bool addFileToProject(const QString &filePath);
|
||||||
@@ -38,11 +35,4 @@ private:
|
|||||||
AbstractView *m_view = nullptr;
|
AbstractView *m_view = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CreateTextures : public CreateTexture
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using CreateTexture::CreateTexture;
|
|
||||||
void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId = -1);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -80,6 +80,7 @@ public:
|
|||||||
LightDirectionalIcon,
|
LightDirectionalIcon,
|
||||||
LightPointIcon,
|
LightPointIcon,
|
||||||
LightSpotIcon,
|
LightSpotIcon,
|
||||||
|
LiveUpdateIcon,
|
||||||
LocalOrientIcon,
|
LocalOrientIcon,
|
||||||
MakeComponentIcon,
|
MakeComponentIcon,
|
||||||
MaterialIcon,
|
MaterialIcon,
|
||||||
@@ -107,6 +108,7 @@ public:
|
|||||||
SnappingIcon,
|
SnappingIcon,
|
||||||
SnappingConfIcon,
|
SnappingConfIcon,
|
||||||
SplitViewIcon,
|
SplitViewIcon,
|
||||||
|
SyncIcon,
|
||||||
TimelineIcon,
|
TimelineIcon,
|
||||||
ToggleGroupIcon,
|
ToggleGroupIcon,
|
||||||
VisibilityIcon
|
VisibilityIcon
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "addimagesdialog.h"
|
#include "addimagesdialog.h"
|
||||||
#include "addsignalhandlerdialog.h"
|
#include "addsignalhandlerdialog.h"
|
||||||
#include "componentcore_constants.h"
|
#include "componentcore_constants.h"
|
||||||
|
#include "createtexture.h"
|
||||||
#include "findimplementation.h"
|
#include "findimplementation.h"
|
||||||
#include "layoutingridlayout.h"
|
#include "layoutingridlayout.h"
|
||||||
#include "modelnodecontextmenu_helper.h"
|
#include "modelnodecontextmenu_helper.h"
|
||||||
@@ -87,11 +88,14 @@ Utils::SmallString auxPropertyString(Utils::SmallStringView name)
|
|||||||
{
|
{
|
||||||
return auxDataString + name;
|
return auxDataString + name;
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
inline static void reparentTo(const ModelNode &node, const QmlItemNode &parent)
|
QString relativePathToQmlFile(const QString &absolutePath)
|
||||||
{
|
{
|
||||||
|
return DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void reparentTo(const ModelNode &node, const QmlItemNode &parent)
|
||||||
|
{
|
||||||
if (parent.isValid() && node.isValid()) {
|
if (parent.isValid() && node.isValid()) {
|
||||||
NodeAbstractProperty parentProperty;
|
NodeAbstractProperty parentProperty;
|
||||||
|
|
||||||
@@ -104,7 +108,7 @@ inline static void reparentTo(const ModelNode &node, const QmlItemNode &parent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static QPointF getUpperLeftPosition(const QList<ModelNode> &modelNodeList)
|
inline QPointF getUpperLeftPosition(const QList<ModelNode> &modelNodeList)
|
||||||
{
|
{
|
||||||
QPointF postion(std::numeric_limits<qreal>::max(), std::numeric_limits<qreal>::max());
|
QPointF postion(std::numeric_limits<qreal>::max(), std::numeric_limits<qreal>::max());
|
||||||
for (const ModelNode &modelNode : modelNodeList) {
|
for (const ModelNode &modelNode : modelNodeList) {
|
||||||
@@ -120,13 +124,15 @@ inline static QPointF getUpperLeftPosition(const QList<ModelNode> &modelNodeList
|
|||||||
return postion;
|
return postion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList<ModelNode> &modelNodeList)
|
void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList<ModelNode> &modelNodeList)
|
||||||
{
|
{
|
||||||
QPointF upperLeftPosition = getUpperLeftPosition(modelNodeList);
|
QPointF upperLeftPosition = getUpperLeftPosition(modelNodeList);
|
||||||
layoutNode.variantProperty("x").setValue(qRound(upperLeftPosition.x()));
|
layoutNode.variantProperty("x").setValue(qRound(upperLeftPosition.x()));
|
||||||
layoutNode.variantProperty("y") .setValue(qRound(upperLeftPosition.y()));
|
layoutNode.variantProperty("y") .setValue(qRound(upperLeftPosition.y()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace ModelNodeOperations {
|
namespace ModelNodeOperations {
|
||||||
|
|
||||||
bool goIntoComponent(const ModelNode &modelNode)
|
bool goIntoComponent(const ModelNode &modelNode)
|
||||||
@@ -1753,13 +1759,10 @@ void editInEffectComposer(const SelectionContext &selectionContext)
|
|||||||
|
|
||||||
bool isEffectComposerActivated()
|
bool isEffectComposerActivated()
|
||||||
{
|
{
|
||||||
const ExtensionSystem::PluginSpecs specs = ExtensionSystem::PluginManager::plugins();
|
using namespace ExtensionSystem;
|
||||||
return std::ranges::find_if(specs,
|
return Utils::anyOf(PluginManager::plugins(), [](PluginSpec *spec) {
|
||||||
[](ExtensionSystem::PluginSpec *spec) {
|
return spec->name() == "EffectComposer" && spec->isEffectivelyEnabled();
|
||||||
return spec->name() == "EffectComposer"
|
});
|
||||||
&& spec->isEffectivelyEnabled();
|
|
||||||
})
|
|
||||||
!= specs.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void openEffectComposer(const QString &filePath)
|
void openEffectComposer(const QString &filePath)
|
||||||
@@ -1905,41 +1908,15 @@ static bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const M
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath)
|
ModelNode createTextureNode(AbstractView *view, const QString &imagePath)
|
||||||
{
|
{
|
||||||
AbstractView *view = targetProp.view();
|
|
||||||
QTC_ASSERT(view, return {});
|
QTC_ASSERT(view, return {});
|
||||||
|
|
||||||
if (targetProp.isValid()) {
|
CreateTexture textureCreator(view);
|
||||||
// create a texture item lib
|
return textureCreator.execute(imagePath, AddTextureMode::Texture);
|
||||||
ItemLibraryEntry itemLibraryEntry;
|
|
||||||
itemLibraryEntry.setName("Texture");
|
|
||||||
itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0);
|
|
||||||
|
|
||||||
// set texture source
|
|
||||||
PropertyName prop = "source";
|
|
||||||
QString type = "QUrl";
|
|
||||||
QVariant val = imagePath;
|
|
||||||
itemLibraryEntry.addProperty(prop, type, val);
|
|
||||||
|
|
||||||
// create a texture
|
|
||||||
ModelNode newModelNode = QmlItemNode::createQmlObjectNode(view,
|
|
||||||
itemLibraryEntry,
|
|
||||||
{},
|
|
||||||
targetProp,
|
|
||||||
false);
|
|
||||||
|
|
||||||
// Rename the node based on source image
|
|
||||||
QFileInfo fi(imagePath);
|
|
||||||
newModelNode.setIdWithoutRefactoring(
|
|
||||||
view->model()->generateNewId(fi.baseName(), "textureImage"));
|
|
||||||
return newModelNode;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dropAsImage3dTexture(const ModelNode &targetNode,
|
bool dropAsImage3dTexture(const ModelNode &targetNode,
|
||||||
const NodeAbstractProperty &targetProp,
|
|
||||||
const QString &imagePath,
|
const QString &imagePath,
|
||||||
ModelNode &newNode,
|
ModelNode &newNode,
|
||||||
bool &outMoveNodesAfter)
|
bool &outMoveNodesAfter)
|
||||||
@@ -1949,16 +1926,11 @@ bool dropAsImage3dTexture(const ModelNode &targetNode,
|
|||||||
|
|
||||||
auto bindToProperty = [&](const PropertyName &propName) {
|
auto bindToProperty = [&](const PropertyName &propName) {
|
||||||
view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] {
|
view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] {
|
||||||
newNode = createTextureNode(targetProp, imagePath);
|
newNode = createTextureNode(view, imagePath);
|
||||||
if (newNode.isValid()) {
|
if (newNode.isValid()) {
|
||||||
BindingProperty bindProp = targetNode.bindingProperty(propName);
|
BindingProperty bindProp = targetNode.bindingProperty(propName);
|
||||||
bindProp.setExpression(newNode.validId());
|
bindProp.setExpression(newNode.validId());
|
||||||
ModelNode matLib = Utils3D::materialLibraryNode(view);
|
outMoveNodesAfter = false;
|
||||||
if (matLib.isValid()) {
|
|
||||||
NodeAbstractProperty matLibProp = matLib.defaultNodeAbstractProperty();
|
|
||||||
matLibProp.reparentHere(newNode);
|
|
||||||
outMoveNodesAfter = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1979,7 +1951,7 @@ bool dropAsImage3dTexture(const ModelNode &targetNode,
|
|||||||
|
|
||||||
if (dialog->result() == QDialog::Accepted) {
|
if (dialog->result() == QDialog::Accepted) {
|
||||||
view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] {
|
view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] {
|
||||||
newNode = createTextureNode(targetProp, imagePath);
|
newNode = createTextureNode(view, imagePath);
|
||||||
if (newNode.isValid()) // Automatically set the texture to selected property
|
if (newNode.isValid()) // Automatically set the texture to selected property
|
||||||
targetNode.bindingProperty(dialog->selectedProperty())
|
targetNode.bindingProperty(dialog->selectedProperty())
|
||||||
.setExpression(newNode.validId());
|
.setExpression(newNode.validId());
|
||||||
@@ -1999,10 +1971,11 @@ bool dropAsImage3dTexture(const ModelNode &targetNode,
|
|||||||
return newNode.isValid();
|
return newNode.isValid();
|
||||||
} else if (targetNode.metaInfo().isQtQuick3DTexture()) {
|
} else if (targetNode.metaInfo().isQtQuick3DTexture()) {
|
||||||
// if dropping an image on an existing texture, set the source
|
// if dropping an image on an existing texture, set the source
|
||||||
targetNode.variantProperty("source").setValue(imagePath);
|
targetNode.variantProperty("source").setValue(relativePathToQmlFile(imagePath));
|
||||||
return true;
|
return true;
|
||||||
} else if (targetNode.metaInfo().isQtQuick3DModel()) {
|
} else if (targetNode.metaInfo().isQtQuick3DModel()) {
|
||||||
QTimer::singleShot(0, view, [targetNode, imagePath, view]() {
|
const QString relImagePath = relativePathToQmlFile(imagePath);
|
||||||
|
QTimer::singleShot(0, view, [targetNode, relImagePath, view]() {
|
||||||
if (view && targetNode.isValid()) {
|
if (view && targetNode.isValid()) {
|
||||||
// To MaterialBrowserView. Done async to avoid custom notification in transaction
|
// To MaterialBrowserView. Done async to avoid custom notification in transaction
|
||||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser");
|
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser");
|
||||||
@@ -2010,7 +1983,7 @@ bool dropAsImage3dTexture(const ModelNode &targetNode,
|
|||||||
{targetNode},
|
{targetNode},
|
||||||
{DocumentManager::currentFilePath()
|
{DocumentManager::currentFilePath()
|
||||||
.absolutePath()
|
.absolutePath()
|
||||||
.pathAppended(imagePath)
|
.pathAppended(relImagePath)
|
||||||
.cleanPath()
|
.cleanPath()
|
||||||
.toString()});
|
.toString()});
|
||||||
}
|
}
|
||||||
@@ -2102,20 +2075,12 @@ ModelNode handleItemLibraryImageDrop(const QString &imagePath,
|
|||||||
AbstractView *view = targetNode.view();
|
AbstractView *view = targetNode.view();
|
||||||
QTC_ASSERT(view, return {});
|
QTC_ASSERT(view, return {});
|
||||||
|
|
||||||
const QString imagePathRelative
|
|
||||||
= DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(
|
|
||||||
imagePath); // relative to .ui.qml file
|
|
||||||
|
|
||||||
ModelNode newModelNode;
|
ModelNode newModelNode;
|
||||||
|
|
||||||
if (!dropAsImage3dTexture(targetNode,
|
if (!dropAsImage3dTexture(targetNode, imagePath, newModelNode, outMoveNodesAfter)) {
|
||||||
targetProperty,
|
|
||||||
imagePathRelative,
|
|
||||||
newModelNode,
|
|
||||||
outMoveNodesAfter)) {
|
|
||||||
if (targetNode.metaInfo().isQtQuickImage() || targetNode.metaInfo().isQtQuickBorderImage()) {
|
if (targetNode.metaInfo().isQtQuickImage() || targetNode.metaInfo().isQtQuickBorderImage()) {
|
||||||
// if dropping an image on an existing image, set the source
|
// if dropping an image on an existing image, set the source
|
||||||
targetNode.variantProperty("source").setValue(imagePathRelative);
|
targetNode.variantProperty("source").setValue(relativePathToQmlFile(imagePath));
|
||||||
} else {
|
} else {
|
||||||
// create an image
|
// create an image
|
||||||
QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(view,
|
QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(view,
|
||||||
@@ -2176,8 +2141,7 @@ ModelNode handleItemLibraryShaderDrop(const QString &shaderPath,
|
|||||||
|
|
||||||
ModelNode newModelNode;
|
ModelNode newModelNode;
|
||||||
|
|
||||||
const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(
|
const QString relPath = relativePathToQmlFile(shaderPath);
|
||||||
shaderPath);
|
|
||||||
|
|
||||||
if (targetNode.metaInfo().isQtQuick3DShader()) {
|
if (targetNode.metaInfo().isQtQuick3DShader()) {
|
||||||
// if dropping into an existing Shader, update
|
// if dropping into an existing Shader, update
|
||||||
@@ -2233,8 +2197,7 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath,
|
|||||||
|
|
||||||
ModelNode newModelNode;
|
ModelNode newModelNode;
|
||||||
|
|
||||||
const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(
|
const QString relPath = relativePathToQmlFile(soundPath);
|
||||||
soundPath);
|
|
||||||
|
|
||||||
if (targetNode.metaInfo().isQtMultimediaSoundEffect()) {
|
if (targetNode.metaInfo().isQtMultimediaSoundEffect()) {
|
||||||
// if dropping into on an existing SoundEffect, update
|
// if dropping into on an existing SoundEffect, update
|
||||||
@@ -2268,7 +2231,6 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath,
|
ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath,
|
||||||
NodeAbstractProperty targetProperty,
|
|
||||||
const ModelNode &targetNode,
|
const ModelNode &targetNode,
|
||||||
bool &outMoveNodesAfter)
|
bool &outMoveNodesAfter)
|
||||||
{
|
{
|
||||||
@@ -2279,24 +2241,9 @@ ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath,
|
|||||||
if (!view->model()->hasImport(import, true, true))
|
if (!view->model()->hasImport(import, true, true))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(
|
|
||||||
tex3DPath); // relative to qml file
|
|
||||||
|
|
||||||
ModelNode newModelNode;
|
ModelNode newModelNode;
|
||||||
|
|
||||||
if (!dropAsImage3dTexture(targetNode,
|
dropAsImage3dTexture(targetNode, tex3DPath, newModelNode, outMoveNodesAfter);
|
||||||
targetProperty,
|
|
||||||
imagePath,
|
|
||||||
newModelNode,
|
|
||||||
outMoveNodesAfter)) {
|
|
||||||
view->executeInTransaction("NavigatorTreeModel::handleItemLibraryTexture3dDrop", [&] {
|
|
||||||
// create a standalone Texture3D at drop location
|
|
||||||
newModelNode = createTextureNode(targetProperty, imagePath);
|
|
||||||
if (!NodeHints::fromModelNode(targetProperty.parentModelNode())
|
|
||||||
.canBeContainerFor(newModelNode))
|
|
||||||
newModelNode.destroy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return newModelNode;
|
return newModelNode;
|
||||||
}
|
}
|
||||||
|
@@ -137,7 +137,7 @@ bool useLayerEffect();
|
|||||||
bool validateEffect(const QString &effectPath);
|
bool validateEffect(const QString &effectPath);
|
||||||
bool isEffectComposerActivated();
|
bool isEffectComposerActivated();
|
||||||
|
|
||||||
Utils::FilePath getImagesDefaultDirectory();
|
QMLDESIGNERCOMPONENTS_EXPORT Utils::FilePath getImagesDefaultDirectory();
|
||||||
|
|
||||||
//Item Library and Assets related drop operations
|
//Item Library and Assets related drop operations
|
||||||
QMLDESIGNERCOMPONENTS_EXPORT ModelNode handleItemLibraryEffectDrop(const QString &effectPath,
|
QMLDESIGNERCOMPONENTS_EXPORT ModelNode handleItemLibraryEffectDrop(const QString &effectPath,
|
||||||
@@ -160,7 +160,6 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath,
|
|||||||
NodeAbstractProperty targetProperty,
|
NodeAbstractProperty targetProperty,
|
||||||
const ModelNode &targetNode);
|
const ModelNode &targetNode);
|
||||||
ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath,
|
ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath,
|
||||||
NodeAbstractProperty targetProperty,
|
|
||||||
const ModelNode &targetNode,
|
const ModelNode &targetNode,
|
||||||
bool &outMoveNodesAfter);
|
bool &outMoveNodesAfter);
|
||||||
|
|
||||||
|
@@ -252,6 +252,43 @@ void applyMaterialToModels(AbstractView *view, const ModelNode &material,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelNode resolveSceneEnv(AbstractView *view, int sceneId)
|
||||||
|
{
|
||||||
|
ModelNode activeSceneEnv;
|
||||||
|
ModelNode selectedNode = view->firstSelectedModelNode();
|
||||||
|
|
||||||
|
if (selectedNode.metaInfo().isQtQuick3DSceneEnvironment()) {
|
||||||
|
activeSceneEnv = selectedNode;
|
||||||
|
} else if (sceneId != -1) {
|
||||||
|
ModelNode activeScene = Utils3D::active3DSceneNode(view);
|
||||||
|
if (activeScene.isValid()) {
|
||||||
|
QmlObjectNode view3D;
|
||||||
|
if (activeScene.metaInfo().isQtQuick3DView3D()) {
|
||||||
|
view3D = activeScene;
|
||||||
|
} else {
|
||||||
|
ModelNode sceneParent = activeScene.parentProperty().parentModelNode();
|
||||||
|
if (sceneParent.metaInfo().isQtQuick3DView3D())
|
||||||
|
view3D = sceneParent;
|
||||||
|
}
|
||||||
|
if (view3D.isValid())
|
||||||
|
activeSceneEnv = view->modelNodeForId(view3D.expression("environment"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeSceneEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId)
|
||||||
|
{
|
||||||
|
ModelNode sceneEnvNode = resolveSceneEnv(view, sceneId);
|
||||||
|
QmlObjectNode sceneEnv = sceneEnvNode;
|
||||||
|
if (sceneEnv.isValid()) {
|
||||||
|
sceneEnv.setBindingProperty("lightProbe", texture.id());
|
||||||
|
sceneEnv.setVariantProperty("backgroundMode",
|
||||||
|
QVariant::fromValue(Enumeration("SceneEnvironment", "SkyBox")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This method should be executed within a transaction as it performs multiple modifications to the model
|
// This method should be executed within a transaction as it performs multiple modifications to the model
|
||||||
#ifdef QDS_USE_PROJECTSTORAGE
|
#ifdef QDS_USE_PROJECTSTORAGE
|
||||||
ModelNode createMaterial(AbstractView *view, const TypeName &typeName)
|
ModelNode createMaterial(AbstractView *view, const TypeName &typeName)
|
||||||
|
@@ -40,10 +40,14 @@ void selectTexture(const ModelNode &texture);
|
|||||||
ModelNode selectedMaterial(AbstractView *view);
|
ModelNode selectedMaterial(AbstractView *view);
|
||||||
ModelNode selectedTexture(AbstractView *view);
|
ModelNode selectedTexture(AbstractView *view);
|
||||||
|
|
||||||
|
ModelNode resolveSceneEnv(AbstractView *view, int sceneId);
|
||||||
|
|
||||||
QList<ModelNode> getSelectedModels(AbstractView *view);
|
QList<ModelNode> getSelectedModels(AbstractView *view);
|
||||||
void applyMaterialToModels(AbstractView *view, const ModelNode &material,
|
void applyMaterialToModels(AbstractView *view, const ModelNode &material,
|
||||||
const QList<ModelNode> &models, bool add = false);
|
const QList<ModelNode> &models, bool add = false);
|
||||||
|
|
||||||
|
void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId);
|
||||||
|
|
||||||
#ifdef QDS_USE_PROJECTSTORAGE
|
#ifdef QDS_USE_PROJECTSTORAGE
|
||||||
ModelNode createMaterial(AbstractView *view, const TypeName &typeName);
|
ModelNode createMaterial(AbstractView *view, const TypeName &typeName);
|
||||||
#else
|
#else
|
||||||
|
@@ -57,7 +57,6 @@ ContentLibraryView::ContentLibraryView(AsynchronousImageCache &imageCache,
|
|||||||
ExternalDependenciesInterface &externalDependencies)
|
ExternalDependenciesInterface &externalDependencies)
|
||||||
: AbstractView(externalDependencies)
|
: AbstractView(externalDependencies)
|
||||||
, m_imageCache(imageCache)
|
, m_imageCache(imageCache)
|
||||||
, m_createTexture(this)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ContentLibraryView::~ContentLibraryView()
|
ContentLibraryView::~ContentLibraryView()
|
||||||
@@ -88,15 +87,17 @@ WidgetInfo ContentLibraryView::widgetInfo()
|
|||||||
m_draggedBundleItem = item;
|
m_draggedBundleItem = item;
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_widget, &ContentLibraryWidget::addTextureRequested, this,
|
connect(m_widget,
|
||||||
[&] (const QString &texPath, AddTextureMode mode) {
|
&ContentLibraryWidget::addTextureRequested,
|
||||||
executeInTransaction("ContentLibraryView::widgetInfo", [&]() {
|
this,
|
||||||
m_createTexture.execute(texPath, mode, m_sceneId);
|
[&](const QString &texPath, AddTextureMode mode) {
|
||||||
});
|
executeInTransaction("ContentLibraryView::widgetInfo", [&]() {
|
||||||
});
|
CreateTexture(this).execute(texPath, mode, m_sceneId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_widget, &ContentLibraryWidget::updateSceneEnvStateRequested, this, [this] {
|
connect(m_widget, &ContentLibraryWidget::updateSceneEnvStateRequested, this, [this] {
|
||||||
ModelNode activeSceneEnv = m_createTexture.resolveSceneEnv(m_sceneId);
|
ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(this, m_sceneId);
|
||||||
const bool sceneEnvExists = activeSceneEnv.isValid();
|
const bool sceneEnvExists = activeSceneEnv.isValid();
|
||||||
m_widget->texturesModel()->setHasSceneEnv(sceneEnvExists);
|
m_widget->texturesModel()->setHasSceneEnv(sceneEnvExists);
|
||||||
m_widget->environmentsModel()->setHasSceneEnv(sceneEnvExists);
|
m_widget->environmentsModel()->setHasSceneEnv(sceneEnvExists);
|
||||||
|
@@ -90,7 +90,6 @@ private:
|
|||||||
bool m_bundleMaterialAddToSelected = false;
|
bool m_bundleMaterialAddToSelected = false;
|
||||||
bool m_hasQuick3DImport = false;
|
bool m_hasQuick3DImport = false;
|
||||||
qint32 m_sceneId = -1;
|
qint32 m_sceneId = -1;
|
||||||
CreateTexture m_createTexture;
|
|
||||||
Utils::FilePath m_iconSavePath;
|
Utils::FilePath m_iconSavePath;
|
||||||
QString m_generatedFolderName;
|
QString m_generatedFolderName;
|
||||||
QString m_bundleId;
|
QString m_bundleId;
|
||||||
|
@@ -101,8 +101,9 @@ bool MoveManipulator::itemsCanReparented() const
|
|||||||
|
|
||||||
void MoveManipulator::setDirectUpdateInNodeInstances(bool directUpdate)
|
void MoveManipulator::setDirectUpdateInNodeInstances(bool directUpdate)
|
||||||
{
|
{
|
||||||
for (FormEditorItem* item : std::as_const(m_itemList)) {
|
const auto allFormEditorItems = m_view->scene()->allFormEditorItems();
|
||||||
if (item && item->qmlItemNode().isValid())
|
for (FormEditorItem *item : std::as_const(m_itemList)) {
|
||||||
|
if (item && allFormEditorItems.contains(item) && item->qmlItemNode().isValid())
|
||||||
item->qmlItemNode().nodeInstance().setDirectUpdate(directUpdate);
|
item->qmlItemNode().nodeInstance().setDirectUpdate(directUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -376,10 +376,11 @@ void ItemLibraryModel::update(Model *model)
|
|||||||
for (const ItemLibraryEntry &entry : itemLibEntries) {
|
for (const ItemLibraryEntry &entry : itemLibEntries) {
|
||||||
NodeMetaInfo metaInfo;
|
NodeMetaInfo metaInfo;
|
||||||
|
|
||||||
if constexpr (useProjectStorage())
|
#ifdef QDS_USE_PROJECTSTORAGE
|
||||||
metaInfo = NodeMetaInfo{entry.typeId(), model->projectStorage()};
|
metaInfo = NodeMetaInfo{entry.typeId(), model->projectStorage()};
|
||||||
else
|
#else
|
||||||
metaInfo = model->metaInfo(entry.typeName());
|
metaInfo = model->metaInfo(entry.typeName());
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef QDS_USE_PROJECTSTORAGE
|
#ifdef QDS_USE_PROJECTSTORAGE
|
||||||
bool valid = metaInfo.isValid();
|
bool valid = metaInfo.isValid();
|
||||||
|
@@ -209,7 +209,7 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
});
|
});
|
||||||
|
|
||||||
connect(texturesModel, &MaterialBrowserTexturesModel::updateSceneEnvStateRequested, this, [this] {
|
connect(texturesModel, &MaterialBrowserTexturesModel::updateSceneEnvStateRequested, this, [this] {
|
||||||
ModelNode activeSceneEnv = CreateTexture(this).resolveSceneEnv(m_sceneId);
|
ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(this, m_sceneId);
|
||||||
const bool sceneEnvExists = activeSceneEnv.isValid();
|
const bool sceneEnvExists = activeSceneEnv.isValid();
|
||||||
m_widget->materialBrowserTexturesModel()->setHasSceneEnv(sceneEnvExists);
|
m_widget->materialBrowserTexturesModel()->setHasSceneEnv(sceneEnvExists);
|
||||||
});
|
});
|
||||||
@@ -222,12 +222,14 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
m_widget->materialBrowserTexturesModel()->setHasSingleModelSelection(hasModel);
|
m_widget->materialBrowserTexturesModel()->setHasSingleModelSelection(hasModel);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(texturesModel, &MaterialBrowserTexturesModel::applyAsLightProbeRequested, this,
|
connect(texturesModel,
|
||||||
[&] (const ModelNode &texture) {
|
&MaterialBrowserTexturesModel::applyAsLightProbeRequested,
|
||||||
executeInTransaction(__FUNCTION__, [&] {
|
this,
|
||||||
CreateTexture(this).assignTextureAsLightProbe(texture, m_sceneId);
|
[&](const ModelNode &texture) {
|
||||||
});
|
executeInTransaction(__FUNCTION__, [&] {
|
||||||
});
|
Utils3D::assignTextureAsLightProbe(this, texture, m_sceneId);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return createWidgetInfo(m_widget.data(),
|
return createWidgetInfo(m_widget.data(),
|
||||||
@@ -239,13 +241,9 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
|
|
||||||
void MaterialBrowserView::createTextures(const QStringList &assetPaths)
|
void MaterialBrowserView::createTextures(const QStringList &assetPaths)
|
||||||
{
|
{
|
||||||
auto *create = new CreateTextures(this);
|
|
||||||
|
|
||||||
executeInTransaction("MaterialBrowserView::createTextures", [&]() {
|
executeInTransaction("MaterialBrowserView::createTextures", [&]() {
|
||||||
create->execute(assetPaths, AddTextureMode::Texture, m_sceneId);
|
CreateTexture(this).execute(assetPaths, AddTextureMode::Texture, m_sceneId);
|
||||||
});
|
});
|
||||||
|
|
||||||
create->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserView::modelAttached(Model *model)
|
void MaterialBrowserView::modelAttached(Model *model)
|
||||||
@@ -740,11 +738,10 @@ void MaterialBrowserView::applyTextureToProperty(const QString &matId, const QSt
|
|||||||
{
|
{
|
||||||
executeInTransaction(__FUNCTION__, [&] {
|
executeInTransaction(__FUNCTION__, [&] {
|
||||||
if (m_appliedTextureId.isEmpty() && !m_appliedTexturePath.isEmpty()) {
|
if (m_appliedTextureId.isEmpty() && !m_appliedTexturePath.isEmpty()) {
|
||||||
auto texCreator = new CreateTexture(this);
|
CreateTexture texCreator(this);
|
||||||
ModelNode tex = texCreator->execute(m_appliedTexturePath, AddTextureMode::Texture);
|
ModelNode tex = texCreator.execute(m_appliedTexturePath, AddTextureMode::Texture);
|
||||||
m_appliedTextureId = tex.id();
|
m_appliedTextureId = tex.id();
|
||||||
m_appliedTexturePath.clear();
|
m_appliedTexturePath.clear();
|
||||||
texCreator->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTC_ASSERT(!m_appliedTextureId.isEmpty(), return);
|
QTC_ASSERT(!m_appliedTextureId.isEmpty(), return);
|
||||||
|
@@ -307,10 +307,8 @@ void MaterialBrowserWidget::acceptBundleTextureDropOnMaterial(int matIndex, cons
|
|||||||
ModelNode mat = m_materialBrowserModel->materialAt(matIndex);
|
ModelNode mat = m_materialBrowserModel->materialAt(matIndex);
|
||||||
QTC_ASSERT(mat.isValid(), return);
|
QTC_ASSERT(mat.isValid(), return);
|
||||||
|
|
||||||
auto *creator = new CreateTexture(m_materialBrowserView);
|
|
||||||
|
|
||||||
m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] {
|
m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] {
|
||||||
ModelNode tex = creator->execute(bundleTexPath.toLocalFile());
|
ModelNode tex = CreateTexture(m_materialBrowserView).execute(bundleTexPath.toLocalFile());
|
||||||
QTC_ASSERT(tex.isValid(), return);
|
QTC_ASSERT(tex.isValid(), return);
|
||||||
|
|
||||||
m_materialBrowserModel->selectMaterial(matIndex);
|
m_materialBrowserModel->selectMaterial(matIndex);
|
||||||
@@ -319,8 +317,6 @@ void MaterialBrowserWidget::acceptBundleTextureDropOnMaterial(int matIndex, cons
|
|||||||
|
|
||||||
if (m_materialBrowserView->model())
|
if (m_materialBrowserView->model())
|
||||||
m_materialBrowserView->model()->endDrag();
|
m_materialBrowserView->model()->endDrag();
|
||||||
|
|
||||||
creator->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserWidget::acceptAssetsDrop(const QList<QUrl> &urls)
|
void MaterialBrowserWidget::acceptAssetsDrop(const QList<QUrl> &urls)
|
||||||
@@ -336,14 +332,12 @@ void MaterialBrowserWidget::acceptAssetsDropOnMaterial(int matIndex, const QList
|
|||||||
ModelNode mat = m_materialBrowserModel->materialAt(matIndex);
|
ModelNode mat = m_materialBrowserModel->materialAt(matIndex);
|
||||||
QTC_ASSERT(mat.isValid(), return);
|
QTC_ASSERT(mat.isValid(), return);
|
||||||
|
|
||||||
auto *creator = new CreateTexture(m_materialBrowserView);
|
QString imageSrc = Utils::findOrDefault(urls, [](const QUrl &url) {
|
||||||
|
return Asset(url.toLocalFile()).isValidTextureSource();
|
||||||
QString imageSrc = Utils::findOrDefault(urls, [] (const QUrl &url) {
|
}).toLocalFile();
|
||||||
return Asset(url.toLocalFile()).isValidTextureSource();
|
|
||||||
}).toLocalFile();
|
|
||||||
|
|
||||||
m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] {
|
m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] {
|
||||||
ModelNode tex = creator->execute(imageSrc);
|
ModelNode tex = CreateTexture(m_materialBrowserView).execute(imageSrc);
|
||||||
QTC_ASSERT(tex.isValid(), return);
|
QTC_ASSERT(tex.isValid(), return);
|
||||||
|
|
||||||
m_materialBrowserModel->selectMaterial(matIndex);
|
m_materialBrowserModel->selectMaterial(matIndex);
|
||||||
@@ -352,8 +346,6 @@ void MaterialBrowserWidget::acceptAssetsDropOnMaterial(int matIndex, const QList
|
|||||||
|
|
||||||
if (m_materialBrowserView->model())
|
if (m_materialBrowserView->model())
|
||||||
m_materialBrowserView->model()->endDrag();
|
m_materialBrowserView->model()->endDrag();
|
||||||
|
|
||||||
creator->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserWidget::acceptTextureDropOnMaterial(int matIndex, const QString &texId)
|
void MaterialBrowserWidget::acceptTextureDropOnMaterial(int matIndex, const QString &texId)
|
||||||
|
@@ -177,8 +177,8 @@ static void reparentModelNodeToNodeProperty(NodeAbstractProperty &parentProperty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigatorTreeModel::NavigatorTreeModel(QObject *parent) : QAbstractItemModel(parent)
|
NavigatorTreeModel::NavigatorTreeModel(QObject *parent)
|
||||||
, m_createTextures(Utils::makeUniqueObjectPtr<CreateTextures>(m_view))
|
: QAbstractItemModel(parent)
|
||||||
{
|
{
|
||||||
m_actionManager = &QmlDesignerPlugin::instance()->viewManager().designerActionManager();
|
m_actionManager = &QmlDesignerPlugin::instance()->viewManager().designerActionManager();
|
||||||
}
|
}
|
||||||
@@ -324,7 +324,10 @@ QList<ModelNode> NavigatorTreeModel::filteredList(const NodeListProperty &proper
|
|||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
list.append(::Utils::filtered(nameFilteredList, [](const ModelNode &arg) {
|
list.append(::Utils::filtered(nameFilteredList, [](const ModelNode &arg) {
|
||||||
const bool value = (QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator())
|
const bool visibleInNavigator = NodeHints::fromModelNode(arg).visibleInNavigator();
|
||||||
|
const bool hideInNavigator = NodeHints::fromModelNode(arg).hideInNavigator();
|
||||||
|
const bool value = ((QmlItemNode::isValidQmlItemNode(arg) && !hideInNavigator)
|
||||||
|
|| visibleInNavigator)
|
||||||
&& arg.id() != Constants::MATERIAL_LIB_ID;
|
&& arg.id() != Constants::MATERIAL_LIB_ID;
|
||||||
return value;
|
return value;
|
||||||
}));
|
}));
|
||||||
@@ -583,17 +586,10 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
|
|||||||
bool moveNodesAfter = false;
|
bool moveNodesAfter = false;
|
||||||
|
|
||||||
m_view->executeInTransaction(__FUNCTION__, [&] {
|
m_view->executeInTransaction(__FUNCTION__, [&] {
|
||||||
m_createTextures->execute(QStringList{texturePath},
|
ModelNodeOperations::handleItemLibraryTexture3dDrop(texturePath,
|
||||||
AddTextureMode::Image,
|
modelNodeForIndex(
|
||||||
Utils3D::active3DSceneId(m_view->model()));
|
rowModelIndex),
|
||||||
QString textureName = Utils::FilePath::fromString(texturePath).fileName();
|
moveNodesAfter);
|
||||||
QString textureAbsolutePath = DocumentManager::currentResourcePath()
|
|
||||||
.pathAppended("images/" + textureName).toString();
|
|
||||||
ModelNodeOperations::handleItemLibraryImageDrop(textureAbsolutePath,
|
|
||||||
targetProperty,
|
|
||||||
modelNodeForIndex(
|
|
||||||
rowModelIndex),
|
|
||||||
moveNodesAfter);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -664,7 +660,6 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
|
|||||||
} else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) {
|
} else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) {
|
||||||
currNode = ModelNodeOperations::handleItemLibraryTexture3dDrop(
|
currNode = ModelNodeOperations::handleItemLibraryTexture3dDrop(
|
||||||
assetPath,
|
assetPath,
|
||||||
targetProperty,
|
|
||||||
modelNodeForIndex(rowModelIndex),
|
modelNodeForIndex(rowModelIndex),
|
||||||
moveNodesAfter);
|
moveNodesAfter);
|
||||||
} else if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) {
|
} else if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) {
|
||||||
@@ -853,34 +848,6 @@ bool QmlDesigner::NavigatorTreeModel::moveNodeToParent(const NodeAbstractPropert
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targetProp,
|
|
||||||
const QString &imagePath)
|
|
||||||
{
|
|
||||||
if (targetProp.isValid()) {
|
|
||||||
// create a texture item lib
|
|
||||||
ItemLibraryEntry itemLibraryEntry;
|
|
||||||
itemLibraryEntry.setName("Texture");
|
|
||||||
itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0);
|
|
||||||
|
|
||||||
// set texture source
|
|
||||||
PropertyName prop = "source";
|
|
||||||
QString type = "QUrl";
|
|
||||||
QVariant val = imagePath;
|
|
||||||
itemLibraryEntry.addProperty(prop, type, val);
|
|
||||||
|
|
||||||
// create a texture
|
|
||||||
ModelNode newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {},
|
|
||||||
targetProp, false);
|
|
||||||
|
|
||||||
// Rename the node based on source image
|
|
||||||
QFileInfo fi(imagePath);
|
|
||||||
newModelNode.setIdWithoutRefactoring(
|
|
||||||
m_view->model()->generateNewId(fi.baseName(), "textureImage"));
|
|
||||||
return newModelNode;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
NodeMetaInfo propertyType(const NodeAbstractProperty &property)
|
NodeMetaInfo propertyType(const NodeAbstractProperty &property)
|
||||||
{
|
{
|
||||||
|
@@ -17,7 +17,6 @@ QT_FORWARD_DECLARE_CLASS(QPixmap)
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class CreateTextures;
|
|
||||||
class DesignerActionManager;
|
class DesignerActionManager;
|
||||||
class Model;
|
class Model;
|
||||||
class ModelNode;
|
class ModelNode;
|
||||||
@@ -88,7 +87,7 @@ public:
|
|||||||
void updateToolTipPixmap(const ModelNode &node, const QPixmap &pixmap);
|
void updateToolTipPixmap(const ModelNode &node, const QPixmap &pixmap);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void toolTipPixmapUpdated(const QString &id, const QPixmap &pixmap) const;
|
void toolTipPixmapUpdated(const QString &id, const QPixmap &pixmap);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void moveNodesInteractive(NodeAbstractProperty &parentProperty, const QList<ModelNode> &modelNodes,
|
void moveNodesInteractive(NodeAbstractProperty &parentProperty, const QList<ModelNode> &modelNodes,
|
||||||
@@ -96,16 +95,17 @@ private:
|
|||||||
void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
|
void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
|
||||||
void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
|
void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
|
||||||
|
|
||||||
bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp,
|
bool dropAsImage3dTexture(const ModelNode &targetNode,
|
||||||
const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter);
|
const NodeAbstractProperty &targetProp,
|
||||||
ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath);
|
const QString &imagePath,
|
||||||
|
ModelNode &newNode,
|
||||||
|
bool &outMoveNodesAfter);
|
||||||
QList<QPersistentModelIndex> nodesToPersistentIndex(const QList<ModelNode> &modelNodes);
|
QList<QPersistentModelIndex> nodesToPersistentIndex(const QList<ModelNode> &modelNodes);
|
||||||
void addImport(const QString &importName);
|
void addImport(const QString &importName);
|
||||||
QList<ModelNode> filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const;
|
QList<ModelNode> filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const;
|
||||||
bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const ModelNode &newModelNode);
|
bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const ModelNode &newModelNode);
|
||||||
|
|
||||||
QPointer<NavigatorView> m_view;
|
QPointer<NavigatorView> m_view;
|
||||||
Utils::UniqueObjectPtr<CreateTextures> m_createTextures;
|
|
||||||
mutable QHash<ModelNode, QModelIndex> m_nodeIndexHash;
|
mutable QHash<ModelNode, QModelIndex> m_nodeIndexHash;
|
||||||
mutable QHash<ModelNode, QList<ModelNode> > m_rowCache;
|
mutable QHash<ModelNode, QList<ModelNode> > m_rowCache;
|
||||||
bool m_showOnlyVisibleItems = true;
|
bool m_showOnlyVisibleItems = true;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user