Merge remote-tracking branch 'origin/qds/dev'
Change-Id: Ic852bc9977d0292fb6cd93a319f4bfdebb22a1b0
28
README.md
@@ -934,6 +934,34 @@ SQLite (https://www.sqlite.org) is in the Public Domain.
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
### QrCodeGenerator
|
||||||
|
|
||||||
|
The QML Designer plugin uses QR Code Generator for Design Viewer integration.
|
||||||
|
|
||||||
|
https://github.com/alex-spataru/Qt-QrCodeGenerator
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Alex Spataru
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
### cmake
|
### cmake
|
||||||
|
|
||||||
The CMake project manager uses the CMake lexer code for parsing CMake files
|
The CMake project manager uses the CMake lexer code for parsing CMake files
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set(IDE_VERSION "4.3.0") # The IDE version.
|
set(IDE_VERSION "4.4.0") # The IDE version.
|
||||||
set(IDE_VERSION_COMPAT "4.3.0") # The IDE Compatibility version.
|
set(IDE_VERSION_COMPAT "4.4.0") # The IDE Compatibility version.
|
||||||
set(IDE_VERSION_DISPLAY "4.3.0") # The IDE display version.
|
set(IDE_VERSION_DISPLAY "4.4.0") # The IDE display version.
|
||||||
set(IDE_COPYRIGHT_YEAR "2023") # The IDE current copyright year.
|
set(IDE_COPYRIGHT_YEAR "2023") # The IDE current copyright year.
|
||||||
|
|
||||||
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
|
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
|
||||||
|
|||||||
BIN
doc/qtcreator/images/extraimages/images/KDxnMQzgmIY.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -2,7 +2,6 @@
|
|||||||
images/commercial.png \
|
images/commercial.png \
|
||||||
images/SsFWyUeAA_4.jpg \
|
images/SsFWyUeAA_4.jpg \
|
||||||
images/9ihYeC0YJ0M.jpg \
|
images/9ihYeC0YJ0M.jpg \
|
||||||
images/RfEYO-5Mw6s.jpg \
|
|
||||||
images/yOUdg1o2KJM.jpg \
|
images/yOUdg1o2KJM.jpg \
|
||||||
images/DVWd_xMMgvg.jpg \
|
images/DVWd_xMMgvg.jpg \
|
||||||
images/Ed8WS03C-Vk.jpg \
|
images/Ed8WS03C-Vk.jpg \
|
||||||
@@ -11,6 +10,5 @@
|
|||||||
images/w1yhDl93YI0.jpg \
|
images/w1yhDl93YI0.jpg \
|
||||||
images/pEETxSxYazg.jpg \
|
images/pEETxSxYazg.jpg \
|
||||||
images/V3Po15bNErw.jpg \
|
images/V3Po15bNErw.jpg \
|
||||||
images/bMXeeQw6BYs.jpg \
|
images/9MqUCP6JLCQ.jpg \
|
||||||
images/u3kZJjlk3CY.jpg \
|
images/KDxnMQzgmIY.jpg
|
||||||
images/9MqUCP6JLCQ.jpg
|
|
||||||
|
|||||||
@@ -897,6 +897,18 @@
|
|||||||
|
|
||||||
\include license-mit.qdocinc
|
\include license-mit.qdocinc
|
||||||
|
|
||||||
|
\li \b QrCodeGenerator
|
||||||
|
|
||||||
|
The QML Designer plugin uses QR Code Generator for Design Viewer integration.
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li \l https://github.com/alex-spataru/Qt-QrCodeGenerator
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
Distributed under the MIT license.
|
||||||
|
|
||||||
|
\include license-mit.qdocinc
|
||||||
|
|
||||||
\li \b cmake
|
\li \b cmake
|
||||||
|
|
||||||
The CMake project manager uses the CMake lexer code for parsing CMake files.
|
The CMake project manager uses the CMake lexer code for parsing CMake files.
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
Besides the 3D model, the 3D scene also has the default camera and the default directional
|
Besides the 3D model, the 3D scene also has the default camera and the default directional
|
||||||
light.
|
light.
|
||||||
|
|
||||||
|
\include run-tutorial-project.qdocinc
|
||||||
|
|
||||||
\section1 Adding Materials to the 3D Models
|
\section1 Adding Materials to the 3D Models
|
||||||
|
|
||||||
First, use materials from \uicontrol {Content Library} on the ball bearing.
|
First, use materials from \uicontrol {Content Library} on the ball bearing.
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
All assets you need for this tutorial are included in the Car Demo project.
|
All assets you need for this tutorial are included in the Car Demo project.
|
||||||
|
|
||||||
|
\include run-tutorial-project.qdocinc
|
||||||
|
|
||||||
\section1 Creating States
|
\section1 Creating States
|
||||||
|
|
||||||
First, you create the different states. In this tutorial, you create four
|
First, you create the different states. In this tutorial, you create four
|
||||||
@@ -121,16 +123,19 @@
|
|||||||
\list 1
|
\list 1
|
||||||
\li Go to the \uicontrol Connections view.
|
\li Go to the \uicontrol Connections view.
|
||||||
\li In \uicontrol{Navigator}, select \e button_side and in
|
\li In \uicontrol{Navigator}, select \e button_side and in
|
||||||
\uicontrol {Connections}, select \inlineimage icons/plus.png
|
\uicontrol {Connections}, select the \inlineimage icons/plus.png
|
||||||
.
|
button to open the connection setup options.
|
||||||
This creates a new connection with \e button_side as the target.
|
\li Set \uicontrol Signal to \c clicked, \uicontrol Action to
|
||||||
\li Set \uicontrol{Signal Handler} to \uicontrol onClicked.
|
\c {Change State}, \uicontrol {State Group} to \c rectangle and
|
||||||
\li Set \uicontrol Actions to \e {Change state to side}.
|
\uicontrol State to \c side in the respective
|
||||||
|
drop-down menus.
|
||||||
|
\li Select the \inlineimage icons/close.png
|
||||||
|
button to close the connection setup options.
|
||||||
\li Repeat steps 2 to 4 for the next three buttons and set them to go to
|
\li Repeat steps 2 to 4 for the next three buttons and set them to go to
|
||||||
their corresponding states.
|
their corresponding states.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\image state-transition-connections.png
|
\image state-transition-connections.webp
|
||||||
|
|
||||||
Now you can preview and try the transitions to see how the UI moves between
|
Now you can preview and try the transitions to see how the UI moves between
|
||||||
the states when you select the buttons.
|
the states when you select the buttons.
|
||||||
|
|||||||
@@ -52,6 +52,8 @@
|
|||||||
This tutorial requires that you know the basics of \QDS, see
|
This tutorial requires that you know the basics of \QDS, see
|
||||||
\l{Getting Started}.
|
\l{Getting Started}.
|
||||||
|
|
||||||
|
\include run-tutorial-project.qdocinc
|
||||||
|
|
||||||
\section1 Creating a Timeline Animation
|
\section1 Creating a Timeline Animation
|
||||||
|
|
||||||
First, you create an animation where the ball bearing continuously rotates
|
First, you create an animation where the ball bearing continuously rotates
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.2 KiB |
BIN
doc/qtdesignstudio/examples/doc/images/loginui3-connections.webp
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
@@ -252,7 +252,7 @@
|
|||||||
|
|
||||||
\image loginui1-entry-field-styled.jpg "Modified button in the 2D view"
|
\image loginui1-entry-field-styled.jpg "Modified button in the 2D view"
|
||||||
|
|
||||||
\note Do not edit the the value of \uicontrol Text in the \uicontrol Character
|
\note Do not edit the value of \uicontrol Text in the \uicontrol Character
|
||||||
property, because this will break the connection, and later you won't be able
|
property, because this will break the connection, and later you won't be able
|
||||||
to change the text in \uicontrol {Button Content} > \uicontrol Text.
|
to change the text in \uicontrol {Button Content} > \uicontrol Text.
|
||||||
|
|
||||||
|
|||||||
@@ -135,17 +135,22 @@
|
|||||||
\uicontrol {Connections} to open the \uicontrol Connections view.
|
\uicontrol {Connections} to open the \uicontrol Connections view.
|
||||||
\li Select \e createAccount in \uicontrol Navigator.
|
\li Select \e createAccount in \uicontrol Navigator.
|
||||||
\li In the \uicontrol Connections tab, select the \inlineimage icons/plus.png
|
\li In the \uicontrol Connections tab, select the \inlineimage icons/plus.png
|
||||||
button to add the action that the \c onClicked signal handler of
|
button to open the connection setup options.
|
||||||
\e createAccount should apply.
|
\li Set \uicontrol Signal to \c clicked, \uicontrol Action to
|
||||||
\li Double-click the value \uicontrol Action column and select
|
\c {Change State}, \uicontrol {State Group} to \c rectangle and
|
||||||
\uicontrol {Change state to createAccount} in the drop-down menu.
|
\uicontrol State to \c createAccount in the respective
|
||||||
\note Or, you can right-click the \e createAccount button in \l Navigator.
|
drop-down menus.
|
||||||
Then select \uicontrol {Connections} > \uicontrol {Add signal handler} >
|
\li Select the \inlineimage icons/close.png
|
||||||
\uicontrol {clicked} > \uicontrol {Change State to createAccount}.
|
button to close the connection setup options.
|
||||||
\image loginui3-connections.png "Connections tab"
|
|
||||||
|
\image loginui3-connections.webp "Connections tab"
|
||||||
|
|
||||||
\li Select \uicontrol File > \uicontrol Save or press \key {Ctrl+S}
|
\li Select \uicontrol File > \uicontrol Save or press \key {Ctrl+S}
|
||||||
to save your changes.
|
to save your changes.
|
||||||
|
|
||||||
|
\note Or, you can right-click the \e createAccount button in \l Navigator.
|
||||||
|
Then select \uicontrol {Connections} > \uicontrol {Add signal handler} >
|
||||||
|
\uicontrol {clicked} > \uicontrol {Change State to createAccount}.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
In the live preview, you can now click the \uicontrol {Create Account}
|
In the live preview, you can now click the \uicontrol {Create Account}
|
||||||
|
|||||||
@@ -20,14 +20,13 @@
|
|||||||
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/multi-language%20tutorial/Loginui2}{here}
|
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/multi-language%20tutorial/Loginui2}{here}
|
||||||
before you start.
|
before you start.
|
||||||
|
|
||||||
Download the project and open the \e loginui2.qmlproject file in \QDS
|
|
||||||
to get started.
|
|
||||||
|
|
||||||
This project consists of a login page with a couple of text elements.
|
This project consists of a login page with a couple of text elements.
|
||||||
|
|
||||||
Additionally, you will use a JSON translation file in this tutorial.
|
Additionally, you will use a JSON translation file in this tutorial.
|
||||||
Download it from \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/multi-language}{here}.
|
Download it from \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/multi-language}{here}.
|
||||||
|
|
||||||
|
\include run-tutorial-project.qdocinc
|
||||||
|
|
||||||
\section1 JSON Translation File
|
\section1 JSON Translation File
|
||||||
|
|
||||||
The JSON translation file you are using in this project has the following
|
The JSON translation file you are using in this project has the following
|
||||||
|
|||||||
@@ -40,10 +40,23 @@
|
|||||||
|
|
||||||
We use the \uicontrol {\QMCU Application} project template to create
|
We use the \uicontrol {\QMCU Application} project template to create
|
||||||
an application for MCUs, which support only a subset of the preset
|
an application for MCUs, which support only a subset of the preset
|
||||||
\l{glossary-component}{components}. We select \uicontrol File >
|
\l{glossary-component}{components}.
|
||||||
\uicontrol {New Project} > \uicontrol {\QMCU Application} >
|
|
||||||
\uicontrol Choose, and follow the instructions of the wizard to create our
|
To create an MCU project:
|
||||||
project.
|
|
||||||
|
\list 1
|
||||||
|
\li Select \uicontrol {File} > \uicontrol {New Project}.
|
||||||
|
\li In the \uicontrol {Presets} tab, select the \uicontrol {\QMCU} preset.
|
||||||
|
\li In the \uicontrol {Details} tab:
|
||||||
|
\list
|
||||||
|
\li Select the path for the project files. You can move the project
|
||||||
|
folders later.
|
||||||
|
\li Set the screen size to match the device screen, which also enables
|
||||||
|
previewing on the desktop. You can change the screen size later in
|
||||||
|
\l {Properties}.
|
||||||
|
\endlist
|
||||||
|
\li Select \uicontrol {Create} to create the project.
|
||||||
|
\endlist
|
||||||
|
|
||||||
This way, only the components and properties supported on MCUs are visible
|
This way, only the components and properties supported on MCUs are visible
|
||||||
in \l Components and \l Properties, and we won't accidentally
|
in \l Components and \l Properties, and we won't accidentally
|
||||||
@@ -193,10 +206,12 @@
|
|||||||
Then, we select the mouse area for the start button, \e startMA,
|
Then, we select the mouse area for the start button, \e startMA,
|
||||||
in \uicontrol Navigator. On the \uicontrol Connections tab in the
|
in \uicontrol Navigator. On the \uicontrol Connections tab in the
|
||||||
\l {Connections} view, we select the \inlineimage icons/plus.png
|
\l {Connections} view, we select the \inlineimage icons/plus.png
|
||||||
(\uicontrol Add) button to connect the \c onClicked() signal handler
|
(\uicontrol Add) button. We set \uicontrol Signal to \c clicked,
|
||||||
of the button to the \c startClicked() signal.
|
\uicontrol Action to \c {Call Function} and \uicontrol Item to
|
||||||
|
\c startClicked. Next, we select the \inlineimage icons/close.png
|
||||||
|
button to close the connection setup options.
|
||||||
|
|
||||||
\image washingmachineui-connections.png "Connections view"
|
\image washingmachineui-connections.webp "Connections view"
|
||||||
|
|
||||||
Then, in \e ApplicationView.qml, we specify that the \c startClicked()
|
Then, in \e ApplicationView.qml, we specify that the \c startClicked()
|
||||||
signal changes the application state to \e presets:
|
signal changes the application state to \e presets:
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
BIN
doc/qtdesignstudio/images/qtquick-component-signal.webp
Normal file
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
BIN
doc/qtdesignstudio/images/studio-project-export-advanced.webp
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
doc/qtdesignstudio/images/studio-project-export.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 50 KiB |
@@ -28,19 +28,19 @@
|
|||||||
in ways that are not supported in \QDS by default, you can define
|
in ways that are not supported in \QDS by default, you can define
|
||||||
custom properties on the \uicontrol {Properties} tab in the
|
custom properties on the \uicontrol {Properties} tab in the
|
||||||
\l {Connections} view.
|
\l {Connections} view.
|
||||||
\image qmldesigner-dynamicprops.png "Connections View Properties tab"
|
\image add-updated-local-custom-property.webp "Connections View Properties tab"
|
||||||
For more information, see \l{Specifying Custom Properties}.
|
For more information, see \l{Specifying Custom Properties}.
|
||||||
\li To enable users to interact with the component instances, connect
|
\li To enable users to interact with the component instances, connect
|
||||||
the instances to signals on the \uicontrol Connections tab in the
|
the instances to signals on the \uicontrol Connections tab in the
|
||||||
\uicontrol {Connections} view. For example, you can specify what
|
\uicontrol {Connections} view. For example, you can specify what
|
||||||
happens when a component instance is clicked. For more information,
|
happens when a component instance is clicked. For more information,
|
||||||
see \l{Connecting Components to Signals}.
|
see \l{Connecting Components to Signals}.
|
||||||
\image qmldesigner-connections.png "Connections View Connections tab"
|
\image qmldesigner-connections.webp "Connections View Connections tab"
|
||||||
\li To dynamically change the behavior of a component instance when
|
\li To dynamically change the behavior of a component instance when
|
||||||
another component instance changes, create bindings between them on
|
another component instance changes, create bindings between them on
|
||||||
the \uicontrol Bindings tab in the \uicontrol {Connections} view.
|
the \uicontrol Bindings tab in the \uicontrol {Connections} view.
|
||||||
For more information, see \l{Adding Bindings Between Properties}.
|
For more information, see \l{Adding Bindings Between Properties}.
|
||||||
\image qmldesigner-bindings.png "Connections view Bindings tab"
|
\image qmldesigner-bindings.webp "Connections view Bindings tab"
|
||||||
\li Add states to apply sets of changes to the property values of one
|
\li Add states to apply sets of changes to the property values of one
|
||||||
or several component instances in the \uicontrol States view.
|
or several component instances in the \uicontrol States view.
|
||||||
For more information, see \l{Working with States}.
|
For more information, see \l{Working with States}.
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
the \l{UI Files}{UI files} (.ui.qml), while developers should work
|
the \l{UI Files}{UI files} (.ui.qml), while developers should work
|
||||||
on the corresponding implementation files (.qml) to define their
|
on the corresponding implementation files (.qml) to define their
|
||||||
programmatic behaviors or JavaScript. This enables iteration from
|
programmatic behaviors or JavaScript. This enables iteration from
|
||||||
both the design and development side of the process without the the
|
both the design and development side of the process without the
|
||||||
risk of overwriting each other's work.
|
risk of overwriting each other's work.
|
||||||
\endlist
|
\endlist
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -421,7 +421,7 @@
|
|||||||
The child components of grid layout components are arranged according to the
|
The child components of grid layout components are arranged according to the
|
||||||
\uicontrol Flow property. When the direction of a flow is set to
|
\uicontrol Flow property. When the direction of a flow is set to
|
||||||
\uicontrol LeftToRight, child components are positioned next to to each
|
\uicontrol LeftToRight, child components are positioned next to to each
|
||||||
other until the the number of columns specified in the
|
other until the number of columns specified in the
|
||||||
\uicontrol {Columns & Rows} field is reached. Then,
|
\uicontrol {Columns & Rows} field is reached. Then,
|
||||||
the auto-positioning wraps back to the beginning of the next row.
|
the auto-positioning wraps back to the beginning of the next row.
|
||||||
|
|
||||||
|
|||||||
@@ -73,19 +73,6 @@
|
|||||||
\note Using 3D components will affect the performance of your UI. Do not
|
\note Using 3D components will affect the performance of your UI. Do not
|
||||||
use 3D components if the same results can be achieved using 2D components.
|
use 3D components if the same results can be achieved using 2D components.
|
||||||
|
|
||||||
\section2 Videos About 3D Components
|
|
||||||
|
|
||||||
The following video shows you how to add the components included in the
|
|
||||||
\uicontrol {Qt Quick 3D} module, such as 3D models, cameras, and lights,
|
|
||||||
to your scene:
|
|
||||||
|
|
||||||
\youtube u3kZJjlk3CY
|
|
||||||
|
|
||||||
The following video shows you how to use the custom shader utilities, 3D
|
|
||||||
effects, and materials:
|
|
||||||
|
|
||||||
\youtube bMXeeQw6BYs
|
|
||||||
|
|
||||||
The following video shows you how to combine 2D and 3D components:
|
The following video shows you how to combine 2D and 3D components:
|
||||||
|
|
||||||
\youtube w1yhDl93YI0
|
\youtube w1yhDl93YI0
|
||||||
|
|||||||
@@ -206,7 +206,7 @@
|
|||||||
|
|
||||||
Text can be either in plain text or rich text format, depending on the
|
Text can be either in plain text or rich text format, depending on the
|
||||||
value you set in the \uicontrol Format field. If you select
|
value you set in the \uicontrol Format field. If you select
|
||||||
\uicontrol AutoText and the the first line of text contains an HTML tag,
|
\uicontrol AutoText and the first line of text contains an HTML tag,
|
||||||
the text is treated as rich text. Rich text supports a subset of HTML 4
|
the text is treated as rich text. Rich text supports a subset of HTML 4
|
||||||
described on the \l {Supported HTML Subset}. Note that plain text offers
|
described on the \l {Supported HTML Subset}. Note that plain text offers
|
||||||
better performance than rich text.
|
better performance than rich text.
|
||||||
|
|||||||
@@ -31,76 +31,58 @@
|
|||||||
\e CMakeLists.txt file as the project file. This enables you to share
|
\e CMakeLists.txt file as the project file. This enables you to share
|
||||||
your project as a fully working C++ application with developers.
|
your project as a fully working C++ application with developers.
|
||||||
|
|
||||||
If you add or remove QML files in \QDS, you have to regenerate the
|
|
||||||
\e CMakeLists.txt project configuration file by selecting \uicontrol File
|
|
||||||
> \uicontrol {Export Project} > \uicontrol {Generate CMake Build Files}.
|
|
||||||
|
|
||||||
If you use Git, you can clone an example project
|
If you use Git, you can clone an example project
|
||||||
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/playground/AuroraCluster0}
|
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/playground/AuroraCluster0}
|
||||||
{here}.
|
{here}.
|
||||||
|
|
||||||
The following image shows the example project structure and contents in the
|
\section1 Exporting a \QDS Project
|
||||||
\l Projects and \l {File System} views in \QDS and Qt Creator:
|
|
||||||
|
|
||||||
\image studio-project-structure.png "\QDS project in \QDS and Qt Creator views"
|
\QDS uses a different project format than Qt Creator. \QDS does not build the project,
|
||||||
|
it uses a pre-compiled \l{QML runtime} to run the project. To export a \QDS project for the
|
||||||
\section1 Converting Project Structure for CMake
|
Qt Creator, follow the process:
|
||||||
|
|
||||||
\QDS can generate \e CMakeLists.txt and other related files to use with
|
|
||||||
Qt Creator and to compile into an executable application but only if the
|
|
||||||
project has a certain folder structure. If you have a \QDS QML project that
|
|
||||||
doesn't have the CMake configuration, follow these steps to convert its
|
|
||||||
file structure to the correct format.
|
|
||||||
|
|
||||||
\list 1
|
\list 1
|
||||||
\li Create a folder named \e content in the project's folder. This folder contains the
|
\li Open the project you want to export in \QDS.
|
||||||
application's main module.
|
\li Select \uicontrol {File} > \uicontrol {Export Project} > \uicontrol {Generate CMake Build Files}.
|
||||||
\li Move all QML files of the project's main module to the \e content folder. If your project
|
\image studio-project-export.webp "Export the \QDS project for Qt Creator"
|
||||||
has multiple modules, place the other modules in the \e imports or
|
|
||||||
\e asset_imports folder.
|
\li Select \uicontrol {Details} to access the \l {Advanced Options}.
|
||||||
\li If your project's main module has resource folders such as \e fonts or \e {images}, move
|
\image studio-project-export-advanced.webp "Access Advanced Options in the project exporter"
|
||||||
them to the \e content folder.
|
|
||||||
\li Create a folder named \e src in the project's folder. This folder contains C++ code for
|
\note The project exporter has default settings selected. This works better if the project
|
||||||
compiling the project.
|
is combined with an existing Qt project.
|
||||||
\li If your project doesn't have an \e imports folder for other QML modules, create it
|
|
||||||
now even if you do not have other modules. The CMake file generator expects it.
|
\li Select all the options here. This allows to export the
|
||||||
\li In the project's \e .qmlproject file:
|
complete project. So, it can be compiled as a stand-alone application.
|
||||||
\list
|
\image studio-project-export-advanced-options.webp "Select all the options in the project exporter"
|
||||||
\li Add \e "." in importPaths. For example:
|
|
||||||
\code
|
\note If you copy this export on top of the existing Qt Creator project
|
||||||
importPaths: [ "imports", "asset_imports", "." ]
|
it overwrites the existing project. Hence, the default selected options in
|
||||||
\endcode
|
the exporter only exports the QML-specific items. You get a list of
|
||||||
\li Change mainFile to \e "content/App.qml":
|
warnings at the bottom part of the exporter that denotes exactly which parts
|
||||||
\code
|
of the project gets overwritten.
|
||||||
mainFile: "content/App.qml"
|
|
||||||
\endcode
|
|
||||||
\endlist
|
\endlist
|
||||||
\li In the \e content folder, create a file named \e App.qml and add the following content:
|
|
||||||
|
|
||||||
\qml
|
\section1 Using the Exported Project in Qt Creator
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Window
|
|
||||||
import YourImportModuleHere
|
|
||||||
Window {
|
|
||||||
width: Constants.width
|
|
||||||
height: Constants.height
|
|
||||||
visible: true
|
|
||||||
title: "YourWindowTitleHere"
|
|
||||||
<YourMainQmlClassHere> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\endqml
|
|
||||||
|
|
||||||
\li In \e{App.qml}, modify imported modules, window dimensions, window title, and main QML
|
After exporting the project from the \QDS, you have to open it from Qt Creator.
|
||||||
class appropriately.
|
|
||||||
|
|
||||||
\note This template assumes that your project has a module named \e YourImportModuleHere in
|
If you have used any version before \QDS 4.0 to create the project, manually include this code
|
||||||
the \a imports folder containing a singleton class named \a Constants.
|
in the \l {CMakeLists.txt} file so the exported project works in Qt Creator.
|
||||||
This isn't mandatory.
|
|
||||||
|
|
||||||
\li Generate CMake files and C++ source files that are used to compile the application into
|
\code
|
||||||
an executable file by selecting \uicontrol File > \uicontrol {Export Project} >
|
set(BUILD_QDS_COMPONENTS ON CACHE BOOL "Build design studio components")
|
||||||
\uicontrol {Generate CMake Build Files}.
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
if (${BUILD_QDS_COMPONENTS})
|
||||||
|
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\note If you have created the project with the \QDS version 4.0 or above, you already have this code in
|
||||||
|
\l {CMakeLists.txt} by default.
|
||||||
|
|
||||||
\endlist
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,8 +16,14 @@
|
|||||||
\li \QDS Version
|
\li \QDS Version
|
||||||
\li \QMCU SDK Version
|
\li \QMCU SDK Version
|
||||||
\row
|
\row
|
||||||
\li 4.0 or later
|
\li 4.3 or later
|
||||||
\li 2.4 or later
|
\li 2.6 or later
|
||||||
|
\row
|
||||||
|
\li 4.2 or later
|
||||||
|
\li 2.5
|
||||||
|
\row
|
||||||
|
\li 4.0 up to 4.1
|
||||||
|
\li 2.4
|
||||||
\row
|
\row
|
||||||
\li 3.8 up to 3.9
|
\li 3.8 up to 3.9
|
||||||
\li 2.3
|
\li 2.3
|
||||||
|
|||||||
@@ -25,7 +25,8 @@
|
|||||||
\li \b -
|
\li \b -
|
||||||
\li A scene in the \uicontrol 2D view is rendered by the regular Qt Quick
|
\li A scene in the \uicontrol 2D view is rendered by the regular Qt Quick
|
||||||
and QML, and not as \QUL and \QMCU, so some imperfections or inaccuracies
|
and QML, and not as \QUL and \QMCU, so some imperfections or inaccuracies
|
||||||
can occur.
|
can occur. Note that the default font used in \QDS preview and \QUL are
|
||||||
|
different, and the developer must confirm both fonts are the same.
|
||||||
\row
|
\row
|
||||||
\li \l 3D
|
\li \l 3D
|
||||||
\li \b -
|
\li \b -
|
||||||
@@ -71,15 +72,19 @@
|
|||||||
\li \b -
|
\li \b -
|
||||||
\li \b -
|
\li \b -
|
||||||
\li The \uicontrol Connections view displays all signal handlers in the
|
\li The \uicontrol Connections view displays all signal handlers in the
|
||||||
current file but it doesn't filter available signals, so you can still
|
current file, but it doesn't filter available signals, so you can still
|
||||||
see and select signals that are available in Qt Quick, but not in \QUL.
|
see and select signals available in Qt Quick, but not in \QUL.
|
||||||
|
The same also applies if \uicontrol Action is set to \uicontrol{Call Function}
|
||||||
|
and \uicontrol Item is set to \uicontrol Qt. See the component documentation
|
||||||
|
to filter available signal/function.
|
||||||
\row
|
\row
|
||||||
\li \l {States}
|
\li \l {States}
|
||||||
\li \b X
|
\li \b X
|
||||||
\li \b -
|
\li \b -
|
||||||
\li \b -
|
\li \b -
|
||||||
\li The feature is fully supported as such, but there are some
|
\li The feature is fully supported as such, but there are some
|
||||||
limitations listed in \l {\QMCU Known Issues or Limitations}.
|
limitations such as StateGroup and the ones listed in
|
||||||
|
\l {\QMCU Known Issues or Limitations}.
|
||||||
\row
|
\row
|
||||||
\li \l {Transitions}
|
\li \l {Transitions}
|
||||||
\li \b X
|
\li \b X
|
||||||
@@ -89,9 +94,11 @@
|
|||||||
\row
|
\row
|
||||||
\li \l {Translations}
|
\li \l {Translations}
|
||||||
\li \b -
|
\li \b -
|
||||||
\li \b -
|
|
||||||
\li \b X
|
\li \b X
|
||||||
\li \b -
|
\li \b -
|
||||||
|
\li The \uicontrol Translations view previews with regular Qt Quick instead
|
||||||
|
of \QUL, and it can be inaccurate in calculating the text overflow in some translations.
|
||||||
|
Also, the developer needs to configure the \QUL project to use \QDS translations (.ts) files.
|
||||||
\row
|
\row
|
||||||
\li \l {Timeline}
|
\li \l {Timeline}
|
||||||
\li \b X
|
\li \b X
|
||||||
@@ -100,11 +107,11 @@
|
|||||||
\li \b -
|
\li \b -
|
||||||
\row
|
\row
|
||||||
\li \l {Curves}
|
\li \l {Curves}
|
||||||
\li \b -
|
|
||||||
\li \b X
|
\li \b X
|
||||||
\li \b -
|
\li \b -
|
||||||
\li Linear interpolation works, but \QMCU does not support the
|
\li \b -
|
||||||
\c easing.bezierCurve property of a keyframe.
|
\li Linear interpolation works, and \QMCU supports the \c easing.bezierCurve property
|
||||||
|
of a keyframe in \QMCU 2.6 or higher.
|
||||||
\row
|
\row
|
||||||
\li \l Code
|
\li \l Code
|
||||||
\li \b X
|
\li \b X
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
\image qtquick-annotation-editor.png "Annotation Editor"
|
\image qtquick-annotation-editor.png "Annotation Editor"
|
||||||
\li The \uicontrol {Selected Item} field displays the ID of the
|
\li The \uicontrol {Selected Item} field displays the ID of the
|
||||||
component.
|
component.
|
||||||
\li In the the \uicontrol Name field, enter a free-form text that
|
\li In the \uicontrol Name field, enter a free-form text that
|
||||||
describes the component.
|
describes the component.
|
||||||
\li In the \uicontrol Title field, enter the text to display in
|
\li In the \uicontrol Title field, enter the text to display in
|
||||||
the tab for this comment.
|
the tab for this comment.
|
||||||
|
|||||||
@@ -132,7 +132,7 @@
|
|||||||
|
|
||||||
\section2 Set the AVD as the Device in the Android Kit
|
\section2 Set the AVD as the Device in the Android Kit
|
||||||
|
|
||||||
Next, you need to set the AVD as the Android device kit. You do this under the the
|
Next, you need to set the AVD as the Android device kit. You do this under the
|
||||||
\uicontrol Kits tab. If the \uicontrol Kits list is empty, restart \QDS.
|
\uicontrol Kits tab. If the \uicontrol Kits list is empty, restart \QDS.
|
||||||
|
|
||||||
\image qtds-options-kits.png
|
\image qtds-options-kits.png
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
component height is adjusted automatically. Similarly, the opacity of a
|
component height is adjusted automatically. Similarly, the opacity of a
|
||||||
component can be bound to the opacity of its parent component.
|
component can be bound to the opacity of its parent component.
|
||||||
|
|
||||||
\image qtquick-connection-editor-assignment.png "Binding Editor"
|
\image qtquick-connection-editor-assignment.webp "Binding Editor"
|
||||||
|
|
||||||
Property bindings are created implicitly whenever a property is assigned a
|
Property bindings are created implicitly whenever a property is assigned a
|
||||||
JavaScript expression.
|
JavaScript expression.
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
is to create \l{glossary-binding}{bindings} between the values of their
|
is to create \l{glossary-binding}{bindings} between the values of their
|
||||||
\l{glossary-property}{properties}.
|
\l{glossary-property}{properties}.
|
||||||
|
|
||||||
\image qmldesigner-connections.png "The Connections view"
|
\image qmldesigner-connections.webp "The Connections view"
|
||||||
|
|
||||||
Read more about connections:
|
Read more about connections:
|
||||||
|
|
||||||
@@ -211,9 +211,9 @@
|
|||||||
the application. For example, the \l {Mouse Area} component has a \c clicked
|
the application. For example, the \l {Mouse Area} component has a \c clicked
|
||||||
signal that is emitted whenever the mouse is clicked within the area. Since
|
signal that is emitted whenever the mouse is clicked within the area. Since
|
||||||
the signal name is \c clicked, the signal handler for receiving this signal
|
the signal name is \c clicked, the signal handler for receiving this signal
|
||||||
is named \c onClicked.
|
is named \c onClicked. Then it performs the defined \uicontrol {Action}.
|
||||||
|
|
||||||
\image washingmachineui-connections.png "Connections view, Connections tab"
|
\image qtquick-component-signal.webp "Component signal"
|
||||||
|
|
||||||
Further, a signal is automatically emitted when the value of a
|
Further, a signal is automatically emitted when the value of a
|
||||||
\l{glossary-property}{property} changes.
|
\l{glossary-property}{property} changes.
|
||||||
|
|||||||
@@ -792,7 +792,7 @@
|
|||||||
in particle size, specify values for \uicontrol {Particle scale variation}
|
in particle size, specify values for \uicontrol {Particle scale variation}
|
||||||
and \uicontrol {Particle end scale variation}.
|
and \uicontrol {Particle end scale variation}.
|
||||||
|
|
||||||
\uicontrol {Depth bias} specifies the the depth bias of the emitter. Depth
|
\uicontrol {Depth bias} specifies the depth bias of the emitter. Depth
|
||||||
bias is added to the object's distance from camera when sorting objects.
|
bias is added to the object's distance from camera when sorting objects.
|
||||||
This can be used to force the rendering order of objects that are located
|
This can be used to force the rendering order of objects that are located
|
||||||
close to each other if it might otherwise change between frames. Negative
|
close to each other if it might otherwise change between frames. Negative
|
||||||
@@ -1046,7 +1046,7 @@
|
|||||||
\uicontrol {Maximum Size} defines the maximum size that the affector can
|
\uicontrol {Maximum Size} defines the maximum size that the affector can
|
||||||
scale particles to.
|
scale particles to.
|
||||||
|
|
||||||
\uicontrol Duration defines the the duration of the scaling cycle in
|
\uicontrol Duration defines the duration of the scaling cycle in
|
||||||
milliseconds.
|
milliseconds.
|
||||||
|
|
||||||
\uicontrol {Easing Curve} defines the
|
\uicontrol {Easing Curve} defines the
|
||||||
|
|||||||
@@ -285,7 +285,7 @@
|
|||||||
\uicontrol {Input 01} field to the value of the \uicontrol {Below min}
|
\uicontrol {Input 01} field to the value of the \uicontrol {Below min}
|
||||||
field of the minimum-maximum mapper for the bad value range. For the
|
field of the minimum-maximum mapper for the bad value range. For the
|
||||||
\e overValueAnd operator, we bind it to the value of the
|
\e overValueAnd operator, we bind it to the value of the
|
||||||
\uicontrol {Above max} field of the the same mapper.
|
\uicontrol {Above max} field of the same mapper.
|
||||||
|
|
||||||
\image studio-logic-helper-combining-example-ao2.png "Under value minimum-maximum mapper Input 01"
|
\image studio-logic-helper-combining-example-ao2.png "Under value minimum-maximum mapper Input 01"
|
||||||
|
|
||||||
|
|||||||
4
doc/qtdesignstudio/src/run-tutorial-project.qdocinc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
\section1 Running the Tutorial Project
|
||||||
|
|
||||||
|
To open the tutorial project in \QDS, open the \e{.qmlproject} file located
|
||||||
|
in the root folder of the downloaded project.
|
||||||
@@ -112,6 +112,13 @@
|
|||||||
\li Open the \uicontrol {Manual Code Edit} window from the
|
\li Open the \uicontrol {Manual Code Edit} window from the
|
||||||
\uicontrol {Connections} view and write JavaScript expressions with components
|
\uicontrol {Connections} view and write JavaScript expressions with components
|
||||||
and logical expressions manually.
|
and logical expressions manually.
|
||||||
|
|
||||||
|
\note If you create a conditional expression by selecting options from the
|
||||||
|
drop-down menus in the \uicontrol {Connection} view, you can only create a single
|
||||||
|
level \e {if-else} expression. For nested level \e {if-else} expressions,
|
||||||
|
use the \uicontrol {Manual Code Edit}.
|
||||||
|
|
||||||
|
\image qmldesigner-connections-ConditionalAction-Manual.webp
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section2 Action Properties
|
\section2 Action Properties
|
||||||
@@ -152,11 +159,7 @@
|
|||||||
\li N/A
|
\li N/A
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
\note If you create a conditional expression by selecting options from drop-down menus in
|
Watch this video for practical examples of the \uicontrol {Connection} view workflow:
|
||||||
the \uicontrol {Connection} view, you can only create a single
|
\youtube KDxnMQzgmIY
|
||||||
level {if-else} expression. For nested level \e {if-elseif-else} expressions,
|
|
||||||
you have to use the \uicontrol {Manual Code Edit}.
|
|
||||||
|
|
||||||
\image qmldesigner-connections-ConditionalAction-Manual.webp
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,10 +25,6 @@
|
|||||||
You can move the views anywhere on the screen and save them as
|
You can move the views anywhere on the screen and save them as
|
||||||
\e workspaces, as instructed in \l {Managing Workspaces}.
|
\e workspaces, as instructed in \l {Managing Workspaces}.
|
||||||
|
|
||||||
To learn more about using the design views, see the following video:
|
|
||||||
|
|
||||||
\youtube RfEYO-5Mw6s
|
|
||||||
|
|
||||||
\section1 Summary of Design Views
|
\section1 Summary of Design Views
|
||||||
|
|
||||||
In addition to the summary of design views, the table below includes an MCU
|
In addition to the summary of design views, the table below includes an MCU
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
\li \l{Previewing Component Size}
|
\li \l{Previewing Component Size}
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/canvas-color.png
|
\li \inlineimage icons/canvas-color.png
|
||||||
\li Sets the color of the the \uicontrol {2D} view working area.
|
\li Sets the color of the \uicontrol {2D} view working area.
|
||||||
\li \l{Setting Canvas Color}
|
\li \l{Setting Canvas Color}
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/zoomIn.png
|
\li \inlineimage icons/zoomIn.png
|
||||||
|
|||||||
@@ -32,12 +32,7 @@ TreeViewDelegate {
|
|||||||
readonly property int __dirItemHeight: 21
|
readonly property int __dirItemHeight: 21
|
||||||
|
|
||||||
implicitHeight: root.__isDirectory ? root.__dirItemHeight : root.__fileItemHeight
|
implicitHeight: root.__isDirectory ? root.__dirItemHeight : root.__fileItemHeight
|
||||||
implicitWidth: {
|
implicitWidth: root.assetsView.width
|
||||||
if (root.assetsView.verticalScrollBar.scrollBarVisible)
|
|
||||||
return root.assetsView.width - root.indentation - root.assetsView.verticalScrollBar.width
|
|
||||||
else
|
|
||||||
return root.assetsView.width - root.indentation
|
|
||||||
}
|
|
||||||
|
|
||||||
leftMargin: root.__isDirectory ? 0 : thumbnailImage.width
|
leftMargin: root.__isDirectory ? 0 : thumbnailImage.width
|
||||||
|
|
||||||
@@ -88,7 +83,7 @@ TreeViewDelegate {
|
|||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
id: bg
|
id: bg
|
||||||
|
|
||||||
x: root.indentation * root.depth
|
x: root.indentation * (root.depth - 1)
|
||||||
width: root.implicitWidth - bg.x
|
width: root.implicitWidth - bg.x
|
||||||
|
|
||||||
color: {
|
color: {
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import CollectionDetails 1.0 as CollectionDetails
|
||||||
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import StudioHelpers as StudioHelpers
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
required property var columnType
|
||||||
|
|
||||||
|
property var __modifier : textEditor
|
||||||
|
property bool __changesAccepted: true
|
||||||
|
|
||||||
|
TableView.onCommit: {
|
||||||
|
if (root.__changesAccepted)
|
||||||
|
edit = __modifier.editor.editValue
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
__changesAccepted = true
|
||||||
|
if (edit && edit !== "")
|
||||||
|
root.__modifier.editor.editValue = edit
|
||||||
|
}
|
||||||
|
|
||||||
|
onActiveFocusChanged: {
|
||||||
|
if (root.activeFocus)
|
||||||
|
root.__modifier.editor.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
id: modifierFocusConnection
|
||||||
|
|
||||||
|
target: root.__modifier.editor
|
||||||
|
|
||||||
|
function onActiveFocusChanged() {
|
||||||
|
if (!modifierFocusConnection.target.activeFocus)
|
||||||
|
root.TableView.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorPopup {
|
||||||
|
id: textEditor
|
||||||
|
|
||||||
|
editor: textField
|
||||||
|
|
||||||
|
StudioControls.TextField {
|
||||||
|
id: textField
|
||||||
|
|
||||||
|
property alias editValue: textField.text
|
||||||
|
|
||||||
|
actionIndicator.visible: false
|
||||||
|
translationIndicatorVisible: false
|
||||||
|
|
||||||
|
onRejected: root.__changesAccepted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorPopup {
|
||||||
|
id: numberEditor
|
||||||
|
|
||||||
|
editor: numberField
|
||||||
|
|
||||||
|
StudioControls.RealSpinBox {
|
||||||
|
id: numberField
|
||||||
|
|
||||||
|
property alias editValue: numberField.realValue
|
||||||
|
|
||||||
|
actionIndicator.visible: false
|
||||||
|
realFrom: -9e9
|
||||||
|
realTo: 9e9
|
||||||
|
realStepSize: 1.0
|
||||||
|
decimals: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorPopup {
|
||||||
|
id: boolEditor
|
||||||
|
|
||||||
|
editor: boolField
|
||||||
|
|
||||||
|
StudioControls.CheckBox {
|
||||||
|
id: boolField
|
||||||
|
|
||||||
|
property alias editValue: boolField.checked
|
||||||
|
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorPopup {
|
||||||
|
id: colorEditor
|
||||||
|
|
||||||
|
editor: colorPicker
|
||||||
|
|
||||||
|
implicitHeight: colorPicker.height + topPadding + bottomPadding
|
||||||
|
implicitWidth: colorPicker.width + leftPadding + rightPadding
|
||||||
|
padding: 8
|
||||||
|
|
||||||
|
StudioHelpers.ColorBackend {
|
||||||
|
id: colorBackend
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.ColorEditorPopup {
|
||||||
|
id: colorPicker
|
||||||
|
|
||||||
|
property alias editValue: colorBackend.color
|
||||||
|
color: colorBackend.color
|
||||||
|
|
||||||
|
width: 200
|
||||||
|
|
||||||
|
Keys.onEnterPressed: colorPicker.focus = false
|
||||||
|
|
||||||
|
onActivateColor: function(color) {
|
||||||
|
colorBackend.activateColor(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
border.color: StudioTheme.Values.themeInteraction
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component EditorPopup: T.Popup {
|
||||||
|
id: editorPopup
|
||||||
|
|
||||||
|
required property Item editor
|
||||||
|
|
||||||
|
implicitHeight: contentHeight
|
||||||
|
implicitWidth: contentWidth
|
||||||
|
|
||||||
|
enabled: visible
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: editorPopup.editor
|
||||||
|
|
||||||
|
function onActiveFocusChanged() {
|
||||||
|
if (!editorPopup.editor.activeFocus)
|
||||||
|
editorPopup.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: editorPopup.editor.Keys
|
||||||
|
|
||||||
|
function onEscapePressed() {
|
||||||
|
root.__changesAccepted = false
|
||||||
|
editorPopup.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "default"
|
||||||
|
when: columnType !== CollectionDetails.DataType.Boolean
|
||||||
|
&& columnType !== CollectionDetails.DataType.Color
|
||||||
|
&& columnType !== CollectionDetails.DataType.Number
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
__modifier: textEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: textEditor
|
||||||
|
visible: true
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "number"
|
||||||
|
when: columnType === CollectionDetails.DataType.Number
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
__modifier: numberEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: numberEditor
|
||||||
|
visible: true
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "bool"
|
||||||
|
when: columnType === CollectionDetails.DataType.Boolean
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
__modifier: boolEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: boolEditor
|
||||||
|
visible: true
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "color"
|
||||||
|
when: columnType === CollectionDetails.DataType.Color
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
__modifier: colorEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: colorEditor
|
||||||
|
visible: true
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Qt.labs.platform as PlatformWidgets
|
||||||
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
import CollectionEditorBackend
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real iconHeight: 2 * StudioTheme.Values.bigFont
|
||||||
|
required property var model
|
||||||
|
required property var backend
|
||||||
|
property int selectedRow: -1
|
||||||
|
|
||||||
|
implicitHeight: container.height
|
||||||
|
|
||||||
|
function addNewColumn() {
|
||||||
|
addColumnDialog.popUp(root.model.columnCount())
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNewRow() {
|
||||||
|
root.model.insertRow(root.model.rowCount())
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: container
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: leftSideToolbar
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.addcolumnleft_medium
|
||||||
|
tooltip: qsTr("Add property left %1").arg(leftSideToolbar.topPadding)
|
||||||
|
enabled: root.model.selectedColumn > -1
|
||||||
|
onClicked: addColumnDialog.popUp(root.model.selectedColumn - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.addcolumnright_medium
|
||||||
|
tooltip: qsTr("Add property right")
|
||||||
|
enabled: root.model.selectedColumn > -1
|
||||||
|
onClicked: addColumnDialog.popUp(root.model.selectedColumn + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.deletecolumn_medium
|
||||||
|
tooltip: qsTr("Delete selected property")
|
||||||
|
enabled: root.model.selectedColumn > -1
|
||||||
|
onClicked: root.model.removeColumn(root.model.selectedColumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { // spacer
|
||||||
|
implicitWidth: StudioTheme.Values.toolbarSpacing
|
||||||
|
implicitHeight: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.addrowbelow_medium
|
||||||
|
tooltip: qsTr("Insert row below")
|
||||||
|
enabled: root.model.selectedRow > -1
|
||||||
|
onClicked: root.model.insertRow(root.model.selectedRow + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.addrowabove_medium
|
||||||
|
tooltip: qsTr("Insert row above")
|
||||||
|
enabled: root.model.selectedRow > -1
|
||||||
|
onClicked: root.model.insertRow(root.model.selectedRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.deleterow_medium
|
||||||
|
tooltip: qsTr("Delete selected row")
|
||||||
|
enabled: root.model.selectedRow > -1
|
||||||
|
onClicked: root.model.removeRow(root.model.selectedRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { // spacer
|
||||||
|
Layout.minimumHeight: 1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rightSideToolbar
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.updateContent_medium
|
||||||
|
tooltip: qsTr("Update existing file with changes")
|
||||||
|
enabled: root.model.collectionName !== ""
|
||||||
|
onClicked:
|
||||||
|
{
|
||||||
|
if (root.backend.selectedSourceAddress().indexOf("json") !== -1)
|
||||||
|
root.model.exportCollection(root.backend.selectedSourceAddress(), root.model.collectionName, "JSON")
|
||||||
|
else
|
||||||
|
root.model.exportCollection(root.backend.selectedSourceAddress(), root.model.collectionName, "CSV")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: StudioTheme.Constants.export_medium
|
||||||
|
tooltip: qsTr("Export the model to a new file")
|
||||||
|
enabled: root.model.collectionName !== ""
|
||||||
|
onClicked: exportMenu.popup()
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.Menu {
|
||||||
|
id: exportMenu
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Export as JSON")
|
||||||
|
onTriggered:
|
||||||
|
{
|
||||||
|
fileDialog.defaultSuffix = "json"
|
||||||
|
fileDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Export as CSV")
|
||||||
|
onTriggered:
|
||||||
|
{
|
||||||
|
fileDialog.defaultSuffix = "csv"
|
||||||
|
fileDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PlatformWidgets.FileDialog {
|
||||||
|
id: fileDialog
|
||||||
|
fileMode: PlatformWidgets.FileDialog.SaveFile
|
||||||
|
onAccepted:
|
||||||
|
{
|
||||||
|
var fileAddress = file.toString()
|
||||||
|
|
||||||
|
if (fileAddress.indexOf("json") !== -1)
|
||||||
|
root.model.exportCollection(fileAddress, root.model.collectionName, "JSON")
|
||||||
|
else if (fileAddress.indexOf("csv") !== -1)
|
||||||
|
root.model.exportCollection(fileAddress, root.model.collectionName, "CSV")
|
||||||
|
|
||||||
|
fileDialog.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component IconButton: HelperWidgets.IconButton {
|
||||||
|
Layout.preferredHeight: root.iconHeight
|
||||||
|
Layout.preferredWidth: root.iconHeight
|
||||||
|
radius: StudioTheme.Values.smallRadius
|
||||||
|
iconSize: StudioTheme.Values.bigFont
|
||||||
|
}
|
||||||
|
|
||||||
|
component Spacer: Item {
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.columnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
RegularExpressionValidator {
|
||||||
|
id: nameValidator
|
||||||
|
regularExpression: /^\w+$/
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.Dialog {
|
||||||
|
id: addColumnDialog
|
||||||
|
|
||||||
|
property int clickedIndex: -1
|
||||||
|
property bool nameIsValid
|
||||||
|
|
||||||
|
title: qsTr("Add Column")
|
||||||
|
|
||||||
|
function popUp(index)
|
||||||
|
{
|
||||||
|
addColumnDialog.clickedIndex = index
|
||||||
|
columnName.text = ""
|
||||||
|
addedPropertyType.currentIndex = addedPropertyType.find("String")
|
||||||
|
|
||||||
|
addColumnDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addColumnName() {
|
||||||
|
if (addColumnDialog.nameIsValid) {
|
||||||
|
root.model.addColumn(addColumnDialog.clickedIndex, columnName.text, addedPropertyType.currentText)
|
||||||
|
addColumnDialog.accept()
|
||||||
|
} else {
|
||||||
|
addColumnDialog.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Column name:")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.TextField {
|
||||||
|
id: columnName
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
actionIndicator.visible: false
|
||||||
|
translationIndicator.visible: false
|
||||||
|
validator: nameValidator
|
||||||
|
|
||||||
|
Keys.onEnterPressed: addColumnDialog.addColumnName()
|
||||||
|
Keys.onReturnPressed: addColumnDialog.addColumnName()
|
||||||
|
Keys.onEscapePressed: addColumnDialog.reject()
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
addColumnDialog.nameIsValid = (columnName.text !== ""
|
||||||
|
&& !root.model.isPropertyAvailable(columnName.text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitHeight: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("The model already contains \"%1\"!").arg(columnName.text)
|
||||||
|
visible: columnName.text !== "" && !addColumnDialog.nameIsValid
|
||||||
|
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
wrapMode: Label.WordWrap
|
||||||
|
padding: 5
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
border.color: StudioTheme.Values.themeWarning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Type:")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.ComboBox {
|
||||||
|
id: addedPropertyType
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
model: root.model.typesList()
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
enabled: addColumnDialog.nameIsValid
|
||||||
|
text: qsTr("Add")
|
||||||
|
onClicked: addColumnDialog.addColumnName()
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: addColumnDialog.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,434 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var model
|
||||||
|
required property var backend
|
||||||
|
required property var sortedModel
|
||||||
|
|
||||||
|
implicitWidth: 300
|
||||||
|
implicitHeight: 400
|
||||||
|
|
||||||
|
color: StudioTheme.Values.themeControlBackground
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: topRow
|
||||||
|
|
||||||
|
visible: collectionNameText.text !== ""
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
topMargin: 10
|
||||||
|
leftMargin: 15
|
||||||
|
rightMargin: 15
|
||||||
|
bottomMargin: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: collectionNameText
|
||||||
|
|
||||||
|
leftPadding: 8
|
||||||
|
rightPadding: 8
|
||||||
|
topPadding: 3
|
||||||
|
bottomPadding: 3
|
||||||
|
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
text: root.model.collectionName
|
||||||
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { // spacer
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionDetailsToolbar {
|
||||||
|
id: toolbar
|
||||||
|
model: root.model
|
||||||
|
backend: root.backend
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: implicitWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { // spacer
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
columns: 3
|
||||||
|
rowSpacing: 1
|
||||||
|
columnSpacing: 1
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.maximumWidth: parent.width
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
clip: true
|
||||||
|
visible: !tableView.model.isEmpty
|
||||||
|
color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
border.color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
Layout.preferredWidth: rowIdView.width
|
||||||
|
Layout.preferredHeight: headerView.height
|
||||||
|
Layout.minimumWidth: rowIdView.width
|
||||||
|
Layout.minimumHeight: headerView.height
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
font: headerTextMetrics.font
|
||||||
|
text: "#"
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalHeaderView {
|
||||||
|
id: headerView
|
||||||
|
|
||||||
|
property real topPadding: 5
|
||||||
|
property real bottomPadding: 5
|
||||||
|
|
||||||
|
Layout.preferredHeight: headerTextMetrics.height + topPadding + bottomPadding
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
syncView: tableView
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
delegate: HeaderDelegate {
|
||||||
|
id: horizontalHeaderItem
|
||||||
|
|
||||||
|
selectedItem: tableView.model.selectedColumn
|
||||||
|
color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
|
||||||
|
function getGlobalBottomLeft() {
|
||||||
|
return mapToGlobal(0, horizontalHeaderItem.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
tableView.model.selectColumn(index)
|
||||||
|
|
||||||
|
if (mouse.button === Qt.RightButton)
|
||||||
|
headerMenu.popIndex(index, horizontalHeaderItem.getGlobalBottomLeft())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.Menu {
|
||||||
|
id: headerMenu
|
||||||
|
|
||||||
|
property int clickedHeader: -1
|
||||||
|
property point initialPosition
|
||||||
|
|
||||||
|
function popIndex(clickedIndex, clickedRect)
|
||||||
|
{
|
||||||
|
headerMenu.clickedHeader = clickedIndex
|
||||||
|
headerMenu.initialPosition = clickedRect
|
||||||
|
headerMenu.popup()
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: {
|
||||||
|
headerMenu.clickedHeader = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Edit")
|
||||||
|
onTriggered: editProperyDialog.editProperty(headerMenu.clickedHeader, headerMenu.initialPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Delete")
|
||||||
|
onTriggered: deleteColumnDialog.popUp(headerMenu.clickedHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Sort Ascending")
|
||||||
|
onTriggered: sortedModel.sort(headerMenu.clickedHeader, Qt.AscendingOrder)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Sort Descending")
|
||||||
|
onTriggered: sortedModel.sort(headerMenu.clickedHeader, Qt.DescendingOrder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalHeaderView {
|
||||||
|
id: rowIdView
|
||||||
|
|
||||||
|
syncView: tableView
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Layout.preferredHeight: tableView.height
|
||||||
|
Layout.rowSpan: 2
|
||||||
|
Layout.alignment: Qt.AlignTop + Qt.AlignLeft
|
||||||
|
|
||||||
|
delegate: HeaderDelegate {
|
||||||
|
selectedItem: tableView.model.selectedRow
|
||||||
|
color: StudioTheme.Values.themeControlBackgroundHover
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onClicked: tableView.model.selectRow(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TableView {
|
||||||
|
id: tableView
|
||||||
|
|
||||||
|
model: root.sortedModel
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Layout.preferredWidth: tableView.contentWidth
|
||||||
|
Layout.preferredHeight: tableView.contentHeight
|
||||||
|
Layout.minimumWidth: 100
|
||||||
|
Layout.minimumHeight: 20
|
||||||
|
Layout.maximumWidth: root.width
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: itemCell
|
||||||
|
implicitWidth: 100
|
||||||
|
implicitHeight: itemText.height
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: itemText
|
||||||
|
|
||||||
|
text: display ? display : ""
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
leftPadding: 5
|
||||||
|
topPadding: 3
|
||||||
|
bottomPadding: 3
|
||||||
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
TableView.editDelegate: CollectionDetailsEditDelegate {
|
||||||
|
anchors {
|
||||||
|
top: itemText.top
|
||||||
|
left: itemText.left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "default"
|
||||||
|
when: !itemSelected
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: itemCell
|
||||||
|
color: StudioTheme.Values.themeControlBackground
|
||||||
|
border.color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: itemText
|
||||||
|
color: StudioTheme.Values.themePlaceholderTextColorInteraction
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "selected"
|
||||||
|
when: itemSelected
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: itemCell
|
||||||
|
color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
border.color: StudioTheme.Values.themeControlBackground
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: itemText
|
||||||
|
color: StudioTheme.Values.themeInteraction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.IconButton {
|
||||||
|
id: addColumnContainer
|
||||||
|
|
||||||
|
iconSize:16
|
||||||
|
Layout.preferredWidth: 24
|
||||||
|
Layout.preferredHeight: tableView.height
|
||||||
|
Layout.minimumHeight: 24
|
||||||
|
Layout.alignment: Qt.AlignLeft + Qt.AlignVCenter
|
||||||
|
|
||||||
|
icon: StudioTheme.Constants.create_medium
|
||||||
|
tooltip: "Add Column"
|
||||||
|
|
||||||
|
onClicked: toolbar.addNewColumn()
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.IconButton {
|
||||||
|
id: addRowContainer
|
||||||
|
|
||||||
|
iconSize:16
|
||||||
|
Layout.preferredWidth: tableView.width
|
||||||
|
Layout.preferredHeight: 24
|
||||||
|
Layout.minimumWidth: 24
|
||||||
|
Layout.alignment: Qt.AlignTop + Qt.AlignHCenter
|
||||||
|
|
||||||
|
icon: StudioTheme.Constants.create_medium
|
||||||
|
tooltip: "Add Row"
|
||||||
|
|
||||||
|
onClicked: toolbar.addNewRow()
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
text: qsTr("Select a model to continue")
|
||||||
|
visible: !topRow.visible
|
||||||
|
textFormat: Text.RichText
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
font.pixelSize: StudioTheme.Values.mediumFontSize
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: headerTextMetrics
|
||||||
|
|
||||||
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
|
text: "Xq"
|
||||||
|
}
|
||||||
|
|
||||||
|
component HeaderDelegate: Rectangle {
|
||||||
|
id: headerItem
|
||||||
|
|
||||||
|
required property int selectedItem
|
||||||
|
property alias horizontalAlignment: headerText.horizontalAlignment
|
||||||
|
property alias verticalAlignment: headerText.verticalAlignment
|
||||||
|
|
||||||
|
implicitWidth: headerText.implicitWidth
|
||||||
|
implicitHeight: headerText.implicitHeight
|
||||||
|
border.width: 1
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: headerText
|
||||||
|
|
||||||
|
topPadding: headerView.topPadding
|
||||||
|
bottomPadding: headerView.bottomPadding
|
||||||
|
leftPadding: 5
|
||||||
|
rightPadding: 5
|
||||||
|
text: display
|
||||||
|
font: headerTextMetrics.font
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "default"
|
||||||
|
when: index !== selectedItem
|
||||||
|
PropertyChanges {
|
||||||
|
target: headerItem
|
||||||
|
border.color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: headerText
|
||||||
|
font.bold: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "selected"
|
||||||
|
when: index === selectedItem
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: headerItem
|
||||||
|
border.color: StudioTheme.Values.themeControlBackground
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: headerText
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
EditPropertyDialog {
|
||||||
|
id: editProperyDialog
|
||||||
|
model: root.model
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.Dialog {
|
||||||
|
id: deleteColumnDialog
|
||||||
|
|
||||||
|
property int clickedIndex: -1
|
||||||
|
|
||||||
|
title: qsTr("Delete Column")
|
||||||
|
width: 400
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
root.model.removeColumn(clickedIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
function popUp(index)
|
||||||
|
{
|
||||||
|
deleteColumnDialog.clickedIndex = index
|
||||||
|
deleteColumnDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: StudioTheme.Values.sectionColumnSpacing
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Are you sure that you want to delete column \"%1\"?").arg(
|
||||||
|
root.model.headerData(
|
||||||
|
deleteColumnDialog.clickedIndex, Qt.Horizontal))
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Delete")
|
||||||
|
onClicked: deleteColumnDialog.accept()
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: deleteColumnDialog.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import Qt.labs.platform as PlatformWidgets
|
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 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
@@ -12,9 +12,10 @@ Item {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
implicitWidth: 300
|
implicitWidth: 300
|
||||||
implicitHeight: innerRect.height + 6
|
implicitHeight: innerRect.height + 3
|
||||||
|
|
||||||
property color textColor
|
property color textColor
|
||||||
|
property string sourceType
|
||||||
|
|
||||||
signal selectItem(int itemIndex)
|
signal selectItem(int itemIndex)
|
||||||
signal deleteItem()
|
signal deleteItem()
|
||||||
@@ -23,7 +24,7 @@ Item {
|
|||||||
id: boundingRect
|
id: boundingRect
|
||||||
|
|
||||||
anchors.centerIn: root
|
anchors.centerIn: root
|
||||||
width: root.width - 24
|
width: parent.width
|
||||||
height: nameHolder.height
|
height: nameHolder.height
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
@@ -47,21 +48,23 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
width: parent.width - threeDots.width
|
width: parent.width
|
||||||
leftPadding: 20
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: moveTool
|
id: moveTool
|
||||||
|
|
||||||
property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
|
property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
|
||||||
|
|
||||||
width: moveTool.style.squareControlSize.width
|
Layout.preferredWidth: moveTool.style.squareControlSize.width
|
||||||
height: nameHolder.height
|
Layout.preferredHeight: nameHolder.height
|
||||||
|
Layout.leftMargin: 12
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
|
||||||
text: StudioTheme.Constants.dragmarks
|
text: StudioTheme.Constants.dragmarks
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
font.pixelSize: moveTool.style.baseIconFontSize
|
font.pixelSize: moveTool.style.baseIconFontSize
|
||||||
|
color: root.textColor
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
@@ -69,9 +72,12 @@ Item {
|
|||||||
Text {
|
Text {
|
||||||
id: nameHolder
|
id: nameHolder
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
|
||||||
text: collectionName
|
text: collectionName
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
color: textColor
|
color: root.textColor
|
||||||
leftPadding: 5
|
leftPadding: 5
|
||||||
topPadding: 8
|
topPadding: 8
|
||||||
rightPadding: 8
|
rightPadding: 8
|
||||||
@@ -79,82 +85,92 @@ Item {
|
|||||||
elide: Text.ElideMiddle
|
elide: Text.ElideMiddle
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: threeDots
|
id: threeDots
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
text: StudioTheme.Constants.more_medium
|
text: StudioTheme.Constants.more_medium
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
font.pixelSize: StudioTheme.Values.baseIconFontSize
|
font.pixelSize: StudioTheme.Values.baseIconFontSize
|
||||||
color: textColor
|
color: root.textColor
|
||||||
anchors.right: boundingRect.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
rightPadding: 12
|
rightPadding: 12
|
||||||
topPadding: nameHolder.topPadding
|
topPadding: nameHolder.topPadding
|
||||||
bottomPadding: nameHolder.bottomPadding
|
bottomPadding: nameHolder.bottomPadding
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton + Qt.LeftButton
|
acceptedButtons: Qt.RightButton | Qt.LeftButton
|
||||||
onClicked: (event) => {
|
onClicked: collectionMenu.popup()
|
||||||
collectionMenu.open()
|
|
||||||
event.accepted = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformWidgets.Menu {
|
StudioControls.Menu {
|
||||||
id: collectionMenu
|
id: collectionMenu
|
||||||
|
|
||||||
PlatformWidgets.MenuItem {
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Delete")
|
text: qsTr("Delete")
|
||||||
shortcut: StandardKey.Delete
|
shortcut: StandardKey.Delete
|
||||||
onTriggered: deleteDialog.open()
|
onTriggered: deleteDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformWidgets.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Rename")
|
text: qsTr("Rename")
|
||||||
shortcut: StandardKey.Replace
|
shortcut: StandardKey.Replace
|
||||||
onTriggered: renameDialog.open()
|
onTriggered: renameDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component Spacer: Item {
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.columnGap
|
||||||
|
}
|
||||||
|
|
||||||
StudioControls.Dialog {
|
StudioControls.Dialog {
|
||||||
id: deleteDialog
|
id: deleteDialog
|
||||||
|
|
||||||
title: qsTr("Deleting whole collection")
|
title: qsTr("Deleting the model")
|
||||||
|
clip: true
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: ColumnLayout {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("Are you sure that you want to delete collection \"" + collectionName + "\"?")
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
text: {
|
||||||
|
if (root.sourceType === "json") {
|
||||||
|
qsTr("Are you sure that you want to delete model \"%1\"?"
|
||||||
|
+ "\nThe model will be deleted permanently.").arg(collectionName)
|
||||||
|
} else if (root.sourceType === "csv") {
|
||||||
|
qsTr("Are you sure that you want to delete model \"%1\"?"
|
||||||
|
+ "\nThe model will be removed from the project "
|
||||||
|
+ "but the file will not be deleted.").arg(collectionName)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // spacer
|
Spacer {}
|
||||||
width: 1
|
|
||||||
height: 20
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
anchors.right: parent.right
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
spacing: 10
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: btnDelete
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Delete")
|
text: qsTr("Delete")
|
||||||
onClicked: root.deleteItem(index)
|
onClicked: root.deleteItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
onClicked: deleteDialog.reject()
|
onClicked: deleteDialog.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,7 +180,7 @@ Item {
|
|||||||
StudioControls.Dialog {
|
StudioControls.Dialog {
|
||||||
id: renameDialog
|
id: renameDialog
|
||||||
|
|
||||||
title: qsTr("Rename collection")
|
title: qsTr("Rename model")
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (newNameField.text !== "")
|
if (newNameField.text !== "")
|
||||||
@@ -175,7 +191,7 @@ Item {
|
|||||||
newNameField.text = collectionName
|
newNameField.text = collectionName
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: ColumnLayout {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@@ -183,9 +199,10 @@ Item {
|
|||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Spacer {}
|
||||||
spacing: 10
|
|
||||||
Text {
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
text: qsTr("New name:")
|
text: qsTr("New name:")
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
@@ -193,7 +210,9 @@ Item {
|
|||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: newNameField
|
id: newNameField
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
actionIndicator.visible: false
|
actionIndicator.visible: false
|
||||||
translationIndicator.visible: false
|
translationIndicator.visible: false
|
||||||
validator: newNameValidator
|
validator: newNameValidator
|
||||||
@@ -206,37 +225,31 @@ Item {
|
|||||||
btnRename.enabled = newNameField.text !== ""
|
btnRename.enabled = newNameField.text !== ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Item { // spacer
|
Spacer {}
|
||||||
width: 1
|
|
||||||
height: 20
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
anchors.right: parent.right
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
spacing: 10
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: btnRename
|
id: btnRename
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
text: qsTr("Rename")
|
text: qsTr("Rename")
|
||||||
onClicked: renameDialog.accept()
|
onClicked: renameDialog.accept()
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
onClicked: renameDialog.reject()
|
onClicked: renameDialog.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.RegExpValidator {
|
RegularExpressionValidator {
|
||||||
id: newNameValidator
|
id: newNameValidator
|
||||||
regExp: /^\w+$/
|
regularExpression: /^\w+$/
|
||||||
}
|
}
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
@@ -277,12 +290,12 @@ Item {
|
|||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: innerRect
|
target: innerRect
|
||||||
opacity: 1
|
opacity: 1
|
||||||
color: StudioTheme.Values.themeControlBackgroundInteraction
|
color: StudioTheme.Values.themeIconColorSelected
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: root
|
target: root
|
||||||
textColor: StudioTheme.Values.themeIconColorSelected
|
textColor: StudioTheme.Values.themeTextSelectedTextColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuickDesignerTheme 1.0
|
import QtQuickDesignerTheme 1.0
|
||||||
import HelperWidgets 2.0 as HelperWidgets
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme 1.0 as StudioTheme
|
||||||
@@ -14,7 +15,8 @@ Item {
|
|||||||
|
|
||||||
property var rootView: CollectionEditorBackend.rootView
|
property var rootView: CollectionEditorBackend.rootView
|
||||||
property var model: CollectionEditorBackend.model
|
property var model: CollectionEditorBackend.model
|
||||||
property var singleCollectionModel: CollectionEditorBackend.singleCollectionModel
|
property var collectionDetailsModel: CollectionEditorBackend.collectionDetailsModel
|
||||||
|
property var collectionDetailsSortFilterModel: CollectionEditorBackend.collectionDetailsSortFilterModel
|
||||||
|
|
||||||
function showWarning(title, message) {
|
function showWarning(title, message) {
|
||||||
warningDialog.title = title
|
warningDialog.title = title
|
||||||
@@ -40,6 +42,7 @@ Item {
|
|||||||
id: newCollection
|
id: newCollection
|
||||||
|
|
||||||
backendValue: root.rootView
|
backendValue: root.rootView
|
||||||
|
sourceModel: root.model
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,57 +53,63 @@ Item {
|
|||||||
message: ""
|
message: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
GridLayout {
|
||||||
id: collectionsRect
|
id: grid
|
||||||
|
readonly property bool isHorizontal: width >= 500
|
||||||
|
|
||||||
color: StudioTheme.Values.themeToolbarBackground
|
anchors.fill: parent
|
||||||
width: 300
|
columns: isHorizontal ? 3 : 1
|
||||||
height: root.height
|
|
||||||
|
|
||||||
Column {
|
ColumnLayout {
|
||||||
width: parent.width
|
id: collectionsSideBar
|
||||||
|
|
||||||
Rectangle {
|
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||||
width: parent.width
|
Layout.minimumWidth: 300
|
||||||
height: StudioTheme.Values.height + 5
|
Layout.fillWidth: !grid.isHorizontal
|
||||||
color: StudioTheme.Values.themeToolbarBackground
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 50
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: collectionText
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
text: qsTr("Data Models")
|
||||||
text: qsTr("Collections")
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
font.pixelSize: StudioTheme.Values.mediumIconFont
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
leftPadding: 15
|
leftPadding: 15
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
IconTextButton {
|
||||||
anchors.right: parent.right
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
rightPadding: 12
|
|
||||||
spacing: 2
|
|
||||||
|
|
||||||
HelperWidgets.IconButton {
|
icon: StudioTheme.Constants.import_medium
|
||||||
icon: StudioTheme.Constants.downloadjson_large
|
text: qsTr("JSON")
|
||||||
tooltip: qsTr("Import Json")
|
tooltip: qsTr("Import JSON")
|
||||||
|
radius: StudioTheme.Values.smallRadius
|
||||||
|
|
||||||
onClicked: jsonImporter.open()
|
onClicked: jsonImporter.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.IconButton {
|
IconTextButton {
|
||||||
icon: StudioTheme.Constants.downloadcsv_large
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
|
icon: StudioTheme.Constants.import_medium
|
||||||
|
text: qsTr("CSV")
|
||||||
tooltip: qsTr("Import CSV")
|
tooltip: qsTr("Import CSV")
|
||||||
|
radius: StudioTheme.Values.smallRadius
|
||||||
|
|
||||||
onClicked: csvImporter.open()
|
onClicked: csvImporter.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { // Collections
|
Rectangle { // Model Groups
|
||||||
width: parent.width
|
Layout.fillWidth: true
|
||||||
color: StudioTheme.Values.themeBackgroundColorNormal
|
color: StudioTheme.Values.themeBackgroundColorNormal
|
||||||
height: 330
|
Layout.minimumHeight: 150
|
||||||
|
Layout.preferredHeight: sourceListView.contentHeight
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -114,41 +123,46 @@ Item {
|
|||||||
ListView {
|
ListView {
|
||||||
id: sourceListView
|
id: sourceListView
|
||||||
|
|
||||||
width: parent.width
|
anchors.fill: parent
|
||||||
height: contentHeight
|
|
||||||
model: root.model
|
model: root.model
|
||||||
|
|
||||||
delegate: ModelSourceItem {
|
delegate: ModelSourceItem {
|
||||||
|
implicitWidth: sourceListView.width
|
||||||
onDeleteItem: root.model.removeRow(index)
|
onDeleteItem: root.model.removeRow(index)
|
||||||
|
hasSelectedTarget: root.rootView.targetNodeSelected
|
||||||
|
onAssignToSelected: root.rootView.assignSourceNodeToSelectedItem(sourceNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
HelperWidgets.IconButton {
|
||||||
width: parent.width
|
|
||||||
height: addCollectionButton.height
|
|
||||||
color: StudioTheme.Values.themeBackgroundColorNormal
|
|
||||||
|
|
||||||
IconTextButton {
|
|
||||||
id: addCollectionButton
|
id: addCollectionButton
|
||||||
|
|
||||||
anchors.centerIn: parent
|
iconSize:16
|
||||||
text: qsTr("Add new collection")
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: 24
|
||||||
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||||
|
|
||||||
|
tooltip: qsTr("Add a new model")
|
||||||
icon: StudioTheme.Constants.create_medium
|
icon: StudioTheme.Constants.create_medium
|
||||||
onClicked: newCollection.open()
|
onClicked: newCollection.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Rectangle { // Splitter
|
||||||
|
Layout.fillWidth: !grid.isHorizontal
|
||||||
|
Layout.fillHeight: grid.isHorizontal
|
||||||
|
Layout.minimumWidth: 2
|
||||||
|
Layout.minimumHeight: 2
|
||||||
|
color: "black"
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleCollectionView {
|
CollectionDetailsView {
|
||||||
model: root.singleCollectionModel
|
model: root.collectionDetailsModel
|
||||||
anchors {
|
backend: root.model
|
||||||
left: collectionsRect.right
|
sortedModel: root.collectionDetailsSortFilterModel
|
||||||
right: parent.right
|
Layout.fillHeight: true
|
||||||
top: parent.top
|
Layout.fillWidth: true
|
||||||
bottom: parent.bottom
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuickDesignerTheme 1.0
|
import QtQuickDesignerTheme 1.0
|
||||||
import Qt.labs.platform as PlatformWidgets
|
import Qt.labs.platform as PlatformWidgets
|
||||||
import HelperWidgets 2.0 as HelperWidgets
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
@@ -32,9 +33,9 @@ StudioControls.Dialog {
|
|||||||
fileName.text = ""
|
fileName.text = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.RegExpValidator {
|
RegularExpressionValidator {
|
||||||
id: fileNameValidator
|
id: fileNameValidator
|
||||||
regExp: /^(\w[^*><?|]*)[^/\\:*><?|]$/
|
regularExpression: /^(\w[^*><?|]*)[^/\\:*><?|]$/
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformWidgets.FileDialog {
|
PlatformWidgets.FileDialog {
|
||||||
@@ -51,21 +52,30 @@ StudioControls.Dialog {
|
|||||||
onClosed: root.reject()
|
onClosed: root.reject()
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
component Spacer: Item {
|
||||||
spacing: 10
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.columnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: 10
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("File name: ")
|
text: qsTr("File name: ")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: fileName
|
id: fileName
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
actionIndicator.visible: false
|
actionIndicator.visible: false
|
||||||
translationIndicator.visible: false
|
translationIndicator.visible: false
|
||||||
validator: fileNameValidator
|
validator: fileNameValidator
|
||||||
@@ -74,49 +84,58 @@ StudioControls.Dialog {
|
|||||||
Keys.onReturnPressed: btnCreate.onClicked()
|
Keys.onReturnPressed: btnCreate.onClicked()
|
||||||
Keys.onEscapePressed: root.reject()
|
Keys.onEscapePressed: root.reject()
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: root.fileExists = root.backendValue.isCsvFile(fileName.text)
|
||||||
root.fileExists = root.backendValue.isCsvFile(fileName.text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: fileDialogButton
|
id: fileDialogButton
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
text: qsTr("Open")
|
text: qsTr("Open")
|
||||||
onClicked: fileDialog.open()
|
onClicked: fileDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Spacer {}
|
||||||
spacing: 10
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("Collection name: ")
|
text: qsTr("The model name: ")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: collectionName
|
id: collectionName
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Layout.fillWidth: true
|
||||||
|
|
||||||
actionIndicator.visible: false
|
actionIndicator.visible: false
|
||||||
translationIndicator.visible: false
|
translationIndicator.visible: false
|
||||||
validator: HelperWidgets.RegExpValidator {
|
validator: RegularExpressionValidator {
|
||||||
regExp: /^\w+$/
|
regularExpression: /^\w+$/
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: btnCreate.onClicked()
|
Keys.onEnterPressed: btnCreate.onClicked()
|
||||||
Keys.onReturnPressed: btnCreate.onClicked()
|
Keys.onReturnPressed: btnCreate.onClicked()
|
||||||
Keys.onEscapePressed: root.reject()
|
Keys.onEscapePressed: root.reject()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Spacer { implicitHeight: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
Label {
|
||||||
id: fieldErrorText
|
id: fieldErrorText
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
anchors.right: parent.right
|
wrapMode: Label.WordWrap
|
||||||
|
padding: 5
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
border.color: StudioTheme.Values.themeWarning
|
||||||
|
}
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
@@ -145,31 +164,28 @@ StudioControls.Dialog {
|
|||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: fieldErrorText
|
target: fieldErrorText
|
||||||
text: qsTr("Collection name can not be empty")
|
text: qsTr("The model name can not be empty")
|
||||||
visible: true
|
visible: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // spacer
|
Spacer {}
|
||||||
width: 1
|
|
||||||
height: 20
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
anchors.right: parent.right
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
spacing: 10
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: btnCreate
|
id: btnCreate
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
text: qsTr("Import")
|
text: qsTr("Import")
|
||||||
enabled: root.fileExists && collectionName.text !== ""
|
enabled: root.fileExists && collectionName.text !== ""
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
let csvLoaded = root.backendValue.loadCsvFile(collectionName.text, fileName.text)
|
let csvLoaded = root.backendValue.loadCsvFile(fileName.text, collectionName.text)
|
||||||
|
|
||||||
if (csvLoaded)
|
if (csvLoaded)
|
||||||
root.accept()
|
root.accept()
|
||||||
@@ -180,7 +196,6 @@ StudioControls.Dialog {
|
|||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
onClicked: root.reject()
|
onClicked: root.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
|
|
||||||
|
StudioControls.Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var model
|
||||||
|
property int __propertyIndex: -1
|
||||||
|
property string __oldName
|
||||||
|
|
||||||
|
title: qsTr("Edit Property")
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
function editProperty(index, initialPosition) {
|
||||||
|
root.__propertyIndex = index
|
||||||
|
|
||||||
|
if (root.__propertyIndex < 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
let previousName = root.model.propertyName(root.__propertyIndex)
|
||||||
|
let previousType = root.model.propertyType(root.__propertyIndex)
|
||||||
|
|
||||||
|
root.__oldName = previousName
|
||||||
|
newNameField.text = previousName
|
||||||
|
|
||||||
|
propertyType.initialType = previousType
|
||||||
|
|
||||||
|
forceChangeType.checked = false
|
||||||
|
|
||||||
|
let newPoint = mapFromGlobal(initialPosition.x, initialPosition.y)
|
||||||
|
x = newPoint.x
|
||||||
|
y = newPoint.y
|
||||||
|
|
||||||
|
root.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
if (newNameField.text !== "" && newNameField.text !== root.__oldName)
|
||||||
|
root.model.renameColumn(root.__propertyIndex, newNameField.text)
|
||||||
|
|
||||||
|
if (propertyType.changed || forceChangeType.checked)
|
||||||
|
root.model.setPropertyType(root.__propertyIndex, propertyType.currentText, forceChangeType.checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
onRejected: {
|
||||||
|
let currentDatatype = propertyType.initialType
|
||||||
|
propertyType.currentIndex = propertyType.find(currentDatatype)
|
||||||
|
}
|
||||||
|
|
||||||
|
component Spacer: Item {
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.columnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Name")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.TextField {
|
||||||
|
id: newNameField
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
actionIndicator.visible: false
|
||||||
|
translationIndicator.visible: false
|
||||||
|
|
||||||
|
Keys.onEnterPressed: root.accept()
|
||||||
|
Keys.onReturnPressed: root.accept()
|
||||||
|
Keys.onEscapePressed: root.reject()
|
||||||
|
|
||||||
|
validator: RegularExpressionValidator {
|
||||||
|
regularExpression: /^\w+$/
|
||||||
|
}
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
editButton.enabled = newNameField.text !== ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Type")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.ComboBox {
|
||||||
|
id: propertyType
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
property string initialType
|
||||||
|
readonly property bool changed: propertyType.initialType !== propertyType.currentText
|
||||||
|
|
||||||
|
model: root.model.typesList()
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
|
||||||
|
onInitialTypeChanged: propertyType.currentIndex = propertyType.find(initialType)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
StudioControls.CheckBox {
|
||||||
|
id: forceChangeType
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Force update values")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
visible: warningBox.visible
|
||||||
|
implicitHeight: StudioTheme.Values.controlLabelGap
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: warningBox
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: warning.height
|
||||||
|
|
||||||
|
visible: propertyType.initialType !== propertyType.currentText
|
||||||
|
color: "transparent"
|
||||||
|
clip: true
|
||||||
|
border.color: StudioTheme.Values.themeWarning
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: warning
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
HelperWidgets.IconLabel {
|
||||||
|
icon: StudioTheme.Constants.warning_medium
|
||||||
|
Layout.leftMargin: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Conversion from %1 to %2 may lead to irreversible data loss")
|
||||||
|
.arg(propertyType.initialType)
|
||||||
|
.arg(propertyType.currentText)
|
||||||
|
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
id: editButton
|
||||||
|
|
||||||
|
text: qsTr("Edit")
|
||||||
|
onClicked: root.accept()
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
// 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 QtQuick.Layouts
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -10,42 +12,45 @@ Rectangle {
|
|||||||
required property string text
|
required property string text
|
||||||
required property string icon
|
required property string icon
|
||||||
|
|
||||||
|
property alias tooltip: toolTip.text
|
||||||
property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
|
property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
|
||||||
|
property int fontSize: StudioTheme.Values.baseFontSize
|
||||||
|
|
||||||
implicitHeight: style.squareControlSize.height
|
implicitHeight: style.squareControlSize.height
|
||||||
implicitWidth: rowAlign.width
|
implicitWidth: rowAlign.width
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
id: rowAlign
|
id: rowAlign
|
||||||
spacing: 0
|
|
||||||
leftPadding: StudioTheme.Values.inputHorizontalPadding
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
rightPadding: StudioTheme.Values.inputHorizontalPadding
|
spacing: StudioTheme.Values.inputHorizontalPadding
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: iconItem
|
id: iconItem
|
||||||
width: root.style.squareControlSize.width
|
|
||||||
height: root.height
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
text: root.icon
|
text: root.icon
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
font.pixelSize: root.style.baseIconFontSize
|
font.pixelSize: StudioTheme.Values.bigFont
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
leftPadding: StudioTheme.Values.inputHorizontalPadding
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: textItem
|
id: textItem
|
||||||
height: root.height
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
text: root.text
|
text: root.text
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.family: StudioTheme.Constants.font.family
|
font.family: StudioTheme.Constants.font.family
|
||||||
font.pixelSize: root.style.baseIconFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
rightPadding: StudioTheme.Values.inputHorizontalPadding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,13 +61,20 @@ Rectangle {
|
|||||||
onClicked: root.clicked()
|
onClicked: root.clicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
id: toolTip
|
||||||
|
|
||||||
|
visible: mouseArea.containsMouse && text !== ""
|
||||||
|
delay: 1000
|
||||||
|
}
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "default"
|
name: "default"
|
||||||
when: !mouseArea.pressed && !mouseArea.containsMouse
|
when: !mouseArea.pressed && !mouseArea.containsMouse
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: root
|
target: root
|
||||||
color: StudioTheme.Values.themeBackgroundColorNormal
|
color: StudioTheme.Values.themeControlBackground
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuickDesignerTheme 1.0
|
import QtQuickDesignerTheme 1.0
|
||||||
import Qt.labs.platform as PlatformWidgets
|
import Qt.labs.platform as PlatformWidgets
|
||||||
import HelperWidgets 2.0 as HelperWidgets
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
@@ -12,7 +13,7 @@ import StudioTheme as StudioTheme
|
|||||||
StudioControls.Dialog {
|
StudioControls.Dialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
title: qsTr("Import Collections")
|
title: qsTr("Import Models")
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
closePolicy: Popup.CloseOnEscape
|
closePolicy: Popup.CloseOnEscape
|
||||||
modal: true
|
modal: true
|
||||||
@@ -21,7 +22,7 @@ StudioControls.Dialog {
|
|||||||
property bool fileExists: false
|
property bool fileExists: false
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
fileName.text = qsTr("New Json File")
|
fileName.text = qsTr("New JSON File")
|
||||||
fileName.selectAll()
|
fileName.selectAll()
|
||||||
fileName.forceActiveFocus()
|
fileName.forceActiveFocus()
|
||||||
}
|
}
|
||||||
@@ -30,9 +31,9 @@ StudioControls.Dialog {
|
|||||||
fileName.text = ""
|
fileName.text = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.RegExpValidator {
|
RegularExpressionValidator {
|
||||||
id: fileNameValidator
|
id: fileNameValidator
|
||||||
regExp: /^(\w[^*><?|]*)[^/\\:*><?|]$/
|
regularExpression: /^(\w[^*><?|]*)[^/\\:*><?|]$/
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformWidgets.FileDialog {
|
PlatformWidgets.FileDialog {
|
||||||
@@ -49,21 +50,25 @@ StudioControls.Dialog {
|
|||||||
onClosed: root.reject()
|
onClosed: root.reject()
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: ColumnLayout {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: 10
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("File name: ")
|
text: qsTr("File name: ")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: fileName
|
id: fileName
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
actionIndicator.visible: false
|
actionIndicator.visible: false
|
||||||
translationIndicator.visible: false
|
translationIndicator.visible: false
|
||||||
validator: fileNameValidator
|
validator: fileNameValidator
|
||||||
@@ -72,38 +77,52 @@ StudioControls.Dialog {
|
|||||||
Keys.onReturnPressed: btnCreate.onClicked()
|
Keys.onReturnPressed: btnCreate.onClicked()
|
||||||
Keys.onEscapePressed: root.reject()
|
Keys.onEscapePressed: root.reject()
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: root.fileExists = root.backendValue.isJsonFile(fileName.text)
|
||||||
root.fileExists = root.backendValue.isJsonFile(fileName.text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: fileDialogButton
|
id: fileDialogButton
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
text: qsTr("Open")
|
text: qsTr("Open")
|
||||||
onClicked: fileDialog.open()
|
onClicked: fileDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Item { // spacer
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.controlLabelGap
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
padding: 5
|
||||||
text: qsTr("File name cannot be empty.")
|
text: qsTr("File name cannot be empty.")
|
||||||
|
wrapMode: Label.WordWrap
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
anchors.right: parent.right
|
|
||||||
visible: fileName.text === ""
|
visible: fileName.text === ""
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
border.color: StudioTheme.Values.themeWarning
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // spacer
|
Item { // spacer
|
||||||
width: 1
|
implicitWidth: 1
|
||||||
height: 20
|
implicitHeight: StudioTheme.Values.sectionColumnSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
anchors.right: parent.right
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
spacing: 10
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: btnCreate
|
id: btnCreate
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Import")
|
text: qsTr("Import")
|
||||||
enabled: root.fileExists
|
enabled: root.fileExists
|
||||||
@@ -119,7 +138,6 @@ StudioControls.Dialog {
|
|||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
onClicked: root.reject()
|
onClicked: root.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
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 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
@@ -17,22 +18,22 @@ StudioControls.Dialog {
|
|||||||
implicitWidth: 300
|
implicitWidth: 300
|
||||||
modal: true
|
modal: true
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: ColumnLayout {
|
||||||
spacing: 20
|
spacing: StudioTheme.Values.sectionColumnSpacing
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
text: root.message
|
text: root.message
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: root.width
|
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
rightPadding: 10
|
rightPadding: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
text: qsTr("Close")
|
text: qsTr("Close")
|
||||||
anchors.right: parent.right
|
|
||||||
onClicked: root.reject()
|
onClicked: root.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
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 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
@@ -11,7 +12,9 @@ Item {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
implicitWidth: 300
|
implicitWidth: 300
|
||||||
implicitHeight: wholeColumn.height + 6
|
implicitHeight: wholeColumn.height
|
||||||
|
|
||||||
|
property bool hasSelectedTarget
|
||||||
|
|
||||||
property color textColor
|
property color textColor
|
||||||
property var collectionModel
|
property var collectionModel
|
||||||
@@ -20,16 +23,24 @@ Item {
|
|||||||
|
|
||||||
signal selectItem(int itemIndex)
|
signal selectItem(int itemIndex)
|
||||||
signal deleteItem()
|
signal deleteItem()
|
||||||
|
signal assignToSelected()
|
||||||
|
|
||||||
Column {
|
function toggleExpanded() {
|
||||||
|
if (collectionListView.count > 0)
|
||||||
|
root.expanded = !root.expanded || sourceIsSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
id: wholeColumn
|
id: wholeColumn
|
||||||
|
width: parent.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: boundingRect
|
id: boundingRect
|
||||||
|
|
||||||
anchors.centerIn: root
|
Layout.fillWidth: true
|
||||||
width: root.width - 24
|
Layout.preferredHeight: nameHolder.height
|
||||||
height: nameHolder.height
|
Layout.leftMargin: 6
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -48,8 +59,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDoubleClicked: (event) => {
|
onDoubleClicked: (event) => {
|
||||||
if (collectionListView.count > 0)
|
root.toggleExpanded()
|
||||||
root.expanded = !root.expanded;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,26 +68,27 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
width: parent.width - threeDots.width
|
width: parent.width
|
||||||
leftPadding: 20
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: expandButton
|
id: expandButton
|
||||||
|
|
||||||
property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
|
property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
|
||||||
|
|
||||||
width: expandButton.style.squareControlSize.width
|
Layout.preferredWidth: expandButton.style.squareControlSize.width
|
||||||
height: nameHolder.height
|
Layout.preferredHeight: nameHolder.height
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
|
||||||
text: StudioTheme.Constants.startNode
|
text: StudioTheme.Constants.startNode
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
font.pixelSize: expandButton.style.baseIconFontSize
|
font.pixelSize: 6
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
color: textColor
|
color: textColor
|
||||||
|
|
||||||
rotation: root.expanded ? 90 : 0
|
rotation: root.expanded ? 90 : 0
|
||||||
|
visible: collectionListView.count > 0
|
||||||
|
|
||||||
Behavior on rotation {
|
Behavior on rotation {
|
||||||
SpringAnimation { spring: 2; damping: 0.2 }
|
SpringAnimation { spring: 2; damping: 0.2 }
|
||||||
@@ -85,18 +96,17 @@ Item {
|
|||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton + Qt.LeftButton
|
acceptedButtons: Qt.RightButton | Qt.LeftButton
|
||||||
onClicked: (event) => {
|
onClicked: root.toggleExpanded()
|
||||||
root.expanded = !root.expanded
|
|
||||||
event.accepted = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visible: collectionListView.count > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: nameHolder
|
id: nameHolder
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
|
||||||
text: sourceName
|
text: sourceName
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
color: textColor
|
color: textColor
|
||||||
@@ -105,30 +115,29 @@ Item {
|
|||||||
rightPadding: 8
|
rightPadding: 8
|
||||||
bottomPadding: 8
|
bottomPadding: 8
|
||||||
elide: Text.ElideMiddle
|
elide: Text.ElideMiddle
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: threeDots
|
id: threeDots
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
|
||||||
text: StudioTheme.Constants.more_medium
|
text: StudioTheme.Constants.more_medium
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
font.pixelSize: StudioTheme.Values.baseIconFontSize
|
font.pixelSize: StudioTheme.Values.baseIconFontSize
|
||||||
color: textColor
|
color: textColor
|
||||||
anchors.right: boundingRect.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
rightPadding: 12
|
rightPadding: 12
|
||||||
topPadding: nameHolder.topPadding
|
topPadding: nameHolder.topPadding
|
||||||
bottomPadding: nameHolder.bottomPadding
|
bottomPadding: nameHolder.bottomPadding
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton + Qt.LeftButton
|
acceptedButtons: Qt.RightButton | Qt.LeftButton
|
||||||
onClicked: (event) => {
|
onClicked: collectionMenu.popup()
|
||||||
collectionMenu.popup()
|
|
||||||
event.accepted = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,18 +146,20 @@ Item {
|
|||||||
ListView {
|
ListView {
|
||||||
id: collectionListView
|
id: collectionListView
|
||||||
|
|
||||||
width: parent.width
|
Layout.fillWidth: true
|
||||||
height: root.expanded ? contentHeight : 0
|
Layout.preferredHeight: root.expanded ? contentHeight : 0
|
||||||
model: collections
|
Layout.leftMargin: 6
|
||||||
|
model: internalModels
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
Behavior on height {
|
Behavior on Layout.preferredHeight {
|
||||||
NumberAnimation {duration: 500}
|
NumberAnimation {duration: 500}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: CollectionItem {
|
delegate: CollectionItem {
|
||||||
width: parent.width
|
width: collectionListView.width
|
||||||
onDeleteItem: root.model.removeRow(index)
|
sourceType: collectionListView.model.sourceType
|
||||||
|
onDeleteItem: collectionListView.model.removeRow(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,6 +167,8 @@ Item {
|
|||||||
StudioControls.Menu {
|
StudioControls.Menu {
|
||||||
id: collectionMenu
|
id: collectionMenu
|
||||||
|
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Delete")
|
text: qsTr("Delete")
|
||||||
shortcut: StandardKey.Delete
|
shortcut: StandardKey.Delete
|
||||||
@@ -167,6 +180,17 @@ Item {
|
|||||||
shortcut: StandardKey.Replace
|
shortcut: StandardKey.Replace
|
||||||
onTriggered: renameDialog.open()
|
onTriggered: renameDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Assign to the selected node")
|
||||||
|
enabled: root.hasSelectedTarget
|
||||||
|
onTriggered: root.assignToSelected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component Spacer: Item {
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.sectionColumnSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.Dialog {
|
StudioControls.Dialog {
|
||||||
@@ -174,22 +198,17 @@ Item {
|
|||||||
|
|
||||||
title: qsTr("Deleting source")
|
title: qsTr("Deleting source")
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: ColumnLayout {
|
||||||
spacing: 2
|
spacing: StudioTheme.Values.sectionColumnSpacing
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("Are you sure that you want to delete source \"" + sourceName + "\"?")
|
text: qsTr("Are you sure that you want to delete source \"" + sourceName + "\"?")
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // spacer
|
RowLayout {
|
||||||
width: 1
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
height: 20
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.right: parent.right
|
|
||||||
spacing: 10
|
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: btnDelete
|
id: btnDelete
|
||||||
@@ -220,7 +239,7 @@ Item {
|
|||||||
newNameField.text = sourceName
|
newNameField.text = sourceName
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: ColumnLayout {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@@ -228,8 +247,8 @@ Item {
|
|||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Spacer {}
|
||||||
spacing: 10
|
|
||||||
Text {
|
Text {
|
||||||
text: qsTr("New name:")
|
text: qsTr("New name:")
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
@@ -238,6 +257,7 @@ Item {
|
|||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: newNameField
|
id: newNameField
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
actionIndicator.visible: false
|
actionIndicator.visible: false
|
||||||
translationIndicator.visible: false
|
translationIndicator.visible: false
|
||||||
validator: newNameValidator
|
validator: newNameValidator
|
||||||
@@ -250,16 +270,12 @@ Item {
|
|||||||
btnRename.enabled = newNameField.text !== ""
|
btnRename.enabled = newNameField.text !== ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Item { // spacer
|
Spacer {}
|
||||||
width: 1
|
|
||||||
height: 20
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
anchors.right: parent.right
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
spacing: 10
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: btnRename
|
id: btnRename
|
||||||
@@ -276,9 +292,9 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.RegExpValidator {
|
RegularExpressionValidator {
|
||||||
id: newNameValidator
|
id: newNameValidator
|
||||||
regExp: /^\w+$/
|
regularExpression: /^\w+$/
|
||||||
}
|
}
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
@@ -325,6 +341,12 @@ Item {
|
|||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: root
|
target: root
|
||||||
textColor: StudioTheme.Values.themeIconColorSelected
|
textColor: StudioTheme.Values.themeIconColorSelected
|
||||||
|
expanded: true
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: expandButton
|
||||||
|
enabled: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,23 +3,37 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuickDesignerTheme 1.0
|
import QtQuickDesignerTheme 1.0
|
||||||
|
import Qt.labs.platform as PlatformWidgets
|
||||||
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 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
import CollectionEditor 1.0
|
||||||
|
|
||||||
StudioControls.Dialog {
|
StudioControls.Dialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
title: qsTr("Add a new Collection")
|
enum SourceType { NewJson, NewCsv, ExistingCollection, NewCollectionToJson }
|
||||||
|
|
||||||
|
required property var backendValue
|
||||||
|
required property var sourceModel
|
||||||
|
|
||||||
|
readonly property alias collectionType: typeMode.collectionType
|
||||||
|
readonly property bool isValid: collectionName.isValid
|
||||||
|
&& jsonCollections.isValid
|
||||||
|
&& newCollectionPath.isValid
|
||||||
|
|
||||||
|
title: qsTr("Add a new Model")
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
closePolicy: Popup.CloseOnEscape
|
closePolicy: Popup.CloseOnEscape
|
||||||
modal: true
|
modal: true
|
||||||
|
|
||||||
required property var backendValue
|
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
collectionName.text = "Collection"
|
collectionName.text = qsTr("Model")
|
||||||
|
updateType()
|
||||||
|
updateJsonSourceIndex()
|
||||||
|
updateCollectionExists()
|
||||||
}
|
}
|
||||||
|
|
||||||
onRejected: {
|
onRejected: {
|
||||||
@@ -27,65 +41,252 @@ StudioControls.Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (collectionName.text !== "")
|
if (root.isValid) {
|
||||||
root.backendValue.addCollection(collectionName.text)
|
root.backendValue.addCollection(collectionName.text,
|
||||||
|
root.collectionType,
|
||||||
|
newCollectionPath.text,
|
||||||
|
jsonCollections.currentValue)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
function updateType() {
|
||||||
spacing: 10
|
newCollectionPath.text = ""
|
||||||
Row {
|
if (typeMode.currentValue === NewCollectionDialog.SourceType.NewJson) {
|
||||||
spacing: 10
|
newCollectionFileDialog.nameFilters = ["JSON Files (*.json)"]
|
||||||
Text {
|
newCollectionFileDialog.fileMode = PlatformWidgets.FileDialog.SaveFile
|
||||||
text: qsTr("Collection name: ")
|
newCollectionPath.enabled = true
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
jsonCollections.enabled = false
|
||||||
|
typeMode.collectionType = "json"
|
||||||
|
} else if (typeMode.currentValue === NewCollectionDialog.SourceType.NewCsv) {
|
||||||
|
newCollectionFileDialog.nameFilters = ["Comma-Separated Values (*.csv)"]
|
||||||
|
newCollectionFileDialog.fileMode = PlatformWidgets.FileDialog.SaveFile
|
||||||
|
newCollectionPath.enabled = true
|
||||||
|
jsonCollections.enabled = false
|
||||||
|
typeMode.collectionType = "csv"
|
||||||
|
} else if (typeMode.currentValue === NewCollectionDialog.SourceType.ExistingCollection) {
|
||||||
|
newCollectionFileDialog.nameFilters = ["All Model Group Files (*.json *.csv)",
|
||||||
|
"JSON Files (*.json)",
|
||||||
|
"Comma-Separated Values (*.csv)"]
|
||||||
|
newCollectionFileDialog.fileMode = PlatformWidgets.FileDialog.OpenFile
|
||||||
|
newCollectionPath.enabled = true
|
||||||
|
jsonCollections.enabled = false
|
||||||
|
typeMode.collectionType = "existing"
|
||||||
|
} else if (typeMode.currentValue === NewCollectionDialog.SourceType.NewCollectionToJson) {
|
||||||
|
newCollectionFileDialog.nameFilters = [""]
|
||||||
|
newCollectionPath.enabled = false
|
||||||
|
jsonCollections.enabled = true
|
||||||
|
typeMode.collectionType = "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateJsonSourceIndex() {
|
||||||
|
if (!jsonCollections.enabled) {
|
||||||
|
jsonCollections.currentIndex = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonCollections.currentIndex === -1 && jsonCollections.model.rowCount())
|
||||||
|
jsonCollections.currentIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCollectionExists() {
|
||||||
|
collectionName.alreadyExists = sourceModel.collectionExists(jsonCollections.currentValue,
|
||||||
|
collectionName.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
component NameField: Text {
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
horizontalAlignment: Qt.AlignRight
|
||||||
|
verticalAlignment: Qt.AlignCenter
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
font.family: StudioTheme.Constants.font.family
|
||||||
|
font.pixelSize: StudioTheme.Values.baseIconFontSize
|
||||||
|
}
|
||||||
|
|
||||||
|
component ErrorField: Text {
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
color: StudioTheme.Values.themeError
|
||||||
|
font.family: StudioTheme.Constants.font.family
|
||||||
|
font.pixelSize: StudioTheme.Values.baseIconFontSize
|
||||||
|
}
|
||||||
|
|
||||||
|
component Spacer: Item {
|
||||||
|
Layout.minimumWidth: 1
|
||||||
|
Layout.preferredHeight: StudioTheme.Values.columnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
NameField {
|
||||||
|
text: qsTr("Type")
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.ComboBox {
|
||||||
|
id: typeMode
|
||||||
|
|
||||||
|
property string collectionType
|
||||||
|
|
||||||
|
Layout.minimumWidth: 300
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { text: qsTr("New JSON model group"); value: NewCollectionDialog.SourceType.NewJson}
|
||||||
|
ListElement { text: qsTr("New CSV model"); value: NewCollectionDialog.SourceType.NewCsv}
|
||||||
|
ListElement { text: qsTr("Import an existing model group"); value: NewCollectionDialog.SourceType.ExistingCollection}
|
||||||
|
ListElement { text: qsTr("Add a model to an available JSON model group"); value: NewCollectionDialog.SourceType.NewCollectionToJson}
|
||||||
|
}
|
||||||
|
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "value"
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
|
||||||
|
onCurrentValueChanged: root.updateType()
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
visible: newCollectionPath.enabled
|
||||||
|
|
||||||
|
NameField {
|
||||||
|
text: qsTr("File location")
|
||||||
|
visible: newCollectionPath.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: newCollectionPath
|
||||||
|
|
||||||
|
readonly property bool isValid: !newCollectionPath.enabled || newCollectionPath.text !== ""
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: StudioTheme.Constants.font.family
|
||||||
|
font.pixelSize: StudioTheme.Values.baseIconFontSize
|
||||||
|
color: StudioTheme.Values.themePlaceholderTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
text: qsTr("Select")
|
||||||
|
|
||||||
|
onClicked: newCollectionFileDialog.open()
|
||||||
|
|
||||||
|
PlatformWidgets.FileDialog {
|
||||||
|
id: newCollectionFileDialog
|
||||||
|
|
||||||
|
title: qsTr("Select source file")
|
||||||
|
fileMode: PlatformWidgets.FileDialog.OpenFile
|
||||||
|
acceptLabel: newCollectionFileDialog.fileMode === PlatformWidgets.FileDialog.OpenFile
|
||||||
|
? qsTr("Open")
|
||||||
|
: qsTr("Add")
|
||||||
|
|
||||||
|
onAccepted: newCollectionPath.text = newCollectionFileDialog.currentFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorField {
|
||||||
|
visible: !newCollectionPath.isValid
|
||||||
|
text: qsTr("Select a file to continue")
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { visible: newCollectionPath.enabled }
|
||||||
|
|
||||||
|
NameField {
|
||||||
|
text: qsTr("JSON model group")
|
||||||
|
visible: jsonCollections.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.ComboBox {
|
||||||
|
id: jsonCollections
|
||||||
|
|
||||||
|
readonly property bool isValid: !jsonCollections.enabled || jsonCollections.currentIndex !== -1
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
implicitWidth: 300
|
||||||
|
textRole: "sourceName"
|
||||||
|
valueRole: "sourceNode"
|
||||||
|
visible: jsonCollections.enabled
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
|
||||||
|
model: CollectionJsonSourceFilterModel {
|
||||||
|
sourceModel: root.sourceModel
|
||||||
|
onRowsInserted: root.updateJsonSourceIndex()
|
||||||
|
onModelReset: root.updateJsonSourceIndex()
|
||||||
|
onRowsRemoved: root.updateJsonSourceIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnabledChanged: root.updateJsonSourceIndex()
|
||||||
|
onCurrentValueChanged: root.updateCollectionExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorField {
|
||||||
|
visible: !jsonCollections.isValid
|
||||||
|
text: qsTr("Add a JSON resource to continue")
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {visible: jsonCollections.visible }
|
||||||
|
|
||||||
|
NameField {
|
||||||
|
text: qsTr("The model name")
|
||||||
|
visible: collectionName.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: collectionName
|
id: collectionName
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
readonly property bool isValid: !collectionName.enabled
|
||||||
|
|| (collectionName.text !== "" && !collectionName.alreadyExists)
|
||||||
|
property bool alreadyExists
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: collectionName.enabled
|
||||||
actionIndicator.visible: false
|
actionIndicator.visible: false
|
||||||
translationIndicator.visible: false
|
translationIndicator.visible: false
|
||||||
validator: HelperWidgets.RegExpValidator {
|
validator: RegularExpressionValidator {
|
||||||
regExp: /^\w+$/
|
regularExpression: /^\w+$/
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: btnCreate.onClicked()
|
Keys.onEnterPressed: btnCreate.onClicked()
|
||||||
Keys.onReturnPressed: btnCreate.onClicked()
|
Keys.onReturnPressed: btnCreate.onClicked()
|
||||||
Keys.onEscapePressed: root.reject()
|
Keys.onEscapePressed: root.reject()
|
||||||
}
|
|
||||||
|
onTextChanged: root.updateCollectionExists()
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
ErrorField {
|
||||||
id: fieldErrorText
|
text: qsTr("The model name can not be empty")
|
||||||
color: StudioTheme.Values.themeTextColor
|
visible: collectionName.enabled && collectionName.text === ""
|
||||||
anchors.right: parent.right
|
|
||||||
text: qsTr("Collection name can not be empty")
|
|
||||||
visible: collectionName.text === ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // spacer
|
ErrorField {
|
||||||
width: 1
|
text: qsTr("The model name already exists %1").arg(collectionName.text)
|
||||||
height: 20
|
visible: collectionName.enabled && collectionName.alreadyExists
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Spacer { visible: collectionName.visible }
|
||||||
anchors.right: parent.right
|
|
||||||
spacing: 10
|
RowLayout {
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
id: btnCreate
|
id: btnCreate
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
text: qsTr("Create")
|
text: qsTr("Create")
|
||||||
enabled: collectionName.text !== ""
|
enabled: root.isValid
|
||||||
onClicked: root.accept()
|
onClicked: root.accept()
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
onClicked: root.reject()
|
onClicked: root.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import StudioTheme 1.0 as StudioTheme
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property var model
|
|
||||||
|
|
||||||
property alias leftPadding: topRow.leftPadding
|
|
||||||
property real rightPadding: topRow.rightPadding
|
|
||||||
|
|
||||||
color: StudioTheme.Values.themeBackgroundColorAlternate
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: topRow
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
width: parent.width
|
|
||||||
leftPadding: 20
|
|
||||||
rightPadding: 0
|
|
||||||
topPadding: 5
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: collectionNameText
|
|
||||||
|
|
||||||
leftPadding: 8
|
|
||||||
rightPadding: 8
|
|
||||||
topPadding: 3
|
|
||||||
bottomPadding: 3
|
|
||||||
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
text: root.model.collectionName
|
|
||||||
font.pixelSize: StudioTheme.Values.mediumIconFont
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
z: parent.z - 1
|
|
||||||
color: StudioTheme.Values.themeBackgroundColorNormal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { // spacer
|
|
||||||
width: 1
|
|
||||||
height: 10
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalHeaderView {
|
|
||||||
id: headerView
|
|
||||||
|
|
||||||
property real topPadding: 5
|
|
||||||
property real bottomPadding: 5
|
|
||||||
|
|
||||||
height: headerMetrics.height + topPadding + bottomPadding
|
|
||||||
|
|
||||||
syncView: tableView
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
implicitWidth: 100
|
|
||||||
implicitHeight: headerText.height
|
|
||||||
color: StudioTheme.Values.themeControlBackground
|
|
||||||
border.width: 2
|
|
||||||
border.color: StudioTheme.Values.themeControlOutline
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: headerText
|
|
||||||
|
|
||||||
topPadding: headerView.topPadding
|
|
||||||
bottomPadding: headerView.bottomPadding
|
|
||||||
leftPadding: 5
|
|
||||||
rightPadding: 5
|
|
||||||
text: display
|
|
||||||
font.pixelSize: headerMetrics.font
|
|
||||||
color: StudioTheme.Values.themeIdleGreen
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
anchors.centerIn: parent
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: headerMetrics
|
|
||||||
|
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
|
||||||
text: "Xq"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TableView {
|
|
||||||
id: tableView
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: topRow.bottom
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: parent.bottom
|
|
||||||
leftMargin: root.leftPadding
|
|
||||||
rightMargin: root.rightPadding
|
|
||||||
}
|
|
||||||
|
|
||||||
model: root.model
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
implicitWidth: 100
|
|
||||||
implicitHeight: itemText.height
|
|
||||||
color: StudioTheme.Values.themeControlBackground
|
|
||||||
border.width: 1
|
|
||||||
border.color: StudioTheme.Values.themeControlOutline
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: itemText
|
|
||||||
|
|
||||||
text: display
|
|
||||||
width: parent.width
|
|
||||||
leftPadding: 5
|
|
||||||
topPadding: 3
|
|
||||||
bottomPadding: 3
|
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,11 +2,13 @@
|
|||||||
// 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 StudioTheme 1.0 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
import StudioControls as StudioControls
|
||||||
import HelperWidgets as HelperWidgets
|
import HelperWidgets as HelperWidgets
|
||||||
|
|
||||||
PopupDialog {
|
StudioControls.PopupDialog {
|
||||||
property alias backend: form.backend
|
property alias backend: form.backend
|
||||||
|
|
||||||
titleBar: Row {
|
titleBar: Row {
|
||||||
spacing: 30 // TODO
|
spacing: 30 // TODO
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -16,6 +18,7 @@ PopupDialog {
|
|||||||
text: qsTr("Owner")
|
text: qsTr("Owner")
|
||||||
font.pixelSize: StudioTheme.Values.myFontSize
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
HelperWidgets.ToolTipArea {
|
HelperWidgets.ToolTipArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
tooltip: qsTr("The owner of the property")
|
tooltip: qsTr("The owner of the property")
|
||||||
@@ -27,14 +30,10 @@ PopupDialog {
|
|||||||
font.pixelSize: StudioTheme.Values.myFontSize
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: form.backend.targetNode
|
text: form.backend.targetNode
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BindingsDialogForm {
|
BindingsDialogForm {
|
||||||
id: form
|
id: form
|
||||||
y: 32
|
|
||||||
height: 160
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
// 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 QtQuick.Controls
|
||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
@@ -10,12 +10,11 @@ Column {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property real horizontalSpacing: 10
|
readonly property real horizontalSpacing: 10
|
||||||
readonly property real verticalSpacing: 16
|
readonly property real verticalSpacing: 12
|
||||||
readonly property real columnWidth: (root.width - root.horizontalSpacing) / 2
|
readonly property real columnWidth: (root.width - root.horizontalSpacing) / 2
|
||||||
|
|
||||||
property var backend
|
property var backend
|
||||||
|
|
||||||
y: StudioTheme.Values.popupMargin
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: root.verticalSpacing
|
spacing: root.verticalSpacing
|
||||||
|
|
||||||
@@ -53,8 +52,8 @@ Column {
|
|||||||
PopupLabel {
|
PopupLabel {
|
||||||
width: root.columnWidth
|
width: root.columnWidth
|
||||||
text: backend.targetNode
|
text: backend.targetNode
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ ListView {
|
|||||||
|
|
||||||
property bool adsFocus: false
|
property bool adsFocus: false
|
||||||
|
|
||||||
// Temporarily remove due to dockwidget focus issue
|
|
||||||
//onAdsFocusChanged: {
|
|
||||||
// if (!root.adsFocus)
|
|
||||||
// dialog.close()
|
|
||||||
//}
|
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
interactive: true
|
interactive: true
|
||||||
highlightMoveDuration: 0
|
highlightMoveDuration: 0
|
||||||
@@ -43,9 +37,7 @@ ListView {
|
|||||||
&& verticalScrollBar.isNeeded
|
&& verticalScrollBar.isNeeded
|
||||||
}
|
}
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: dialog.close()
|
||||||
dialog.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
property int modelCurrentIndex: root.model.currentIndex ?? 0
|
property int modelCurrentIndex: root.model.currentIndex ?? 0
|
||||||
|
|
||||||
@@ -72,7 +64,7 @@ ListView {
|
|||||||
function addBinding() {
|
function addBinding() {
|
||||||
ConnectionsEditorEditorBackend.bindingModel.add()
|
ConnectionsEditorEditorBackend.bindingModel.add()
|
||||||
if (root.currentItem)
|
if (root.currentItem)
|
||||||
dialog.popup(root.currentItem.delegateMouseArea)
|
dialog.show(root.currentItem.delegateMouseArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetIndex() {
|
function resetIndex() {
|
||||||
@@ -104,9 +96,11 @@ ListView {
|
|||||||
|
|
||||||
property alias delegateMouseArea: mouseArea
|
property alias delegateMouseArea: mouseArea
|
||||||
|
|
||||||
|
property bool hovered: mouseArea.containsMouse || toolTipArea.containsMouse
|
||||||
|
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
height: root.style.squareControlSize.height
|
height: root.style.squareControlSize.height
|
||||||
color: mouseArea.containsMouse ?
|
color: itemDelegate.hovered ?
|
||||||
itemDelegate.ListView.isCurrentItem ? root.style.interactionHover
|
itemDelegate.ListView.isCurrentItem ? root.style.interactionHover
|
||||||
: root.style.background.hover
|
: root.style.background.hover
|
||||||
: "transparent"
|
: "transparent"
|
||||||
@@ -120,7 +114,7 @@ ListView {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
root.model.currentIndex = itemDelegate.index
|
root.model.currentIndex = itemDelegate.index
|
||||||
root.currentIndex = itemDelegate.index
|
root.currentIndex = itemDelegate.index
|
||||||
dialog.popup(mouseArea)
|
dialog.show(mouseArea)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
// 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 StudioControls 1.0 as StudioControls
|
import StudioControls as StudioControls
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
import HelperWidgets 2.0 as HelperWidgets
|
import HelperWidgets as HelperWidgets
|
||||||
|
|
||||||
PopupDialog {
|
StudioControls.PopupDialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property alias backend: form.backend
|
property alias backend: form.backend
|
||||||
|
|
||||||
titleBar: Row {
|
titleBar: Row {
|
||||||
@@ -19,6 +20,7 @@ PopupDialog {
|
|||||||
text: qsTr("Target")
|
text: qsTr("Target")
|
||||||
font.pixelSize: StudioTheme.Values.myFontSize
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
HelperWidgets.ToolTipArea {
|
HelperWidgets.ToolTipArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
tooltip: qsTr("Sets the Component that is connected to a <b>Signal</b>.")
|
tooltip: qsTr("Sets the Component that is connected to a <b>Signal</b>.")
|
||||||
@@ -46,6 +48,9 @@ PopupDialog {
|
|||||||
function onPopupShouldClose() {
|
function onPopupShouldClose() {
|
||||||
root.close()
|
root.close()
|
||||||
}
|
}
|
||||||
|
function onPopupShouldOpen() {
|
||||||
|
root.showGlobal()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ Column {
|
|||||||
|
|
||||||
property var backend
|
property var backend
|
||||||
|
|
||||||
y: StudioTheme.Values.popupMargin
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: root.verticalSpacing
|
spacing: root.verticalSpacing
|
||||||
|
|
||||||
@@ -45,6 +44,7 @@ Column {
|
|||||||
|
|
||||||
StudioControls.TopLevelComboBox {
|
StudioControls.TopLevelComboBox {
|
||||||
id: signal
|
id: signal
|
||||||
|
|
||||||
style: StudioTheme.Values.connectionPopupControlStyle
|
style: StudioTheme.Values.connectionPopupControlStyle
|
||||||
width: root.columnWidth
|
width: root.columnWidth
|
||||||
|
|
||||||
@@ -216,12 +216,38 @@ Column {
|
|||||||
&& backend.hasCondition && backend.hasElse
|
&& backend.hasCondition && backend.hasElse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// code preview toolbar
|
||||||
|
Column {
|
||||||
|
id: miniToolbarEditor
|
||||||
|
width: parent.width
|
||||||
|
spacing: -2
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: miniToolbar
|
||||||
|
width: parent.width
|
||||||
|
height: editorButton.height + 2
|
||||||
|
radius: 4
|
||||||
|
z: -1
|
||||||
|
color: StudioTheme.Values.themeConnectionEditorMicroToolbar
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 2
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
id: editorButton
|
id: editorButton
|
||||||
|
style: StudioTheme.Values.microToolbarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.codeEditor_medium
|
buttonIcon: StudioTheme.Constants.codeEditor_medium
|
||||||
tooltip: qsTr("Write the conditions for the components and the signals manually.")
|
tooltip: qsTr("Write the conditions for the components and the signals manually.")
|
||||||
onClicked: expressionDialogLoader.show()
|
onClicked: expressionDialogLoader.show()
|
||||||
}
|
}
|
||||||
|
HelperWidgets.AbstractButton {
|
||||||
|
id: jumpToCodeButton
|
||||||
|
style: StudioTheme.Values.microToolbarButtonStyle
|
||||||
|
buttonIcon: StudioTheme.Constants.jumpToCode_medium
|
||||||
|
tooltip: qsTr("Jump to the code.")
|
||||||
|
onClicked: backend.jumpToCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -244,6 +270,7 @@ Column {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: expressionDialogLoader
|
id: expressionDialogLoader
|
||||||
parent: editor
|
parent: editor
|
||||||
@@ -281,6 +308,8 @@ Column {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // loader
|
||||||
}
|
} // rect
|
||||||
}
|
} //col 2
|
||||||
|
}//col1
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ ListView {
|
|||||||
|
|
||||||
property bool adsFocus: false
|
property bool adsFocus: false
|
||||||
|
|
||||||
// Temporarily remove due to dockwidget focus issue
|
|
||||||
//onAdsFocusChanged: {
|
|
||||||
// if (!root.adsFocus)
|
|
||||||
// dialog.close()
|
|
||||||
//}
|
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
interactive: true
|
interactive: true
|
||||||
highlightMoveDuration: 0
|
highlightMoveDuration: 0
|
||||||
@@ -43,9 +37,7 @@ ListView {
|
|||||||
&& verticalScrollBar.isNeeded
|
&& verticalScrollBar.isNeeded
|
||||||
}
|
}
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: dialog.close()
|
||||||
dialog.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
property int modelCurrentIndex: root.model.currentIndex ?? 0
|
property int modelCurrentIndex: root.model.currentIndex ?? 0
|
||||||
|
|
||||||
@@ -73,7 +65,7 @@ ListView {
|
|||||||
function addConnection() {
|
function addConnection() {
|
||||||
ConnectionsEditorEditorBackend.connectionModel.add()
|
ConnectionsEditorEditorBackend.connectionModel.add()
|
||||||
if (root.currentItem)
|
if (root.currentItem)
|
||||||
dialog.popup(root.currentItem.delegateMouseArea)
|
dialog.show(root.currentItem.delegateMouseArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetIndex() {
|
function resetIndex() {
|
||||||
@@ -124,7 +116,7 @@ ListView {
|
|||||||
root.model.currentIndex = itemDelegate.index
|
root.model.currentIndex = itemDelegate.index
|
||||||
root.currentIndex = itemDelegate.index
|
root.currentIndex = itemDelegate.index
|
||||||
dialog.backend.currentRow = itemDelegate.index
|
dialog.backend.currentRow = itemDelegate.index
|
||||||
dialog.popup(mouseArea)
|
dialog.show(mouseArea)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Rectangle {
|
|||||||
Column {
|
Column {
|
||||||
id: column
|
id: column
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 8 // TODO
|
spacing: 5 // TODO
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: toolbar
|
id: toolbar
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import HelperWidgets 2.0 as HelperWidgets
|
|
||||||
import StudioTheme 1.0 as StudioTheme
|
|
||||||
import ConnectionsEditorEditorBackend
|
|
||||||
|
|
||||||
Window {
|
|
||||||
id: window
|
|
||||||
|
|
||||||
property alias titleBar: titleBarContent.children
|
|
||||||
default property alias content: mainContent.children
|
|
||||||
property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
|
|
||||||
|
|
||||||
width: 300
|
|
||||||
height: column.implicitHeight
|
|
||||||
visible: true
|
|
||||||
flags: Qt.FramelessWindowHint | Qt.Dialog
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
color: StudioTheme.Values.themePopoutBackground
|
|
||||||
border.color: "#636363"//StudioTheme.Values.themeTextColor
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureVerticalPosition() {
|
|
||||||
if ((window.y + window.height) > (Screen.height - window.style.dialogScreenMargin)) {
|
|
||||||
window.y = (Screen.height - window.height - window.style.dialogScreenMargin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onHeightChanged: window.ensureVerticalPosition()
|
|
||||||
|
|
||||||
function popup(item) {
|
|
||||||
var padding = 12
|
|
||||||
var p = item.mapToGlobal(0, 0)
|
|
||||||
window.x = p.x - window.width - padding
|
|
||||||
if (window.x < 0)
|
|
||||||
window.x = p.x + item.width + padding
|
|
||||||
window.y = p.y
|
|
||||||
|
|
||||||
window.ensureVerticalPosition()
|
|
||||||
|
|
||||||
window.show()
|
|
||||||
window.raise()
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: column
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: titleBarItem
|
|
||||||
width: parent.width
|
|
||||||
height: StudioTheme.Values.titleBarHeight
|
|
||||||
|
|
||||||
DragHandler {
|
|
||||||
id: dragHandler
|
|
||||||
|
|
||||||
target: null
|
|
||||||
grabPermissions: PointerHandler.CanTakeOverFromAnything
|
|
||||||
onActiveChanged: {
|
|
||||||
if (dragHandler.active)
|
|
||||||
window.startSystemMove() // QTBUG-102488
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: row
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: StudioTheme.Values.popupMargin
|
|
||||||
anchors.rightMargin: StudioTheme.Values.popupMargin
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: titleBarContent
|
|
||||||
width: row.width - closeIndicator.width //- row.anchors.leftMargin
|
|
||||||
height: row.height
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.IconIndicator {
|
|
||||||
id: closeIndicator
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
icon: StudioTheme.Constants.colorPopupClose
|
|
||||||
pixelSize: StudioTheme.Values.myIconFontSize// * 1.4
|
|
||||||
onClicked: window.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width - 8
|
|
||||||
height: 1
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: "#636363"
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: mainContent
|
|
||||||
width: parent.width - 2 * StudioTheme.Values.popupMargin
|
|
||||||
height: mainContent.childrenRect.height + 2 * StudioTheme.Values.popupMargin
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
// 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 StudioTheme 1.0 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
import HelperWidgets as HelperWidgets
|
import HelperWidgets as HelperWidgets
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
|
||||||
PopupDialog {
|
StudioControls.PopupDialog {
|
||||||
property alias backend: form.backend
|
property alias backend: form.backend
|
||||||
|
|
||||||
titleBar: Row {
|
titleBar: Row {
|
||||||
@@ -17,6 +18,7 @@ PopupDialog {
|
|||||||
text: qsTr("Owner")
|
text: qsTr("Owner")
|
||||||
font.pixelSize: StudioTheme.Values.myFontSize
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
HelperWidgets.ToolTipArea {
|
HelperWidgets.ToolTipArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
tooltip: qsTr("The owner of the property")
|
tooltip: qsTr("The owner of the property")
|
||||||
@@ -29,12 +31,9 @@ PopupDialog {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: form.backend.targetNode
|
text: form.backend.targetNode
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertiesDialogForm {
|
PropertiesDialogForm {
|
||||||
id: form
|
id: form
|
||||||
y: 32
|
|
||||||
height: 180
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ Column {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property real horizontalSpacing: 10
|
readonly property real horizontalSpacing: 10
|
||||||
readonly property real verticalSpacing: 16
|
readonly property real verticalSpacing: 12
|
||||||
readonly property real columnWidth: (root.width - root.horizontalSpacing) / 2
|
readonly property real columnWidth: (root.width - root.horizontalSpacing) / 2
|
||||||
|
|
||||||
property var backend
|
property var backend
|
||||||
|
|
||||||
y: StudioTheme.Values.popupMargin
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: root.verticalSpacing
|
spacing: root.verticalSpacing
|
||||||
|
|
||||||
@@ -23,11 +22,11 @@ Column {
|
|||||||
text: qsTr("Type")
|
text: qsTr("Type")
|
||||||
tooltip: qsTr("Sets the category of the <b>Local Custom Property</b>.")
|
tooltip: qsTr("Sets the category of the <b>Local Custom Property</b>.")
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.TopLevelComboBox {
|
StudioControls.TopLevelComboBox {
|
||||||
id: type
|
id: type
|
||||||
style: StudioTheme.Values.connectionPopupControlStyle
|
style: StudioTheme.Values.connectionPopupControlStyle
|
||||||
width: root.columnWidth
|
width: root.columnWidth
|
||||||
//width: root.width
|
|
||||||
|
|
||||||
model: backend.type.model ?? []
|
model: backend.type.model ?? []
|
||||||
onActivated: backend.type.activateIndex(type.currentIndex)
|
onActivated: backend.type.activateIndex(type.currentIndex)
|
||||||
@@ -53,6 +52,7 @@ Column {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: root.horizontalSpacing
|
spacing: root.horizontalSpacing
|
||||||
|
|
||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: name
|
id: name
|
||||||
|
|
||||||
@@ -61,10 +61,9 @@ Column {
|
|||||||
translationIndicatorVisible: false
|
translationIndicatorVisible: false
|
||||||
|
|
||||||
text: backend.name.text ?? ""
|
text: backend.name.text ?? ""
|
||||||
onEditingFinished: {
|
onEditingFinished: backend.name.activateText(name.text)
|
||||||
backend.name.activateText(name.text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.TextField {
|
StudioControls.TextField {
|
||||||
id: value
|
id: value
|
||||||
|
|
||||||
@@ -74,9 +73,7 @@ Column {
|
|||||||
|
|
||||||
|
|
||||||
text: backend.value.text ?? ""
|
text: backend.value.text ?? ""
|
||||||
onEditingFinished: {
|
onEditingFinished: backend.value.activateText(value.text)
|
||||||
backend.value.activateText(value.text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ ListView {
|
|||||||
|
|
||||||
property bool adsFocus: false
|
property bool adsFocus: false
|
||||||
|
|
||||||
// Temporarily remove due to dockwidget focus issue
|
|
||||||
//onAdsFocusChanged: {
|
|
||||||
// if (!root.adsFocus)
|
|
||||||
// dialog.close()
|
|
||||||
//}
|
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
interactive: true
|
interactive: true
|
||||||
highlightMoveDuration: 0
|
highlightMoveDuration: 0
|
||||||
@@ -43,9 +37,7 @@ ListView {
|
|||||||
&& verticalScrollBar.isNeeded
|
&& verticalScrollBar.isNeeded
|
||||||
}
|
}
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: dialog.close()
|
||||||
dialog.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
property int modelCurrentIndex: root.model.currentIndex ?? 0
|
property int modelCurrentIndex: root.model.currentIndex ?? 0
|
||||||
|
|
||||||
@@ -72,7 +64,7 @@ ListView {
|
|||||||
function addProperty() {
|
function addProperty() {
|
||||||
ConnectionsEditorEditorBackend.dynamicPropertiesModel.add()
|
ConnectionsEditorEditorBackend.dynamicPropertiesModel.add()
|
||||||
if (root.currentItem)
|
if (root.currentItem)
|
||||||
dialog.popup(root.currentItem.delegateMouseArea)
|
dialog.show(root.currentItem.delegateMouseArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetIndex() {
|
function resetIndex() {
|
||||||
@@ -104,9 +96,11 @@ ListView {
|
|||||||
|
|
||||||
property alias delegateMouseArea: mouseArea
|
property alias delegateMouseArea: mouseArea
|
||||||
|
|
||||||
|
property bool hovered: mouseArea.containsMouse || toolTipArea.containsMouse
|
||||||
|
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
height: root.style.squareControlSize.height
|
height: root.style.squareControlSize.height
|
||||||
color: mouseArea.containsMouse ?
|
color: itemDelegate.hovered ?
|
||||||
itemDelegate.ListView.isCurrentItem ? root.style.interactionHover
|
itemDelegate.ListView.isCurrentItem ? root.style.interactionHover
|
||||||
: root.style.background.hover
|
: root.style.background.hover
|
||||||
: "transparent"
|
: "transparent"
|
||||||
@@ -124,7 +118,7 @@ ListView {
|
|||||||
function onClicked() {
|
function onClicked() {
|
||||||
root.model.currentIndex = itemDelegate.index
|
root.model.currentIndex = itemDelegate.index
|
||||||
root.currentIndex = itemDelegate.index
|
root.currentIndex = itemDelegate.index
|
||||||
dialog.popup(mouseArea)
|
dialog.show(mouseArea)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ Item {
|
|||||||
objectName: "__mainSrollView"
|
objectName: "__mainSrollView"
|
||||||
|
|
||||||
// Called also from C++ to close context menu on focus out
|
// Called also from C++ to close context menu on focus out
|
||||||
function closeContextMenu()
|
function closeContextMenu() {
|
||||||
{
|
|
||||||
materialsView.closeContextMenu()
|
materialsView.closeContextMenu()
|
||||||
texturesView.closeContextMenu()
|
texturesView.closeContextMenu()
|
||||||
environmentsView.closeContextMenu()
|
environmentsView.closeContextMenu()
|
||||||
@@ -29,9 +28,43 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called from C++
|
// Called from C++
|
||||||
function clearSearchFilter()
|
function clearSearchFilter() {
|
||||||
{
|
searchBox.clear()
|
||||||
searchBox.clear();
|
}
|
||||||
|
|
||||||
|
property int numColumns: 4
|
||||||
|
property real thumbnailSize: 100
|
||||||
|
|
||||||
|
readonly property int minThumbSize: 100
|
||||||
|
readonly property int maxThumbSize: 150
|
||||||
|
|
||||||
|
function responsiveResize(width: int, height: int) {
|
||||||
|
width -= 2 * StudioTheme.Values.sectionPadding
|
||||||
|
|
||||||
|
let numColumns = Math.floor(width / root.minThumbSize)
|
||||||
|
let remainder = width % root.minThumbSize
|
||||||
|
let space = (numColumns - 1) * StudioTheme.Values.sectionGridSpacing
|
||||||
|
|
||||||
|
if (remainder < space)
|
||||||
|
numColumns -= 1
|
||||||
|
|
||||||
|
if (numColumns < 1)
|
||||||
|
return
|
||||||
|
|
||||||
|
let maxItems = Math.max(materialsView.count,
|
||||||
|
texturesView.count,
|
||||||
|
environmentsView.count,
|
||||||
|
effectsView.count)
|
||||||
|
|
||||||
|
if (numColumns > maxItems)
|
||||||
|
numColumns = maxItems
|
||||||
|
|
||||||
|
let rest = width - (numColumns * root.minThumbSize)
|
||||||
|
- ((numColumns - 1) * StudioTheme.Values.sectionGridSpacing)
|
||||||
|
|
||||||
|
root.thumbnailSize = Math.min(root.minThumbSize + (rest / numColumns),
|
||||||
|
root.maxThumbSize)
|
||||||
|
root.numColumns = numColumns
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -46,11 +79,11 @@ Item {
|
|||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.topMargin: 6
|
anchors.topMargin: StudioTheme.Values.toolbarVerticalMargin
|
||||||
anchors.bottomMargin: 6
|
anchors.bottomMargin: StudioTheme.Values.toolbarVerticalMargin
|
||||||
anchors.leftMargin: 10
|
anchors.leftMargin: StudioTheme.Values.toolbarHorizontalMargin
|
||||||
anchors.rightMargin: 10
|
anchors.rightMargin: StudioTheme.Values.toolbarHorizontalMargin
|
||||||
spacing: 12
|
spacing: StudioTheme.Values.toolbarColumnSpacing
|
||||||
|
|
||||||
StudioControls.SearchBox {
|
StudioControls.SearchBox {
|
||||||
id: searchBox
|
id: searchBox
|
||||||
@@ -94,16 +127,24 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StackLayout {
|
StackLayout {
|
||||||
|
id: stackLayout
|
||||||
width: root.width
|
width: root.width
|
||||||
height: root.height - y
|
height: root.height - y
|
||||||
currentIndex: tabBar.currIndex
|
currentIndex: tabBar.currIndex
|
||||||
|
|
||||||
|
onWidthChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
||||||
|
|
||||||
ContentLibraryMaterialsView {
|
ContentLibraryMaterialsView {
|
||||||
id: materialsView
|
id: materialsView
|
||||||
|
|
||||||
adsFocus: root.adsFocus
|
adsFocus: root.adsFocus
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
|
cellWidth: root.thumbnailSize
|
||||||
|
cellHeight: root.thumbnailSize + 20
|
||||||
|
numColumns: root.numColumns
|
||||||
|
hideHorizontalScrollBar: true
|
||||||
|
|
||||||
searchBox: searchBox
|
searchBox: searchBox
|
||||||
|
|
||||||
onUnimport: (bundleMat) => {
|
onUnimport: (bundleMat) => {
|
||||||
@@ -111,6 +152,8 @@ Item {
|
|||||||
confirmUnimportDialog.targetBundleType = "material"
|
confirmUnimportDialog.targetBundleType = "material"
|
||||||
confirmUnimportDialog.open()
|
confirmUnimportDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentLibraryTexturesView {
|
ContentLibraryTexturesView {
|
||||||
@@ -118,10 +161,18 @@ Item {
|
|||||||
|
|
||||||
adsFocus: root.adsFocus
|
adsFocus: root.adsFocus
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
|
cellWidth: root.thumbnailSize
|
||||||
|
cellHeight: root.thumbnailSize
|
||||||
|
numColumns: root.numColumns
|
||||||
|
hideHorizontalScrollBar: true
|
||||||
|
|
||||||
model: ContentLibraryBackend.texturesModel
|
model: ContentLibraryBackend.texturesModel
|
||||||
sectionCategory: "ContentLib_Tex"
|
sectionCategory: "ContentLib_Tex"
|
||||||
|
|
||||||
searchBox: searchBox
|
searchBox: searchBox
|
||||||
|
|
||||||
|
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentLibraryTexturesView {
|
ContentLibraryTexturesView {
|
||||||
@@ -129,10 +180,18 @@ Item {
|
|||||||
|
|
||||||
adsFocus: root.adsFocus
|
adsFocus: root.adsFocus
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
|
cellWidth: root.thumbnailSize
|
||||||
|
cellHeight: root.thumbnailSize
|
||||||
|
numColumns: root.numColumns
|
||||||
|
hideHorizontalScrollBar: true
|
||||||
|
|
||||||
model: ContentLibraryBackend.environmentsModel
|
model: ContentLibraryBackend.environmentsModel
|
||||||
sectionCategory: "ContentLib_Env"
|
sectionCategory: "ContentLib_Env"
|
||||||
|
|
||||||
searchBox: searchBox
|
searchBox: searchBox
|
||||||
|
|
||||||
|
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentLibraryEffectsView {
|
ContentLibraryEffectsView {
|
||||||
@@ -141,6 +200,11 @@ Item {
|
|||||||
adsFocus: root.adsFocus
|
adsFocus: root.adsFocus
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
|
cellWidth: root.thumbnailSize
|
||||||
|
cellHeight: root.thumbnailSize + 20
|
||||||
|
numColumns: root.numColumns
|
||||||
|
hideHorizontalScrollBar: true
|
||||||
|
|
||||||
searchBox: searchBox
|
searchBox: searchBox
|
||||||
|
|
||||||
onUnimport: (bundleItem) => {
|
onUnimport: (bundleItem) => {
|
||||||
@@ -148,6 +212,8 @@ Item {
|
|||||||
confirmUnimportDialog.targetBundleType = "effect"
|
confirmUnimportDialog.targetBundleType = "effect"
|
||||||
confirmUnimportDialog.open()
|
confirmUnimportDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,12 +36,10 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 1
|
spacing: 1
|
||||||
|
|
||||||
Item { width: 1; height: 5 } // spacer
|
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: img
|
id: img
|
||||||
|
|
||||||
width: root.width - 10
|
width: root.width
|
||||||
height: img.width
|
height: img.width
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
source: modelData.bundleItemIcon
|
source: modelData.bundleItemIcon
|
||||||
@@ -74,16 +72,13 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: modelData.bundleItemName
|
|
||||||
|
|
||||||
width: img.width
|
width: img.width
|
||||||
clip: true
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
horizontalAlignment: TextInput.AlignHCenter
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
|
||||||
|
text: modelData.bundleItemName
|
||||||
|
elide: Text.ElideRight
|
||||||
font.pixelSize: StudioTheme.Values.myFontSize
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
}
|
}
|
||||||
} // Column
|
} // Column
|
||||||
|
|||||||
@@ -14,20 +14,28 @@ HelperWidgets.ScrollView {
|
|||||||
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
|
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
|
||||||
&& !HelperWidgets.Controller.contextMenuOpened
|
&& !HelperWidgets.Controller.contextMenuOpened
|
||||||
|
|
||||||
readonly property int cellWidth: 100
|
property real cellWidth: 100
|
||||||
readonly property int cellHeight: 120
|
property real cellHeight: 120
|
||||||
|
property int numColumns: 4
|
||||||
|
|
||||||
|
property int count: 0
|
||||||
|
function assignMaxCount() {
|
||||||
|
let c = 0
|
||||||
|
for (let i = 0; i < categoryRepeater.count; ++i)
|
||||||
|
c = Math.max(c, categoryRepeater.itemAt(i)?.count ?? 0)
|
||||||
|
|
||||||
|
root.count = c
|
||||||
|
}
|
||||||
|
|
||||||
required property var searchBox
|
required property var searchBox
|
||||||
|
|
||||||
signal unimport(var bundleItem);
|
signal unimport(var bundleItem);
|
||||||
|
|
||||||
function closeContextMenu()
|
function closeContextMenu() {
|
||||||
{
|
|
||||||
ctxMenu.close()
|
ctxMenu.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandVisibleSections()
|
function expandVisibleSections() {
|
||||||
{
|
|
||||||
for (let i = 0; i < categoryRepeater.count; ++i) {
|
for (let i = 0; i < categoryRepeater.count; ++i) {
|
||||||
let cat = categoryRepeater.itemAt(i)
|
let cat = categoryRepeater.itemAt(i)
|
||||||
if (cat.visible && !cat.expanded)
|
if (cat.visible && !cat.expanded)
|
||||||
@@ -48,10 +56,15 @@ HelperWidgets.ScrollView {
|
|||||||
model: ContentLibraryBackend.effectsModel
|
model: ContentLibraryBackend.effectsModel
|
||||||
|
|
||||||
delegate: HelperWidgets.Section {
|
delegate: HelperWidgets.Section {
|
||||||
|
id: section
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
|
leftPadding: StudioTheme.Values.sectionPadding
|
||||||
|
rightPadding: StudioTheme.Values.sectionPadding
|
||||||
|
topPadding: StudioTheme.Values.sectionPadding
|
||||||
|
bottomPadding: StudioTheme.Values.sectionPadding
|
||||||
|
|
||||||
caption: bundleCategoryName
|
caption: bundleCategoryName
|
||||||
addTopPadding: false
|
|
||||||
sectionBackgroundColor: "transparent"
|
|
||||||
visible: bundleCategoryVisible && !ContentLibraryBackend.effectsModel.isEmpty
|
visible: bundleCategoryVisible && !ContentLibraryBackend.effectsModel.isEmpty
|
||||||
expanded: bundleCategoryExpanded
|
expanded: bundleCategoryExpanded
|
||||||
expandOnClick: false
|
expandOnClick: false
|
||||||
@@ -65,14 +78,17 @@ HelperWidgets.ScrollView {
|
|||||||
bundleCategoryExpanded = true
|
bundleCategoryExpanded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property alias count: repeater.count
|
||||||
|
|
||||||
|
onCountChanged: root.assignMaxCount()
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
width: root.width
|
width: section.width - section.leftPadding - section.rightPadding
|
||||||
leftPadding: 5
|
spacing: StudioTheme.Values.sectionGridSpacing
|
||||||
rightPadding: 5
|
columns: root.numColumns
|
||||||
bottomPadding: 5
|
|
||||||
columns: root.width / root.cellWidth
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
id: repeater
|
||||||
model: bundleCategoryItems
|
model: bundleCategoryItems
|
||||||
|
|
||||||
delegate: ContentLibraryEffect {
|
delegate: ContentLibraryEffect {
|
||||||
@@ -81,6 +97,8 @@ HelperWidgets.ScrollView {
|
|||||||
|
|
||||||
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: root.assignMaxCount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
// 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 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
|
||||||
import QtQuickDesignerTheme 1.0
|
|
||||||
import HelperWidgets 2.0
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuickDesignerTheme
|
||||||
|
import HelperWidgets
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
import StudioTheme 1.0 as StudioTheme
|
|
||||||
import ContentLibraryBackend
|
import ContentLibraryBackend
|
||||||
|
import WebFetcher
|
||||||
import WebFetcher 1.0
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -45,8 +44,6 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 1
|
spacing: 1
|
||||||
|
|
||||||
Item { width: 1; height: 5 } // spacer
|
|
||||||
|
|
||||||
DownloadPane {
|
DownloadPane {
|
||||||
id: downloadPane
|
id: downloadPane
|
||||||
width: root.width - 10
|
width: root.width - 10
|
||||||
@@ -59,7 +56,7 @@ Item {
|
|||||||
Image {
|
Image {
|
||||||
id: img
|
id: img
|
||||||
|
|
||||||
width: root.width - 10
|
width: root.width
|
||||||
height: img.width
|
height: img.width
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
source: modelData.bundleMaterialIcon
|
source: modelData.bundleMaterialIcon
|
||||||
@@ -108,7 +105,7 @@ Item {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
ContentLibraryBackend.materialsModel.addToProject(modelData)
|
ContentLibraryBackend.materialsModel.addToProject(modelData)
|
||||||
}
|
}
|
||||||
} // IconButton
|
}
|
||||||
|
|
||||||
IconButton {
|
IconButton {
|
||||||
id: downloadIcon
|
id: downloadIcon
|
||||||
@@ -154,29 +151,22 @@ Item {
|
|||||||
root.downloadState = ""
|
root.downloadState = ""
|
||||||
downloader.start()
|
downloader.start()
|
||||||
}
|
}
|
||||||
} // IconButton
|
}
|
||||||
} // Image
|
}
|
||||||
|
|
||||||
TextInput {
|
Text {
|
||||||
id: matName
|
id: matName
|
||||||
|
|
||||||
text: modelData.bundleMaterialName
|
|
||||||
|
|
||||||
width: img.width
|
width: img.width
|
||||||
clip: true
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
horizontalAlignment: TextInput.AlignHCenter
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
|
||||||
|
text: modelData.bundleMaterialName
|
||||||
|
elide: Text.ElideRight
|
||||||
font.pixelSize: StudioTheme.Values.myFontSize
|
font.pixelSize: StudioTheme.Values.myFontSize
|
||||||
|
|
||||||
readOnly: true
|
|
||||||
selectByMouse: !matName.readOnly
|
|
||||||
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
selectionColor: StudioTheme.Values.themeTextSelectionColor
|
|
||||||
selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
|
|
||||||
}
|
}
|
||||||
} // Column
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: delayedFinish
|
id: delayedFinish
|
||||||
@@ -223,6 +213,6 @@ Item {
|
|||||||
probeUrl: false
|
probeUrl: false
|
||||||
downloadEnabled: true
|
downloadEnabled: true
|
||||||
targetFilePath: downloader.nextTargetPath
|
targetFilePath: downloader.nextTargetPath
|
||||||
} // FileDownloader
|
}
|
||||||
} // MultiFileDownloader
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,18 @@ HelperWidgets.ScrollView {
|
|||||||
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
|
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
|
||||||
&& !HelperWidgets.Controller.contextMenuOpened
|
&& !HelperWidgets.Controller.contextMenuOpened
|
||||||
|
|
||||||
readonly property int cellWidth: 100
|
property real cellWidth: 100
|
||||||
readonly property int cellHeight: 120
|
property real cellHeight: 120
|
||||||
|
property int numColumns: 4
|
||||||
|
|
||||||
|
property int count: 0
|
||||||
|
function assignMaxCount() {
|
||||||
|
let c = 0
|
||||||
|
for (let i = 0; i < categoryRepeater.count; ++i)
|
||||||
|
c = Math.max(c, categoryRepeater.itemAt(i)?.count ?? 0)
|
||||||
|
|
||||||
|
root.count = c
|
||||||
|
}
|
||||||
|
|
||||||
property var currMaterialItem: null
|
property var currMaterialItem: null
|
||||||
property var rootItem: null
|
property var rootItem: null
|
||||||
@@ -23,15 +33,13 @@ HelperWidgets.ScrollView {
|
|||||||
|
|
||||||
required property var searchBox
|
required property var searchBox
|
||||||
|
|
||||||
signal unimport(var bundleMat);
|
signal unimport(var bundleMat)
|
||||||
|
|
||||||
function closeContextMenu()
|
function closeContextMenu() {
|
||||||
{
|
|
||||||
ctxMenu.close()
|
ctxMenu.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandVisibleSections()
|
function expandVisibleSections() {
|
||||||
{
|
|
||||||
for (let i = 0; i < categoryRepeater.count; ++i) {
|
for (let i = 0; i < categoryRepeater.count; ++i) {
|
||||||
let cat = categoryRepeater.itemAt(i)
|
let cat = categoryRepeater.itemAt(i)
|
||||||
if (cat.visible && !cat.expanded)
|
if (cat.visible && !cat.expanded)
|
||||||
@@ -56,10 +64,15 @@ HelperWidgets.ScrollView {
|
|||||||
model: materialsModel
|
model: materialsModel
|
||||||
|
|
||||||
delegate: HelperWidgets.Section {
|
delegate: HelperWidgets.Section {
|
||||||
|
id: section
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
|
leftPadding: StudioTheme.Values.sectionPadding
|
||||||
|
rightPadding: StudioTheme.Values.sectionPadding
|
||||||
|
topPadding: StudioTheme.Values.sectionPadding
|
||||||
|
bottomPadding: StudioTheme.Values.sectionPadding
|
||||||
|
|
||||||
caption: bundleCategoryName
|
caption: bundleCategoryName
|
||||||
addTopPadding: false
|
|
||||||
sectionBackgroundColor: "transparent"
|
|
||||||
visible: bundleCategoryVisible && !materialsModel.isEmpty
|
visible: bundleCategoryVisible && !materialsModel.isEmpty
|
||||||
expanded: bundleCategoryExpanded
|
expanded: bundleCategoryExpanded
|
||||||
expandOnClick: false
|
expandOnClick: false
|
||||||
@@ -73,14 +86,17 @@ HelperWidgets.ScrollView {
|
|||||||
bundleCategoryExpanded = true
|
bundleCategoryExpanded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property alias count: repeater.count
|
||||||
|
|
||||||
|
onCountChanged: root.assignMaxCount()
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
width: root.width
|
width: section.width - section.leftPadding - section.rightPadding
|
||||||
leftPadding: 5
|
spacing: StudioTheme.Values.sectionGridSpacing
|
||||||
rightPadding: 5
|
columns: root.numColumns
|
||||||
bottomPadding: 5
|
|
||||||
columns: root.width / root.cellWidth
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
id: repeater
|
||||||
model: bundleCategoryMaterials
|
model: bundleCategoryMaterials
|
||||||
|
|
||||||
delegate: ContentLibraryMaterial {
|
delegate: ContentLibraryMaterial {
|
||||||
@@ -89,6 +105,8 @@ HelperWidgets.ScrollView {
|
|||||||
|
|
||||||
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: root.assignMaxCount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
// 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 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
|
||||||
import QtQuickDesignerTheme 1.0
|
|
||||||
import HelperWidgets 2.0
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuickDesignerTheme
|
||||||
|
import HelperWidgets
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
import StudioTheme 1.0 as StudioTheme
|
|
||||||
|
|
||||||
import WebFetcher 1.0
|
|
||||||
import ContentLibraryBackend
|
import ContentLibraryBackend
|
||||||
|
import WebFetcher
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -30,8 +29,7 @@ Item {
|
|||||||
|
|
||||||
signal showContextMenu()
|
signal showContextMenu()
|
||||||
|
|
||||||
function statusText()
|
function statusText() {
|
||||||
{
|
|
||||||
if (root.downloadState === "downloaded")
|
if (root.downloadState === "downloaded")
|
||||||
return qsTr("Texture was already downloaded.")
|
return qsTr("Texture was already downloaded.")
|
||||||
if (root.downloadState === "unavailable")
|
if (root.downloadState === "unavailable")
|
||||||
@@ -42,16 +40,14 @@ Item {
|
|||||||
return qsTr("Click to download the texture.")
|
return qsTr("Click to download the texture.")
|
||||||
}
|
}
|
||||||
|
|
||||||
function startDownload(message)
|
function startDownload(message) {
|
||||||
{
|
|
||||||
if (root.downloadState !== "" && root.downloadState !== "failed")
|
if (root.downloadState !== "" && root.downloadState !== "failed")
|
||||||
return
|
return
|
||||||
|
|
||||||
root._startDownload(textureDownloader, message)
|
root._startDownload(textureDownloader, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTexture()
|
function updateTexture() {
|
||||||
{
|
|
||||||
if (root.downloadState !== "downloaded")
|
if (root.downloadState !== "downloaded")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -59,8 +55,7 @@ Item {
|
|||||||
root._startDownload(textureDownloader, qsTr("Updating..."))
|
root._startDownload(textureDownloader, qsTr("Updating..."))
|
||||||
}
|
}
|
||||||
|
|
||||||
function _startDownload(downloader, message)
|
function _startDownload(downloader, message) {
|
||||||
{
|
|
||||||
progressBar.visible = true
|
progressBar.visible = true
|
||||||
tooltip.visible = false
|
tooltip.visible = false
|
||||||
root.progressText = message
|
root.progressText = message
|
||||||
@@ -144,8 +139,8 @@ Item {
|
|||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // TextureProgressBar
|
}
|
||||||
} // Rectangle
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: image
|
id: image
|
||||||
@@ -197,7 +192,7 @@ Item {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
root.startDownload(qsTr("Downloading..."))
|
root.startDownload(qsTr("Downloading..."))
|
||||||
}
|
}
|
||||||
} // IconButton
|
}
|
||||||
|
|
||||||
IconButton {
|
IconButton {
|
||||||
id: updateButton
|
id: updateButton
|
||||||
@@ -233,7 +228,7 @@ Item {
|
|||||||
|
|
||||||
scale: updateButton.containsMouse ? 1.2 : 1
|
scale: updateButton.containsMouse ? 1.2 : 1
|
||||||
}
|
}
|
||||||
} // Update IconButton
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: isNewFlag
|
id: isNewFlag
|
||||||
@@ -282,7 +277,7 @@ Item {
|
|||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Image
|
}
|
||||||
|
|
||||||
FileDownloader {
|
FileDownloader {
|
||||||
id: textureDownloader
|
id: textureDownloader
|
||||||
|
|||||||
@@ -14,8 +14,18 @@ HelperWidgets.ScrollView {
|
|||||||
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
|
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
|
||||||
&& !HelperWidgets.Controller.contextMenuOpened
|
&& !HelperWidgets.Controller.contextMenuOpened
|
||||||
|
|
||||||
readonly property int cellWidth: 100
|
property int cellWidth: 100
|
||||||
readonly property int cellHeight: 100
|
property int cellHeight: 100
|
||||||
|
property int numColumns: 4
|
||||||
|
|
||||||
|
property int count: 0
|
||||||
|
function assignMaxCount() {
|
||||||
|
let c = 0
|
||||||
|
for (let i = 0; i < categoryRepeater.count; ++i)
|
||||||
|
c = Math.max(c, categoryRepeater.itemAt(i)?.count ?? 0)
|
||||||
|
|
||||||
|
root.count = c
|
||||||
|
}
|
||||||
|
|
||||||
property var currMaterialItem: null
|
property var currMaterialItem: null
|
||||||
property var rootItem: null
|
property var rootItem: null
|
||||||
@@ -24,21 +34,20 @@ HelperWidgets.ScrollView {
|
|||||||
required property var model
|
required property var model
|
||||||
required property string sectionCategory
|
required property string sectionCategory
|
||||||
|
|
||||||
signal unimport(var bundleMat);
|
signal unimport(var bundleMat)
|
||||||
|
|
||||||
function closeContextMenu()
|
function closeContextMenu() {
|
||||||
{
|
|
||||||
ctxMenu.close()
|
ctxMenu.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandVisibleSections()
|
function expandVisibleSections() {
|
||||||
{
|
|
||||||
for (let i = 0; i < categoryRepeater.count; ++i) {
|
for (let i = 0; i < categoryRepeater.count; ++i) {
|
||||||
let cat = categoryRepeater.itemAt(i)
|
let cat = categoryRepeater.itemAt(i)
|
||||||
if (cat.visible && !cat.expanded)
|
if (cat.visible && !cat.expanded)
|
||||||
cat.expandSection()
|
cat.expandSection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
ContentLibraryTextureContextMenu {
|
ContentLibraryTextureContextMenu {
|
||||||
id: ctxMenu
|
id: ctxMenu
|
||||||
@@ -52,10 +61,15 @@ HelperWidgets.ScrollView {
|
|||||||
model: root.model
|
model: root.model
|
||||||
|
|
||||||
delegate: HelperWidgets.Section {
|
delegate: HelperWidgets.Section {
|
||||||
|
id: section
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
|
leftPadding: StudioTheme.Values.sectionPadding
|
||||||
|
rightPadding: StudioTheme.Values.sectionPadding
|
||||||
|
topPadding: StudioTheme.Values.sectionPadding
|
||||||
|
bottomPadding: StudioTheme.Values.sectionPadding
|
||||||
|
|
||||||
caption: bundleCategoryName
|
caption: bundleCategoryName
|
||||||
addTopPadding: false
|
|
||||||
sectionBackgroundColor: "transparent"
|
|
||||||
visible: bundleCategoryVisible && !root.model.isEmpty
|
visible: bundleCategoryVisible && !root.model.isEmpty
|
||||||
expanded: bundleCategoryExpanded
|
expanded: bundleCategoryExpanded
|
||||||
expandOnClick: false
|
expandOnClick: false
|
||||||
@@ -69,15 +83,17 @@ HelperWidgets.ScrollView {
|
|||||||
bundleCategoryExpanded = true
|
bundleCategoryExpanded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property alias count: repeater.count
|
||||||
|
|
||||||
|
onCountChanged: root.assignMaxCount()
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
width: root.width
|
width: section.width - section.leftPadding - section.rightPadding
|
||||||
leftPadding: 5
|
spacing: StudioTheme.Values.sectionGridSpacing
|
||||||
rightPadding: 5
|
columns: root.numColumns
|
||||||
bottomPadding: 5
|
|
||||||
spacing: 5
|
|
||||||
columns: root.width / root.cellWidth
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
id: repeater
|
||||||
model: bundleCategoryTextures
|
model: bundleCategoryTextures
|
||||||
|
|
||||||
delegate: ContentLibraryTexture {
|
delegate: ContentLibraryTexture {
|
||||||
@@ -86,6 +102,8 @@ HelperWidgets.ScrollView {
|
|||||||
|
|
||||||
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: root.assignMaxCount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,9 @@
|
|||||||
"EnterComponentIcon": {
|
"EnterComponentIcon": {
|
||||||
"iconName": "editComponent_small"
|
"iconName": "editComponent_small"
|
||||||
},
|
},
|
||||||
|
"JumpToCodeIcon": {
|
||||||
|
"iconName": "jumpToCode_small"
|
||||||
|
},
|
||||||
"EventListIcon": {
|
"EventListIcon": {
|
||||||
"iconName": "events_small"
|
"iconName": "events_small"
|
||||||
},
|
},
|
||||||
@@ -218,6 +221,9 @@
|
|||||||
"EditColorIcon": {
|
"EditColorIcon": {
|
||||||
"iconName": "colorSelection_medium"
|
"iconName": "colorSelection_medium"
|
||||||
},
|
},
|
||||||
|
"BakeLightIcon": {
|
||||||
|
"iconName": "bakeLights_medium"
|
||||||
|
},
|
||||||
"EditLightIcon": {
|
"EditLightIcon": {
|
||||||
"Off": {
|
"Off": {
|
||||||
"iconName": "editLightOff_medium"
|
"iconName": "editLightOff_medium"
|
||||||
@@ -264,6 +270,9 @@
|
|||||||
"SnappingConfIcon": {
|
"SnappingConfIcon": {
|
||||||
"iconName": "snapping_conf_medium"
|
"iconName": "snapping_conf_medium"
|
||||||
},
|
},
|
||||||
|
"SplitViewIcon": {
|
||||||
|
"iconName": "splitScreen_medium"
|
||||||
|
},
|
||||||
"ToggleGroupIcon": {
|
"ToggleGroupIcon": {
|
||||||
"Off": {
|
"Off": {
|
||||||
"iconName": "selectOutline_medium"
|
"iconName": "selectOutline_medium"
|
||||||
|
|||||||
@@ -12,14 +12,7 @@ import EffectMakerBackend
|
|||||||
HelperWidgets.Section {
|
HelperWidgets.Section {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// model properties
|
caption: nodeName
|
||||||
required property string nodeName
|
|
||||||
required property bool nodeEnabled
|
|
||||||
required property var nodeUniformsModel
|
|
||||||
|
|
||||||
required property int index
|
|
||||||
|
|
||||||
caption: root.nodeName
|
|
||||||
category: "EffectMaker"
|
category: "EffectMaker"
|
||||||
|
|
||||||
draggable: true
|
draggable: true
|
||||||
@@ -32,18 +25,18 @@ HelperWidgets.Section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showEyeButton: true
|
showEyeButton: true
|
||||||
eyeEnabled: root.nodeEnabled
|
eyeEnabled: nodeEnabled
|
||||||
eyeButtonToolTip: qsTr("Enable/Disable Node")
|
eyeButtonToolTip: qsTr("Enable/Disable Node")
|
||||||
|
|
||||||
onEyeButtonClicked: {
|
onEyeButtonClicked: {
|
||||||
root.nodeEnabled = root.eyeEnabled
|
nodeEnabled = root.eyeEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.nodeUniformsModel
|
model: nodeUniformsModel
|
||||||
|
|
||||||
EffectCompositionNodeUniform {
|
EffectCompositionNodeUniform {
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Item {
|
|||||||
valueLoader.source = "ValueBool.qml"
|
valueLoader.source = "ValueBool.qml"
|
||||||
else if (uniformType === "color")
|
else if (uniformType === "color")
|
||||||
valueLoader.source = "ValueColor.qml"
|
valueLoader.source = "ValueColor.qml"
|
||||||
else if (uniformType === "image")
|
else if (uniformType === "sampler2D")
|
||||||
valueLoader.source = "ValueImage.qml"
|
valueLoader.source = "ValueImage.qml"
|
||||||
else if (uniformType === "define")
|
else if (uniformType === "define")
|
||||||
valueLoader.source = "ValueDefine.qml"
|
valueLoader.source = "ValueDefine.qml"
|
||||||
@@ -50,6 +50,7 @@ Item {
|
|||||||
Layout.maximumWidth: 140
|
Layout.maximumWidth: 140
|
||||||
Layout.minimumWidth: 140
|
Layout.minimumWidth: 140
|
||||||
Layout.preferredWidth: 140
|
Layout.preferredWidth: 140
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
HelperWidgets.ToolTipArea {
|
HelperWidgets.ToolTipArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -14,6 +14,18 @@ Item {
|
|||||||
property var secsY: []
|
property var secsY: []
|
||||||
property int moveFromIdx: 0
|
property int moveFromIdx: 0
|
||||||
property int moveToIdx: 0
|
property int moveToIdx: 0
|
||||||
|
property bool previewAnimationRunning: false
|
||||||
|
|
||||||
|
SaveDialog {
|
||||||
|
id: saveDialog
|
||||||
|
compositionName: EffectMakerBackend.effectMakerModel.currentComposition
|
||||||
|
anchors.centerIn: parent
|
||||||
|
onAccepted: {
|
||||||
|
let name = saveDialog.compositionName
|
||||||
|
EffectMakerBackend.effectMakerModel.exportComposition(name)
|
||||||
|
EffectMakerBackend.effectMakerModel.exportResources(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: col
|
id: col
|
||||||
@@ -21,11 +33,17 @@ Item {
|
|||||||
spacing: 1
|
spacing: 1
|
||||||
|
|
||||||
EffectMakerTopBar {
|
EffectMakerTopBar {
|
||||||
|
onSaveClicked: saveDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectMakerPreview {
|
EffectMakerPreview {
|
||||||
mainRoot: root
|
mainRoot: root
|
||||||
|
|
||||||
|
FrameAnimation {
|
||||||
|
id: previewFrameTimer
|
||||||
|
running: true
|
||||||
|
paused: !previewAnimationRunning
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -47,11 +65,14 @@ Item {
|
|||||||
style: StudioTheme.Values.viewBarButtonStyle
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.code
|
buttonIcon: StudioTheme.Constants.code
|
||||||
tooltip: qsTr("Open Shader in Code Editor")
|
tooltip: qsTr("Open Shader in Code Editor")
|
||||||
|
visible: false // TODO: to be implemented
|
||||||
|
|
||||||
onClicked: {} // TODO
|
onClicked: {} // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: HelperWidgets.Controller.mainScrollView = scrollView
|
||||||
|
|
||||||
HelperWidgets.ScrollView {
|
HelperWidgets.ScrollView {
|
||||||
id: scrollView
|
id: scrollView
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// 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 QtQuickDesignerTheme
|
import QtQuickDesignerTheme
|
||||||
import HelperWidgets as HelperWidgets
|
import HelperWidgets as HelperWidgets
|
||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
@@ -12,24 +11,58 @@ import EffectMakerBackend
|
|||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property real animatedTime: previewFrameTimer.elapsedTime
|
||||||
|
property int animatedFrame: previewFrameTimer.currentFrame
|
||||||
|
property bool timeRunning: previewAnimationRunning
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
required property Item mainRoot
|
required property Item mainRoot
|
||||||
property var effectMakerModel: EffectMakerBackend.effectMakerModel
|
property var effectMakerModel: EffectMakerBackend.effectMakerModel
|
||||||
property alias source: source
|
property alias source: source
|
||||||
// The delay in ms to wait until updating the effect
|
// The delay in ms to wait until updating the effect
|
||||||
readonly property int updateDelay: 200
|
readonly property int updateDelay: 100
|
||||||
|
|
||||||
|
// Create a dummy parent to host the effect qml object
|
||||||
|
function createNewComponent() {
|
||||||
|
// If we have a working effect, do not show preview image as it shows through
|
||||||
|
// transparent parts of the final image
|
||||||
|
source.visible = false;
|
||||||
|
|
||||||
|
var oldComponent = componentParent.children[0];
|
||||||
|
if (oldComponent)
|
||||||
|
oldComponent.destroy();
|
||||||
|
try {
|
||||||
|
const newObject = Qt.createQmlObject(
|
||||||
|
effectMakerModel.qmlComponentString,
|
||||||
|
componentParent,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
effectMakerModel.resetEffectError(0);
|
||||||
|
} catch (error) {
|
||||||
|
let errorString = "QML: ERROR: ";
|
||||||
|
let errorLine = -1;
|
||||||
|
if (error.qmlErrors.length > 0) {
|
||||||
|
// Show the first QML error
|
||||||
|
let e = error.qmlErrors[0];
|
||||||
|
errorString += e.lineNumber + ": " + e.message;
|
||||||
|
errorLine = e.lineNumber;
|
||||||
|
}
|
||||||
|
effectMakerModel.setEffectError(errorString, 0, errorLine);
|
||||||
|
source.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle { // toolbar
|
Rectangle { // toolbar
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: StudioTheme.Values.toolbarHeight
|
height: StudioTheme.Values.toolbarHeight
|
||||||
color: StudioTheme.Values.themeToolbarBackground
|
color: StudioTheme.Values.themeToolbarBackground
|
||||||
|
|
||||||
RowLayout {
|
Row {
|
||||||
anchors.fill: parent
|
|
||||||
spacing: 5
|
spacing: 5
|
||||||
anchors.rightMargin: 5
|
|
||||||
anchors.leftMargin: 5
|
anchors.leftMargin: 5
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
PreviewImagesComboBox {
|
PreviewImagesComboBox {
|
||||||
id: imagesComboBox
|
id: imagesComboBox
|
||||||
@@ -37,9 +70,19 @@ Column {
|
|||||||
mainRoot: root.mainRoot
|
mainRoot: root.mainRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
StudioControls.ColorEditor {
|
||||||
Layout.fillWidth: true
|
id: colorEditor
|
||||||
|
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
showHexTextField: false
|
||||||
|
color: "#dddddd"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 5
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
enabled: sourceImage.scale > .4
|
enabled: sourceImage.scale > .4
|
||||||
@@ -73,20 +116,24 @@ Column {
|
|||||||
sourceImage.scale = 1
|
sourceImage.scale = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 5
|
||||||
|
anchors.rightMargin: 5
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Text {
|
Text {
|
||||||
text: "0.000s"
|
text: animatedTime >= 100
|
||||||
|
? animatedTime.toFixed(1) + " s" : animatedTime.toFixed(3) + " s"
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: 10
|
font.pixelSize: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: "0000000"
|
text: (animatedFrame).toString().padStart(6, '0')
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: 10
|
font.pixelSize: 10
|
||||||
}
|
}
|
||||||
@@ -97,15 +144,20 @@ Column {
|
|||||||
buttonIcon: StudioTheme.Constants.toStartFrame_medium
|
buttonIcon: StudioTheme.Constants.toStartFrame_medium
|
||||||
tooltip: qsTr("Restart Animation")
|
tooltip: qsTr("Restart Animation")
|
||||||
|
|
||||||
onClicked: {} // TODO
|
onClicked: {
|
||||||
|
previewFrameTimer.reset()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
style: StudioTheme.Values.viewBarButtonStyle
|
||||||
buttonIcon: StudioTheme.Constants.topToolbar_runProject
|
buttonIcon: previewAnimationRunning ? StudioTheme.Constants.pause_medium
|
||||||
|
: StudioTheme.Constants.playOutline_medium
|
||||||
tooltip: qsTr("Play Animation")
|
tooltip: qsTr("Play Animation")
|
||||||
|
|
||||||
onClicked: {} // TODO
|
onClicked: {
|
||||||
|
previewAnimationRunning = !previewAnimationRunning
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +165,7 @@ Column {
|
|||||||
Rectangle { // preview image
|
Rectangle { // preview image
|
||||||
id: preview
|
id: preview
|
||||||
|
|
||||||
color: "#dddddd"
|
color: colorEditor.color
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 200
|
height: 200
|
||||||
clip: true
|
clip: true
|
||||||
@@ -147,53 +199,26 @@ Column {
|
|||||||
width: source.width
|
width: source.width
|
||||||
height: source.height
|
height: source.height
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
scale: 1 //TODO should come from toolbar
|
|
||||||
// Cache the layer. This way heavy shaders rendering doesn't
|
// Cache the layer. This way heavy shaders rendering doesn't
|
||||||
// slow down code editing & rest of the UI.
|
// slow down code editing & rest of the UI.
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.smooth: true
|
layer.smooth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a dummy parent to host the effect qml object
|
|
||||||
function createNewComponent() {
|
|
||||||
var oldComponent = componentParent.children[0];
|
|
||||||
if (oldComponent)
|
|
||||||
oldComponent.destroy();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const newObject = Qt.createQmlObject(
|
|
||||||
effectMakerModel.qmlComponentString,
|
|
||||||
componentParent,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
effectMakerModel.resetEffectError(0);
|
|
||||||
} catch (error) {
|
|
||||||
let errorString = "QML: ERROR: ";
|
|
||||||
let errorLine = -1;
|
|
||||||
if (error.qmlErrors.length > 0) {
|
|
||||||
// Show the first QML error
|
|
||||||
let e = error.qmlErrors[0];
|
|
||||||
errorString += e.lineNumber + ": " + e.message;
|
|
||||||
errorLine = e.lineNumber;
|
|
||||||
}
|
|
||||||
effectMakerModel.setEffectError(errorString, 0, errorLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: effectMakerModel
|
target: effectMakerModel
|
||||||
function onShadersBaked() {
|
function onShadersBaked() {
|
||||||
console.log("Shaders Baked!")
|
console.log("Shaders Baked!")
|
||||||
//updateTimer.restart(); // Disable for now
|
updateTimer.restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: updateTimer
|
id: updateTimer
|
||||||
interval: updateDelay;
|
interval: updateDelay
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
effectMakerModel.updateQmlComponent();
|
effectMakerModel.updateQmlComponent()
|
||||||
createNewComponent();
|
createNewComponent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ Rectangle {
|
|||||||
height: StudioTheme.Values.toolbarHeight
|
height: StudioTheme.Values.toolbarHeight
|
||||||
color: StudioTheme.Values.themeToolbarBackground
|
color: StudioTheme.Values.themeToolbarBackground
|
||||||
|
|
||||||
|
signal saveClicked
|
||||||
|
|
||||||
HelperWidgets.Button {
|
HelperWidgets.Button {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
x: 5
|
x: 5
|
||||||
|
|
||||||
text: qsTr("Save in Library")
|
text: qsTr("Save in Library")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: root.saveClicked()
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ StudioControls.ComboBox {
|
|||||||
|
|
||||||
width: row.width + 2 // 2: scrollView left and right 1px margins
|
width: row.width + 2 // 2: scrollView left and right 1px margins
|
||||||
height: Math.min(800, Math.min(row.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar
|
height: Math.min(800, Math.min(row.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar
|
||||||
flags: Qt.Dialog | Qt.FramelessWindowHint
|
flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
|
||||||
|
|
||||||
onActiveFocusItemChanged: {
|
onActiveFocusItemChanged: {
|
||||||
if (!window.activeFocusItem && !root.indicator.hover && root.popup.opened)
|
if (!window.activeFocusItem && !root.indicator.hover && root.popup.opened)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ StudioControls.ComboBox {
|
|||||||
|
|
||||||
width: col.width + 2 // 2: scrollView left and right 1px margins
|
width: col.width + 2 // 2: scrollView left and right 1px margins
|
||||||
height: Math.min(800, Math.min(col.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar
|
height: Math.min(800, Math.min(col.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar
|
||||||
flags: Qt.Dialog | Qt.FramelessWindowHint
|
flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
|
||||||
|
|
||||||
onActiveFocusItemChanged: {
|
onActiveFocusItemChanged: {
|
||||||
if (!window.activeFocusItem && !root.indicator.hover && root.popup.opened)
|
if (!window.activeFocusItem && !root.indicator.hover && root.popup.opened)
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import HelperWidgets as HelperWidgets
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
import AssetsLibraryBackend
|
||||||
|
|
||||||
|
StudioControls.Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Save Effect")
|
||||||
|
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
modal: true
|
||||||
|
implicitWidth: 250
|
||||||
|
implicitHeight: 160
|
||||||
|
|
||||||
|
property string compositionName: ""
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
nameText.text = compositionName //TODO: Generate unique name
|
||||||
|
emptyText.text = ""
|
||||||
|
nameText.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
Column {
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: row
|
||||||
|
Text {
|
||||||
|
text: qsTr("Effect name: ")
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.TextField {
|
||||||
|
id: nameText
|
||||||
|
|
||||||
|
actionIndicator.visible: false
|
||||||
|
translationIndicator.visible: false
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
let errMsg = ""
|
||||||
|
if (/[^A-Za-z0-9_]+/.test(text))
|
||||||
|
errMsg = qsTr("Name contains invalid characters.")
|
||||||
|
else if (!/^[A-Z]/.test(text))
|
||||||
|
errMsg = qsTr("Name must start with a capital letter")
|
||||||
|
else if (text.length < 3)
|
||||||
|
errMsg = qsTr("Name must have at least 3 characters")
|
||||||
|
else if (/\s/.test(text))
|
||||||
|
errMsg = qsTr("Name cannot contain white space")
|
||||||
|
|
||||||
|
emptyText.text = errMsg
|
||||||
|
btnSave.enabled = errMsg.length === 0
|
||||||
|
}
|
||||||
|
Keys.onEnterPressed: btnSave.onClicked()
|
||||||
|
Keys.onReturnPressed: btnSave.onClicked()
|
||||||
|
Keys.onEscapePressed: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: emptyText
|
||||||
|
|
||||||
|
color: StudioTheme.Values.themeError
|
||||||
|
anchors.right: row.right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
id: btnSave
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
enabled: nameText.text !== ""
|
||||||
|
onClicked: {
|
||||||
|
root.compositionName = nameText.text
|
||||||
|
root.accept() //TODO: Check if name is unique
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuickDesignerTheme
|
import QtQuickDesignerTheme
|
||||||
import HelperWidgets as HelperWidgets
|
import StudioControls as StudioControls
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme 1.0 as StudioTheme
|
||||||
import EffectMakerBackend
|
import EffectMakerBackend
|
||||||
|
|
||||||
@@ -13,11 +13,11 @@ Row {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: 5
|
spacing: 5
|
||||||
|
|
||||||
HelperWidgets.ColorEditor {
|
StudioControls.ColorEditor {
|
||||||
backendValue: uniformBackendValue
|
actionIndicatorVisible: false
|
||||||
|
|
||||||
showExtendedFunctionButton: false
|
Component.onCompleted: color = uniformValue
|
||||||
|
|
||||||
onValueChanged: uniformValue = convertColorToString(color)
|
onColorChanged: uniformValue = color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ Rectangle {
|
|||||||
id: column
|
id: column
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
Section {
|
HelperWidgets.Section {
|
||||||
id: trackingSection
|
id: trackingSection
|
||||||
caption: qsTr("Tracking")
|
caption: qsTr("Tracking")
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -167,7 +167,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
HelperWidgets.Section {
|
||||||
id: predefinedSection
|
id: predefinedSection
|
||||||
caption: qsTr("Predefined Categories")
|
caption: qsTr("Predefined Categories")
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -227,7 +227,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: 1; height: 4}
|
Item { width: 1; height: 4 }
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: insightModel
|
model: insightModel
|
||||||
@@ -268,7 +268,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
HelperWidgets.Section {
|
||||||
id: customSection
|
id: customSection
|
||||||
caption: qsTr("Custom Categories")
|
caption: qsTr("Custom Categories")
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -325,7 +325,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: 1; height: 4}
|
Item { width: 1; height: 4 }
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: customRepeater
|
id: customRepeater
|
||||||
@@ -387,7 +387,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: 1; height: 4}
|
Item { width: 1; height: 4 }
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: StudioTheme.Values.checkBoxSpacing
|
spacing: StudioTheme.Values.checkBoxSpacing
|
||||||
|
|||||||
@@ -237,9 +237,7 @@ Item {
|
|||||||
Repeater {
|
Repeater {
|
||||||
model: ItemLibraryBackend.itemLibraryModel // to be set in Qml context
|
model: ItemLibraryBackend.itemLibraryModel // to be set in Qml context
|
||||||
delegate: HelperWidgets.Section {
|
delegate: HelperWidgets.Section {
|
||||||
width: itemsView.width -
|
width: itemsView.width
|
||||||
(verticalScrollView.verticalScrollBarVisible
|
|
||||||
? verticalScrollView.verticalThickness : 0)
|
|
||||||
caption: importName
|
caption: importName
|
||||||
visible: importVisible
|
visible: importVisible
|
||||||
sectionHeight: 30
|
sectionHeight: 30
|
||||||
@@ -270,9 +268,7 @@ Item {
|
|||||||
Repeater {
|
Repeater {
|
||||||
model: categoryModel
|
model: categoryModel
|
||||||
delegate: HelperWidgets.Section {
|
delegate: HelperWidgets.Section {
|
||||||
width: itemsView.width -
|
width: itemsView.width
|
||||||
(verticalScrollView.verticalScrollBarVisible
|
|
||||||
? verticalScrollView.verticalThickness : 0)
|
|
||||||
sectionBackgroundColor: "transparent"
|
sectionBackgroundColor: "transparent"
|
||||||
showTopSeparator: index > 0
|
showTopSeparator: index > 0
|
||||||
hideHeader: categoryModel.rowCount() <= 1
|
hideHeader: categoryModel.rowCount() <= 1
|
||||||
@@ -351,9 +347,7 @@ Item {
|
|||||||
Repeater {
|
Repeater {
|
||||||
model: ItemLibraryBackend.itemLibraryModel // to be set in Qml context
|
model: ItemLibraryBackend.itemLibraryModel // to be set in Qml context
|
||||||
delegate: HelperWidgets.Section {
|
delegate: HelperWidgets.Section {
|
||||||
width: 265 -
|
width: 265
|
||||||
(horizontalScrollView.verticalScrollBarVisible
|
|
||||||
? horizontalScrollView.verticalThickness : 0)
|
|
||||||
caption: importName
|
caption: importName
|
||||||
visible: importVisible
|
visible: importVisible
|
||||||
sectionHeight: 30
|
sectionHeight: 30
|
||||||
@@ -384,9 +378,7 @@ Item {
|
|||||||
Repeater {
|
Repeater {
|
||||||
model: categoryModel
|
model: categoryModel
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
width: 265 -
|
width: 265
|
||||||
(horizontalScrollView.verticalScrollBarVisible
|
|
||||||
? horizontalScrollView.verticalThickness : 0)
|
|
||||||
height: 25
|
height: 25
|
||||||
visible: categoryVisible
|
visible: categoryVisible
|
||||||
border.width: StudioTheme.Values.border
|
border.width: StudioTheme.Values.border
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ Item {
|
|||||||
id: root
|
id: root
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
readonly property int cellWidth: 100
|
readonly property real cellWidth: root.thumbnailSize
|
||||||
readonly property int cellHeight: 120
|
readonly property real cellHeight: root.thumbnailSize + 20
|
||||||
readonly property bool enableUiElements: materialBrowserModel.hasMaterialLibrary
|
readonly property bool enableUiElements: materialBrowserModel.hasMaterialLibrary
|
||||||
&& materialBrowserModel.hasQuick3DImport
|
&& materialBrowserModel.hasQuick3DImport
|
||||||
|
|
||||||
@@ -22,30 +22,60 @@ Item {
|
|||||||
property var materialBrowserModel: MaterialBrowserBackend.materialBrowserModel
|
property var materialBrowserModel: MaterialBrowserBackend.materialBrowserModel
|
||||||
property var materialBrowserTexturesModel: MaterialBrowserBackend.materialBrowserTexturesModel
|
property var materialBrowserTexturesModel: MaterialBrowserBackend.materialBrowserTexturesModel
|
||||||
|
|
||||||
|
property int numColumns: 0
|
||||||
|
property real thumbnailSize: 100
|
||||||
|
|
||||||
|
readonly property int minThumbSize: 100
|
||||||
|
readonly property int maxThumbSize: 150
|
||||||
|
|
||||||
|
function responsiveResize(width: int, height: int) {
|
||||||
|
width -= 2 * StudioTheme.Values.sectionPadding
|
||||||
|
|
||||||
|
let numColumns = Math.floor(width / root.minThumbSize)
|
||||||
|
let remainder = width % root.minThumbSize
|
||||||
|
let space = (numColumns - 1) * StudioTheme.Values.sectionGridSpacing
|
||||||
|
|
||||||
|
if (remainder < space)
|
||||||
|
numColumns -= 1
|
||||||
|
|
||||||
|
if (numColumns < 1)
|
||||||
|
return
|
||||||
|
|
||||||
|
let maxItems = Math.max(texturesRepeater.count, materialRepeater.count)
|
||||||
|
|
||||||
|
if (numColumns > maxItems)
|
||||||
|
numColumns = maxItems
|
||||||
|
|
||||||
|
let rest = width - (numColumns * root.minThumbSize)
|
||||||
|
- ((numColumns - 1) * StudioTheme.Values.sectionGridSpacing)
|
||||||
|
|
||||||
|
root.thumbnailSize = Math.min(root.minThumbSize + (rest / numColumns),
|
||||||
|
root.maxThumbSize)
|
||||||
|
root.numColumns = numColumns
|
||||||
|
}
|
||||||
|
|
||||||
|
onWidthChanged: root.responsiveResize(root.width, root.height)
|
||||||
|
|
||||||
// Called also from C++ to close context menu on focus out
|
// Called also from C++ to close context menu on focus out
|
||||||
function closeContextMenu()
|
function closeContextMenu() {
|
||||||
{
|
|
||||||
ctxMenu.close()
|
ctxMenu.close()
|
||||||
ctxMenuTextures.close()
|
ctxMenuTextures.close()
|
||||||
HelperWidgets.Controller.closeContextMenu()
|
HelperWidgets.Controller.closeContextMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from C++ to refresh a preview material after it changes
|
// Called from C++ to refresh a preview material after it changes
|
||||||
function refreshPreview(idx)
|
function refreshPreview(idx) {
|
||||||
{
|
|
||||||
var item = materialRepeater.itemAt(idx);
|
var item = materialRepeater.itemAt(idx);
|
||||||
if (item)
|
if (item)
|
||||||
item.refreshPreview();
|
item.refreshPreview()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from C++
|
// Called from C++
|
||||||
function clearSearchFilter()
|
function clearSearchFilter() {
|
||||||
{
|
searchBox.clear()
|
||||||
searchBox.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextVisibleItem(idx, count, itemModel)
|
function nextVisibleItem(idx, count, itemModel) {
|
||||||
{
|
|
||||||
if (count === 0)
|
if (count === 0)
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
@@ -66,8 +96,7 @@ Item {
|
|||||||
return newIdx
|
return newIdx
|
||||||
}
|
}
|
||||||
|
|
||||||
function visibleItemCount(itemModel)
|
function visibleItemCount(itemModel) {
|
||||||
{
|
|
||||||
let curIdx = 0
|
let curIdx = 0
|
||||||
let count = 0
|
let count = 0
|
||||||
|
|
||||||
@@ -79,8 +108,7 @@ Item {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
function rowIndexOfItem(idx, rowSize, itemModel)
|
function rowIndexOfItem(idx, rowSize, itemModel) {
|
||||||
{
|
|
||||||
if (rowSize === 1)
|
if (rowSize === 1)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -98,8 +126,7 @@ Item {
|
|||||||
return count % rowSize
|
return count % rowSize
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNextVisibleItem(delta)
|
function selectNextVisibleItem(delta) {
|
||||||
{
|
|
||||||
if (searchBox.activeFocus)
|
if (searchBox.activeFocus)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -112,35 +139,35 @@ Item {
|
|||||||
|
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
if (matSecFocused) {
|
if (matSecFocused) {
|
||||||
targetIdx = nextVisibleItem(materialBrowserModel.selectedIndex,
|
targetIdx = root.nextVisibleItem(materialBrowserModel.selectedIndex,
|
||||||
delta, materialBrowserModel)
|
delta, materialBrowserModel)
|
||||||
if (targetIdx >= 0)
|
if (targetIdx >= 0)
|
||||||
materialBrowserModel.selectMaterial(targetIdx)
|
materialBrowserModel.selectMaterial(targetIdx)
|
||||||
} else if (texSecFocused) {
|
} else if (texSecFocused) {
|
||||||
targetIdx = nextVisibleItem(materialBrowserTexturesModel.selectedIndex,
|
targetIdx = root.nextVisibleItem(materialBrowserTexturesModel.selectedIndex,
|
||||||
delta, materialBrowserTexturesModel)
|
delta, materialBrowserTexturesModel)
|
||||||
if (targetIdx >= 0) {
|
if (targetIdx >= 0) {
|
||||||
materialBrowserTexturesModel.selectTexture(targetIdx)
|
materialBrowserTexturesModel.selectTexture(targetIdx)
|
||||||
} else if (!materialBrowserModel.isEmpty && materialsSection.expanded) {
|
} else if (!materialBrowserModel.isEmpty && materialsSection.expanded) {
|
||||||
targetIdx = nextVisibleItem(materialBrowserModel.rowCount(), -1, materialBrowserModel)
|
targetIdx = root.nextVisibleItem(materialBrowserModel.rowCount(), -1, materialBrowserModel)
|
||||||
if (targetIdx >= 0) {
|
if (targetIdx >= 0) {
|
||||||
if (delta !== -1) {
|
if (delta !== -1) {
|
||||||
// Try to match column when switching between materials/textures
|
// Try to match column when switching between materials/textures
|
||||||
origRowIdx = rowIndexOfItem(materialBrowserTexturesModel.selectedIndex,
|
origRowIdx = root.rowIndexOfItem(materialBrowserTexturesModel.selectedIndex,
|
||||||
-delta, materialBrowserTexturesModel)
|
-delta, materialBrowserTexturesModel)
|
||||||
if (visibleItemCount(materialBrowserModel) > origRowIdx) {
|
if (root.visibleItemCount(materialBrowserModel) > origRowIdx) {
|
||||||
rowIdx = rowIndexOfItem(targetIdx, -delta, materialBrowserModel)
|
rowIdx = root.rowIndexOfItem(targetIdx, -delta, materialBrowserModel)
|
||||||
if (rowIdx >= origRowIdx) {
|
if (rowIdx >= origRowIdx) {
|
||||||
newTargetIdx = nextVisibleItem(targetIdx,
|
newTargetIdx = root.nextVisibleItem(targetIdx,
|
||||||
-(rowIdx - origRowIdx),
|
-(rowIdx - origRowIdx),
|
||||||
materialBrowserModel)
|
materialBrowserModel)
|
||||||
} else {
|
} else {
|
||||||
newTargetIdx = nextVisibleItem(targetIdx,
|
newTargetIdx = root.nextVisibleItem(targetIdx,
|
||||||
-(-delta - origRowIdx + rowIdx),
|
-(-delta - origRowIdx + rowIdx),
|
||||||
materialBrowserModel)
|
materialBrowserModel)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newTargetIdx = nextVisibleItem(materialBrowserModel.rowCount(),
|
newTargetIdx = root.nextVisibleItem(materialBrowserModel.rowCount(),
|
||||||
-1, materialBrowserModel)
|
-1, materialBrowserModel)
|
||||||
}
|
}
|
||||||
if (newTargetIdx >= 0)
|
if (newTargetIdx >= 0)
|
||||||
@@ -153,24 +180,24 @@ Item {
|
|||||||
}
|
}
|
||||||
} else if (delta > 0) {
|
} else if (delta > 0) {
|
||||||
if (matSecFocused) {
|
if (matSecFocused) {
|
||||||
targetIdx = nextVisibleItem(materialBrowserModel.selectedIndex,
|
targetIdx = root.nextVisibleItem(materialBrowserModel.selectedIndex,
|
||||||
delta, materialBrowserModel)
|
delta, materialBrowserModel)
|
||||||
if (targetIdx >= 0) {
|
if (targetIdx >= 0) {
|
||||||
materialBrowserModel.selectMaterial(targetIdx)
|
materialBrowserModel.selectMaterial(targetIdx)
|
||||||
} else if (!materialBrowserTexturesModel.isEmpty && texturesSection.expanded) {
|
} else if (!materialBrowserTexturesModel.isEmpty && texturesSection.expanded) {
|
||||||
targetIdx = nextVisibleItem(-1, 1, materialBrowserTexturesModel)
|
targetIdx = root.nextVisibleItem(-1, 1, materialBrowserTexturesModel)
|
||||||
if (targetIdx >= 0) {
|
if (targetIdx >= 0) {
|
||||||
if (delta !== 1) {
|
if (delta !== 1) {
|
||||||
// Try to match column when switching between materials/textures
|
// Try to match column when switching between materials/textures
|
||||||
origRowIdx = rowIndexOfItem(materialBrowserModel.selectedIndex,
|
origRowIdx = root.rowIndexOfItem(materialBrowserModel.selectedIndex,
|
||||||
delta, materialBrowserModel)
|
delta, materialBrowserModel)
|
||||||
if (visibleItemCount(materialBrowserTexturesModel) > origRowIdx) {
|
if (root.visibleItemCount(materialBrowserTexturesModel) > origRowIdx) {
|
||||||
if (origRowIdx > 0) {
|
if (origRowIdx > 0) {
|
||||||
newTargetIdx = nextVisibleItem(targetIdx, origRowIdx,
|
newTargetIdx = root.nextVisibleItem(targetIdx, origRowIdx,
|
||||||
materialBrowserTexturesModel)
|
materialBrowserTexturesModel)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newTargetIdx = nextVisibleItem(materialBrowserTexturesModel.rowCount(),
|
newTargetIdx = root.nextVisibleItem(materialBrowserTexturesModel.rowCount(),
|
||||||
-1, materialBrowserTexturesModel)
|
-1, materialBrowserTexturesModel)
|
||||||
}
|
}
|
||||||
if (newTargetIdx >= 0)
|
if (newTargetIdx >= 0)
|
||||||
@@ -181,7 +208,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (texSecFocused) {
|
} else if (texSecFocused) {
|
||||||
targetIdx = nextVisibleItem(materialBrowserTexturesModel.selectedIndex,
|
targetIdx = root.nextVisibleItem(materialBrowserTexturesModel.selectedIndex,
|
||||||
delta, materialBrowserTexturesModel)
|
delta, materialBrowserTexturesModel)
|
||||||
if (targetIdx >= 0)
|
if (targetIdx >= 0)
|
||||||
materialBrowserTexturesModel.selectTexture(targetIdx)
|
materialBrowserTexturesModel.selectTexture(targetIdx)
|
||||||
@@ -190,24 +217,12 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Keys.enabled: true
|
Keys.enabled: true
|
||||||
Keys.onDownPressed: {
|
Keys.onDownPressed: root.selectNextVisibleItem(gridMaterials.columns)
|
||||||
selectNextVisibleItem(gridMaterials.columns)
|
Keys.onUpPressed: root.selectNextVisibleItem(-gridMaterials.columns)
|
||||||
}
|
Keys.onLeftPressed: root.selectNextVisibleItem(-1)
|
||||||
|
Keys.onRightPressed: root.selectNextVisibleItem(1)
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
function handleEnterPress() {
|
||||||
selectNextVisibleItem(-gridMaterials.columns)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
selectNextVisibleItem(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
selectNextVisibleItem(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEnterPress()
|
|
||||||
{
|
|
||||||
if (searchBox.activeFocus)
|
if (searchBox.activeFocus)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -217,13 +232,8 @@ Item {
|
|||||||
materialBrowserTexturesModel.openTextureEditor()
|
materialBrowserTexturesModel.openTextureEditor()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: {
|
Keys.onEnterPressed: root.handleEnterPress()
|
||||||
handleEnterPress()
|
Keys.onReturnPressed: root.handleEnterPress()
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onReturnPressed: {
|
|
||||||
handleEnterPress()
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: focusGrabber
|
id: focusGrabber
|
||||||
@@ -249,10 +259,10 @@ Item {
|
|||||||
|
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
if (!root.enableUiElements)
|
if (!root.enableUiElements)
|
||||||
return;
|
return
|
||||||
|
|
||||||
var matsSecBottom = mapFromItem(materialsSection, 0, materialsSection.y).y
|
var matsSecBottom = mapFromItem(materialsSection, 0, materialsSection.y).y
|
||||||
+ materialsSection.height;
|
+ materialsSection.height
|
||||||
|
|
||||||
if (mouse.y < matsSecBottom)
|
if (mouse.y < matsSecBottom)
|
||||||
ctxMenu.popupMenu()
|
ctxMenu.popupMenu()
|
||||||
@@ -261,8 +271,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureVisible(yPos, itemHeight)
|
function ensureVisible(yPos, itemHeight) {
|
||||||
{
|
|
||||||
let currentY = contentYBehavior.targetValue && scrollViewAnim.running
|
let currentY = contentYBehavior.targetValue && scrollViewAnim.running
|
||||||
? contentYBehavior.targetValue : scrollView.contentY
|
? contentYBehavior.targetValue : scrollView.contentY
|
||||||
|
|
||||||
@@ -286,18 +295,18 @@ Item {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureSelectedVisible()
|
function ensureSelectedVisible() {
|
||||||
{
|
|
||||||
if (rootView.materialSectionFocused && materialsSection.expanded && root.currMaterialItem
|
if (rootView.materialSectionFocused && materialsSection.expanded && root.currMaterialItem
|
||||||
&& materialBrowserModel.isVisible(materialBrowserModel.selectedIndex)) {
|
&& materialBrowserModel.isVisible(materialBrowserModel.selectedIndex)) {
|
||||||
return ensureVisible(root.currMaterialItem.mapToItem(scrollView.contentItem, 0, 0).y,
|
return root.ensureVisible(root.currMaterialItem.mapToItem(scrollView.contentItem, 0, 0).y,
|
||||||
root.currMaterialItem.height)
|
root.currMaterialItem.height)
|
||||||
} else if (!rootView.materialSectionFocused && texturesSection.expanded) {
|
} else if (!rootView.materialSectionFocused && texturesSection.expanded) {
|
||||||
let currItem = texturesRepeater.itemAt(materialBrowserTexturesModel.selectedIndex)
|
let currItem = texturesRepeater.itemAt(materialBrowserTexturesModel.selectedIndex)
|
||||||
if (currItem && materialBrowserTexturesModel.isVisible(materialBrowserTexturesModel.selectedIndex))
|
if (currItem && materialBrowserTexturesModel.isVisible(materialBrowserTexturesModel.selectedIndex))
|
||||||
return ensureVisible(currItem.mapToItem(scrollView.contentItem, 0, 0).y, currItem.height)
|
return root.ensureVisible(currItem.mapToItem(scrollView.contentItem, 0, 0).y,
|
||||||
|
currItem.height)
|
||||||
} else {
|
} else {
|
||||||
return ensureVisible(0, 90)
|
return root.ensureVisible(0, 90)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,15 +319,14 @@ Item {
|
|||||||
onTriggered: {
|
onTriggered: {
|
||||||
// Redo until ensuring didn't change things
|
// Redo until ensuring didn't change things
|
||||||
if (!root.ensureSelectedVisible()) {
|
if (!root.ensureSelectedVisible()) {
|
||||||
stop()
|
ensureTimer.stop()
|
||||||
interval = 20
|
ensureTimer.interval = 20
|
||||||
triggeredOnStart = true
|
ensureTimer.triggeredOnStart = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startDelayedEnsureTimer(delay)
|
function startDelayedEnsureTimer(delay) {
|
||||||
{
|
|
||||||
// Ensuring visibility immediately in some cases like before new search results are rendered
|
// Ensuring visibility immediately in some cases like before new search results are rendered
|
||||||
// causes mapToItem return incorrect values, leading to undesirable flicker,
|
// causes mapToItem return incorrect values, leading to undesirable flicker,
|
||||||
// so delay ensuring visibility a bit.
|
// so delay ensuring visibility a bit.
|
||||||
@@ -330,8 +338,7 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: materialBrowserModel
|
target: materialBrowserModel
|
||||||
|
|
||||||
function onSelectedIndexChanged()
|
function onSelectedIndexChanged() {
|
||||||
{
|
|
||||||
// commit rename upon changing selection
|
// commit rename upon changing selection
|
||||||
if (root.currMaterialItem)
|
if (root.currMaterialItem)
|
||||||
root.currMaterialItem.forceFinishEditing();
|
root.currMaterialItem.forceFinishEditing();
|
||||||
@@ -341,8 +348,7 @@ Item {
|
|||||||
ensureTimer.start()
|
ensureTimer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onIsEmptyChanged()
|
function onIsEmptyChanged() {
|
||||||
{
|
|
||||||
ensureTimer.start()
|
ensureTimer.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,13 +356,11 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: materialBrowserTexturesModel
|
target: materialBrowserTexturesModel
|
||||||
|
|
||||||
function onSelectedIndexChanged()
|
function onSelectedIndexChanged() {
|
||||||
{
|
|
||||||
ensureTimer.start()
|
ensureTimer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onIsEmptyChanged()
|
function onIsEmptyChanged() {
|
||||||
{
|
|
||||||
ensureTimer.start()
|
ensureTimer.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,8 +368,7 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: rootView
|
target: rootView
|
||||||
|
|
||||||
function onMaterialSectionFocusedChanged()
|
function onMaterialSectionFocusedChanged() {
|
||||||
{
|
|
||||||
ensureTimer.start()
|
ensureTimer.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -614,9 +617,10 @@ Item {
|
|||||||
id: scrollView
|
id: scrollView
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
height: root.height - toolbar.height
|
height: root.height - toolbar.height - col.spacing
|
||||||
clip: true
|
clip: true
|
||||||
visible: root.enableUiElements
|
visible: root.enableUiElements
|
||||||
|
hideHorizontalScrollBar: true
|
||||||
interactive: !ctxMenu.opened && !ctxMenuTextures.opened && !rootView.isDragging
|
interactive: !ctxMenu.opened && !ctxMenuTextures.opened && !rootView.isDragging
|
||||||
&& !HelperWidgets.Controller.contextMenuOpened
|
&& !HelperWidgets.Controller.contextMenuOpened
|
||||||
|
|
||||||
@@ -637,6 +641,12 @@ Item {
|
|||||||
id: materialsSection
|
id: materialsSection
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
|
leftPadding: StudioTheme.Values.sectionPadding
|
||||||
|
rightPadding: StudioTheme.Values.sectionPadding
|
||||||
|
topPadding: StudioTheme.Values.sectionPadding
|
||||||
|
bottomPadding: StudioTheme.Values.sectionPadding
|
||||||
|
|
||||||
caption: qsTr("Materials")
|
caption: qsTr("Materials")
|
||||||
dropEnabled: true
|
dropEnabled: true
|
||||||
category: "MaterialBrowser"
|
category: "MaterialBrowser"
|
||||||
@@ -671,11 +681,10 @@ Item {
|
|||||||
Grid {
|
Grid {
|
||||||
id: gridMaterials
|
id: gridMaterials
|
||||||
|
|
||||||
width: scrollView.width
|
width: scrollView.width - materialsSection.leftPadding
|
||||||
leftPadding: 5
|
- materialsSection.rightPadding
|
||||||
rightPadding: 5
|
spacing: StudioTheme.Values.sectionGridSpacing
|
||||||
bottomPadding: 5
|
columns: root.numColumns
|
||||||
columns: root.width / root.cellWidth
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: materialRepeater
|
id: materialRepeater
|
||||||
@@ -691,10 +700,10 @@ Item {
|
|||||||
width: root.cellWidth
|
width: root.cellWidth
|
||||||
height: root.cellHeight
|
height: root.cellHeight
|
||||||
|
|
||||||
onShowContextMenu: {
|
onShowContextMenu: ctxMenu.popupMenu(this, model)
|
||||||
ctxMenu.popupMenu(this, model)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: root.responsiveResize(root.width, root.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,6 +736,11 @@ Item {
|
|||||||
id: texturesSection
|
id: texturesSection
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
|
leftPadding: StudioTheme.Values.sectionPadding
|
||||||
|
rightPadding: StudioTheme.Values.sectionPadding
|
||||||
|
topPadding: StudioTheme.Values.sectionPadding
|
||||||
|
bottomPadding: StudioTheme.Values.sectionPadding
|
||||||
|
|
||||||
caption: qsTr("Textures")
|
caption: qsTr("Textures")
|
||||||
category: "MaterialBrowser"
|
category: "MaterialBrowser"
|
||||||
|
|
||||||
@@ -768,11 +782,10 @@ Item {
|
|||||||
Grid {
|
Grid {
|
||||||
id: gridTextures
|
id: gridTextures
|
||||||
|
|
||||||
width: scrollView.width
|
width: scrollView.width - texturesSection.leftPadding
|
||||||
leftPadding: 5
|
- texturesSection.rightPadding
|
||||||
rightPadding: 5
|
spacing: StudioTheme.Values.sectionGridSpacing
|
||||||
bottomPadding: 5
|
columns: root.numColumns
|
||||||
columns: root.width / root.cellWidth
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: texturesRepeater
|
id: texturesRepeater
|
||||||
@@ -782,10 +795,10 @@ Item {
|
|||||||
width: root.cellWidth
|
width: root.cellWidth
|
||||||
height: root.cellHeight
|
height: root.cellHeight
|
||||||
|
|
||||||
onShowContextMenu: {
|
onShowContextMenu: ctxMenuTextures.popupMenu(model)
|
||||||
ctxMenuTextures.popupMenu(model)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCountChanged: root.responsiveResize(root.width, root.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,32 +8,24 @@ import HelperWidgets 2.0
|
|||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme 1.0 as StudioTheme
|
||||||
import MaterialBrowserBackend
|
import MaterialBrowserBackend
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
signal showContextMenu()
|
signal showContextMenu()
|
||||||
|
|
||||||
function refreshPreview()
|
function refreshPreview() {
|
||||||
{
|
|
||||||
img.source = ""
|
img.source = ""
|
||||||
img.source = "image://materialBrowser/" + materialInternalId
|
img.source = "image://materialBrowser/" + materialInternalId
|
||||||
}
|
}
|
||||||
|
|
||||||
function forceFinishEditing()
|
function forceFinishEditing() {
|
||||||
{
|
|
||||||
matName.commitRename()
|
matName.commitRename()
|
||||||
}
|
}
|
||||||
|
|
||||||
function startRename()
|
function startRename() {
|
||||||
{
|
|
||||||
matName.startRename()
|
matName.startRename()
|
||||||
}
|
}
|
||||||
|
|
||||||
border.width: MaterialBrowserBackend.materialBrowserModel.selectedIndex === index ? MaterialBrowserBackend.rootView.materialSectionFocused ? 3 : 1 : 0
|
|
||||||
border.color: MaterialBrowserBackend.materialBrowserModel.selectedIndex === index
|
|
||||||
? StudioTheme.Values.themeControlOutlineInteraction
|
|
||||||
: "transparent"
|
|
||||||
color: "transparent"
|
|
||||||
visible: materialVisible
|
visible: materialVisible
|
||||||
|
|
||||||
DropArea {
|
DropArea {
|
||||||
@@ -81,12 +73,10 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 1
|
spacing: 1
|
||||||
|
|
||||||
Item { width: 1; height: 5 } // spacer
|
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: img
|
id: img
|
||||||
|
|
||||||
width: root.width - 10
|
width: root.width
|
||||||
height: img.width
|
height: img.width
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
source: "image://materialBrowser/" + materialInternalId
|
source: "image://materialBrowser/" + materialInternalId
|
||||||
@@ -94,8 +84,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Eat keys so they are not passed to parent while editing name
|
// Eat keys so they are not passed to parent while editing name
|
||||||
Keys.onPressed: (e) => {
|
Keys.onPressed: (event) => {
|
||||||
e.accepted = true;
|
event.accepted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialBrowserItemName {
|
MaterialBrowserItemName {
|
||||||
@@ -116,4 +106,14 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: marker
|
||||||
|
anchors.fill: parent
|
||||||
|
border.width: MaterialBrowserBackend.materialBrowserModel.selectedIndex === index ? MaterialBrowserBackend.rootView.materialSectionFocused ? 3 : 1 : 0
|
||||||
|
border.color: MaterialBrowserBackend.materialBrowserModel.selectedIndex === index
|
||||||
|
? StudioTheme.Values.themeControlOutlineInteraction
|
||||||
|
: "transparent"
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,22 +9,14 @@ import HelperWidgets
|
|||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
import MaterialBrowserBackend
|
import MaterialBrowserBackend
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
visible: textureVisible
|
visible: textureVisible
|
||||||
|
|
||||||
color: "transparent"
|
|
||||||
border.width: MaterialBrowserBackend.materialBrowserTexturesModel.selectedIndex === index
|
|
||||||
? !MaterialBrowserBackend.rootView.materialSectionFocused ? 3 : 1 : 0
|
|
||||||
border.color: MaterialBrowserBackend.materialBrowserTexturesModel.selectedIndex === index
|
|
||||||
? StudioTheme.Values.themeControlOutlineInteraction
|
|
||||||
: "transparent"
|
|
||||||
|
|
||||||
signal showContextMenu()
|
signal showContextMenu()
|
||||||
|
|
||||||
function forceFinishEditing()
|
function forceFinishEditing() {
|
||||||
{
|
|
||||||
txtId.commitRename()
|
txtId.commitRename()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +60,11 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 1
|
spacing: 1
|
||||||
|
|
||||||
Item { width: 1; height: 5 } // spacer
|
|
||||||
Image {
|
Image {
|
||||||
id: img
|
id: img
|
||||||
source: "image://materialBrowserTex/" + textureSource
|
source: "image://materialBrowserTex/" + textureSource
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
width: root.width - 10
|
width: root.width
|
||||||
height: img.width
|
height: img.width
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
smooth: true
|
smooth: true
|
||||||
@@ -81,8 +72,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Eat keys so they are not passed to parent while editing name
|
// Eat keys so they are not passed to parent while editing name
|
||||||
Keys.onPressed: (e) => {
|
Keys.onPressed: (event) => {
|
||||||
e.accepted = true;
|
event.accepted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialBrowserItemName {
|
MaterialBrowserItemName {
|
||||||
@@ -103,4 +94,16 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: marker
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
border.width: MaterialBrowserBackend.materialBrowserTexturesModel.selectedIndex === index
|
||||||
|
? !MaterialBrowserBackend.rootView.materialSectionFocused ? 3 : 1 : 0
|
||||||
|
border.color: MaterialBrowserBackend.materialBrowserTexturesModel.selectedIndex === index
|
||||||
|
? StudioTheme.Values.themeControlOutlineInteraction
|
||||||
|
: "transparent"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
import QtQuick.Window 2.15
|
|
||||||
|
|
||||||
Window {
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import QtQuick 2.15
|
|
||||||
|
|
||||||
Window {
|
|
||||||
}
|
|
||||||
@@ -20,6 +20,21 @@ Section {
|
|||||||
// TODO position property, what should be the range?!
|
// TODO position property, what should be the range?!
|
||||||
|
|
||||||
SectionLayout {
|
SectionLayout {
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Source")
|
||||||
|
tooltip: qsTr("Adds an image from the local file system.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
UrlChooser {
|
||||||
|
backendValue: backendValues.source
|
||||||
|
filter: "*.avi *.mp4 *.mpeg *.wav"
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
PropertyLabel { text: qsTr("Playback rate") }
|
PropertyLabel { text: qsTr("Playback rate") }
|
||||||
|
|
||||||
SecondColumnLayout {
|
SecondColumnLayout {
|
||||||
|
|||||||
@@ -0,0 +1,364 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import HelperWidgets
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
Section {
|
||||||
|
caption: qsTr("Animated Sprite")
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
SectionLayout {
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Source")
|
||||||
|
tooltip: qsTr("Adds an image from the local file system.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
UrlChooser {
|
||||||
|
backendValue: backendValues.source
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Frame size")
|
||||||
|
tooltip: qsTr("Sets the width and height of the frame.")
|
||||||
|
blockedByTemplate: !(backendValues.frameWidth.isAvailable || backendValues.frameHeight.isAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameWidth
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 8192
|
||||||
|
decimals: 0
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
//: The width of the animated sprite frame
|
||||||
|
text: qsTr("W", "width")
|
||||||
|
tooltip: qsTr("Width.")
|
||||||
|
enabled: backendValues.frameWidth.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameHeight
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 8192
|
||||||
|
decimals: 0
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
//: The height of the animated sprite frame
|
||||||
|
text: qsTr("H", "height")
|
||||||
|
tooltip: qsTr("Height.")
|
||||||
|
enabled: backendValues.frameHeight.isAvailable
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
TODO QDS-4836
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
LinkIndicator2D {}
|
||||||
|
*/
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Frame coordinates")
|
||||||
|
tooltip: qsTr("Sets the coordinates of the first frame of the animated sprite.")
|
||||||
|
blockedByTemplate: !(backendValues.frameX.isAvailable || backendValues.frameY.isAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameX
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 8192
|
||||||
|
decimals: 0
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
//: The width of the animated sprite frame
|
||||||
|
text: qsTr("X", "Frame X")
|
||||||
|
tooltip: qsTr("Frame X coordinate.")
|
||||||
|
enabled: backendValues.frameX.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameY
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 8192
|
||||||
|
decimals: 0
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
//: The height of the animated sprite frame
|
||||||
|
text: qsTr("Y", "Frame Y")
|
||||||
|
tooltip: qsTr("Frame Y coordinate.")
|
||||||
|
enabled: backendValues.frameY.isAvailable
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
TODO QDS-4836
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
LinkIndicator2D {}
|
||||||
|
*/
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Frame count")
|
||||||
|
tooltip: qsTr("Sets the number of frames in this animated sprite.")
|
||||||
|
blockedByTemplate: !backendValues.frameCount.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameCount
|
||||||
|
decimals: 0
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 10000
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//frame rate OR frame duration OR frame sync should be used
|
||||||
|
//frame rate has priority over frame duration
|
||||||
|
//frame sync has priority over rate and duration
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Frame rate")
|
||||||
|
tooltip: qsTr("Sets the number of frames per second to show in the animation.")
|
||||||
|
blockedByTemplate: !backendValues.frameRate.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameRate
|
||||||
|
decimals: 2
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 1000
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//frame duration OR frame rate OR frame sync should be used
|
||||||
|
//frame rate has priority over frame duration
|
||||||
|
//frame sync has priority over rate and duration
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Frame duration")
|
||||||
|
tooltip: qsTr("Sets the duration of each frame of the animation in milliseconds.")
|
||||||
|
blockedByTemplate: !backendValues.frameDuration.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameDuration
|
||||||
|
decimals: 0
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 100000
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//frame sync OR frame rate OR frame duration should be used
|
||||||
|
//frame rate has priority over frame duration
|
||||||
|
//frame sync has priority over rate and duration
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Frame sync")
|
||||||
|
tooltip: qsTr("Sets frame advancements one frame each time a frame is rendered to the screen.")
|
||||||
|
blockedByTemplate: !backendValues.frameSync.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.frameSync.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.frameSync
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Loops")
|
||||||
|
tooltip: qsTr("After playing the animation this many times, the animation will automatically stop.")
|
||||||
|
blockedByTemplate: !backendValues.loops.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.loops
|
||||||
|
decimals: 0
|
||||||
|
minimumValue: -1 //AnimatedSprite.Infinite = -1
|
||||||
|
maximumValue: 100000
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Interpolate")
|
||||||
|
tooltip: qsTr("If true, interpolation will occur between sprite frames to make the animation appear smoother.")
|
||||||
|
blockedByTemplate: !backendValues.interpolate.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.interpolate.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.interpolate
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Finish behavior")
|
||||||
|
tooltip: qsTr("Sets the behavior when the animation finishes on its own.")
|
||||||
|
blockedByTemplate: !backendValues.finishBehavior.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
ComboBox {
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
width: implicitWidth
|
||||||
|
scope: "AnimatedSprite"
|
||||||
|
model: ["FinishAtInitialFrame", "FinishAtFinalFrame"]
|
||||||
|
backendValue: backendValues.finishBehavior
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Reverse")
|
||||||
|
tooltip: qsTr("If true, the animation will be played in reverse.")
|
||||||
|
blockedByTemplate: !backendValues.reverse.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.reverse.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.reverse
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Running")
|
||||||
|
tooltip: qsTr("Whether the sprite is animating or not.")
|
||||||
|
blockedByTemplate: !backendValues.running.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.running.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.running
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Paused")
|
||||||
|
tooltip: qsTr("When paused, the current frame can be advanced manually.")
|
||||||
|
blockedByTemplate: !backendValues.paused.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.paused.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.paused
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Current frame")
|
||||||
|
tooltip: qsTr("When paused, the current frame can be advanced manually by setting this property.")
|
||||||
|
blockedByTemplate: !backendValues.currentFrame.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.currentFrame
|
||||||
|
decimals: 0
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 100000
|
||||||
|
enabled: backendValue.isAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,11 @@ PropertyEditorPane {
|
|||||||
|
|
||||||
ComponentSection {}
|
ComponentSection {}
|
||||||
|
|
||||||
|
DynamicPropertiesSection {
|
||||||
|
propertiesModel: SelectionDynamicPropertiesModel {}
|
||||||
|
visible: !hasMultiSelection
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
// 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 2.15
|
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick
|
||||||
import QtQuick.Shapes 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Templates 2.15 as T
|
import QtQuick.Shapes
|
||||||
import QtQuickDesignerTheme 1.0
|
import QtQuick.Templates as T
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
import StudioControls 1.0 as StudioControls
|
import StudioControls as StudioControls
|
||||||
import QtQuickDesignerColorPalette 1.0
|
import QtQuickDesignerTheme
|
||||||
|
import QtQuickDesignerColorPalette
|
||||||
|
|
||||||
SecondColumnLayout {
|
SecondColumnLayout {
|
||||||
id: colorEditor
|
id: colorEditor
|
||||||
@@ -29,7 +30,7 @@ SecondColumnLayout {
|
|||||||
return colorEditor.backendValue.value
|
return colorEditor.backendValue.value
|
||||||
}
|
}
|
||||||
|
|
||||||
property alias gradientPropertyName: popupLoader.gradientPropertyName
|
property alias gradientPropertyName: popupDialog.gradientPropertyName
|
||||||
|
|
||||||
property alias gradientThumbnail: gradientThumbnail
|
property alias gradientThumbnail: gradientThumbnail
|
||||||
property alias shapeGradientThumbnail: shapeGradientThumbnail
|
property alias shapeGradientThumbnail: shapeGradientThumbnail
|
||||||
@@ -66,12 +67,12 @@ SecondColumnLayout {
|
|||||||
target: colorEditor
|
target: colorEditor
|
||||||
|
|
||||||
function onValueChanged() {
|
function onValueChanged() {
|
||||||
if (popupLoader.isNotInGradientMode())
|
if (popupDialog.isSolid())
|
||||||
colorEditor.syncColor()
|
colorEditor.syncColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBackendValueChanged() {
|
function onBackendValueChanged() {
|
||||||
if (popupLoader.isNotInGradientMode())
|
if (popupDialog.isSolid())
|
||||||
colorEditor.syncColor()
|
colorEditor.syncColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,13 +102,13 @@ SecondColumnLayout {
|
|||||||
if (colorEditor.__block)
|
if (colorEditor.__block)
|
||||||
return
|
return
|
||||||
|
|
||||||
if (!popupLoader.isInValidState)
|
if (!popupDialog.isInValidState)
|
||||||
return
|
return
|
||||||
|
|
||||||
popupLoader.commitToGradient()
|
popupDialog.commitToGradient()
|
||||||
|
|
||||||
// Delay setting the color to keep ui responsive
|
// Delay setting the color to keep ui responsive
|
||||||
if (popupLoader.isNotInGradientMode())
|
if (popupDialog.isSolid())
|
||||||
colorEditorTimer.restart()
|
colorEditorTimer.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,17 +128,16 @@ SecondColumnLayout {
|
|||||||
id: gradientThumbnail
|
id: gradientThumbnail
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: StudioTheme.Values.border
|
anchors.margins: StudioTheme.Values.border
|
||||||
visible: !popupLoader.isNotInGradientMode()
|
visible: !popupDialog.isSolid()
|
||||||
&& !colorEditor.shapeGradients
|
&& !colorEditor.shapeGradients
|
||||||
&& popupLoader.hasLinearGradient()
|
&& popupDialog.isLinearGradient()
|
||||||
}
|
}
|
||||||
|
|
||||||
Shape {
|
Shape {
|
||||||
id: shape
|
id: shape
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: StudioTheme.Values.border
|
anchors.margins: StudioTheme.Values.border
|
||||||
visible: !popupLoader.isNotInGradientMode()
|
visible: !popupDialog.isSolid() && colorEditor.shapeGradients
|
||||||
&& colorEditor.shapeGradients
|
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: shapeGradientThumbnail
|
id: shapeGradientThumbnail
|
||||||
@@ -171,78 +171,77 @@ SecondColumnLayout {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
popupLoader.opened ? popupLoader.close() : popupLoader.open()
|
popupDialog.visibility ? popupDialog.close() : popupDialog.open()
|
||||||
forceActiveFocus()
|
forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
StudioControls.PopupDialog {
|
||||||
id: popupLoader
|
id: popupDialog
|
||||||
|
|
||||||
property bool isInValidState: popupLoader.active ? popupLoader.dialog.isInValidState : true
|
|
||||||
|
|
||||||
property QtObject dialog: popupLoader.loader.item
|
|
||||||
|
|
||||||
property bool opened: popupLoader.active ? popupLoader.dialog.opened : false
|
|
||||||
|
|
||||||
|
property bool isInValidState: loader.active ? popupDialog.loaderItem.isInValidState : true
|
||||||
|
property QtObject loaderItem: loader.item
|
||||||
property string gradientPropertyName
|
property string gradientPropertyName
|
||||||
|
|
||||||
|
width: 260
|
||||||
|
maximumHeight: Screen.desktopAvailableHeight * 0.7
|
||||||
|
|
||||||
function commitToGradient() {
|
function commitToGradient() {
|
||||||
if (!popupLoader.active)
|
if (!loader.active)
|
||||||
return
|
return
|
||||||
|
|
||||||
if (colorEditor.supportGradient && popupLoader.dialog.gradientModel.hasGradient) {
|
if (colorEditor.supportGradient && popupDialog.loaderItem.gradientModel.hasGradient) {
|
||||||
var hexColor = convertColorToString(colorEditor.color)
|
var hexColor = convertColorToString(colorEditor.color)
|
||||||
hexTextField.text = hexColor
|
hexTextField.text = hexColor
|
||||||
popupLoader.dialog.commitGradientColor()
|
popupDialog.loaderItem.commitGradientColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNotInGradientMode() {
|
function isSolid() {
|
||||||
if (!popupLoader.active)
|
if (!loader.active)
|
||||||
return true
|
return true
|
||||||
return popupLoader.dialog.isNotInGradientMode()
|
|
||||||
|
return popupDialog.loaderItem.isSolid()
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasLinearGradient(){
|
function isLinearGradient(){
|
||||||
if (!popupLoader.active)
|
if (!loader.active)
|
||||||
return false
|
return false
|
||||||
return popupLoader.dialog.hasLinearGradient()
|
|
||||||
|
return popupDialog.loaderItem.isLinearGradient()
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureLoader() {
|
function ensureLoader() {
|
||||||
if (!popupLoader.active)
|
if (!loader.active)
|
||||||
popupLoader.active = true
|
loader.active = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function open() {
|
function open() {
|
||||||
popupLoader.ensureLoader()
|
popupDialog.ensureLoader()
|
||||||
popupLoader.dialog.open()
|
popupDialog.show(preview)
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
popupLoader.ensureLoader()
|
|
||||||
popupLoader.dialog.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function determineActiveColorMode() {
|
function determineActiveColorMode() {
|
||||||
if (popupLoader.active && popupLoader.dialog)
|
if (loader.active && popupDialog.loaderItem)
|
||||||
popupLoader.dialog.determineActiveColorMode()
|
popupDialog.loaderItem.determineActiveColorMode()
|
||||||
else
|
else
|
||||||
colorEditor.syncColor()
|
colorEditor.syncColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
property alias active: popupLoader.loader.active
|
Loader {
|
||||||
property Loader loader: Loader {
|
id: loader
|
||||||
parent: preview
|
|
||||||
active: colorEditor.supportGradient
|
active: colorEditor.supportGradient
|
||||||
|
|
||||||
sourceComponent: ColorEditorPopup {
|
sourceComponent: ColorEditorPopup {
|
||||||
id: cePopup
|
shapeGradients: colorEditor.shapeGradients
|
||||||
x: cePopup.__defaultX
|
supportGradient: colorEditor.supportGradient
|
||||||
y: cePopup.__defaultY
|
width: popupDialog.contentWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
popupDialog.loaderItem.initEditor()
|
||||||
|
popupDialog.titleBar = loader.item.titleBarContent
|
||||||
}
|
}
|
||||||
onLoaded: popupLoader.dialog.initEditor()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,19 +254,26 @@ SecondColumnLayout {
|
|||||||
id: hexTextField
|
id: hexTextField
|
||||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
+ StudioTheme.Values.actionIndicatorWidth
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
width: implicitWidth
|
width: hexTextField.implicitWidth
|
||||||
enabled: popupLoader.isNotInGradientMode()
|
enabled: popupDialog.isSolid()
|
||||||
writeValueManually: true
|
writeValueManually: true
|
||||||
validator: RegExpValidator {
|
validator: RegularExpressionValidator {
|
||||||
regExp: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g
|
regularExpression: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g
|
||||||
}
|
}
|
||||||
showTranslateCheckBox: false
|
showTranslateCheckBox: false
|
||||||
|
indicatorVisible: true
|
||||||
|
indicator.icon.text: StudioTheme.Constants.copy_small
|
||||||
|
indicator.onClicked: {
|
||||||
|
hexTextField.selectAll()
|
||||||
|
hexTextField.copy()
|
||||||
|
hexTextField.deselect()
|
||||||
|
}
|
||||||
backendValue: colorEditor.backendValue
|
backendValue: colorEditor.backendValue
|
||||||
|
|
||||||
onAccepted: colorEditor.color = colorFromString(hexTextField.text)
|
onAccepted: colorEditor.color = colorFromString(hexTextField.text)
|
||||||
onCommitData: {
|
onCommitData: {
|
||||||
colorEditor.color = colorFromString(hexTextField.text)
|
colorEditor.color = colorFromString(hexTextField.text)
|
||||||
if (popupLoader.isNotInGradientMode()) {
|
if (popupDialog.isSolid()) {
|
||||||
if (colorEditor.isVector3D) {
|
if (colorEditor.isVector3D) {
|
||||||
backendValue.value = Qt.vector3d(colorEditor.color.r,
|
backendValue.value = Qt.vector3d(colorEditor.color.r,
|
||||||
colorEditor.color.g,
|
colorEditor.color.g,
|
||||||
@@ -283,9 +289,7 @@ SecondColumnLayout {
|
|||||||
id: spacer
|
id: spacer
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: popupLoader.determineActiveColorMode()
|
Component.onCompleted: popupDialog.determineActiveColorMode()
|
||||||
|
|
||||||
onBackendValueChanged: {
|
onBackendValueChanged: popupDialog.determineActiveColorMode()
|
||||||
popupLoader.determineActiveColorMode()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// Copyright (C) 2021 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick 2.15
|
|
||||||
import HelperWidgets 2.0
|
|
||||||
import StudioTheme 1.0 as StudioTheme
|
|
||||||
|
|
||||||
Item {
|
|
||||||
property alias currentColor: colorLine.color
|
|
||||||
|
|
||||||
width: 300
|
|
||||||
height: StudioTheme.Values.colorEditorPopupLineHeight
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: checkerboard
|
|
||||||
anchors.fill: colorLine
|
|
||||||
source: "images/checkers.png"
|
|
||||||
fillMode: Image.Tile
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: colorLine
|
|
||||||
height: StudioTheme.Values.hueSliderHeight
|
|
||||||
width: parent.width
|
|
||||||
border.color: StudioTheme.Values.themeControlOutline
|
|
||||||
border.width: StudioTheme.Values.border
|
|
||||||
color: "white"
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
}
|
|
||||||
}
|
|
||||||