From ac508832f2d23e6eeb62b0c5b2da83b7ddbb72bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tinja=20Paavosepp=C3=A4?= <tinja.paavoseppa@qt.io> Date: Thu, 17 Mar 2022 09:08:50 +0200 Subject: [PATCH] Add GUI for configuring build. Still largely WIP. Wizard UI for configuring the build. TODO: icons for checkbox, create data containers for stuff like component dependencies, error handling... --- CMakeLists.txt | 10 +- DirSelectionItem.qml | 29 ++++++ Footer.qml | 75 ++++++++++++++ Header.qml | 31 ++++++ PageBuilding.qml | 28 ++++++ PageModules.qml | 100 +++++++++++++++++++ PageStart.qml | 168 ++++++++++++++++++++++++++++++++ PageSummary.qml | 132 +++++++++++++++++++++++++ buildparams.cpp | 109 +++++++++++++++++++++ buildparams.h | 57 +++++++++++ icons/qt_logo_green_64x64px.png | Bin 0 -> 2318 bytes imports/QtStyle/Button.qml | 36 +++++++ imports/QtStyle/CheckBox.qml | 43 ++++++++ imports/QtStyle/Label.qml | 11 +++ imports/QtStyle/ProgressBar.qml | 42 ++++++++ imports/QtStyle/TextField.qml | 30 ++++++ imports/QtStyle/qmldir | 7 ++ imports/Theme/Theme.qml | 16 +++ imports/Theme/qmldir | 2 + main.cpp | 1 + main.qml | 107 +++++++++++++++++++- qml.qrc | 22 +++++ qtquickcontrols2.conf | 6 ++ 23 files changed, 1056 insertions(+), 6 deletions(-) create mode 100644 DirSelectionItem.qml create mode 100644 Footer.qml create mode 100644 Header.qml create mode 100644 PageBuilding.qml create mode 100644 PageModules.qml create mode 100644 PageStart.qml create mode 100644 PageSummary.qml create mode 100644 buildparams.cpp create mode 100644 buildparams.h create mode 100644 icons/qt_logo_green_64x64px.png create mode 100644 imports/QtStyle/Button.qml create mode 100644 imports/QtStyle/CheckBox.qml create mode 100644 imports/QtStyle/Label.qml create mode 100644 imports/QtStyle/ProgressBar.qml create mode 100644 imports/QtStyle/TextField.qml create mode 100644 imports/QtStyle/qmldir create mode 100644 imports/Theme/Theme.qml create mode 100644 imports/Theme/qmldir create mode 100644 qml.qrc create mode 100644 qtquickcontrols2.conf diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ebe4a3..00df331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.16) project(UnixsocketPlayground2 VERSION 0.1 LANGUAGES CXX) set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.2 COMPONENTS Quick REQUIRED) @@ -11,15 +12,20 @@ qt_add_executable(appUnixsocketPlayground2 main.cpp qunixsockettotcpserver.h qunixsockettotcpserver.cpp qunixsockettotcpbridge.h qunixsockettotcpbridge.cpp - qhttprequest.h qhttprequest.cpp + qhttprequest.h qhttprequest.cpp buildparams.h buildparams.cpp + qml.qrc ) qt_add_qml_module(appUnixsocketPlayground2 URI UnixsocketPlayground2 VERSION 1.0 - QML_FILES main.qml + QML_FILES main.qml DirSelectionItem.qml + PageStart.qml PageModules.qml Header.qml + PageBuilding.qml Footer.qml PageSummary.qml ) +set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/imports CACHE STRING "" FORCE) + set_target_properties(appUnixsocketPlayground2 PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} diff --git a/DirSelectionItem.qml b/DirSelectionItem.qml new file mode 100644 index 0000000..3193ba1 --- /dev/null +++ b/DirSelectionItem.qml @@ -0,0 +1,29 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +RowLayout { + id: root + + property alias text: label.text + property alias input: textField.text + + signal buttonClicked() + + spacing: 8 + + Label { + id: label + Layout.fillWidth: true + } + + TextField { + id: textField + } + + Button { + id: button + text: qsTr("Browse") + onClicked: root.buttonClicked() + } +} diff --git a/Footer.qml b/Footer.qml new file mode 100644 index 0000000..30b1811 --- /dev/null +++ b/Footer.qml @@ -0,0 +1,75 @@ +import QtQuick +import QtQuick.Controls +import Theme + +Item { + id: root + + property int currentIndex + property int pageCount + + signal back() + signal next() + signal quit() + signal build() + + Rectangle { + id: bottomDivider + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + color: Theme.colorLight + height: 1 + } + + Row { + id: rowButtons + anchors.right: parent.right + anchors.bottom: parent.bottom + padding: 12 + spacing: 8 + + Button { + id: buttonBack + text: qsTr("Back") + enabled: currentIndex > 0 && currentIndex < pageCount - 1 + onClicked: back() + } + + Button { + id: buttonNext + focus: true + enabled: currentIndex < pageCount - 1 + onClicked: { + if (currentIndex === pageCount - 2) { + build() + buttonQuit.focus = true + } + next() + } + + states: [ + State { + when: currentIndex < pageCount - 2 + PropertyChanges { + target: buttonNext + text: qsTr("Next") + } + }, + State { + when: currentIndex >= pageCount - 2 + PropertyChanges { + target: buttonNext + text: qsTr("Build") + } + } + ] + } + + Button { + id: buttonQuit + text: qsTr("Quit") + onClicked: quit() + } + } +} diff --git a/Header.qml b/Header.qml new file mode 100644 index 0000000..144e3a0 --- /dev/null +++ b/Header.qml @@ -0,0 +1,31 @@ +import QtQuick +import QtQuick.Controls + +Item { + id: header + height: qtIcon.height + 24 + + Label { + text: "Let's build Qt!" + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 12 + } + + Image { + id: qtIcon + source: "qrc:/icons/qt_logo_green_64x64px.png" + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 12 + } + + Rectangle { + id: divider + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + color: "#f3f3f4" + height: 1 + } +} diff --git a/PageBuilding.qml b/PageBuilding.qml new file mode 100644 index 0000000..24ae49a --- /dev/null +++ b/PageBuilding.qml @@ -0,0 +1,28 @@ +import QtQuick +import QtQuick.Controls + +Item { + id: pageBuilding + + Label { + id: title + text: "Building..." + } + + Label { + // TODO show details, errors etc + id: details + text: "Everything going great!" + anchors.top: title.bottom + anchors.topMargin: 24 + } + + ProgressBar { + id: progressBar + indeterminate: true + width: 500 + anchors.top: details.bottom + anchors.left: parent.left + anchors.topMargin: 24 + } +} diff --git a/PageModules.qml b/PageModules.qml new file mode 100644 index 0000000..09bdbee --- /dev/null +++ b/PageModules.qml @@ -0,0 +1,100 @@ +import QtQuick +import QtQuick.Controls +import UnixsocketPlayground2 + +Item { + id: root + + property var moduleNames: ["qtbase", "qtdeclarative", "qtremoteobjects", "qt5compat", "qttools", + "qtimageformats", "qtquicktimeline", "qtshadertools", "qtmultimedia"] + property var requiredModules: [] // TODO add required submodules to component + + property BuildParams buildParams: null + + onBuildParamsChanged: { + if (buildParams) + setModules() + + } + + Label { + id: label + text: qsTr("Choose what modules you would like to include.") + + qsTr(" Some modules may be selected due to being required by add-ons selected in the previous page") + width: parent.width + } + + ScrollView { + id: scrollView + anchors.left: parent.left + anchors.top: label.bottom + anchors.topMargin: 28 + anchors.right: parent.horizontalCenter + height: 400 + ScrollBar.vertical.policy: ScrollBar.AlwaysOn + + Column { + id: moduleCheckBoxes + spacing: 8 + + Repeater { + id: repeater + CheckBox { + text: modelData + enabled: !isModuleRequired(modelData) + checked: !enabled + } + } + } + } + + Label { + id: labelBranch + text: qsTr("Choose the branch to checkout:") + anchors.left: scrollView.right + anchors.leftMargin: 12 + anchors.top: label.bottom + anchors.topMargin: 28 + } + + TextField { + id: fieldBranch + anchors.left: scrollView.right + anchors.leftMargin: 12 + anchors.top: labelBranch.bottom + anchors.topMargin: 8 + anchors.right: parent.right + text: "dev" + } + + CheckBox { + id: chbSubmodulesUseSameBranch + anchors.left: scrollView.right + anchors.leftMargin: 12 + anchors.top: fieldBranch.bottom + anchors.topMargin: 24 + text: "Use the same branch for submodules" + } + + function isModuleRequired(moduleName) { + for (var i = 0; i < requiredModules.length; i++) { + if (requiredModules[i] === moduleName) { + return true + } + + } + return false + } + + function setModules() { + repeater.model = [] + requiredModules = [] + requiredModules.push("qtbase") + if (buildParams.isComponentSelected("Qt Android Automotive")) { + for (var i = 1; i < moduleNames.length - 1; i++) { + requiredModules.push(moduleNames[i]) + } + } + repeater.model = moduleNames + } +} diff --git a/PageStart.qml b/PageStart.qml new file mode 100644 index 0000000..6ac1932 --- /dev/null +++ b/PageStart.qml @@ -0,0 +1,168 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt.labs.platform +import UnixsocketPlayground2 + +Item { + id: root + property url qtDir: qtDirSelection.input + property url sdkDir: sdkSelection.input + property url ndkDir: ndkSelection.input + + property BuildParams buildParams: null + + onBuildParamsChanged: console.log("boo " + buildParams) + + Label { + id: label + text: qsTr("Choose what to build and where to install.") + anchors.left: parent.left + anchors.right: parent.right + } + + DirSelectionItem { + id: qtDirSelection + text: qsTr("Qt installation folder:") + anchors.left: parent.left + anchors.top: label.bottom + anchors.right: parent.right + anchors.topMargin: 28 + + onButtonClicked: { + folderDialog.currentItem = this + folderDialog.open() + } + } + + Column { + id: qtVariantsCheckboxes + anchors.left: parent.left + anchors.top: qtDirSelection.bottom + anchors.topMargin: 28 + anchors.right: parent.horizontalCenter + anchors.rightMargin: 12 + height: 8 * 32 + spacing: 8 + + Label { + text: qsTr("Choose which components you would like to build and install.") + width: parent.width + } + + ButtonGroup { + id: childGroup + exclusive: false + checkState: chbAndroid.checkState + } + + CheckBox { + text: "GCC 64" + onCheckedChanged: componenSelectedChanged(text, checked) + } + + CheckBox { + id: chbAndroid + text: "Android" + checkState: childGroup.checkState + } + + CheckBox { + text: "arm64 v8a" + leftPadding: 8 + visible: chbAndroid.checkState === Qt.Checked + || chbAndroid.checkState === Qt.PartiallyChecked + ButtonGroup.group: childGroup + onCheckedChanged: componenSelectedChanged(text, checked) + } + + CheckBox { + text: "arm7" + leftPadding: 8 + visible: chbAndroid.checkState === Qt.Checked + || chbAndroid.checkState === Qt.PartiallyChecked + ButtonGroup.group: childGroup + onCheckedChanged: componenSelectedChanged(text, checked) + } + + CheckBox { + text: "x86" + leftPadding: 8 + visible: chbAndroid.checkState === Qt.Checked + || chbAndroid.checkState === Qt.PartiallyChecked + ButtonGroup.group: childGroup + onCheckedChanged: componenSelectedChanged(text, checked) + } + + CheckBox { + text: "x86 64" + leftPadding: 8 + visible: chbAndroid.checkState === Qt.Checked + || chbAndroid.checkState === Qt.PartiallyChecked + ButtonGroup.group: childGroup + onCheckedChanged: componenSelectedChanged(text, checked) + } + + CheckBox { + text: "Qt Android Automotive" + enabled: chbAndroid.checkState === Qt.Checked + || chbAndroid.checkState === Qt.PartiallyChecked + onCheckedChanged: componenSelectedChanged(text, checked) + } + } + + Label { + id: labelAndroidDirs + anchors.top: qtVariantsCheckboxes.bottom + anchors.topMargin: 32 + text: qsTr("Choose the location of Android SDK and NDK root folders.") + enabled: chbAndroid.checkState !== Qt.Unchecked + } + + DirSelectionItem { + id: sdkSelection + text: qsTr("Android SDK root folder:") + anchors.left: parent.left + anchors.top: labelAndroidDirs.bottom + anchors.right: parent.right + anchors.topMargin: 24 + enabled: chbAndroid.checkState !== Qt.Unchecked + + onButtonClicked: { + folderDialog.currentItem = this + folderDialog.open() + } + } + + DirSelectionItem { + id: ndkSelection + text: qsTr("Android NDK root folder:") + anchors.left: parent.left + anchors.top: sdkSelection.bottom + anchors.right: parent.right + anchors.topMargin: 18 + enabled: chbAndroid.checkState !== Qt.Unchecked + + onButtonClicked: { + folderDialog.currentItem = this + folderDialog.open() + } + } + + function componenSelectedChanged(componentName, selected) { + if (selected) + buildParams.addComponent(componentName) + else + buildParams.removeComponent(componentName) + } + + FolderDialog { + id: folderDialog + + property DirSelectionItem currentItem + + onAccepted: { + currentItem.input = folder + } + } +} diff --git a/PageSummary.qml b/PageSummary.qml new file mode 100644 index 0000000..0dadd69 --- /dev/null +++ b/PageSummary.qml @@ -0,0 +1,132 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import Theme +import UnixsocketPlayground2 + +Item { + id: pageSummary + + property var variantsToBuild: ["Qt GCC", "Qt for Android", "Qt Android Automotive"] + property var modulesToBuild: ["my bow", "my sword", "and my axe!"] + + property BuildParams buildParams: null + + onBuildParamsChanged: { + if (buildParams) { + if (buildParams.isComponentSelected("Qt Android Automotive")) { + gitCredentials.enabled = true + } + } + } + + Item { + id: gitCredentials + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: 160 + enabled: true // TODO if contains QTAA + visible: enabled // TODO a Loader + + Label { + id: labelGitCredentials + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + text: qsTr("You have chosen to build some components that have restricted access. ") + + qsTr("Please enter your credentials for checking out the repositories. ") + + qsTr("Make sure you have set up your account according to these instructions: ") + + qsTr("<a href=\"https://wiki.qt.io/Setting_up_Gerrit\">Setting up Gerrit</a>") + linkColor: Theme.colorHighlight + onLinkActivated: (link)=> Qt.openUrlExternally(link) + } + + RowLayout { + id: rowUsername + anchors.left: parent.left + anchors.top: labelGitCredentials.bottom + anchors.topMargin: 24 + anchors.right: parent.right + anchors.rightMargin: 104 + + Label { + id: labelUsername + text: "Gerrit username:" + Layout.fillWidth: true + } + + TextField { + id: username + } + } + + DirSelectionItem { + id: gitKey + anchors.left: parent.left + anchors.top: rowUsername.bottom + anchors.topMargin: 18 + anchors.right: parent.right + text: qsTr("Git private key location:") + + onButtonClicked: { + fileDialog.open() + } + } + } + + Label { + id: label + anchors.left: parent.left + anchors.top: gitCredentials.bottom + anchors.topMargin: 28 + anchors.right: parent.horizontalCenter + text: "You will be building the following Qt components:" + } + + Column { + anchors.left: parent.left + anchors.top: label.bottom + anchors.topMargin: 12 + anchors.right: parent.horizontalCenter + anchors.bottom: parent.bottom + + Repeater { + model: buildParams ? buildParams.selectedComponents : [] + Label { + text: modelData + } + } + } + + Label { + id: labelModules + anchors.left: parent.horizontalCenter + anchors.leftMargin: 24 + anchors.top: gitCredentials.bottom + anchors.topMargin: 28 + anchors.right: parent.right + text: "Submodules:" + } + + ListView { + anchors.left: parent.horizontalCenter + anchors.leftMargin: 24 + anchors.top: label.bottom + anchors.topMargin: 12 + anchors.right: parent.right + anchors.bottom: parent.bottom + model: modulesToBuild + + delegate: Label { + text: modelData + } + } + + FileDialog { + id: fileDialog + + onAccepted: gitKey.input = selectedFile + } +} diff --git a/buildparams.cpp b/buildparams.cpp new file mode 100644 index 0000000..fef7b92 --- /dev/null +++ b/buildparams.cpp @@ -0,0 +1,109 @@ +#include "buildparams.h" + +BuildParams::BuildParams(QObject *parent) + : QObject{parent} +{ +} + +void BuildParams::addComponent(const QString &component) +{ + if (!m_selectedComponents.contains(component)) { + m_selectedComponents.append(component); + emit selectedComponentsChanged(); + } +} + +void BuildParams::addSubmodule(const QString &submodule) +{ + if (!m_selectedSubmodules.contains(submodule)) { + m_selectedSubmodules.append(submodule); + emit selectedSubmodulesChanged(); + } +} + +void BuildParams::removeComponent(const QString &component) +{ + if (m_selectedComponents.removeOne(component)) + emit selectedComponentsChanged(); +} + +void BuildParams::removeSubmodule(const QString &submodule) +{ + if (m_selectedSubmodules.removeOne(submodule)) + emit selectedSubmodulesChanged(); +} + +bool BuildParams::isComponentSelected(const QString &component) +{ + return m_selectedComponents.contains(component); +} + +bool BuildParams::isSubmoduleSelected(const QString &submodule) +{ + return m_selectedSubmodules.contains(submodule); +} + +QUrl BuildParams::qtDir() const +{ + return m_qtDir; +} + +QUrl BuildParams::sdkDir() const +{ + return m_sdkDir; +} + +QUrl BuildParams::ndkDir() const +{ + return m_ndkDir; +} + +QString BuildParams::userName() const +{ + return m_userName; +} + +QUrl BuildParams::keyLocation() const +{ + return m_keyLocation; +} + +void BuildParams::setQtDir(const QUrl &url) +{ + if (url != m_qtDir) { + m_qtDir = url; + emit qtDirChanged(); + } +} + +void BuildParams::setSdkDir(const QUrl &url) +{ + if (url != m_sdkDir) { + m_sdkDir = url; + emit sdkDirChanged(); + } +} + +void BuildParams::setNdkDir(const QUrl &url) +{ + if (url != m_ndkDir) { + m_ndkDir = url; + emit ndkDirChanged(); + } +} + +void BuildParams::setUserName(const QString &userName) +{ + if (userName != m_userName) { + m_userName = userName; + emit userNameChanged(); + } +} + +void BuildParams::setKeyLocation(const QUrl &url) +{ + if (url != m_keyLocation) { + m_keyLocation = url; + emit keyLocationChanged(); + } +} diff --git a/buildparams.h b/buildparams.h new file mode 100644 index 0000000..be5c6ac --- /dev/null +++ b/buildparams.h @@ -0,0 +1,57 @@ +#ifndef BUILDPARAMS_H +#define BUILDPARAMS_H + +#include <QObject> +#include <QQmlEngine> + +class BuildParams : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUrl qtDir READ qtDir WRITE setQtDir NOTIFY qtDirChanged) + Q_PROPERTY(QUrl sdkDir READ sdkDir WRITE setSdkDir NOTIFY sdkDirChanged) + Q_PROPERTY(QUrl ndkDir READ ndkDir WRITE setNdkDir NOTIFY ndkDirChanged) + Q_PROPERTY(QStringList selectedComponents MEMBER m_selectedComponents NOTIFY selectedComponentsChanged) + Q_PROPERTY(QStringList selectedSubmodules MEMBER m_selectedSubmodules NOTIFY selectedSubmodulesChanged) + Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged) + Q_PROPERTY(QUrl keyLocation READ keyLocation WRITE setKeyLocation NOTIFY keyLocationChanged) + QML_ELEMENT + +public: + explicit BuildParams(QObject *parent = nullptr); + Q_INVOKABLE void addComponent(const QString &component); + Q_INVOKABLE void addSubmodule(const QString &submodule); + Q_INVOKABLE void removeComponent(const QString &component); + Q_INVOKABLE void removeSubmodule(const QString &submodule); + Q_INVOKABLE bool isComponentSelected(const QString &component); + Q_INVOKABLE bool isSubmoduleSelected(const QString &submodule); + QUrl qtDir() const; + QUrl sdkDir() const; + QUrl ndkDir() const; + QString userName() const; + QUrl keyLocation() const; + void setQtDir(const QUrl &url); + void setSdkDir(const QUrl &url); + void setNdkDir(const QUrl &url); + void setUserName(const QString &userName); + void setKeyLocation(const QUrl &url); + +private: + QUrl m_qtDir; + QUrl m_sdkDir; + QUrl m_ndkDir; + QStringList m_selectedComponents; + QStringList m_selectedSubmodules; + QString m_userName; + QUrl m_keyLocation; + +signals: + void qtDirChanged(); + void sdkDirChanged(); + void ndkDirChanged(); + void selectedComponentsChanged(); + void selectedSubmodulesChanged(); + void userNameChanged(); + void keyLocationChanged(); +}; + +#endif // BUILDPARAMS_H diff --git a/icons/qt_logo_green_64x64px.png b/icons/qt_logo_green_64x64px.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb2e01d3895ed7d1a81e91ed5393b474d041671 GIT binary patch literal 2318 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE<t`_ZS!$BuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztFl%LoM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTc<hj*9RNP;kyKN>wn`Gt*5rG&WK& zx70H<wKTFY(NQomFf`LQFwr-()HO7=GBma_F;IX4B|8P1qLehNAQv~NT}3Hrwn`Z# zB?VUc`sL;2dgaD?`9<mahL)C=`UXb&Mn<|tDQUXJm3bwJ6}oxF$}kgLQj3#|G7CyF z^YauyCMG83mzLNnDM5{`$Sr^yn^z1CrsVuw{ffi_eM3D1ke48S%`Nct#ji9s7p}Uv zBq$Z(UaSTehg24%>IbD3=a&{Grv{~_DTCZpVC7ttnpl!w6q28x0}I7~jQo=P;*9(P z1!reasF~`SDrop7CTHe>gf+qXe0{Av^NLFn^O93NU2K&qatrh_GgGWAj4g~Tja&>& z4V;|}4PDJFEL|*|EKCe6OdVY;joeINdR_99OLJ56N?>|Z5PA)9>IEeUP_S6Jq!wkC zrKY$Q<>xAZy>69>(=E=fIL(9VO~L6FXE&UB_3adF^g$7f6yY$TAQv|f6Pz|d>C{dE zkpWWkQf!rql<e&oKOAynU|_BCba4!+xb-HwIwv?)#J+ZW^!9D9Pn|k;XNKQ$o`@Mg z4k!w$?3$3;BhYO8kzcr3?O&_aWBE3pzs|{5T#|jRZg7#4nknRbq^Ci_jl)MkxoHFM zx18M@%d)S3-Ma1i``x>ieZP2o@7nFL?`(ZHe|uAX=kxCSme0%2-A!R}Y?$H7rzFnF zfPjMCL28p#|2|C?FJE!7KkiGO@Lf)U=8v9?0^J|iFm#-(U}H!!p2yT6(c90g5cb%U z;Yg0nN#>%|Jv@8EUcYZO{q=i6SU7L0m+}h{s}3Q-5AMwdlKXg@8>270-^=rD!sZ1G z8K<v(C_6oQ!|Eh!o#5%|CeQir$8R|QPxQ~r-P6j}I7V`53ohs^D*eaSlFV(%=+G9^ zQ0~7bB9P^7Y3zn|DW=bNvQ&Ll5a6@e?`yg4=nsZHk>90UuU9^GEofW*DVqC4YEcDu ztc3hyasPA0Q|E5Ddudj=_ybkh7l&qhNlE@%`N8DNPQQbt{{_yt*({i}azRWi+ga7@ zgw2`CE1qhd`f)e({GrP8t_4qC^l>pUm_3qw?br5i#%q-tlW&%*>*tmHXJWrtSpR&T z`2w%x-q)r@rf)Wt9cW*?ZD}xHzKI=+o5-9MjW4bC*ni4A^}wWY(f`-Y`OYmJL0_Uz zn>B{5i?mW-aP)_Q^Y;5Uz1g;v7|9hKn0d4KglyC!tDHYpPn6Pa|2`?NaVqdS8WbOL zJmPWS<--qpD>SXXAJU2W@K2A2!S`3_l=pHahT=9e^Xm@PwlOhG+p4<y5ktb`-C1#7 zR{vQ=%x?r~%QIN)W;pki?bgTRKW!%Oo}cySu1@(bg=B}RX_n6A#s;S{dw;H&e@5)( zHQf^u0qeAqU#L|sG2n4%y(RQNFKp(c`RmW}A5ed6`{cP*Ebo?C=E0A99~)FGw(H8X zdLzWfur}uOg-WI3Ip)V?8vS|-ym*ctG7yqczu)aMf$u>7y7`}uvy^hB?fP{5&m8k( ztU+oI#A0|ZoGi7xIio@1^eu0O1_Qx!zM^3Y{VEpmtlt9JOsB21%wID}J94x0LFNbP zJ3aO;n(_HqRfyMRRRL}>JBE85{ZnNMMZ3GK()rd(D=M|}GerM-=#^BUpSW|G(%W6E zoCh>co&RFp`nw_KiC?Vl;$M#ssoi|kp1|-RNX&Sv%gSqEPHVSWJvKFyxVHHUd-&ud za~QbeFFfIA(0RUhy2P&KYh@+R>IS`7aQ72Sudslp_D<GmI}*|sK5k+vxKlc7>&lNI zuGXHJlR5Jiy^H<HB{7w)>)-X8bu;1$)YnSBIJBLA=H@zveK+im9N#`QKlRGX=zzKP zcm5jlD9@kwbG>>-kmL!e{a5$2Ui9ozQuuz8f2q!_f-0YsPV4Dg9i0PhcPJSzn4;;y zW&2`3>$Xn)Rz`-?>ED<O>NACxE{cBh;7aj|x4FW<6D=&JH5n;?{}9vUyNp+)cJV$% z^}<GT`J<J;uQuitw5U~HV`8aEwCC6x?0&iL=v%X0rwx<1&r7LlJN5mpKL7u(QH}9W zTb5)+zv9}9l|K@Hxws|gv$-wE-XNX#qkU2z=MknqS(9?+@m$p2`Rvlx3lTN^UfrQ7 z&CZQ~KF5EvU>Dme8J3}?S^O)&ptk%;vfu9qrP*7wPvkUNU$8jW!~S+pX305*6D@yk zNZnJ8Ojz_r@&@<x=j(LlW=&Yn!`k-n#M@+^zw@liCeKvzFABM^XwUJFraLlz%I$Vt zUg{p#b6hesfWcsGY)+ZlDdl5dHRfxxn*R&=T%Ne}!iM?tEV*x=>7UFfZ0~3N#D?j) z&HlowbrZB7Z&q@;d4fIJY}4L(C*?i<%s=*=m%(S=51|z?Qu-NUCpK@8(idZxB&E;B s5G3Vq<oNPGo2#A>0}Lijt7nm5coV^VX1a5*8>ofi>FVdQ&MBb@0GSG@$p8QV literal 0 HcmV?d00001 diff --git a/imports/QtStyle/Button.qml b/imports/QtStyle/Button.qml new file mode 100644 index 0000000..c2db259 --- /dev/null +++ b/imports/QtStyle/Button.qml @@ -0,0 +1,36 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import Theme + +T.Button { + id: button + + implicitWidth: background.implicitWidth + implicitHeight: background.implicitHeight + + Keys.onEnterPressed: clicked() + Keys.onReturnPressed: clicked() + + contentItem: Text { + text: button.text + font: button.font + opacity: enabled ? 1.0 : 0.3 + color: button.hovered && button.enabled ? Theme.colorDark + : button.focus ? Theme.colorLight : Theme.colorHighlight + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Rectangle { + color: button.hovered && button.enabled ? Theme.colorHighlight : "transparent" + border.width: 1 + border.color: button.hovered && button.enabled ? Theme.colorHighlight + : button.focus ? Theme.colorLight : Theme.colorHighlight + implicitWidth: 96 + implicitHeight: 28 + opacity: enabled ? 1.0 : 0.3 + radius: 2 + } +} diff --git a/imports/QtStyle/CheckBox.qml b/imports/QtStyle/CheckBox.qml new file mode 100644 index 0000000..59a7929 --- /dev/null +++ b/imports/QtStyle/CheckBox.qml @@ -0,0 +1,43 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import Theme + +T.CheckBox { + id: checkBox + + font: Theme.font + implicitHeight: indicator.implicitHeight + implicitWidth: contentItem.implicitWidth + indicator.implicitWidth + spacing: 8 + + indicator: Rectangle { + implicitWidth: 20 + implicitHeight: 20 + x: checkBox.leftPadding + y: parent.height / 2 - height / 2 + radius: 2 + color: (checkBox.checkState === Qt.Checked || checkBox.checkState === Qt.PartiallyChecked) + ? (checkBox.enabled ? (checkBox.hovered ? Theme.colorAccent : Theme.colorHighlight) : Theme.colorHighlightDark) + : "transparent" + border.width: 2 + border.color: (checkBox.checkState === Qt.Checked || checkBox.checkState === Qt.PartiallyChecked) + ? (checkBox.enabled ? (checkBox.hovered ? Theme.colorAccent : Theme.colorHighlight) : Theme.colorHighlightDark) + : Theme.colorHighlight + + Image { + anchors.centerIn: parent + visible: checkBox.checkState !== Qt.Unchecked + // TODO add icon + } + } + + contentItem: Text { + text: checkBox.text + font: checkBox.font + opacity: enabled ? 1.0 : 0.3 + color: Theme.colorLight + verticalAlignment: Text.AlignVCenter + leftPadding: checkBox.indicator.width + checkBox.spacing + } +} diff --git a/imports/QtStyle/Label.qml b/imports/QtStyle/Label.qml new file mode 100644 index 0000000..09e78b1 --- /dev/null +++ b/imports/QtStyle/Label.qml @@ -0,0 +1,11 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import Theme + +T.Label { + color: Theme.colorLight + wrapMode: Text.WordWrap + font: Theme.font + opacity: enabled ? 1.0 : 0.3 +} diff --git a/imports/QtStyle/ProgressBar.qml b/imports/QtStyle/ProgressBar.qml new file mode 100644 index 0000000..2668b03 --- /dev/null +++ b/imports/QtStyle/ProgressBar.qml @@ -0,0 +1,42 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import Theme + +T.ProgressBar { + id: progressBar + implicitWidth: background.implicitWidth + implicitHeight: background.implicitHeight + + background: Rectangle { + implicitWidth: 200 + implicitHeight: 24 + color: "transparent" + border.color: Theme.colorHighlight + border.width: 1 + radius: 2 + z: 2 + } + + contentItem: Item { + implicitWidth: progressBar.implicitWidth + implicitHeight: progressBar.implicitHeight + clip: true + z: 1 + + Rectangle { + width: parent.width > 0 ? parent.width / 2 : parent.implicitWidth / 2 + height: parent.height > 0 ? parent.height : parent.implicitHeight + radius: 2 + color: Theme.colorHighlightDark + + XAnimator on x { + from: -progressBar.width + to: progressBar.width + duration: 1500 + running: progressBar.indeterminate + loops: Animation.Infinite + } + } + } +} diff --git a/imports/QtStyle/TextField.qml b/imports/QtStyle/TextField.qml new file mode 100644 index 0000000..ec38e34 --- /dev/null +++ b/imports/QtStyle/TextField.qml @@ -0,0 +1,30 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import Theme + +T.TextField { + id: textField + + implicitWidth: background.implicitWidth + implicitHeight: background.implicitHeight + color: Theme.colorHighlight + padding: 6 + bottomPadding: 3 + topPadding: 3 + selectByMouse: true + selectionColor: Theme.colorHighlightDark + selectedTextColor: Theme.colorHighlight + verticalAlignment: TextInput.AlignVCenter + font: Theme.font + opacity: enabled ? 1.0 : 0.3 + + background: Rectangle { + color: "transparent" + border.width: 1 + border.color: Theme.colorHighlight + implicitWidth: 400 + implicitHeight: 28 + radius: 2 + } +} diff --git a/imports/QtStyle/qmldir b/imports/QtStyle/qmldir new file mode 100644 index 0000000..37e35b7 --- /dev/null +++ b/imports/QtStyle/qmldir @@ -0,0 +1,7 @@ +module QtStyle + +Button 1.0 Button.qml +CheckBox 1.0 CheckBox.qml +Label 1.0 Label.qml +ProgressBar 1.0 ProgressBar.qml +TextField 1.0 TextField.qml diff --git a/imports/Theme/Theme.qml b/imports/Theme/Theme.qml new file mode 100644 index 0000000..87ae9b3 --- /dev/null +++ b/imports/Theme/Theme.qml @@ -0,0 +1,16 @@ +pragma Singleton + +import QtQuick + +QtObject { + readonly property color colorLight: "#f3f3f4" + readonly property color colorDark: "#09102b" + readonly property color colorHighlight: "#41cd52" + readonly property color colorHighlightDark: Qt.darker(colorHighlight, 2.0) + readonly property color colorAccent: "#ffe353" + + property font font + font.pixelSize: 14 + font.family: "Titillium" +} + diff --git a/imports/Theme/qmldir b/imports/Theme/qmldir new file mode 100644 index 0000000..4a58c13 --- /dev/null +++ b/imports/Theme/qmldir @@ -0,0 +1,2 @@ +module Theme +singleton Theme 1.0 Theme.qml diff --git a/main.cpp b/main.cpp index 4d66376..a034f4d 100644 --- a/main.cpp +++ b/main.cpp @@ -11,6 +11,7 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; + engine.addImportPath(":/imports"); const QUrl url(u"qrc:/UnixsocketPlayground2/main.qml"_qs); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { diff --git a/main.qml b/main.qml index 23eea85..8643a71 100644 --- a/main.qml +++ b/main.qml @@ -1,18 +1,117 @@ import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt.labs.platform +import QtQuick.Dialogs +import Theme import HttpRequest +import UnixsocketPlayground2 Window { - width: 640 - height: 480 + id: mainWindow + width: 1020 + height: 720 visible: true - title: qsTr("QtAA Docker build") + title: qsTr("You're a wizard, Harry") + color: Theme.colorDark + + BuildParams { + id: buildParameters + + qtDir: pageStart.qtDir + ndkDir: pageStart.ndkDir + sdkDir: pageStart.sdkDir + } + + Header { + id: header + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + } + + Item { + id: content + anchors.left: parent.left + anchors.top: header.bottom + anchors.right: parent.right + anchors.bottom: footer.top + + Column { + id: steps + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 24 + spacing: 12 + width: 240 + + Repeater { + model: ["What to build", "Submodules", "Summary", "Building"] + Label { + text: modelData + color: index <= stackLayout.currentIndex ? Theme.colorLight : Theme.colorHighlight + font.bold: index === stackLayout.currentIndex + } + } + } + + StackLayout { + id: stackLayout + anchors.left: steps.right + anchors.top: parent.top + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 24 + currentIndex: 0 + clip: true + + PageStart { + id: pageStart + buildParams: buildParameters + } + + PageModules { + id: pageModules + buildParams: StackLayout.isCurrentItem ? buildParameters : null // just a fast way to avoid page setting values before it's shown + } + + PageSummary { + id: pageSummary + buildParams: StackLayout.isCurrentItem ? buildParameters : null + } + + PageBuilding { + id: pageBuilding + } + } + } + + Footer { + id: footer + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + currentIndex: stackLayout.currentIndex + pageCount: stackLayout.count + + onNext: stackLayout.currentIndex++ + onBack: stackLayout.currentIndex-- + onBuild: startBuild() + onQuit: Qt.quit() + } HttpRequest { url: "http://localhost:2323/info" running: true onResponseBodyChanged: function(responseBody) { - console.log(responseBodys) + console.log(responseBody) } } + + function startBuild() { + console.log("building so hard") + } } diff --git a/qml.qrc b/qml.qrc new file mode 100644 index 0000000..be8a9f4 --- /dev/null +++ b/qml.qrc @@ -0,0 +1,22 @@ +<RCC> + <qresource prefix="/"> + <file>qtquickcontrols2.conf</file> + <file>imports/QtStyle/qmldir</file> + <file>imports/QtStyle/Button.qml</file> + <file>main.qml</file> + <file>icons/qt_logo_green_64x64px.png</file> + <file>PageStart.qml</file> + <file>PageModules.qml</file> + <file>DirSelectionItem.qml</file> + <file>imports/QtStyle/Label.qml</file> + <file>imports/QtStyle/TextField.qml</file> + <file>imports/QtStyle/ProgressBar.qml</file> + <file>Header.qml</file> + <file>imports/Theme/qmldir</file> + <file>imports/Theme/Theme.qml</file> + <file>imports/QtStyle/CheckBox.qml</file> + <file>PageBuilding.qml</file> + <file>Footer.qml</file> + <file>PageSummary.qml</file> + </qresource> +</RCC> diff --git a/qtquickcontrols2.conf b/qtquickcontrols2.conf new file mode 100644 index 0000000..c7cae21 --- /dev/null +++ b/qtquickcontrols2.conf @@ -0,0 +1,6 @@ +[Controls] +Style=QtStyle + +[Default] +Font\Family=Arial +Font\PixelSize=20 -- GitLab