forked from Shinonome/dots-hyprland
waffles: functioning search
This commit is contained in:
@@ -19,11 +19,14 @@ QtObject {
|
||||
}
|
||||
property var actions: []
|
||||
|
||||
// Stuff needed for DesktopEntry objects
|
||||
// Stuff needed for DesktopEntry
|
||||
property string id: ""
|
||||
property bool shown: true
|
||||
property string comment: ""
|
||||
property bool runInTerminal: false
|
||||
property string genericName: ""
|
||||
property list<string> keywords: []
|
||||
|
||||
// Extra stuff to allow for more flexibility
|
||||
property string category: type
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
topPadding: Appearance.rounding.normal
|
||||
bottomPadding: Appearance.rounding.normal
|
||||
active: hovered || pressed
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: 4
|
||||
|
||||
@@ -152,6 +152,7 @@ Singleton {
|
||||
property real normal: 11
|
||||
property real large: 13
|
||||
property real larger: 15
|
||||
property real xlarger: 17
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ Singleton {
|
||||
}
|
||||
|
||||
property string batteryLevelIcon: {
|
||||
const discreteLevel = Math.ceil(Battery.percentage * 10)
|
||||
const discreteLevel = Math.ceil(Battery.percentage * 10);
|
||||
return `battery-${discreteLevel > 9 ? "full" : discreteLevel}`;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,8 @@ Singleton {
|
||||
function audioAppIcon(node) {
|
||||
let icon;
|
||||
icon = AppSearch.guessIcon(node?.properties["application.icon-name"] ?? "");
|
||||
if (AppSearch.iconExists(icon)) return icon;
|
||||
if (AppSearch.iconExists(icon))
|
||||
return icon;
|
||||
icon = AppSearch.guessIcon(node?.properties["node.name"] ?? "");
|
||||
return icon;
|
||||
}
|
||||
@@ -127,4 +128,60 @@ Singleton {
|
||||
return "bluetooth";
|
||||
}
|
||||
|
||||
function fluentFromMaterial(icon) {
|
||||
switch (icon) {
|
||||
case "calculate":
|
||||
return "calculator";
|
||||
case "keyboard_return":
|
||||
return "arrow-enter-left";
|
||||
case "open_in_new":
|
||||
return "open";
|
||||
case "settings_suggest":
|
||||
return "wand";
|
||||
case "terminal":
|
||||
return "app-generic";
|
||||
case "travel_explore":
|
||||
return "globe-search";
|
||||
case "keep":
|
||||
return "pin";
|
||||
case "keep_off":
|
||||
return "pin-off";
|
||||
default:
|
||||
return "apps";
|
||||
}
|
||||
}
|
||||
|
||||
function guessIconForName(name) {
|
||||
const lowerName = name.toLowerCase();
|
||||
if (lowerName.includes("app") || lowerName.includes("desktop"))
|
||||
return "apps";
|
||||
if (lowerName.includes("news"))
|
||||
return "news";
|
||||
if (lowerName.includes("new") || lowerName.includes("create") || lowerName.includes("add"))
|
||||
return "add";
|
||||
if (lowerName.includes("open"))
|
||||
return "open";
|
||||
if (lowerName.includes("friends") || lowerName.includes("contact") || lowerName.includes("family"))
|
||||
return "people";
|
||||
if (lowerName.includes("community"))
|
||||
return "people-team";
|
||||
if (lowerName.includes("library"))
|
||||
return "library";
|
||||
if (lowerName.includes("setting"))
|
||||
return "settings";
|
||||
if (lowerName.includes("gallery"))
|
||||
return "image-copy";
|
||||
if (lowerName.includes("server"))
|
||||
return "server";
|
||||
if (lowerName.includes("picture") || lowerName.includes("photo") || lowerName.includes("image"))
|
||||
return "image";
|
||||
if (lowerName.includes("store") || lowerName.includes("shop"))
|
||||
return "store-microsoft";
|
||||
if (lowerName.includes("record") || lowerName.includes("capture"))
|
||||
return "record";
|
||||
if (lowerName.includes("screen") || lowerName.includes("display") || lowerName.includes("monitor") || lowerName.includes("desktop"))
|
||||
return "desktop";
|
||||
|
||||
return "apps";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
ScrollBar.vertical: WScrollBar {}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
|
||||
ScrollBar {
|
||||
id: root
|
||||
|
||||
policy: ScrollBar.AsNeeded
|
||||
active: hovered || pressed
|
||||
property color color: Looks.colors.controlBg
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: root.active ? 4 : 2
|
||||
implicitHeight: root.visualSize
|
||||
radius: 9999
|
||||
color: root.color
|
||||
|
||||
opacity: root.policy === ScrollBar.AlwaysOn || (root.active && root.size < 1.0) ? 0.5 : 0
|
||||
Behavior on opacity {
|
||||
animation: Looks.transition.opacity.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,16 @@ FooterRectangle {
|
||||
property real horizontalPadding: 32
|
||||
property real verticalPadding: 16
|
||||
property bool searching: text.length > 0
|
||||
property alias searchInput: searchInput
|
||||
property alias text: searchInput.text
|
||||
implicitHeight: outline.implicitHeight + verticalPadding * 2
|
||||
|
||||
Component.onCompleted: searchInput.forceActiveFocus()
|
||||
signal accepted()
|
||||
|
||||
Component.onCompleted: forceFocus()
|
||||
function forceFocus() {
|
||||
searchInput.forceActiveFocus();
|
||||
}
|
||||
|
||||
focus: true
|
||||
color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter
|
||||
@@ -81,6 +87,10 @@ FooterRectangle {
|
||||
visible: searchInput.text.length === 0
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
root.accepted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.models
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property LauncherSearchResult entry
|
||||
property int iconSize: 24
|
||||
implicitWidth: Math.max(iconSize, textIconLoader.implicitWidth)
|
||||
implicitHeight: iconSize
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: root.entry.iconType === LauncherSearchResult.IconType.System && root.entry.iconName !== ""
|
||||
sourceComponent: WAppIcon {
|
||||
implicitSize: root.iconSize
|
||||
iconName: root.entry.iconName
|
||||
tryCustomIcon: false
|
||||
animated: false
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: textIconLoader
|
||||
anchors.centerIn: parent
|
||||
active: root.entry.iconType === LauncherSearchResult.IconType.Text
|
||||
sourceComponent: WText {
|
||||
text: root.entry.iconName
|
||||
font.pixelSize: root.iconSize
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: root.entry.iconType === LauncherSearchResult.IconType.Material || root.entry.iconType === LauncherSearchResult.IconType.None || root.entry.iconName === ""
|
||||
sourceComponent: FluentIcon {
|
||||
icon: root.entry.iconName ? WIcons.fluentFromMaterial(root.entry.iconName) : WIcons.guessIconForName(root.entry.name)
|
||||
implicitSize: root.iconSize
|
||||
animated: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,9 @@ import qs.modules.waffle.looks
|
||||
BodyRectangle {
|
||||
id: root
|
||||
|
||||
property alias context: searchResults.context
|
||||
property string searchText: LauncherSearch.query
|
||||
property alias currentIndex: searchResults.currentIndex
|
||||
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
@@ -24,11 +26,13 @@ BodyRectangle {
|
||||
spacing: 12
|
||||
|
||||
TagStrip {
|
||||
context: root.context
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: false
|
||||
}
|
||||
|
||||
SearchResults {
|
||||
id: searchResults
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
@@ -1,19 +1,44 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.waffle.looks
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common
|
||||
import qs.services
|
||||
import qs
|
||||
import qs.modules.common.models
|
||||
import Quickshell
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import QtQuick
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
|
||||
property int maxResultsPerCategory: 4
|
||||
property StartMenuContext context
|
||||
property int currentIndex: context.currentIndex
|
||||
onCurrentIndexChanged: {
|
||||
forceCurrentIndex(currentIndex);
|
||||
}
|
||||
function focusFirstItem() {
|
||||
resultList.currentIndex = 0;
|
||||
forceCurrentIndex(0);
|
||||
}
|
||||
function forceCurrentIndex(index) {
|
||||
context.currentIndex = index;
|
||||
// Somehow this hack is needed
|
||||
if (index === 0) {
|
||||
resultList.incrementCurrentIndex();
|
||||
resultList.decrementCurrentIndex();
|
||||
} else {
|
||||
resultList.decrementCurrentIndex();
|
||||
resultList.incrementCurrentIndex();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: context
|
||||
function onAccepted() {
|
||||
resultList.currentItem?.execute();
|
||||
}
|
||||
}
|
||||
|
||||
ResultList {
|
||||
@@ -25,23 +50,74 @@ RowLayout {
|
||||
Layout.preferredWidth: 386
|
||||
Layout.leftMargin: 1
|
||||
Layout.rightMargin: 1
|
||||
entry: resultList.model[resultList.currentIndex] ?? searchResultComp.createObject()
|
||||
}
|
||||
|
||||
component ResultList: ListView {
|
||||
component ResultList: WListView {
|
||||
id: resultListView
|
||||
section {
|
||||
criteria: ViewSection.FullString
|
||||
property: "type"
|
||||
property: "category" // This is "type" with tweaks to make it match more closely
|
||||
labelPositioning: ViewSection.InlineLabels
|
||||
delegate: Item {
|
||||
id: sectionButton
|
||||
required property string section
|
||||
implicitHeight: sectionChoiceButton.implicitHeight + resultListView.spacing
|
||||
width: ListView.view?.width
|
||||
WChoiceButton {
|
||||
id: sectionChoiceButton
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
}
|
||||
implicitHeight: 38
|
||||
contentItem: WText {
|
||||
text: sectionButton.section
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
font.weight: Looks.font.weight.strong
|
||||
}
|
||||
onClicked: {
|
||||
root.context.selectCategory(sectionButton.section);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clip: true
|
||||
spacing: 4
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
// TODO: categorize and have max per category
|
||||
LauncherSearch.results.slice(0, 10)
|
||||
}
|
||||
onValuesChanged: {
|
||||
root.focusFirstItem();
|
||||
currentIndex: root.currentIndex
|
||||
|
||||
// We can't use a ScriptModel here because it would mess up sections
|
||||
model: {
|
||||
const allResults = LauncherSearch.results;
|
||||
// Find categories
|
||||
var categories = new Set();
|
||||
for (let i = 0; i < allResults.length; i++) {
|
||||
categories.add(allResults[i].type);
|
||||
}
|
||||
|
||||
// Collect max 4 per category
|
||||
var categorizedResults = [];
|
||||
categories.forEach(category => {
|
||||
let count = 0;
|
||||
for (let i = 0; i < allResults.length; i++) {
|
||||
if (allResults[i].type === category) {
|
||||
const entry = allResults[i];
|
||||
const tweakedEntry = searchResultComp.createObject(null, Object.assign({}, entry));
|
||||
tweakedEntry.category = categorizedResults.length === 0 ? Translation.tr("Best match") : entry.type
|
||||
categorizedResults.push(tweakedEntry); // Section header
|
||||
count++;
|
||||
if (count >= root.maxResultsPerCategory) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// print(JSON.stringify(categorizedResults, null, 2));
|
||||
return categorizedResults;
|
||||
}
|
||||
onModelChanged: {
|
||||
root.focusFirstItem();
|
||||
}
|
||||
delegate: WSearchResultButton {
|
||||
required property int index
|
||||
@@ -53,8 +129,112 @@ RowLayout {
|
||||
}
|
||||
|
||||
component ResultPreview: Rectangle {
|
||||
id: resultPreview
|
||||
|
||||
property LauncherSearchResult entry // LauncherSearchResult
|
||||
|
||||
Layout.fillHeight: true
|
||||
color: Looks.colors.bg1
|
||||
radius: Looks.radius.large
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 22
|
||||
spacing: 13
|
||||
|
||||
ColumnLayout {
|
||||
id: mainInfoColumn
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
SearchEntryIcon {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 10
|
||||
Layout.bottomMargin: 12
|
||||
entry: resultPreview.entry
|
||||
iconSize: 64
|
||||
}
|
||||
WText {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
text: resultPreview.entry?.name || ""
|
||||
font.pixelSize: Looks.font.pixelSize.xlarger
|
||||
}
|
||||
WText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: resultPreview.entry?.type || ""
|
||||
color: Looks.colors.accentUnfocused
|
||||
font.pixelSize: Looks.font.pixelSize.normal
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: resultSeparator
|
||||
implicitHeight: 2
|
||||
Layout.topMargin: 16
|
||||
Layout.fillWidth: true
|
||||
color: Looks.colors.bg2Hover
|
||||
}
|
||||
WListView {
|
||||
id: actionsColumn
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
spacing: 2
|
||||
model: {
|
||||
const isAppEntry = resultPreview.entry.type === Translation.tr("App");
|
||||
const appId = isAppEntry ? resultPreview.entry.id : "";
|
||||
const pinned = isAppEntry ? (Config.options.dock.pinnedApps.includes(appId)) : false;
|
||||
var result = [
|
||||
searchResultComp.createObject(null, {
|
||||
name: resultPreview.entry.verb,
|
||||
iconName: isAppEntry ? "open_in_new" : "keyboard_return",
|
||||
iconType: LauncherSearchResult.IconType.Material,
|
||||
execute: () => {
|
||||
resultPreview.entry.execute();
|
||||
}
|
||||
}),
|
||||
...(isAppEntry ? [
|
||||
searchResultComp.createObject(null, {
|
||||
name: pinned ? Translation.tr("Unpin from taskbar") : Translation.tr("Pin to taskbar"),
|
||||
iconName: pinned ? "keep_off" : "keep",
|
||||
iconType: LauncherSearchResult.IconType.Material,
|
||||
execute: () => {
|
||||
TaskbarApps.togglePin(appId);
|
||||
}
|
||||
})
|
||||
] : [])
|
||||
];
|
||||
result = result.concat(resultPreview.entry.actions);
|
||||
return result;
|
||||
}
|
||||
delegate: WButton {
|
||||
id: actionButton
|
||||
required property var modelData
|
||||
width: ListView.view?.width
|
||||
icon.name: modelData.iconName
|
||||
text: modelData.name
|
||||
onClicked: modelData.execute();
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: 11
|
||||
SearchEntryIcon {
|
||||
entry: actionButton.modelData
|
||||
iconSize: 16
|
||||
}
|
||||
WText {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
text: actionButton.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: searchResultComp
|
||||
LauncherSearchResult {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,72 @@ WBarAttachedPanelContent {
|
||||
property bool searching: false
|
||||
property string searchText: LauncherSearch.query
|
||||
|
||||
StartMenuContext {
|
||||
id: context
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
// Prevent Esc and Backspace from registering
|
||||
if (event.key === Qt.Key_Escape)
|
||||
return;
|
||||
|
||||
// Handle Backspace: focus and delete character if not focused
|
||||
if (event.key === Qt.Key_Backspace) {
|
||||
searchBar.forceFocus();
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
// Delete word before cursor
|
||||
let text = searchBar.text;
|
||||
let pos = searchBar.searchInput.cursorPosition;
|
||||
if (pos > 0) {
|
||||
// Find the start of the previous word
|
||||
let left = text.slice(0, pos);
|
||||
let match = left.match(/(\s*\S+)\s*$/);
|
||||
let deleteLen = match ? match[0].length : 1;
|
||||
searchBar.text = text.slice(0, pos - deleteLen) + text.slice(pos);
|
||||
searchBar.searchInput.cursorPosition = pos - deleteLen;
|
||||
}
|
||||
} else {
|
||||
// Delete character before cursor if any
|
||||
if (searchBar.searchInput.cursorPosition > 0) {
|
||||
searchBar.text = searchBar.text.slice(0, searchBar.searchInput.cursorPosition - 1) + searchBar.text.slice(searchBar.searchInput.cursorPosition);
|
||||
searchBar.searchInput.cursorPosition -= 1;
|
||||
}
|
||||
}
|
||||
// Always move cursor to end after programmatic edit
|
||||
searchBar.searchInput.cursorPosition = searchBar.text.length;
|
||||
event.accepted = true;
|
||||
// If already focused, let TextField handle it
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle visible printable characters (ignore control chars, arrows, etc.)
|
||||
if (event.text && event.text.length === 1 && event.key !== Qt.Key_Enter && event.key !== Qt.Key_Return && event.key !== Qt.Key_Delete && event.text.charCodeAt(0) >= 0x20) // ignore control chars like Backspace, Tab, etc.
|
||||
{
|
||||
if (!searchBar.searchInput.activeFocus) {
|
||||
searchBar.forceFocus();
|
||||
// Insert the character at the cursor position
|
||||
searchBar.text = searchBar.text.slice(0, searchBar.searchInput.cursorPosition) + event.text + searchBar.text.slice(searchBar.searchInput.cursorPosition);
|
||||
searchBar.searchInput.cursorPosition += 1;
|
||||
event.accepted = true;
|
||||
context.setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Arrow keys for item navigation
|
||||
if (event.key === Qt.Key_Down) {
|
||||
let maxIndex = Math.max(0, LauncherSearch.results.length - 1);
|
||||
context.setCurrentIndex(Math.min(context.currentIndex + 1, maxIndex));
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
context.setCurrentIndex(Math.max(context.currentIndex - 1, 0));
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: WPane {
|
||||
contentItem: WPanelPageColumn {
|
||||
SearchBar {
|
||||
focus: true
|
||||
id: searchBar
|
||||
Layout.fillWidth: true
|
||||
implicitWidth: 832 // TODO: Make sizes naturally inferred
|
||||
horizontalPadding: root.searching ? 24 : 32
|
||||
@@ -27,10 +89,14 @@ WBarAttachedPanelContent {
|
||||
Synchronizer on searching {
|
||||
property alias target: root.searching
|
||||
}
|
||||
focus: true
|
||||
text: root.searchText
|
||||
onTextChanged: {
|
||||
LauncherSearch.query = text;
|
||||
}
|
||||
onAccepted: {
|
||||
context.accepted();
|
||||
}
|
||||
}
|
||||
Item {
|
||||
implicitHeight: root.searching ? 736 : 736 // TODO: Make sizes naturally inferred
|
||||
@@ -46,7 +112,9 @@ WBarAttachedPanelContent {
|
||||
|
||||
Component {
|
||||
id: searchPageComp
|
||||
SearchPageContent {}
|
||||
SearchPageContent {
|
||||
context: context
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs
|
||||
import qs.modules.common
|
||||
import qs.services
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
signal accepted
|
||||
|
||||
property int currentIndex: 0
|
||||
function setCurrentIndex(index) {
|
||||
if (index == currentIndex)
|
||||
return;
|
||||
currentIndex = index;
|
||||
}
|
||||
|
||||
function selectCategory(category) {
|
||||
for (let i = 0; i < root.categories.length; i++) {
|
||||
const thisCategoryName = root.categories[i].name;
|
||||
if (thisCategoryName.startsWith(category) || category.startsWith(thisCategoryName)) {
|
||||
LauncherSearch.ensurePrefix(root.categories[i].prefix);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
property list<var> categories: [
|
||||
{
|
||||
name: Translation.tr("All"),
|
||||
prefix: ""
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Apps"),
|
||||
prefix: Config.options.search.prefix.app
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Actions"),
|
||||
prefix: Config.options.search.prefix.action
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Clipboard"),
|
||||
prefix: Config.options.search.prefix.clipboard
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Emojis"),
|
||||
prefix: Config.options.search.prefix.emojis
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Math"),
|
||||
prefix: Config.options.search.prefix.math
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Commands"),
|
||||
prefix: Config.options.search.prefix.shellCommand
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Web"),
|
||||
prefix: Config.options.search.prefix.webSearch
|
||||
},
|
||||
]
|
||||
|
||||
}
|
||||
@@ -10,6 +10,9 @@ import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
property StartMenuContext context
|
||||
|
||||
WPanelIconButton {
|
||||
implicitWidth: 36
|
||||
implicitHeight: 36
|
||||
@@ -23,40 +26,7 @@ RowLayout {
|
||||
Layout.fillHeight: true
|
||||
orientation: Qt.Horizontal
|
||||
spacing: 4
|
||||
model: [
|
||||
{
|
||||
name: Translation.tr("All"),
|
||||
prefix: ""
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Apps"),
|
||||
prefix: Config.options.search.prefix.app
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Actions"),
|
||||
prefix: Config.options.search.prefix.action
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Clipboard"),
|
||||
prefix: Config.options.search.prefix.clipboard
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Emojis"),
|
||||
prefix: Config.options.search.prefix.emojis
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Math"),
|
||||
prefix: Config.options.search.prefix.math
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Commands"),
|
||||
prefix: Config.options.search.prefix.shellCommand
|
||||
},
|
||||
{
|
||||
name: Translation.tr("Web"),
|
||||
prefix: Config.options.search.prefix.webSearch
|
||||
},
|
||||
]
|
||||
model: root.context.categories
|
||||
delegate: WBorderedButton {
|
||||
id: tagButton
|
||||
required property var modelData
|
||||
|
||||
@@ -11,7 +11,7 @@ import qs.modules.waffle.looks
|
||||
|
||||
WChoiceButton {
|
||||
id: root
|
||||
|
||||
|
||||
required property LauncherSearchResult entry
|
||||
property bool firstEntry: false
|
||||
|
||||
@@ -21,45 +21,28 @@ WChoiceButton {
|
||||
implicitHeight: contentLayout.implicitHeight + topPadding + bottomPadding
|
||||
|
||||
onClicked: {
|
||||
GlobalStates.searchOpen = false
|
||||
root.entry.execute()
|
||||
execute();
|
||||
}
|
||||
|
||||
|
||||
function execute() {
|
||||
GlobalStates.searchOpen = false;
|
||||
root.entry.execute();
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
id: contentLayout
|
||||
spacing: 8
|
||||
|
||||
EntryIcon {}
|
||||
|
||||
SearchEntryIcon {
|
||||
entry: root.entry
|
||||
iconSize: 24
|
||||
}
|
||||
EntryNameColumn {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
component EntryIcon: Item {
|
||||
implicitWidth: 24
|
||||
implicitHeight: 24
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: root.entry.iconType === LauncherSearchResult.IconType.System
|
||||
sourceComponent: WAppIcon {
|
||||
implicitSize: 24
|
||||
tryCustomIcon: false
|
||||
iconName: root.entry.iconName
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: root.entry.iconType === LauncherSearchResult.IconType.Text
|
||||
sourceComponent: WText {
|
||||
text: root.entry.iconName
|
||||
font.pixelSize: 24
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component EntryNameColumn: ColumnLayout {
|
||||
spacing: 4
|
||||
|
||||
@@ -78,4 +61,11 @@ WChoiceButton {
|
||||
color: Looks.colors.accentUnfocused
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
// hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@ Scope {
|
||||
target: GlobalStates
|
||||
|
||||
function onSearchOpenChanged() {
|
||||
if (GlobalStates.searchOpen)
|
||||
if (GlobalStates.searchOpen) {
|
||||
LauncherSearch.query = "";
|
||||
panelLoader.active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +64,7 @@ Scope {
|
||||
onClosed: {
|
||||
GlobalStates.searchOpen = false;
|
||||
panelLoader.active = false;
|
||||
LauncherSearch.query = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user