diff options
author | Kaj Grönholm <kaj.gronholm@qt.io> | 2022-11-11 15:39:29 +0200 |
---|---|---|
committer | Kaj Grönholm <kaj.gronholm@qt.io> | 2022-12-07 08:31:43 +0200 |
commit | fc0d46971869e88c3ff82f090c57fb888e9787f5 (patch) | |
tree | 76f10f132fd05c4ac881471b08bf72b101304d38 /examples/quick | |
parent | 84d3c382f808d70c418a9c220cff6fee06f5639a (diff) |
Add QtQuick.Effects & MultiEffect
Add new QtQuick.Effects plugin for post-processing effects.
The plan is to add essential effects directly into QtQuick,
not to duplicate Qt Graphical Effects.
Initially the plugin will contain MultiEffect which supports
7 different effects in a single ShaderEffect (brightness,
contrast, saturation, colorize, blur, shadow, mask). Combining
multiple effects into a single shader is more performant than
chaining multiple effect items. Depending on used features,
the most optimal shader gets selected.
Includes two examples demonstrating the usage of MultiEffect.
Task-number: QTBUG-106651
Change-Id: I35865030fd4b7a1f657146cee03b195451545bc6
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Diffstat (limited to 'examples/quick')
56 files changed, 2714 insertions, 1 deletions
diff --git a/examples/quick/CMakeLists.txt b/examples/quick/CMakeLists.txt index d9cdeb617f..f063585486 100644 --- a/examples/quick/CMakeLists.txt +++ b/examples/quick/CMakeLists.txt @@ -30,6 +30,7 @@ add_subdirectory(particles) qt_internal_add_example(delegatechooser) qt_internal_add_example(shapes) qt_internal_add_example(itemvariablerefreshrate) +add_subdirectory(multieffect) if(QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3) add_subdirectory(rendercontrol) endif() @@ -62,6 +63,8 @@ set(reused_dir_targets itemparticle_shared system_shared draganddrop_shared + testbed_shared + itemswitcher_shared ) foreach(target IN LISTS reused_dir_targets) diff --git a/examples/quick/multieffect/CMakeLists.txt b/examples/quick/multieffect/CMakeLists.txt new file mode 100644 index 0000000000..7462337905 --- /dev/null +++ b/examples/quick/multieffect/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_example(itemswitcher) +qt_internal_add_example(testbed) diff --git a/examples/quick/multieffect/itemswitcher/CMakeLists.txt b/examples/quick/multieffect/itemswitcher/CMakeLists.txt new file mode 100644 index 0000000000..17ccb243d6 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(itemswitcher LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/multieffect/itemswitcher") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick QuickControls2) + +add_subdirectory("../../shared" "shared") + +qt_add_executable(itemswitcherexample WIN32 MACOSX_BUNDLE + main.cpp +) + +target_link_libraries(itemswitcherexample PRIVATE + Qt::Core + Qt::Gui + Qt::Qml + Qt::Quick + Qt::QuickControls2 +) + +add_dependencies(itemswitcherexample itemswitcher_shared) + +# Resources: +qt_add_qml_module(itemswitcherexample + URI itemswitcher + VERSION 1.0 + AUTO_RESOURCE_PREFIX + QML_FILES + "qml/main.qml" + "qml/PagesView.qml" + "qml/SwitchEffect3DFlip.qml" + "qml/SwitchEffectBlur.qml" + "qml/SwitchEffectStars.qml" + "qml/ItemSwitcher.qml" + "qml/PagesItem.qml" + "qml/SettingsView.qml" + "qml/SwitchEffectBlinds.qml" + "qml/SwitchEffectHeart.qml" + "qml/SwitchEffectThunder.qml" + "qml/SettingsComponentButton.qml" + "qml/SettingsComponentSlider.qml" + RESOURCES + "qml/images/background.png" + "qml/images/hblinds.png" + "qml/images/heart.png" + "qml/images/quit_coding.png" + "qml/images/smoke.png" + "qml/images/star.png" + "qml/images/stripes.png" + "qml/images/arrow.png" + "qml/images/Built_with_Qt.png" + "qml/images/Built_with_Qt_RGB_logo.png" +) + +install(TARGETS itemswitcherexample + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) + +bundle_shared(itemswitcherexample) diff --git a/examples/quick/multieffect/itemswitcher/itemswitcher.pro b/examples/quick/multieffect/itemswitcher/itemswitcher.pro new file mode 100644 index 0000000000..f1ab3e381b --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/itemswitcher.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +QT += quick qml +QT += quickcontrols2 +SOURCES += main.cpp +RESOURCES += \ + qml.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/multieffect/itemswitcher +INSTALLS += target diff --git a/examples/quick/multieffect/itemswitcher/main.cpp b/examples/quick/multieffect/itemswitcher/main.cpp new file mode 100644 index 0000000000..a7d7046411 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/main.cpp @@ -0,0 +1,4 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include "../../shared/shared.h" +DECLARATIVE_EXAMPLE_MAIN(itemswitcher/qml/main) diff --git a/examples/quick/multieffect/itemswitcher/qml.qrc b/examples/quick/multieffect/itemswitcher/qml.qrc new file mode 100644 index 0000000000..3ccc23502a --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml.qrc @@ -0,0 +1,27 @@ +<RCC> + <qresource prefix="/qt/qml/itemswitcher"> + <file>qml/ItemSwitcher.qml</file> + <file>qml/main.qml</file> + <file>qml/SwitchEffectBlur.qml</file> + <file>qml/SwitchEffectBlinds.qml</file> + <file>qml/images/hblinds.png</file> + <file>qml/SwitchEffectHeart.qml</file> + <file>qml/images/heart.png</file> + <file>qml/SwitchEffectStars.qml</file> + <file>qml/images/star.png</file> + <file>qml/PagesView.qml</file> + <file>qml/PagesItem.qml</file> + <file>qml/SwitchEffectThunder.qml</file> + <file>qml/images/stripes.png</file> + <file>qml/images/background.png</file> + <file>qml/SettingsView.qml</file> + <file>qml/images/quit_coding.png</file> + <file>qml/images/smoke.png</file> + <file>qml/SwitchEffect3DFlip.qml</file> + <file>qml/SettingsComponentButton.qml</file> + <file>qml/SettingsComponentSlider.qml</file> + <file>qml/images/arrow.png</file> + <file>qml/images/Built_with_Qt.png</file> + <file>qml/images/Built_with_Qt_RGB_logo.png</file> + </qresource> +</RCC> diff --git a/examples/quick/multieffect/itemswitcher/qml/ItemSwitcher.qml b/examples/quick/multieffect/itemswitcher/qml/ItemSwitcher.qml new file mode 100644 index 0000000000..eb405749be --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/ItemSwitcher.qml @@ -0,0 +1,57 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + + property var sourceItems: [] + + property Item fromItem + property Item toItem + + property var effect + + property int currentIndex: 0 + property int previousIndex: 0 + property real inAnimation: 0 + readonly property real outAnimation: 1.0 - inAnimation + // Duration of switch animation, in ms + property int duration: 1500 + + property bool _initialized: false + + onCurrentIndexChanged: { + fromItem = sourceItems[previousIndex]; + toItem = sourceItems[currentIndex]; + if (_initialized) + switchAnimation.restart(); + previousIndex = currentIndex; + } + + // Initialize the items and currentIndex + Timer { + running: true + interval: 0 + onTriggered: { + fromItem = sourceItems[previousIndex]; + toItem = sourceItems[currentIndex]; + previousIndex = currentIndex; + _initialized = true; + } + } + + SequentialAnimation { + id: switchAnimation + alwaysRunToEnd: true + NumberAnimation { + target: rootItem + property: "inAnimation" + from: 0 + to: 1 + duration: rootItem.duration + easing.type: Easing.InOutQuad + } + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/PagesItem.qml b/examples/quick/multieffect/itemswitcher/qml/PagesItem.qml new file mode 100644 index 0000000000..87b39d4947 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/PagesItem.qml @@ -0,0 +1,49 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + + property Item source + property bool selected: false + property string text + + signal clicked + + Rectangle { + anchors.fill: parent + color: "#000000" + border.color: "#f0f0f0" + opacity: rootItem.selected ? 0.4 : 0 + Behavior on opacity { + NumberAnimation { + duration: 400 + easing.type: Easing.InOutQuad + } + } + } + + ShaderEffectSource { + anchors.fill: parent + anchors.margins: 10 + sourceItem: rootItem.source + smooth: true + mipmap: true + } + Text { + anchors.centerIn: parent + visible: rootItem.text != "" + text: rootItem.text + font.pixelSize: 14 * dp + color: "#ffffff" + } + + MouseArea { + anchors.fill: parent + onClicked: { + rootItem.clicked(); + } + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/PagesView.qml b/examples/quick/multieffect/itemswitcher/qml/PagesView.qml new file mode 100644 index 0000000000..b6e5c45a94 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/PagesView.qml @@ -0,0 +1,30 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + + property real itemSize: 120 * dp + property real margin: 10 * dp + + default property alias contents: contentItem.children + + width: contentItem.width + 2 * margin + height: itemSize + 2 * margin + + Rectangle { + anchors.fill: parent + color: "#606060" + border.color: "#f0f0f0" + border.width: 1 + opacity: 0.4 + } + Row { + id: contentItem + x: margin + y: margin + spacing: margin + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SettingsComponentButton.qml b/examples/quick/multieffect/itemswitcher/qml/SettingsComponentButton.qml new file mode 100644 index 0000000000..26a0085d8a --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SettingsComponentButton.qml @@ -0,0 +1,35 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + + property alias text: textItem.text + property bool selected: false + + signal clicked + + width: parent.width + height: 40 * dp + Rectangle { + anchors.fill: parent + color: "#606060" + border.color: "#d0d0d0" + border.width: 1 + opacity: selected ? 0.8 : 0.4 + } + Text { + id: textItem + anchors.centerIn: parent + font.pixelSize: 16 * dp + color: "#f0f0f0" + } + MouseArea { + anchors.fill: parent + onClicked: { + rootItem.clicked(); + } + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SettingsComponentSlider.qml b/examples/quick/multieffect/itemswitcher/qml/SettingsComponentSlider.qml new file mode 100644 index 0000000000..ed04584e44 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SettingsComponentSlider.qml @@ -0,0 +1,54 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material + +Column { + id: rootItem + + property alias text: textItem.text + property alias value: slider.value + property alias from: slider.from + property alias to: slider.to + property alias checked: checkBox.checked + property alias stepSize: slider.stepSize + property bool showCheckbox: false + + signal toggled + signal moved + + Material.theme: Material.Dark + Material.accent: Material.LightGreen + spacing: -12 + + Text { + id: textItem + anchors.horizontalCenter: parent.horizontalCenter + color: "#f0f0f0" + font.pixelSize: 14 * dp + } + + Row { + CheckBox { + id: checkBox + visible: rootItem.showCheckbox + checked: true + onToggled: { + rootItem.toggled(); + } + } + Slider { + id: slider + property real sliderWidth: settings.settingsViewWidth - 50 + width: rootItem.showCheckbox ? sliderWidth : sliderWidth + checkBox.width + value: 50 + from: 0 + to: 800 + onMoved: { + rootItem.moved(); + } + } + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SettingsView.qml b/examples/quick/multieffect/itemswitcher/qml/SettingsView.qml new file mode 100644 index 0000000000..cf1a753b4d --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SettingsView.qml @@ -0,0 +1,168 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls.Material + +Item { + id: rootItem + + property bool show: true + property real showAnimation: show ? 1 : 0 + + Material.theme: Material.Dark + Material.accent: Material.LightGreen + width: settings.settingsViewWidth + x: -(width + 30) * (1 - showAnimation) + 20 + + Behavior on showAnimation { + NumberAnimation { + duration: 400 + easing.type: Easing.InOutQuad + } + } + + // Open/close button + Item { + width: 30 * dp + height: 30 * dp + anchors.left: parent.right + anchors.leftMargin: 20 + anchors.top: parent.top + anchors.topMargin: -10 + Rectangle { + anchors.fill: parent + color: "#404040" + opacity: 0.4 + border.width: 1 + border.color: "#808080" + } + + Image { + anchors.centerIn: parent + source: "images/arrow.png" + rotation: rootItem.showAnimation * 180 + } + MouseArea { + anchors.fill: parent + anchors.margins: -30 * dp + onClicked: { + rootItem.show = !rootItem.show; + } + } + } + + // Background + Rectangle { + anchors.fill: scrollView + opacity: showAnimation ? 0.6 : 0 + visible: opacity + anchors.margins: -10 + color: "#202020" + border.color: "#808080" + border.width: 1 + } + + ScrollView { + id: scrollView + anchors.fill: parent + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.interactive: false + clip: true + Column { + id: settingsArea + width: rootItem.width + opacity: showAnimation + visible: opacity + spacing: 8 * dp + + Item { + width: 1 + height: 20 * dp + } + Image { + anchors.horizontalCenter: parent.horizontalCenter + fillMode: Image.PreserveAspectFit + width: parent.width * 0.8 + height: width * 0.25 + source: "images/Built_with_Qt_RGB_logo.png" + } + Item { + width: 1 + height: 28 * dp + } + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Switching Effects") + font.pixelSize: 20 * dp + font.bold: true + color: "#f0f0f0" + } + SettingsComponentButton { + text: "Blinds" + selected: settings.effectIndex === 0 + onClicked: { + settings.effectIndex = 0; + } + } + SettingsComponentButton { + text: "Blurry" + selected: settings.effectIndex === 1 + onClicked: { + settings.effectIndex = 1; + } + } + SettingsComponentButton { + text: "Heart" + selected: settings.effectIndex === 2 + onClicked: { + settings.effectIndex = 2; + } + } + SettingsComponentButton { + text: "Stars" + selected: settings.effectIndex === 3 + onClicked: { + settings.effectIndex = 3; + } + } + SettingsComponentButton { + text: "Thunder" + selected: settings.effectIndex === 4 + onClicked: { + settings.effectIndex = 4; + } + } + SettingsComponentButton { + text: "3D Flip" + selected: settings.effectIndex === 5 + onClicked: { + settings.effectIndex = 5; + } + } + Item { + width: 1 + height: 10 + } + + SettingsComponentSlider { + text: qsTr("Animation Duration") + ": " + value.toFixed(0) + " ms" + value: settings.switchDuration + from: 500 + to: 5000 + onMoved: { + settings.switchDuration = value; + } + } + SettingsComponentSlider { + text: qsTr("Animation Time") + ": " + (value * settings.switchDuration).toFixed(0) + " ms" + value: itemSwitcher.inAnimation + from: 0 + to: 1 + onMoved: { + itemSwitcher.inAnimation = value; + } + } + } + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SwitchEffect3DFlip.qml b/examples/quick/multieffect/itemswitcher/qml/SwitchEffect3DFlip.qml new file mode 100644 index 0000000000..ae8ec481fb --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SwitchEffect3DFlip.qml @@ -0,0 +1,93 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Effects + +Item { + id: rootItem + // We expect all effects to be placed under ItemSwitcher + property Item switcher: rootItem.parent + + anchors.fill: parent + + MultiEffect { + source: switcher.fromItem + width: parent.width + height: parent.height + x: switcher.inAnimation * rootItem.width + blurEnabled: true + blur: switcher.inAnimation + blurMax: 32 + blurMultiplier: 1.0 + opacity: switcher.outAnimation + + saturation: -switcher.inAnimation * 1.5 + + maskEnabled: true + maskSource: Image { + source: "images/smoke.png" + visible: false + } + maskThresholdLow: switcher.inAnimation * 0.6 + maskSpreadLow: 0.1 + maskThresholdUp: 1.0 - (switcher.inAnimation * 0.6) + maskSpreadUp: 0.1 + + shadowEnabled: true + shadowOpacity: 0.5 + shadowBlur: 0.8 + shadowVerticalOffset: 5 + shadowHorizontalOffset: 10 + (x * 0.2) + shadowScale: 1.02 + + transform: Rotation { + origin.x: parent.width / 2 + origin.y: parent.height / 2 + axis { x: 0; y: 1; z: 0 } + angle: switcher.inAnimation * 60 + } + rotation: -switcher.inAnimation * 20 + scale: 1.0 + (switcher.inAnimation * 0.2) + } + + MultiEffect { + source: switcher.toItem + width: parent.width + height: parent.height + x: -switcher.outAnimation * rootItem.width + blurEnabled: true + blur: switcher.outAnimation * 2 + blurMax: 32 + blurMultiplier: 1.0 + opacity: switcher.inAnimation + + saturation: -switcher.outAnimation * 1.5 + + maskEnabled: true + maskSource: Image { + source: "images/smoke.png" + visible: false + } + maskThresholdLow: switcher.outAnimation * 0.6 + maskSpreadLow: 0.1 + maskThresholdUp: 1.0 - (switcher.outAnimation * 0.6) + maskSpreadUp: 0.1 + + shadowEnabled: true + shadowOpacity: 0.5 + shadowBlur: 0.8 + shadowVerticalOffset: 5 + shadowHorizontalOffset: 10 + (x * 0.2) + shadowScale: 1.02 + + transform: Rotation { + origin.x: parent.width / 2 + origin.y: parent.height / 2 + axis { x: 0; y: 1; z: 0 } + angle: -switcher.outAnimation * 60 + } + rotation: switcher.outAnimation * 20 + scale: 1.0 - (switcher.outAnimation * 0.4) + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SwitchEffectBlinds.qml b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectBlinds.qml new file mode 100644 index 0000000000..3a9f22e3ad --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectBlinds.qml @@ -0,0 +1,49 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Effects + +Item { + id: rootItem + // We expect all effects to be placed under ItemSwitcher + property Item switcher: rootItem.parent + property real rotation: 0 + + anchors.fill: parent + + Item { + id: mask + anchors.fill: parent + layer.enabled: true + visible: false + smooth: false + clip: true + Image { + anchors.fill: parent + anchors.margins: -parent.width * 0.25 + source: "images/hblinds.png" + rotation: rootItem.rotation + smooth: false + } + } + + // Item going out + MultiEffect { + source: switcher.fromItem + anchors.fill: parent + maskEnabled: true + maskSource: mask + maskThresholdLow: switcher.inAnimation + maskSpreadLow: 0.4 + } + // Item coming in + MultiEffect { + source: switcher.toItem + anchors.fill: parent + maskEnabled: true + maskSource: mask + maskThresholdUp: switcher.inAnimation + maskSpreadUp: 0.4 + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SwitchEffectBlur.qml b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectBlur.qml new file mode 100644 index 0000000000..9b48116226 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectBlur.qml @@ -0,0 +1,34 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Effects + +Item { + id: rootItem + // We expect all effects to be placed under ItemSwitcher + property Item switcher: rootItem.parent + + anchors.fill: parent + + MultiEffect { + source: switcher.fromItem + anchors.fill: parent + blurEnabled: true + blur: switcher.inAnimation * 4 + blurMax: 32 + blurMultiplier: 1.0 + opacity: switcher.outAnimation + saturation: -switcher.inAnimation * 2 + } + MultiEffect { + source: switcher.toItem + anchors.fill: parent + blurEnabled: true + blur: switcher.outAnimation * 4 + blurMax: 32 + blurMultiplier: 1.0 + opacity: switcher.inAnimation + saturation: -switcher.outAnimation * 2 + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SwitchEffectHeart.qml b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectHeart.qml new file mode 100644 index 0000000000..e81c648e2c --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectHeart.qml @@ -0,0 +1,48 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Effects + +Item { + id: rootItem + // We expect all effects to be placed under ItemSwitcher + property Item switcher: rootItem.parent + + anchors.fill: parent + + Item { + id: mask + anchors.fill: parent + layer.enabled: true + visible: false + clip: true + Image { + anchors.fill: parent + source: "images/heart.png" + scale: switcher.inAnimation * 3 + } + } + + // Item going out + MultiEffect { + source: switcher.fromItem + anchors.fill: parent + maskEnabled: true + maskSource: mask + maskInverted: true + maskThresholdLow: 0.5 + maskSpreadLow: 0.0 + } + // Item coming in + MultiEffect { + source: switcher.toItem + anchors.fill: parent + maskEnabled: true + maskSource: mask + maskThresholdLow: 0.5 + maskSpreadLow: 0.0 + colorizeColor: "red" + colorize: Math.max(0, 1.0 - switcher.inAnimation * 2) + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SwitchEffectStars.qml b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectStars.qml new file mode 100644 index 0000000000..47bdf3f64d --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectStars.qml @@ -0,0 +1,50 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Effects + +Item { + id: rootItem + // We expect all effects to be placed under ItemSwitcher + property Item switcher: rootItem.parent + + anchors.fill: parent + + Item { + id: mask + anchors.fill: parent + layer.enabled: true + visible: false + clip: true + Image { + anchors.fill: parent + source: "images/star.png" + scale: switcher.inAnimation * 5 + rotation: switcher.outAnimation * 360 + } + } + + // Item going out + MultiEffect { + source: switcher.fromItem + anchors.fill: parent + maskEnabled: true + maskSource: mask + maskInverted: true + maskThresholdLow: 0.5 + maskSpreadLow: 0.5 + } + // Item coming in + MultiEffect { + source: switcher.toItem + anchors.fill: parent + maskEnabled: true + maskSource: mask + maskThresholdLow: 0.5 + maskSpreadLow: 0.5 + colorizeColor: "#ffd020" + colorize: Math.max(0, 1.0 - switcher.inAnimation * 2) + brightness: Math.max(0.0, 0.8 - switcher.inAnimation * 2) + } +} diff --git a/examples/quick/multieffect/itemswitcher/qml/SwitchEffectThunder.qml b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectThunder.qml new file mode 100644 index 0000000000..581d001e26 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/SwitchEffectThunder.qml @@ -0,0 +1,87 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Effects + +Item { + id: rootItem + // We expect all effects to be placed under ItemSwitcher + property Item switcher: rootItem.parent + + property real _xPos: Math.sin(switcher.inAnimation * Math.PI * 50) * width * 0.03 * (0.5 - Math.abs(0.5 - switcher.inAnimation)) + property real _yPos: Math.sin(switcher.inAnimation * Math.PI * 35) * width * 0.02 * (0.5 - Math.abs(0.5 - switcher.inAnimation)) + + anchors.fill: parent + + Image { + id: maskImage + source: "images/stripes.png" + visible: false + } + + MultiEffect { + source: switcher.fromItem + width: parent.width + height: parent.height + x: rootItem._xPos + y: rootItem._yPos + blurEnabled: true + blur: switcher.inAnimation + blurMax: 32 + blurMultiplier: 1.0 + opacity: switcher.outAnimation + colorizeColor: "#f0d060" + colorize: switcher.inAnimation + + contrast: switcher.inAnimation + brightness: switcher.inAnimation + + maskEnabled: true + maskSource: maskImage + maskThresholdLow: switcher.inAnimation * 0.9 + maskSpreadLow: 0.2 + maskThresholdUp: 1.0 + + shadowEnabled: true + shadowColor: "#f04000" + shadowBlur: 1.0 + shadowOpacity: 5.0 - switcher.outAnimation * 5.0 + shadowHorizontalOffset: 0 + shadowVerticalOffset: 0 + shadowScale: 1.04 + + } + MultiEffect { + source: switcher.toItem + width: parent.width + height: parent.height + x: -rootItem._xPos + y: -rootItem._yPos + blurEnabled: true + blur: switcher.outAnimation * 2 + blurMax: 32 + blurMultiplier: 1.0 + opacity: switcher.inAnimation * 3.0 - 1.0 + + colorizeColor: "#f0d060" + colorize: switcher.outAnimation + contrast: switcher.outAnimation + brightness: switcher.outAnimation + + maskEnabled: true + maskSource: maskImage + maskThresholdLow: switcher.outAnimation * 0.6 + maskSpreadLow: 0.2 + maskThresholdUp: 1.0 + + shadowEnabled: true + shadowColor: "#f04000" + shadowBlur: 1.0 + shadowOpacity: 5.0 - switcher.inAnimation * 5.0 + shadowHorizontalOffset: 0 + shadowVerticalOffset: 0 + shadowScale: 1.04 + } + +} diff --git a/examples/quick/multieffect/itemswitcher/qml/images/Built_with_Qt.png b/examples/quick/multieffect/itemswitcher/qml/images/Built_with_Qt.png Binary files differnew file mode 100644 index 0000000000..e612481510 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/Built_with_Qt.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/Built_with_Qt_RGB_logo.png b/examples/quick/multieffect/itemswitcher/qml/images/Built_with_Qt_RGB_logo.png Binary files differnew file mode 100644 index 0000000000..8d2dfc17ec --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/Built_with_Qt_RGB_logo.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/arrow.png b/examples/quick/multieffect/itemswitcher/qml/images/arrow.png Binary files differnew file mode 100644 index 0000000000..067bec4509 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/arrow.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/background.png b/examples/quick/multieffect/itemswitcher/qml/images/background.png Binary files differnew file mode 100644 index 0000000000..9b9e9e487d --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/background.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/hblinds.png b/examples/quick/multieffect/itemswitcher/qml/images/hblinds.png Binary files differnew file mode 100644 index 0000000000..09ce73ee03 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/hblinds.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/heart.png b/examples/quick/multieffect/itemswitcher/qml/images/heart.png Binary files differnew file mode 100644 index 0000000000..dda1f4bab1 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/heart.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/quit_coding.png b/examples/quick/multieffect/itemswitcher/qml/images/quit_coding.png Binary files differnew file mode 100644 index 0000000000..0930013af4 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/quit_coding.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/smoke.png b/examples/quick/multieffect/itemswitcher/qml/images/smoke.png Binary files differnew file mode 100644 index 0000000000..83dfcc453c --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/smoke.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/star.png b/examples/quick/multieffect/itemswitcher/qml/images/star.png Binary files differnew file mode 100644 index 0000000000..f83bd87892 --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/star.png diff --git a/examples/quick/multieffect/itemswitcher/qml/images/stripes.png b/examples/quick/multieffect/itemswitcher/qml/images/stripes.png Binary files differnew file mode 100644 index 0000000000..7a79767e6e --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/images/stripes.png diff --git a/examples/quick/multieffect/itemswitcher/qml/main.qml b/examples/quick/multieffect/itemswitcher/qml/main.qml new file mode 100644 index 0000000000..9685c71ccb --- /dev/null +++ b/examples/quick/multieffect/itemswitcher/qml/main.qml @@ -0,0 +1,219 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import QtQuick.Controls.Material + +Rectangle { + id: mainWindow + + // Multiplier for resolution independency + readonly property real dp: 0.2 + Math.min(width, height) / 1200 + + width: 1280 + height: 720 + visible: true + color: "#404040" + + QtObject { + id: settings + property real settingsViewWidth: 100 + 150 * dp + property int effectIndex: 0 + property int switchDuration: 1500 + property int itemSize: mainWindow.height * 0.6 + } + + Item { + id: testItem1 + width: 1 + height: 1 + } + + Rectangle { + id: testItem2 + anchors.fill: itemSwitcher + color: "#d0d0d0" + visible: false + Image { + anchors.fill: parent + anchors.margins: 4 + source: "images/background.png" + } + Text { + anchors.centerIn: parent + font.pixelSize: 40 * dp + horizontalAlignment: Text.AlignHCenter + text: "This is the\nfirst item" + color: "#ffffff" + style: Text.Outline + styleColor: "#202020" + } + } + + Rectangle { + id: testItem3Content + anchors.fill: itemSwitcher + color: "white" + border.width: 5 + visible: itemSwitcher.currentIndex === 2 + Text { + anchors.centerIn: parent + font.pixelSize: 48 * dp + horizontalAlignment: Text.AlignHCenter + text: "This is a\nDIFFERENT\nsecond item" + rotation: slider.value * 360 + } + Slider { + id: slider + anchors.top: parent.top + anchors.topMargin: 20 * dp + anchors.horizontalCenter: parent.horizontalCenter + from: 0 + to: 1 + width: parent.width * 0.8 + } + Button { + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 * dp + anchors.horizontalCenter: parent.horizontalCenter + text: "Controls Button" + } + } + ShaderEffectSource { + // Wrap testItem3 into ShaderEffectSource so it doesn't need + // visible = false and can be interactive. + id: testItem3 + anchors.fill: testItem3Content + sourceItem: testItem3Content + hideSource: true + visible: false + } + + Image { + id: testItem4 + source: "images/Built_with_Qt.png" + anchors.fill: itemSwitcher + visible: false + } + + Image { + id: testItem5 + source: "images/quit_coding.png" + anchors.fill: itemSwitcher + visible: false + } + + Item { + id: mainArea + anchors.left: settingsView.right + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + + PagesView { + id: pagesView + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 20 * dp + PagesItem { + width: pagesView.itemSize + height: pagesView.itemSize + source: testItem1 + text: "(EMPTY)" + selected: itemSwitcher.currentIndex === 0 + onClicked: { + itemSwitcher.currentIndex = 0; + } + } + PagesItem { + width: pagesView.itemSize + height: pagesView.itemSize + source: testItem2 + selected: itemSwitcher.currentIndex === 1 + onClicked: { + itemSwitcher.currentIndex = 1; + } + } + PagesItem { + width: pagesView.itemSize + height: pagesView.itemSize + source: testItem3 + selected: itemSwitcher.currentIndex === 2 + onClicked: { + itemSwitcher.currentIndex = 2; + } + } + PagesItem { + width: pagesView.itemSize + height: pagesView.itemSize + source: testItem4 + selected: itemSwitcher.currentIndex === 3 + onClicked: { + itemSwitcher.currentIndex = 3; + } + } + PagesItem { + width: pagesView.itemSize + height: pagesView.itemSize + source: testItem5 + selected: itemSwitcher.currentIndex === 4 + onClicked: { + itemSwitcher.currentIndex = 4; + } + } + } + } + ItemSwitcher { + id: itemSwitcher + anchors.centerIn: mainArea + anchors.verticalCenterOffset: pagesView.height / 2 + width: settings.itemSize + height: settings.itemSize + duration: settings.switchDuration + Component.onCompleted: { + // Add all switchable items into switcher + sourceItems.push(testItem1); + sourceItems.push(testItem2); + sourceItems.push(testItem3); + sourceItems.push(testItem4); + sourceItems.push(testItem5); + // From item is the currently selected one + currentIndex = settings.effectIndex; + } + + SwitchEffectBlinds { + id: blindsEffect + visible: settings.effectIndex == 0 + rotation: 45 + } + SwitchEffectBlur { + id: blurEffect + visible: settings.effectIndex == 1 + } + SwitchEffectHeart { + id: heartEffect + visible: settings.effectIndex == 2 + } + SwitchEffectStars { + id: starsEffect + visible: settings.effectIndex == 3 + } + SwitchEffectThunder { + id: thunderEffect + visible: settings.effectIndex == 4 + } + SwitchEffect3DFlip { + id: flipEffect + visible: settings.effectIndex == 5 + } + } + + SettingsView { + id: settingsView + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 20 + } +} diff --git a/examples/quick/multieffect/multieffect.pro b/examples/quick/multieffect/multieffect.pro new file mode 100644 index 0000000000..b06faae7df --- /dev/null +++ b/examples/quick/multieffect/multieffect.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS += testbed \ + itemswitcher diff --git a/examples/quick/multieffect/testbed/CMakeLists.txt b/examples/quick/multieffect/testbed/CMakeLists.txt new file mode 100644 index 0000000000..7f7fda0082 --- /dev/null +++ b/examples/quick/multieffect/testbed/CMakeLists.txt @@ -0,0 +1,69 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(testbed LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/multieffect/testbed") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick QuickControls2) + +add_subdirectory("../../shared" "shared") + +qt_add_executable(testbedexample WIN32 MACOSX_BUNDLE + main.cpp +) + +target_link_libraries(testbedexample PRIVATE + Qt::Core + Qt::Gui + Qt::Qml + Qt::Quick + Qt::QuickControls2 +) + +add_dependencies(testbedexample testbed_shared) + +# Resources: +qt_add_qml_module(testbedexample + URI testbed + VERSION 1.0 + AUTO_RESOURCE_PREFIX + QML_FILES + "qml/FpsItem.qml" + "qml/main.qml" + "qml/ResetSettingsOverlay.qml" + "qml/Settings.qml" + "qml/SettingsView.qml" + "qml/ShaderView.qml" + "qml/TestMaskItem.qml" + "qml/TestSourceItem.qml" + "qml/WarningsItem.qml" + "qml/WarningsView.qml" + "qml/SettingsComponentView.qml" + "qml/SettingsComponentSlider.qml" + "qml/SettingsComponentCheckBox.qml" + "qml/SettingsComponentColorSelector.qml" + RESOURCES + "qml/images/pause.png" + "qml/images/play.png" + "qml/images/spinner.png" + "qml/images/warning.png" + "qml/images/arrow.png" + "qml/images/Built_with_Qt.png" + "qml/images/Built_with_Qt_RGB_logo.png" +) + +install(TARGETS testbedexample + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) + +bundle_shared(testbedexample) diff --git a/examples/quick/multieffect/testbed/main.cpp b/examples/quick/multieffect/testbed/main.cpp new file mode 100644 index 0000000000..130e3ab0b4 --- /dev/null +++ b/examples/quick/multieffect/testbed/main.cpp @@ -0,0 +1,4 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include "../../shared/shared.h" +DECLARATIVE_EXAMPLE_MAIN(testbed/qml/main) diff --git a/examples/quick/multieffect/testbed/qml.qrc b/examples/quick/multieffect/testbed/qml.qrc new file mode 100644 index 0000000000..ab21cc8b0f --- /dev/null +++ b/examples/quick/multieffect/testbed/qml.qrc @@ -0,0 +1,25 @@ +<RCC> + <qresource prefix="/qt/qml/testbed"> + <file>qml/main.qml</file> + <file>qml/Settings.qml</file> + <file>qml/ResetSettingsOverlay.qml</file> + <file>qml/FpsItem.qml</file> + <file>qml/images/spinner.png</file> + <file>qml/images/warning.png</file> + <file>qml/WarningsView.qml</file> + <file>qml/WarningsItem.qml</file> + <file>qml/ShaderView.qml</file> + <file>qml/TestSourceItem.qml</file> + <file>qml/TestMaskItem.qml</file> + <file>qml/SettingsView.qml</file> + <file>qml/images/pause.png</file> + <file>qml/images/play.png</file> + <file>qml/SettingsComponentCheckBox.qml</file> + <file>qml/SettingsComponentColorSelector.qml</file> + <file>qml/SettingsComponentSlider.qml</file> + <file>qml/SettingsComponentView.qml</file> + <file>qml/images/arrow.png</file> + <file>qml/images/Built_with_Qt.png</file> + <file>qml/images/Built_with_Qt_RGB_logo.png</file> + </qresource> +</RCC> diff --git a/examples/quick/multieffect/testbed/qml/FpsItem.qml b/examples/quick/multieffect/testbed/qml/FpsItem.qml new file mode 100644 index 0000000000..53042655a3 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/FpsItem.qml @@ -0,0 +1,65 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: root + property int frameCounter: 0 + property int frameCounterAvg: 0 + property int counter: 0 + property int fps: 0 + property int fpsAvg: 0 + + width: 200 * dp + height: Math.floor(42 * dp) + + Image { + id: spinnerImage + anchors.verticalCenter: parent.verticalCenter + x: 4 * dp + width: 32 * dp + height: width + source: "images/spinner.png" + NumberAnimation on rotation { + from:0 + to: 360 + duration: 800 + loops: Animation.Infinite + } + onRotationChanged: frameCounter++; + } + Image { + anchors.centerIn: spinnerImage + width: 18 * dp + height: width + source: settings.animateMovement ? "images/play.png" : "images/pause.png" + opacity: 0.5 + } + + Text { + anchors.left: spinnerImage.right + anchors.leftMargin: 8 * dp + anchors.verticalCenter: spinnerImage.verticalCenter + color: "#c0c0c0" + font.pixelSize: 22 * dp + text: "Ø " + root.fpsAvg + " | " + root.fps + " fps" + } + + Timer { + interval: 2000 + repeat: true + running: true + onTriggered: { + frameCounterAvg += frameCounter; + root.fps = Math.ceil(frameCounter / 2); + counter++; + frameCounter = 0; + if (counter >= 3) { + root.fpsAvg = Math.ceil(frameCounterAvg / (2 * counter)); + frameCounterAvg = 0; + counter = 0; + } + } + } +} diff --git a/examples/quick/multieffect/testbed/qml/ResetSettingsOverlay.qml b/examples/quick/multieffect/testbed/qml/ResetSettingsOverlay.qml new file mode 100644 index 0000000000..3931548124 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/ResetSettingsOverlay.qml @@ -0,0 +1,170 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Shapes + +Item { + id: rootItem + + property real showAnimationProgress: 0 + property int itemWidth: 256 * dp + property int lineSpacing1: 0 + property int lineWidth1: 20 * dp + property int lineSpacing2: 10 * dp + property int lineWidth2: 10 * dp + + readonly property int cx: itemWidth / 2 + readonly property int cy: itemWidth / 2 + + signal animationFinished + + function startShow() { + hideAnimationItem.stop(); + showAnimationItem.restart(); + } + function stopShow() { + showAnimationItem.stop(); + hideAnimationItem.restart(); + } + + function ringProgress() { + return showAnimationProgress * (2 * Math.PI) - (Math.PI / 2); + } + + function useLargeArcFunc() { + return (ringProgress() > Math.PI / 2); + } + + anchors.fill: parent + visible: opacity + opacity: 0 + + SequentialAnimation { + id: showAnimationItem + PauseAnimation { + duration: 400 + } + ScriptAction { + script: { + rootItem.showAnimationProgress = 0; + } + } + NumberAnimation { + target: rootItem + property: "opacity" + to: 1 + duration: 400 + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: rootItem + property: "showAnimationProgress" + to: 1 + duration: 2000 + easing.type: Easing.InOutQuad + } + ScriptAction { + script: rootItem.animationFinished(); + } + } + SequentialAnimation { + id: hideAnimationItem + NumberAnimation { + target: rootItem + property: "opacity" + to: 0 + duration: 400 + easing.type: Easing.InOutQuad + } + ScriptAction { + script: { + rootItem.showAnimationProgress = 0; + } + } + } + + Rectangle { + anchors.fill: parent + color: "#000000" + opacity: 0.6 + } + + Shape { + id: shapeItem + x: (parent.width / 2) - (itemWidth / 2) + y: (parent.height / 2) - (itemWidth / 2) + opacity: rootItem.showAnimationProgress + width: itemWidth + height: itemWidth + rotation: rootItem.showAnimationProgress * 360 + ShapePath { + strokeColor: "#606060" + fillColor: "transparent" + strokeWidth: lineWidth1 + capStyle: ShapePath.RoundCap + PathMove { + x: itemWidth / 2 + y: pathArc1.spacing + } + PathArc { + id: pathArc1 + property real spacing: lineSpacing1 + lineWidth1 + x: cx + ((itemWidth / 2 - spacing) * Math.cos(ringProgress())) + y: cy + ((itemWidth / 2 - spacing) * Math.sin(ringProgress())) + radiusX: itemWidth / 2 - spacing + radiusY: itemWidth / 2 - spacing + useLargeArc: useLargeArcFunc() + } + } + + ShapePath { + strokeColor: "#808080" + fillColor: "transparent" + strokeWidth: lineWidth2 + capStyle: ShapePath.RoundCap + PathMove { + x: itemWidth / 2 + y: pathArc2.spacing + } + PathArc { + id: pathArc2 + property real spacing: lineSpacing2 + lineWidth2 + x: cx + ((itemWidth / 2 - spacing) * Math.cos(ringProgress())) + y: cy + ((itemWidth / 2 - spacing) * Math.sin(ringProgress())) + radiusX: itemWidth / 2 - spacing + radiusY: itemWidth / 2 - spacing + useLargeArc: useLargeArcFunc() + } + } + } + Text { + id: textItem + anchors.centerIn: shapeItem + font.pixelSize: 32 * dp + color: "#d0d0d0" + text: showAnimationProgress < 1 ? qsTr("Reset to default settings?") : qsTr("Reseted!") + Behavior on text { + SequentialAnimation { + NumberAnimation { + target: textItem + properties: "scale, opacity" + to: 0 + duration: 200 + easing.type: Easing.InOutQuad + } + PropertyAction { + target: textItem + property: "text" + } + NumberAnimation { + target: textItem + properties: "scale, opacity" + to: 1.0 + duration: 200 + easing.type: Easing.InOutQuad + } + } + } + } +} diff --git a/examples/quick/multieffect/testbed/qml/Settings.qml b/examples/quick/multieffect/testbed/qml/Settings.qml new file mode 100644 index 0000000000..82db53202c --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/Settings.qml @@ -0,0 +1,91 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +QtObject { + id: rootItem + + // Emitted when settings are reseted to default + signal reseted + + // When adding settings here remember to add them also into reset() + + // *** General settings - No UI for these *** + // Change to false to not show settings view at all + property bool showSettingsView: true + property real settingsViewWidth: 100 + 150 * dp + property bool animateMovement: true + property bool showShader: false + property bool showItemSize: false + + property bool autoPaddingEnabled: true + property rect paddingRect: Qt.rect(0, 0, 0, 0) + + property bool brightnessEnabled: true + property real brightness: 0.0 + property bool contrastEnabled: true + property real contrast: 0.0 + property bool saturationEnabled: true + property real saturation: 0.0 + property bool colorizeEnabled: true + property color colorizeColor: Qt.rgba(1.0, 0.0, 0.0, 1.0) + property real colorize: 0.0 + + property bool blurEnabled: true + property real blur: 0.0 + property int blurMax: 32 + property real blurMultiplier: 0.0 + + property bool shadowEnabled: true + property real shadowOpacity: 1.0 + property real shadowBlur: 1.0 + property real shadowHorizontalOffset: 10 + property real shadowVerticalOffset: 5 + property color shadowColor: Qt.rgba(0.0, 0.0, 0.0, 1.0) + property real shadowScale: 1.0 + + property bool maskEnabled: true + property bool maskInverted: false + property real maskThresholdLow: 0.0 + property real maskSpreadLow: 0.0 + property real maskThresholdUp: 1.0 + property real maskSpreadUp: 0.0 + + function reset() { + autoPaddingEnabled = defaultSettings.autoPaddingEnabled; + paddingRect = defaultSettings.paddingRect; + + brightnessEnabled = defaultSettings.brightnessEnabled; + brightness = defaultSettings.brightness; + contrastEnabled = defaultSettings.contrastEnabled; + contrast = defaultSettings.contrast; + saturationEnabled = defaultSettings.saturationEnabled; + saturation = defaultSettings.saturation; + colorizeEnabled = defaultSettings.colorizeEnabled; + colorizeColor = defaultSettings.colorizeColor; + colorize = defaultSettings.colorize; + + blurEnabled = defaultSettings.blurEnabled; + blur = defaultSettings.blur; + blurMax = defaultSettings.blurMax; + blurMultiplier = defaultSettings.blurMultiplier; + + shadowEnabled = defaultSettings.shadowEnabled; + shadowOpacity = defaultSettings.shadowOpacity; + shadowBlur = defaultSettings.shadowBlur; + shadowHorizontalOffset = defaultSettings.shadowHorizontalOffset; + shadowVerticalOffset = defaultSettings.shadowVerticalOffset; + shadowColor = defaultSettings.shadowColor; + shadowScale = defaultSettings.shadowScale; + + maskEnabled = defaultSettings.maskEnabled; + maskInverted = defaultSettings.maskInverted; + maskThresholdLow = defaultSettings.maskThresholdLow; + maskSpreadLow = defaultSettings.maskSpreadLow; + maskThresholdUp = defaultSettings.maskThresholdUp; + maskSpreadUp = defaultSettings.maskSpreadUp; + + rootItem.reseted(); + } +} diff --git a/examples/quick/multieffect/testbed/qml/SettingsComponentCheckBox.qml b/examples/quick/multieffect/testbed/qml/SettingsComponentCheckBox.qml new file mode 100644 index 0000000000..ef1cb27d89 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/SettingsComponentCheckBox.qml @@ -0,0 +1,35 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material + +Column { + id: rootItem + + property alias text: textItem.text + property alias checked: checkBox.checked + + signal toggled + + Material.theme: Material.Dark + Material.accent: Material.LightGreen + spacing: -12 + + Row { + CheckBox { + id: checkBox + checked: true + onToggled: { + rootItem.toggled(); + } + } + Text { + id: textItem + anchors.verticalCenter: parent.verticalCenter + color: "#f0f0f0" + font.pixelSize: 14 * dp + } + } +} diff --git a/examples/quick/multieffect/testbed/qml/SettingsComponentColorSelector.qml b/examples/quick/multieffect/testbed/qml/SettingsComponentColorSelector.qml new file mode 100644 index 0000000000..c158f84a7d --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/SettingsComponentColorSelector.qml @@ -0,0 +1,135 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material + +Column { + id: rootItem + + property alias text: textItem.text + readonly property color value: Qt.rgba(colorRed, colorGreen, colorBlue, 1.0) + readonly property real colorRed: sliderRed.value + readonly property real colorGreen: sliderGreen.value + readonly property real colorBlue: sliderBlue.value + readonly property real itemWidth: (rootItem.width / 3) - itemMargin + readonly property real itemMargin: 4 + readonly property real colorBarHeight: 4 + + // Use this to set the initial values + function setValues(r, g, b) { + sliderRed.value = r; + sliderGreen.value = g; + sliderBlue.value = b; + } + + Material.theme: Material.Dark + Material.accent: Material.LightGreen + spacing: -12 + width: 200 + + Text { + id: textItem + anchors.horizontalCenter: parent.horizontalCenter + color: "#f0f0f0" + font.pixelSize: 14 * dp + } + Item { + width: 1 + height: 36 + } + + Row { + x: itemMargin / 2 + spacing: itemMargin + opacity: rootItem.enabled ? 1.0 : 0.2 + Column { + Rectangle { + width: rootItem.itemWidth + height: colorBarHeight + border.width: 1 + border.color: "#202020" + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { position: 0.0; color: Qt.rgba(0.0, colorGreen, colorBlue, 1.0) } + GradientStop { position: 1.0; color: Qt.rgba(1.0, colorGreen, colorBlue, 1.0) } + } + Text { + id: textItemRed + anchors.centerIn: parent + color: "#f0f0f0" + style: Text.Outline + styleColor: "#000000" + text: "R: " + Math.ceil(sliderRed.value * 255) + font.pixelSize: 14 * dp + } + } + Slider { + id: sliderRed + width: rootItem.itemWidth + value: 0 + from: 0 + to: 1 + } + } + Column { + Rectangle { + width: rootItem.itemWidth + height: colorBarHeight + border.width: 1 + border.color: "#202020" + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { position: 0.0; color: Qt.rgba(colorRed, 0.0, colorBlue, 1.0) } + GradientStop { position: 1.0; color: Qt.rgba(colorRed, 1.0, colorBlue, 1.0) } + } + Text { + id: textItemGreen + anchors.centerIn: parent + color: "#f0f0f0" + style: Text.Outline + styleColor: "#000000" + text: "G: " + Math.ceil(sliderGreen.value * 255) + font.pixelSize: 14 * dp + } + } + Slider { + id: sliderGreen + width: rootItem.itemWidth + value: 0 + from: 0 + to: 1 + } + } + Column { + Rectangle { + width: rootItem.itemWidth + height: colorBarHeight + border.width: 1 + border.color: "#202020" + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { position: 0.0; color: Qt.rgba(colorRed, colorGreen, 0.0, 1.0) } + GradientStop { position: 1.0; color: Qt.rgba(colorRed, colorGreen, 1.0, 1.0) } + } + Text { + id: textItemBlue + anchors.centerIn: parent + color: "#f0f0f0" + style: Text.Outline + styleColor: "#000000" + text: "B: " + Math.ceil(sliderBlue.value * 255) + font.pixelSize: 14 * dp + } + } + Slider { + id: sliderBlue + width: rootItem.itemWidth + value: 0 + from: 0 + to: 1 + } + } + } +} diff --git a/examples/quick/multieffect/testbed/qml/SettingsComponentSlider.qml b/examples/quick/multieffect/testbed/qml/SettingsComponentSlider.qml new file mode 100644 index 0000000000..ed04584e44 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/SettingsComponentSlider.qml @@ -0,0 +1,54 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material + +Column { + id: rootItem + + property alias text: textItem.text + property alias value: slider.value + property alias from: slider.from + property alias to: slider.to + property alias checked: checkBox.checked + property alias stepSize: slider.stepSize + property bool showCheckbox: false + + signal toggled + signal moved + + Material.theme: Material.Dark + Material.accent: Material.LightGreen + spacing: -12 + + Text { + id: textItem + anchors.horizontalCenter: parent.horizontalCenter + color: "#f0f0f0" + font.pixelSize: 14 * dp + } + + Row { + CheckBox { + id: checkBox + visible: rootItem.showCheckbox + checked: true + onToggled: { + rootItem.toggled(); + } + } + Slider { + id: slider + property real sliderWidth: settings.settingsViewWidth - 50 + width: rootItem.showCheckbox ? sliderWidth : sliderWidth + checkBox.width + value: 50 + from: 0 + to: 800 + onMoved: { + rootItem.moved(); + } + } + } +} diff --git a/examples/quick/multieffect/testbed/qml/SettingsComponentView.qml b/examples/quick/multieffect/testbed/qml/SettingsComponentView.qml new file mode 100644 index 0000000000..08eb0ad300 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/SettingsComponentView.qml @@ -0,0 +1,147 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Column { + id: rootItem + + property alias text: textItem.text + property bool show: true + + default property alias contents: contentItem.children + property real showHideAnimationSpeed: 400 + + width: settings.settingsViewWidth + + Component.onCompleted: { + // Set initial open state + contentItem.visible = rootItem.show; + contentItem.opacity = rootItem.show; + contentItemArea.height = rootItem.show ? contentItem.height : 0; + } + + Item { + id: lightsSettings + width: parent.width + height: 30 + Rectangle { + anchors.fill: parent + color: "#404040" + border.width: 1 + border.color: "#808080" + opacity: 0.4 + } + Image { + x: 8 + source: "images/arrow.png" + anchors.verticalCenter: parent.verticalCenter + rotation: rootItem.show ? 90 : 0 + Behavior on rotation { + NumberAnimation { + duration: showHideAnimationSpeed + easing.type: Easing.InOutQuad + } + } + } + + Text { + id: textItem + x: 30 + anchors.verticalCenter: parent.verticalCenter + color: "#f0f0f0" + font.bold: true + font.pixelSize: 16 * dp + } + MouseArea { + anchors.fill: parent + onClicked: { + rootItem.show = !rootItem.show; + if (rootItem.show) { + hideAnimation.stop(); + showAnimation.start(); + } else { + showAnimation.stop(); + hideAnimation.start(); + } + + } + } + } + + Item { + width: 1 + height: 5 + } + + SequentialAnimation { + id: showAnimation + ScriptAction { + script: contentItem.visible = true; + } + ParallelAnimation { + NumberAnimation { + target: contentItemArea + property: "height" + to: contentItem.height + duration: showHideAnimationSpeed + easing.type: Easing.InOutQuad + } + SequentialAnimation { + PauseAnimation { + duration: showHideAnimationSpeed / 2 + } + NumberAnimation { + target: contentItem + property: "opacity" + to: 1.0 + duration: showHideAnimationSpeed / 2 + easing.type: Easing.InOutQuad + } + } + } + } + + SequentialAnimation { + id: hideAnimation + ParallelAnimation { + NumberAnimation { + target: contentItemArea + property: "height" + to: 0 + duration: showHideAnimationSpeed + easing.type: Easing.InOutQuad + } + SequentialAnimation { + NumberAnimation { + target: contentItem + property: "opacity" + to: 0 + duration: showHideAnimationSpeed / 2 + easing.type: Easing.InOutQuad + } + PauseAnimation { + duration: showHideAnimationSpeed / 2 + } + } + } + ScriptAction { + script: contentItem.visible = false; + } + } + + Item { + id: contentItemArea + width: parent.width - 10 + x: 5 + Column { + id: contentItem + spacing: -10 + } + } + + Item { + width: 1 + height: 5 + } +} diff --git a/examples/quick/multieffect/testbed/qml/SettingsView.qml b/examples/quick/multieffect/testbed/qml/SettingsView.qml new file mode 100644 index 0000000000..d0d70958bf --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/SettingsView.qml @@ -0,0 +1,400 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls.Material + +Item { + id: rootItem + + property bool show: true + property real showAnimation: show ? 1 : 0 + + function resetSettings() { + colorizeColorSelector.setValues(defaultSettings.colorizeColor.r, + defaultSettings.colorizeColor.g, + defaultSettings.colorizeColor.b); + shadowColorSelector.setValues(defaultSettings.shadowColor.r, + defaultSettings.shadowColor.g, + defaultSettings.shadowColor.b); + } + + Material.theme: Material.Dark + Material.accent: Material.LightGreen + width: settings.settingsViewWidth + x: -(width + 30) * (1 - showAnimation) + 20 + + Behavior on showAnimation { + NumberAnimation { + duration: 400 + easing.type: Easing.InOutQuad + } + } + + // Open/close button + Item { + width: 30 * dp + height: 30 * dp + anchors.left: parent.right + anchors.leftMargin: 20 + anchors.top: parent.top + anchors.topMargin: -10 + Rectangle { + anchors.fill: parent + color: "#404040" + opacity: 0.4 + border.width: 1 + border.color: "#808080" + } + + Image { + anchors.centerIn: parent + source: "images/arrow.png" + rotation: rootItem.showAnimation * 180 + } + MouseArea { + anchors.fill: parent + anchors.margins: -30 * dp + onClicked: { + rootItem.show = !rootItem.show; + } + } + } + + // Background + Rectangle { + anchors.fill: scrollView + opacity: showAnimation ? 0.6 : 0 + visible: opacity + anchors.margins: -10 + color: "#202020" + border.color: "#808080" + border.width: 1 + } + + ScrollView { + id: scrollView + anchors.fill: parent + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.interactive: false + clip: true + Column { + id: settingsArea + anchors.fill: parent + opacity: showAnimation + visible: opacity + + Item { + width: 1 + height: 20 * dp + } + Image { + anchors.horizontalCenter: parent.horizontalCenter + fillMode: Image.PreserveAspectFit + width: parent.width * 0.8 + height: width * 0.25 + source: "images/Built_with_Qt_RGB_logo.png" + } + Item { + width: 1 + height: 28 * dp + } + + SettingsComponentView { + id: settingsViewGeneral + text: qsTr("General") + show: true + SettingsComponentCheckBox { + text: "Show Shaders" + checked: settings.showShader + onToggled: { + settings.showShader = checked; + } + } + SettingsComponentCheckBox { + text: "Show Item Size" + checked: settings.showItemSize + onToggled: { + settings.showItemSize = checked; + } + } + SettingsComponentCheckBox { + text: "AutoPadding Enabled" + checked: settings.autoPaddingEnabled + onToggled: { + settings.autoPaddingEnabled = checked; + } + } + Item { + width: 1 + height: 20 * dp + } + SettingsComponentSlider { + text: qsTr("Padding Left") + ": " + value.toFixed(0) + value: settings.paddingRect.x + from: 0.0 + to: 300 + onMoved: { + settings.paddingRect.x = value; + } + } + SettingsComponentSlider { + text: qsTr("Padding Right") + ": " + value.toFixed(0) + value: settings.paddingRect.width + from: 0.0 + to: 300 + onMoved: { + settings.paddingRect.width = value; + } + } + SettingsComponentSlider { + text: qsTr("Padding Top") + ": " + value.toFixed(0) + value: settings.paddingRect.y + from: 0.0 + to: 300 + onMoved: { + settings.paddingRect.y = value; + } + } + SettingsComponentSlider { + text: qsTr("Padding Bottom") + ": " + value.toFixed(0) + value: settings.paddingRect.height + from: 0.0 + to: 300 + onMoved: { + settings.paddingRect.height = value; + } + } + } + + SettingsComponentView { + text: qsTr("Color") + show: false + SettingsComponentSlider { + text: qsTr("Brightness") + ": " + value.toFixed(3) + showCheckbox: true + checked: settings.brightnessEnabled + onToggled: { + settings.brightnessEnabled = checked; + } + value: settings.brightness + from: -1 + to: 1 + onMoved: { + settings.brightness = value; + } + } + SettingsComponentSlider { + text: qsTr("Contrast") + ": " + value.toFixed(3) + showCheckbox: true + checked: settings.contrastEnabled + onToggled: { + settings.contrastEnabled = checked; + } + value: settings.contrast + from: -1 + to: 1 + onMoved: { + settings.contrast = value; + } + } + SettingsComponentSlider { + text: qsTr("Saturation") + ": " + value.toFixed(3) + showCheckbox: true + checked: settings.saturationEnabled + onToggled: { + settings.saturationEnabled = checked; + } + value: settings.saturation + from: -1 + to: 1 + onMoved: { + settings.saturation = value; + } + } + SettingsComponentSlider { + text: qsTr("Colorize") + ": " + value.toFixed(3) + showCheckbox: true + checked: settings.colorizeEnabled + onToggled: { + settings.colorizeEnabled = checked; + } + value: settings.colorize + from: 0 + to: 1 + onMoved: { + settings.colorize = value; + } + } + SettingsComponentColorSelector { + id: colorizeColorSelector + text: qsTr("Colorize Color") + width: settings.settingsViewWidth - 10 + onValueChanged: { + settings.colorizeColor = value; + } + } + } + SettingsComponentView { + text: qsTr("Blur") + show: false + + SettingsComponentSlider { + text: qsTr("Blur") + ": " + value.toFixed(3) + showCheckbox: true + checked: settings.blurEnabled + onToggled: { + settings.blurEnabled = checked; + } + value: settings.blur + from: 0 + to: 1.0 + onMoved: { + settings.blur = value; + } + } + SettingsComponentSlider { + text: qsTr("Blur Multiplier") + ": " + value.toFixed(3) + value: settings.blurMultiplier + from: 0.0 + to: 2.0 + onMoved: { + settings.blurMultiplier = value; + } + } + SettingsComponentSlider { + text: qsTr("Blur Max") + ": " + value.toFixed(0) + value: settings.blurMax + from: 0 + to: 64 + stepSize: 2 + onMoved: { + settings.blurMax = value; + } + } + + } + SettingsComponentView { + text: qsTr("Shadow") + show: false + + SettingsComponentSlider { + text: qsTr("Shadow") + ": " + value.toFixed(3) + showCheckbox: true + checked: settings.shadowEnabled + onToggled: { + settings.shadowEnabled = checked; + } + value: settings.shadowOpacity + from: 0 + to: 1.0 + onMoved: { + settings.shadowOpacity = value; + } + } + SettingsComponentSlider { + text: qsTr("Shadow Blur") + ": " + value.toFixed(3) + value: settings.shadowBlur + from: 0.0 + to: 1.0 + onMoved: { + settings.shadowBlur = value; + } + } + SettingsComponentSlider { + text: qsTr("Shadow HorizontalOffset") + ": " + value.toFixed(1) + value: settings.shadowHorizontalOffset + from: -20.0 + to: 20.0 + onMoved: { + settings.shadowHorizontalOffset = value; + } + } + SettingsComponentSlider { + text: qsTr("Shadow VerticalOffset") + ": " + value.toFixed(1) + value: settings.shadowVerticalOffset + from: -20.0 + to: 20.0 + onMoved: { + settings.shadowVerticalOffset = value; + } + } + SettingsComponentSlider { + text: qsTr("Shadow Scale") + ": " + value.toFixed(3) + value: settings.shadowScale + from: 0.8 + to: 1.2 + onMoved: { + settings.shadowScale = value; + } + } + SettingsComponentColorSelector { + id: shadowColorSelector + text: qsTr("Shadow Color") + width: settings.settingsViewWidth - 10 + onValueChanged: { + settings.shadowColor = value; + } + } + } + SettingsComponentView { + text: qsTr("Mask") + show: false + SettingsComponentCheckBox { + text: "Mask Enabled" + checked: settings.maskEnabled + onToggled: { + settings.maskEnabled = checked; + } + } + SettingsComponentCheckBox { + text: "Mask Inverted" + checked: settings.maskInverted + onToggled: { + settings.maskInverted = checked; + } + } + Item { + width: 1 + height: 20 * dp + } + SettingsComponentSlider { + text: qsTr("Mask Lower Threshold") + ": " + value.toFixed(3) + value: settings.maskThresholdLow + from: 0.0 + to: 1.0 + onMoved: { + settings.maskThresholdLow = value; + } + } + SettingsComponentSlider { + text: qsTr("Mask Lower Spread") + ": " + value.toFixed(3) + value: settings.maskSpreadLow + from: 0.0 + to: 1.0 + onMoved: { + settings.maskSpreadLow = value; + } + } + SettingsComponentSlider { + text: qsTr("Mask Upper Threshold") + ": " + value.toFixed(3) + value: settings.maskThresholdUp + from: 0.0 + to: 1.0 + onMoved: { + settings.maskThresholdUp = value; + } + } + SettingsComponentSlider { + text: qsTr("Mask Upper Spread") + ": " + value.toFixed(3) + value: settings.maskSpreadUp + from: 0.0 + to: 1.0 + onMoved: { + settings.maskSpreadUp = value; + } + } + } + } + } +} diff --git a/examples/quick/multieffect/testbed/qml/ShaderView.qml b/examples/quick/multieffect/testbed/qml/ShaderView.qml new file mode 100644 index 0000000000..fc89f5aec5 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/ShaderView.qml @@ -0,0 +1,29 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + + property string text + + width: textItem.width + height: textItem.height + + Rectangle { + anchors.fill: textItem + anchors.margins: -10 + z: -1 + color: "#000000" + opacity: 0.6 + border.color: "#ffffff" + border.width: 2 + } + Text { + id: textItem + text: rootItem.text + font.pixelSize: 16 + color: "#ffffff" + } +} diff --git a/examples/quick/multieffect/testbed/qml/TestMaskItem.qml b/examples/quick/multieffect/testbed/qml/TestMaskItem.qml new file mode 100644 index 0000000000..4ba5950b96 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/TestMaskItem.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + layer.enabled: true + visible: false + Rectangle { + anchors.fill: parent + gradient: Gradient { + GradientStop { position: 0.0; color: "#00000000" } + GradientStop { position: 1.0; color: "#ffffffff" } + } + } +} diff --git a/examples/quick/multieffect/testbed/qml/TestSourceItem.qml b/examples/quick/multieffect/testbed/qml/TestSourceItem.qml new file mode 100644 index 0000000000..ca5ca387ec --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/TestSourceItem.qml @@ -0,0 +1,113 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material + +Item { + id: rootItem + + Material.theme: Material.Dark + Material.accent: Material.LightGreen + + Image { + anchors.centerIn: parent + width: parent.width / 2 + height: parent.height / 2 + sourceSize.width: width + sourceSize.height: height + source: "images/Built_with_Qt.png" + fillMode: Image.PreserveAspectFit + SequentialAnimation on anchors.verticalCenterOffset { + loops: Animation.Infinite + paused: !settings.animateMovement + NumberAnimation { + to: 50 + duration: 2000 + easing.type: Easing.InOutQuad + } + NumberAnimation { + to: -50 + duration: 2000 + easing.type: Easing.InOutQuad + } + } + } + Text { + font.pixelSize: 50 + font.bold: true + text: "TESTING" + color: "white" + } + Image { + source: "images/warning.png" + anchors.bottom: parent.bottom + anchors.left: parent.left + mipmap: true + SequentialAnimation on scale { + loops: Animation.Infinite + paused: !settings.animateMovement + NumberAnimation { + to: 0.4 + duration: 3000 + easing.type: Easing.InOutQuad + } + NumberAnimation { + to: 1.0 + duration: 1000 + easing.type: Easing.OutBack + } + } + + } + Rectangle { + width: parent.width * 0.2 + height: width + anchors.top: parent.top + anchors.topMargin: width * 0.2 + anchors.right: parent.right + anchors.rightMargin: width * 0.2 + color: "#808080" + border.color: "#f0f0f0" + border.width: 2 + radius: width * 0.1 + SequentialAnimation on opacity { + paused: !settings.animateMovement + loops: Animation.Infinite + NumberAnimation { + to: 0.0 + duration: 2000 + easing.type: Easing.InOutQuad + } + NumberAnimation { + to: 1.0 + duration: 2000 + easing.type: Easing.InOutQuad + } + } + + NumberAnimation on rotation { + paused: !settings.animateMovement + loops: Animation.Infinite + from: 0 + to: 360 + duration: 10000 + } + } + + Column { + anchors.right: parent.right + anchors.rightMargin: width * 0.2 + anchors.bottom: parent.bottom + Button { + id: button + text: "Controls Button" + Material.theme: Material.Light + } + Slider { + width: button.width + } + } +} + diff --git a/examples/quick/multieffect/testbed/qml/WarningsItem.qml b/examples/quick/multieffect/testbed/qml/WarningsItem.qml new file mode 100644 index 0000000000..201332c87b --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/WarningsItem.qml @@ -0,0 +1,66 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + + property string text + + function show() { + showAnimation.restart(); + } + + height: 42 + width: warningIcon.width + textItem.width + 40 + opacity: 0 + + Rectangle { + anchors.fill: parent + color: "#000000" + opacity: 0.6 + } + + SequentialAnimation { + id: showAnimation + NumberAnimation { + target: rootItem + property: "opacity" + to: 1 + duration: 400 + easing.type: Easing.InOutQuad + } + PauseAnimation { + duration: 2000 + } + NumberAnimation { + target: rootItem + property: "opacity" + to: 0 + duration: 400 + easing.type: Easing.InOutQuad + } + } + + Image { + id: warningIcon + anchors.verticalCenter: parent.verticalCenter + x: 8 + source: "images/warning.png" + mipmap: true + width: 24 + height: width + } + + Text { + id: textItem + anchors.left: warningIcon.right + anchors.leftMargin: 8 + anchors.verticalCenter: parent.verticalCenter + color: "#ffffff" + font.pixelSize: 16 + text: rootItem.text + } + +} diff --git a/examples/quick/multieffect/testbed/qml/WarningsView.qml b/examples/quick/multieffect/testbed/qml/WarningsView.qml new file mode 100644 index 0000000000..880a75b885 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/WarningsView.qml @@ -0,0 +1,31 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: rootItem + + function showShaderWarning() { + shaderWarning.show(); + } + function showSizeWarning() { + sizeWarning.show(); + } + + height: 60 + + WarningsItem { + id: shaderWarning + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + text: qsTr("Shader changed!") + } + WarningsItem { + id: sizeWarning + anchors.verticalCenter: parent.verticalCenter + anchors.left: shaderWarning.right + anchors.leftMargin: 16 + text: qsTr("Item resized!") + } +} diff --git a/examples/quick/multieffect/testbed/qml/images/Built_with_Qt.png b/examples/quick/multieffect/testbed/qml/images/Built_with_Qt.png Binary files differnew file mode 100644 index 0000000000..e612481510 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/images/Built_with_Qt.png diff --git a/examples/quick/multieffect/testbed/qml/images/Built_with_Qt_RGB_logo.png b/examples/quick/multieffect/testbed/qml/images/Built_with_Qt_RGB_logo.png Binary files differnew file mode 100644 index 0000000000..8d2dfc17ec --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/images/Built_with_Qt_RGB_logo.png diff --git a/examples/quick/multieffect/testbed/qml/images/arrow.png b/examples/quick/multieffect/testbed/qml/images/arrow.png Binary files differnew file mode 100644 index 0000000000..067bec4509 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/images/arrow.png diff --git a/examples/quick/multieffect/testbed/qml/images/pause.png b/examples/quick/multieffect/testbed/qml/images/pause.png Binary files differnew file mode 100644 index 0000000000..ef6e0ac26a --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/images/pause.png diff --git a/examples/quick/multieffect/testbed/qml/images/play.png b/examples/quick/multieffect/testbed/qml/images/play.png Binary files differnew file mode 100644 index 0000000000..4cd0f78184 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/images/play.png diff --git a/examples/quick/multieffect/testbed/qml/images/spinner.png b/examples/quick/multieffect/testbed/qml/images/spinner.png Binary files differnew file mode 100644 index 0000000000..3ff86d53ac --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/images/spinner.png diff --git a/examples/quick/multieffect/testbed/qml/images/warning.png b/examples/quick/multieffect/testbed/qml/images/warning.png Binary files differnew file mode 100644 index 0000000000..08d74b8b83 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/images/warning.png diff --git a/examples/quick/multieffect/testbed/qml/main.qml b/examples/quick/multieffect/testbed/qml/main.qml new file mode 100644 index 0000000000..71cec0a486 --- /dev/null +++ b/examples/quick/multieffect/testbed/qml/main.qml @@ -0,0 +1,155 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Window +import QtQuick.Effects + +Rectangle { + id: mainWindow + + // Multiplier for resolution independency + readonly property real dp: 0.2 + Math.min(width, height) / 1200 + + width: 1280 + height: 720 + color: "#404040" + + Settings { + id: settings + onReseted: { + settingsView.resetSettings(); + } + } + + Settings { + id: defaultSettings + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (resetSettingsOverlay.showAnimationProgress == 0) + settings.animateMovement = !settings.animateMovement; + } + onPressed: { + resetSettingsOverlay.startShow(); + } + onReleased: { + resetSettingsOverlay.stopShow(); + } + } + + + Item { + id: mainArea + anchors.left: settingsView.right + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + + TestSourceItem { + id: testSourceItem + anchors.centerIn: parent + width: parent.width / 2 + height: parent.height / 2 + + layer.enabled: true + visible: false + } + TestMaskItem { + id: testMaskItem + anchors.fill: testSourceItem + } + + Rectangle { + readonly property int margin: 2 + x: quickMultiEffect.x + quickMultiEffect.itemRect.x - margin + y: quickMultiEffect.y + quickMultiEffect.itemRect.y - margin + width: quickMultiEffect.itemRect.width + margin * 2 + height: quickMultiEffect.itemRect.height + margin * 2 + visible: settings.showItemSize + color: "transparent" + border.color: "#ffffff" + border.width: 2 + } + + MultiEffect { + id: quickMultiEffect + anchors.fill: testSourceItem + source: testSourceItem + maskSource: testMaskItem + + autoPaddingEnabled: settings.autoPaddingEnabled + paddingRect: settings.paddingRect + brightness: settings.brightnessEnabled ? settings.brightness : 0 + contrast: settings.contrastEnabled ? settings.contrast : 0 + saturation: settings.saturationEnabled ? settings.saturation : 0 + colorizeColor: settings.colorizeColor + colorize: settings.colorizeEnabled ? settings.colorize : 0 + blurEnabled: settings.blurEnabled + blur: settings.blur + blurMax: settings.blurMax + blurMultiplier: settings.blurMultiplier + shadowEnabled: settings.shadowEnabled + shadowOpacity: settings.shadowOpacity + shadowBlur: settings.shadowBlur + shadowHorizontalOffset: settings.shadowHorizontalOffset + shadowVerticalOffset: settings.shadowVerticalOffset + shadowColor: settings.shadowColor + shadowScale: settings.shadowScale + maskEnabled: settings.maskEnabled + maskInverted: settings.maskInverted + maskThresholdLow: settings.maskThresholdLow + maskSpreadLow: settings.maskSpreadLow + maskThresholdUp: settings.maskThresholdUp + maskSpreadUp: settings.maskSpreadUp + + onItemSizeChanged: { + warningsView.showSizeWarning(); + } + onShaderChanged: { + warningsView.showShaderWarning(); + } + } + } + + SettingsView { + id: settingsView + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 20 + visible: settings.showSettingsView + Component.onCompleted: { + settings.reset(); + } + } + + FpsItem { + anchors.right: parent.right + } + + ShaderView { + id: shaderView + visible: settings.showShader + anchors.horizontalCenter: mainArea.horizontalCenter + anchors.top: mainArea.top + anchors.topMargin: 20 + text: "Fragment shader: " + quickMultiEffect.fragmentShader + "\nVertex shader: " + quickMultiEffect.vertexShader + } + + WarningsView { + id: warningsView + anchors.bottom: parent.bottom + anchors.left: settingsView.right + anchors.leftMargin: 40 + anchors.right: parent.right + } + + ResetSettingsOverlay { + id: resetSettingsOverlay + onAnimationFinished: { + settings.reset(); + } + } +} diff --git a/examples/quick/multieffect/testbed/testbed.pro b/examples/quick/multieffect/testbed/testbed.pro new file mode 100644 index 0000000000..e1ae55b118 --- /dev/null +++ b/examples/quick/multieffect/testbed/testbed.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +QT += quick qml +QT += quickcontrols2 +SOURCES += main.cpp +RESOURCES += \ + qml.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/multieffect/testbed +INSTALLS += target diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro index 2003b1c03b..159b0082a3 100644 --- a/examples/quick/quick.pro +++ b/examples/quick/quick.pro @@ -27,7 +27,8 @@ SUBDIRS = quick-accessibility \ particles \ delegatechooser \ shapes \ - itemvariablerefreshrate + itemvariablerefreshrate \ + multieffect #OpenGL Support Required qtConfig(opengl(es1|es2)?) { |