mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 14:59:27 -05:00
format, move text color to styled text area
This commit is contained in:
@@ -10,6 +10,7 @@ TextArea {
|
||||
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
|
||||
selectionColor: Appearance.colors.colSecondaryContainer
|
||||
placeholderTextColor: Appearance.m3colors.m3outline
|
||||
color: Appearance.colors.colOnLayer0
|
||||
font {
|
||||
family: Appearance.font.family.main
|
||||
pixelSize: Appearance?.font.pixelSize.small ?? 15
|
||||
|
||||
@@ -11,149 +11,146 @@ import qs.modules.ii.overlay
|
||||
|
||||
OverlayBackground {
|
||||
id: root
|
||||
|
||||
readonly property real panelPadding: 20
|
||||
|
||||
property string stickypadContents: ""
|
||||
property bool pendingReload: false
|
||||
property var copylistEntries: []
|
||||
property string lastParsedCopylistText: ""
|
||||
property var parsedCopylistLines: []
|
||||
property bool isClickthrough: false
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
stickypadFile.reload()
|
||||
updateCopylistEntries()
|
||||
stickypadFile.reload();
|
||||
updateCopylistEntries();
|
||||
}
|
||||
|
||||
|
||||
function saveStickypad() {
|
||||
if (!stickypadInput)
|
||||
return
|
||||
stickypadContents = stickypadInput.text
|
||||
stickypadFile.setText(stickypadContents)
|
||||
return;
|
||||
stickypadContents = stickypadInput.text;
|
||||
stickypadFile.setText(stickypadContents);
|
||||
}
|
||||
|
||||
|
||||
function focusStickypadAtEnd() {
|
||||
if (!stickypadInput)
|
||||
return
|
||||
stickypadInput.forceActiveFocus()
|
||||
const endPos = stickypadInput.text.length
|
||||
applySelection(endPos, endPos)
|
||||
return;
|
||||
stickypadInput.forceActiveFocus();
|
||||
const endPos = stickypadInput.text.length;
|
||||
applySelection(endPos, endPos);
|
||||
}
|
||||
|
||||
|
||||
function applySelection(cursorPos, anchorPos) {
|
||||
if (!stickypadInput)
|
||||
return
|
||||
const textLength = stickypadInput.text.length
|
||||
const cursor = Math.max(0, Math.min(cursorPos, textLength))
|
||||
const anchor = Math.max(0, Math.min(anchorPos, textLength))
|
||||
stickypadInput.select(anchor, cursor)
|
||||
return;
|
||||
const textLength = stickypadInput.text.length;
|
||||
const cursor = Math.max(0, Math.min(cursorPos, textLength));
|
||||
const anchor = Math.max(0, Math.min(anchorPos, textLength));
|
||||
stickypadInput.select(anchor, cursor);
|
||||
if (cursor === anchor)
|
||||
stickypadInput.deselect()
|
||||
stickypadInput.deselect();
|
||||
}
|
||||
|
||||
|
||||
function scheduleCopylistUpdate(immediate = false) {
|
||||
if (!stickypadInput)
|
||||
return
|
||||
return;
|
||||
if (immediate) {
|
||||
copyListDebounce.stop()
|
||||
updateCopylistEntries()
|
||||
copyListDebounce.stop();
|
||||
updateCopylistEntries();
|
||||
} else {
|
||||
copyListDebounce.restart()
|
||||
copyListDebounce.restart();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateCopylistEntries() {
|
||||
if (!stickypadInput)
|
||||
return
|
||||
const textValue = stickypadInput.text
|
||||
return;
|
||||
const textValue = stickypadInput.text;
|
||||
if (!textValue || textValue.length === 0) {
|
||||
lastParsedCopylistText = ""
|
||||
parsedCopylistLines = []
|
||||
copylistEntries = []
|
||||
return
|
||||
lastParsedCopylistText = "";
|
||||
parsedCopylistLines = [];
|
||||
copylistEntries = [];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (textValue !== lastParsedCopylistText) {
|
||||
const lineRegex = /(.*?)(\r?\n|$)/g
|
||||
let match = null
|
||||
const parsed = []
|
||||
const lineRegex = /(.*?)(\r?\n|$)/g;
|
||||
let match = null;
|
||||
const parsed = [];
|
||||
while ((match = lineRegex.exec(textValue)) !== null) {
|
||||
const lineText = match[1]
|
||||
const newlineText = match[2]
|
||||
const lineStart = match.index
|
||||
const lineEnd = lineStart + lineText.length
|
||||
const bulletMatch = lineText.match(/^\s*-\s+(.*\S)\s*$/)
|
||||
const lineText = match[1];
|
||||
const newlineText = match[2];
|
||||
const lineStart = match.index;
|
||||
const lineEnd = lineStart + lineText.length;
|
||||
const bulletMatch = lineText.match(/^\s*-\s+(.*\S)\s*$/);
|
||||
if (bulletMatch) {
|
||||
parsed.push({
|
||||
content: bulletMatch[1].trim(),
|
||||
start: lineStart,
|
||||
end: lineEnd
|
||||
})
|
||||
});
|
||||
}
|
||||
if (newlineText === "")
|
||||
break
|
||||
break;
|
||||
}
|
||||
lastParsedCopylistText = textValue
|
||||
parsedCopylistLines = parsed
|
||||
lastParsedCopylistText = textValue;
|
||||
parsedCopylistLines = parsed;
|
||||
if (parsed.length === 0) {
|
||||
copylistEntries = []
|
||||
return
|
||||
copylistEntries = [];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
updateCopylistPositions()
|
||||
|
||||
updateCopylistPositions();
|
||||
}
|
||||
|
||||
|
||||
function updateCopylistPositions() {
|
||||
if (!stickypadInput || parsedCopylistLines.length === 0)
|
||||
return
|
||||
|
||||
const rawSelectionStart = stickypadInput.selectionStart
|
||||
const rawSelectionEnd = stickypadInput.selectionEnd
|
||||
const selectionStart = rawSelectionStart === -1 ? stickypadInput.cursorPosition : rawSelectionStart
|
||||
const selectionEnd = rawSelectionEnd === -1 ? stickypadInput.cursorPosition : rawSelectionEnd
|
||||
const rangeStart = Math.min(selectionStart, selectionEnd)
|
||||
const rangeEnd = Math.max(selectionStart, selectionEnd)
|
||||
|
||||
return;
|
||||
const rawSelectionStart = stickypadInput.selectionStart;
|
||||
const rawSelectionEnd = stickypadInput.selectionEnd;
|
||||
const selectionStart = rawSelectionStart === -1 ? stickypadInput.cursorPosition : rawSelectionStart;
|
||||
const selectionEnd = rawSelectionEnd === -1 ? stickypadInput.cursorPosition : rawSelectionEnd;
|
||||
const rangeStart = Math.min(selectionStart, selectionEnd);
|
||||
const rangeEnd = Math.max(selectionStart, selectionEnd);
|
||||
|
||||
const entries = parsedCopylistLines.map(line => {
|
||||
const caretIntersects = rangeEnd > line.start && rangeStart <= line.end
|
||||
const caretIntersects = rangeEnd > line.start && rangeStart <= line.end;
|
||||
if (caretIntersects)
|
||||
return null
|
||||
const startRect = stickypadInput.positionToRectangle(line.start)
|
||||
let endRect = stickypadInput.positionToRectangle(line.end)
|
||||
return null;
|
||||
const startRect = stickypadInput.positionToRectangle(line.start);
|
||||
let endRect = stickypadInput.positionToRectangle(line.end);
|
||||
if (!isFinite(startRect.y))
|
||||
return null
|
||||
return null;
|
||||
if (!isFinite(endRect.y))
|
||||
endRect = startRect
|
||||
const lineBottom = endRect.y + endRect.height
|
||||
const rectHeight = Math.max(lineBottom - startRect.y, stickypadInput.font.pixelSize + 8)
|
||||
endRect = startRect;
|
||||
const lineBottom = endRect.y + endRect.height;
|
||||
const rectHeight = Math.max(lineBottom - startRect.y, stickypadInput.font.pixelSize + 8);
|
||||
return {
|
||||
content: line.content,
|
||||
y: startRect.y,
|
||||
height: rectHeight
|
||||
}
|
||||
}).filter(entry => entry !== null)
|
||||
|
||||
copylistEntries = entries
|
||||
};
|
||||
}).filter(entry => entry !== null);
|
||||
|
||||
copylistEntries = entries;
|
||||
}
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
id: stickypadLayout
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: panelPadding
|
||||
margins: 16
|
||||
}
|
||||
spacing: 14
|
||||
|
||||
spacing: 10
|
||||
|
||||
ScrollView {
|
||||
id: editorScrollView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumHeight: 200
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
onWidthChanged: root.scheduleCopylistUpdate(true)
|
||||
|
||||
|
||||
StyledTextArea {
|
||||
id: stickypadInput
|
||||
anchors {
|
||||
@@ -167,19 +164,16 @@ OverlayBackground {
|
||||
textFormat: TextEdit.PlainText
|
||||
background: null
|
||||
rightPadding: 44
|
||||
// Adapt text color to theme (light/dark mode) - START
|
||||
color: Appearance.colors.colOnLayer0
|
||||
// Adapt text color to theme (light/dark mode) - END
|
||||
// Disable text area when clickthrough enabled - START
|
||||
enabled: GlobalStates.overlayOpen || !root.isClickthrough
|
||||
activeFocusOnTab: GlobalStates.overlayOpen || !root.isClickthrough
|
||||
// Disable text area when clickthrough enabled - END
|
||||
|
||||
|
||||
onTextChanged: {
|
||||
if (stickypadInput.activeFocus) {
|
||||
saveDebounce.restart()
|
||||
saveDebounce.restart();
|
||||
}
|
||||
root.scheduleCopylistUpdate(true)
|
||||
root.scheduleCopylistUpdate(true);
|
||||
}
|
||||
onCursorPositionChanged: root.scheduleCopylistUpdate()
|
||||
onSelectionStartChanged: root.scheduleCopylistUpdate()
|
||||
@@ -187,25 +181,25 @@ OverlayBackground {
|
||||
onHeightChanged: root.scheduleCopylistUpdate(true)
|
||||
onContentHeightChanged: root.scheduleCopylistUpdate(true)
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
anchors.fill: stickypadInput
|
||||
visible: copylistEntries.length > 0
|
||||
clip: true
|
||||
|
||||
|
||||
Repeater {
|
||||
model: copylistEntries
|
||||
delegate: Item {
|
||||
readonly property real lineHeight: Math.max(modelData.height, Appearance.font.pixelSize.normal + 6)
|
||||
readonly property real iconSizeLocal: Appearance.font.pixelSize.normal
|
||||
readonly property real hitPadding: 6
|
||||
|
||||
|
||||
width: iconSizeLocal + hitPadding * 2
|
||||
height: lineHeight
|
||||
y: modelData.y
|
||||
x: Math.max(stickypadInput.width - width - 8, 0)
|
||||
z: 5
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: feedbackFlash
|
||||
anchors.centerIn: iconItem
|
||||
@@ -214,9 +208,9 @@ OverlayBackground {
|
||||
radius: width / 2
|
||||
color: Appearance.colors.colLayer2
|
||||
opacity: 0
|
||||
z: -1
|
||||
z: 999
|
||||
}
|
||||
|
||||
|
||||
MaterialSymbol {
|
||||
id: iconItem
|
||||
anchors.centerIn: parent
|
||||
@@ -237,7 +231,7 @@ OverlayBackground {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
@@ -248,12 +242,12 @@ OverlayBackground {
|
||||
onReleased: iconItem.scale = 1
|
||||
onCanceled: iconItem.scale = 1
|
||||
onClicked: {
|
||||
feedbackFlash.opacity = 0.6
|
||||
feedbackFade.restart()
|
||||
Quickshell.clipboardText = modelData.content
|
||||
feedbackFlash.opacity = 0.6;
|
||||
feedbackFade.restart();
|
||||
Quickshell.clipboardText = modelData.content;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NumberAnimation {
|
||||
id: feedbackFade
|
||||
target: feedbackFlash
|
||||
@@ -266,72 +260,63 @@ OverlayBackground {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
StyledText {
|
||||
id: statusLabel
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 28
|
||||
Layout.minimumHeight: 28
|
||||
color: "transparent"
|
||||
|
||||
StyledText {
|
||||
id: statusLabel
|
||||
anchors {
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
rightMargin: 8
|
||||
}
|
||||
text: saveDebounce.running ? "Saving..." : "Saved"
|
||||
color: Appearance.colors.colSubtext
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
// Layout.preferredHeight: 28
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: saveDebounce.running ? Translation.tr("Saving...") : Translation.tr("Saved")
|
||||
color: Appearance.colors.colSubtext
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Timer {
|
||||
id: saveDebounce
|
||||
interval: 500
|
||||
repeat: false
|
||||
onTriggered: saveStickypad()
|
||||
}
|
||||
|
||||
|
||||
Timer {
|
||||
id: copyListDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
onTriggered: updateCopylistPositions()
|
||||
}
|
||||
|
||||
|
||||
FileView {
|
||||
id: stickypadFile
|
||||
path: Qt.resolvedUrl(Directories.stickypadPath)
|
||||
onLoaded: {
|
||||
stickypadContents = stickypadFile.text()
|
||||
stickypadContents = stickypadFile.text();
|
||||
if (stickypadInput && stickypadInput.text !== stickypadContents) {
|
||||
const previousCursor = stickypadInput.cursorPosition
|
||||
const previousAnchor = stickypadInput.selectionStart
|
||||
stickypadInput.text = stickypadContents
|
||||
applySelection(previousCursor, previousAnchor)
|
||||
const previousCursor = stickypadInput.cursorPosition;
|
||||
const previousAnchor = stickypadInput.selectionStart;
|
||||
stickypadInput.text = stickypadContents;
|
||||
applySelection(previousCursor, previousAnchor);
|
||||
}
|
||||
if (pendingReload) {
|
||||
pendingReload = false
|
||||
Qt.callLater(focusStickypadAtEnd)
|
||||
pendingReload = false;
|
||||
Qt.callLater(focusStickypadAtEnd);
|
||||
}
|
||||
Qt.callLater(root.updateCopylistEntries)
|
||||
Qt.callLater(root.updateCopylistEntries);
|
||||
}
|
||||
onLoadFailed: (error) => {
|
||||
onLoadFailed: error => {
|
||||
if (error === FileViewError.FileNotFound) {
|
||||
stickypadContents = ""
|
||||
stickypadFile.setText(stickypadContents)
|
||||
stickypadContents = "";
|
||||
stickypadFile.setText(stickypadContents);
|
||||
if (stickypadInput)
|
||||
stickypadInput.text = stickypadContents
|
||||
stickypadInput.text = stickypadContents;
|
||||
if (pendingReload) {
|
||||
pendingReload = false
|
||||
Qt.callLater(focusStickypadAtEnd)
|
||||
pendingReload = false;
|
||||
Qt.callLater(focusStickypadAtEnd);
|
||||
}
|
||||
Qt.callLater(root.updateCopylistEntries)
|
||||
Qt.callLater(root.updateCopylistEntries);
|
||||
} else {
|
||||
console.log("[Stickypad] Error loading file: " + error)
|
||||
console.log("[Stickypad] Error loading file: " + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user