diff --git a/doc/src/images/status_item_picker.png b/doc/src/images/status_item_picker.png new file mode 100644 index 00000000..b2e09161 Binary files /dev/null and b/doc/src/images/status_item_picker.png differ diff --git a/doc/src/images/status_list_picker.png b/doc/src/images/status_list_picker.png new file mode 100644 index 00000000..f68fc422 Binary files /dev/null and b/doc/src/images/status_list_picker.png differ diff --git a/doc/src/statusqcomponents.qdoc b/doc/src/statusqcomponents.qdoc index ca394eca..8a27a894 100644 --- a/doc/src/statusqcomponents.qdoc +++ b/doc/src/statusqcomponents.qdoc @@ -22,6 +22,7 @@ \li \l{StatusDescriptionListItem} \li \l{StatusLetterIdenticon} \li \l{StatusListItem} + \li \l{StatusListPicker} \li \l{StatusListSectionHeadline} \li \l{StatusLoadingIndicator} \li \l{StatusMemberListItem} diff --git a/doc/src/statusqcontrols.qdoc b/doc/src/statusqcontrols.qdoc index fd022549..aee3af67 100644 --- a/doc/src/statusqcontrols.qdoc +++ b/doc/src/statusqcontrols.qdoc @@ -32,6 +32,7 @@ \li \l{StatusBaseInput} \li \l{StatusIdenticonRing} \li \l{StatusInput} + \li \l{StatusItemPicker} \li \l{StatusPickerButton} \li \l{StatusPinInput} \li \l{StatusProgressBar} diff --git a/sandbox/demoapp/data/Models.qml b/sandbox/demoapp/data/Models.qml index 63828103..930120bd 100644 --- a/sandbox/demoapp/data/Models.qml +++ b/sandbox/demoapp/data/Models.qml @@ -1052,4 +1052,309 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I notificationsCount: 0 } } + + property ListModel currencyPickerModel: ListModel { + ListElement { + key: 0 + name: "United States Dollar" + shortName: "USD" + symbol: "$" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "" + selected: false + } + ListElement { + key: 1 + name: "British Pound" + shortName: "GBP" + symbol: "£" + imageSource: "../../assets/twemoji/26x26/1f4b5.png" + category: "" + selected: false + } + ListElement { + key: 2 + name: "Euro" + shortName: "EUR" + symbol: "€" + imageSource: "../../assets/twemoji/26x26/1f4b6.png" + category: "" + selected: true + } + ListElement { + key: 3 + name: "Shout Korean Won" + shortName: "KRW" + symbol: "₩" + imageSource: "../../assets/twemoji/26x26/1f4b8.png" + category: "" + selected: false + } + ListElement { + key: 4 + name: "Ethereum" + shortName: "ETH" + symbol: "Ξ" + imageSource: "../../assets/twemoji/26x26/1f4b7.png" + category: "Tokens" + selected: true + } + ListElement { + key: 5 + name: "Bitcoin" + shortName: "BTC" + symbol: "฿" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "Tokens" + selected: false + } + ListElement { + key: 6 + name: "Status Network Token" + shortName: "SNT" + symbol: "" + imageSource: "../../assets/twemoji/26x26/1f4b8.png" + category: "Tokens" + selected: false + } + + ListElement { + key: 7 + name: "Emirati Dirham" + shortName: "AED" + symbol: "د.إ" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "Other Fiat" + selected: false + } + ListElement { + key: 8 + name: "Afghani" + shortName: "AFN" + symbol: "؋" + imageSource: "../../assets/twemoji/26x26/1f4b7.png" + category: "Other Fiat" + selected: false + } + ListElement { + key: 9 + name: "Argentine Peso" + shortName: "AFN" + symbol: "$" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "Other Fiat" + selected: false + } + } + + property ListModel currencyPickerModel2: ListModel { + ListElement { + key: 0 + name: "United States Dollar" + shortName: "USD" + symbol: "$" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "" + selected: false + } + ListElement { + key: 1 + name: "British Pound" + shortName: "GBP" + symbol: "£" + imageSource: "../../assets/twemoji/26x26/1f4b5.png" + category: "" + selected: false + } + ListElement { + key: 2 + name: "Euro" + shortName: "EUR" + symbol: "€" + imageSource: "../../assets/twemoji/26x26/1f4b6.png" + category: "" + selected: true + } + ListElement { + key: 3 + name: "Shout Korean Won" + shortName: "KRW" + symbol: "₩" + imageSource: "../../assets/twemoji/26x26/1f4b8.png" + category: "" + selected: false + } + ListElement { + key: 4 + name: "Ethereum" + shortName: "ETH" + symbol: "Ξ" + imageSource: "../../assets/twemoji/26x26/1f4b7.png" + category: "Tokens" + selected: true + } + ListElement { + key: 5 + name: "Bitcoin" + shortName: "BTC" + symbol: "฿" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "Tokens" + selected: false + } + ListElement { + key: 6 + name: "Status Network Token" + shortName: "SNT" + symbol: "" + imageSource: "../../assets/twemoji/26x26/1f4b8.png" + category: "Tokens" + selected: false + } + + ListElement { + key: 7 + name: "Emirati Dirham" + shortName: "AED" + symbol: "د.إ" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "Other Fiat" + selected: false + } + ListElement { + key: 8 + name: "Afghani" + shortName: "AFN" + symbol: "؋" + imageSource: "../../assets/twemoji/26x26/1f4b7.png" + category: "Other Fiat" + selected: false + } + ListElement { + key: 9 + name: "Argentine Peso" + shortName: "AFN" + symbol: "$" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "Other Fiat" + selected: false + } + } + + property ListModel languagePickerModel: ListModel { + ListElement { + key: 0 + name: "English" + shortName: "English" + imageSource: "../../assets/twemoji/26x26/1f1ec-1f1e7.png" + category: "" + selected: false + } + ListElement { + key: 1 + name: "Korean" + shortName: "한국어" + imageSource: "../../assets/twemoji/26x26/1f1f0-1f1f7.png" + category: "" + selected: false + } + ListElement { + key: 2 + name: "Portuguese (Brazilian)" + shortName: "Português" + imageSource: "../../assets/twemoji/26x26/1f1e7-1f1f7.png" + category: "" + selected: true + } + ListElement { + key: 3 + name: "Dutch" + shortName: "Nederlands" + imageSource: "../../assets/twemoji/26x26/1f1f3-1f1f1.png" + category: "Beta Languages" + selected: false + } + ListElement { + key: 4 + name: "Indonesian" + shortName: "Bahasa Indonesia" + imageSource: "../../assets/twemoji/26x26/1f1ee-1f1e9.png" + category: "Beta Languages" + selected: false + } + ListElement { + key: 5 + name: "Spanish" + shortName: "Español" + imageSource: "../../assets/twemoji/26x26/1f1ea-1f1e6.png" + category: "Beta Languages" + selected: false + } + } + + property ListModel languageNoImagePickerModel: ListModel { + ListElement { + key: 0 + name: "Chinese (Mainland China)" + shortName: "普通话" + category: "" + selected: true + } + ListElement { + key: 1 + name: "Russian" + shortName: "Русский Язык" + category: "" + selected: false + } + ListElement { + key: 2 + name: "Arabic" + shortName: "اَلْعَرَبِيَّةُ" + category: "Beta Languages" + selected: true + } + ListElement { + key: 3 + name: "Chinese (Taiwan)" + shortName: "臺灣華語" + category: "Beta Languages" + selected: false + } + ListElement { + key: 4 + name: "Filipino" + shortName: "Wikang Filipino" + category: "Beta Languages" + selected: false + } + ListElement { + key: 5 + name: "French" + shortName: "Français" + category: "Beta Languages" + selected: false + } + ListElement { + key: 6 + name: "Italian" + shortName: "Italiano" + category: "Beta Languages" + selected: false + } + ListElement { + key: 7 + name: "Turkish" + shortName: "Türkçe" + category: "Beta Languages" + selected: false + } + ListElement { + key: 8 + name: "Urdu" + shortName: "اُردُو" + category: "Beta Languages" + selected: false + } + } } diff --git a/sandbox/main.qml b/sandbox/main.qml index 608f01b5..0e75f1f7 100644 --- a/sandbox/main.qml +++ b/sandbox/main.qml @@ -275,6 +275,11 @@ StatusWindow { selected: viewLoader.source.toString().includes(title) onClicked: mainPageView.page(title); } + StatusNavigationListItem { + title: "StatusListPicker" + selected: viewLoader.source.toString().includes(title) + onClicked: mainPageView.page(title); + } StatusListSectionHeadline { text: "StatusQ.Popup" } StatusNavigationListItem { title: "StatusPopupMenu" diff --git a/sandbox/pages/StatusListPickerPage.qml b/sandbox/pages/StatusListPickerPage.qml new file mode 100644 index 00000000..8c7cbc94 --- /dev/null +++ b/sandbox/pages/StatusListPickerPage.qml @@ -0,0 +1,78 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.14 + +import StatusQ.Controls 0.1 +import StatusQ.Components 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Core 0.1 + +import "../demoapp/data" 1.0 + +GridLayout { + id: root + columns: 1 + rowSpacing: 150 + + GridLayout { + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + rows: 4 + columns: 2 + rowSpacing: 170 + columnSpacing: 150 + z: 100 + StatusListPicker { + id: languagePicker + z: 100 + inputList: Models.languagePickerModel + searchText: qsTr("Search Languages") + } + + StatusListPicker { + id: languagePicker2 + z: 100 + inputList: Models.languageNoImagePickerModel + searchText: qsTr("Search Languages") + } + + StatusListPicker { + id: currencyPicker + inputList: Models.currencyPickerModel + searchText: qsTr("Search Currencies") + multiSelection: true + } + + StatusListPicker { + id: currencyPicker2 + inputList: Models.currencyPickerModel2 + searchText: qsTr("Search Currencies") + multiSelection: true + printSymbol: true + } + } + + StatusBaseText { + id: pageDesc + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + height: 100 + width: 500 + text: "4 different configurations for the `StatusListPicker` component:\n + * Single selection. \n + * Single selection but dynamically changed to multiple selection (model provides multiple selected items).\n + * Multiple selection.\n + * Multiple selection and displayed name is the symbol + shortName\n" + color: Theme.palette.baseColor1 + font.pixelSize: 15 + } + + // Outsite area + MouseArea { + height: root.height + width: root.width + onClicked: { + languagePicker.close() + languagePicker2.close() + currencyPicker.close() + currencyPicker2.close() + } + } +} diff --git a/src/StatusQ/Components/StatusListPicker.qml b/src/StatusQ/Components/StatusListPicker.qml new file mode 100644 index 00000000..48120e79 --- /dev/null +++ b/src/StatusQ/Components/StatusListPicker.qml @@ -0,0 +1,324 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtGraphicalEffects 1.13 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 + +/*! + \qmltype StatusListPicker + \inherits Item + \inqmlmodule StatusQ.Components + \since StatusQ.Components 0.1 + \brief It is a combination of StatusPickerButton and a drop-down list component that provides a way of presenting a list of selectable options to the user. + + The \c StatusListPicker is populated with a data model. The data model is commonly a JavaScript array or a ListModel object. + + StatusListPicker can be made as a single or multiple options picker by setting its StatusListPicker::multiSelection property properly or will be auto-set if the model contains / provides more than one selected items. + The StatusPickerButton text holds the text of the current item selected in the list picker. If there is more than one item selected, a string composed will be displayed. + The drop-down list incorporates a searcher by the following model roles: `name` or / and `shortName`. + + NOTE: Make sure to set the appropriate z-index when instantiating the component in order to place it on top of your view in order to display the drop-down data properly. + Make sure to position the component inside its parent also when it is spanned in order to achieve a better user experience. + + Example of how the component looks like: + \image status_list_picker.png + Example of how to use it: + \qml + StatusListPicker { + id: currencyPicker + inputList: Models.currencyPickerModel + searchText: qsTr("Search Language") + multiSelection: true + printSymbol: true + } + \endqml + For a list of components available see StatusQ. +*/ +Item { + id: root + + /*! + \qmlproperty string StatusListPicker::inputList + This property holds the data that will be populated in the list picker. + + NOTE: This model property should not change so it is an in / out property where the selected role will be dynamically changed according to user actions. + + Here an example of the model roles expected: + \qml + inputList: ListModel { + ListElement { + key: 0 + name: "United States Dollar" + shortName: "USD" + symbol: "$" + imageSource: "../../assets/twemoji/26x26/1f4b4.png" + category: "fiat" + selected: true + } + ListElement { + key: 1 + name: "British Pound" + shortName: "GBP" + symbol: "£" + imageSource: "../../assets/twemoji/26x26/1f4b5.png" + category: "fiat" + selected: false + } + } + \endqml + */ + property ListModel inputList: ListModel { } + + /*! + \qmlproperty string StatusListPicker::searchText + This property holds the placeholder text the searcher input displays by default. + */ + property string searchText: qsTr("Search") + + /*! + \qmlproperty string StatusListPicker::multiSelection + This property holds whether the list picker is a single or a multiple picker option by displaying a StatusRadioButton or StatusCheckBox instead. + */ + property bool multiSelection: false + + /*! + \qmlproperty string StatusListPicker::printSymbol + This property holds whether the selected items will display a composition of the role `symbol` in the StatusPickerButton text or just only the role `shortName`. + */ + property bool printSymbol: false + + /*! + \qmlproperty string StatusListPicker::maxPickerHeight + This property holds the maximum drop-down list height allowed. The drop-down list height will be set as the minimum value between the list content height and the maxPickerHeight property. + */ + property int maxPickerHeight: 718 + + /* + \qmlmethod StatusListPicker::close() + It can be used to force to close the drop-down picker list whenever the consumer needs it. For example by adding an outside MouseArea to close the picker when user clicks outsite the component: + \qml + // Outsite area + MouseArea { + height: root.height + width: root.width + onClicked: { currencyPicker.close() } + } + \endqml + */ + function close() { if(picker.visible) picker.visible = false } + + QtObject { + id: d + property var filteredModel: ListModel { } + + // Used to set up component and the needed private properties + function initialize() { + if(filteredModel.count === 0) { + // It is necessary to load the model, not loaded yet! + var selected = 0 + var selectionText = "" + for(var i = 0; i < root.inputList.count; i++) { + var item = root.inputList.get(i) + d.filteredModel.append(item) + if(item.selected) selected++; + } + + // If the given model has more than one selected elements, the behaviour of the list picker will be as a multiple selector with checkboxes although it is + // set in the radiobutton mode. Radiobutton mode is only for mutial-exclusion. + if(selected > 1) + multiSelection = true + + // Update selected items text: + d.getSelectedItemsText() + } + } + + // Used to update model elements given a specific text by filtering them for its `name` and / or `shortName`. + function applyFilter(text) { + const input = text.toLowerCase() + filteredModel.clear() + for(var i = 0; i < root.inputList.count; i++) { + let item = root.inputList.get(i) + if(item.name.toLowerCase().includes(input) || item.shortName.toLowerCase().includes(input)) + filteredModel.append(item) + } + } + + function formatSymbolShortNameText(symbol, shortName) { + var formattedText = "" + if(root.printSymbol && symbol) + formattedText = symbol + shortName + else + formattedText = shortName + return formattedText + } + + function getSelectedItemsText() { + var res = "" + for(var i = 0; i < root.inputList.count; i++) { + var item = root.inputList.get(i) + if(item.selected) { + if(res != "") + res += ", " + res += d.formatSymbolShortNameText(item.symbol, item.shortName) + } + } + return res + } + + // Used to update the base input list model with the new selected property + function updateInputListModel(key, selected, isSingleSelection) { + // If it is a single selection we must ensure that when a new key is selected others are cleared. + // It must be done manually because as there is the option of filterning, the model visualized changes + // and it could be possible to have a filtered list without an element selected (but in the base model + // it is) so, the binding to not selected will not be executed, as in the current filtered model + // there are no changes to update, just only the selected one. + for(var i = 0; i < root.inputList.count; i++) { + if(root.inputList.get(i).key === key) { + root.inputList.get(i).selected = selected + } + else if(isSingleSelection && selected) { + // Clear all the list + root.inputList.get(i).selected = false + } + } + } + } + + width: 110 + height: 38 + + Component.onCompleted: d.initialize() + + StatusPickerButton { + id: btn + anchors.fill: parent + bgColor: Theme.palette.primaryColor3 + contentColor: Theme.palette.primaryColor1 + text: picker.selectedItemsText + type: StatusPickerButton.Type.Down + + onClicked: { + picker.visible = !picker.visible + + // Restart list position: + content.positionViewAtBeginning() + content.forceActiveFocus() + } + } + + Rectangle { + id: picker + + property string selectedItemsText: "" + + width: content.itemWidth + height: Math.min(content.contentHeight + content.anchors.topMargin + content.anchors.bottomMargin, root.maxPickerHeight) + anchors.left: btn.left + anchors.top: btn.bottom + anchors.topMargin: 4 + visible: false + color: Theme.palette.statusPopupMenu.backgroundColor + radius: 8 + layer.enabled: true + layer.effect: DropShadow { + source: picker + horizontalOffset: 0 + verticalOffset: 4 + radius: 12 + samples: 25 + spread: 0.2 + color: Theme.palette.dropShadow + } + + ListView { + id: content + + property int itemHeight: 40 + property int itemWidth: 360 + + model: d.filteredModel + width: itemWidth + anchors.top: parent.top + anchors.topMargin: 8 + anchors.bottom: parent.bottom + anchors.bottomMargin: 8 + currentIndex: -1 + clip: true + headerPositioning: ListView.OverlayHeader + header: Rectangle { + id: header + width: content.itemWidth + height: searchInput.height + 24 + color: Theme.palette.statusPopupMenu.backgroundColor + z: 3 // Above delegate (z=1) and above section.delegate (z = 2) + + StatusBaseInput { + id: searchInput + implicitHeight: 36 + width: content.itemWidth - 2 * 18 + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + topPadding: 8 + bottomPadding: 0 + placeholderText: root.searchText + icon.name: "search" + + onTextChanged: { d.applyFilter(text) } + } + }// End of search input item + delegate: StatusItemPicker { + width: content.itemWidth + height: content.itemHeight + image: StatusImageSettings { + source: model.imageSource ? model.imageSource : "" + width: 15 + height: 15 + isIdenticon: false + } + name: model.name + shortName: model.shortName + selectorType: root.multiSelection ? StatusItemPicker.SelectorType.CheckBox : StatusItemPicker.SelectorType.RadioButton + selected: model.selected + radioGroup: radioBtnGroup + + onCheckedChanged: { + d.updateInputListModel(model.key, checked, selectorType === StatusItemPicker.SelectorType.RadioButton) + if(selectorType === StatusItemPicker.SelectorType.RadioButton && checked) { + // Update selected item text + picker.selectedItemsText = d.formatSymbolShortNameText(model.symbol, model.shortName) + } + else { + // Update selected items text (multiple selection, text chain). + picker.selectedItemsText = d.getSelectedItemsText() + } + } + } + section.property: "category" + section.criteria: ViewSection.FullString + section.delegate: Item { + width: content.itemWidth + height: content.itemHeight + + StatusBaseText { + anchors.leftMargin: 18 + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + text: section + color: Theme.palette.baseColor1 + font.pixelSize: 15 + elide: Text.ElideRight + } + }// End of Category item + + onActiveFocusChanged: { if(!activeFocus) root.close() } + + // Not visual element to control mutual-exclusion of radiobuttons that are not sharing the same parent (inside list view) + ButtonGroup { + id: radioBtnGroup + } + }// End of Content + }// End of Rectangle picker +} diff --git a/src/StatusQ/Components/qmldir b/src/StatusQ/Components/qmldir index c834d2f4..973bb377 100644 --- a/src/StatusQ/Components/qmldir +++ b/src/StatusQ/Components/qmldir @@ -24,6 +24,7 @@ StatusRoundedImage 0.1 StatusRoundedImage.qml StatusMacWindowButtons 0.1 StatusMacWindowButtons.qml StatusListItemBadge 0.1 StatusListItemBadge.qml StatusListItemTag 0.1 StatusListItemTag.qml +StatusListPicker 0.1 StatusListPicker.qml StatusExpandableItem 0.1 StatusExpandableItem.qml StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml StatusMessage 0.1 StatusMessage.qml diff --git a/src/StatusQ/Controls/StatusItemPicker.qml b/src/StatusQ/Controls/StatusItemPicker.qml new file mode 100644 index 00000000..c9112899 --- /dev/null +++ b/src/StatusQ/Controls/StatusItemPicker.qml @@ -0,0 +1,183 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.13 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 + +/*! + \qmltype StatusItemPicker + \inherits Item + \inqmlmodule StatusQ.Controls + \since StatusQ.Controls 0.1 + \brief It presents a selectable item to the user. + + The \c StatusItemPicker is populated with the given properties data. + + StatusItemPicker can be made as a RadioButton or CheckBox selectable item. + + Example of how the component looks like: + \image status_item_picker.png + Example of how to use it: + \qml + StatusItemPicker { + width: 300 + height: 40 + imageSource: model.imageSource + name: model.name + shortName: model.shortName + selectorType: root.multiSelection ? StatusItemPicker.SelectorType.CheckBox : StatusItemPicker.SelectorType.RadioButton + selected: model.selected + radioGroup: content.radioGroup + + onCheckedChanged: { // Some updates } + } + \endqml + For a list of components available see StatusQ. +*/ +Item { + id: root + + /*! + \qmlproperty string StatusItemPicker::image + This property holds the image settings information. + */ + property StatusImageSettings image + + /*! + \qmlproperty string StatusItemPicker::name + This property holds the main text or name to be displayed. + */ + property string name + + /*! + \qmlproperty string StatusItemPicker::shortName + This property holds the secondary text or short name to be displayed. + */ + property string shortName + + /*! + \qmlproperty string StatusItemPicker::selectorType + This property holds the selector type. Possible options are: + \qml + enum SelectorType { + RadioButton, + CheckBox + } + \endqml + By default, RadioButton. + */ + property int selectorType: StatusItemPicker.SelectorType.RadioButton + + /*! + \qmlproperty string StatusItemPicker::selected + This property holds if the item is selected. + */ + property bool selected + + /*! + \qmlproperty string StatusItemPicker::radioGroup + This property holds the button group object the radiobutton belongs to. + */ + property ButtonGroup radioGroup + + /*! + \qmlsignal StatusItemPicker::checkedChanged(bool checked) + This signal is emitted when the item is selected by pressing the radiobutton or the checkbox. + */ + signal checkedChanged(bool checked) + + enum SelectorType { + RadioButton, + CheckBox + } + + QtObject { + id: d + + property int minShortNameWidth: 50 + + function availableTextWidth() { + return root.width - imageItem.width - row.spacing - shortNameItem.anchors.rightMargin - selector.width - selector.anchors.rightMargin - 24/*Margin between both texts*/ + } + } + + Row { + id: row + anchors.left: parent.left + anchors.leftMargin: 18 + anchors.verticalCenter: parent.verticalCenter + spacing: 8 + + StatusIcon { + id: imageItem + anchors.verticalCenter: parent.verticalCenter + source: root.image.source ? root.image.source : "" + width: root.image.width + height: root.image.height + visible: root.image.source !== undefined + } + + StatusBaseText { + id: nameItem + anchors.verticalCenter: parent.verticalCenter + width: dummyNameItem.width > d.availableTextWidth() - d.minShortNameWidth ? + d.availableTextWidth() - d.minShortNameWidth : + dummyNameItem.width + text: root.name + color: Theme.palette.directColor1 + font.pixelSize: 15 + clip: true + elide: Text.ElideRight + } + // Dummy object just to exactly know the width needed by `name` and dynamically set a limit for nameItem and shortNameItem components + StatusBaseText { + id: dummyNameItem + visible: false + text: root.name + font.pixelSize: 15 + } + } + + StatusBaseText { + id: shortNameItem + width: d.availableTextWidth() - nameItem.width < d.minShortNameWidth ? + d.minShortNameWidth : + d.availableTextWidth() - nameItem.width + anchors.right: selector.left + anchors.rightMargin: 10 + anchors.verticalCenter: parent.verticalCenter + text: root.shortName + color: Theme.palette.baseColor1 + font.pixelSize: 15 + clip: true + elide: Text.ElideRight + horizontalAlignment: Text.AlignRight + } + + // 2 different options: Or with radio buttons or with checkboxes: + Loader { + id: selector + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 18 + sourceComponent: root.selectorType === StatusItemPicker.SelectorType.RadioButton ? radioBtn : checkbox + } + + Component { + id: radioBtn + StatusRadioButton { + ButtonGroup.group: root.radioGroup + checked: root.selected + onCheckedChanged: root.checkedChanged(checked) + } + } + + Component { + id: checkbox + StatusCheckBox { + checked: root.selected + onCheckedChanged: root.checkedChanged(checked) + } + } +}// End of Content item diff --git a/src/StatusQ/Controls/StatusPickerButton.qml b/src/StatusQ/Controls/StatusPickerButton.qml index 8bcf5a56..c2395bb5 100644 --- a/src/StatusQ/Controls/StatusPickerButton.qml +++ b/src/StatusQ/Controls/StatusPickerButton.qml @@ -11,7 +11,13 @@ Button { property color bgColor: Theme.palette.baseColor2 property color contentColor: Theme.palette.baseColor1 - signal clicked() + property var type: StatusPickerButton.Type.Next + property int lateralMargins: 16 + + enum Type { + Next, + Down + } background: Item { anchors.fill: parent @@ -20,31 +26,57 @@ Button { anchors.fill: parent radius: 8 color: root.bgColor - } - StatusIcon { - id: nextIcon - anchors.right: parent.right - anchors.rightMargin: 8 - anchors.verticalCenter: parent.verticalCenter - icon: "next" - color: !Qt.colorEqual(root.contentColor, Theme.palette.baseColor1) - ? root.contentColor : Theme.palette.directColor1 - } + } } contentItem: Item { anchors.fill: parent + state: root.type === StatusPickerButton.Type.Next ? "NEXT" : "DOWN" + StatusBaseText { id: textLabel - anchors { - fill: parent - leftMargin: 16 - } + anchors.verticalCenter: parent.verticalCenter + width: parent.width - icon.width - anchors.rightMargin - anchors.leftMargin - icon.anchors.rightMargin - icon.anchors.leftMargin verticalAlignment: Text.AlignVCenter font.pixelSize: 15 color: root.contentColor text: root.text + clip: true + elide: Text.ElideRight } + + StatusIcon { + id: icon + anchors.verticalCenter: parent.verticalCenter + color: !Qt.colorEqual(root.contentColor, Theme.palette.baseColor1) ? root.contentColor : Theme.palette.directColor1 + } + + states: [ + State { + name: "NEXT" + PropertyChanges {target: icon; icon: "next"} + PropertyChanges {target: icon; anchors.left: undefined } + PropertyChanges {target: icon; anchors.right: parent.right } + PropertyChanges {target: icon; anchors.rightMargin: root.lateralMargins / 2 } + PropertyChanges {target: icon; anchors.leftMargin: root.lateralMargins / 2 } + PropertyChanges {target: textLabel; anchors.left: parent.left } + PropertyChanges {target: textLabel; anchors.right: undefined } + PropertyChanges {target: textLabel; anchors.rightMargin: undefined } + PropertyChanges {target: textLabel; anchors.leftMargin: root.lateralMargins } + }, + State { + name: "DOWN" + PropertyChanges {target: icon; icon: "chevron-down"} + PropertyChanges {target: icon; anchors.left: parent.left } + PropertyChanges {target: icon; anchors.right: undefined } + PropertyChanges {target: icon; anchors.rightMargin: root.lateralMargins / 2 } + PropertyChanges {target: icon; anchors.leftMargin: root.lateralMargins } + PropertyChanges {target: textLabel; anchors.left: icon.right } + PropertyChanges {target: textLabel; anchors.right: undefined } + PropertyChanges {target: textLabel; anchors.rightMargin: root.lateralMargins / 2 } + PropertyChanges {target: textLabel; anchors.leftMargin: undefined } + } + ] } MouseArea { @@ -52,8 +84,6 @@ Button { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: { - root.clicked(); - } + onClicked: { root.clicked() } } } diff --git a/src/StatusQ/Controls/qmldir b/src/StatusQ/Controls/qmldir index 8c677cf3..1c1afaf9 100644 --- a/src/StatusQ/Controls/qmldir +++ b/src/StatusQ/Controls/qmldir @@ -9,6 +9,7 @@ StatusChatListCategoryItemButton 0.1 StatusChatListCategoryItemButton.qml StatusColorSelector 0.1 StatusColorSelector.qml StatusIconTabButton 0.1 StatusIconTabButton.qml StatusIdenticonRing 0.1 StatusIdenticonRing.qml +StatusItemPicker 0.1 StatusItemPicker.qml StatusNavBarTabButton 0.1 StatusNavBarTabButton.qml StatusTabBarIconButton 0.1 StatusTabBarIconButton.qml StatusToolTip 0.1 StatusToolTip.qml diff --git a/statusq.qrc b/statusq.qrc index b59f4be9..11d955ea 100644 --- a/statusq.qrc +++ b/statusq.qrc @@ -335,5 +335,7 @@ src/assets/img/icons/OMG.png src/assets/img/icons/ETH.png src/assets/img/icons/MANA.png + src/StatusQ/Components/StatusListPicker.qml + src/StatusQ/Controls/StatusItemPicker.qml