From 4182aa40be85068eb3e6229c0562ba4b9a78e988 Mon Sep 17 00:00:00 2001 From: sachinrajauriya Date: Mon, 9 Sep 2024 14:44:45 +0530 Subject: [PATCH 1/2] localChanges --- .../AdaptiveCardQmlTypes.h | 3 + .../AdaptiveCardQmlEngine/CMakeLists.txt | 4 +- .../models/CollectionItemModel.cpp | 12 + .../models/CollectionItemModel.h | 4 + .../models/NumberInputModel.cpp | 50 ++ .../models/NumberInputModel.h | 42 ++ .../qml/CardConstants.qml | 4 +- .../qml/CollectionItemDelegate.qml | 28 +- .../qml/InputFieldClearIcon.qml | 33 + .../AdaptiveCardQmlEngine/qml/InputLabel.qml | 19 + .../qml/NumberInputRender.qml | 600 ++++++++++++++++++ .../AdaptiveCardQmlEngine/resourceEngine.qrc | 3 + .../utils/AdaptiveCardEnums.h | 1 + .../JSONSamples/numberInput.json | 46 ++ .../SampleCardListModel.cpp | 2 +- 15 files changed, 828 insertions(+), 23 deletions(-) create mode 100644 source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp create mode 100644 source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h create mode 100644 source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml create mode 100644 source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml create mode 100644 source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml create mode 100644 source/qml_v2/AdaptiveCardVisualizer/JSONSamples/numberInput.json diff --git a/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h b/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h index 168a931b58..f0d8f18cd3 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h +++ b/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h @@ -23,5 +23,8 @@ namespace AdaptiveCardQmlEngine qmlRegisterType(QUrl("qrc:qml/CardConstants.qml"), "AdaptiveCardQmlEngine", 1, 0, "CardConstants"); qmlRegisterType(QUrl("qrc:qml/TextBlockRender.qml"), "AdaptiveCardQmlEngine", 1, 0, "TextBlockRender"); + qmlRegisterType(QUrl("qrc:qml/NumberInputRender.qml"), "AdaptiveCardQmlEngine", 1, 0, "NumberInputRender"); + qmlRegisterType(QUrl("qrc:qml/InputFieldClearIcon.qml"), "AdaptiveCardQmlEngine", 1, 0, "InputFieldClearIcon"); + qmlRegisterType(QUrl("qrc:qml/InputLabel.qml"), "AdaptiveCardQmlEngine", 1, 0, "InputLabel"); } } // namespace RendererQml diff --git a/source/qml_v2/AdaptiveCardQmlEngine/CMakeLists.txt b/source/qml_v2/AdaptiveCardQmlEngine/CMakeLists.txt index 0f3f27a477..15ed3b458c 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/CMakeLists.txt +++ b/source/qml_v2/AdaptiveCardQmlEngine/CMakeLists.txt @@ -53,6 +53,7 @@ file(GLOB_RECURSE SOURCES "AdaptiveCardController.cpp" "AdaptiveCardModel.cpp" "CollectionItemModel.cpp" + "NumberInputModel.cpp" "TextBlockModel.cpp" "RichTextBlockModel.cpp" @@ -74,7 +75,8 @@ file(GLOB_RECURSE SOURCES "CollectionItemModel.h" "TextBlockModel.h" - "RichTextBlockModel.h" + "RichTextBlockModel.h" + "NumberInputModel.h" ) # Setup Library diff --git a/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.cpp b/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.cpp index 285efd34f7..1a9776c087 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.cpp +++ b/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.cpp @@ -1,6 +1,7 @@ #include "CollectionItemModel.h" #include "TextBlockModel.h" #include "RichTextBlockModel.h" +#include "NumberInputModel.h" #include "AdaptiveCardEnums.h" CollectionItemModel::CollectionItemModel(std::vector> elements, QObject* parent) @@ -41,6 +42,7 @@ QHash CollectionItemModel::roleNames() const cardListModel[DelegateType] = "delegateType"; cardListModel[TextBlockRole] = "textBlockRole"; cardListModel[RichTextBlockRole] = "richTextBlockRole"; + cardListModel[NumberInputRole] = "numberInputRole"; cardListModel[FillHeightRole] = "fillHeightRole"; return cardListModel; @@ -59,6 +61,10 @@ void CollectionItemModel::populateRowData(std::shared_ptr(element), rowContent); break; + case AdaptiveCards::CardElementType::NumberInput: + populateNumberInputModel(std::dynamic_pointer_cast(element), rowContent); + break; + default: break; } @@ -77,3 +83,9 @@ void CollectionItemModel::populateRichTextBlockModel(std::shared_ptr numberInput, RowContent& rowContent) +{ + rowContent[CollectionModelRole::DelegateType] = QVariant::fromValue(AdaptiveCardEnums::CardElementType::NumberInput); + rowContent[CollectionModelRole::NumberInputRole] = QVariant::fromValue(new NumberInputModel(numberInput, nullptr)); +} diff --git a/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.h b/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.h index b343bd0648..6468b36f8a 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.h +++ b/source/qml_v2/AdaptiveCardQmlEngine/models/CollectionItemModel.h @@ -5,11 +5,13 @@ #include #include "RichTextBlock.h" +#include "NumberInput.h" #include "Enums.h" class TextBlockModel; class RichTextBlockModel; +class NumberInputModel; class CollectionItemModel : public QAbstractListModel { @@ -20,6 +22,7 @@ class CollectionItemModel : public QAbstractListModel DelegateType = Qt::UserRole + 1, TextBlockRole, RichTextBlockRole, + NumberInputRole, FillHeightRole }; @@ -41,4 +44,5 @@ class CollectionItemModel : public QAbstractListModel void populateRowData(std::shared_ptr element); void populateTextBlockModel(std::shared_ptr textBlock, RowContent& rowContent); void populateRichTextBlockModel(std::shared_ptr rightTextBlock, RowContent& rowContent); + void populateNumberInputModel(std::shared_ptr numberInput, RowContent& rowContent); }; diff --git a/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp new file mode 100644 index 0000000000..1031cf914a --- /dev/null +++ b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp @@ -0,0 +1,50 @@ +#include "NumberInputModel.h" +#include "SharedAdaptiveCard.h" +#include +#include "Utils.h" +#include "MarkDownParser.h" + +NumberInputModel::NumberInputModel(std::shared_ptr numberInput, QObject* parent) : + QObject(parent), mInput(numberInput) + +{ + const auto hostConfig = AdaptiveCardQmlEngine::AdaptiveCardContext::getInstance().getHostConfig(); + const auto rendererConfig = AdaptiveCardQmlEngine::AdaptiveCardContext::getInstance().getCardConfig(); + + mVisible = mInput->GetIsVisible(); + //mPlaceholder = QString::fromStdString(AdaptiveCardQmlEngine::Utils::getBackQuoteEscapedString(mInput->GetPlaceholder()) + "`"); + + createInputLabel(); + + if (mInput->GetValue().has_value()) + { + mValue = mInput->GetValue().value(); + mDefaultValue = true; + } + + mMinValue = numberInput->GetMin().value_or(-DBL_MAX); + mMaxValue = numberInput->GetMax().value_or(DBL_MAX); + + if (numberInput->GetIsRequired() || numberInput->GetMin().has_value() || numberInput->GetMax().has_value()) + { + } +} +void NumberInputModel::createInputLabel() +{ + if (!mInput->GetLabel().empty()) + { + // mContext->addHeightEstimate(mContext->getEstimatedTextHeight(mInput->GetLabel())); + //mEscapedLabelString = QString::fromStdString(AdaptiveCardQmlEngine::Utils::getBackQuoteEscapedString(mInput->GetLabel()) + "`"); + } + else + { + if (mInput->GetIsRequired()) + { + // mContext->AddWarning(RendererQml::AdaptiveWarning(RendererQml::Code::RenderException, "isRequired is not supported without labels")); + } + } +} + +NumberInputModel::~NumberInputModel() +{ +} diff --git a/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h new file mode 100644 index 0000000000..f8fd81b1d9 --- /dev/null +++ b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h @@ -0,0 +1,42 @@ +#pragma once +#include "AdaptiveCardContext.h" +#include "NumberInput.h" +#include "OpenUrlAction.h" +#include "ToggleVisibilityAction.h" +#include "SubmitAction.h" + +#include +#include +#include +#include + +class NumberInputModel : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool visible MEMBER mVisible CONSTANT); + Q_PROPERTY(QString placeHolder MEMBER mPlaceholder CONSTANT); + Q_PROPERTY(QString value MEMBER mValue CONSTANT); + Q_PROPERTY(bool defaultValue MEMBER mDefaultValue CONSTANT); + Q_PROPERTY(QString minValue MEMBER mMinValue CONSTANT); + Q_PROPERTY(QString maxValue MEMBER mMaxValue CONSTANT); + Q_PROPERTY(QString escapedLabelString MEMBER mEscapedLabelString CONSTANT); + +public: + explicit NumberInputModel(std::shared_ptr numberInput, QObject* parent = nullptr); + ~NumberInputModel(); + +private: + void createInputLabel(); + const std::shared_ptr& mInput; + +private: + bool mVisible; + QString mPlaceholder; + QString mValue; + bool mDefaultValue; + QString mMinValue; + QString mMaxValue; + QString mEscapedLabelString; +}; +#pragma once diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/CardConstants.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/CardConstants.qml index 720a6bd9e4..661ac845c7 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/qml/CardConstants.qml +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/CardConstants.qml @@ -1,6 +1,6 @@ -import "AdaptiveCardUtils.js" as AdaptiveCardUtils +import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils import QtQuick 2.15 -pragma Singleton +//pragma Singleton QtObject { property bool isDarkTheme: false diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/CollectionItemDelegate.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/CollectionItemDelegate.qml index 2df8d83c11..bf11d10647 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/qml/CollectionItemDelegate.qml +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/CollectionItemDelegate.qml @@ -7,24 +7,14 @@ Loader { property var parentCardItem - source: "qrc:qml/RichTextBlockRender.qml" - - /* - { - switch (delegateType) { - case AdaptiveCardEnums.CardElementType.TextBlock: - return "TextBlockRender.qml" - case AdaptiveCardEnums.CardElementType.Container: - return "ContainerRender.qml" - case AdaptiveCardEnums.CardElementType.ColumnSet: - return "ColumnSetRender.qml" - case AdaptiveCardEnums.CardElementType.Column: - return "ColumnRender.qml" - case AdaptiveCardEnums.CardElementType.ToggleInput: - return "ToggleInputRender.qml" - case AdaptiveCardEnums.CardElementType.ActionSet: - return "ActionSetRender.qml" - } + Component.onCompleted :{ + if (model.delegateType == AdaptiveCardEnums.CardElementType.TextBlock) + source = "TextBlockRender.qml" + else if (model.delegateType == AdaptiveCardEnums.CardElementType.RichTextBlock) + source = "RichTextBlockRender.qml"; + else if (model.delegateType == AdaptiveCardEnums.CardElementType.NumberInput) + source = "NumberInputRender.qml"; } - */ + + } diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml new file mode 100644 index 0000000000..ca41515c3f --- /dev/null +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml @@ -0,0 +1,33 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.15 +import QtQuick.Controls 2.15 +import AdaptiveCardQmlEngine 1.0 +import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils + +Button { + id: inputFieldClearIcon + + width: 16//CardConstants.inputFieldConstants.clearIconSize + horizontalPadding: 0 + verticalPadding: 0 + icon.width: 16//CardConstants.inputFieldConstants.clearIconSize + icon.height:16// CardConstants.inputFieldConstants.clearIconSize + icon.color: "black"//CardConstants.inputFieldConstants.clearIconColorNormal + icon.source: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIHZpZXdCb3g9IjAgMCAxMCAxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+Y29tbW9uLWFjdGlvbnMvY2FuY2VsXzEwPC90aXRsZT48cGF0aCBkPSJNNS43MDcyNSA1LjAwMDI1bDIuNjQ2LTIuNjQ2Yy4xOTYtLjE5Ni4xOTYtLjUxMiAwLS43MDgtLjE5NS0uMTk1LS41MTEtLjE5NS0uNzA3IDBsLTIuNjQ2IDIuNjQ3LTIuNjQ3LTIuNjQ3Yy0uMTk1LS4xOTUtLjUxMS0uMTk1LS43MDcgMC0uMTk1LjE5Ni0uMTk1LjUxMiAwIC43MDhsMi42NDcgMi42NDYtMi42NDcgMi42NDZjLS4xOTUuMTk2LS4xOTUuNTEyIDAgLjcwOC4wOTguMDk3LjIyNi4xNDYuMzU0LjE0Ni4xMjggMCAuMjU2LS4wNDkuMzUzLS4xNDZsMi42NDctMi42NDcgMi42NDYgMi42NDdjLjA5OC4wOTcuMjI2LjE0Ni4zNTQuMTQ2LjEyOCAwIC4yNTYtLjA0OS4zNTMtLjE0Ni4xOTYtLjE5Ni4xOTYtLjUxMiAwLS43MDhsLTIuNjQ2LTIuNjQ2eiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+"//CardConstants.clearIconImage + Accessible.name: qsTr("Clear Input") + Accessible.role: Accessible.Button + + background: Rectangle { + color: 'transparent' + radius:8 //CardConstants.inputFieldConstants.borderRadius + + /* WCustomFocusItem { + isRectangle: true + visible: inputFieldClearIcon.activeFocus + designatedParent: parent + }*/ + + } + +} diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml new file mode 100644 index 0000000000..593cfc6341 --- /dev/null +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml @@ -0,0 +1,19 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.15 +import QtQuick.Controls 2.15 +import AdaptiveCardQmlEngine 1.0 +import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils +Label { + id: inputLabel + + property bool _required + property string _label + + wrapMode: Text.Wrap + width: parent.width + color: "black"//CardConstants.toggleButtonConstants.textColor + font.pixelSize: 14 //CardConstants.inputFieldConstants.labelPixelSize + Accessible.ignored: true + text:""// _isRequired ? AdaptiveCardUtils.escapeHtml(_label) + " " + "*" : AdaptiveCardUtils.escapeHtml(_label) +} diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml new file mode 100644 index 0000000000..2acab3e83e --- /dev/null +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml @@ -0,0 +1,600 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.15 +import QtQuick.Controls 2.15 +import AdaptiveCardQmlEngine 1.0 +import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils +Column { + id: numberInput + + property var _adaptiveCard + property bool _isRequired + property bool _validationRequired + property string _mEscapedLabelString + property string _mEscapedErrorString + property string _mEscapedPlaceholderString + property bool showErrorMessage: false + property double _minValue + property double _maxValue + property double _value + property int _spinBoxMinVal : Math.max(-2147483648, _minValue) + property int _spinBoxMaxVal : Math.min(2147483647, _maxValue) + property bool _hasDefaultValue: false + + property int minWidth: cardConst.inputNumberConstants.numberInputMinWidth + property string _submitValue: _numberInputTextField.text ? Number(_numberInputTextField.text).toString() : '' + + CardConstants{ + + id:cardConst + + } + + function getAccessibleName() { + let accessibleName = ''; + if (showErrorMessage) + accessibleName += 'Error. ' + _mEscapedErrorString + '. '; + + if (_mEscapedLabelString) + accessibleName += _mEscapedLabelString + '. '; + + if (_numberInputTextField.text !== '') + accessibleName += (_numberInputTextField.text); + else + accessibleName += _mEscapedPlaceholderString; + accessibleName += qsTr(", Type the number"); + return accessibleName; + } + + width: parent.width + spacing:cardConst.inputFieldConstants.columnSpacing + Component.onCompleted: { + console.log("inputFieldConstants.columnSpacing",+cardConst.inputFieldConstants.columnSpacing); + } + onShowErrorMessageChanged: { + _numberInputRectangle.colorChange(false); + } + onActiveFocusChanged: { + if (activeFocus) + _numberInputTextField.forceActiveFocus(); + + } + + InputLabel { + id: _numberInputLabel + + _label: _mEscapedLabelString + _required: _isRequired + visible: _label + } + + Row { + id: _numberInputRow + + width: parent.width + height: cardConst.inputFieldConstants.height + + Rectangle { + id: _numberInputRectangle + + + + border.width: cardConst.inputFieldConstants.borderWidth + border.color: "black"//showErrorMessage ? inputFieldConstants.borderColorOnError : inputFieldConstants.borderColorNormal + radius: cardConst.inputFieldConstants.borderRadius + height: parent.height + color:"white"// _numberInputSpinBox.pressed ? inputFieldConstants.backgroundColorOnPressed : _numberInputSpinBox.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal + width: parent.width - 31//_numberInputArrowRectangle.width + + + /*WCustomFocusItem { + isRectangle: true + visible: _numberInputTextField.activeFocus + }*/ + + SpinBox { + id: _numberInputSpinBox + + function changeValue(keyPressed) { + if ((keyPressed === Qt.Key_Up || keyPressed === Qt.Key_Down) && _numberInputTextField.text.length === 0) { + value = (from > 0) ? from : 0; + } else if (keyPressed === Qt.Key_Up) { + _numberInputSpinBox.value = Number(_numberInputTextField.text); + _numberInputSpinBox.increase(); + } else if (keyPressed === Qt.Key_Down) { + _numberInputSpinBox.value = Number(_numberInputTextField.text); + _numberInputSpinBox.decrease(); + } + _numberInputTextField.text = _numberInputSpinBox.value; + } + + width: parent.width - _numberInputClearIcon.width - cardConst.inputFieldConstants.clearIconHorizontalPadding + padding: 0 + editable: true + stepSize: 1 + // to: _spinBoxMaxVal + // from: _spinBoxMinVal + Keys.onPressed: { + if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { + _numberInputSpinBox.changeValue(event.key); + event.accepted = true; + } + } + Accessible.ignored: true + Component.onCompleted: { + if (_hasDefaultValue) + _numberInputSpinBox.value = _value; + + } + + contentItem: TextField { + id: _numberInputTextField + + font.pixelSize: cardConst.inputFieldConstants.pixelSize + anchors.left: parent.left + anchors.right: parent.right + selectByMouse: true + selectedTextColor: 'white' + readOnly: !_numberInputSpinBox.editable + validator: _numberInputSpinBox.validator + inputMethodHints: Qt.ImhFormattedNumbersOnly + onPressed: { + _numberInputRectangle.colorChange(true); + event.accepted = true; + } + onReleased: { + _numberInputRectangle.colorChange(false); + forceActiveFocus(); + event.accepted = true; + } + onHoveredChanged: _numberInputRectangle.colorChange(false) + onActiveFocusChanged: { + _numberInputRectangle.colorChange(false); + Accessible.name = getAccessibleName(); + } + leftPadding: cardConst.inputFieldConstants.textHorizontalPadding + rightPadding: cardConst.inputFieldConstants.textHorizontalPadding + topPadding: cardConst.inputFieldConstants.textVerticalPadding + bottomPadding: cardConst.inputFieldConstants.textVerticalPadding + placeholderText: _mEscapedPlaceholderString + Accessible.role: Accessible.EditableText + color: cardConst.inputFieldConstants.textColor + placeholderTextColor: cardConst.inputFieldConstants.placeHolderColor + onTextChanged: { + validate(); + } + Component.onCompleted: { + if (_hasDefaultValue) + _numberInputTextField.text = _numberInputSpinBox.value; + } + + background: Rectangle { + id: _numberInputTextFieldBg + + color: 'transparent' + } + + } + + background: Rectangle { + id: _numberSpinBoxBg + + color: 'transparent' + } + + up.indicator: Rectangle { + color: 'transparent' + z: -1 + } + + down.indicator: Rectangle { + color: 'transparent' + z: -1 + } + + validator: DoubleValidator { + } + + } + + InputFieldClearIcon { + id: _numberInputClearIcon + + Keys.onReturnPressed: onClicked() + visible: _numberInputTextField.length !== 0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: cardConst.inputFieldConstants.clearIconHorizontalPadding + onClicked: { + nextItemInFocusChain().forceActiveFocus(); + _numberInputSpinBox.value = _numberInputSpinBox.from; + _numberInputTextField.clear(); + } + } + + } + + Rectangle { + id: _numberInputArrowRectangle + + property string accessibilityPrefix: '' + + width: 31//numberInputConstants.upDownButtonWidth + radius:8// inputFieldConstants.borderRadius + height: parent.height + border.color: "black"//inputFieldConstants.borderColorNormal + activeFocusOnTab: true + color:"gray" //(_numberInputArrowIcon.pressed || activeFocus) ? inputFieldConstants.backgroundColorOnPressed : _numberInputArrowIcon.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal + Keys.onPressed: { + if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { + _numberInputSpinBox.changeValue(event.key); + accessibilityPrefix = ''; + event.accepted = true; + } + } + onActiveFocusChanged: { + if (activeFocus) + accessibilityPrefix = qsTr("Use up arrow to increase the value and down arrow to decrease the value") + (_numberInputTextField.text ? ", Current number is " : ""); + + } + Accessible.name: accessibilityPrefix + _numberInputTextField.displayText + Accessible.role: Accessible.NoRole + + Button { + id: _numberInputArrowIcon + + width: parent.width + anchors.right: parent.right + horizontalPadding: 4//inputFieldConstants.iconPadding + verticalPadding: 4//inputFieldConstants.iconPadding + icon.width: 31//numberInputConstants.upDownIconSize + icon.height:31// numberInputConstants.upDownIconSize + focusPolicy: Qt.NoFocus + icon.color: "black"//numberInputConstants.upDownIconColor + height: parent.height + icon.source: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHZpZXdCb3g9IjAgMCAxNCAxNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEzLjQ0NzQgOS43NzYzOEMxMy40MTggOS43MTc2MyAxMy4zNzc0IDkuNjY1MjUgMTMuMzI3OCA5LjYyMjIyQzEzLjI3ODIgOS41NzkxOCAxMy4yMjA2IDkuNTQ2MzUgMTMuMTU4MyA5LjUyNTU4QzEzLjA5NiA5LjUwNDgxIDEzLjAzMDIgOS40OTY1MiAxMi45NjQ3IDkuNTAxMThDMTIuODk5MiA5LjUwNTgzIDEyLjgzNTIgOS41MjMzNSAxMi43NzY1IDkuNTUyNzNMNy4wMDAwNCAxMi40NDA5TDEuMjIzNzkgOS41NTI3M0MxLjEwNTE2IDkuNDkzNDEgMC45Njc4MzIgOS40ODM2NSAwLjg0MjAwOSA5LjUyNTU5QzAuNzE2MTg2IDkuNTY3NTIgMC42MTIxNzYgOS42NTc3MyAwLjU1Mjg2MSA5Ljc3NjM1QzAuNDkzNTQ1IDkuODk0OTggMC40ODM3ODIgMTAuMDMyMyAwLjUyNTcyIDEwLjE1ODFDMC41Njc2NTggMTAuMjg0IDAuNjU3ODYxIDEwLjM4OCAwLjc3NjQ4NiAxMC40NDczTDYuNzc2NDkgMTMuNDQ3M0M2Ljg0NTk0IDEzLjQ4MiA2LjkyMjUgMTMuNSA3LjAwMDE0IDEzLjVDNy4wNzc3NyAxMy41IDcuMTU0MzQgMTMuNDgyIDcuMjIzNzkgMTMuNDQ3M0wxMy4yMjM4IDEwLjQ0NzNDMTMuMjgyNSAxMC40MTc5IDEzLjMzNDkgMTAuMzc3MyAxMy4zNzc5IDEwLjMyNzdDMTMuNDIxIDEwLjI3OCAxMy40NTM4IDEwLjIyMDQgMTMuNDc0NiAxMC4xNTgxQzEzLjQ5NTMgMTAuMDk1OCAxMy41MDM2IDEwLjAzMDEgMTMuNDk4OSA5Ljk2NDU2QzEzLjQ5NDMgOS44OTkwNSAxMy40NzY4IDkuODM1MTEgMTMuNDQ3NCA5Ljc3NjM4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8cGF0aCBkPSJNMTMuMjIzOSAzLjU1MjcyTDcuMjIzNjkgMC41NTI3MjRDNy4xNTQyNCAwLjUxODA1IDcuMDc3NjggMC41IDcuMDAwMDYgMC41QzYuOTIyNDQgMC41IDYuODQ1ODggMC41MTgwNSA2Ljc3NjQ0IDAuNTUyNzI0TDAuNzc2NDM4IDMuNTUyNzJDMC42NTc4MTMgMy42MTIwMyAwLjU2NzYwOCAzLjcxNjA0IDAuNTI1NjY1IDMuODQxODZDMC41MDQ4OTcgMy45MDQxNSAwLjQ5NjYwNCAzLjk2OTkzIDAuNTAxMjU3IDQuMDM1NDRDMC41MDU5MTEgNC4xMDA5NCAwLjUyMzQyMSA0LjE2NDg5IDAuNTUyNzg4IDQuMjIzNjJDMC41ODIxNTUgNC4yODIzNiAwLjYyMjgwMyA0LjMzNDc0IDAuNjcyNDEzIDQuMzc3NzdDMC43MjIwMjIgNC40MjA3OSAwLjc3OTYyIDQuNDUzNjMgMC44NDE5MTkgNC40NzQ0QzAuOTY3NzM3IDQuNTE2MzQgMS4xMDUwNiA0LjUwNjU4IDEuMjIzNjkgNC40NDcyN0w3LjAwMDA5IDEuNTU5MDdMMTIuNzc2NyA0LjQ0NzI3QzEyLjg5NTMgNC41MDY1OCAxMy4wMzI2IDQuNTE2MzQgMTMuMTU4NSA0LjQ3NDRDMTMuMjIwOCA0LjQ1MzYzIDEzLjI3ODQgNC40MjA3OSAxMy4zMjggNC4zNzc3N0MxMy4zNzc2IDQuMzM0NzQgMTMuNDE4MiA0LjI4MjM2IDEzLjQ0NzYgNC4yMjM2MkMxMy40NzcgNC4xNjQ4OSAxMy40OTQ1IDQuMTAwOTQgMTMuNDk5MSA0LjAzNTQ0QzEzLjUwMzggMy45Njk5MyAxMy40OTU1IDMuOTA0MTUgMTMuNDc0NyAzLjg0MTg2QzEzLjQ1MzkgMy43Nzk1NiAxMy40MjExIDMuNzIxOTYgMTMuMzc4MSAzLjY3MjM1QzEzLjMzNTEgMy42MjI3NCAxMy4yODI3IDMuNTgyMDkgMTMuMjIzOSAzLjU1MjcyWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8L3N2Zz4K"//CardConstants.numberInputUpDownArrowImage + + background: Rectangle { + color: 'transparent' + } + + } + + MouseArea { + id: _numberInputSpinBoxUpIndicatorArea + + width: parent.width + height: parent.height / 2 + anchors.top: parent.top + onReleased: { + _numberInputSpinBox.changeValue(Qt.Key_Up); + _numberInputArrowRectangle.forceActiveFocus(); + } + } + + MouseArea { + id: _numberInputSpinBoxDownIndicatorArea + + width: parent.width + height: parent.height / 2 + anchors.top: _numberInputSpinBoxUpIndicatorArea.bottom + onReleased: { + _numberInputSpinBox.changeValue(Qt.Key_Down); + _numberInputArrowRectangle.forceActiveFocus(); + } + } + + /*WCustomFocusItem { + isRectangle: true + }*/ + + } + + } + + /*InputErrorMessage { + id: _numberInputErrorMessage + + _errorMessage: _mEscapedErrorString + visible: showErrorMessage + }*/ + +} +/*Column { + id: numberInput + + property var _adaptiveCard + property bool _isRequired + property bool _validationRequired + property string _mEscapedLabelString + property string _mEscapedErrorString + property string _mEscapedPlaceholderString + property bool showErrorMessage: false + property double _minValue + property double _maxValue + property double _value + property int _spinBoxMinVal : Math.max(-2147483648, _minValue) + property int _spinBoxMaxVal : Math.min(2147483647, _maxValue) + property bool _hasDefaultValue: false + //property var numberInputConstants: CardConstants.inputNumberConstants + //property var inputFieldConstants: CardConstants.inputFieldConstants + property int minWidth:200// numberInputConstants.numberInputMinWidth + property string _submitValue: _numberInputTextField.text ? Number(_numberInputTextField.text).toString() : '' + + function validate() { + if (_numberInputTextField.text.length !== 0 && Number(_numberInputTextField.text) >= _minValue && Number(_numberInputTextField.text) <= _maxValue) { + showErrorMessage = false; + return false; + } else { + return true; + } + } + + function getAccessibleName() { + let accessibleName = ''; + if (showErrorMessage) + accessibleName += 'Error. ' + _mEscapedErrorString + '. '; + + if (_mEscapedLabelString) + accessibleName += _mEscapedLabelString + '. '; + + if (_numberInputTextField.text !== '') + accessibleName += (_numberInputTextField.text); + else + accessibleName += _mEscapedPlaceholderString; + accessibleName += qsTr(", Type the number"); + return accessibleName; + } + + width:50//parent.width + spacing: 3//inputFieldConstants.columnSpacing + onShowErrorMessageChanged: { + _numberInputRectangle.colorChange(false); + } + onActiveFocusChanged: { + if (activeFocus) + _numberInputTextField.forceActiveFocus(); + + } + + InputLabel { + id: _numberInputLabel + + _label: _mEscapedLabelString + _required: _isRequired + visible: _label + } + + Row { + id: _numberInputRow + + width: parent.width + height: 32//inputFieldConstants.height + + Rectangle { + id: _numberInputRectangle + + + + border.width: 1//inputFieldConstants.borderWidth + border.color: "black"//showErrorMessage ? inputFieldConstants.borderColorOnError : inputFieldConstants.borderColorNormal + radius: 8//inputFieldConstants.borderRadius + height: parent.height + color:"white"// _numberInputSpinBox.pressed ? inputFieldConstants.backgroundColorOnPressed : _numberInputSpinBox.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal + width: 400//parent.width - _numberInputArrowRectangle.width + + + WCustomFocusItem { + isRectangle: true + visible: _numberInputTextField.activeFocus + } + + SpinBox { + id: _numberInputSpinBox + + function changeValue(keyPressed) { + if ((keyPressed === Qt.Key_Up || keyPressed === Qt.Key_Down) && _numberInputTextField.text.length === 0) { + value = (from > 0) ? from : 0; + } else if (keyPressed === Qt.Key_Up) { + _numberInputSpinBox.value = Number(_numberInputTextField.text); + _numberInputSpinBox.increase(); + } else if (keyPressed === Qt.Key_Down) { + _numberInputSpinBox.value = Number(_numberInputTextField.text); + _numberInputSpinBox.decrease(); + } + _numberInputTextField.text = _numberInputSpinBox.value; + } + + width:50// parent.width - _numberInputClearIcon.width - CardConstants.inputFieldConstants.clearIconHorizontalPadding + padding: 0 + editable: true + stepSize: 1 + // to: _spinBoxMaxVal + // from: _spinBoxMinVal + Keys.onPressed: { + if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { + _numberInputSpinBox.changeValue(event.key); + event.accepted = true; + } + } + Accessible.ignored: true + Component.onCompleted: { + if (_hasDefaultValue) + _numberInputSpinBox.value = _value; + + } + + contentItem: TextField { + id: _numberInputTextField + + font.pixelSize: 16//inputFieldConstants.pixelSize + anchors.left: parent.left + anchors.right: parent.right + selectByMouse: true + selectedTextColor: 'white' + readOnly: !_numberInputSpinBox.editable + validator: _numberInputSpinBox.validator + inputMethodHints: Qt.ImhFormattedNumbersOnly + onPressed: { + _numberInputRectangle.colorChange(true); + event.accepted = true; + } + onReleased: { + _numberInputRectangle.colorChange(false); + forceActiveFocus(); + event.accepted = true; + } + onHoveredChanged: _numberInputRectangle.colorChange(false) + onActiveFocusChanged: { + _numberInputRectangle.colorChange(false); + Accessible.name = getAccessibleName(); + } + leftPadding: 12//inputFieldConstants.textHorizontalPadding + rightPadding: 12//inputFieldConstants.textHorizontalPadding + topPadding: 4//inputFieldConstants.textVerticalPadding + bottomPadding: 4//inputFieldConstants.textVerticalPadding + placeholderText: _mEscapedPlaceholderString + Accessible.role: Accessible.EditableText + color: "black"//inputFieldConstants.textColor + placeholderTextColor: "white"//inputFieldConstants.placeHolderColor + onTextChanged: { + validate(); + } + Component.onCompleted: { + if (_hasDefaultValue) + _numberInputTextField.text = _numberInputSpinBox.value; + } + + background: Rectangle { + id: _numberInputTextFieldBg + + color: 'transparent' + } + + } + + background: Rectangle { + id: _numberSpinBoxBg + + color: 'transparent' + } + + up.indicator: Rectangle { + color: 'transparent' + z: -1 + } + + down.indicator: Rectangle { + color: 'transparent' + z: -1 + } + + validator: DoubleValidator { + } + + } + + InputFieldClearIcon { + id: _numberInputClearIcon + + Keys.onReturnPressed: onClicked() + visible: _numberInputTextField.length !== 0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: 12//CardConstants.inputFieldConstants.clearIconHorizontalPadding + onClicked: { + nextItemInFocusChain().forceActiveFocus(); + _numberInputSpinBox.value = _numberInputSpinBox.from; + _numberInputTextField.clear(); + } + } + + } + + Rectangle { + id: _numberInputArrowRectangle + + property string accessibilityPrefix: '' + + width: 31//numberInputConstants.upDownButtonWidth + radius:8// inputFieldConstants.borderRadius + height: parent.height + border.color: "black"//inputFieldConstants.borderColorNormal + activeFocusOnTab: true + color:"gray" //(_numberInputArrowIcon.pressed || activeFocus) ? inputFieldConstants.backgroundColorOnPressed : _numberInputArrowIcon.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal + Keys.onPressed: { + if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { + _numberInputSpinBox.changeValue(event.key); + accessibilityPrefix = ''; + event.accepted = true; + } + } + onActiveFocusChanged: { + if (activeFocus) + accessibilityPrefix = qsTr("Use up arrow to increase the value and down arrow to decrease the value") + (_numberInputTextField.text ? ", Current number is " : ""); + + } + Accessible.name: accessibilityPrefix + _numberInputTextField.displayText + Accessible.role: Accessible.NoRole + + Button { + id: _numberInputArrowIcon + + width: parent.width + anchors.right: parent.right + horizontalPadding: 4//inputFieldConstants.iconPadding + verticalPadding: 4//inputFieldConstants.iconPadding + icon.width: 31//numberInputConstants.upDownIconSize + icon.height:31// numberInputConstants.upDownIconSize + focusPolicy: Qt.NoFocus + icon.color: "black"//numberInputConstants.upDownIconColor + height: parent.height + icon.source: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHZpZXdCb3g9IjAgMCAxNCAxNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEzLjQ0NzQgOS43NzYzOEMxMy40MTggOS43MTc2MyAxMy4zNzc0IDkuNjY1MjUgMTMuMzI3OCA5LjYyMjIyQzEzLjI3ODIgOS41NzkxOCAxMy4yMjA2IDkuNTQ2MzUgMTMuMTU4MyA5LjUyNTU4QzEzLjA5NiA5LjUwNDgxIDEzLjAzMDIgOS40OTY1MiAxMi45NjQ3IDkuNTAxMThDMTIuODk5MiA5LjUwNTgzIDEyLjgzNTIgOS41MjMzNSAxMi43NzY1IDkuNTUyNzNMNy4wMDAwNCAxMi40NDA5TDEuMjIzNzkgOS41NTI3M0MxLjEwNTE2IDkuNDkzNDEgMC45Njc4MzIgOS40ODM2NSAwLjg0MjAwOSA5LjUyNTU5QzAuNzE2MTg2IDkuNTY3NTIgMC42MTIxNzYgOS42NTc3MyAwLjU1Mjg2MSA5Ljc3NjM1QzAuNDkzNTQ1IDkuODk0OTggMC40ODM3ODIgMTAuMDMyMyAwLjUyNTcyIDEwLjE1ODFDMC41Njc2NTggMTAuMjg0IDAuNjU3ODYxIDEwLjM4OCAwLjc3NjQ4NiAxMC40NDczTDYuNzc2NDkgMTMuNDQ3M0M2Ljg0NTk0IDEzLjQ4MiA2LjkyMjUgMTMuNSA3LjAwMDE0IDEzLjVDNy4wNzc3NyAxMy41IDcuMTU0MzQgMTMuNDgyIDcuMjIzNzkgMTMuNDQ3M0wxMy4yMjM4IDEwLjQ0NzNDMTMuMjgyNSAxMC40MTc5IDEzLjMzNDkgMTAuMzc3MyAxMy4zNzc5IDEwLjMyNzdDMTMuNDIxIDEwLjI3OCAxMy40NTM4IDEwLjIyMDQgMTMuNDc0NiAxMC4xNTgxQzEzLjQ5NTMgMTAuMDk1OCAxMy41MDM2IDEwLjAzMDEgMTMuNDk4OSA5Ljk2NDU2QzEzLjQ5NDMgOS44OTkwNSAxMy40NzY4IDkuODM1MTEgMTMuNDQ3NCA5Ljc3NjM4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8cGF0aCBkPSJNMTMuMjIzOSAzLjU1MjcyTDcuMjIzNjkgMC41NTI3MjRDNy4xNTQyNCAwLjUxODA1IDcuMDc3NjggMC41IDcuMDAwMDYgMC41QzYuOTIyNDQgMC41IDYuODQ1ODggMC41MTgwNSA2Ljc3NjQ0IDAuNTUyNzI0TDAuNzc2NDM4IDMuNTUyNzJDMC42NTc4MTMgMy42MTIwMyAwLjU2NzYwOCAzLjcxNjA0IDAuNTI1NjY1IDMuODQxODZDMC41MDQ4OTcgMy45MDQxNSAwLjQ5NjYwNCAzLjk2OTkzIDAuNTAxMjU3IDQuMDM1NDRDMC41MDU5MTEgNC4xMDA5NCAwLjUyMzQyMSA0LjE2NDg5IDAuNTUyNzg4IDQuMjIzNjJDMC41ODIxNTUgNC4yODIzNiAwLjYyMjgwMyA0LjMzNDc0IDAuNjcyNDEzIDQuMzc3NzdDMC43MjIwMjIgNC40MjA3OSAwLjc3OTYyIDQuNDUzNjMgMC44NDE5MTkgNC40NzQ0QzAuOTY3NzM3IDQuNTE2MzQgMS4xMDUwNiA0LjUwNjU4IDEuMjIzNjkgNC40NDcyN0w3LjAwMDA5IDEuNTU5MDdMMTIuNzc2NyA0LjQ0NzI3QzEyLjg5NTMgNC41MDY1OCAxMy4wMzI2IDQuNTE2MzQgMTMuMTU4NSA0LjQ3NDRDMTMuMjIwOCA0LjQ1MzYzIDEzLjI3ODQgNC40MjA3OSAxMy4zMjggNC4zNzc3N0MxMy4zNzc2IDQuMzM0NzQgMTMuNDE4MiA0LjI4MjM2IDEzLjQ0NzYgNC4yMjM2MkMxMy40NzcgNC4xNjQ4OSAxMy40OTQ1IDQuMTAwOTQgMTMuNDk5MSA0LjAzNTQ0QzEzLjUwMzggMy45Njk5MyAxMy40OTU1IDMuOTA0MTUgMTMuNDc0NyAzLjg0MTg2QzEzLjQ1MzkgMy43Nzk1NiAxMy40MjExIDMuNzIxOTYgMTMuMzc4MSAzLjY3MjM1QzEzLjMzNTEgMy42MjI3NCAxMy4yODI3IDMuNTgyMDkgMTMuMjIzOSAzLjU1MjcyWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8L3N2Zz4K"//CardConstants.numberInputUpDownArrowImage + + background: Rectangle { + color: 'transparent' + } + + } + + MouseArea { + id: _numberInputSpinBoxUpIndicatorArea + + width: parent.width + height: parent.height / 2 + anchors.top: parent.top + onReleased: { + _numberInputSpinBox.changeValue(Qt.Key_Up); + _numberInputArrowRectangle.forceActiveFocus(); + } + } + + MouseArea { + id: _numberInputSpinBoxDownIndicatorArea + + width: parent.width + height: parent.height / 2 + anchors.top: _numberInputSpinBoxUpIndicatorArea.bottom + onReleased: { + _numberInputSpinBox.changeValue(Qt.Key_Down); + _numberInputArrowRectangle.forceActiveFocus(); + } + } + + /*WCustomFocusItem { + isRectangle: true + } + + } + + } + + /*InputErrorMessage { + id: _numberInputErrorMessage + + _errorMessage: _mEscapedErrorString + visible: showErrorMessage + } + +}*/ + diff --git a/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc b/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc index 5109db63f1..ac1a3dc905 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc +++ b/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc @@ -10,5 +10,8 @@ qml/JSUtils/ThemeUtils.js qml/CardConstants.qml qml/RichTextBlockRender.qml + qml/NumberInputRender.qml + qml/InputLabel.qml + qml/InputFieldClearIcon.qml diff --git a/source/qml_v2/AdaptiveCardQmlEngine/utils/AdaptiveCardEnums.h b/source/qml_v2/AdaptiveCardQmlEngine/utils/AdaptiveCardEnums.h index af5575ff6f..cdb51044d6 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/utils/AdaptiveCardEnums.h +++ b/source/qml_v2/AdaptiveCardQmlEngine/utils/AdaptiveCardEnums.h @@ -9,6 +9,7 @@ namespace AdaptiveCardEnums AdaptiveCard, TextBlock, RichTextBlock, + NumberInput, Container, Column, ColumnSet, diff --git a/source/qml_v2/AdaptiveCardVisualizer/JSONSamples/numberInput.json b/source/qml_v2/AdaptiveCardVisualizer/JSONSamples/numberInput.json new file mode 100644 index 0000000000..0286aca842 --- /dev/null +++ b/source/qml_v2/AdaptiveCardVisualizer/JSONSamples/numberInput.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + "body": [ + { + "type": "TextBlock", + "text": "Default text input" + }, + { + "type": "Input.Text", + "id": "defaultInputId", + "placeholder": "enter comment", + "maxLength": 500 + }, + { + "type": "TextBlock", + "text": "Multiline text input" + }, + { + "type": "Input.Text", + "id": "multilineInputId", + "placeholder": "enter comment", + "maxLength": 50, + "isMultiline": true + }, + { + "type": "TextBlock", + "text": "Input Number" + }, + { + "type": "Input.Number", + "id": "number", + "placeholder": "Enter a number", + "min": 1, + "max": 10, + "value": 3 + } + ], + "actions": [ + { + "type": "Action.Submit", + "title": "OK" + } + ] +} diff --git a/source/qml_v2/AdaptiveCardVisualizer/SampleCardListModel.cpp b/source/qml_v2/AdaptiveCardVisualizer/SampleCardListModel.cpp index 392880625b..d736b16ce5 100644 --- a/source/qml_v2/AdaptiveCardVisualizer/SampleCardListModel.cpp +++ b/source/qml_v2/AdaptiveCardVisualizer/SampleCardListModel.cpp @@ -56,8 +56,8 @@ void SampleCardListModel::populateCardDisplayNames() mCardDisplayNames.insert("textBlock.json", "TextBlock"); mCardDisplayNames.insert("richTextBlock.json", "Rich text"); mCardDisplayNames.insert("inputText.json", "Input text"); + mCardDisplayNames.insert("numberInput.json", "Input Number"); mCardDisplayNames.insert("actionInline.json", "Action Inline"); - mCardDisplayNames.insert("inputNumber.json", "Input number"); mCardDisplayNames.insert("dateInput.json", "Input date"); mCardDisplayNames.insert("checkBoxInput.json", "Input Toggle"); mCardDisplayNames.insert("choiceSetInput.json", "Input ChoiceSet"); From 8588f7964a91ab4935ccbd357abf71ea2583b0f0 Mon Sep 17 00:00:00 2001 From: sachinrajauriya Date: Sun, 15 Sep 2024 16:05:13 +0530 Subject: [PATCH 2/2] NumberInput UI --- .../AdaptiveCardQmlTypes.h | 1 + .../models/NumberInputModel.cpp | 39 +- .../models/NumberInputModel.h | 21 - .../qml/InputErrorMessage.qml | 52 ++ .../qml/InputFieldClearIcon.qml | 18 +- .../AdaptiveCardQmlEngine/qml/InputLabel.qml | 10 +- .../qml/NumberInputRender.qml | 515 ++---------------- .../qml/WCustomFocusItem.qml | 8 +- .../AdaptiveCardQmlEngine/resourceEngine.qrc | 1 + 9 files changed, 130 insertions(+), 535 deletions(-) create mode 100644 source/qml_v2/AdaptiveCardQmlEngine/qml/InputErrorMessage.qml diff --git a/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h b/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h index f0d8f18cd3..766a526cf1 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h +++ b/source/qml_v2/AdaptiveCardQmlEngine/AdaptiveCardQmlTypes.h @@ -26,5 +26,6 @@ namespace AdaptiveCardQmlEngine qmlRegisterType(QUrl("qrc:qml/NumberInputRender.qml"), "AdaptiveCardQmlEngine", 1, 0, "NumberInputRender"); qmlRegisterType(QUrl("qrc:qml/InputFieldClearIcon.qml"), "AdaptiveCardQmlEngine", 1, 0, "InputFieldClearIcon"); qmlRegisterType(QUrl("qrc:qml/InputLabel.qml"), "AdaptiveCardQmlEngine", 1, 0, "InputLabel"); + qmlRegisterType(QUrl("qrc:qml/InputErrorMessage.qml"), "AdaptiveCardQmlEngine", 1, 0, "InputErrorMessage"); } } // namespace RendererQml diff --git a/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp index 1031cf914a..e9d6fabf81 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp +++ b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.cpp @@ -5,46 +5,9 @@ #include "MarkDownParser.h" NumberInputModel::NumberInputModel(std::shared_ptr numberInput, QObject* parent) : - QObject(parent), mInput(numberInput) - + QObject(parent) { - const auto hostConfig = AdaptiveCardQmlEngine::AdaptiveCardContext::getInstance().getHostConfig(); - const auto rendererConfig = AdaptiveCardQmlEngine::AdaptiveCardContext::getInstance().getCardConfig(); - - mVisible = mInput->GetIsVisible(); - //mPlaceholder = QString::fromStdString(AdaptiveCardQmlEngine::Utils::getBackQuoteEscapedString(mInput->GetPlaceholder()) + "`"); - - createInputLabel(); - - if (mInput->GetValue().has_value()) - { - mValue = mInput->GetValue().value(); - mDefaultValue = true; - } - - mMinValue = numberInput->GetMin().value_or(-DBL_MAX); - mMaxValue = numberInput->GetMax().value_or(DBL_MAX); - - if (numberInput->GetIsRequired() || numberInput->GetMin().has_value() || numberInput->GetMax().has_value()) - { - } -} -void NumberInputModel::createInputLabel() -{ - if (!mInput->GetLabel().empty()) - { - // mContext->addHeightEstimate(mContext->getEstimatedTextHeight(mInput->GetLabel())); - //mEscapedLabelString = QString::fromStdString(AdaptiveCardQmlEngine::Utils::getBackQuoteEscapedString(mInput->GetLabel()) + "`"); - } - else - { - if (mInput->GetIsRequired()) - { - // mContext->AddWarning(RendererQml::AdaptiveWarning(RendererQml::Code::RenderException, "isRequired is not supported without labels")); - } - } } - NumberInputModel::~NumberInputModel() { } diff --git a/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h index f8fd81b1d9..329e2d4214 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h +++ b/source/qml_v2/AdaptiveCardQmlEngine/models/NumberInputModel.h @@ -14,29 +14,8 @@ class NumberInputModel : public QObject { Q_OBJECT - Q_PROPERTY(bool visible MEMBER mVisible CONSTANT); - Q_PROPERTY(QString placeHolder MEMBER mPlaceholder CONSTANT); - Q_PROPERTY(QString value MEMBER mValue CONSTANT); - Q_PROPERTY(bool defaultValue MEMBER mDefaultValue CONSTANT); - Q_PROPERTY(QString minValue MEMBER mMinValue CONSTANT); - Q_PROPERTY(QString maxValue MEMBER mMaxValue CONSTANT); - Q_PROPERTY(QString escapedLabelString MEMBER mEscapedLabelString CONSTANT); - public: explicit NumberInputModel(std::shared_ptr numberInput, QObject* parent = nullptr); ~NumberInputModel(); -private: - void createInputLabel(); - const std::shared_ptr& mInput; - -private: - bool mVisible; - QString mPlaceholder; - QString mValue; - bool mDefaultValue; - QString mMinValue; - QString mMaxValue; - QString mEscapedLabelString; }; -#pragma once diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/InputErrorMessage.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputErrorMessage.qml new file mode 100644 index 0000000000..9dd4b9a45f --- /dev/null +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputErrorMessage.qml @@ -0,0 +1,52 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.15 +import QtQuick.Controls 2.15 +import AdaptiveCardQmlEngine 1.0 +import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils + +Rectangle { + id: errorMessage + + property string isErrorMessage + + width: parent.width + height: errorMessageLabel.implicitHeight + color: 'transparent' + + Button { + id: errorIcon + + width: cardConst.inputFieldConstants.errorIconWidth + anchors.left: parent.left + anchors.leftMargin: cardConst.inputFieldConstants.errorIconLeftMargin + anchors.topMargin: cardConst.inputFieldConstants.errorIconTopMargin + horizontalPadding: 0 + verticalPadding: 0 + icon.width: cardConst.inputFieldConstants.errorIconWidth + icon.height: cardConst.inputFieldConstants.errorIconHeight + icon.color: cardConst.toggleButtonConstants.errorMessageColor + anchors.top: parent.top + icon.source: cardConst.errorIcon + enabled: false + + background: Rectangle { + color: 'transparent' + } + + } + + Label { + id: errorMessageLabel + + wrapMode: Text.Wrap + font.pixelSize: cardConst.inputFieldConstants.labelPixelSize + Accessible.ignored: true + color: cardConst.toggleButtonConstants.errorMessageColor + anchors.left: errorIcon.right + anchors.leftMargin: cardConst.inputFieldConstants.errorIconLeftMargin + anchors.right: parent.right + text: isErrorMessage + } + +} diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml index ca41515c3f..0f1f0732b7 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputFieldClearIcon.qml @@ -8,26 +8,24 @@ import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils Button { id: inputFieldClearIcon - width: 16//CardConstants.inputFieldConstants.clearIconSize + width: cardConst.inputFieldConstants.clearIconSize horizontalPadding: 0 verticalPadding: 0 - icon.width: 16//CardConstants.inputFieldConstants.clearIconSize - icon.height:16// CardConstants.inputFieldConstants.clearIconSize - icon.color: "black"//CardConstants.inputFieldConstants.clearIconColorNormal - icon.source: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIHZpZXdCb3g9IjAgMCAxMCAxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+Y29tbW9uLWFjdGlvbnMvY2FuY2VsXzEwPC90aXRsZT48cGF0aCBkPSJNNS43MDcyNSA1LjAwMDI1bDIuNjQ2LTIuNjQ2Yy4xOTYtLjE5Ni4xOTYtLjUxMiAwLS43MDgtLjE5NS0uMTk1LS41MTEtLjE5NS0uNzA3IDBsLTIuNjQ2IDIuNjQ3LTIuNjQ3LTIuNjQ3Yy0uMTk1LS4xOTUtLjUxMS0uMTk1LS43MDcgMC0uMTk1LjE5Ni0uMTk1LjUxMiAwIC43MDhsMi42NDcgMi42NDYtMi42NDcgMi42NDZjLS4xOTUuMTk2LS4xOTUuNTEyIDAgLjcwOC4wOTguMDk3LjIyNi4xNDYuMzU0LjE0Ni4xMjggMCAuMjU2LS4wNDkuMzUzLS4xNDZsMi42NDctMi42NDcgMi42NDYgMi42NDdjLjA5OC4wOTcuMjI2LjE0Ni4zNTQuMTQ2LjEyOCAwIC4yNTYtLjA0OS4zNTMtLjE0Ni4xOTYtLjE5Ni4xOTYtLjUxMiAwLS43MDhsLTIuNjQ2LTIuNjQ2eiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+"//CardConstants.clearIconImage + icon.width: cardConst.inputFieldConstants.clearIconSize + icon.height: cardConst.inputFieldConstants.clearIconSize + icon.color: cardConst.inputFieldConstants.clearIconColorNormal + icon.source: cardConst.clearIconImage Accessible.name: qsTr("Clear Input") Accessible.role: Accessible.Button background: Rectangle { color: 'transparent' - radius:8 //CardConstants.inputFieldConstants.borderRadius + radius: cardConst.inputFieldConstants.borderRadius - /* WCustomFocusItem { + WCustomFocusItem { isRectangle: true visible: inputFieldClearIcon.activeFocus designatedParent: parent - }*/ - + } } - } diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml index 593cfc6341..57eb41dba3 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/InputLabel.qml @@ -7,13 +7,13 @@ import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils Label { id: inputLabel - property bool _required - property string _label + property bool required + property string label wrapMode: Text.Wrap width: parent.width - color: "black"//CardConstants.toggleButtonConstants.textColor - font.pixelSize: 14 //CardConstants.inputFieldConstants.labelPixelSize + color: cardConst.toggleButtonConstants.textColor + font.pixelSize: cardConst.inputFieldConstants.labelPixelSize Accessible.ignored: true - text:""// _isRequired ? AdaptiveCardUtils.escapeHtml(_label) + " " + "*" : AdaptiveCardUtils.escapeHtml(_label) + text: required ? AdaptiveCardUtils.escapeHtml(label) + " " + "*" : AdaptiveCardUtils.escapeHtml(label) } diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml index 2acab3e83e..72c2184b8a 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/NumberInputRender.qml @@ -7,169 +7,88 @@ import "JSUtils/AdaptiveCardUtils.js" as AdaptiveCardUtils Column { id: numberInput - property var _adaptiveCard - property bool _isRequired - property bool _validationRequired - property string _mEscapedLabelString - property string _mEscapedErrorString - property string _mEscapedPlaceholderString - property bool showErrorMessage: false - property double _minValue - property double _maxValue - property double _value - property int _spinBoxMinVal : Math.max(-2147483648, _minValue) - property int _spinBoxMaxVal : Math.min(2147483647, _maxValue) - property bool _hasDefaultValue: false - - property int minWidth: cardConst.inputNumberConstants.numberInputMinWidth - property string _submitValue: _numberInputTextField.text ? Number(_numberInputTextField.text).toString() : '' - - CardConstants{ - - id:cardConst - - } - - function getAccessibleName() { - let accessibleName = ''; - if (showErrorMessage) - accessibleName += 'Error. ' + _mEscapedErrorString + '. '; - - if (_mEscapedLabelString) - accessibleName += _mEscapedLabelString + '. '; - - if (_numberInputTextField.text !== '') - accessibleName += (_numberInputTextField.text); - else - accessibleName += _mEscapedPlaceholderString; - accessibleName += qsTr(", Type the number"); - return accessibleName; - } + CardConstants{ - width: parent.width - spacing:cardConst.inputFieldConstants.columnSpacing - Component.onCompleted: { - console.log("inputFieldConstants.columnSpacing",+cardConst.inputFieldConstants.columnSpacing); - } - onShowErrorMessageChanged: { - _numberInputRectangle.colorChange(false); + id:cardConst } - onActiveFocusChanged: { - if (activeFocus) - _numberInputTextField.forceActiveFocus(); - } + width: parent.width + spacing: cardConst.inputFieldConstants.columnSpacing InputLabel { - id: _numberInputLabel + id: numberInputLabel - _label: _mEscapedLabelString - _required: _isRequired - visible: _label + label: "This is the label " + required: true + visible: label } Row { - id: _numberInputRow + id: numberInputRow width: parent.width height: cardConst.inputFieldConstants.height Rectangle { - id: _numberInputRectangle - - + id: numberInputRectangle border.width: cardConst.inputFieldConstants.borderWidth - border.color: "black"//showErrorMessage ? inputFieldConstants.borderColorOnError : inputFieldConstants.borderColorNormal + border.color: true ? cardConst.inputFieldConstants.borderColorOnError : cardConst.inputFieldConstants.borderColorNormal radius: cardConst.inputFieldConstants.borderRadius height: parent.height - color:"white"// _numberInputSpinBox.pressed ? inputFieldConstants.backgroundColorOnPressed : _numberInputSpinBox.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal - width: parent.width - 31//_numberInputArrowRectangle.width - - - /*WCustomFocusItem { + color: numberInputSpinBox.Opressed ? cardConst.inputFieldConstants.backgroundColorOnPressed : numberInputSpinBox.hovered ? cardConst.inputFieldConstants.backgroundColorOnHovered : cardConst.inputFieldConstants.backgroundColorNormal + width: parent.width - numberInputArrowRectangle.width + WCustomFocusItem { isRectangle: true - visible: _numberInputTextField.activeFocus - }*/ + visible: numberInputTextField.activeFocus + } SpinBox { - id: _numberInputSpinBox - - function changeValue(keyPressed) { - if ((keyPressed === Qt.Key_Up || keyPressed === Qt.Key_Down) && _numberInputTextField.text.length === 0) { - value = (from > 0) ? from : 0; - } else if (keyPressed === Qt.Key_Up) { - _numberInputSpinBox.value = Number(_numberInputTextField.text); - _numberInputSpinBox.increase(); - } else if (keyPressed === Qt.Key_Down) { - _numberInputSpinBox.value = Number(_numberInputTextField.text); - _numberInputSpinBox.decrease(); - } - _numberInputTextField.text = _numberInputSpinBox.value; - } + id: numberInputSpinBox - width: parent.width - _numberInputClearIcon.width - cardConst.inputFieldConstants.clearIconHorizontalPadding + width: parent.width - numberInputClearIcon.width - cardConst.inputFieldConstants.clearIconHorizontalPadding padding: 0 editable: true stepSize: 1 - // to: _spinBoxMaxVal - // from: _spinBoxMinVal - Keys.onPressed: { - if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { - _numberInputSpinBox.changeValue(event.key); - event.accepted = true; - } - } Accessible.ignored: true - Component.onCompleted: { - if (_hasDefaultValue) - _numberInputSpinBox.value = _value; - - } contentItem: TextField { - id: _numberInputTextField + id: numberInputTextField font.pixelSize: cardConst.inputFieldConstants.pixelSize anchors.left: parent.left anchors.right: parent.right selectByMouse: true selectedTextColor: 'white' - readOnly: !_numberInputSpinBox.editable - validator: _numberInputSpinBox.validator + readOnly: !numberInputSpinBox.editable + validator: numberInputSpinBox.validator inputMethodHints: Qt.ImhFormattedNumbersOnly onPressed: { - _numberInputRectangle.colorChange(true); + numberInputRectangle.colorChange(true); event.accepted = true; } onReleased: { - _numberInputRectangle.colorChange(false); + numberInputRectangle.colorChange(false); forceActiveFocus(); event.accepted = true; } - onHoveredChanged: _numberInputRectangle.colorChange(false) + onHoveredChanged: numberInputRectangle.colorChange(false) onActiveFocusChanged: { - _numberInputRectangle.colorChange(false); + numberInputRectangle.colorChange(false); Accessible.name = getAccessibleName(); } + leftPadding: cardConst.inputFieldConstants.textHorizontalPadding rightPadding: cardConst.inputFieldConstants.textHorizontalPadding topPadding: cardConst.inputFieldConstants.textVerticalPadding bottomPadding: cardConst.inputFieldConstants.textVerticalPadding - placeholderText: _mEscapedPlaceholderString + placeholderText: "Enter a number" Accessible.role: Accessible.EditableText color: cardConst.inputFieldConstants.textColor placeholderTextColor: cardConst.inputFieldConstants.placeHolderColor - onTextChanged: { - validate(); - } - Component.onCompleted: { - if (_hasDefaultValue) - _numberInputTextField.text = _numberInputSpinBox.value; - } - + background: Rectangle { - id: _numberInputTextFieldBg + id: numberInputTextFieldBg color: 'transparent' } @@ -177,7 +96,7 @@ Column { } background: Rectangle { - id: _numberSpinBoxBg + id: numberSpinBoxBg color: 'transparent' } @@ -194,407 +113,89 @@ Column { validator: DoubleValidator { } - } InputFieldClearIcon { - id: _numberInputClearIcon + id: numberInputClearIcon Keys.onReturnPressed: onClicked() - visible: _numberInputTextField.length !== 0 + visible: numberInputTextField.length !== 0 anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter anchors.margins: cardConst.inputFieldConstants.clearIconHorizontalPadding onClicked: { nextItemInFocusChain().forceActiveFocus(); - _numberInputSpinBox.value = _numberInputSpinBox.from; - _numberInputTextField.clear(); + numberInputSpinBox.value = numberInputSpinBox.from; + numberInputTextField.clear(); } } - } Rectangle { - id: _numberInputArrowRectangle + id: numberInputArrowRectangle property string accessibilityPrefix: '' - width: 31//numberInputConstants.upDownButtonWidth - radius:8// inputFieldConstants.borderRadius - height: parent.height - border.color: "black"//inputFieldConstants.borderColorNormal - activeFocusOnTab: true - color:"gray" //(_numberInputArrowIcon.pressed || activeFocus) ? inputFieldConstants.backgroundColorOnPressed : _numberInputArrowIcon.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal - Keys.onPressed: { - if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { - _numberInputSpinBox.changeValue(event.key); - accessibilityPrefix = ''; - event.accepted = true; - } - } - onActiveFocusChanged: { - if (activeFocus) - accessibilityPrefix = qsTr("Use up arrow to increase the value and down arrow to decrease the value") + (_numberInputTextField.text ? ", Current number is " : ""); - - } - Accessible.name: accessibilityPrefix + _numberInputTextField.displayText - Accessible.role: Accessible.NoRole - - Button { - id: _numberInputArrowIcon - - width: parent.width - anchors.right: parent.right - horizontalPadding: 4//inputFieldConstants.iconPadding - verticalPadding: 4//inputFieldConstants.iconPadding - icon.width: 31//numberInputConstants.upDownIconSize - icon.height:31// numberInputConstants.upDownIconSize - focusPolicy: Qt.NoFocus - icon.color: "black"//numberInputConstants.upDownIconColor - height: parent.height - icon.source: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHZpZXdCb3g9IjAgMCAxNCAxNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEzLjQ0NzQgOS43NzYzOEMxMy40MTggOS43MTc2MyAxMy4zNzc0IDkuNjY1MjUgMTMuMzI3OCA5LjYyMjIyQzEzLjI3ODIgOS41NzkxOCAxMy4yMjA2IDkuNTQ2MzUgMTMuMTU4MyA5LjUyNTU4QzEzLjA5NiA5LjUwNDgxIDEzLjAzMDIgOS40OTY1MiAxMi45NjQ3IDkuNTAxMThDMTIuODk5MiA5LjUwNTgzIDEyLjgzNTIgOS41MjMzNSAxMi43NzY1IDkuNTUyNzNMNy4wMDAwNCAxMi40NDA5TDEuMjIzNzkgOS41NTI3M0MxLjEwNTE2IDkuNDkzNDEgMC45Njc4MzIgOS40ODM2NSAwLjg0MjAwOSA5LjUyNTU5QzAuNzE2MTg2IDkuNTY3NTIgMC42MTIxNzYgOS42NTc3MyAwLjU1Mjg2MSA5Ljc3NjM1QzAuNDkzNTQ1IDkuODk0OTggMC40ODM3ODIgMTAuMDMyMyAwLjUyNTcyIDEwLjE1ODFDMC41Njc2NTggMTAuMjg0IDAuNjU3ODYxIDEwLjM4OCAwLjc3NjQ4NiAxMC40NDczTDYuNzc2NDkgMTMuNDQ3M0M2Ljg0NTk0IDEzLjQ4MiA2LjkyMjUgMTMuNSA3LjAwMDE0IDEzLjVDNy4wNzc3NyAxMy41IDcuMTU0MzQgMTMuNDgyIDcuMjIzNzkgMTMuNDQ3M0wxMy4yMjM4IDEwLjQ0NzNDMTMuMjgyNSAxMC40MTc5IDEzLjMzNDkgMTAuMzc3MyAxMy4zNzc5IDEwLjMyNzdDMTMuNDIxIDEwLjI3OCAxMy40NTM4IDEwLjIyMDQgMTMuNDc0NiAxMC4xNTgxQzEzLjQ5NTMgMTAuMDk1OCAxMy41MDM2IDEwLjAzMDEgMTMuNDk4OSA5Ljk2NDU2QzEzLjQ5NDMgOS44OTkwNSAxMy40NzY4IDkuODM1MTEgMTMuNDQ3NCA5Ljc3NjM4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8cGF0aCBkPSJNMTMuMjIzOSAzLjU1MjcyTDcuMjIzNjkgMC41NTI3MjRDNy4xNTQyNCAwLjUxODA1IDcuMDc3NjggMC41IDcuMDAwMDYgMC41QzYuOTIyNDQgMC41IDYuODQ1ODggMC41MTgwNSA2Ljc3NjQ0IDAuNTUyNzI0TDAuNzc2NDM4IDMuNTUyNzJDMC42NTc4MTMgMy42MTIwMyAwLjU2NzYwOCAzLjcxNjA0IDAuNTI1NjY1IDMuODQxODZDMC41MDQ4OTcgMy45MDQxNSAwLjQ5NjYwNCAzLjk2OTkzIDAuNTAxMjU3IDQuMDM1NDRDMC41MDU5MTEgNC4xMDA5NCAwLjUyMzQyMSA0LjE2NDg5IDAuNTUyNzg4IDQuMjIzNjJDMC41ODIxNTUgNC4yODIzNiAwLjYyMjgwMyA0LjMzNDc0IDAuNjcyNDEzIDQuMzc3NzdDMC43MjIwMjIgNC40MjA3OSAwLjc3OTYyIDQuNDUzNjMgMC44NDE5MTkgNC40NzQ0QzAuOTY3NzM3IDQuNTE2MzQgMS4xMDUwNiA0LjUwNjU4IDEuMjIzNjkgNC40NDcyN0w3LjAwMDA5IDEuNTU5MDdMMTIuNzc2NyA0LjQ0NzI3QzEyLjg5NTMgNC41MDY1OCAxMy4wMzI2IDQuNTE2MzQgMTMuMTU4NSA0LjQ3NDRDMTMuMjIwOCA0LjQ1MzYzIDEzLjI3ODQgNC40MjA3OSAxMy4zMjggNC4zNzc3N0MxMy4zNzc2IDQuMzM0NzQgMTMuNDE4MiA0LjI4MjM2IDEzLjQ0NzYgNC4yMjM2MkMxMy40NzcgNC4xNjQ4OSAxMy40OTQ1IDQuMTAwOTQgMTMuNDk5MSA0LjAzNTQ0QzEzLjUwMzggMy45Njk5MyAxMy40OTU1IDMuOTA0MTUgMTMuNDc0NyAzLjg0MTg2QzEzLjQ1MzkgMy43Nzk1NiAxMy40MjExIDMuNzIxOTYgMTMuMzc4MSAzLjY3MjM1QzEzLjMzNTEgMy42MjI3NCAxMy4yODI3IDMuNTgyMDkgMTMuMjIzOSAzLjU1MjcyWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8L3N2Zz4K"//CardConstants.numberInputUpDownArrowImage - - background: Rectangle { - color: 'transparent' - } - - } - - MouseArea { - id: _numberInputSpinBoxUpIndicatorArea - - width: parent.width - height: parent.height / 2 - anchors.top: parent.top - onReleased: { - _numberInputSpinBox.changeValue(Qt.Key_Up); - _numberInputArrowRectangle.forceActiveFocus(); - } - } - - MouseArea { - id: _numberInputSpinBoxDownIndicatorArea - - width: parent.width - height: parent.height / 2 - anchors.top: _numberInputSpinBoxUpIndicatorArea.bottom - onReleased: { - _numberInputSpinBox.changeValue(Qt.Key_Down); - _numberInputArrowRectangle.forceActiveFocus(); - } - } - - /*WCustomFocusItem { - isRectangle: true - }*/ - - } - - } - - /*InputErrorMessage { - id: _numberInputErrorMessage - - _errorMessage: _mEscapedErrorString - visible: showErrorMessage - }*/ - -} -/*Column { - id: numberInput - - property var _adaptiveCard - property bool _isRequired - property bool _validationRequired - property string _mEscapedLabelString - property string _mEscapedErrorString - property string _mEscapedPlaceholderString - property bool showErrorMessage: false - property double _minValue - property double _maxValue - property double _value - property int _spinBoxMinVal : Math.max(-2147483648, _minValue) - property int _spinBoxMaxVal : Math.min(2147483647, _maxValue) - property bool _hasDefaultValue: false - //property var numberInputConstants: CardConstants.inputNumberConstants - //property var inputFieldConstants: CardConstants.inputFieldConstants - property int minWidth:200// numberInputConstants.numberInputMinWidth - property string _submitValue: _numberInputTextField.text ? Number(_numberInputTextField.text).toString() : '' - - function validate() { - if (_numberInputTextField.text.length !== 0 && Number(_numberInputTextField.text) >= _minValue && Number(_numberInputTextField.text) <= _maxValue) { - showErrorMessage = false; - return false; - } else { - return true; - } - } - - function getAccessibleName() { - let accessibleName = ''; - if (showErrorMessage) - accessibleName += 'Error. ' + _mEscapedErrorString + '. '; - - if (_mEscapedLabelString) - accessibleName += _mEscapedLabelString + '. '; - - if (_numberInputTextField.text !== '') - accessibleName += (_numberInputTextField.text); - else - accessibleName += _mEscapedPlaceholderString; - accessibleName += qsTr(", Type the number"); - return accessibleName; - } - - width:50//parent.width - spacing: 3//inputFieldConstants.columnSpacing - onShowErrorMessageChanged: { - _numberInputRectangle.colorChange(false); - } - onActiveFocusChanged: { - if (activeFocus) - _numberInputTextField.forceActiveFocus(); - - } - - InputLabel { - id: _numberInputLabel - - _label: _mEscapedLabelString - _required: _isRequired - visible: _label - } - - Row { - id: _numberInputRow - - width: parent.width - height: 32//inputFieldConstants.height - - Rectangle { - id: _numberInputRectangle - - - - border.width: 1//inputFieldConstants.borderWidth - border.color: "black"//showErrorMessage ? inputFieldConstants.borderColorOnError : inputFieldConstants.borderColorNormal - radius: 8//inputFieldConstants.borderRadius - height: parent.height - color:"white"// _numberInputSpinBox.pressed ? inputFieldConstants.backgroundColorOnPressed : _numberInputSpinBox.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal - width: 400//parent.width - _numberInputArrowRectangle.width - - - WCustomFocusItem { - isRectangle: true - visible: _numberInputTextField.activeFocus - } - - SpinBox { - id: _numberInputSpinBox - - function changeValue(keyPressed) { - if ((keyPressed === Qt.Key_Up || keyPressed === Qt.Key_Down) && _numberInputTextField.text.length === 0) { - value = (from > 0) ? from : 0; - } else if (keyPressed === Qt.Key_Up) { - _numberInputSpinBox.value = Number(_numberInputTextField.text); - _numberInputSpinBox.increase(); - } else if (keyPressed === Qt.Key_Down) { - _numberInputSpinBox.value = Number(_numberInputTextField.text); - _numberInputSpinBox.decrease(); - } - _numberInputTextField.text = _numberInputSpinBox.value; - } - - width:50// parent.width - _numberInputClearIcon.width - CardConstants.inputFieldConstants.clearIconHorizontalPadding - padding: 0 - editable: true - stepSize: 1 - // to: _spinBoxMaxVal - // from: _spinBoxMinVal - Keys.onPressed: { - if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { - _numberInputSpinBox.changeValue(event.key); - event.accepted = true; - } - } - Accessible.ignored: true - Component.onCompleted: { - if (_hasDefaultValue) - _numberInputSpinBox.value = _value; - - } - - contentItem: TextField { - id: _numberInputTextField - - font.pixelSize: 16//inputFieldConstants.pixelSize - anchors.left: parent.left - anchors.right: parent.right - selectByMouse: true - selectedTextColor: 'white' - readOnly: !_numberInputSpinBox.editable - validator: _numberInputSpinBox.validator - inputMethodHints: Qt.ImhFormattedNumbersOnly - onPressed: { - _numberInputRectangle.colorChange(true); - event.accepted = true; - } - onReleased: { - _numberInputRectangle.colorChange(false); - forceActiveFocus(); - event.accepted = true; - } - onHoveredChanged: _numberInputRectangle.colorChange(false) - onActiveFocusChanged: { - _numberInputRectangle.colorChange(false); - Accessible.name = getAccessibleName(); - } - leftPadding: 12//inputFieldConstants.textHorizontalPadding - rightPadding: 12//inputFieldConstants.textHorizontalPadding - topPadding: 4//inputFieldConstants.textVerticalPadding - bottomPadding: 4//inputFieldConstants.textVerticalPadding - placeholderText: _mEscapedPlaceholderString - Accessible.role: Accessible.EditableText - color: "black"//inputFieldConstants.textColor - placeholderTextColor: "white"//inputFieldConstants.placeHolderColor - onTextChanged: { - validate(); - } - Component.onCompleted: { - if (_hasDefaultValue) - _numberInputTextField.text = _numberInputSpinBox.value; - } - - background: Rectangle { - id: _numberInputTextFieldBg - - color: 'transparent' - } - - } - - background: Rectangle { - id: _numberSpinBoxBg - - color: 'transparent' - } - - up.indicator: Rectangle { - color: 'transparent' - z: -1 - } - - down.indicator: Rectangle { - color: 'transparent' - z: -1 - } - - validator: DoubleValidator { - } - - } - - InputFieldClearIcon { - id: _numberInputClearIcon - - Keys.onReturnPressed: onClicked() - visible: _numberInputTextField.length !== 0 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: 12//CardConstants.inputFieldConstants.clearIconHorizontalPadding - onClicked: { - nextItemInFocusChain().forceActiveFocus(); - _numberInputSpinBox.value = _numberInputSpinBox.from; - _numberInputTextField.clear(); - } - } - - } - - Rectangle { - id: _numberInputArrowRectangle - - property string accessibilityPrefix: '' - - width: 31//numberInputConstants.upDownButtonWidth - radius:8// inputFieldConstants.borderRadius + width: cardConst.inputNumberConstants.upDownButtonWidth + radius: cardConst.inputFieldConstants.borderRadius height: parent.height - border.color: "black"//inputFieldConstants.borderColorNormal + border.color: cardConst.inputFieldConstants.borderColorNormal activeFocusOnTab: true - color:"gray" //(_numberInputArrowIcon.pressed || activeFocus) ? inputFieldConstants.backgroundColorOnPressed : _numberInputArrowIcon.hovered ? inputFieldConstants.backgroundColorOnHovered : inputFieldConstants.backgroundColorNormal - Keys.onPressed: { - if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { - _numberInputSpinBox.changeValue(event.key); - accessibilityPrefix = ''; - event.accepted = true; - } - } + color:(numberInputArrowIcon.pressed || activeFocus) ? cardConst.inputFieldConstants.backgroundColorOnPressed : numberInputArrowIcon.hovered ? cardConst.inputFieldConstants.backgroundColorOnHovered : cardConst.inputFieldConstants.backgroundColorNormal + onActiveFocusChanged: { if (activeFocus) - accessibilityPrefix = qsTr("Use up arrow to increase the value and down arrow to decrease the value") + (_numberInputTextField.text ? ", Current number is " : ""); + accessibilityPrefix = qsTr("Use up arrow to increase the value and down arrow to decrease the value") + (numberInputTextField.text ? ", Current number is " : ""); } - Accessible.name: accessibilityPrefix + _numberInputTextField.displayText + Accessible.name: accessibilityPrefix + numberInputTextField.displayText Accessible.role: Accessible.NoRole Button { - id: _numberInputArrowIcon + id: numberInputArrowIcon width: parent.width anchors.right: parent.right - horizontalPadding: 4//inputFieldConstants.iconPadding - verticalPadding: 4//inputFieldConstants.iconPadding - icon.width: 31//numberInputConstants.upDownIconSize - icon.height:31// numberInputConstants.upDownIconSize + horizontalPadding: cardConst.inputFieldConstants.iconPadding + verticalPadding: cardConst.inputFieldConstants.iconPadding + icon.width: cardConst.numberInputConstants.upDownIconSize + icon.height: cardConst.numberInputConstants.upDownIconSize focusPolicy: Qt.NoFocus - icon.color: "black"//numberInputConstants.upDownIconColor + icon.color: cardConst.inputNumberConstants.upDownIconColor height: parent.height - icon.source: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHZpZXdCb3g9IjAgMCAxNCAxNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEzLjQ0NzQgOS43NzYzOEMxMy40MTggOS43MTc2MyAxMy4zNzc0IDkuNjY1MjUgMTMuMzI3OCA5LjYyMjIyQzEzLjI3ODIgOS41NzkxOCAxMy4yMjA2IDkuNTQ2MzUgMTMuMTU4MyA5LjUyNTU4QzEzLjA5NiA5LjUwNDgxIDEzLjAzMDIgOS40OTY1MiAxMi45NjQ3IDkuNTAxMThDMTIuODk5MiA5LjUwNTgzIDEyLjgzNTIgOS41MjMzNSAxMi43NzY1IDkuNTUyNzNMNy4wMDAwNCAxMi40NDA5TDEuMjIzNzkgOS41NTI3M0MxLjEwNTE2IDkuNDkzNDEgMC45Njc4MzIgOS40ODM2NSAwLjg0MjAwOSA5LjUyNTU5QzAuNzE2MTg2IDkuNTY3NTIgMC42MTIxNzYgOS42NTc3MyAwLjU1Mjg2MSA5Ljc3NjM1QzAuNDkzNTQ1IDkuODk0OTggMC40ODM3ODIgMTAuMDMyMyAwLjUyNTcyIDEwLjE1ODFDMC41Njc2NTggMTAuMjg0IDAuNjU3ODYxIDEwLjM4OCAwLjc3NjQ4NiAxMC40NDczTDYuNzc2NDkgMTMuNDQ3M0M2Ljg0NTk0IDEzLjQ4MiA2LjkyMjUgMTMuNSA3LjAwMDE0IDEzLjVDNy4wNzc3NyAxMy41IDcuMTU0MzQgMTMuNDgyIDcuMjIzNzkgMTMuNDQ3M0wxMy4yMjM4IDEwLjQ0NzNDMTMuMjgyNSAxMC40MTc5IDEzLjMzNDkgMTAuMzc3MyAxMy4zNzc5IDEwLjMyNzdDMTMuNDIxIDEwLjI3OCAxMy40NTM4IDEwLjIyMDQgMTMuNDc0NiAxMC4xNTgxQzEzLjQ5NTMgMTAuMDk1OCAxMy41MDM2IDEwLjAzMDEgMTMuNDk4OSA5Ljk2NDU2QzEzLjQ5NDMgOS44OTkwNSAxMy40NzY4IDkuODM1MTEgMTMuNDQ3NCA5Ljc3NjM4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8cGF0aCBkPSJNMTMuMjIzOSAzLjU1MjcyTDcuMjIzNjkgMC41NTI3MjRDNy4xNTQyNCAwLjUxODA1IDcuMDc3NjggMC41IDcuMDAwMDYgMC41QzYuOTIyNDQgMC41IDYuODQ1ODggMC41MTgwNSA2Ljc3NjQ0IDAuNTUyNzI0TDAuNzc2NDM4IDMuNTUyNzJDMC42NTc4MTMgMy42MTIwMyAwLjU2NzYwOCAzLjcxNjA0IDAuNTI1NjY1IDMuODQxODZDMC41MDQ4OTcgMy45MDQxNSAwLjQ5NjYwNCAzLjk2OTkzIDAuNTAxMjU3IDQuMDM1NDRDMC41MDU5MTEgNC4xMDA5NCAwLjUyMzQyMSA0LjE2NDg5IDAuNTUyNzg4IDQuMjIzNjJDMC41ODIxNTUgNC4yODIzNiAwLjYyMjgwMyA0LjMzNDc0IDAuNjcyNDEzIDQuMzc3NzdDMC43MjIwMjIgNC40MjA3OSAwLjc3OTYyIDQuNDUzNjMgMC44NDE5MTkgNC40NzQ0QzAuOTY3NzM3IDQuNTE2MzQgMS4xMDUwNiA0LjUwNjU4IDEuMjIzNjkgNC40NDcyN0w3LjAwMDA5IDEuNTU5MDdMMTIuNzc2NyA0LjQ0NzI3QzEyLjg5NTMgNC41MDY1OCAxMy4wMzI2IDQuNTE2MzQgMTMuMTU4NSA0LjQ3NDRDMTMuMjIwOCA0LjQ1MzYzIDEzLjI3ODQgNC40MjA3OSAxMy4zMjggNC4zNzc3N0MxMy4zNzc2IDQuMzM0NzQgMTMuNDE4MiA0LjI4MjM2IDEzLjQ0NzYgNC4yMjM2MkMxMy40NzcgNC4xNjQ4OSAxMy40OTQ1IDQuMTAwOTQgMTMuNDk5MSA0LjAzNTQ0QzEzLjUwMzggMy45Njk5MyAxMy40OTU1IDMuOTA0MTUgMTMuNDc0NyAzLjg0MTg2QzEzLjQ1MzkgMy43Nzk1NiAxMy40MjExIDMuNzIxOTYgMTMuMzc4MSAzLjY3MjM1QzEzLjMzNTEgMy42MjI3NCAxMy4yODI3IDMuNTgyMDkgMTMuMjIzOSAzLjU1MjcyWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC45NSIvPgo8L3N2Zz4K"//CardConstants.numberInputUpDownArrowImage + icon.source: cardConst.numberInputUpDownArrowImage background: Rectangle { color: 'transparent' } - } MouseArea { - id: _numberInputSpinBoxUpIndicatorArea + id: numberInputSpinBoxUpIndicatorArea width: parent.width height: parent.height / 2 anchors.top: parent.top - onReleased: { - _numberInputSpinBox.changeValue(Qt.Key_Up); - _numberInputArrowRectangle.forceActiveFocus(); - } } MouseArea { - id: _numberInputSpinBoxDownIndicatorArea + id: numberInputSpinBoxDownIndicatorArea width: parent.width height: parent.height / 2 - anchors.top: _numberInputSpinBoxUpIndicatorArea.bottom - onReleased: { - _numberInputSpinBox.changeValue(Qt.Key_Down); - _numberInputArrowRectangle.forceActiveFocus(); - } + anchors.top: numberInputSpinBoxUpIndicatorArea.bottom } - /*WCustomFocusItem { + WCustomFocusItem { isRectangle: true } - } - } - /*InputErrorMessage { - id: _numberInputErrorMessage + InputErrorMessage { + id: numberInputErrorMessage - _errorMessage: _mEscapedErrorString - visible: showErrorMessage + isErrorMessage:"errorMessage" + visible: true } - -}*/ - +} \ No newline at end of file diff --git a/source/qml_v2/AdaptiveCardQmlEngine/qml/WCustomFocusItem.qml b/source/qml_v2/AdaptiveCardQmlEngine/qml/WCustomFocusItem.qml index b353063c98..890382c896 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/qml/WCustomFocusItem.qml +++ b/source/qml_v2/AdaptiveCardQmlEngine/qml/WCustomFocusItem.qml @@ -93,12 +93,12 @@ Item { Canvas { id: canvas - readonly property var focusOutlineMiddleColor: CardConstants.cardConstants.focusOutlineMiddleColor - readonly property var focusOutlineOuterColor: CardConstants.cardConstants.focusOutlineOuterColor - readonly property var focusOutlineInnerColor: CardConstants.cardConstants.focusOutlineInnerColor + readonly property var focusOutlineMiddleColor: cardConst.cardConst.focusOutlineMiddleColor + readonly property var focusOutlineOuterColor: cardConst.cardConst.focusOutlineOuterColor + readonly property var focusOutlineInnerColor: cardConst.cardConst.focusOutlineInnerColor readonly property int lineThickness: 2 readonly property int outerLineThickness: 1 - readonly property int smallRadius: 4 + readonly property int smallRadius: 5 readonly property int extraSmallRadius: 2 readonly property bool isRTLEnabled: Qt.application.layoutDirection === Qt.RightToLeft diff --git a/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc b/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc index 1ec7dc74e4..4cfeb92e46 100644 --- a/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc +++ b/source/qml_v2/AdaptiveCardQmlEngine/resourceEngine.qrc @@ -19,5 +19,6 @@ qml/NumberInputRender.qml qml/InputLabel.qml qml/InputFieldClearIcon.qml + qml/InputErrorMessage.qml