mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 23:42:51 -05:00
Merge branch 'master' of github.com:bbedward/DankMaterialShell
This commit is contained in:
@@ -881,7 +881,7 @@ Singleton {
|
|||||||
|
|
||||||
function toggle(): string {
|
function toggle(): string {
|
||||||
root.toggleLightMode()
|
root.toggleLightMode()
|
||||||
return root.isLightMode ? "light" : "dark"
|
return root.isLightMode ? "dark" : "light"
|
||||||
}
|
}
|
||||||
|
|
||||||
function light(): string {
|
function light(): string {
|
||||||
|
|||||||
@@ -211,6 +211,10 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
isVisible: showSettingsMenu
|
isVisible: showSettingsMenu
|
||||||
onSettingsRequested: showSettingsMenu = !showSettingsMenu
|
onSettingsRequested: showSettingsMenu = !showSettingsMenu
|
||||||
|
onFindRequested: {
|
||||||
|
showSettingsMenu = false
|
||||||
|
textEditor.showSearch()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Item {
|
|||||||
property bool fontsEnumerated: false
|
property bool fontsEnumerated: false
|
||||||
|
|
||||||
signal settingsRequested()
|
signal settingsRequested()
|
||||||
|
signal findRequested()
|
||||||
|
|
||||||
function enumerateFonts() {
|
function enumerateFonts() {
|
||||||
var fonts = ["Default"]
|
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 {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: visible ? (fontDropdown.height + Theme.spacingS) : 0
|
height: visible ? (fontDropdown.height + Theme.spacingS) : 0
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -15,6 +16,11 @@ Column {
|
|||||||
property bool contentLoaded: false
|
property bool contentLoaded: false
|
||||||
property string lastSavedContent: ""
|
property string lastSavedContent: ""
|
||||||
property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null
|
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 saveRequested()
|
||||||
signal openRequested()
|
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
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
StyledRect {
|
StyledRect {
|
||||||
|
id: searchBar
|
||||||
width: parent.width
|
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)
|
color: Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, Theme.notepadTransparency)
|
||||||
border.color: Theme.outlineMedium
|
border.color: Theme.outlineMedium
|
||||||
border.width: 1
|
border.width: 1
|
||||||
@@ -159,6 +404,8 @@ Column {
|
|||||||
font.pixelSize: SettingsData.notepadFontSize * SettingsData.fontScale
|
font.pixelSize: SettingsData.notepadFontSize * SettingsData.fontScale
|
||||||
font.letterSpacing: 0
|
font.letterSpacing: 0
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
|
selectedTextColor: Theme.background
|
||||||
|
selectionColor: Theme.primary
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
selectByKeyboard: true
|
selectByKeyboard: true
|
||||||
wrapMode: TextArea.Wrap
|
wrapMode: TextArea.Wrap
|
||||||
@@ -177,12 +424,18 @@ Column {
|
|||||||
loadCurrentTabContent()
|
loadCurrentTabContent()
|
||||||
setTextDocumentLineHeight()
|
setTextDocumentLineHeight()
|
||||||
root.updateLineModel()
|
root.updateLineModel()
|
||||||
|
Qt.callLater(() => {
|
||||||
|
textArea.forceActiveFocus()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: NotepadStorageService
|
target: NotepadStorageService
|
||||||
function onCurrentTabIndexChanged() {
|
function onCurrentTabIndexChanged() {
|
||||||
loadCurrentTabContent()
|
loadCurrentTabContent()
|
||||||
|
Qt.callLater(() => {
|
||||||
|
textArea.forceActiveFocus()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
function onTabsChanged() {
|
function onTabsChanged() {
|
||||||
if (NotepadStorageService.tabs.length > 0 && !contentLoaded) {
|
if (NotepadStorageService.tabs.length > 0 && !contentLoaded) {
|
||||||
@@ -230,6 +483,10 @@ Column {
|
|||||||
event.accepted = true
|
event.accepted = true
|
||||||
selectAll()
|
selectAll()
|
||||||
break
|
break
|
||||||
|
case Qt.Key_F:
|
||||||
|
event.accepted = true
|
||||||
|
root.showSearch()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user