waffles: start menu base

This commit is contained in:
end-4
2025-11-29 23:23:58 +01:00
parent 677fa06b06
commit 4442200479
26 changed files with 464 additions and 61 deletions
@@ -0,0 +1,84 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
FooterRectangle {
id: root
property bool searching: text.length > 0
property alias text: searchInput.text
Component.onCompleted: searchInput.forceActiveFocus()
focus: true
color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter
implicitWidth: 832 // TODO: Make sizes naturally inferred
implicitHeight: 63
Rectangle {
id: outline
anchors {
fill: parent
leftMargin: 32
rightMargin: 32
topMargin: 16
bottomMargin: 15
}
color: "transparent"
radius: height / 2
border.width: 1
border.color: Looks.colors.bg2Border
}
Rectangle {
id: searchInputBg
anchors.fill: outline
anchors.margins: 1
radius: height / 2
color: Looks.colors.inputBg
RowLayout {
anchors.fill: parent
spacing: 11
WAppIcon {
Layout.leftMargin: 14
iconName: "system-search-checked"
separateLightDark: true
implicitSize: 18
}
WTextInput {
id: searchInput
focus: true
Layout.fillWidth: true
WText {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
color: Looks.colors.accentUnfocused
text: Translation.tr("Search for apps") // should also have "", settings, and documents" but we don't have those
visible: searchInput.text.length === 0
font.pixelSize: Looks.font.pixelSize.large
}
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
}
@@ -0,0 +1,16 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
BodyRectangle {
id: root
}
@@ -0,0 +1,39 @@
pragma ComponentBehavior: Bound
import Qt.labs.synchronizer
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
WBarAttachedPanelContent {
id: root
property bool searching: false
property string searchText: ""
contentItem: WPane {
contentItem: WPanelPageColumn {
SearchBar {
focus: true
Layout.fillWidth: true
Synchronizer on searching {
property alias target: root.searching
}
Synchronizer on text {
property alias source: root.searchText
}
}
Loader {
id: pageContentLoader
Layout.fillWidth: true
source: root.searching ? "SearchPageContent.qml" : "StartPageContent.qml"
}
}
}
}
@@ -0,0 +1,98 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import org.kde.kirigami as Kirigami
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
WPanelPageColumn {
id: root
WPanelSeparator {}
BodyRectangle {
implicitHeight: 736 // TODO: Make sizes naturally inferred
}
WPanelSeparator {}
StartFooter {
Layout.fillWidth: true
}
component StartFooter: FooterRectangle {
implicitHeight: 63
UserButton {
anchors {
left: parent.left
leftMargin: 52
bottom: parent.bottom
bottomMargin: 12
}
}
PowerButton {
anchors {
right: parent.right
rightMargin: 52
bottom: parent.bottom
bottomMargin: 12
}
}
}
component UserButton: WBorderlessButton {
id: userButton
implicitWidth: userButtonRow.implicitWidth + 12 * 2
implicitHeight: 40
contentItem: Item {
RowLayout {
id: userButtonRow
anchors.centerIn: parent
spacing: 12
StyledImage {
id: avatar
// Use this for free fallback because I'm lazy
Layout.alignment: Qt.AlignTop
sourceSize: Qt.size(32, 32)
source: Directories.userAvatarPathAccountsService
fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2]
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Circle {
diameter: avatar.height
}
}
}
WText {
Layout.alignment: Qt.AlignVCenter
text: SystemInfo.username
}
}
}
}
component PowerButton: WBorderlessButton {
implicitWidth: 40
implicitHeight: 40
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
icon: "power"
implicitSize: 20
}
}
}
}
@@ -0,0 +1,119 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
Scope {
id: root
Connections {
target: GlobalStates
function onSearchOpenChanged() {
if (GlobalStates.searchOpen)
panelLoader.active = true;
}
}
Loader {
id: panelLoader
active: GlobalStates.searchOpen
sourceComponent: PanelWindow {
id: panelWindow
exclusiveZone: 0
WlrLayershell.namespace: "quickshell:wStartMenu"
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
color: "transparent"
anchors {
bottom: Config.options.waffles.bar.bottom
top: !Config.options.waffles.bar.bottom
left: Config.options.waffles.bar.leftAlignApps
}
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
HyprlandFocusGrab {
id: focusGrab
active: true
windows: [panelWindow]
onCleared: content.close()
}
Connections {
target: GlobalStates
function onSearchOpenChanged() {
if (!GlobalStates.searchOpen)
content.close();
}
}
StartMenuContent {
id: content
anchors.fill: parent
focus: true
onClosed: {
GlobalStates.searchOpen = false;
panelLoader.active = false;
}
}
}
}
IpcHandler {
target: "search"
function toggle() {
GlobalStates.searchOpen = !GlobalStates.searchOpen;
}
function close() {
GlobalStates.searchOpen = false;
}
function open() {
GlobalStates.searchOpen = true;
}
function toggleReleaseInterrupt() {
GlobalStates.superReleaseMightTrigger = false;
}
}
GlobalShortcut {
name: "searchToggle"
description: "Toggles search on press"
onPressed: {
GlobalStates.searchOpen = !GlobalStates.searchOpen;
}
}
GlobalShortcut {
name: "searchToggleRelease"
description: "Toggles search on release"
onPressed: {
GlobalStates.superReleaseMightTrigger = true;
}
onReleased: {
if (!GlobalStates.superReleaseMightTrigger) {
GlobalStates.superReleaseMightTrigger = true;
return;
}
GlobalStates.searchOpen = !GlobalStates.searchOpen;
}
}
GlobalShortcut {
name: "searchToggleReleaseInterrupt"
description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
onPressed: {
GlobalStates.superReleaseMightTrigger = false;
}
}
}