forked from Shinonome/alt-illogical-impulse
fix: add wayland dev headers and scanner for pywayland build on NixOS
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
// pragma NativeMethodBehavior: AcceptThisObject
|
||||
import qs
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Hyprland
|
||||
|
||||
RippleButton {
|
||||
id: root
|
||||
property var entry
|
||||
property string query
|
||||
property bool entryShown: entry?.shown ?? true
|
||||
property string itemType: entry?.type ?? Translation.tr("App")
|
||||
property string itemName: entry?.name
|
||||
property string itemIcon: entry?.icon ?? ""
|
||||
property var itemExecute: entry?.execute
|
||||
property string fontType: entry?.fontType ?? "main"
|
||||
property string itemClickActionName: entry?.clickActionName
|
||||
property string bigText: entry?.bigText ?? ""
|
||||
property string materialSymbol: entry?.materialSymbol ?? ""
|
||||
property string cliphistRawString: entry?.cliphistRawString ?? ""
|
||||
|
||||
visible: root.entryShown
|
||||
property int horizontalMargin: 10
|
||||
property int buttonHorizontalPadding: 10
|
||||
property int buttonVerticalPadding: 5
|
||||
property bool keyboardDown: false
|
||||
|
||||
implicitHeight: rowLayout.implicitHeight + root.buttonVerticalPadding * 2
|
||||
implicitWidth: rowLayout.implicitWidth + root.buttonHorizontalPadding * 2
|
||||
buttonRadius: Appearance.rounding.normal
|
||||
colBackground: (root.down || root.keyboardDown) ? Appearance.colors.colSecondaryContainerActive :
|
||||
((root.hovered || root.focus) ? Appearance.colors.colSecondaryContainerHover :
|
||||
ColorUtils.transparentize(Appearance.colors.colSecondaryContainer, 1))
|
||||
colBackgroundHover: Appearance.colors.colSecondaryContainerHover
|
||||
colRipple: Appearance.colors.colSecondaryContainerActive
|
||||
|
||||
property string highlightPrefix: `<u><font color="${Appearance.colors.colPrimary}">`
|
||||
property string highlightSuffix: `</font></u>`
|
||||
function highlightContent(content, query) {
|
||||
if (!query || query.length === 0 || content == query || fontType === "monospace")
|
||||
return StringUtils.escapeHtml(content);
|
||||
|
||||
let contentLower = content.toLowerCase();
|
||||
let queryLower = query.toLowerCase();
|
||||
|
||||
let result = "";
|
||||
let lastIndex = 0;
|
||||
let qIndex = 0;
|
||||
|
||||
for (let i = 0; i < content.length && qIndex < query.length; i++) {
|
||||
if (contentLower[i] === queryLower[qIndex]) {
|
||||
// Add non-highlighted part (escaped)
|
||||
if (i > lastIndex)
|
||||
result += StringUtils.escapeHtml(content.slice(lastIndex, i));
|
||||
// Add highlighted character (escaped)
|
||||
result += root.highlightPrefix + StringUtils.escapeHtml(content[i]) + root.highlightSuffix;
|
||||
lastIndex = i + 1;
|
||||
qIndex++;
|
||||
}
|
||||
}
|
||||
// Add the rest of the string (escaped)
|
||||
if (lastIndex < content.length)
|
||||
result += StringUtils.escapeHtml(content.slice(lastIndex));
|
||||
|
||||
return result;
|
||||
}
|
||||
property string displayContent: highlightContent(root.itemName, root.query)
|
||||
|
||||
property list<string> urls: {
|
||||
if (!root.itemName) return [];
|
||||
// Regular expression to match URLs
|
||||
const urlRegex = /https?:\/\/[^\s<>"{}|\\^`[\]]+/gi;
|
||||
const matches = root.itemName?.match(urlRegex)
|
||||
?.filter(url => !url.includes("…")) // Elided = invalid
|
||||
return matches ? matches : [];
|
||||
}
|
||||
|
||||
PointingHandInteraction {}
|
||||
|
||||
background {
|
||||
anchors.fill: root
|
||||
anchors.leftMargin: root.horizontalMargin
|
||||
anchors.rightMargin: root.horizontalMargin
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.itemExecute()
|
||||
GlobalStates.overviewOpen = false
|
||||
}
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
root.keyboardDown = true
|
||||
root.clicked()
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
Keys.onReleased: (event) => {
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
root.keyboardDown = false
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
spacing: iconLoader.sourceComponent === null ? 0 : 10
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: root.horizontalMargin + root.buttonHorizontalPadding
|
||||
anchors.rightMargin: root.horizontalMargin + root.buttonHorizontalPadding
|
||||
|
||||
// Icon
|
||||
Loader {
|
||||
id: iconLoader
|
||||
active: true
|
||||
sourceComponent: root.materialSymbol !== "" ? materialSymbolComponent :
|
||||
root.bigText ? bigTextComponent :
|
||||
root.itemIcon !== "" ? iconImageComponent :
|
||||
null
|
||||
}
|
||||
|
||||
Component {
|
||||
id: iconImageComponent
|
||||
IconImage {
|
||||
source: Quickshell.iconPath(root.itemIcon, "image-missing")
|
||||
width: 35
|
||||
height: 35
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: materialSymbolComponent
|
||||
MaterialSymbol {
|
||||
text: root.materialSymbol
|
||||
iconSize: 30
|
||||
color: Appearance.m3colors.m3onSurface
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: bigTextComponent
|
||||
StyledText {
|
||||
text: root.bigText
|
||||
font.pixelSize: Appearance.font.pixelSize.larger
|
||||
color: Appearance.m3colors.m3onSurface
|
||||
}
|
||||
}
|
||||
|
||||
// Main text
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
StyledText {
|
||||
font.pixelSize: Appearance.font.pixelSize.smaller
|
||||
color: Appearance.colors.colSubtext
|
||||
visible: root.itemType && root.itemType != Translation.tr("App")
|
||||
text: root.itemType
|
||||
}
|
||||
RowLayout {
|
||||
Loader { // Checkmark for copied clipboard entry
|
||||
visible: itemName == Quickshell.clipboardText && root.cliphistRawString
|
||||
active: itemName == Quickshell.clipboardText && root.cliphistRawString
|
||||
sourceComponent: Rectangle {
|
||||
implicitWidth: activeText.implicitHeight
|
||||
implicitHeight: activeText.implicitHeight
|
||||
radius: Appearance.rounding.full
|
||||
color: Appearance.colors.colPrimary
|
||||
MaterialSymbol {
|
||||
id: activeText
|
||||
anchors.centerIn: parent
|
||||
text: "check"
|
||||
font.pixelSize: Appearance.font.pixelSize.normal
|
||||
color: Appearance.m3colors.m3onPrimary
|
||||
}
|
||||
}
|
||||
}
|
||||
Repeater { // Favicons for links
|
||||
model: root.query == root.itemName ? [] : root.urls
|
||||
Favicon {
|
||||
required property var modelData
|
||||
size: parent.height
|
||||
url: modelData
|
||||
}
|
||||
}
|
||||
StyledText { // Item name/content
|
||||
Layout.fillWidth: true
|
||||
id: nameText
|
||||
textFormat: Text.StyledText // RichText also works, but StyledText ensures elide work
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
font.family: Appearance.font.family[root.fontType]
|
||||
color: Appearance.m3colors.m3onSurface
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
text: `${root.displayContent}`
|
||||
}
|
||||
}
|
||||
Loader { // Clipboard image preview
|
||||
active: root.cliphistRawString && /^\d+\t\[\[.*binary data.*\d+x\d+.*\]\]$/.test(root.cliphistRawString)
|
||||
sourceComponent: CliphistImage {
|
||||
Layout.fillWidth: true
|
||||
entry: root.cliphistRawString
|
||||
maxWidth: contentColumn.width
|
||||
maxHeight: 140
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Action text
|
||||
StyledText {
|
||||
Layout.fillWidth: false
|
||||
visible: (root.hovered || root.focus)
|
||||
id: clickAction
|
||||
font.pixelSize: Appearance.font.pixelSize.normal
|
||||
color: Appearance.colors.colSubtext
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: root.itemClickActionName
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 4
|
||||
Repeater {
|
||||
model: (root.entry.actions ?? []).slice(0, 4)
|
||||
delegate: RippleButton {
|
||||
id: actionButton
|
||||
required property var modelData
|
||||
implicitHeight: 34
|
||||
implicitWidth: 34
|
||||
|
||||
contentItem: Item {
|
||||
id: actionContentItem
|
||||
anchors.centerIn: parent
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: !(actionButton.modelData.icon && actionButton.modelData.icon !== "")
|
||||
sourceComponent: MaterialSymbol {
|
||||
text: "video_settings"
|
||||
font.pixelSize: Appearance.font.pixelSize.hugeass
|
||||
color: Appearance.m3colors.m3onSurface
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: actionButton.modelData.icon && actionButton.modelData.icon !== ""
|
||||
sourceComponent: IconImage {
|
||||
source: Quickshell.iconPath(actionButton.modelData.icon)
|
||||
implicitSize: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: modelData.execute()
|
||||
|
||||
StyledToolTip {
|
||||
content: modelData.name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user