Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions quickshell/Common/SettingsData.qml
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,11 @@ Singleton {
property bool syncModeWithPortal: true
property bool terminalsAlwaysDark: false

property string muxType: "tmux"
property bool muxUseCustomCommand: false
property string muxCustomCommand: ""
property string muxSessionFilter: ""

property bool runDmsMatugenTemplates: true
property bool matugenTemplateGtk: true
property bool matugenTemplateNiri: true
Expand Down
5 changes: 5 additions & 0 deletions quickshell/Common/settings/SettingsSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ var SPEC = {
syncModeWithPortal: { def: true },
terminalsAlwaysDark: { def: false, onChange: "regenSystemThemes" },

muxType: { def: "tmux" },
muxUseCustomCommand: { def: false },
muxCustomCommand: { def: "" },
muxSessionFilter: { def: "" },

runDmsMatugenTemplates: { def: true },
matugenTemplateGtk: { def: true },
matugenTemplateNiri: { def: true },
Expand Down
5 changes: 5 additions & 0 deletions quickshell/DMSShell.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import qs.Modals.Clipboard
import qs.Modals.Greeter
import qs.Modals.Settings
import qs.Modals.DankLauncherV2
import qs.Modals
import qs.Modules
import qs.Modules.AppDrawer
import qs.Modules.DankDash
Expand Down Expand Up @@ -269,6 +270,10 @@ Item {
}
}

MuxModal {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should wrap in a LazyLoader here, like other modals - allow it to unload from memory

id: muxModal
}

LazyLoader {
id: dockContextMenuLoader

Expand Down
312 changes: 312 additions & 0 deletions quickshell/Modals/Common/InputModal.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
import QtQuick
import qs.Common
import qs.Modals.Common
import qs.Widgets

DankModal {
id: root

layerNamespace: "dms:input-modal"
keepPopoutsOpen: true

property string inputTitle: ""
property string inputMessage: ""
property string inputPlaceholder: ""
property string inputText: ""
property string confirmButtonText: "Confirm"
property string cancelButtonText: "Cancel"
property color confirmButtonColor: Theme.primary
property var onConfirm: function (text) {}
property var onCancel: function () {}
property int selectedButton: -1
property bool keyboardNavigation: false

function show(title, message, onConfirmCallback, onCancelCallback) {
inputTitle = title || "";
inputMessage = message || "";
inputPlaceholder = "";
inputText = "";
confirmButtonText = "Confirm";
cancelButtonText = "Cancel";
confirmButtonColor = Theme.primary;
onConfirm = onConfirmCallback || ((text) => {});
onCancel = onCancelCallback || (() => {});
selectedButton = -1;
keyboardNavigation = false;
open();
}

function showWithOptions(options) {
inputTitle = options.title || "";
inputMessage = options.message || "";
inputPlaceholder = options.placeholder || "";
inputText = options.initialText || "";
confirmButtonText = options.confirmText || "Confirm";
cancelButtonText = options.cancelText || "Cancel";
confirmButtonColor = options.confirmColor || Theme.primary;
onConfirm = options.onConfirm || ((text) => {});
onCancel = options.onCancel || (() => {});
selectedButton = -1;
keyboardNavigation = false;
open();
}

function confirmAndClose() {
const text = inputText;
close();
if (onConfirm) {
onConfirm(text);
}
}

function cancelAndClose() {
close();
if (onCancel) {
onCancel();
}
}

function selectButton() {
if (selectedButton === 0) {
cancelAndClose();
} else {
confirmAndClose();
}
}

shouldBeVisible: false
allowStacking: true
modalWidth: 350
modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 200
enableShadow: true
shouldHaveFocus: true
onBackgroundClicked: cancelAndClose()
onOpened: {
Qt.callLater(function () {
if (contentLoader.item && contentLoader.item.textInputRef) {
contentLoader.item.textInputRef.forceActiveFocus();
}
});
}

content: Component {
FocusScope {
anchors.fill: parent
implicitHeight: mainColumn.implicitHeight
focus: true

property alias textInputRef: textInput

Keys.onPressed: function (event) {
const textFieldFocused = textInput.activeFocus;

switch (event.key) {
case Qt.Key_Escape:
root.cancelAndClose();
event.accepted = true;
break;
case Qt.Key_Tab:
if (textFieldFocused) {
root.keyboardNavigation = true;
root.selectedButton = 0;
textInput.focus = false;
} else {
root.keyboardNavigation = true;
if (root.selectedButton === -1) {
root.selectedButton = 0;
} else if (root.selectedButton === 0) {
root.selectedButton = 1;
} else {
root.selectedButton = -1;
textInput.forceActiveFocus();
}
}
event.accepted = true;
break;
case Qt.Key_Left:
if (!textFieldFocused) {
root.keyboardNavigation = true;
root.selectedButton = 0;
event.accepted = true;
}
break;
case Qt.Key_Right:
if (!textFieldFocused) {
root.keyboardNavigation = true;
root.selectedButton = 1;
event.accepted = true;
}
break;
case Qt.Key_Return:
case Qt.Key_Enter:
if (root.selectedButton !== -1) {
root.selectButton();
} else {
root.confirmAndClose();
}
event.accepted = true;
break;
}
}

Column {
id: mainColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.leftMargin: Theme.spacingL
anchors.rightMargin: Theme.spacingL
anchors.topMargin: Theme.spacingL
spacing: 0

StyledText {
text: root.inputTitle
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
width: parent.width
horizontalAlignment: Text.AlignHCenter
}

Item {
width: 1
height: Theme.spacingL
}

StyledText {
text: root.inputMessage
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
width: parent.width
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
visible: root.inputMessage !== ""
}

Item {
width: 1
height: root.inputMessage !== "" ? Theme.spacingL : 0
visible: root.inputMessage !== ""
}

Rectangle {
width: parent.width
height: 40
radius: Theme.cornerRadius
color: Theme.surfaceVariantAlpha
border.color: textInput.activeFocus ? Theme.primary : "transparent"
border.width: textInput.activeFocus ? 1 : 0

TextInput {
id: textInput

anchors.fill: parent
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
verticalAlignment: TextInput.AlignVCenter
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
selectionColor: Theme.primary
selectedTextColor: Theme.primaryText
clip: true
text: root.inputText
onTextChanged: root.inputText = text

StyledText {
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
font.pixelSize: Theme.fontSizeMedium
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4)
text: root.inputPlaceholder
visible: textInput.text === "" && !textInput.activeFocus
}
}
}

Item {
width: 1
height: Theme.spacingL * 1.5
}

Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM

Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: {
if (root.keyboardNavigation && root.selectedButton === 0) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
} else if (cancelButton.containsMouse) {
return Theme.surfacePressed;
} else {
return Theme.surfaceVariantAlpha;
}
}
border.color: (root.keyboardNavigation && root.selectedButton === 0) ? Theme.primary : "transparent"
border.width: (root.keyboardNavigation && root.selectedButton === 0) ? 1 : 0

StyledText {
text: root.cancelButtonText
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
}

MouseArea {
id: cancelButton

anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.cancelAndClose()
}
}

Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: {
const baseColor = root.confirmButtonColor;
if (root.keyboardNavigation && root.selectedButton === 1) {
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 1);
} else if (confirmButton.containsMouse) {
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, 0.9);
} else {
return baseColor;
}
}
border.color: (root.keyboardNavigation && root.selectedButton === 1) ? "white" : "transparent"
border.width: (root.keyboardNavigation && root.selectedButton === 1) ? 1 : 0

StyledText {
text: root.confirmButtonText
font.pixelSize: Theme.fontSizeMedium
color: Theme.primaryText
font.weight: Font.Medium
anchors.centerIn: parent
}

MouseArea {
id: confirmButton

anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.confirmAndClose()
}
}
}

Item {
width: 1
height: Theme.spacingL
}
}
}
}
}
Loading