import QtCore import QtQuick import QtQuick.Controls import QtQuick.Dialogs import QtQuick.Layouts import QtMultimedia import QtWebView import org.kde.kirigami as Kirigami import com.github.digitalartifex.komplex as Komplex Item { id: mainItem //anchors.fill: parent signal accepted Komplex.ShaderToySearchModel { id: searchModel } ColumnLayout { width: mainItem.width height: mainItem.height RowLayout { Layout.fillHeight: false Layout.fillWidth: true Layout.margins: 6 TextField { Layout.preferredHeight: 32 Layout.fillWidth: true id: searchField placeholderText: "Search" onEditingFinished: mainItem.updateSearch() Keys.onPressed: (event) => { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { searchField.focus = false; // Unfocus the TextField event.accepted = true; // Prevent further propagation of the key event } } } Button { Layout.preferredHeight: 32 Layout.preferredWidth: 32 icon.name: "search-symbolic" onClicked: mainItem.updateSearch() } } Component { id: highlight Rectangle { width: view.cellWidth; height: view.cellHeight color: palette.highlight; radius: 5 x: view.currentItem.x y: view.currentItem.y Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } } Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } } } } Rectangle { Layout.fillHeight: true Layout.fillWidth: true color: palette.base clip: true RowLayout { anchors.fill: parent GridView { // The standard size property int idealCellHeight: 200 property int idealCellWidth: 250 cellWidth: width / Math.floor(width / idealCellWidth) cellHeight: idealCellHeight id: view model: searchModel highlight: highlight highlightFollowsCurrentItem: false Layout.fillHeight: true Layout.fillWidth: true Layout.margins: 6 delegate: Column { property int itemIndex: index property string shaderThumbnail: thumbnail property string shaderEmbed: embedUrl property string shaderId: id property string author: username property string shaderDescription: model.description id: entry leftPadding: Math.floor((width - thumbnailImage.width) / 2) topPadding: 10 rightPadding: Math.floor((width - thumbnailImage.width) / 2) bottomPadding: 10 width: view.cellWidth Image { width: 250 height: 140 id: thumbnailImage source: thumbnail anchors.horizontalCenter: parent.horizontalCenter Rectangle { color: palette.base anchors.fill: parent visible: thumbnailImage.status === Image.Loading RowLayout { anchors.fill: parent BusyIndicator { Layout.alignment: Qt.AlignCenter Layout.preferredHeight: 64 Layout.preferredWidth: 64 visible: running } } } Rectangle { color: palette.dark anchors.fill: parent visible: thumbnailImage.status === Image.Error Text { color: palette.text anchors.centerIn: parent text: qsTr("Error Loading Image") } } MouseArea { anchors.fill: parent onClicked: (mouse) => { view.currentIndex = parent.parent.itemIndex //searchModel.currentIndex = view.currentIndex } } } RowLayout { visible: parent.itemIndex === view.currentIndex width: thumbnailImage.width Button { Layout.topMargin: 4 Layout.alignment: Qt.AlignRight Layout.preferredHeight: 32 Layout.fillWidth: true icon.source: "./icons/download.svg" icon.name: "download-symbolic" text: qsTr("Preview & Download") onClicked: () => { downloadDialog.open() } } } Dialog { id: downloadDialog modal: Qt.WindowModal width: 600 height: 440 parent: mainItem anchors.centerIn: mainItem clip: true ColumnLayout { anchors.fill: parent WebView { Layout.fillHeight: true Layout.fillWidth: true id: shaderPreview Layout.preferredWidth: 500 Layout.preferredHeight: 281 Layout.alignment: Qt.AlignHCenter url: "" } Text { Layout.preferredHeight: 64 Layout.fillHeight: true Layout.fillWidth: true id: shaderDescription text: model.description elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere maximumLineCount: 3 color: palette.text } Button { Layout.fillWidth: true icon.source: "./icons/download.svg" icon.name: "download-symbolic" id: downloadButton text: qsTr("Convert to Komplex Pack") onClicked: () => { workingThumbnail.source = model.thumbnail searchModel.convert(model.index); downloadDialog.close(); } } } onClosed: () => { shaderPreview.loadHtml(``) } onOpened: () => { shaderDescription.text = model.description shaderPreview.loadHtml(`