diff --git a/app/main.cpp b/app/main.cpp
index 00eceb9de..b226586d3 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -454,6 +454,11 @@ int main( int argc, char *argv[] )
init_qgis( appBundleDir );
+#ifdef ANDROID
+ // See https://bugreports.qt.io/browse/QTBUG-86982 -> fix to make the predictive text disabled on Android
+ qputenv( "QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT", "1" );
+#endif
+
// AppSettings has to be initialized after QGIS app init (because of correct reading/writing QSettings).
AppSettings as;
diff --git a/app/mmstyle.h b/app/mmstyle.h
index bf116ec3d..0b548ad7f 100644
--- a/app/mmstyle.h
+++ b/app/mmstyle.h
@@ -83,8 +83,6 @@ class MMStyle: public QObject
Q_PROPERTY( QColor informativeColor READ informativeColor CONSTANT )
// Colors - others
- Q_PROPERTY( QColor nightAlphaColor READ nightAlphaColor CONSTANT ) // placeholder input color
- Q_PROPERTY( QColor errorBgInputColor READ errorBgInputColor CONSTANT ) // error bg input color
Q_PROPERTY( QColor shadowColor READ shadowColor CONSTANT )
Q_PROPERTY( QColor snappingColor READ snappingColor CONSTANT )
@@ -286,6 +284,7 @@ class MMStyle: public QObject
// Other
Q_PROPERTY( double row1 READ number1 CONSTANT )
+ Q_PROPERTY( double row4 READ number4 CONSTANT )
Q_PROPERTY( double row24 READ number24 CONSTANT )
Q_PROPERTY( double row36 READ number36 CONSTANT )
Q_PROPERTY( double row40 READ number40 CONSTANT )
@@ -297,6 +296,9 @@ class MMStyle: public QObject
Q_PROPERTY( double row67 READ number67 CONSTANT )
Q_PROPERTY( double row80 READ number80 CONSTANT )
Q_PROPERTY( double row114 READ number114 CONSTANT )
+ Q_PROPERTY( double row120 READ number120 CONSTANT )
+ Q_PROPERTY( double row160 READ number160 CONSTANT )
+ Q_PROPERTY( double radius2 READ number2 CONSTANT )
Q_PROPERTY( double radius6 READ number6 CONSTANT )
Q_PROPERTY( double radius8 READ number8 CONSTANT )
Q_PROPERTY( double radius12 READ number12 CONSTANT )
@@ -304,6 +306,8 @@ class MMStyle: public QObject
Q_PROPERTY( double radius20 READ number20 CONSTANT )
Q_PROPERTY( double radius30 READ number30 CONSTANT )
Q_PROPERTY( double radius40 READ number40 CONSTANT )
+ Q_PROPERTY( double width1 READ number1 CONSTANT )
+ Q_PROPERTY( double width2 READ number2 CONSTANT )
Q_PROPERTY( double scrollVelocityAndroid READ scrollVelocityAndroid CONSTANT ) // [px/s] scrolling on Android devices is too slow by default
// Breakpoint we use in some screens to differentiate mobile landscape
@@ -366,8 +370,6 @@ class MMStyle: public QObject
QColor informativeColor() {return QColor::fromString( "#BEDAF0" );}
QColor snappingColor() {return QColor::fromString( "#BD74FF" );}
- QColor nightAlphaColor() {return QColor::fromString( "#AA12181F" );}
- QColor errorBgInputColor() {return QColor::fromString( "#FEFAF9" );}
QColor shadowColor() {return QColor::fromString( "#66777777" );}
QUrl splitGeometryIcon() {return QUrl( "qrc:/SplitGeometry.svg" );}
@@ -675,6 +677,7 @@ class MMStyle: public QObject
double number148() {return 148 * mDp;}
double number149() {return 149 * mDp;}
double number150() {return 150 * mDp;}
+ double number160() {return 160 * mDp;}
double number250() {return 250 * mDp;}
double number400() {return 400 * mDp;}
double number720() {return 720 * mDp;}
diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt
index 425c41ed3..4f6a37960 100644
--- a/app/qml/CMakeLists.txt
+++ b/app/qml/CMakeLists.txt
@@ -34,15 +34,12 @@ set(MM_QML
components/MMListSpacer.qml
components/MMBusyIndicator.qml
components/MMMessage.qml
- components/MMMorePhoto.qml
components/MMNotification.qml
components/MMNotificationView.qml
components/MMPage.qml
components/MMPageHeader.qml
components/MMPopup.qml
components/MMPhoto.qml
- components/MMPhotoAttachment.qml
- components/MMPhotoPreview.qml
components/MMProgressBar.qml
components/MMRadioButton.qml
components/MMRoundButton.qml
@@ -52,6 +49,8 @@ set(MM_QML
components/MMText.qml
components/MMToolbar.qml
components/MMToolbarButton.qml
+ components/private/MMBaseInput.qml
+ components/private/MMBaseSingleLineInput.qml
components/private/MMToolbarLongButton.qml
components/private/MMToolbarShortButton.qml
dialogs/MMCloseAccountDialog.qml
@@ -91,6 +90,8 @@ set(MM_QML
form/components/calendar/MMMonthGrid.qml
form/components/calendar/MMTimeTumbler.qml
form/components/calendar/MMTumbler.qml
+ form/components/photo/MMPhotoAttachment.qml
+ form/components/photo/MMPhotoPreview.qml
form/editors/MMFormCalendarEditor.qml
form/editors/MMFormComboboxBaseEditor.qml
form/editors/MMFormGalleryEditor.qml
@@ -114,12 +115,10 @@ set(MM_QML
gps/MMPositionProviderPage.qml
gps/MMStakeoutDrawer.qml
gps/components/MMGpsDataText.qml
- inputs/MMBaseInput.qml
inputs/MMComboboxInput.qml
inputs/MMPasswordInput.qml
inputs/MMSearchInput.qml
inputs/MMTextInput.qml
- inputs/MMTextWithButtonInput.qml
inputs/MMSwitchInput.qml
layers/MMFeaturesListPage.qml
layers/MMLayerDetailPage.qml
diff --git a/app/qml/account/MMHowYouFoundUsPage.qml b/app/qml/account/MMHowYouFoundUsPage.qml
index 4c5583f9d..fa7f89690 100644
--- a/app/qml/account/MMHowYouFoundUsPage.qml
+++ b/app/qml/account/MMHowYouFoundUsPage.qml
@@ -224,7 +224,7 @@ MMPage {
onTextChanged: root.selectedText = text
- Component.onCompleted: textFieldComponent.forceActiveFocus()
+ Component.onCompleted: textField.forceActiveFocus()
}
}
}
diff --git a/app/qml/account/MMLoginPage.qml b/app/qml/account/MMLoginPage.qml
index 5929fc0ad..95e29dc1e 100644
--- a/app/qml/account/MMLoginPage.qml
+++ b/app/qml/account/MMLoginPage.qml
@@ -85,7 +85,7 @@ MMPage {
width: parent.width
title: qsTr( "Email or username" )
- textFieldComponent.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
+ textField.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhEmailCharactersOnly
}
MMPasswordInput {
@@ -200,10 +200,10 @@ MMPage {
title: qsTr( "Server address" )
- bgColor: __style.lightGreenColor
+ textFieldBackground.color: __style.lightGreenColor
text: root.apiRoot
- textFieldComponent.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
+ textField.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhUrlCharactersOnly
}
MMListSpacer { height: __style.spacing40 }
diff --git a/app/qml/account/MMSignUpPage.qml b/app/qml/account/MMSignUpPage.qml
index e1de1645f..cc5fd028b 100644
--- a/app/qml/account/MMSignUpPage.qml
+++ b/app/qml/account/MMSignUpPage.qml
@@ -72,7 +72,7 @@ MMPage {
width: parent.width
title: qsTr( "Username" )
- textFieldComponent.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
+ textField.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
}
MMTextInput {
@@ -81,7 +81,7 @@ MMPage {
width: parent.width
title: qsTr( "Email" )
- textFieldComponent.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
+ textField.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhEmailCharactersOnly
}
MMPasswordInput {
diff --git a/app/qml/account/MMSwitchWorkspacePage.qml b/app/qml/account/MMSwitchWorkspacePage.qml
index 14164749a..eb12841b1 100644
--- a/app/qml/account/MMSwitchWorkspacePage.qml
+++ b/app/qml/account/MMSwitchWorkspacePage.qml
@@ -60,7 +60,7 @@ MMComponents.MMPage {
placeholderText: qsTr( "Search" ) + "..."
- onSearchTextChanged: function( searchText ) { root.searchTextChanged( searchText ) }
+ onSearchTextChanged: root.searchTextChanged( searchBar.searchText )
}
MMComponents.MMScrollView {
diff --git a/app/qml/account/MMWhichIndustryPage.qml b/app/qml/account/MMWhichIndustryPage.qml
index b0c82786e..e8fb981e3 100644
--- a/app/qml/account/MMWhichIndustryPage.qml
+++ b/app/qml/account/MMWhichIndustryPage.qml
@@ -211,9 +211,9 @@ MMPage {
title: qsTr( "Industry" )
placeholderText: internal.specifyIndustryText
- onTextChanged: root.selectedText = text
+ onTextEdited: ( text ) => root.selectedText = text
- Component.onCompleted: textFieldComponent.forceActiveFocus()
+ Component.onCompleted: textField.forceActiveFocus()
}
}
}
diff --git a/app/qml/components/MMCheckBox.qml b/app/qml/components/MMCheckBox.qml
index a7ffebd77..e2f49f9f0 100644
--- a/app/qml/components/MMCheckBox.qml
+++ b/app/qml/components/MMCheckBox.qml
@@ -18,6 +18,8 @@ CheckBox {
property bool hasError: false
+ property color emptyStateColor: __style.transparentColor
+
implicitHeight: Math.max( textContent.implicitHeight, indicatorContent.height )
topPadding: __style.margin4
@@ -35,7 +37,7 @@ CheckBox {
radius: __style.radius6
- color: ( root.checked && root.enabled ) ? __style.grassColor: __style.transparentColor
+ color: ( root.checked && root.enabled ) ? __style.grassColor : emptyStateColor
border.color: {
if ( enabled ) {
diff --git a/app/qml/components/MMListMultiselectDrawer.qml b/app/qml/components/MMListMultiselectDrawer.qml
index 2ec833eab..709172540 100644
--- a/app/qml/components/MMListMultiselectDrawer.qml
+++ b/app/qml/components/MMListMultiselectDrawer.qml
@@ -52,10 +52,11 @@ MMDrawer {
placeholderText: qsTr( "Search" )
- bgColor: __style.lightGreenColor
+ textFieldBackground.color: __style.lightGreenColor
+
visible: root.withSearch
- onSearchTextChanged: ( text ) => root.searchTextChanged( text )
+ onSearchTextChanged: root.searchTextChanged( searchBar.searchText )
}
MMListSpacer { id: searchBarSpacer; height: __style.spacing20; visible: root.withSearch }
diff --git a/app/qml/components/MMMorePhoto.qml b/app/qml/components/MMMorePhoto.qml
deleted file mode 100644
index 7a0fe644b..000000000
--- a/app/qml/components/MMMorePhoto.qml
+++ /dev/null
@@ -1,110 +0,0 @@
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-
-import QtQuick
-import QtQuick.Controls
-import Qt5Compat.GraphicalEffects
-
-Row {
- id: control
-
- required property url photoUrl
- property int hiddenPhotoCount: 0
- property int space: 0
-
- signal clicked()
-
- // left space
- Item { width: control.space; height: 1 }
-
- Image {
- id: image
-
- width: control.width - control.space
- height: width
-
- source: control.photoUrl
- asynchronous: true
- autoTransform: true
- layer.enabled: true
- layer {
- effect: OpacityMask {
- maskSource: Item {
- width: image.width
- height: width
- Rectangle {
- anchors.centerIn: parent
- width: image.width
- height: parent.height
- radius: 20 * __dp
- }
- }
- }
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: control.clicked()
- }
-
- Rectangle {
- anchors.centerIn: parent
- width: image.width
- height: parent.height
-
- radius: 20 * __dp
- color: __style.transparentColor
- border.color: __style.forestColor
- border.width: 1 * __dp
- }
-
- Image {
- id: bluredImage
-
- anchors.fill: parent
- source: image.source
-
- asynchronous: true
- layer.enabled: true
-
- layer {
- effect: FastBlur {
- anchors.fill: bluredImage
- source: bluredImage
- radius: 32
- }
- }
- }
-
- Column {
- anchors.centerIn: parent
-
- Image {
- source: __style.morePhotosIcon
- anchors.horizontalCenter: parent.horizontalCenter
- }
-
- Text {
- height: 26 * __dp
- font: __style.t4
- text: qsTr("+%1 more").arg(control.hiddenPhotoCount)
- color: __style.polarColor
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- elide: Text.ElideRight
- }
- }
-
- onStatusChanged: {
- if (status === Image.Error) {
- console.error("MMMorePhoto: Error loading image");
- }
- }
- }
-}
diff --git a/app/qml/components/MMSwitch.qml b/app/qml/components/MMSwitch.qml
index 5ecca21ab..ae9d1d181 100644
--- a/app/qml/components/MMSwitch.qml
+++ b/app/qml/components/MMSwitch.qml
@@ -13,10 +13,9 @@ import QtQuick.Controls
Switch {
id: root
+ property color checkedBgColor: enabled ? __style.grassColor : __style.mediumGreenColor
property color uncheckedBgColor: __style.polarColor
- property color checkedBgColor: __style.grassColor
- property color disabledFgColor: __style.mediumGreenColor
- property color enabledFgColor: __style.forestColor
+ property color handleColor: enabled ? __style.forestColor : __style.mediumGreyColor
topPadding: 0
rightPadding: 0
@@ -26,7 +25,7 @@ Switch {
contentItem: Text {
text: root.text
font: __style.p5
- color: root.enabled ? root.enabledFgColor : root.disabledFgColor
+ color: root.handleColor
verticalAlignment: Text.AlignVCenter
leftPadding: root.indicator.width + ( text ? root.spacing : 0 )
}
@@ -37,7 +36,6 @@ Switch {
implicitWidth: 48 * __dp
implicitHeight: 28 * __dp
x: root.leftPadding
- y: parent.height / 2 - height / 2
radius: implicitHeight / 2
color: root.checked ? root.checkedBgColor : root.uncheckedBgColor
@@ -46,7 +44,7 @@ Switch {
width: 20 * __dp
height: width
radius: width / 2
- color: root.enabled ? root.enabledFgColor : root.disabledFgColor
+ color: root.handleColor
anchors.verticalCenter: parent.verticalCenter
}
}
diff --git a/app/qml/components/private/MMBaseInput.qml b/app/qml/components/private/MMBaseInput.qml
new file mode 100644
index 000000000..b25374702
--- /dev/null
+++ b/app/qml/components/private/MMBaseInput.qml
@@ -0,0 +1,211 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+
+import "../" as MMComponents
+
+/**
+ * MMBaseInput is a base class for all inputs in the app.
+ * Inputs and form editors are derived from this component.
+ *
+ * Private class, do not use in the app.
+ */
+
+Item {
+ id: root
+
+ property alias title: titleText.text
+
+ property bool hasCheckbox: false
+ property alias checkboxChecked: checkbox.checked
+
+ property bool readOnly: false
+
+ property string errorMsg: ""
+ property string warningMsg: ""
+
+ property alias inputContent: contentGroup.children
+
+ property alias editState: editStateGroup.state
+ property alias validationState: validationStateGroup.state
+
+ StateGroup {
+ id: editStateGroup
+
+ states: [
+ State {
+ name: "enabled"
+ when: enabled && !readOnly
+ },
+ State {
+ name: "disabled"
+ when: !enabled
+ },
+ State {
+ name: "readOnly"
+ when: enabled && readOnly
+ }
+ ]
+
+ state: "enabled"
+ }
+
+ StateGroup {
+ id: validationStateGroup
+
+ states: [
+ State {
+ name: "valid"
+ when: !warningMsg && !errorMsg
+ },
+ State {
+ name: "error"
+ when: errorMsg
+ },
+ State {
+ name: "warning"
+ when: warningMsg && !errorMsg
+ }
+ ]
+
+ state: "valid"
+ }
+
+ implicitHeight: rootGroup.implicitHeight
+
+ Column {
+ id: rootGroup
+
+ width: parent.width
+
+ spacing: __style.margin4
+
+ Item {
+ // checkbox and title div
+
+ width: parent.width
+ implicitHeight: titleRowGroup.implicitHeight
+
+ RowLayout {
+ id: titleRowGroup
+
+ width: parent.width
+
+ // Checkbox has some padding to the right so we do not need spacing.
+ // Once we refactor the checkbox, we need to add spacing here.
+ spacing: 0
+
+ MMComponents.MMCheckBox {
+ id: checkbox
+
+ small: true
+ visible: root.hasCheckbox && root.editState === "enabled"
+
+ emptyStateColor: __style.polarColor
+ checked: root.checkboxChecked
+
+ MouseArea {
+ anchors {
+ fill: parent
+ margins: -__style.margin16
+ }
+
+ onClicked: function( mouse ) {
+ mouse.accepted = true
+ checkbox.toggle()
+ }
+ }
+
+ }
+
+ MMComponents.MMText {
+ id: titleText
+
+ text: root.title
+ font: __style.p6
+
+ Layout.fillWidth: true
+
+ wrapMode: Text.Wrap
+ maximumLineCount: 10
+
+ MouseArea {
+ width: parent.contentWidth + 2 * __style.margin12
+ height: parent.contentHeight
+
+ x: -__style.margin12
+
+ onClicked: function( mouse ) {
+ mouse.accepted = true
+
+ if ( checkbox.visible ) {
+ checkbox.toggle()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ id: contentGroup
+
+ width: parent.width
+ height: childrenRect.height
+ }
+
+ Item {
+ // validation messages
+
+ width: parent.width
+ height: validationMessagegroup.implicitHeight
+
+ visible: root.validationState !== "valid" && root.editState === "enabled"
+
+ RowLayout {
+ id: validationMessagegroup
+
+ width: parent.width
+
+ MMComponents.MMIcon {
+ source: __style.errorCircleIcon
+ size: __style.icon16
+ color: {
+ if ( root.validationState === "error" ) return __style.negativeColor
+ if ( root.validationState === "warning" ) return __style.warningColor
+ return __style.forestColor
+ }
+ }
+
+ MMComponents.MMText {
+ Layout.fillWidth: true
+
+ text: {
+ if ( root.validationState === "error" ) return root.errorMsg
+ if ( root.validationState === "warning" ) return root.warningMsg
+ return ""
+ }
+ color: {
+ if ( root.validationState === "error" ) return __style.grapeColor
+ if ( root.validationState === "warning" ) return __style.earthColor
+ return __style.forestColor
+ }
+
+ font: __style.t4
+
+
+ wrapMode: Text.Wrap
+ maximumLineCount: 2
+ }
+ }
+ }
+ }
+}
diff --git a/app/qml/components/private/MMBaseSingleLineInput.qml b/app/qml/components/private/MMBaseSingleLineInput.qml
new file mode 100644
index 000000000..e7fb44676
--- /dev/null
+++ b/app/qml/components/private/MMBaseSingleLineInput.qml
@@ -0,0 +1,216 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+// To ignore the warning "The current style does not support customization"
+// see from https://stackoverflow.com/questions/76625756/the-current-style-does-not-support-customization-of-this-control
+import QtQuick.Controls.Basic
+
+/**
+ * MMBaseSingleLineInput serves as a base class for all inputs that can benefit from
+ * predefined textfield and/or left/right icons (actions).
+ *
+ * Private class, do not use standalone in the app.
+ */
+
+MMBaseInput {
+ id: root
+
+ property alias text: textFieldControl.text
+ property alias placeholderText: textFieldControl.placeholderText
+
+ property alias textField: textFieldControl
+ property alias textFieldBackground: textFieldBackgroundGroup
+
+ property alias leftContent: leftContentGroup.children
+ property alias rightContent: rightContentGroup.children
+ property alias leftContentMouseArea: leftContentMouseAreaGroup
+ property alias rightContentMouseArea: rightContentMouseAreaGroup
+
+ property bool rightContentVisible: rightContentGroup.children.length > 0
+ property bool leftContentVisible: leftContentGroup.children.length > 0
+
+ // IconColor is not used in this file directly, but derived components can use it
+ // as precalculated color for icons to avoid repeating the same text over and over.
+ property color iconColor: {
+ if ( root.editState !== "enabled" ) return __style.mediumGreyColor
+ if ( root.validationState === "error" ) return __style.grapeColor
+ if ( root.validationState === "warning" ) return __style.earthColor
+ return __style.forestColor
+ }
+
+ signal textEdited( string text )
+ signal textClicked()
+ signal leftContentClicked()
+ signal rightContentClicked()
+
+ inputContent: Rectangle {
+ id: textFieldBackgroundGroup
+
+ width: parent.width
+ height: __style.row50
+
+ color: {
+ if ( root.editState !== "enabled" ) return __style.polarColor
+ if ( root.validationState === "error" ) return __style.negativeUltraLightColor
+ if ( root.validationState === "warning" ) return __style.negativeUltraLightColor
+
+ return __style.polarColor
+ }
+
+ border.width: {
+ if ( root.validationState === "error" ) return __style.width2
+ if ( root.validationState === "warning" ) return __style.width2
+ if ( textFieldControl.activeFocus ) return __style.width2
+ if ( textFieldControl.hovered ) return __style.width1
+ return 0
+ }
+
+ border.color: {
+ if ( root.editState !== "enabled" ) return __style.polarColor
+ if ( root.validationState === "error" ) return __style.negativeColor
+ if ( root.validationState === "warning" ) return __style.warningColor
+ if ( textFieldControl.activeFocus ) return __style.forestColor
+ if ( textFieldControl.hovered ) return __style.forestColor
+
+ return __style.polarColor
+ }
+
+ radius: __style.radius12
+
+ RowLayout {
+ anchors .fill: parent
+
+ spacing: __style.margin12
+
+ Item {
+ id: leftContentGroupContainer
+
+ Layout.preferredHeight: leftContentGroup.height
+ Layout.preferredWidth: leftContentGroup.width
+ Layout.leftMargin: __style.margin20
+
+ visible: leftContentVisible
+
+ Item {
+ id: leftContentGroup
+
+ width: childrenRect.width
+ height: childrenRect.height
+
+ }
+
+ MouseArea {
+ id: leftContentMouseAreaGroup
+
+ anchors {
+ fill: parent
+
+ leftMargin: -__style.margin20
+ topMargin: -__style.margin16
+ rightMargin: -__style.margin12
+ bottomMargin: -__style.margin16
+ }
+
+ onClicked: function( mouse ) {
+ if ( root.editState === "enabled" ) {
+ mouse.accepted = true
+ root.focus = true
+ root.leftContentClicked()
+ }
+ }
+ }
+ }
+
+ TextField {
+ id: textFieldControl
+
+ Layout.fillWidth: true
+ Layout.preferredHeight: parent.height
+
+ // Do not let TextField calculate implicitWidth automatically based on background, it causes binding loops
+ implicitWidth: width
+
+ readOnly: root.editState === "readOnly" || root.editState === "disabled"
+
+ // Ensure the text is scrolled to the beginning
+ Component.onCompleted: ensureVisible( 0 )
+
+ color: {
+ if ( root.editState === "readOnly" ) return __style.nightColor
+ if ( root.editState === "enabled" ) return __style.nightColor
+ if ( root.editState === "disabled" ) return __style.mediumGreyColor
+ return __style.nightColor
+ }
+
+ topPadding: 0
+ bottomPadding: 0
+ leftPadding: leftContentGroupContainer.visible ? 0 : __style.margin20
+ rightPadding: rightContentGroupContainer.visible ? 0 : __style.margin20
+
+ inputMethodHints: Qt.ImhNoPredictiveText
+
+ placeholderTextColor: __style.darkGreyColor
+
+ font: __style.p5
+
+ background: Rectangle { color: __style.transparentColor }
+
+ onTextEdited: root.textEdited( text )
+
+ onReleased: {
+ if ( root.editState !== "readOnly" ) {
+ root.textClicked()
+ }
+ }
+ }
+
+ Item {
+ id: rightContentGroupContainer
+
+ Layout.preferredHeight: rightContentGroup.height
+ Layout.preferredWidth: rightContentGroup.width
+ Layout.rightMargin: __style.margin20
+
+ visible: rightContentVisible
+
+ Item {
+ id: rightContentGroup
+
+ width: childrenRect.width
+ height: childrenRect.height
+ }
+
+ MouseArea {
+ id: rightContentMouseAreaGroup
+
+ anchors {
+ fill: parent
+
+ leftMargin: -__style.margin12
+ topMargin: -__style.margin16
+ rightMargin: -__style.margin20
+ bottomMargin: -__style.margin16
+ }
+
+ onClicked: function( mouse ) {
+ if ( root.editState === "enabled" ) {
+ mouse.accepted = true
+ root.focus = true
+ root.rightContentClicked()
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/qml/dialogs/MMCloseAccountDialog.qml b/app/qml/dialogs/MMCloseAccountDialog.qml
index 72f5c7bae..1e6bed258 100644
--- a/app/qml/dialogs/MMCloseAccountDialog.qml
+++ b/app/qml/dialogs/MMCloseAccountDialog.qml
@@ -56,7 +56,7 @@ MMDrawer {
id: usernameInput
width: parent.width
- bgColor: __style.lightGreenColor
+ textFieldBackground.color: __style.lightGreenColor
title: qsTr("Username")
placeholderText: qsTr("Enter your username")
diff --git a/app/qml/form/components/MMFeaturesListPageDrawer.qml b/app/qml/form/components/MMFeaturesListPageDrawer.qml
index 562c715b3..a8b93ed42 100644
--- a/app/qml/form/components/MMFeaturesListPageDrawer.qml
+++ b/app/qml/form/components/MMFeaturesListPageDrawer.qml
@@ -62,15 +62,13 @@ Drawer {
MMComponents.MMListSpacer { height: __style.spacing20 }
MMInputs.MMSearchInput {
- id: searchInput
+ id: searchBar
width: parent.width
placeholderText: qsTr("Search for features...")
- onSearchTextChanged: function( text ) {
- root.searchTextChanged( text )
- }
+ onSearchTextChanged: root.searchTextChanged( searchBar.searchText )
}
MMComponents.MMListSpacer { height: __style.spacing20 }
@@ -79,7 +77,7 @@ Drawer {
id: listView
width: parent.width
- height: parent.height - 2 * __style.spacing20 - searchInput.height
+ height: parent.height - 2 * __style.spacing20 - searchBar.height
clip: true
diff --git a/app/qml/components/MMPhotoAttachment.qml b/app/qml/form/components/photo/MMPhotoAttachment.qml
similarity index 92%
rename from app/qml/components/MMPhotoAttachment.qml
rename to app/qml/form/components/photo/MMPhotoAttachment.qml
index 0590737ac..58737b3cc 100644
--- a/app/qml/components/MMPhotoAttachment.qml
+++ b/app/qml/form/components/photo/MMPhotoAttachment.qml
@@ -9,13 +9,14 @@
import QtQuick
import QtQuick.Controls
-import "."
+
+import "../../../components" as MMComponents
Rectangle {
id: root
color: __style.polarColor
- radius: 20 * __dp
+ radius: __style.radius20
property bool hasCameraCapability: true
@@ -42,18 +43,18 @@ Rectangle {
anchors.centerIn: parent
spacing: 8 * __dp
- MMIcon {
+ MMComponents.MMIcon {
anchors.horizontalCenter: parent.horizontalCenter
source: __style.addImageIcon
color: __style.forestColor
}
- Text {
+ MMComponents.MMText {
width: parent.width
- height: 24 * __dp
+
font: __style.p6
text: qsTr("Take a picture")
- color: __style.nightColor
+
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideMiddle
@@ -79,18 +80,18 @@ Rectangle {
anchors.centerIn: parent
spacing: 8 * __dp
- MMIcon {
+ MMComponents.MMIcon {
anchors.horizontalCenter: parent.horizontalCenter
source: __style.morePhotosIcon
color: __style.forestColor
}
- Text {
+ MMComponents.MMText {
width: parent.width
- height: 24 * __dp
+
font: __style.p6
text: qsTr("From gallery")
- color: __style.nightColor
+
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideMiddle
diff --git a/app/qml/components/MMPhotoPreview.qml b/app/qml/form/components/photo/MMPhotoPreview.qml
similarity index 93%
rename from app/qml/components/MMPhotoPreview.qml
rename to app/qml/form/components/photo/MMPhotoPreview.qml
index 347cbb2d1..eb99b1c03 100644
--- a/app/qml/components/MMPhotoPreview.qml
+++ b/app/qml/form/components/photo/MMPhotoPreview.qml
@@ -10,6 +10,8 @@
import QtQuick
import QtQuick.Controls
+import "../../../components" as MMComponents
+
Popup {
id: root
@@ -22,13 +24,13 @@ Popup {
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
background: Rectangle {
- color: Qt.alpha(__style.nightAlphaColor, 0.9)
+ color: Qt.alpha(__style.darkGreyColor, 0.9)
}
contentItem: Item {
anchors.fill: parent
- MMBusyIndicator {
+ MMComponents.MMBusyIndicator {
anchors.centerIn: parent
visible: true
}
@@ -67,7 +69,7 @@ Popup {
width: parent.width - __style.safeAreaLeft - __style.safeAreaRight
height: parent.height - __style.safeAreaBottom - __style.safeAreaTop
- MMRoundButton {
+ MMComponents.MMRoundButton {
id: closeButton
anchors {
@@ -82,7 +84,6 @@ Popup {
previewLoader.active = false
}
}
-
}
}
}
diff --git a/app/qml/form/editors/MMFormCalendarEditor.qml b/app/qml/form/editors/MMFormCalendarEditor.qml
index 5ce240644..42f45ff8b 100644
--- a/app/qml/form/editors/MMFormCalendarEditor.qml
+++ b/app/qml/form/editors/MMFormCalendarEditor.qml
@@ -8,12 +8,11 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
import "../../components" as MMComponents
+import "../../components/private" as MMPrivateComponents
+
import "../components" as MMFormComponents
-import "../../inputs"
/*
* Calendar (datetime) editor for QGIS Attribute Form
@@ -23,7 +22,7 @@ import "../../inputs"
* Should be used only within feature form.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property var _field: parent.field
@@ -50,9 +49,8 @@ MMBaseInput {
property bool includesDate: typeFromFieldFormat.includes("Date")
property bool showSeconds: true
- property alias text: textField.text
-
title: _fieldShouldShowTitle ? _fieldTitle : ""
+ text: formatText( root._fieldValue )
warningMsg: _fieldWarningMessage
errorMsg: _fieldErrorMessage
@@ -60,37 +58,23 @@ MMBaseInput {
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
- enabled: !_fieldIsReadOnly
- hasFocus: textField.activeFocus
+ readOnly: _fieldIsReadOnly
onCheckboxCheckedChanged: {
root.rememberValueBoxClicked( checkboxChecked )
}
- content: MMComponents.MMText {
- id: textField
-
- anchors.fill: parent
-
- text: formatText( root._fieldValue )
- color: __style.nightColor
- font: __style.p5
- }
-
- onContentClicked: root.openCalendar()
+ onTextClicked: root.openCalendar()
+ onRightContentClicked: root.openCalendar()
- rightAction: MMComponents.MMIcon {
+ rightContent: MMComponents.MMIcon {
id: rightIcon
- anchors.verticalCenter: parent.verticalCenter
-
size: __style.icon24
source: __style.calendarIcon
- color: root.enabled ? __style.forestColor : __style.mediumGreenColor
+ color: root.iconColor
}
- onRightActionClicked: root.openCalendar()
-
Loader {
id: dateTimeDrawerLoader
diff --git a/app/qml/form/editors/MMFormComboboxBaseEditor.qml b/app/qml/form/editors/MMFormComboboxBaseEditor.qml
index c60ba5472..4dec4f8f1 100644
--- a/app/qml/form/editors/MMFormComboboxBaseEditor.qml
+++ b/app/qml/form/editors/MMFormComboboxBaseEditor.qml
@@ -8,11 +8,9 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
import "../../components" as MMComponents
-import "../../inputs" as MMInputs
+import "../../components/private" as MMPrivateComponents
/*
* Common dropdown (combobox) for forms (value relation and value map).
@@ -21,63 +19,25 @@ import "../../inputs" as MMInputs
*
* Disabled state can be achieved by setting `enabled: false`.
*
- * See MMBaseInput for more properties.
+ * See MMBaseSingleLineInput for more properties.
*/
-MMInputs.MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
- property alias placeholderText: textField.placeholderText
- property alias text: textField.text
- property alias textFieldComponent: textField
-
property alias dropdownLoader: drawerLoader
- hasFocus: textField.activeFocus
-
- content: TextField {
- id: textField
-
- anchors.fill: parent
- anchors.verticalCenter: parent.verticalCenter
-
- readOnly: true
-
- color: root.enabled ? __style.nightColor : __style.mediumGreenColor
- placeholderTextColor: __style.nightAlphaColor
-
- font: __style.p5
- hoverEnabled: true
+ textField.readOnly: true
- background: Rectangle {
- color: __style.transparentColor
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: function( mouse ) {
- mouse.accepted = true
- openDrawer()
- }
- }
- }
-
- rightAction: MMComponents.MMIcon {
- property bool pressed: false
-
- anchors.verticalCenter: parent.verticalCenter
+ onTextClicked: openDrawer()
+ rightContent: MMComponents.MMIcon {
size: __style.icon24
source: __style.arrowDownIcon
- color: root.enabled ? __style.forestColor : __style.mediumGreenColor
+ color: root.iconColor
}
- onRightActionClicked: {
- if ( !root.enabled )
- return
-
- openDrawer()
- }
+ onRightContentClicked: openDrawer()
Loader {
id: drawerLoader
diff --git a/app/qml/form/editors/MMFormGalleryEditor.qml b/app/qml/form/editors/MMFormGalleryEditor.qml
index 0279d7cf4..d2dccddf5 100644
--- a/app/qml/form/editors/MMFormGalleryEditor.qml
+++ b/app/qml/form/editors/MMFormGalleryEditor.qml
@@ -12,184 +12,93 @@ import QtQuick.Controls
import mm 1.0 as MM
-import "../../components"
+import "../../components" as MMComponents
+import "../../components/private" as MMPrivateComponents
-Item {
+MMPrivateComponents.MMBaseInput {
id: root
- width: parent.width
- height: column.height
-
property var _fieldAssociatedRelation: parent.fieldAssociatedRelation
property var _fieldFeatureLayerPair: parent.fieldFeatureLayerPair
property var _fieldActiveProject: parent.fieldActiveProject
- property string _fieldTitle: parent.fieldTitle
property bool _fieldShouldShowTitle: parent.fieldShouldShowTitle
-
- property var model
- property string title: _fieldShouldShowTitle ? _fieldTitle : ""
- property string warningMsg
- property string errorMsg
- property int maxVisiblePhotos: -1 // -1 for showing all photos
- property bool showAddImage: true
-
- signal showAll()
- signal clicked( var path )
- signal addImage()
+ property string _fieldTitle: parent.fieldTitle
signal openLinkedFeature( var linkedFeature )
signal createLinkedFeature( var parentFeature, var relation )
- Column {
- id: column
+ title: _fieldShouldShowTitle ? _fieldTitle : ""
- padding: 20 * __dp
- spacing: 10 * __dp
- width: parent.width - 40 * __dp
+ inputContent: ListView {
+ id: rowView
- Item {
- width: parent.width
- height: 15 * __dp
+ width: parent.width
+ height: __style.row120
- Text {
- width: column.width - showAllButton.width - 10 * __dp
+ clip: true
+ spacing: __style.spacing12
+ orientation: ListView.Horizontal
- text: root.title
- font: __style.p6
- elide: Text.ElideRight
- color: __style.nightColor
- }
+ model: MM.RelationFeaturesModel {
+ id: rmodel
- Text {
- id: showAllButton
+ relation: root._fieldAssociatedRelation
+ parentFeatureLayerPair: root._fieldFeatureLayerPair
+ homePath: root._fieldActiveProject.homePath
+ }
- anchors.right: parent.right
+ delegate: MMComponents.MMPhoto {
+ width: rowView.height
- visible: false // for now
+ fillMode: Image.PreserveAspectCrop
- text: qsTr("Show all")
- font: __style.t4
- color: __style.forestColor
+ photoUrl: {
+ let absolutePath = model.PhotoPath
- MouseArea {
- anchors.fill: parent
- onClicked: root.showAll()
+ if ( absolutePath !== '' && __inputUtils.fileExists( absolutePath ) ) {
+ return "file://" + absolutePath
}
+ return ''
}
- }
- ListView {
- id: rowView
-
- height: 120 * __dp
- width: parent.width
- spacing: root.maxVisiblePhotos !== 0 ? __style.spacing12 : 0
- orientation: ListView.Horizontal
-
-// model: {
-// if(root.maxVisiblePhotos >= 0 && root.model.length > root.maxVisiblePhotos) {
-// return root.model.slice(0, root.maxVisiblePhotos)
-// }
-// return root.model
-// }
-
- model: MM.RelationFeaturesModel {
- id: rmodel
-
- relation: root._fieldAssociatedRelation
- parentFeatureLayerPair: root._fieldFeatureLayerPair
- homePath: root._fieldActiveProject.homePath
+ onClicked: function( path ) {
+ root.openLinkedFeature( model.FeaturePair )
}
+ }
- delegate: MMPhoto {
- width: rowView.height
-
- fillMode: Image.PreserveAspectCrop
+ header: addFeatureComponent
+ }
- photoUrl: {
- let absolutePath = model.PhotoPath
+ Component {
+ id: addFeatureComponent
- if ( absolutePath !== '' && __inputUtils.fileExists( absolutePath ) ) {
- return "file://" + absolutePath
- }
- return ''
- }
+ Row {
- onClicked: function(path) {
- root.clicked(path)
- root.openLinkedFeature( model.FeaturePair )
- }
- }
+ Rectangle {
+ height: rowView.height
+ width: height
- header: Row {
- visible: root.showAddImage
-
- Rectangle {
- width: visible ? height : 0
- height: rowView.height
- radius: 20 * __dp
- border.width: 2 * __dp
- border.color: root.errorMsg.length > 0 ? __style.negativeColor : root.warningMsg.length > 0 ? __style.warningColor : __style.polarColor
- color: (root.errorMsg.length > 0 || root.warningMsg.length > 0) ? __style.errorBgInputColor : __style.polarColor
-
- MMIcon {
- anchors.centerIn: parent
- source: __style.addImageIcon
- color: root.errorMsg.length > 0 ? __style.grapeColor : root.warningMsg.length > 0 ? __style.earthColor : __style.forestColor
- size: __style.icon32
- }
+ radius: __style.radius20
+ color: __style.polarColor
- MouseArea {
- anchors.fill: parent
- onClicked: {
- root.addImage()
- root.createLinkedFeature( root._fieldFeatureLayerPair, root._fieldAssociatedRelation )
- }
- }
+ MMComponents.MMIcon {
+ anchors.centerIn: parent
+ source: __style.addImageIcon
+ color: root.errorMsg.length > 0 ? __style.grapeColor : root.warningMsg.length > 0 ? __style.earthColor : __style.forestColor
+ size: __style.icon32
}
- Item {
- width: visible ? rowView.spacing : 0
- height: rowView.height
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ root.createLinkedFeature( root._fieldFeatureLayerPair, root._fieldAssociatedRelation )
+ }
}
}
- footer: MMMorePhoto {
- width: visible ? rowView.height + rowView.spacing: 0
-
-// hiddenPhotoCount: root.model.length - root.maxVisiblePhotos
-// visible: root.maxVisiblePhotos >= 0 && root.model.length > root.maxVisiblePhotos
-// photoUrl: visible ? model[root.maxVisiblePhotos] : ""
-// space: visible ? rowView.spacing : 0
-
- visible: false
-
- onClicked: root.showAll()
- }
- }
-
- Row {
- id: msgRow
-
- spacing: 4 * __dp
-
- MMIcon {
- id: msgIcon
-
- source: visible ? __style.errorCircleIcon : ""
- color: root.errorMsg.length > 0 ? __style.negativeColor : __style.warningColor
- size: __style.icon16
- visible: root.errorMsg.length > 0 || root.warningMsg.length > 0
- }
-
- Text {
- width: column.width - msgRow.spacing - msgIcon.size
-
- text: root.errorMsg.length > 0 ? root.errorMsg : root.warningMsg
- font: __style.t4
- wrapMode: Text.WordWrap
- visible: root.errorMsg.length > 0 || root.warningMsg.length > 0
+ MMComponents.MMListSpacer {
+ width: rowView.spacing
}
}
}
diff --git a/app/qml/form/editors/MMFormNumberEditor.qml b/app/qml/form/editors/MMFormNumberEditor.qml
index 76952953f..3ae2a070d 100644
--- a/app/qml/form/editors/MMFormNumberEditor.qml
+++ b/app/qml/form/editors/MMFormNumberEditor.qml
@@ -8,11 +8,9 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
-import "../../components"
-import "../../inputs"
+import "../../components" as MMComponents
+import "../../components/private" as MMPrivateComponents
/*
* Number (range editable) editor for QGIS Attribute Form
@@ -22,7 +20,7 @@ import "../../inputs"
* Should be used only within feature form.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property var _fieldValue: parent.fieldValue
@@ -39,20 +37,15 @@ MMBaseInput {
property bool _fieldRememberValueSupported: parent.fieldRememberValueSupported
property bool _fieldRememberValueState: parent.fieldRememberValueState
- property alias placeholderText: numberInput.placeholderText
-
signal editorValueChanged( var newValue, var isNull )
signal rememberValueBoxClicked( bool state )
-
title: _fieldShouldShowTitle ? _fieldTitle : ""
+ readOnly: _fieldIsReadOnly
errorMsg: _fieldErrorMessage
warningMsg: _fieldWarningMessage
- enabled: !_fieldIsReadOnly
- hasFocus: numberInput.activeFocus
-
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
@@ -60,93 +53,95 @@ MMBaseInput {
root.rememberValueBoxClicked( checkboxChecked )
}
- leftAction: MMIcon {
+ leftContent: MMComponents.MMIcon {
id: leftIcon
- anchors.verticalCenter: parent.verticalCenter
-
size: __style.icon24
source: __style.minusIcon
- color: enabled ? __style.forestColor : __style.mediumGreenColor
- enabled: Number( numberInput.text ) - internal.step >= internal.from
- }
-
- onLeftActionClicked: {
- if ( leftIcon.enabled )
- {
- let decremented = Number( numberInput.text ) - internal.step
- root.editorValueChanged( decremented.toFixed( internal.precision ), false )
+ color: {
+ if ( root.editState !== "enabled" ) return __style.mediumGreyColor
+ if ( internal.canSubtractStep ) {
+ if ( root.validationState === "error" ) return __style.grapeColor
+ if ( root.validationState === "warning" ) return __style.earthColor
+ return __style.forestColor
+ }
+ else {
+ if ( root.validationState === "error" ) return __style.negativeColor
+ if ( root.validationState === "warning" ) return __style.warningColor
+ return __style.mediumGreyColor
+ }
}
}
- content: Item {
- anchors.fill: parent
-
- Row {
- height: parent.height
- anchors.horizontalCenter: parent.horizontalCenter
- clip: true
+ textField {
+ text: root._fieldValue === undefined || root._fieldValueIsNull ? '' : root._fieldValue
- TextField {
- id: numberInput
+ clip: true
- height: parent.height
+ // AlignHCenter with optional suffix
+ leftPadding: Math.max( 0, ( textField.width / 2 - textField.contentWidth / 2 ) - ( internal.suffix ? suffixText.width / 2 : 0 ) )
- text: root._fieldValue === undefined || root._fieldValueIsNull ? '' : root._fieldValue
+ inputMethodHints: Qt.ImhFormattedNumbersOnly
- placeholderTextColor: __style.nightAlphaColor
- color: __style.nightColor
+ background: Rectangle {
+ color: "transparent"
- font: __style.p5
+ // Suffix is added as a part of the background property in order to not block clicks to the textField
+ MMComponents.MMText {
+ id: suffixText
- clip: true
- hoverEnabled: true
+ property real maxWidth: textField.width / 2
- verticalAlignment: Qt.AlignVCenter
- inputMethodHints: Qt.ImhFormattedNumbersOnly
+ width: Math.min( implicitWidth + __style.margin4, maxWidth )
+ x: textField.leftPadding + textField.contentWidth + __style.margin4
+ anchors.verticalCenter: parent.verticalCenter
- onTextEdited: {
- let val = text.replace( ",", "." ).replace( / /g, '' ) // replace comma with dot
+ color: __style.nightColor
+ font: __style.p5
- root.editorValueChanged( val, val === "" )
- }
+ text: internal.suffix
- background: Rectangle {
- color: __style.transparentColor
- }
+ visible: internal.suffix && textField.text.length > 0
}
+ }
+ }
- Text {
- id: suffix
-
- text: internal.suffix ? ' ' + internal.suffix : "" // to make sure there is a space between the number and the suffix
-
- visible: internal.suffix !== "" && numberInput.text !== ""
-
- height: parent.height
- verticalAlignment: Qt.AlignVCenter
+ rightContent: MMComponents.MMIcon {
+ id: rightIcon
- font: __style.p5
- color: numberInput.color
+ size: __style.icon24
+ source: __style.plusIcon
+ color: {
+ if ( root.editState !== "enabled" ) return __style.mediumGreyColor
+ if ( internal.canAddStep ) {
+ if ( root.validationState === "error" ) return __style.grapeColor
+ if ( root.validationState === "warning" ) return __style.earthColor
+ return __style.forestColor
+ }
+ else {
+ if ( root.validationState === "error" ) return __style.negativeColor
+ if ( root.validationState === "warning" ) return __style.warningColor
+ return __style.mediumGreyColor
}
}
}
- rightAction: MMIcon {
- id: rightIcon
+ onLeftContentClicked: {
+ if ( internal.canSubtractStep ) {
+ let decremented = Number( textField.text ) - internal.step
+ root.editorValueChanged( decremented.toFixed( internal.precision ), false )
+ }
+ }
- anchors.verticalCenter: parent.verticalCenter
+ onTextEdited: ( text ) => {
+ let val = text.replace( ",", "." ).replace( / /g, '' ) // replace comma with dot
- size: __style.icon24
- source: __style.plusIcon
- color: enabled ? __style.forestColor : __style.mediumGreenColor
- enabled: Number( numberInput.text ) + internal.step <= internal.to
+ root.editorValueChanged( val, val === "" )
}
- onRightActionClicked: {
- if ( rightIcon.enabled )
- {
- let incremented = Number( numberInput.text ) + internal.step
+ onRightContentClicked: {
+ if ( internal.canAddStep ) {
+ let incremented = Number( textField.text ) + internal.step
root.editorValueChanged( incremented.toFixed( internal.precision ), false )
}
}
@@ -164,6 +159,9 @@ MMBaseInput {
// i.e. if showing 2 decimals, smallest increment will be 0.01
// https://github.com/qgis/QGIS/blob/a038a79997fb560e797daf3903d94c7d68e25f42/src/gui/editorwidgets/qgsdoublespinbox.cpp#L83-L87
property real step: Math.max(_fieldConfig["Step"], Math.pow( 10.0, 0.0 - precision ))
+
+ property bool canSubtractStep: Number( root.textField.text ) - internal.step >= internal.from
+ property bool canAddStep: Number( root.textField.text ) + internal.step <= internal.to
}
// on press and hold behavior can be used from here:
diff --git a/app/qml/form/editors/MMFormPhotoEditor.qml b/app/qml/form/editors/MMFormPhotoEditor.qml
index fa57abfa1..8c04d1138 100644
--- a/app/qml/form/editors/MMFormPhotoEditor.qml
+++ b/app/qml/form/editors/MMFormPhotoEditor.qml
@@ -80,7 +80,7 @@ MMFormPhotoViewer {
warningMsg: _fieldWarningMessage
errorMsg: _fieldErrorMessage
- allowEditing: !_fieldIsReadOnly
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
@@ -204,22 +204,22 @@ MMFormPhotoViewer {
let absolutePath = __inputUtils.getAbsolutePath( root._fieldValue, internal.prefixToRelativePath )
if ( root.photoComponent.status === Image.Error ) {
- root.state = "notAvailable"
+ root.photoState = "notAvailable"
absoluteImagePath = ""
return
}
else if ( root._fieldValue && __inputUtils.fileExists( absolutePath ) ) {
- root.state = "valid"
+ root.photoState = "valid"
absoluteImagePath = "file://" + absolutePath
return
}
else if ( !root._fieldValue || root._fieldValueIsNullfield ) {
- root.state = "notSet"
+ root.photoState = "notSet"
absoluteImagePath = ""
return
}
- root.state = "notAvailable"
+ root.photoState = "notAvailable"
absoluteImagePath = "file://" + absolutePath
}
diff --git a/app/qml/form/editors/MMFormPhotoViewer.qml b/app/qml/form/editors/MMFormPhotoViewer.qml
index d9be3f054..d329cd5c7 100644
--- a/app/qml/form/editors/MMFormPhotoViewer.qml
+++ b/app/qml/form/editors/MMFormPhotoViewer.qml
@@ -8,9 +8,10 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import "../../components"
-import "../../inputs"
+
+import "../../components" as MMComponents
+import "../../components/private" as MMPrivateComponents
+import "../components/photo" as MMPhotoComponents
/*
* Photo viewer for feature form.
@@ -20,83 +21,90 @@ import "../../inputs"
* Serves as a base class for MMPhotoFormEditor.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseInput {
id: root
property url photoUrl: ""
property bool hasCameraCapability: true
- // Do not use "enabled" since we want to always be able to open image previews
- property bool allowEditing: true
-
- property alias photoComponent: photo
+ property var photoComponent: photo
+ property alias photoState: photoStateGroup.state
signal trashClicked()
signal capturePhotoClicked()
signal chooseFromGalleryClicked()
- contentItemHeight: 160 * __dp
- spacing: 0
- radius: 20 * __dp
-
- states: [
- State {
- name: "valid"
- },
- State {
- name: "notSet"
- },
- State {
- name: "notAvailable"
- }
- ]
-
- state: "notSet"
+ StateGroup {
+ id: photoStateGroup
+
+ states: [
+ State {
+ name: "valid"
+ },
+ State {
+ name: "notSet"
+ },
+ State {
+ name: "notAvailable"
+ }
+ ]
- onContentClicked: {
- if ( photo.status === Image.Ready ) {
- previewLoader.active = true
- previewLoader.focus = true
- }
+ state: "notSet"
}
- content: Item {
- MMPhoto {
+
+ inputContent: Rectangle {
+ width: parent.width
+ height: __style.row160
+
+ color: __style.polarColor
+ radius: __style.radius20
+
+ MMComponents.MMPhoto {
id: photo
- width: root.width
- height: root.contentItemHeight
- visible: root.state !== "notSet"
- photoUrl: root.photoUrl
+ width: parent.width
+ height: parent.height
+ visible: photoStateGroup.state !== "notSet"
+
+ photoUrl: root.photoUrl
fillMode: Image.PreserveAspectCrop
MouseArea {
anchors.fill: parent
- onClicked: root.contentClicked()
+ onClicked: {
+ if ( photo.status === Image.Ready ) {
+ previewLoader.active = true
+ previewLoader.focus = true
+ }
+ }
}
- MMRoundButton {
+ MMComponents.MMRoundButton {
anchors {
right: parent.right
bottom: parent.bottom
- rightMargin: 10 * __dp
- bottomMargin: 10 * __dp
+ rightMargin: __style.margin10
+ bottomMargin: __style.margin10
}
bgndColor: __style.negativeColor
iconSource: __style.deleteIcon
iconColor: __style.grapeColor
- visible: root.allowEditing && root.state !== "notSet"
+
+ visible: root.editState === "enabled" && photoStateGroup.state !== "notSet"
+
onClicked: root.trashClicked()
}
}
- MMPhotoAttachment {
- width: root.width
- height: root.contentItemHeight
- visible: root.state === "notSet"
- enabled: root.allowEditing
+ MMPhotoComponents.MMPhotoAttachment {
+ width: parent.width
+ height: parent.height
+
+ visible: photoStateGroup.state === "notSet"
+ enabled: root.editState === "enabled"
hasCameraCapability: root.hasCameraCapability
@@ -116,7 +124,7 @@ MMBaseInput {
Component {
id: previewComponent
- MMPhotoPreview {
+ MMPhotoComponents.MMPhotoPreview {
photoUrl: root.photoUrl
}
}
diff --git a/app/qml/form/editors/MMFormRelationEditor.qml b/app/qml/form/editors/MMFormRelationEditor.qml
index 93a89c791..0931e2415 100644
--- a/app/qml/form/editors/MMFormRelationEditor.qml
+++ b/app/qml/form/editors/MMFormRelationEditor.qml
@@ -9,12 +9,11 @@
import QtQuick
import QtQuick.Controls
-import QtQuick.Controls.Basic
import mm 1.0 as MM
-import "../../inputs" as MMInputs
import "../../components" as MMComponents
+import "../../components/private" as MMPrivateComponents
import "../components" as MMFormComponents
/*
@@ -25,7 +24,7 @@ import "../components" as MMFormComponents
* Should be used only within feature form.
*/
-MMInputs.MMBaseInput {
+MMPrivateComponents.MMBaseInput {
id: root
property var _fieldAssociatedRelation: parent.fieldAssociatedRelation
@@ -38,24 +37,39 @@ MMInputs.MMBaseInput {
signal openLinkedFeature( var linkedFeature )
signal createLinkedFeature( var parentFeature, var relation )
- contentItemHeight: privates.itemHeight * privates.rows + 2 * flow.spacing + 20 * __dp
-
Component.onCompleted: root.recalculateVisibleItems()
onWidthChanged: root.recalculateVisibleItems()
title: _fieldShouldShowTitle ? _fieldTitle : ""
- content: Rectangle {
- width: root.width - 2 * root.spacing
- height: root.contentItemHeight
+ inputContent: Rectangle {
+ width: parent.width
+ height: privates.itemHeight * privates.rows + 2 * flow.spacing + 2 * __style.margin12
+
+ radius: __style.radius12
color: __style.polarColor
+ MouseArea {
+ anchors.fill: parent
+ onClicked: function( mouse ) {
+ mouse.accepted = true
+ listLoader.active = true
+ listLoader.focus = true
+ }
+ }
+
Flow {
id: flow
- anchors.fill: parent
- anchors.margins: 10 * __dp
- spacing: 8 * __dp
+ anchors {
+ fill: parent
+ topMargin: __style.margin12
+ bottomMargin: __style.margin12
+ leftMargin: __style.margin20
+ rightMargin: __style.margin20
+ }
+
+ spacing: __style.margin8
clip: true
Rectangle {
@@ -150,8 +164,6 @@ MMInputs.MMBaseInput {
MouseArea {
anchors.fill: parent
onClicked: {
- if ( !root.enabled )
- return
listLoader.active = true
listLoader.focus = true
}
diff --git a/app/qml/form/editors/MMFormRelationReferenceEditor.qml b/app/qml/form/editors/MMFormRelationReferenceEditor.qml
index 880ae536a..e681c987d 100644
--- a/app/qml/form/editors/MMFormRelationReferenceEditor.qml
+++ b/app/qml/form/editors/MMFormRelationReferenceEditor.qml
@@ -8,30 +8,36 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
import mm 1.0 as MM
-import "../../inputs" as MMInputs
import "../../components" as MMComponents
+import "../../components/private" as MMPrivateComponents
import "../components" as MMFormComponents
-MMInputs.MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property var _fieldValue: parent.fieldValue
property var _fieldConfig: parent.fieldConfig
property var _fieldActiveProject: parent.fieldActiveProject
- property bool _fieldValueIsNull: parent.fieldValueIsNull
+
property bool _fieldIsReadOnly: parent.fieldIsReadOnly
- property string _fieldTitle: parent.fieldTitle
+
property bool _fieldShouldShowTitle: parent.fieldShouldShowTitle
+ property string _fieldTitle: parent.fieldTitle
+ property string _fieldErrorMessage: parent.fieldErrorMessage
+ property string _fieldWarningMessage: parent.fieldWarningMessage
+
+ property bool _fieldRememberValueSupported: parent.fieldRememberValueSupported
+ property bool _fieldRememberValueState: parent.fieldRememberValueState
signal openLinkedFeature( /* FeaturePair */ var linkedFeature )
signal editorValueChanged( var newValue, bool isNull )
+ signal rememberValueBoxClicked( bool state )
on_FieldValueChanged: {
- title.text = rModel.attributeFromForeignKey( root._fieldValue, MM.FeaturesModel.FeatureTitle ) || ""
+ textField.text = rModel.attributeFromForeignKey( root._fieldValue, MM.FeaturesModel.FeatureTitle ) || ""
}
title: _fieldShouldShowTitle ? _fieldTitle : ""
@@ -39,7 +45,7 @@ MMInputs.MMBaseInput {
errorMsg: _fieldErrorMessage
warningMsg: _fieldWarningMessage
- enabled: !_fieldIsReadOnly
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
@@ -48,51 +54,35 @@ MMInputs.MMBaseInput {
root.rememberValueBoxClicked( checkboxChecked )
}
- MM.RelationReferenceFeaturesModel {
- id: rModel
-
- config: root._fieldConfig
- project: root._fieldActiveProject
-
- onModelReset: title.text = rModel.attributeFromForeignKey( root._fieldValue, MM.FeaturesModel.FeatureTitle ) || ""
- }
-
- content: Text {
- id: title
+ textField.readOnly: true
- anchors.fill: parent
- font: __style.p5
- text: root._fieldValue
- color: __style.nightColor
- verticalAlignment: Text.AlignVCenter
- }
-
- onContentClicked: {
+ textField.onReleased: { // can be opened even when the field is readonly
let featurePair = rModel.attributeFromForeignKey( root._fieldValue, MM.FeaturesModel.FeaturePair )
-
- if ( featurePair == null || !featurePair.valid ) return
+ if ( featurePair === null || !featurePair.valid ) return
openLinkedFeature( featurePair )
}
- rightAction: MMComponents.MMIcon {
- id: rightIcon
-
- anchors.verticalCenter: parent.verticalCenter
-
+ rightContent: MMComponents.MMIcon {
size: __style.icon24
source: __style.linkIcon
- color: enabled ? __style.forestColor : __style.mediumGreenColor
+ color: root.iconColor
}
- onRightActionClicked: {
- if ( root._fieldIsReadOnly )
- return
-
+ onRightContentClicked: {
listLoader.active = true
listLoader.focus = true
}
+ MM.RelationReferenceFeaturesModel {
+ id: rModel
+
+ config: root._fieldConfig
+ project: root._fieldActiveProject
+
+ onModelReset: textField.text = rModel.attributeFromForeignKey( root._fieldValue, MM.FeaturesModel.FeatureTitle ) || ""
+ }
+
Loader {
id: listLoader
diff --git a/app/qml/form/editors/MMFormRichTextViewer.qml b/app/qml/form/editors/MMFormRichTextViewer.qml
index 30479e105..ec226d191 100644
--- a/app/qml/form/editors/MMFormRichTextViewer.qml
+++ b/app/qml/form/editors/MMFormRichTextViewer.qml
@@ -8,48 +8,48 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import "../components"
-Item {
+import "../../components/private" as MMPrivateComponents
+
+MMPrivateComponents.MMBaseInput {
id: root
property var _fieldValue: parent.fieldValue
property var _fieldConfig: parent.fieldConfig
- property real padding: 11 * __dp
+ property bool _fieldShouldShowTitle: parent.fieldShouldShowTitle
+
+ property string _fieldTitle: parent.fieldTitle
- height: textArea.height
- width: parent.width
+ title: _fieldShouldShowTitle ? _fieldTitle : ""
- Rectangle { // background
- width: root.width
- height: root.height
- border.width: 2 * __dp
- border.color: __style.transparentColor
+ inputContent: Rectangle { // background
+ width: parent.width
+ height: textArea.implicitHeight
color: __style.polarColor
radius: __style.radius12
- }
- Text {
- id: textArea
+ Text { // intentionally not MMText to that bottom padding works correctly in rich text mode
+ id: textArea
+
+ width: parent.width
- wrapMode: Text.Wrap
- font: __style.p5
- color: __style.nightColor
+ wrapMode: Text.Wrap
+ font: __style.p5
+ color: __style.nightColor
- text: root._fieldValue !== undefined ? root._fieldValue : ''
- textFormat: _fieldConfig['UseHtml'] ? TextEdit.RichText : TextEdit.PlainText
+ text: root._fieldValue !== undefined ? root._fieldValue : ''
+ textFormat: root._fieldConfig['UseHtml'] ? TextEdit.RichText : TextEdit.PlainText
- width: root.width
- topPadding: root.padding
- bottomPadding: root.padding
- leftPadding: root.padding
- rightPadding: root.padding
+ topPadding: __style.margin12
+ bottomPadding: __style.margin12
+ leftPadding: __style.margin20
+ rightPadding: __style.margin20
- onLinkActivated: function( link ) {
- Qt.openUrlExternally( link )
+ onLinkActivated: function( link ) {
+ Qt.openUrlExternally( link )
+ }
}
}
}
diff --git a/app/qml/form/editors/MMFormScannerEditor.qml b/app/qml/form/editors/MMFormScannerEditor.qml
index a926742f4..f2defc302 100644
--- a/app/qml/form/editors/MMFormScannerEditor.qml
+++ b/app/qml/form/editors/MMFormScannerEditor.qml
@@ -8,10 +8,9 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
-import "../../components"
-import "../../inputs"
+
+import "../../components" as MMComponents
+import "../../components/private" as MMPrivateComponents
/*
* QR/Barcode scanner editor for QGIS Attribute Form
@@ -21,7 +20,7 @@ import "../../inputs"
* Should be used only within feature form.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property var _fieldValue: parent.fieldValue
@@ -38,9 +37,6 @@ MMBaseInput {
property bool _fieldRememberValueSupported: parent.fieldRememberValueSupported
property bool _fieldRememberValueState: parent.fieldRememberValueState
- property alias placeholderText: textField.placeholderText
- property alias text: textField.text
-
signal editorValueChanged( var newValue, bool isNull )
signal rememberValueBoxClicked( bool state )
@@ -49,8 +45,7 @@ MMBaseInput {
warningMsg: _fieldWarningMessage
errorMsg: _fieldErrorMessage
- hasFocus: textField.activeFocus
- enabled: !_fieldIsReadOnly
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
@@ -59,39 +54,20 @@ MMBaseInput {
root.rememberValueBoxClicked( checkboxChecked )
}
- content: TextField {
- id: textField
-
- anchors.fill: parent
- anchors.verticalCenter: parent.verticalCenter
-
- readOnly: !root.enabled
-
- text: root._fieldValue === undefined || root._fieldValueIsNull ? '' : root._fieldValue
+ text: root._fieldValue === undefined || root._fieldValueIsNull ? '' : root._fieldValue
- color: __style.nightColor
- placeholderTextColor: __style.nightAlphaColor
+ onTextEdited: root.editorValueChanged( root.text, root.text === "" )
- font: __style.p5
- hoverEnabled: true
-
- background: Rectangle { color: __style.transparentColor }
-
- onTextEdited: root.editorValueChanged( textField.text, textField.text === "" )
- }
-
- rightAction: MMIcon {
+ rightContent: MMComponents.MMIcon {
property bool pressed: false
- anchors.verticalCenter: parent.verticalCenter
-
size: __style.icon24
source: __style.qrCodeIcon
- color: root.enabled ? __style.forestColor : __style.mediumGreenColor
+ color: root.iconColor
}
- onRightActionClicked: {
- if ( !root.enabled )
+ onRightContentClicked: {
+ if ( root.editState !== "enabled" )
return
if (!__inputUtils.acquireCameraPermission())
@@ -112,7 +88,7 @@ MMBaseInput {
Component {
id: readerComponent
- MMCodeScanner {
+ MMComponents.MMCodeScanner {
focus: true
onClosed: codeScannerLoader.active = false
diff --git a/app/qml/form/editors/MMFormSliderEditor.qml b/app/qml/form/editors/MMFormSliderEditor.qml
index 573ea80dc..6465ecc62 100644
--- a/app/qml/form/editors/MMFormSliderEditor.qml
+++ b/app/qml/form/editors/MMFormSliderEditor.qml
@@ -10,9 +10,8 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
-import QtQuick.Layouts
-import "../../inputs"
+import "../../components/private" as MMPrivateComponents
/*
* Number slider editor for QGIS Attribute Form
@@ -22,7 +21,7 @@ import "../../inputs"
* Should be used only within feature form.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property var _fieldValue: parent.fieldValue
@@ -46,8 +45,7 @@ MMBaseInput {
warningMsg: _fieldWarningMessage
errorMsg: _fieldErrorMessage
- hasFocus: slider.activeFocus
- enabled: !_fieldIsReadOnly
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
@@ -56,67 +54,61 @@ MMBaseInput {
root.rememberValueBoxClicked( checkboxChecked )
}
- content: Item {
- id: input
-
- anchors.fill: parent
+ textField {
+ text: Number( slider.value ).toFixed( internal.precision ).toLocaleString( root.locale ) + ' ' + internal.suffix
+ readOnly: true
+ }
- RowLayout {
- id: rowLayout
+ rightContentMouseArea.enabled: false
- anchors.fill: parent
+ rightContent: Slider {
+ id: slider
- Text {
- id: valueLabel
+ width: root.width / 2
- Layout.preferredWidth: rowLayout.width / 2 - root.spacing
- Layout.maximumWidth: rowLayout.width / 2 - root.spacing
- Layout.preferredHeight: input.height
- Layout.maximumHeight: input.height
+ to: internal.to
+ from: internal.from
+ stepSize: internal.step
- elide: Text.ElideRight
- text: Number( slider.value ).toFixed( internal.precision ).toLocaleString( root.locale ) + ' ' + internal.suffix
+ enabled: root.editState === "enabled"
+ value: root._fieldValue ? root._fieldValue : 0
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignLeft
- font: __style.p5
- color: __style.nightColor
- }
+ onPressedChanged: textField.focus = true
+ onValueChanged: root.editorValueChanged( slider.value, false )
- Slider {
- id: slider
+ background: Rectangle {
+ x: slider.leftPadding
+ y: slider.topPadding + slider.availableHeight / 2 - height / 2
+ width: slider.availableWidth
+ height: __style.row4
+ radius: __style.radius2
- Layout.fillWidth: true
- Layout.maximumHeight: input.height
- Layout.preferredHeight: input.height
+ color: {
+ if ( root.validationState === "error" ) return __style.negativeColor
+ if ( root.validationState === "warning" ) return __style.warningColor
+ return __style.lightGreenColor
+ }
- to: internal.to
- from: internal.from
- stepSize: internal.step
- value: root._fieldValue ? root._fieldValue : 0
+ Rectangle {
+ // fill indicator
+ height: parent.height
+ width: slider.visualPosition * parent.width
- onValueChanged: root.editorValueChanged( slider.value, false )
+ color: root.iconColor
- background: Rectangle {
- x: slider.leftPadding
- y: slider.topPadding + slider.availableHeight / 2 - height / 2
- width: slider.availableWidth
- height: 4 * __dp
- radius: 2 * __dp
+ radius: __style.radius2
+ }
+ }
- color: __style.lightGreenColor
- }
+ handle: Rectangle {
+ x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
+ y: slider.topPadding + slider.availableHeight / 2 - height / 2
+ width: 20 * __dp
+ height: width
- handle: Rectangle {
- x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
- y: slider.topPadding + slider.availableHeight / 2 - height / 2
- width: 20 * __dp
- height: width
- radius: height / 2
+ radius: height / 2
- color: root.enabled ? __style.forestColor : __style.lightGreenColor
- }
- }
+ color: root.iconColor
}
}
diff --git a/app/qml/form/editors/MMFormSwitchEditor.qml b/app/qml/form/editors/MMFormSwitchEditor.qml
index 365f64409..7c7ff20cc 100644
--- a/app/qml/form/editors/MMFormSwitchEditor.qml
+++ b/app/qml/form/editors/MMFormSwitchEditor.qml
@@ -8,8 +8,7 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import "../../components"
+
import "../../inputs"
/*
@@ -18,9 +17,10 @@ import "../../inputs"
* These properties are injected here via 'fieldXYZ' properties and captured with underscore `_`.
*
* Should be used only within feature form.
+ * See MMBaseSingleLineInput
*/
-MMBaseInput {
+MMSwitchInput {
id: root
property var _field: parent.field
@@ -45,47 +45,22 @@ MMBaseInput {
warningMsg: _fieldWarningMessage
errorMsg: _fieldErrorMessage
- enabled: !_fieldIsReadOnly
-
- hasFocus: rightSwitch.focus
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
- onCheckboxCheckedChanged: {
- root.rememberValueBoxClicked( checkboxChecked )
- }
-
- content: Text {
- id: textField
-
- width: parent.width
- anchors.verticalCenter: parent.verticalCenter
+ text: checked ? internal.checkedStateValue : internal.uncheckedStateValue
- text: rightSwitch.checked ? internal.checkedStateValue : internal.uncheckedStateValue
+ checked: _fieldValue === internal.checkedStateValue
- color: __style.nightColor
- font: __style.p5
- elide: Text.ElideRight
+ onToggled: {
+ let newVal = checked ? internal.checkedStateValue : internal.uncheckedStateValue
+ editorValueChanged( newVal, false )
}
- onContentClicked: {
- rightSwitch.toggle()
- }
-
- rightAction: MMSwitch {
- id: rightSwitch
-
- height: parent.height
- x: -__style.margin20
-
- uncheckedBgColor: __style.lightGreenColor
- checked: root._fieldValue === internal.checkedStateValue
-
- onCheckedChanged: {
- let newVal = rightSwitch.checked ? internal.checkedStateValue : internal.uncheckedStateValue
- root.editorValueChanged( newVal, false )
- }
+ onCheckboxCheckedChanged: {
+ rememberValueBoxClicked( checkboxChecked )
}
function getConfigValue( configValue, defaultValue ) {
diff --git a/app/qml/form/editors/MMFormTextEditor.qml b/app/qml/form/editors/MMFormTextEditor.qml
index 68122a5e6..49eeb53a8 100644
--- a/app/qml/form/editors/MMFormTextEditor.qml
+++ b/app/qml/form/editors/MMFormTextEditor.qml
@@ -10,7 +10,7 @@
import QtQuick
import QtQuick.Controls
-import "../../inputs"
+import "../../components/private" as MMPrivateComponents
/*
* Text Edit for QGIS Attribute Form
@@ -18,10 +18,10 @@ import "../../inputs"
* These properties are injected here via 'fieldXYZ' properties and captured with underscore `_`.
*
* Should be used only within feature form.
- * See MMTextInput
+ * See MMBaseSingleLineInput
*/
-MMTextInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property var _field: parent.field
@@ -43,12 +43,8 @@ MMTextInput {
text: _fieldValue === undefined || _fieldValueIsNull ? '' : _fieldValue
- showClearIcon: false
-
readOnly: _fieldIsReadOnly
- textFieldComponent.readOnly: _fieldIsReadOnly
- textFieldComponent.inputMethodHints: root._field.isNumeric ? Qt.ImhFormattedNumbersOnly : Qt.ImhNone
- textFieldComponent.color: __style.nightColor
+ textField.inputMethodHints: root._field.isNumeric ? Qt.ImhNoPredictiveText | Qt.ImhFormattedNumbersOnly : Qt.ImhNoPredictiveText
title: _fieldShouldShowTitle ? _fieldTitle : ""
@@ -58,7 +54,7 @@ MMTextInput {
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
- textFieldComponent.maximumLength: {
+ textField.maximumLength: {
if ( ( !root._field.isNumeric ) && ( root._field.length > 0 ) ) {
return root._field.length
}
@@ -79,10 +75,6 @@ MMTextInput {
root.editorValueChanged( val, val === "" )
}
- // Avoid Android's uncommited text
- // Could in theory be fixed with `inputMethodComposing` TextInput property instead
- textFieldComponent.onPreeditTextChanged: if ( __androidUtils.isAndroid ) Qt.inputMethod.commit()
-
QtObject {
id: internal
diff --git a/app/qml/form/editors/MMFormTextMultilineEditor.qml b/app/qml/form/editors/MMFormTextMultilineEditor.qml
index 2627573d1..fd82f401a 100644
--- a/app/qml/form/editors/MMFormTextMultilineEditor.qml
+++ b/app/qml/form/editors/MMFormTextMultilineEditor.qml
@@ -9,9 +9,12 @@
import QtQuick
import QtQuick.Controls
+
+// To ignore the warning "The current style does not support customization"
+// see from https://stackoverflow.com/questions/76625756/the-current-style-does-not-support-customization-of-this-control
import QtQuick.Controls.Basic
-import "../../components"
-import "../../inputs"
+
+import "../../components/private" as MMPrivateComponents
/*
* Text multiline editor for QGIS Attribute Form
@@ -20,7 +23,7 @@ import "../../inputs"
*
* Should be used only within feature form.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseInput {
id: root
property var _fieldValue: parent.fieldValue
@@ -37,11 +40,6 @@ MMBaseInput {
property bool _fieldRememberValueSupported: parent.fieldRememberValueSupported
property bool _fieldRememberValueState: parent.fieldRememberValueState
- property alias placeholderText: textArea.placeholderText
- property string text: _fieldValue === undefined || _fieldValueIsNull ? '' : _fieldValue
-
- property int minimumRows: 3
-
signal editorValueChanged( var newValue, var isNull )
signal rememberValueBoxClicked( bool state )
@@ -50,7 +48,7 @@ MMBaseInput {
warningMsg: _fieldWarningMessage
errorMsg: _fieldErrorMessage
- hasFocus: textArea.activeFocus
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
@@ -59,46 +57,79 @@ MMBaseInput {
root.rememberValueBoxClicked( checkboxChecked )
}
- contentItemHeight: {
- const minHeight = 34 * __dp + metrics.height * root.minimumRows
- var realHeight = textArea.y + textArea.contentHeight + 2 * textArea.verticalPadding
- return realHeight < minHeight ? minHeight : realHeight
- }
-
- content: TextArea {
+ inputContent: TextArea {
id: textArea
- property real verticalPadding: 11 * __dp
-
- y: textArea.verticalPadding
- height: contentHeight + textArea.verticalPadding
width: parent.width
+ height: Math.max( implicitHeight, internal.minHeight )
- readOnly: root._fieldIsReadOnly
-
- text: root.text
+ text: _fieldValue === undefined || _fieldValueIsNull ? '' : _fieldValue
textFormat: root._fieldConfig['UseHtml'] ? TextEdit.RichText : TextEdit.PlainText
- hoverEnabled: true
- placeholderTextColor: __style.nightAlphaColor
- color: __style.nightColor
+ topPadding: __style.margin12
+ bottomPadding: __style.margin12
+ leftPadding: __style.margin20
+ rightPadding: __style.margin20
- font: __style.p5
- wrapMode: Text.WordWrap
+ wrapMode: TextEdit.Wrap
- onLinkActivated: function( link ) {
- Qt.openUrlExternally( link )
+ font: __style.p5
+ color: {
+ if ( root.editState === "readOnly" ) return __style.nightColor
+ if ( root.editState === "enabled" ) return __style.nightColor
+ if ( root.editState === "disabled" ) return __style.mediumGreyColor
+ return __style.nightColor
}
+ placeholderTextColor: __style.darkGreyColor
+
+ inputMethodHints: Qt.ImhNoPredictiveText
- onTextChanged: root.editorValueChanged( text, text === "" )
+ readOnly: root.editState !== "enabled"
- // Avoid Android's uncommited text
- // Could in theory be fixed with `inputMethodComposing` TextInput property instead
- onPreeditTextChanged: if ( __androidUtils.isAndroid ) Qt.inputMethod.commit()
+ background: Rectangle {
+
+ color: {
+ if ( root.editState !== "enabled" ) return __style.polarColor
+ if ( root.validationState === "error" ) return __style.negativeUltraLightColor
+ if ( root.validationState === "warning" ) return __style.negativeUltraLightColor
+
+ return __style.polarColor
+ }
+
+ border.width: {
+ if ( root.validationState === "error" ) return __style.width2
+ if ( root.validationState === "warning" ) return __style.width2
+ if ( textArea.activeFocus ) return __style.width2
+ if ( textArea.hovered ) return __style.width1
+ return 0
+ }
+
+ border.color: {
+ if ( root.editState !== "enabled" ) return __style.polarColor
+ if ( root.validationState === "error" ) return __style.negativeColor
+ if ( root.validationState === "warning" ) return __style.warningColor
+ if ( textArea.activeFocus ) return __style.forestColor
+ if ( textArea.hovered ) return __style.forestColor
+
+ return __style.polarColor
+ }
+
+ radius: __style.radius12
+ }
+
+ onLinkActivated: ( link ) => Qt.openUrlExternally( link )
+ onTextChanged: root.editorValueChanged( textArea.text, textArea.text === "" )
}
FontMetrics {
id: metrics
font: textArea.font
}
+
+ QtObject {
+ id: internal
+
+ // Minimum height for multiline is 3 lines + paddings
+ property real minHeight: metrics.height * 3 + textArea.topPadding + textArea.bottomPadding
+ }
}
diff --git a/app/qml/form/editors/MMFormValueMapEditor.qml b/app/qml/form/editors/MMFormValueMapEditor.qml
index f4eeca432..45c4c9f3d 100644
--- a/app/qml/form/editors/MMFormValueMapEditor.qml
+++ b/app/qml/form/editors/MMFormValueMapEditor.qml
@@ -47,13 +47,11 @@ MMFormComboboxBaseEditor {
errorMsg: _fieldErrorMessage
warningMsg: _fieldWarningMessage
- enabled: !_fieldIsReadOnly
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
- textFieldComponent.color: __style.nightColor
-
onCheckboxCheckedChanged: {
root.rememberValueBoxClicked( checkboxChecked )
}
diff --git a/app/qml/form/editors/MMFormValueRelationEditor.qml b/app/qml/form/editors/MMFormValueRelationEditor.qml
index aaad6c310..d43c5a950 100644
--- a/app/qml/form/editors/MMFormValueRelationEditor.qml
+++ b/app/qml/form/editors/MMFormValueRelationEditor.qml
@@ -48,13 +48,11 @@ MMFormComboboxBaseEditor {
errorMsg: _fieldErrorMessage
warningMsg: _fieldWarningMessage
- enabled: !_fieldIsReadOnly
+ readOnly: _fieldIsReadOnly
hasCheckbox: _fieldRememberValueSupported
checkboxChecked: _fieldRememberValueState
- textFieldComponent.color: __style.nightColor
-
on_FieldValueChanged: {
vrModel.pair = root._fieldFeatureLayerPair
}
diff --git a/app/qml/inputs/MMBaseInput.qml b/app/qml/inputs/MMBaseInput.qml
deleted file mode 100644
index 7c117a3ec..000000000
--- a/app/qml/inputs/MMBaseInput.qml
+++ /dev/null
@@ -1,198 +0,0 @@
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-
-import QtQuick
-import QtQuick.Controls
-import QtQml.Models
-import QtQuick.Layouts
-
-import "../components"
-import "."
-
-//! This is a base class for all inputs/form editors, do not use this in the app directly
-
-Item {
- id: root
-
- signal contentClicked()
- signal leftActionClicked()
- signal rightActionClicked()
-
- property alias title: titleItem.text
- property alias leftAction: leftActionContainer.children
- property alias content: contentContainer.children
- property alias rightAction: rightActionContainer.children
- property string warningMsg
- property string errorMsg
- property bool hasFocus: false
- property color bgColor: __style.polarColor
- property bool hasCheckbox: false
- property alias checkboxChecked: checkbox.checked
-
- property real contentItemHeight: 50 * __dp
-
- property real spacing: 15 * __dp
- property real radius: __style.radius12
-
- width: parent.width
- height: mainColumn.height
-
- Column {
- id: mainColumn
-
- spacing: 6 * __dp
- anchors.left: parent.left
- anchors.right: parent.right
-
- Row {
- id: titleRow
-
- spacing: 4 * __dp
- width: parent.width
- visible: titleItem.text.length > 0
-
- MMCheckBox {
- id: checkbox
-
- small: true
- visible: root.hasCheckbox
- }
- Text {
- id: titleItem
-
- width: parent.width - checkbox.width - titleRow.spacing
-
- font: __style.p6
- wrapMode: Text.WordWrap
- }
- }
-
- Item {
- height: root.contentItemHeight
- anchors.left: parent.left
- anchors.right: parent.right
-
- Rectangle {
- id: background
-
- width: parent.width
- height: parent.height
-
- border.width: 2 * __dp
- color: root.bgColor
- radius: root.radius
- border.color: {
- if (root.hasFocus) {
- if (errorMsg.length > 0) {
- return __style.negativeColor
- }
- else if (warningMsg.length > 0) {
- return __style.warningColor
- }
- return __style.forestColor
- }
- return __style.transparentColor
- }
- }
-
- Row {
- height: parent.height
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.leftMargin: root.spacing
- anchors.rightMargin: root.spacing
-
- Item {
- id: leftActionContainer
-
- property bool actionAllowed: leftActionContainer.children.length > 1
-
- height: parent.height
- width: actionAllowed ? height/2 : 0
-
- Item {
- width: leftActionContainer.actionAllowed ? parent.width + root.spacing/2 : 0
- height: parent.height
- anchors.centerIn: parent
-
- MouseArea {
- anchors.fill: parent
- onReleased: root.leftActionClicked()
- }
- }
- }
-
- Item {
- id: contentContainer
-
- height: parent.height
- width: parent.width - (leftActionContainer.actionAllowed ? leftActionContainer.width : 0) - (rightActionContainer.actionAllowed ? rightActionContainer.width : 0)
-
- MouseArea {
- anchors.fill: parent
-
- onClicked: {
- root.contentClicked()
- }
- }
- }
-
- Item {
- id: rightActionContainer
-
- property bool actionAllowed: rightActionContainer.children.length > 1
-
- height: parent.height
- width: actionAllowed ? height/2 : 0
-
- Item {
- width: rightActionContainer.actionAllowed ? parent.width + root.spacing/2 : 0
- height: parent.height
- anchors.centerIn: parent
-
- MouseArea {
- anchors.fill: parent
- onReleased: root.rightActionClicked()
- }
- }
- }
- }
- }
-
- Item {
- id: messageItem
-
- width: parent.width
- height: msgRow.height
-
- Row {
- id: msgRow
-
- spacing: 4 * __dp
-
- MMIcon {
- id: msgIcon
-
- source: visible ? __style.errorCircleIcon : ""
- color: errorMsg.length > 0 ? __style.negativeColor : __style.warningColor
- size: __style.icon16
- visible: errorMsg.length > 0 || warningMsg.length > 0
- }
- Text {
- width: messageItem.width - msgRow.spacing - msgIcon.width
-
- text: root.errorMsg.length > 0 ? root.errorMsg : root.warningMsg
- font: __style.t4
- wrapMode: Text.WordWrap
- visible: root.errorMsg.length > 0 || root.warningMsg.length > 0
- }
- }
- }
- }
-}
diff --git a/app/qml/inputs/MMComboboxInput.qml b/app/qml/inputs/MMComboboxInput.qml
index d600ef13e..29daef92c 100644
--- a/app/qml/inputs/MMComboboxInput.qml
+++ b/app/qml/inputs/MMComboboxInput.qml
@@ -10,15 +10,16 @@
import QtQuick
import "../components" as MMComponents
+import "../components/private" as MMPrivateComponents
/*
* Common text input to use in the app.
* Disabled state can be achieved by setting `enabled: false`.
*
- * See MMBaseInput for more properties.
+ * See MMBaseSingleLineInput for more properties.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property alias loader: drawerLoader
@@ -30,34 +31,22 @@ MMBaseInput {
property string textRole: "text"
property string valueRole: "value"
- onRightActionClicked: { drawerLoader.active = true; drawerLoader.focus = true }
- onContentClicked: { drawerLoader.active = true; drawerLoader.focus = true }
+ onTextClicked: { drawerLoader.active = true; drawerLoader.focus = true }
+ onRightContentClicked: { drawerLoader.active = true; drawerLoader.focus = true }
- content: MMComponents.MMText {
- id: textField
+ text: {
+ if ( !comboboxModel ) return "";
+ if ( currentIndex < 0 || currentIndex >= comboboxModel.count ) return "";
- anchors.fill: parent
-
- font: __style.p5
-
- color: root.enabled ? __style.nightColor : __style.mediumGreenColor
-
- text: {
- if ( !comboboxModel ) return "";
- if ( currentIndex < 0 || currentIndex >= comboboxModel.count ) return "";
-
- return comboboxModel.get( currentIndex )[textRole]
- }
+ return comboboxModel.get( currentIndex )[textRole]
}
- rightAction: MMComponents.MMIcon {
+ rightContent: MMComponents.MMIcon {
property bool pressed: false
- anchors.verticalCenter: parent.verticalCenter
-
size: __style.icon24
- source: __style.arrowDownIcon
- color: root.enabled ? __style.forestColor : __style.mediumGreenColor
+ source: drawerLoader.active ? __style.arrowUpIcon : __style.arrowDownIcon
+ color: root.iconColor
}
Loader {
diff --git a/app/qml/inputs/MMPasswordInput.qml b/app/qml/inputs/MMPasswordInput.qml
index bf9f1cd2a..bc0850dc9 100644
--- a/app/qml/inputs/MMPasswordInput.qml
+++ b/app/qml/inputs/MMPasswordInput.qml
@@ -8,46 +8,26 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
-import "../components"
-MMBaseInput {
- id: root
-
- property alias placeholderText: textField.placeholderText
- property alias text: textField.text
-
- hasFocus: textField.activeFocus
+import "../components" as MMComponents
+import "../components/private" as MMPrivateComponents
- content: TextField {
- id: textField
+MMPrivateComponents.MMBaseSingleLineInput {
+ id: root
- anchors.fill: parent
- anchors.verticalCenter: parent.verticalCenter
+ textField.echoMode: eyeButton.pressed ? TextInput.Normal : TextInput.Password
- color: root.enabled ? __style.nightColor : __style.mediumGreenColor
- placeholderTextColor: __style.nightAlphaColor
- font: __style.p5
- hoverEnabled: true
- echoMode: eyeButton.pressed ? TextInput.Normal : TextInput.Password
- inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
- background: Rectangle {
- color: __style.transparentColor
- }
- }
+ textField.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhHiddenText
- rightAction: MMIcon {
+ rightContent: MMComponents.MMIcon {
id: eyeButton
property bool pressed: false
- anchors.verticalCenter: parent.verticalCenter
-
size: __style.icon24
source: pressed ? __style.hideIcon : __style.showIcon
- color: root.enabled ? __style.forestColor : __style.mediumGreenColor
+ color: root.iconColor
}
- onRightActionClicked: eyeButton.pressed = !eyeButton.pressed
+ onRightContentClicked: eyeButton.pressed = !eyeButton.pressed
}
diff --git a/app/qml/inputs/MMSearchInput.qml b/app/qml/inputs/MMSearchInput.qml
index 9f8f0c8e1..ca3842456 100644
--- a/app/qml/inputs/MMSearchInput.qml
+++ b/app/qml/inputs/MMSearchInput.qml
@@ -8,91 +8,45 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
-import "../components"
+import "../components" as MMComponents
+import "../components/private" as MMPrivateComponents
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
- property alias textFieldComponent: textField
- property alias placeholderText: textField.placeholderText
- property alias text: textField.text
- property bool allowTimer: false
+ property bool delayedSearch: false
property int emitInterval: 200
property bool showClearIcon: true
+ property string searchText: ""
- hasFocus: textField.activeFocus
-
- signal searchTextChanged( string text )
-
- /**
- * Used for deactivating focus on MMSearchInput when another component should have focus.
- * and the current element's forceActiveFocus() doesnt deactivates SearchBar focus.
- */
- function deactivate() {
- textField.focus = false
- if ( textField.length > 0 )
- textField.clear()
- searchTextChanged("")
- }
-
- content: TextField {
- id: textField
-
- anchors.fill: parent
- anchors.verticalCenter: parent.verticalCenter
-
- color: root.enabled ? __style.nightColor : __style.mediumGreenColor
- placeholderTextColor: __style.nightAlphaColor
- font: __style.p5
- hoverEnabled: true
- background: Rectangle {
- color: __style.transparentColor
- }
-
- onDisplayTextChanged: {
- if ( root.allowTimer ) {
- if ( searchTimer.running )
- searchTimer.restart()
- else
- searchTimer.start()
- }
- else
- {
- root.searchTextChanged( textField.displayText )
- }
- }
- }
-
- leftAction: MMIcon {
+ leftContent: MMComponents.MMIcon {
id: searchIcon
- property bool pressed: false
-
- anchors.verticalCenter: parent.verticalCenter
-
size: __style.icon24
source: __style.searchIcon
- color: root.enabled ? __style.nightColor : __style.mediumGreenColor
+ color: {
+ if ( root.editState === "disabled" ) return __style.mediumGreyColor
+ if ( root.validationState === "error" ) return __style.grapeColor
+ if ( root.validationState === "warning" ) return __style.earthColor
+ return __style.nightColor
+ }
}
- rightAction: MMIcon {
+ rightContent: MMComponents.MMIcon {
id: rightIcon
- anchors.verticalCenter: parent.verticalCenter
-
size: __style.icon24
source: __style.closeIcon
- color: root.enabled ? __style.forestColor : __style.mediumGreenColor
- visible: root.showClearIcon && textField.activeFocus && textField.text.length > 0
+ color: root.iconColor
}
- onRightActionClicked: {
- if (root.showClearIcon) {
+ rightContentVisible: root.showClearIcon && textField.activeFocus && root.text.length > 0
+
+ onRightContentClicked: {
+ if ( root.showClearIcon ) {
textField.clear()
- root.searchTextChanged("")
+ root.searchText = ""
}
else {
// if the clear button should not be there, let's open keyboard instead
@@ -100,14 +54,33 @@ MMBaseInput {
}
}
+ onTextEdited: {
+ if ( root.delayedSearch ) {
+ searchTimer.restart()
+ }
+ else
+ {
+ root.searchText = root.text
+ }
+ }
+
Timer {
id: searchTimer
interval: root.emitInterval
running: false
- onTriggered: {
- searchTextChanged( root.text )
- }
+ onTriggered: root.searchText = root.text
+ }
+
+ /**
+ * Used for deactivating focus on MMSearchInput when another component should have focus.
+ * and the current element's forceActiveFocus() doesnt deactivates SearchBar focus.
+ */
+ function deactivate() {
+ root.textField.focus = false
+ if ( root.text.length > 0 )
+ root.textField.clear()
+ root.searchText = ""
}
}
diff --git a/app/qml/inputs/MMSwitchInput.qml b/app/qml/inputs/MMSwitchInput.qml
index 913b104f6..a534c22bd 100644
--- a/app/qml/inputs/MMSwitchInput.qml
+++ b/app/qml/inputs/MMSwitchInput.qml
@@ -8,49 +8,51 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
-import "../components"
+
+import "../components" as MMComponents
+import "../components/private" as MMPrivateComponents
/*
* Common switch input to use in the app.
*
- * See MMBaseInput for more properties.
+ * See MMBaseSingleLineInput for more properties.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
- property alias text: textField.text
- property alias switchComponent: switchComponent
-
- hasFocus: textField.activeFocus
-
- content: TextField {
- id: textField
+ property alias checked: switchComponent.checked
+ //! emitted when interactively toggled by the user via touch, mouse, or keyboard.
+ signal toggled()
- anchors.fill: parent
+ textField.readOnly: true
- readOnly: true
- placeholderTextColor: __style.nightAlphaColor
- color: root.enabled ? __style.nightColor : __style.mediumGreenColor
+ rightContent: MMComponents.MMSwitch {
+ id: switchComponent
- font: __style.p5
- hoverEnabled: true
+ uncheckedBgColor: {
+ if ( root.editState !== "enabled" ) return __style.lightGreenColor
+ if ( root.validationState === "error" ) return __style.negativeLightColor
+ if ( root.validationState === "warning" ) return __style.sandColor
+ return __style.lightGreenColor
+ }
- background: Rectangle {
- color: __style.transparentColor
+ checkedBgColor: {
+ if ( root.editState !== "enabled" ) return __style.mediumGreenColor
+ if ( root.validationState === "error" ) return __style.negativeColor
+ if ( root.validationState === "warning" ) return __style.warningColor
+ return __style.grassColor
}
- onTextEdited: root.textEdited( textField.text )
+ handleColor: root.iconColor
}
- rightAction: MMSwitch {
- id: switchComponent
+ onTextClicked: toggleSwitchComponent()
- anchors.verticalCenter: parent.verticalCenter
- x: -20 * __dp // TODO why is this needed? bacause of how baseinput works :(
+ onRightContentClicked: toggleSwitchComponent()
- uncheckedBgColor: __style.lightGreenColor
+ function toggleSwitchComponent() {
+ switchComponent.toggle()
+ toggled()
}
}
diff --git a/app/qml/inputs/MMTextInput.qml b/app/qml/inputs/MMTextInput.qml
index 2b030704c..aab67ccac 100644
--- a/app/qml/inputs/MMTextInput.qml
+++ b/app/qml/inputs/MMTextInput.qml
@@ -8,9 +8,9 @@
***************************************************************************/
import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
-import "../components"
+
+import "../components" as MMComponents
+import "../components/private" as MMPrivateComponents
/*
* Common text input to use in the app.
@@ -18,58 +18,21 @@ import "../components"
* Disabled state can be achieved by setting `enabled: false`
* ReadOnly state can be achieved by setting `readOnly: true`
*
- * See MMBaseInput for more properties.
+ * See MMBaseSingleLineInput for more properties.
*/
-MMBaseInput {
+MMPrivateComponents.MMBaseSingleLineInput {
id: root
property bool showClearIcon: true
- property alias text: textField.text
- property alias placeholderText: textField.placeholderText
- property alias readOnly: textField.readOnly
- property alias textFieldComponent: textField
-
- signal textEdited( string text )
-
- hasFocus: textField.activeFocus
-
- content: TextField {
- id: textField
-
- anchors.fill: parent
-
- placeholderTextColor: __style.nightAlphaColor
- color: root.enabled && !readOnly ? __style.nightColor : __style.mediumGreenColor
-
- font: __style.p5
- hoverEnabled: true
-
- background: Rectangle {
- color: __style.transparentColor
- }
-
- onTextEdited: root.textEdited( textField.text )
- }
-
- rightAction: MMIcon {
- id: rightIcon
-
- anchors.verticalCenter: parent.verticalCenter
+ rightContent: MMComponents.MMIcon {
size: __style.icon24
source: __style.closeIcon
- color: root.enabled && !readOnly ? __style.forestColor : __style.mediumGreenColor
- visible: root.showClearIcon && textField.activeFocus && textField.text.length > 0
+ color: root.iconColor
}
- onRightActionClicked: {
- if (root.showClearIcon) {
- textField.clear()
- }
- else {
- // if the clear button should not be there, let's open keyboard instead
- textField.forceActiveFocus()
- }
- }
+ rightContentVisible: root.showClearIcon && textField.activeFocus && textField.text.length > 0
+
+ onRightContentClicked: textField.clear()
}
diff --git a/app/qml/inputs/MMTextWithButtonInput.qml b/app/qml/inputs/MMTextWithButtonInput.qml
deleted file mode 100644
index 36ae9ec0c..000000000
--- a/app/qml/inputs/MMTextWithButtonInput.qml
+++ /dev/null
@@ -1,82 +0,0 @@
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-
-import QtQuick
-import QtQuick.Controls
-import QtQuick.Controls.Basic
-import "../components"
-
-/*
- * Common text input to use in the app, with button on right
- * Disabled state can be achieved by setting `enabled: false`.
- *
- * See MMBaseInput for more properties.
- */
-
-MMBaseInput {
- id: root
-
- property alias placeholderText: textField.placeholderText
- property alias text: textField.text
- property alias buttonText: buttonText.text
- property alias buttonEnabled: rightButton.enabled
-
- signal textEdited( string text )
- signal buttonClicked()
-
- hasFocus: textField.activeFocus
-
- content: TextField {
- id: textField
-
- anchors.verticalCenter: parent.verticalCenter
- width: parent.width + rightButton.x
-
- color: root.enabled ? __style.nightColor : __style.mediumGreenColor
- placeholderTextColor: __style.nightAlphaColor
- font: __style.p5
- hoverEnabled: true
-
- background: Rectangle {
- color: __style.transparentColor
- }
-
- onTextEdited: root.textEdited( textField.text )
- }
-
- rightAction: Button {
- id: rightButton
-
- property bool transparent: false
-
- x: 10 * __dp - buttonText.width
- height: 34 * __dp
- anchors.verticalCenter: parent.verticalCenter
-
- contentItem: Text {
- id: buttonText
-
- anchors.centerIn: rightButton
- font: __style.t3
- color: rightButton.enabled ? rightButton.down || rightButton.hovered ? __style.grassColor : __style.forestColor : __style.deepOceanColor
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- }
-
- background: Rectangle {
- color: rightButton.enabled ? rightButton.down || rightButton.hovered ? __style.forestColor : __style.grassColor : __style.mediumGreenColor
- radius: height / 2
- }
-
- onClicked: {
- textField.forceActiveFocus()
- root.buttonClicked()
- }
- }
-}
diff --git a/app/qml/layers/MMFeaturesListPage.qml b/app/qml/layers/MMFeaturesListPage.qml
index a3c546e84..c3e654b93 100644
--- a/app/qml/layers/MMFeaturesListPage.qml
+++ b/app/qml/layers/MMFeaturesListPage.qml
@@ -33,15 +33,15 @@ MMComponents.MMPage {
height: parent.height
MMSearchInput {
- id: searchbox
+ id: searchBar
anchors.top: parent.top
anchors.topMargin: __style.spacing20
width: parent.width
- allowTimer: true
- onSearchTextChanged: featuresModel.searchExpression = searchbox.text
+ delayedSearch: true
+ onSearchTextChanged: featuresModel.searchExpression = searchBar.text
}
ListView {
@@ -50,7 +50,7 @@ MMComponents.MMPage {
width: parent.width
anchors {
- top: searchbox.bottom
+ top: searchBar.bottom
bottom: parent.bottom
topMargin: __style.spacing20
}
diff --git a/app/qml/layers/MMLayerDetailPage.qml b/app/qml/layers/MMLayerDetailPage.qml
index bf6c7f497..ae47229cc 100644
--- a/app/qml/layers/MMLayerDetailPage.qml
+++ b/app/qml/layers/MMLayerDetailPage.qml
@@ -77,17 +77,9 @@ Page {
title: qsTr( "Settings" )
text: qsTr( "Visible on map" )
- switchComponent.checked: layerDetailData.isVisible
+ checked: layerDetailData.isVisible
- onContentClicked: {
- toggleVisiblity()
- }
-
- onRightActionClicked: {
- toggleVisiblity()
- }
-
- function toggleVisiblity() {
+ onToggled: {
__activeProject.switchLayerTreeNodeVisibility( layerDetailData.layerTreeNode )
}
}
diff --git a/app/qml/layers/MMLayersController.qml b/app/qml/layers/MMLayersController.qml
index 4a98eed31..8b7d5487c 100644
--- a/app/qml/layers/MMLayersController.qml
+++ b/app/qml/layers/MMLayersController.qml
@@ -102,7 +102,7 @@ Item {
}
}
- onSearchboxClicked: function() {
+ onSearchBarClicked: function() {
let item = pagesStackView.push( searchLayersPage, {}, StackView.Immediate )
item.forceActiveFocus()
}
diff --git a/app/qml/layers/MMLayersListPage.qml b/app/qml/layers/MMLayersListPage.qml
index 690f75c6e..7700b010c 100644
--- a/app/qml/layers/MMLayersListPage.qml
+++ b/app/qml/layers/MMLayersListPage.qml
@@ -22,7 +22,7 @@ MMComponents.MMPage {
signal nodeClicked( var node, string nodeType, string nodeName )
signal nodeVisibilityClicked( var node )
- signal searchboxClicked()
+ signal searchBarClicked()
pageHeader.title: root.pageTitle
@@ -33,7 +33,7 @@ MMComponents.MMPage {
height: parent.height
MMSearchInput {
- id: searchbox
+ id: searchBar
anchors.top: parent.top
anchors.topMargin: __style.spacing20
@@ -43,7 +43,7 @@ MMComponents.MMPage {
MouseArea {
anchors.fill: parent
- onClicked: root.searchboxClicked()
+ onClicked: root.searchBarClicked()
}
}
@@ -53,7 +53,7 @@ MMComponents.MMPage {
width: parent.width
anchors {
- top: searchbox.bottom
+ top: searchBar.bottom
topMargin: __style.spacing20
bottom: parent.bottom
}
diff --git a/app/qml/layers/MMLayersListSearchPage.qml b/app/qml/layers/MMLayersListSearchPage.qml
index 9a8a2a214..9fbdb976f 100644
--- a/app/qml/layers/MMLayersListSearchPage.qml
+++ b/app/qml/layers/MMLayersListSearchPage.qml
@@ -33,15 +33,13 @@ MMComponents.MMPage {
height: parent.height
MMSearchInput {
- id: searchbox
+ id: searchBar
anchors.top: parent.top
anchors.topMargin: __style.spacing20
width: parent.width
- onSearchTextChanged: function( searchText ) {
- root.searchTextChanged( searchText )
- }
+ onSearchTextChanged: root.searchTextChanged( searchBar.searchText )
}
MMLayersList {
@@ -50,7 +48,7 @@ MMComponents.MMPage {
width: parent.width
anchors {
- top: searchbox.bottom
+ top: searchBar.bottom
topMargin: __style.spacing20
bottom: parent.bottom
}
@@ -76,5 +74,5 @@ MMComponents.MMPage {
}
// open keyboard automatically
- Component.onCompleted: searchbox.textFieldComponent.forceActiveFocus()
+ Component.onCompleted: searchBar.textField.forceActiveFocus()
}
diff --git a/app/qml/project/MMProjectHomeTab.qml b/app/qml/project/MMProjectHomeTab.qml
index 862081bf9..5ffd3b826 100644
--- a/app/qml/project/MMProjectHomeTab.qml
+++ b/app/qml/project/MMProjectHomeTab.qml
@@ -40,16 +40,13 @@ Item {
width: parent.width - 2 * root.padding
placeholderText: qsTr("Search for projects...")
- onSearchTextChanged: function(text) {
- }
-
anchors {
top: parent.top
left: parent.left
right: parent.right
}
- allowTimer: true
+ delayedSearch: true
}
MMInfoBox {
@@ -99,7 +96,10 @@ Item {
projectModelType: MM.ProjectsModel.LocalProjectsModel
activeProjectId: root.activeProjectId
- searchText: searchBar.text
+
+ hideActiveProject: true // TODO: do not hide when searching!
+ searchText: searchBar.searchText
+
spacing: root.spacing
anchors {
diff --git a/app/qml/project/MMProjectServerTab.qml b/app/qml/project/MMProjectServerTab.qml
index f56097cdb..aafbf9617 100644
--- a/app/qml/project/MMProjectServerTab.qml
+++ b/app/qml/project/MMProjectServerTab.qml
@@ -43,7 +43,7 @@ Item {
right: parent.right
}
- allowTimer: true
+ delayedSearch: true
}
@@ -52,7 +52,7 @@ Item {
projectModelType: root.projectModelType
activeProjectId: root.activeProjectId
- searchText: searchBar.text
+ searchText: searchBar.searchText
spacing: root.spacing
anchors {
diff --git a/app/qml/project/components/MMProjectDelegate.qml b/app/qml/project/components/MMProjectDelegate.qml
index 3607acf7e..02a3e1f6f 100644
--- a/app/qml/project/components/MMProjectDelegate.qml
+++ b/app/qml/project/components/MMProjectDelegate.qml
@@ -98,7 +98,7 @@ Control {
font: __style.t3
color: {
if ( root.projectIsOpened ) return __style.polarColor
- if ( root.state === "Error" ) return __style.nightAlphaColor
+ if ( root.state === "Error" ) return __style.darkGreyColor
return __style.nightColor
}
}
diff --git a/app/qml/project/components/MMProjectWizardDelegate.qml b/app/qml/project/components/MMProjectWizardDelegate.qml
index bb99eb57e..b892c3a2e 100644
--- a/app/qml/project/components/MMProjectWizardDelegate.qml
+++ b/app/qml/project/components/MMProjectWizardDelegate.qml
@@ -41,7 +41,7 @@ Item {
Layout.fillHeight: true
Layout.fillWidth: true
- onTextChanged: root.attrNameChanged( text )
+ onTextEdited: (text) => root.attrNameChanged( text )
}
MMInputs.MMComboboxInput {
diff --git a/app/qml/settings/components/MMSettingsInput.qml b/app/qml/settings/components/MMSettingsInput.qml
index 3b2427075..f76df5c1b 100644
--- a/app/qml/settings/components/MMSettingsInput.qml
+++ b/app/qml/settings/components/MMSettingsInput.qml
@@ -51,10 +51,10 @@ MMSettingsItem {
title: root.title
- bgColor: __style.lightGreenColor
+ textFieldBackground.color: __style.lightGreenColor
text: root.value
- textFieldComponent.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
+ textField.inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
}
MMComponents.MMListSpacer { height: __style.spacing40 }
diff --git a/gallery/qml.qrc b/gallery/qml.qrc
index 6b3519e5b..24feb29bb 100644
--- a/gallery/qml.qrc
+++ b/gallery/qml.qrc
@@ -54,6 +54,8 @@