diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 50d3cb61c5..9ebf264e0f 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -9,7 +9,7 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.1 import UM 1.2 as UM -import Cura 1.6 as Cura +import Cura 1.7 as Cura import DigitalFactory 1.0 as DF @@ -44,32 +44,12 @@ Item height: childrenRect.height spacing: UM.Theme.getSize("default_margin").width - Cura.TextField + Cura.SearchBar { id: searchBar Layout.fillWidth: true implicitHeight: createNewProjectButton.height - leftPadding: searchIcon.width + UM.Theme.getSize("default_margin").width * 2 - onTextEdited: manager.projectFilter = text //Update the search filter when editing this text field. - - placeholderText: "Search" - - UM.RecolorImage - { - id: searchIcon - - anchors - { - verticalCenter: parent.verticalCenter - left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width - } - source: UM.Theme.getIcon("search") - height: UM.Theme.getSize("small_button_icon").height - width: height - color: UM.Theme.getColor("text") - } } Cura.SecondaryButton diff --git a/plugins/Marketplace/RemotePackageList.py b/plugins/Marketplace/RemotePackageList.py index 8fa75453c1..e7df498fbf 100644 --- a/plugins/Marketplace/RemotePackageList.py +++ b/plugins/Marketplace/RemotePackageList.py @@ -32,7 +32,10 @@ class RemotePackageList(PackageList): self._scope = JsonDecoratorScope(UltimakerCloudScope(CuraApplication.getInstance())) self._package_type_filter = "" + self._requested_search_string = "" + self._current_search_string = "" self._request_url = self._initialRequestUrl() + self.isLoadingChanged.connect(self._onLoadingChanged) self.isLoadingChanged.emit() def __del__(self) -> None: @@ -69,6 +72,7 @@ class RemotePackageList(PackageList): self._request_url = self._initialRequestUrl() packageTypeFilterChanged = pyqtSignal() + searchStringChanged = pyqtSignal() def setPackageTypeFilter(self, new_filter: str) -> None: if new_filter != self._package_type_filter: @@ -76,6 +80,10 @@ class RemotePackageList(PackageList): self.reset() self.packageTypeFilterChanged.emit() + def setSearchString(self, new_search: str) -> None: + self._requested_search_string = new_search + self._onLoadingChanged() + @pyqtProperty(str, fset = setPackageTypeFilter, notify = packageTypeFilterChanged) def packageTypeFilter(self) -> str: """ @@ -84,14 +92,33 @@ class RemotePackageList(PackageList): """ return self._package_type_filter + @pyqtProperty(str, fset = setSearchString, notify = searchStringChanged) + def searchString(self) -> str: + """ + Get the string the user is currently searching for (as in: the list is updating) within the packages, + or an empty string if no extra search filter has to be applied. Does not override package-type filter! + :return: String the user is searching for. Empty denotes 'no search filter'. + """ + return self._current_search_string + + def _onLoadingChanged(self) -> None: + if self._requested_search_string != self._current_search_string and not self._is_loading: + self._current_search_string = self._requested_search_string + self.reset() + self.updatePackages() + self.searchStringChanged.emit() + def _initialRequestUrl(self) -> str: """ Get the URL to request the first paginated page with. :return: A URL to request. """ + request_url = f"{Marketplace.PACKAGES_URL}?limit={self.ITEMS_PER_PAGE}" if self._package_type_filter != "": - return f"{Marketplace.PACKAGES_URL}?package_type={self._package_type_filter}&limit={self.ITEMS_PER_PAGE}" - return f"{Marketplace.PACKAGES_URL}?limit={self.ITEMS_PER_PAGE}" + request_url += f"&package_type={self._package_type_filter}" + if self._current_search_string != "": + request_url += f"&search={self._current_search_string}" + return request_url def _parseResponse(self, reply: "QNetworkReply") -> None: """ diff --git a/plugins/Marketplace/resources/qml/ManagePackagesButton.qml b/plugins/Marketplace/resources/qml/ManagePackagesButton.qml index 31b97d89ed..bf122140a7 100644 --- a/plugins/Marketplace/resources/qml/ManagePackagesButton.qml +++ b/plugins/Marketplace/resources/qml/ManagePackagesButton.qml @@ -18,9 +18,7 @@ Button background: Rectangle { color: backgroundColor - border.color: transparent radius: Math.round(width * 0.5) - } Cura.ToolTip diff --git a/plugins/Marketplace/resources/qml/Marketplace.qml b/plugins/Marketplace/resources/qml/Marketplace.qml index 430c237252..ea60bf0c7e 100644 --- a/plugins/Marketplace/resources/qml/Marketplace.qml +++ b/plugins/Marketplace/resources/qml/Marketplace.qml @@ -14,6 +14,8 @@ Window id: marketplaceDialog property variant catalog: UM.I18nCatalog { name: "cura" } + signal searchStringChanged(string new_search) + minimumWidth: UM.Theme.getSize("modal_window_minimum").width minimumHeight: UM.Theme.getSize("modal_window_minimum").height width: minimumWidth @@ -70,46 +72,92 @@ Window } } + // Search & Top-Level Tabs Item { - Layout.preferredWidth: parent.width Layout.preferredHeight: childrenRect.height - - ManagePackagesButton + Layout.preferredWidth: parent.width - 2 * UM.Theme.getSize("thin_margin").width + RowLayout { - id: managePackagesButton + width: parent.width + height: UM.Theme.getSize("button_icon").height + UM.Theme.getSize("default_margin").height + spacing: UM.Theme.getSize("thin_margin").width - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - - onClicked: + Rectangle { - content.source = "ManagedPackages.qml" + Layout.preferredHeight: parent.height + Layout.preferredWidth: searchBar.visible ? UM.Theme.getSize("thin_margin").width : 0 + Layout.fillWidth: ! searchBar.visible } - } - // Page selection. - TabBar - { - id: pageSelectionTabBar - anchors.right: managePackagesButton.left - anchors.rightMargin: UM.Theme.getSize("default_margin").width - height: UM.Theme.getSize("button_icon").height - spacing: 0 - - PackageTypeTab + Cura.SearchBar { - width: implicitWidth - padding: UM.Theme.getSize("default_margin").width/2 - text: catalog.i18nc("@button", "Plugins") - onClicked: content.source = "Plugins.qml" + id: searchBar + Layout.preferredHeight: parent.height + Layout.fillWidth: true + onTextEdited: searchStringChanged(text) } - PackageTypeTab + + // Page selection. + TabBar { + id: pageSelectionTabBar + height: parent.height width: implicitWidth - padding: Math.round(UM.Theme.getSize("default_margin").width / 2) - text: catalog.i18nc("@button", "Materials") - onClicked: content.source = "Materials.qml" + spacing: 0 + + PackageTypeTab + { + id: pluginTabText + width: implicitWidth + padding: UM.Theme.getSize("thin_margin").width + text: catalog.i18nc("@button", "Plugins") + onClicked: + { + searchBar.text = "" + searchBar.visible = true + content.source = "Plugins.qml" + } + } + PackageTypeTab + { + id: materialsTabText + width: implicitWidth + padding: UM.Theme.getSize("thin_margin").width + text: catalog.i18nc("@button", "Materials") + onClicked: + { + searchBar.text = "" + searchBar.visible = true + content.source = "Materials.qml" + } + } + } + TextMetrics + { + id: pluginTabTextMetrics + text: pluginTabText.text + font: pluginTabText.font + } + TextMetrics + { + id: materialsTabTextMetrics + text: materialsTabText.text + font: materialsTabText.font + } + + ManagePackagesButton + { + id: managePackagesButton + height: parent.height + width: UM.Theme.getSize("button_icon").width + + onClicked: + { + searchBar.text = "" + searchBar.visible = false + content.source = "ManagedPackages.qml" + } } } } @@ -135,6 +183,11 @@ Window function onLoaded() { pageTitle.text = content.item.pageTitle + searchStringChanged.connect(handleSearchStringChanged) + } + function handleSearchStringChanged(new_search) + { + content.item.model.searchString = new_search } } } diff --git a/resources/qml/SearchBar.qml b/resources/qml/SearchBar.qml new file mode 100644 index 0000000000..4d9c003653 --- /dev/null +++ b/resources/qml/SearchBar.qml @@ -0,0 +1,35 @@ +// Copyright (C) 2021 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.1 + +import UM 1.6 as UM +import Cura 1.7 as Cura + +Cura.TextField +{ + UM.I18nCatalog { id: catalog; name: "cura" } + + leftPadding: searchIcon.width + UM.Theme.getSize("default_margin").width * 2 + + placeholderText: catalog.i18nc("@placeholder", "Search") + font.italic: true + + UM.RecolorImage + { + id: searchIcon + + anchors + { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + } + source: UM.Theme.getIcon("Magnifier") + height: UM.Theme.getSize("small_button_icon").height + width: height + color: UM.Theme.getColor("text") + } +} diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 074946c6bd..5fc0b60381 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -41,39 +41,19 @@ Item repeat: false } - Cura.TextField + Cura.SearchBar { id: filter height: parent.height anchors.left: parent.left anchors.right: parent.right - leftPadding: searchIcon.width + UM.Theme.getSize("default_margin").width * 2 - placeholderText: catalog.i18nc("@label:textbox", "Search settings") - font.italic: true + + placeholderText: catalog.i18nc("@label:textbox", "Search settings") // Overwrite property var expandedCategories property bool lastFindingSettings: false - UM.RecolorImage - { - id: searchIcon - - anchors - { - verticalCenter: parent.verticalCenter - left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width - } - source: UM.Theme.getIcon("search") - height: UM.Theme.getSize("small_button_icon").height - width: height - color: UM.Theme.getColor("text") - } - - onTextChanged: - { - settingsSearchTimer.restart() - } + onTextChanged: settingsSearchTimer.restart() onEditingFinished: { @@ -86,10 +66,7 @@ Item } } - Keys.onEscapePressed: - { - filter.text = "" - } + Keys.onEscapePressed: filter.text = "" function updateDefinitionModel() {