pragma ComponentBehavior: Bound import QtQuick import QtQuick.Templates as QQCT import Weave.Controls import Weave.Templates as T import "internal" T.Search { id: root implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding) implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding) categorySelectorPopupWidthMode: root.categorySelectorStyle === T.Search.Text ? T.Search.FixedWidth : T.Search.ImplicitWidth hoverEnabled: root.enabled contentItem: TableLayoutRow { verticalItemFillMode: TableLayout.Preferred // TODO: if root.categorySelectorStyle === Icon then it's an IconButton with a dropdown. // Otherwise, use a "normal" dropdown. I guess? TableLayoutLoader { id: categoriesDropdown active: root.categories != null sourceComponent: Component { Dropdown { id: dropdown TableLayout.leftPadding: root.mirrored || root.style === Search.Box ? Theme.component.input.box.paddingLeft : Theme.component.input.line.paddingLeft TableLayout.rightPadding: !root.mirrored || root.style === Search.Box ? Theme.component.input.box.paddingRight : Theme.component.input.line.paddingRight model: root.categories displayCheckmarks: false editable: false textRole: "text" style: root.style displayStyle: root.categorySelectorStyle === T.Search.Text ? T.Dropdown.TextOnly : T.Dropdown.IconOnly popupWidthMode: root.categorySelectorPopupWidthMode === T.Search.ImplicitWidth ? T.Dropdown.ImplicitWidth : T.Dropdown.FixedWidth onCurrentIndexChanged: root.selectedCategory = currentIndex Component.onCompleted: if (root.selectedCategory >= 0) currentIndex = root.selectedCategory background: TextInputBackground { style: root.style focused: dropdown.activeFocus hovered: dropdown.hovered color: dropdown._styleAttributes.backgroundColor rightBorderWidth: 0 } } } } TextField { id: searchEntryField TableLayout.horizontalFillMode: TableLayout.Preferred TableLayout.leftPadding: (!root.mirrored && categoriesDropdown.active) || root.style === Search.Box ? Theme.component.input.box.paddingLeft : Theme.component.input.line.paddingLeft TableLayout.rightPadding: (root.mirrored && categoriesDropdown.active) || root.style === Search.Box ? Theme.component.input.box.paddingRight : Theme.component.input.line.paddingRight text: root.text placeholderText: root.placeholderText decoration: root.searchMode === T.Search.Manual ? null : searchIcon style: root.style onTextChanged: { if (root.searchMode !== T.Search.Manual) { if (text.length > 0) { root.search(text) } else { root.stopSearch() } } } Component { id: searchIcon T.IconImage { icon: manualSearchButton.icon sourceSize: manualSearchButton.icon.size } } background: TextInputBackground { id: backgroundRect style: root.style focused: searchEntryField.activeFocus hovered: searchEntryField.hovered haloEnabled: root.progressIndicatorStyle === T.Search.NoProgressIndicator || !root.searching color: searchEntryField._styleAttributes.backgroundColor leftBorderWidth: categoriesDropdown.status === TableLayout.Ready ? Theme.component.input.box.borderWidth : borderWidth ProgressBar { id: searchProgressBar y: backgroundRect.height width: backgroundRect.width visible: root.progressIndicatorStyle !== T.Search.NoProgressIndicator && root.searching indeterminate: root.progressIndicatorStyle === T.Search.Indeterminate property real searchProgress: root.searchProgress onSearchProgressChanged: if (!indeterminate) value = searchProgress } } buttons: [ ActionIconButton { id: closeButton TableLayout.leftMargin: Theme.component.input.error.iconContainer.marginLeft TableLayout.rightMargin: Theme.component.input.error.iconContainer.marginRight TableLayout.topMargin: Theme.component.input.error.iconContainer.marginTop TableLayout.bottomMargin: Theme.component.input.error.iconContainer.marginBottom enabled: searchEntryField.text.length opacity: searchEntryField.text.length ? 1 : 0 icon.name: Theme.icon.small("close") onClicked: { searchEntryField.clear() root.text = "" root.stopSearch() } }, TableLayoutLoader { id: internalOptionsButton active: root.options != null && (root.optionsButtonStyle === T.Search.Internal || root.searchMode === T.Search.Manual) TableLayout.topMargin: Theme.component.input.box.borderWidth TableLayout.bottomMargin: Theme.component.input.box.borderWidth TableLayout.verticalFillMode: TableLayout.Preferred sourceComponent: TableLayoutRow { verticalItemFillMode: TableLayout.Preferred leftMargin: Theme.component.input.error.iconContainer.marginLeft rightMargin: root.style === T.Search.Line ? Theme.component.input.error.iconContainer.marginLeft : 0 ActionIconButton { id: optionsButton icon.name: Theme.icon.small("more") popupIndicatorVisible: false popup: DropdownPopup { id: dropdownPopup control: optionsButton model: root.options currentIndex: root.selectedOption fixedWidth: false // use implicit width closePolicy: QQCT.Popup.CloseOnEscape | QQCT.Popup.CloseOnPressOutsideParent // avoid causing togglePopup() to reopen it. header: MenuSeparator { text: root.optionsTitle dividerVisible: false } delegate: DropdownDelegate { required property int index required text checked: root.selectedOption === index onClicked: { root.selectedOption = index dropdownPopup.close() } } } } } } ] } Button { id: manualSearchButton TableLayout.leftMargin: root.style === T.Search.Line ? Theme.component.input.error.iconContainer.marginLeft : 0 visible: root.searchMode === T.Search.Manual icon.name: "search" style: root.searchButtonStyle === T.Search.Outline ? Button.Outline : root.searchButtonStyle === T.Search.Flat ? Button.Flat : Button.Solid background: AsymmetricRoundedBackground { implicitHeight: manualSearchButton.height implicitWidth: manualSearchButton.height backgroundStyle: root.searchButtonStyle === T.Search.Solid ? AsymmetricRoundedBackground.BackgroundStyle.SolidButtonStyle : AsymmetricRoundedBackground.BackgroundStyle.OutlineButtonStyle roundedEdge: root.style === T.Search.Box ? AsymmetricRoundedBackground.RoundedEdge.Right : AsymmetricRoundedBackground.RoundedEdge.Both leftBorderVisible: roundedEdge !== AsymmetricRoundedBackground.RoundedEdge.Both } onClicked: { if (searchEntryField.text.length > 0) { root.search(searchEntryField.text) } } } TableLayoutLoader { id: externalOptionsButton leftMargin: root.style === T.Search.Line ? Theme.component.input.error.iconContainer.marginLeft : 0 active: root.options != null && root.optionsButtonStyle === T.Search.External && root.searchMode !== T.Search.Manual sourceComponent: IconButton { id: extOptionsButton icon.name: Theme.icon.small("more") icon.width: 0 icon.height: 0 popupIndicatorVisible: false popup: DropdownPopup { id: dropdownPopup control: extOptionsButton model: root.options currentIndex: root.selectedOption fixedWidth: false // use implicit width closePolicy: QQCT.Popup.CloseOnEscape | QQCT.Popup.CloseOnPressOutsideParent // avoid causing togglePopup() to reopen it. header: MenuSeparator { text: root.optionsTitle dividerVisible: false } delegate: DropdownDelegate { required property int index required text checked: root.selectedOption === index onClicked: { root.selectedOption = index dropdownPopup.close() } } } } } } background: Item { } }