diff options
Diffstat (limited to 'tests/manual')
35 files changed, 1458 insertions, 2 deletions
diff --git a/tests/manual/painterpathquickshape/ControlPanel.qml b/tests/manual/painterpathquickshape/ControlPanel.qml index 87eb9ae3e7..ea3168d124 100644 --- a/tests/manual/painterpathquickshape/ControlPanel.qml +++ b/tests/manual/painterpathquickshape/ControlPanel.qml @@ -28,6 +28,7 @@ Item { property alias painterComparisonAlpha: painterComparisonColorAlpha.value property alias outlineEnabled: enableOutline.checked property alias gradientType: gradientType.currentIndex + property alias fillScaleX: fillTransformSlider.value property alias rendererName: rendererLabel.text property alias preferCurve: rendererLabel.preferCurve @@ -254,6 +255,19 @@ Item { } } Label { + text: "Fill transform (scale x: " + fillTransformSlider.value.toFixed(2) + "):" + color: "white" + visible: gradientType.currentIndex != 0 + } + Slider { + id: fillTransformSlider + Layout.fillWidth: true + from: 0.2 + to: 5.0 + value: 1.0 + visible: gradientType.currentIndex != 0 + } + Label { text: "Fill alpha(" + Math.round(alphaSlider.value*100)/100 + "):" color: "white" } diff --git a/tests/manual/painterpathquickshape/ControlledShape.qml b/tests/manual/painterpathquickshape/ControlledShape.qml index e690f59ccc..26a57163cd 100644 --- a/tests/manual/painterpathquickshape/ControlledShape.qml +++ b/tests/manual/painterpathquickshape/ControlledShape.qml @@ -89,6 +89,7 @@ Item { strokeStyle: controlPanel.outlineStyle joinStyle: controlPanel.joinStyle capStyle: controlPanel.capStyle + fillTransform: Qt.matrix4x4(controlPanel.fillScaleX,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1) } Repeater { diff --git a/tests/manual/platforms/android/qml_in_android_service/.gitignore b/tests/manual/platforms/android/qml_in_android_service/.gitignore new file mode 100644 index 0000000000..2300a2df35 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_android_service/.gitignore @@ -0,0 +1,2 @@ +build/* +CMakeLists.txt.user diff --git a/tests/manual/platforms/android/qml_in_android_service/CMakeLists.txt b/tests/manual/platforms/android/qml_in_android_service/CMakeLists.txt new file mode 100644 index 0000000000..47afd4c0c3 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_android_service/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +cmake_minimum_required(VERSION 3.16) + +project(qml_in_android_service VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 6.7 REQUIRED COMPONENTS Quick) + +qt_standard_project_setup(REQUIRES 6.6) + + +qt_add_executable(qml_in_android_service + main.cpp +) + +qt_add_qml_module(qml_in_android_service + URI qml_in_android_service + VERSION 1.0 + QML_FILES Main.qml +) + +target_link_libraries(qml_in_android_service + PRIVATE Qt6::Quick +) + +install(TARGETS qml_in_android_service + BUNDLE DESTINATION . + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + diff --git a/tests/manual/platforms/android/qml_in_android_service/Main.qml b/tests/manual/platforms/android/qml_in_android_service/Main.qml new file mode 100644 index 0000000000..6b8684e525 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_android_service/Main.qml @@ -0,0 +1,100 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +import QtQuick +import QtQuick.Controls + +Rectangle { + id: mainRectangle + + property string colorStringFormat: "#1CB669" + + signal onClicked() + + color: colorStringFormat + + Text { + id: helloText + + text: "QML" + color: "white" + font.pixelSize: 72 + font.bold: true + fontSizeMode: Text.VerticalFit + horizontalAlignment: Text.AlignHCenter + + // Height is calculated based on display orientation + // from Screen height, dividing numbers are based on what what seem + // to look good on most displays + height: Screen.width > Screen.height ? Screen.height / 8 : (Screen.height / 2) / 8 + + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: 5 + } + } + + + Text { + id: changeColorText + + text: "Tap button to change Java view background color" + color: "white" + font.pixelSize: 58 + fontSizeMode: Text.Fit + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + + // Height and width are calculated based on display orientation + // from Screen height and width, dividing numbers are based on what seem to + // look good on most displays + height: Screen.width > Screen.height ? Screen.height / 8 : (Screen.height / 2) / 8 + width: Screen.width > Screen.height ? (Screen.width / 2) / 2 : Screen.width / 2 + + anchors { + horizontalCenter: parent.horizontalCenter + top: helloText.bottom + topMargin: Screen.height / 10 + } + } + + Button { + id: button + // Width is calculated from changeColorText which is calculated from Screen size + // dividing numbers are base on what seems to look good on most displays + width: changeColorText.width / 1.6 + height: changeColorText.height * 1.2 + + anchors { + + horizontalCenter: parent.horizontalCenter + top: changeColorText.bottom + topMargin: height / 5 + } + + onClicked: mainRectangle.onClicked() + + background: Rectangle { + id: buttonBackground + + radius: 14 + color: "#6200EE" + opacity: button.down ? 0.6 : 1 + scale: button.down ? 0.9 : 1 + } + + contentItem: Text { + id: buttonText + + text: "CHANGE COLOR" + color: "white" + font.pixelSize: 58 + minimumPixelSize: 10 + fontSizeMode: Text.Fit + font.bold: true + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } +} diff --git a/tests/manual/platforms/android/qml_in_android_service/main.cpp b/tests/manual/platforms/android/qml_in_android_service/main.cpp new file mode 100644 index 0000000000..3293373061 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_android_service/main.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QGuiApplication> + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + return app.exec(); +} diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/.gitignore b/tests/manual/platforms/android/qml_in_java_based_android_project/.gitignore new file mode 100644 index 0000000000..347e252ef1 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/.gitignore @@ -0,0 +1,33 @@ +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log/OS Files +*.log + +# Android Studio generated files and folders +captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json + +# IntelliJ +*.iml +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Android Profiling +*.hprof diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/README.md b/tests/manual/platforms/android/qml_in_java_based_android_project/README.md new file mode 100644 index 0000000000..5199430bc8 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/README.md @@ -0,0 +1,35 @@ +# What is this? + +This project is for manual testing of embedding QML into Android Services. It +loads a QML view and a regular Android view side by side, both hosted by a +Service, and wires them together. + +This application is meant to be built using Android Studio, with the Qt Gradle +plugin. There is no need to manually build the Qt project or edit it, only this +Android project. + +# How to sign the application +In order to sign the application, you must have a keystore file and list it in +a 'keystore.properties' file in the project root. + +1) Create 'keystore.properties' file in the same folder as this README +2) Add the following information to the file: + ``` + storePassword=somePassword + keyPassword=someOtherPassword + keyAlias=someKeyAlias + storeFile=/full/path/to/your/keystore.keystore + ``` + +After this, the app build.gradle will read that file and extract the required +information from it, and use that to sign the app before it is deployed. + +# How to configure QtBuild Gradle plugin +The app-level build.gradle already includes and configures the plugin, but it requires some information about the environment it's running in: The Qt installation directory, and the Qt for Android kit directory. + +1) Create 'qtbuild.properties' file in the same folder as this README +2) Add the following information to the file: + ``` + qtKitDir=/path/to/your/android/kit/ + qtPath=/path/to/your/Qt/installation // e.g. /etc/Qt/ + ``` diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/build.gradle b/tests/manual/platforms/android/qml_in_java_based_android_project/app/build.gradle new file mode 100644 index 0000000000..3aa396c87a --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/build.gradle @@ -0,0 +1,83 @@ +plugins { + id 'com.android.application' + id 'org.qtproject.qt.gradleplugin' version '0.1-SNAPSHOT+' +} + +def qtBuildPropertiesFile = rootProject.file('qtbuild.properties'); +def qtBuildProperties = new Properties(); +qtBuildProperties.load(new FileInputStream(qtBuildPropertiesFile)); +QtBuild { + projectPath file('../../qml_in_android_service') + qtKitDir file(qtBuildProperties['qtKitDir']) + qtPath file(qtBuildProperties['qtPath']) +} + +def keystorePropertiesFile = rootProject.file('keystore.properties'); +def keystoreProperties = new Properties(); +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)); + +android { + signingConfigs { + debug { + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + } + } + namespace 'com.example.qml_in_java_based_android_project' + compileSdk 34 + + defaultConfig { + applicationId "com.example.qml_in_java_based_android_project" + minSdk 28 + targetSdk 34 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + signingConfig signingConfigs.debug + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.debug + } + debug { + signingConfig signingConfigs.debug + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + packagingOptions { + jniLibs { + useLegacyPackaging true + } + } + sourceSets { + main { + assets { + srcDirs 'assets' + } + jniLibs { + srcDirs 'libs' + } + } + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.9.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation "org.qtproject.qt.gradleplugin:QtGradlePlugin:0.1-SNAPSHOT" + implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} + diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/AndroidManifest.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..896b975a0b --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> + + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> + + <application + android:allowBackup="true" + android:dataExtractionRules="@xml/data_extraction_rules" + android:fullBackupContent="@xml/backup_rules" + android:label="@string/app_name" + android:supportsRtl="true" + tools:targetApi="34" + android:theme="@style/Theme.AppCompat"> + <service + android:name=".QmlService" + android:enabled="true" + android:exported="true"/> + + <activity + android:name=".MainActivity" + android:configChanges="orientation|screenLayout|screenSize" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java new file mode 100644 index 0000000000..c619dce985 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java @@ -0,0 +1,20 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +package com.example.qml_in_java_based_android_project; + +import androidx.appcompat.app.AppCompatActivity; +import android.content.Intent; +import android.os.Bundle; + +public class MainActivity extends AppCompatActivity +{ + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.view_main); + startService(new Intent(this, QmlService.class)); + finish(); + } +} diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/QmlService.java b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/QmlService.java new file mode 100644 index 0000000000..0c9de067e6 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/QmlService.java @@ -0,0 +1,204 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +package com.example.qml_in_java_based_android_project; + +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.util.Size; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.Gravity; + +import android.widget.Button; +import android.widget.Switch; +import android.widget.TextView; + +import java.util.Random; +import java.util.function.Consumer; + +import org.qtproject.qt.android.QtQuickView; +import org.qtproject.qt.android.QtQmlStatus; +import org.qtproject.qt.android.QtQmlStatusChangeListener; +import org.qtproject.example.qml_in_android_service.Qml_in_android_service.Main; + +@SuppressLint("UseSwitchCompatOrMaterialCode") +public class QmlService extends Service implements QtQmlStatusChangeListener +{ + private static final String TAG = "QmlService"; + private WindowManager m_windowManager; + private QtQuickView m_serviceView; + private final Main m_serviceViewComponent = new Main(); + private View m_mainView; + + private TextView m_qmlBackgroundColorTextView; + private TextView m_qmlStatusTextView; + private View m_colorBox; + private Switch m_connectionSwitch; + private int m_qmlSignalListenerId; + + @Override + public IBinder onBind(Intent intent) + { + throw new UnsupportedOperationException("Not yet implemented"); + } + + @Override + public void onCreate() + { + m_windowManager = getSystemService(WindowManager.class); + + getScreenSize((size) -> { + // Get the available geometry, and split it between the Android and QML UIs + m_serviceView = addQuickView(new Size(size.getWidth() / 2, size.getHeight())); + m_serviceViewComponent.setStatusChangeListener(this); + m_serviceView.loadComponent(m_serviceViewComponent); + + m_mainView = addMainView(new Size(size.getWidth() / 2, size.getHeight())); + connectToNativeControls(m_mainView); + }); + } + + /* + Draw the "main" view on the left side of the screen, with the native controls + */ + private View addMainView(final Size size) + { + final LayoutInflater inflater = getSystemService(LayoutInflater.class); + + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( + size.getWidth(), size.getHeight(), + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, + PixelFormat.TRANSLUCENT); + layoutParams.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; + + View mainView = inflater.inflate(R.layout.view_main, null); + m_windowManager.addView(mainView, layoutParams); + return mainView; + } + + /* + Take size, and draw QtQuickView of that size on the right side of the screen + */ + private QtQuickView addQuickView(final Size size) + { + WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( + size.getWidth(), size.getHeight(), + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, + PixelFormat.TRANSLUCENT); + layoutParams.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; + + QtQuickView serviceView = new QtQuickView(this); + m_windowManager.addView(serviceView, layoutParams); + return serviceView; + } + + /* + Draw empty View that fills the parent (screen in this case) to discover the available size, + report to consumer + */ + private void getScreenSize(final Consumer<Size> screenSizeConsumer) + { + final WindowManager.LayoutParams params = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, + PixelFormat.TRANSLUCENT); + final View view = new View(this) { + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) + { + m_windowManager.removeView(this); + screenSizeConsumer.accept(new Size(right - left, bottom - top)); + } + }; + m_windowManager.addView(view, params); + } + + @Override + public void onDestroy() + { + if (m_windowManager != null) { + if (m_serviceView != null) { + m_windowManager.removeView(m_serviceView); + m_serviceView = null; + } + if (m_mainView != null) { + m_windowManager.removeView(m_mainView); + m_mainView = null; + } + } + } + + /* + Connect listeners to the native controls + */ + private void connectToNativeControls(final View mainView) + { + m_qmlBackgroundColorTextView = mainView.findViewById(R.id.qmlBackgroundColorText); + m_qmlStatusTextView = mainView.findViewById(R.id.qmlStatus); + m_colorBox = mainView.findViewById(R.id.box); + + m_connectionSwitch = mainView.findViewById(R.id.switch1); + m_connectionSwitch.setOnCheckedChangeListener( + (buttonView, isChecked) -> connectSwitchListener(isChecked)); + + final Button changeColorButton = mainView.findViewById(R.id.button); + changeColorButton.setOnClickListener(this::onChangeColorButtonListener); + } + + public void onChangeColorButtonListener(View view) + { + m_serviceViewComponent.setColorStringFormat(getRandomColorString()); + + final String qmlColor = m_serviceView.getProperty("colorStringFormat"); + m_qmlBackgroundColorTextView.setText(qmlColor); + m_colorBox.setBackgroundColor(Color.parseColor(qmlColor)); + } + + @Override + public void onStatusChanged(QtQmlStatus status) + { + m_qmlStatusTextView.setText( + String.format("%s %s", getResources().getString(R.string.qml_view_status), status)); + // Once QML is loaded and the signal listener switch is not checked, + // connect to onClicked() signal in main.qml + if (status == QtQmlStatus.READY && m_connectionSwitch.isChecked()) + connectSwitchListener(m_connectionSwitch.isChecked()); + } + + private void connectSwitchListener(boolean checked) + { + if (checked) { + m_qmlSignalListenerId = m_serviceView.connectSignalListener( + "onClicked", Object.class, this::onQmlChangeColorButtonClicked); + } else { + m_serviceView.disconnectSignalListener(m_qmlSignalListenerId); + } + } + + public void onQmlChangeColorButtonClicked(String signal, Object o) + { + m_mainView.setBackgroundColor(Color.parseColor(getRandomColorString())); + } + + private String getRandomColorString() + { + Random rand = new Random(); + return String.format("#%06x", rand.nextInt(0xffffff + 1)); + } +} diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/view_main.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/view_main.xml new file mode 100644 index 0000000000..65b6b3fe6c --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/view_main.xml @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="utf-8"?> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/mainLinear" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:baselineAligned="false" + android:background="#AF93DF"> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="8dp" + android:gravity="center_horizontal" + android:includeFontPadding="false" + android:text="@string/java" + android:textColor="#FFFFFF" + android:textSize="24sp" + android:textStyle="bold" /> + + <TextView + android:id="@+id/qmlStatus" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="16dp" + android:gravity="center_horizontal" + android:text="@string/qml_view_status" + android:textColor="#FFFFFF"/> + + <LinearLayout + android:id="@+id/buttonAndSwitchLayout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:orientation="horizontal" + android:layout_marginTop="16dp"> + + <LinearLayout + android:id="@+id/buttonLinearLayout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_weight="1"> + + <TextView + android:id="@+id/changeColorText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:maxLines="3" + android:text="@string/change_qml_background" + android:textColor="#FFFFFF" /> + + <Button + android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="8dp" + android:text="@string/button" + android:textSize="14sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/switchLinearLayout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_weight="1"> + + <TextView + android:id="@+id/switchText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:maxLines="3" + android:text="@string/connect_qml_button_signal_listener" + android:textColor="#FFFFFF" /> + + <Switch + android:id="@+id/switch1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:textOff="@string/off" + android:textOn="@string/on" + android:showText="true" + android:checked="true" + tools:ignore="UseSwitchCompatOrMaterialXml" /> + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:id="@+id/qmlColorLinear" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:padding="10dp"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_weight="1"> + + <TextView + android:id="@+id/qmlViewBackgroundText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:maxLines="2" + android:text="@string/qml_view_background_color" + android:textColor="#FFFFFF" /> + + <TextView + android:id="@+id/qmlBackgroundColorText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" + android:textColor="#FFFFFF" /> + </LinearLayout> + + <View + android:id="@+id/box" + android:layout_width="100dp" + android:layout_height="50dp" + android:layout_gravity="center_horizontal" + android:background="@android:color/transparent" + android:layout_weight="0"/> + </LinearLayout> +</LinearLayout> diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/values/strings.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000..39d33f40c9 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/values/strings.xml @@ -0,0 +1,12 @@ +<resources> + <string name="app_name">qml_in_java_based_android_project</string> + <string name="button">Change color</string> + <string name="java">Java</string> + <string name="change_qml_background">Tap button to change QML view background color</string> + <string name="connect_qml_button_signal_listener">QML Button listener connected</string> + <string name="on">On</string> + <string name="off">Off</string> + <string name="qml_view_status">QML view status: </string> + <string name="qml_view_background_color">QML view background color:</string> +</resources> + diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/backup_rules.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000000..04dd1acfe3 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + Sample backup rules file; uncomment and customize as necessary. + See https://developer.android.com/guide/topics/data/autobackup + for details. + Note: This file is ignored for devices older that API 31 + See https://developer.android.com/about/versions/12/backup-restore +--> +<full-backup-content> +</full-backup-content> + diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/data_extraction_rules.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000000..9840b57766 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + Sample data extraction rules file; uncomment and customize as necessary. + See https://developer.android.com/about/versions/12/backup-restore#xml-changes + for details. +--> +<data-extraction-rules> + <cloud-backup> + </cloud-backup> +</data-extraction-rules> + diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/build.gradle b/tests/manual/platforms/android/qml_in_java_based_android_project/build.gradle new file mode 100644 index 0000000000..b92d690313 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/build.gradle @@ -0,0 +1,4 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { +id 'com.android.application' version '7.4.1' apply false +} diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/gradle.properties b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle.properties new file mode 100644 index 0000000000..dacb776f4a --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle.properties @@ -0,0 +1,22 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true + diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/gradle/wrapper/gradle-wrapper.properties b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..62f495dfed --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/settings.gradle b/tests/manual/platforms/android/qml_in_java_based_android_project/settings.gradle new file mode 100644 index 0000000000..8a59ffb868 --- /dev/null +++ b/tests/manual/platforms/android/qml_in_java_based_android_project/settings.gradle @@ -0,0 +1,23 @@ +pluginManagement { + repositories { + google() + mavenCentral() + maven { + url "https://android.qt.io/maven/snapshots" + } + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven { + url "https://android.qt.io/maven/snapshots" + } + } +} + +rootProject.name = "qml_in_java_based_android_project" +include ':app' diff --git a/tests/manual/quickcontrols/CMakeLists.txt b/tests/manual/quickcontrols/CMakeLists.txt index e7f07e6110..fa3bf67e9d 100644 --- a/tests/manual/quickcontrols/CMakeLists.txt +++ b/tests/manual/quickcontrols/CMakeLists.txt @@ -10,6 +10,7 @@ if(LINUX) endif() add_subdirectory(headerview) add_subdirectory(imagine/musicplayer) +add_subdirectory(menus) add_subdirectory(qquickdialog) add_subdirectory(screenshots) add_subdirectory(sidepanel) diff --git a/tests/manual/quickcontrols/menus/CMakeLists.txt b/tests/manual/quickcontrols/menus/CMakeLists.txt new file mode 100644 index 0000000000..ce757613a1 --- /dev/null +++ b/tests/manual/quickcontrols/menus/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(menus VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Quick QuickControls2) + +qt_standard_project_setup(REQUIRES 6.8) + +qt_add_executable(appmenus + main.cpp +) + +qt_add_qml_module(appmenus + URI Menus + VERSION 1.0 + QML_FILES + Main.qml + SOURCES + cppsettings.cpp + cppsettings.h + main.cpp + RESOURCES + icons/warning.png + icons/warning@2x.png +) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +set_target_properties(appmenus PROPERTIES +# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appmenus + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +target_link_libraries(appmenus + PRIVATE + Qt6::Quick + Qt6::QuickControls2 +) diff --git a/tests/manual/quickcontrols/menus/Main.qml b/tests/manual/quickcontrols/menus/Main.qml new file mode 100644 index 0000000000..a75f2afd6c --- /dev/null +++ b/tests/manual/quickcontrols/menus/Main.qml @@ -0,0 +1,453 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtCore +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick.Dialogs + +ApplicationWindow { + id: window + width: 800 + height: 600 + visible: true + title: qsTr("Menus - style: %1").arg(currentStyle) + + required property string currentStyle + + Shortcut { + sequence: "Ctrl+Q" + onActivated: Qt.quit() + } + + Settings { + id: settings + + property alias windowX: window.x + property alias windowY: window.y + } + + menuBar: MenuBar { + visible: menuBarVisibleSwitch.checked + + Menu { + id: fileMenu + objectName: "file" + title: qsTr("&File") + popupType: popupTypeCombo.currentIndex + ContextAction { text: qsTr("&New...") } + ContextMenuItem { text: "menuItem" } + ContextAction { text: qsTr("&Open...") } + ContextAction { text: qsTr("&Save") } + ContextAction { text: qsTr("Save &As...") } + Menu { + title: qsTr("Sub...") + ContextAction { text: qsTr("Sub action 1") } + ContextAction { text: qsTr("Sub action 2") } + } + MenuSeparator { } + ContextAction { + text: qsTr("&Quit") + // This is needed for macOS since it takes priority over the Shortcut. + onTriggered: Qt.quit() + } + Action { + text: qsTr("Remove menu") + onTriggered: menuBar.removeMenu(fileMenu) + } + } + Menu { + id: editMenu + objectName: "edit" + title: qsTr("&Edit") + popupType: popupTypeCombo.currentIndex + ContextAction { + id: cutAction + text: qsTr("Cut") + enabled: textArea.selectedText.length > 0 + } + ContextAction { + text: qsTr("Copy") + enabled: textArea.selectedText.length > 0 + } + ContextAction { + text: qsTr("Paste") + enabled: textArea.activeFocus + } + + MenuSeparator {} + + Action { + text: qsTr("Checkable menu") + checkable: true + checked: true + } + Action { + text: qsTr("Remove menu") + onTriggered: menuBar.removeMenu(editMenu) + } + Menu { + id: editSubMenu + title: qsTr("Find / Replace") + Action { text: qsTr("&Find") } + } + + MenuSeparator {} + + ContextAction { + text: qsTr("Dummy Action") + shortcut: "Ctrl+I" + } + } + MenuBarItem { + id: explicitMenuBarItem + menu: Menu { + id: menuBarItemMenu + objectName: "MenuBarItem" + title: "MenuBarItem" + popupType: popupTypeCombo.currentIndex + ContextAction { text: qsTr("Action") } + Action { + text: qsTr("Remove menu") + onTriggered: menuBar.removeMenu(menuBarItemMenu) + } + } + } + } + + Component { + id: extraMenuComp + Menu { + id: extraMenu + objectName: "Extra" + title: qsTr("&Extra") + ContextAction { text: qsTr("&Trigger") } + Action { + text: qsTr("Remove Extra menu") + onTriggered: menuBar.removeMenu(extraMenu) + } + } + } + + ColumnLayout { + anchors.fill: parent + + Label { + text: qsTr("Right click on the window background to open a context menu. " + + "Right click on the TextArea to access its edit context menu.\n\n" + + "Things to check:\n\n" + + "- Do the menu items trigger their actions (check console for output)?\n" + + "- Do checkable menu items work?\n" + + "- Do the Edit menu items (in the MenuBar menu and edit context menu)" + + " work as expected with the TextArea?\n" + + " - Are they enabled/disabled as expected?\n" + + " - Does the TextArea keep focus after interacting with the Edit menu items?\n" + + "- Does adding and removing menu items work?\n" + + "- Do the menus in the MenuBar work?\n" + + "- Can you add and remove menus from the MenuBar?\n" + + "- Do shortcuts work?") + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: window.width * 0.5 + Layout.fillHeight: true + } + + GroupBox { + title: qsTr("Context menu") + + Layout.fillWidth: true + + ColumnLayout { + anchors.fill: parent + + RowLayout { + Label { + text: qsTr("Popup type") + } + + ComboBox { + id: popupTypeCombo + model: ["Default", "Item", "Window", "Native"] + onCurrentIndexChanged: CppSettings.popupType = currentIndex + currentIndex: CppSettings.popupType + } + } + + Row { + Button { + text: qsTr("Add action") + onClicked: backgroundContextMenu.appendAction() + } + Button { + text: qsTr("Remove action") + onClicked: backgroundContextMenu.removeLastAction() + } + + Button { + text: qsTr("Add sub-menu action") + onClicked: subMenu.appendAction() + } + Button { + text: qsTr("Remove sub-menu action") + onClicked: subMenu.removeLastAction() + } + } + } + } + + TextArea { + id: textArea + text: qsTr("Dummy TextArea to test disabled menu items") + + Layout.fillWidth: true + Layout.minimumHeight: 100 + + TapHandler { + objectName: "textAreaMouseTapHandler" + acceptedButtons: Qt.RightButton + onPressedChanged: if (pressed) editContextMenu.popup() + } + TapHandler { + objectName: "textAreaTouchTapHandler" + acceptedDevices: PointerDevice.TouchScreen + onLongPressed: editContextMenu.popup() + } + } + + Component { + id: menuBarItemComp + MenuBarItem { + } + } + + MessageDialog { + id: restartNeededDialog + buttons: MessageDialog.Ok + text: "Your current changes requires a restart to take effect!" + } + + GroupBox { + title: qsTr("MenuBar") + + Layout.fillWidth: true + + ColumnLayout { + anchors.fill: parent + + Row { + Switch { + text: qsTr("Don't use native menu bar") + checked: CppSettings.dontUseNativeMenuBar + + onClicked: { + CppSettings.dontUseNativeMenuBar = checked + restartNeededDialog.open() + } + } + Switch { + id: menuBarVisibleSwitch + text: qsTr("MenuBar visible") + checked: true + } + } + Row { + Button { + text: "Append menu" + onClicked: { + let menu = extraMenuComp.createObject(menuBar, { title: "Extra " + menuBar.count }) + menuBar.addMenu(menu) + } + } + Button { + text: "Prepend menu" + onClicked: { + let menu = extraMenuComp.createObject(menuBar, { title: "Extra " + menuBar.count }) + menuBar.insertMenu(0, menu) + } + } + Button { + text: qsTr("Add file menu") + onClicked: menuBar.addMenu(fileMenu) + } + Button { + text: "Change labels" + onClicked: { + fileMenu.title = "File changed" + cutAction.text = "Cut changed" + } + } + Button { + text: "toggle delegate" + onClicked: menuBar.delegate = menuBar.delegate ? null : menuBarItemComp + } + Switch { + text: "MenuBarItem visible" + checked: true + onCheckedChanged: explicitMenuBarItem.visible = checked + } + } + } + } + } + + TapHandler { + objectName: "backgroundMouseTapHandler" + acceptedButtons: Qt.RightButton + onPressedChanged: if (pressed) backgroundContextMenu.popup() + } + TapHandler { + objectName: "backgroundTouchTapHandler" + acceptedDevices: PointerDevice.TouchScreen + onLongPressed: backgroundContextMenu.popup() + } + + Component { + id: actionComponent + + Action {} + } + + component ContextAction: Action { + onCheckedChanged: (checked) => print("checked of \"" + text + "\" changed to " + checked) + onTriggered: print("triggered \"" + text + "\"") + } + + component ContextMenuItem: MenuItem { + onCheckedChanged: print("checked of \"" + text + "\" changed to " + checked) + onTriggered: print("triggered \"" + text + "\"") + } + + Menu { + id: backgroundContextMenu + objectName: "backgroundContextMenu" + popupType: popupTypeCombo.currentIndex + + function appendAction() { + let action = actionComponent.createObject(null, { text: qsTr("Extra context menu item") }) + backgroundContextMenu.addAction(action) + } + + function removeLastAction() { + // TODO: Can't use count here because it's 0: it uses contentModel->count(), but native menu items + // are not Qt Quick items, so we either need to document that you should use contentData.count + // or add an "actions" property. The problem with contentData is that it could contain + // non-Action objects. Another potential issue is that "It is not re-ordered when items are inserted or moved", + // making it unreliable as a general purpose container of actions if users add or remove them dynamically. + backgroundContextMenu.removeAction(backgroundContextMenu.actionAt(backgroundContextMenu.contentData.length - 1)) + } + + ContextAction { + text: qsTr("Context menu item") + shortcut: "A" + } + ContextMenuItem { + text: qsTr("Checkable context menu item") + checkable: true + } + ContextAction { + text: qsTr("Checked context menu item") + checkable: true + checked: true + shortcut: "C" + } + ContextAction { + text: qsTr("Disabled context menu item") + enabled: false + shortcut: "D" + } + ContextAction { + text: qsTr("Checked and disabled context menu item") + checkable: true + checked: true + enabled: false + shortcut: "E" + } + + MenuSeparator {} + + ContextAction { + text: qsTr("Context menu item with icon (name)") + icon.name: "mail-send" + } + + ContextAction { + text: qsTr("Context menu item with icon (source)") + icon.source: "qrc:/qt/qml/Menus/icons/warning.png" + } + + ContextAction { + text: qsTr("Context menu item with disabled icon (source)") + icon.source: "qrc:/qt/qml/Menus/icons/warning.png" + enabled: false + } + + MenuSeparator {} + + Menu { + id: subMenu + title: qsTr("Sub-menu") + objectName: title + popupType: backgroundContextMenu.popupType + + function appendAction() { + let action = actionComponent.createObject(null, { text: qsTr("Extra sub-menu item") }) + subMenu.addAction(action) + } + + function removeLastAction() { + subMenu.removeAction(subMenu.actionAt(subMenu.contentData.length - 1)) + } + + ContextAction { + text: qsTr("Sub-menu item") + } + ContextAction { + text: qsTr("Checkable sub-menu item") + checkable: true + shortcut: "G" + } + ContextAction { + text: qsTr("Checked sub-menu item") + checkable: true + checked: true + } + + MenuSeparator {} + + ContextAction { + text: qsTr("Disabled sub-menu item") + enabled: false + shortcut: "I" + } + ContextAction { + text: qsTr("Checked and disabled sub-menu item") + checkable: true + checked: true + enabled: false + shortcut: "J" + } + } + } + + Menu { + id: editContextMenu + objectName: "editContextMenu" + + ContextAction { + text: qsTr("Cut") + enabled: textArea.selectedText.length > 0 + } + ContextAction { + text: qsTr("Copy") + enabled: textArea.selectedText.length > 0 + } + ContextAction { + text: qsTr("Paste") + enabled: textArea.activeFocus + } + } +} + diff --git a/tests/manual/quickcontrols/menus/Menu.qml b/tests/manual/quickcontrols/menus/Menu.qml new file mode 100644 index 0000000000..0d18fca2ab --- /dev/null +++ b/tests/manual/quickcontrols/menus/Menu.qml @@ -0,0 +1,6 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick.Controls + +Menu {} diff --git a/tests/manual/quickcontrols/menus/cppsettings.cpp b/tests/manual/quickcontrols/menus/cppsettings.cpp new file mode 100644 index 0000000000..589cea916b --- /dev/null +++ b/tests/manual/quickcontrols/menus/cppsettings.cpp @@ -0,0 +1,43 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "cppsettings.h" + +#include <QCoreApplication> + +CppSettings::CppSettings(QObject *parent) : + QObject(parent), + mSettings("QtProject", "menus") +{ + QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar()); +} + +bool CppSettings::dontUseNativeMenuBar() const +{ + return mSettings.value("dontUseNativeMenuBar").toBool(); +} + +void CppSettings::setDontUseNativeMenuBar(bool dontUseNativeMenuBar) +{ + const bool oldValue = this->dontUseNativeMenuBar(); + if (dontUseNativeMenuBar == oldValue) + return; + + QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar); + mSettings.setValue("dontUseNativeMenuBar", dontUseNativeMenuBar); + emit dontUseNativeMenuBarChanged(); +} + +int CppSettings::popupType() const +{ + return mSettings.value("popupType").toInt(); +} + +void CppSettings::setPopupType(int newPopupType) +{ + const int oldValue = popupType(); + if (oldValue == newPopupType) + return; + mSettings.setValue("popupType", newPopupType); + emit popupTypeChanged(); +} diff --git a/tests/manual/quickcontrols/menus/cppsettings.h b/tests/manual/quickcontrols/menus/cppsettings.h new file mode 100644 index 0000000000..b6af1f9f09 --- /dev/null +++ b/tests/manual/quickcontrols/menus/cppsettings.h @@ -0,0 +1,38 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef CPPSETTINGS_H +#define CPPSETTINGS_H + +#include <QObject> +#include <QQmlEngine> +#include <QSettings> + +class CppSettings : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool dontUseNativeMenuBar READ dontUseNativeMenuBar WRITE setDontUseNativeMenuBar + NOTIFY dontUseNativeMenuBarChanged FINAL) + Q_PROPERTY(int popupType READ popupType WRITE setPopupType + NOTIFY popupTypeChanged FINAL) + QML_ELEMENT + QML_SINGLETON + +public: + explicit CppSettings(QObject *parent = nullptr); + + bool dontUseNativeMenuBar() const; + void setDontUseNativeMenuBar(bool dontUseNativeMenuBar); + + int popupType() const; + void setPopupType(int newPopupType); + +signals: + void dontUseNativeMenuBarChanged(); + void popupTypeChanged(); + +private: + QSettings mSettings; +}; + +#endif // CPPSETTINGS_H diff --git a/tests/manual/quickcontrols/menus/icons/warning.png b/tests/manual/quickcontrols/menus/icons/warning.png Binary files differnew file mode 100644 index 0000000000..590a61eb80 --- /dev/null +++ b/tests/manual/quickcontrols/menus/icons/warning.png diff --git a/tests/manual/quickcontrols/menus/icons/warning@2x.png b/tests/manual/quickcontrols/menus/icons/warning@2x.png Binary files differnew file mode 100644 index 0000000000..487fbafcfd --- /dev/null +++ b/tests/manual/quickcontrols/menus/icons/warning@2x.png diff --git a/tests/manual/quickcontrols/menus/main.cpp b/tests/manual/quickcontrols/menus/main.cpp new file mode 100644 index 0000000000..e9b4e6d5eb --- /dev/null +++ b/tests/manual/quickcontrols/menus/main.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include <QGuiApplication> +#include <QQmlApplicationEngine> +#include <QQuickStyle> + +int main(int argc, char *argv[]) +{ + QGuiApplication::setOrganizationName("QtProject"); + QGuiApplication::setApplicationName("menus"); + + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + engine.setInitialProperties({{ "currentStyle", QQuickStyle::name() }}); + QObject::connect( + &engine, + &QQmlApplicationEngine::objectCreationFailed, + &app, + []() { QCoreApplication::exit(-1); }, + Qt::QueuedConnection); + engine.loadFromModule("Menus", "Main"); + + return app.exec(); +} + diff --git a/tests/manual/svg/data/image/1.svg b/tests/manual/svg/data/image/1.svg new file mode 100644 index 0000000000..d5f27450c2 --- /dev/null +++ b/tests/manual/svg/data/image/1.svg @@ -0,0 +1,3 @@ +<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"> + <image xlink:href="data.png" height="200" width="200" /> +</svg> diff --git a/tests/manual/svg/data/image/2.svg b/tests/manual/svg/data/image/2.svg new file mode 100644 index 0000000000..3f71e5ca23 --- /dev/null +++ b/tests/manual/svg/data/image/2.svg @@ -0,0 +1,3 @@ +<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"> + <image xlink:href="qtlogo.png" height="200" width="200" /> +</svg> diff --git a/tests/manual/svg/data/image/3.svg b/tests/manual/svg/data/image/3.svg new file mode 100644 index 0000000000..85751587d9 --- /dev/null +++ b/tests/manual/svg/data/image/3.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg viewBox="0 0 210 297"> +<image width="200" height="200" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAAA8CAYAAAGPy61gAAAAAXNSR0IArs4c6QAAAJZlWElmTU0A KgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgExAAIAAAARAAAAWodp AAQAAAABAAAAbAAAAAAAAABIAAAAAQAAAEgAAAABQWRvYmUgSW1hZ2VSZWFkeQAAAAOgAQADAAAA AQABAACgAgAEAAAAAQAAAFSgAwAEAAAAAQAAADwAAAAAm/SbDAAAAAlwSFlzAAALEwAACxMBAJqc GAAAAi1pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6 bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRm PSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJk ZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8v bnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMu YWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgSW1h Z2VSZWFkeTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43Mjwv dGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmll bnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzI8L3RpZmY6WFJlc29sdXRpb24+ CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpg60/Z AAAXv0lEQVR4Ae1caZBdxXXuvve+bXaNFhAIJI0EWmZGCEaIJYVLBlxFlkpBbBGXKwRXYkOFwmAW B20uPYFGQrahAnHiiMTlCrHLCYqdhB/g2NiocDDgMEbSLEhCmhkJAVJmkWZ9672d7+v77tvfmzej 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 rkJggg== " id="image1" x="10" y="10" /> +</svg> diff --git a/tests/manual/svg/data/image/data.png b/tests/manual/svg/data/image/data.png Binary files differnew file mode 100644 index 0000000000..7b660be3de --- /dev/null +++ b/tests/manual/svg/data/image/data.png diff --git a/tests/manual/svg/data/image/qtlogo.png b/tests/manual/svg/data/image/qtlogo.png Binary files differnew file mode 100644 index 0000000000..7b660be3de --- /dev/null +++ b/tests/manual/svg/data/image/qtlogo.png diff --git a/tests/manual/tableview/abstracttablemodel/main.qml b/tests/manual/tableview/abstracttablemodel/main.qml index 5578e86dba..9c43af2f99 100644 --- a/tests/manual/tableview/abstracttablemodel/main.qml +++ b/tests/manual/tableview/abstracttablemodel/main.qml @@ -85,6 +85,22 @@ ApplicationWindow { } CheckBox { + id: movableColumnEnabled + checkable: true + checked: false + Layout.fillWidth: false + text: "Reorder columns" + } + + CheckBox { + id: movableRowEnabled + checkable: true + checked: false + Layout.fillWidth: false + text: "Reorder rows" + } + + CheckBox { id: enableAnimation checkable: true checked: true @@ -202,6 +218,14 @@ ApplicationWindow { text: "Clear selection" onClicked: tableView.selectionModel.clearSelection() } + Button { + text: "Clear column reordering" + onClicked: tableView.clearColumnReordering() + } + Button { + text: "Clear row reordering" + onClicked: tableView.clearRowReordering() + } } } @@ -450,7 +474,7 @@ ApplicationWindow { } } - TableView { + HorizontalHeaderView { id: topHeader objectName: "topHeader" anchors.left: centerScrollView.left @@ -465,8 +489,11 @@ ApplicationWindow { } delegate: Rectangle { + required property bool containsDrag implicitHeight: topHeader.height implicitWidth: 20 + border.width: containsDrag ? 1 : 0 + border.color: containsDrag ? window.palette.text : window.palette.alternateBase color: window.palette.alternateBase Label { anchors.centerIn: parent @@ -481,10 +508,11 @@ ApplicationWindow { syncView: tableView syncDirection: Qt.Horizontal + movableColumns: movableColumnEnabled.checked resizableColumns: resizableColumnsEnabled.checked } - TableView { + VerticalHeaderView { id: leftHeader objectName: "leftHeader" anchors.left: menu.right @@ -499,8 +527,11 @@ ApplicationWindow { } delegate: Rectangle { + required property bool containsDrag implicitHeight: 50 implicitWidth: leftHeader.width + border.width: containsDrag ? 1 : 0 + border.color: containsDrag ? window.palette.text : window.palette.alternateBase color: window.palette.alternateBase Label { anchors.centerIn: parent @@ -515,6 +546,7 @@ ApplicationWindow { syncView: tableView syncDirection: Qt.Vertical + movableRows: movableRowEnabled.checked resizableRows: resizableRowsEnabled.checked } |