1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

Merge branch 'master' of github.com:bbedward/DankMaterialShell

This commit is contained in:
bbedward
2025-10-04 08:12:51 -04:00
4 changed files with 309 additions and 2 deletions

View File

@@ -881,7 +881,7 @@ Singleton {
function toggle(): string {
root.toggleLightMode()
return root.isLightMode ? "light" : "dark"
return root.isLightMode ? "dark" : "light"
}
function light(): string {

View File

@@ -211,6 +211,10 @@ Item {
anchors.fill: parent
isVisible: showSettingsMenu
onSettingsRequested: showSettingsMenu = !showSettingsMenu
onFindRequested: {
showSettingsMenu = false
textEditor.showSearch()
}
}
FileView {

View File

@@ -15,6 +15,7 @@ Item {
property bool fontsEnumerated: false
signal settingsRequested()
signal findRequested()
function enumerateFonts() {
var fonts = ["Default"]
@@ -155,6 +156,51 @@ Item {
}
}
Rectangle {
width: parent.width
height: 48
color: findMouseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.05) : "transparent"
MouseArea {
id: findMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.findRequested()
}
Row {
anchors.left: parent.left
anchors.leftMargin: -Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankActionButton {
iconName: "search"
iconSize: Theme.iconSize - 2
iconColor: Theme.primary
onClicked: root.findRequested()
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
StyledText {
text: "Find in Text"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
}
StyledText {
text: "Open search bar to find text"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
}
}
}
}
Rectangle {
width: parent.width
height: visible ? (fontDropdown.height + Theme.spacingS) : 0

View File

@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Io
import qs.Common
import qs.Services
@@ -15,6 +16,11 @@ Column {
property bool contentLoaded: false
property string lastSavedContent: ""
property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null
property bool searchVisible: false
property string searchQuery: ""
property var searchMatches: []
property int currentMatchIndex: -1
property int matchCount: 0
signal saveRequested()
signal openRequested()
@@ -83,11 +89,250 @@ Column {
}
}
function performSearch() {
let matches = []
currentMatchIndex = -1
if (!searchQuery || searchQuery.length === 0) {
searchMatches = []
matchCount = 0
textArea.select(0, 0)
return
}
const text = textArea.text
const query = searchQuery.toLowerCase()
let index = 0
while (index < text.length) {
const foundIndex = text.toLowerCase().indexOf(query, index)
if (foundIndex === -1) break
matches.push({
start: foundIndex,
end: foundIndex + searchQuery.length
})
index = foundIndex + 1
}
searchMatches = matches
matchCount = matches.length
if (matchCount > 0) {
currentMatchIndex = 0
highlightCurrentMatch()
} else {
textArea.select(0, 0)
}
}
function highlightCurrentMatch() {
if (currentMatchIndex >= 0 && currentMatchIndex < searchMatches.length) {
const match = searchMatches[currentMatchIndex]
textArea.cursorPosition = match.start
textArea.moveCursorSelection(match.end, TextEdit.SelectCharacters)
const flickable = textArea.parent
if (flickable && flickable.contentY !== undefined) {
const lineHeight = textArea.font.pixelSize * 1.5
const approxLine = textArea.text.substring(0, match.start).split('\n').length
const targetY = approxLine * lineHeight - flickable.height / 2
flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height))
}
}
}
function findNext() {
if (matchCount === 0 || searchMatches.length === 0) return
currentMatchIndex = (currentMatchIndex + 1) % matchCount
highlightCurrentMatch()
}
function findPrevious() {
if (matchCount === 0 || searchMatches.length === 0) return
currentMatchIndex = currentMatchIndex <= 0 ? matchCount - 1 : currentMatchIndex - 1
highlightCurrentMatch()
}
function showSearch() {
searchVisible = true
Qt.callLater(() => {
searchField.forceActiveFocus()
})
}
function hideSearch() {
searchVisible = false
searchQuery = ""
searchMatches = []
matchCount = 0
currentMatchIndex = -1
textArea.select(0, 0)
textArea.forceActiveFocus()
}
spacing: Theme.spacingM
StyledRect {
id: searchBar
width: parent.width
height: parent.height - bottomControls.height - Theme.spacingM
height: 48
visible: searchVisible
opacity: searchVisible ? 1 : 0
color: Qt.rgba(Theme.surfaceContainerHigh.r, Theme.surfaceContainerHigh.g, Theme.surfaceContainerHigh.b, 0.95)
border.color: Theme.primary
border.width: 1
radius: Theme.cornerRadius
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
RowLayout {
anchors.fill: parent
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
spacing: Theme.spacingS
StyledRect {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
height: 40
radius: Theme.cornerRadius
color: Theme.surface
border.color: searchField.activeFocus ? Theme.primary : Theme.outlineMedium
border.width: searchField.activeFocus ? 2 : 1
Item {
anchors.fill: parent
anchors.margins: 1
DankIcon {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
name: "search"
size: Theme.iconSize - 2
color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText
}
TextInput {
id: searchField
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM + (Theme.iconSize - 2) + Theme.spacingM
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM + 96 + Theme.spacingS * 2
anchors.verticalCenter: parent.verticalCenter
height: parent.height
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
verticalAlignment: TextInput.AlignVCenter
selectByMouse: true
clip: true
Component.onCompleted: {
text = root.searchQuery
}
Connections {
target: root
function onSearchQueryChanged() {
if (searchField.text !== root.searchQuery) {
searchField.text = root.searchQuery
}
}
}
onTextChanged: {
if (root.searchQuery !== text) {
root.searchQuery = text
root.performSearch()
}
}
Keys.onEscapePressed: event => {
root.hideSearch()
event.accepted = true
}
Keys.onReturnPressed: event => {
if (event.modifiers & Qt.ShiftModifier) {
root.findPrevious()
} else {
root.findNext()
}
event.accepted = true
}
Keys.onEnterPressed: event => {
if (event.modifiers & Qt.ShiftModifier) {
root.findPrevious()
} else {
root.findNext()
}
event.accepted = true
}
}
StyledText {
anchors.left: searchField.left
anchors.verticalCenter: searchField.verticalCenter
text: qsTr("Find in note...")
font: searchField.font
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
visible: searchField.text.length === 0 && !searchField.activeFocus
}
}
}
DankActionButton {
id: prevButton
Layout.alignment: Qt.AlignVCenter
iconName: "keyboard_arrow_up"
iconSize: Theme.iconSize
iconColor: matchCount > 0 ? Theme.surfaceText : Theme.surfaceTextAlpha
enabled: matchCount > 0
onClicked: root.findPrevious()
}
DankActionButton {
id: nextButton
Layout.alignment: Qt.AlignVCenter
iconName: "keyboard_arrow_down"
iconSize: Theme.iconSize
iconColor: matchCount > 0 ? Theme.surfaceText : Theme.surfaceTextAlpha
enabled: matchCount > 0
onClicked: root.findNext()
}
DankActionButton {
id: closeSearchButton
Layout.alignment: Qt.AlignVCenter
iconName: "close"
iconSize: Theme.iconSize - 2
iconColor: Theme.surfaceText
onClicked: root.hideSearch()
}
}
StyledText {
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: Theme.spacingM
anchors.topMargin: 2
text: matchCount > 0 ? qsTr("%1/%2").arg(currentMatchIndex + 1).arg(matchCount) : searchQuery.length > 0 ? qsTr("No matches") : ""
font.pixelSize: Theme.fontSizeSmall
color: matchCount > 0 ? Theme.primary : Theme.surfaceTextMedium
visible: searchQuery.length > 0
}
}
StyledRect {
width: parent.width
height: parent.height - bottomControls.height - Theme.spacingM - (searchVisible ? searchBar.height + Theme.spacingM : 0)
color: Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, Theme.notepadTransparency)
border.color: Theme.outlineMedium
border.width: 1
@@ -159,6 +404,8 @@ Column {
font.pixelSize: SettingsData.notepadFontSize * SettingsData.fontScale
font.letterSpacing: 0
color: Theme.surfaceText
selectedTextColor: Theme.background
selectionColor: Theme.primary
selectByMouse: true
selectByKeyboard: true
wrapMode: TextArea.Wrap
@@ -177,12 +424,18 @@ Column {
loadCurrentTabContent()
setTextDocumentLineHeight()
root.updateLineModel()
Qt.callLater(() => {
textArea.forceActiveFocus()
})
}
Connections {
target: NotepadStorageService
function onCurrentTabIndexChanged() {
loadCurrentTabContent()
Qt.callLater(() => {
textArea.forceActiveFocus()
})
}
function onTabsChanged() {
if (NotepadStorageService.tabs.length > 0 && !contentLoaded) {
@@ -230,6 +483,10 @@ Column {
event.accepted = true
selectAll()
break
case Qt.Key_F:
event.accepted = true
root.showSearch()
break
}
}
}