clide/qml/ClideEditor.qml

214 lines
8.0 KiB
QML
Raw Normal View History

2025-03-29 17:59:17 -04:00
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import clide.module 1.0
SplitView {
2025-03-30 13:50:23 -04:00
id: root
2025-03-29 17:59:17 -04:00
Layout.fillHeight: true
Layout.fillWidth: true
orientation: Qt.Vertical
2025-03-30 13:50:23 -04:00
// The path to the file to show in the text editor.
// This is updated by a signal caught within ClideProjectView.
// Initialized by the Default trait for the Rust QML singleton FileSystem.
required property string filePath;
2025-03-29 17:59:17 -04:00
// Customized handle to drag between the Editor and the Console.
handle: Rectangle {
2025-03-30 11:20:21 -04:00
border.color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
2025-03-29 17:59:17 -04:00
implicitHeight: 8
2025-03-30 11:20:21 -04:00
radius: 2.5
2025-03-29 17:59:17 -04:00
2025-03-30 11:20:21 -04:00
// Execute these behaviors when the color is changed.
Behavior on color {
ColorAnimation {
duration: 400
2025-03-29 17:59:17 -04:00
}
}
}
RowLayout {
// We use a flickable to synchronize the position of the editor and
// the line numbers. This is necessary because the line numbers can
// extend the available height.
Flickable {
id: lineNumbers
Layout.fillHeight: true
Layout.fillWidth: false
2025-03-31 19:26:04 -04:00
// Calculating the width correctly is important as the number grows.
// We need to ensure space required to show N line number digits.
// We use log10 to find how many digits are needed in a line number.
// log10(9) ~= .95; log10(10) = 1.0; log10(100) = 2.0 ...etc
// We +1 to ensure space for at least 1 digit, as floor(1.95) = 1.
// The +10 is additional spacing and can be adjusted.
2025-03-30 11:20:21 -04:00
Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
2025-03-29 17:59:17 -04:00
contentY: editorFlickable.contentY
interactive: false
Column {
anchors.fill: parent
2025-03-31 19:26:04 -04:00
topPadding: textArea.topPadding
2025-03-29 17:59:17 -04:00
Repeater {
id: repeatedLineNumbers
2025-03-31 19:26:04 -04:00
// TODO: Bug where text wrapping shows as new line number.
model: textArea.lineCount
2025-03-29 17:59:17 -04:00
2025-03-31 19:26:04 -04:00
// This Item is used for each line number in the gutter.
2025-03-29 17:59:17 -04:00
delegate: Item {
2025-03-31 19:26:04 -04:00
// Calculates the height of each line in the text area.
2025-03-30 11:20:21 -04:00
height: textArea.contentHeight / textArea.lineCount
2025-03-29 17:59:17 -04:00
width: parent.width
2025-03-31 19:26:04 -04:00
required property int index
// Show the line number.
2025-03-29 17:59:17 -04:00
Label {
id: numbers
2025-03-30 21:58:38 -04:00
color: RustColors.linenumber
2025-03-30 11:20:21 -04:00
font: textArea.font
2025-03-29 17:59:17 -04:00
height: parent.height
horizontalAlignment: Text.AlignLeft
text: parent.index + 1
verticalAlignment: Text.AlignVCenter
2025-03-31 19:26:04 -04:00
width: parent.width - indicator.width
2025-03-29 17:59:17 -04:00
}
2025-03-31 19:26:04 -04:00
// Draw edge along the right side of the line number.
2025-03-29 17:59:17 -04:00
Rectangle {
id: indicator
anchors.left: numbers.right
2025-03-30 11:20:21 -04:00
color: RustColors.linenumber
2025-03-29 17:59:17 -04:00
height: parent.height
width: 1
}
}
}
}
}
Flickable {
id: editorFlickable
Layout.fillHeight: true
Layout.fillWidth: true
boundsBehavior: Flickable.StopAtBounds
height: 650
ScrollBar.horizontal: MyScrollBar {
}
ScrollBar.vertical: MyScrollBar {
}
2025-03-31 19:26:04 -04:00
2025-03-29 17:59:17 -04:00
TextArea.flickable: TextArea {
2025-03-30 11:20:21 -04:00
id: textArea
2025-03-29 17:59:17 -04:00
2025-03-30 11:20:21 -04:00
color: RustColors.editor_text
2025-03-29 17:59:17 -04:00
focus: true
persistentSelection: true
selectByMouse: true
2025-03-31 19:26:04 -04:00
selectedTextColor: RustColors.editor_highlighted_text
selectionColor: RustColors.editor_highlight
2025-03-29 17:59:17 -04:00
textFormat: Qt.AutoText
wrapMode: TextArea.Wrap
2025-03-30 13:50:23 -04:00
text: FileSystem.readFile(root.filePath)
2025-03-29 17:59:17 -04:00
background: Rectangle {
2025-03-30 11:20:21 -04:00
color: RustColors.editor_background
2025-03-29 17:59:17 -04:00
}
onLinkActivated: function (link) {
Qt.openUrlExternally(link);
}
// TODO: Handle saving
// Component.onCompleted: {
// if (Qt.application.arguments.length === 2)
// textDocument.source = "file:" + Qt.application.arguments[1]
// else
// textDocument.source = "qrc:/texteditor.html"
// }
// textDocument.onStatusChanged: {
// // a message lookup table using computed properties:
// // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
// const statusMessages = {
// [ TextDocument.ReadError ]: qsTr("Failed to load “%1”"),
// [ TextDocument.WriteError ]: qsTr("Failed to save “%1”"),
// [ TextDocument.NonLocalFileError ]: qsTr("Not a local file: “%1”"),
// }
// const err = statusMessages[textDocument.status]
// if (err) {
// errorDialog.text = err.arg(textDocument.source)
// errorDialog.open()
// }
// }
}
FontMetrics {
id: fontMetrics
2025-03-30 11:20:21 -04:00
font: textArea.font
2025-03-29 17:59:17 -04:00
}
}
}
TextArea {
id: areaConsole
height: 100
placeholderText: qsTr("Placeholder for bash terminal.")
placeholderTextColor: "white"
readOnly: true
wrapMode: TextArea.Wrap
background: Rectangle {
2025-03-30 11:20:21 -04:00
color: RustColors.editor_background
2025-03-29 17:59:17 -04:00
implicitHeight: 100
2025-03-30 11:20:21 -04:00
// border.color: control.enabled ? RustColors.active : RustColors.inactive
2025-03-29 17:59:17 -04:00
}
}
// We use an inline component to customize the horizontal and vertical
// scroll-bars. This is convenient when the component is only used in one file.
component MyScrollBar: ScrollBar {
id: scrollBar
// Scroll bar gutter
background: Rectangle {
implicitHeight: scrollBar.interactive ? 8 : 4
implicitWidth: scrollBar.interactive ? 8 : 4
2025-03-30 11:20:21 -04:00
color: RustColors.scrollbar_gutter
2025-03-29 17:59:17 -04:00
2025-03-30 11:20:21 -04:00
// Fade the scrollbar gutter when inactive.
opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.2
2025-03-29 17:59:17 -04:00
Behavior on opacity {
OpacityAnimator {
duration: 500
}
}
}
// Scroll bar
contentItem: Rectangle {
implicitHeight: scrollBar.interactive ? 8 : 4
implicitWidth: scrollBar.interactive ? 8 : 4
2025-03-30 11:20:21 -04:00
// If we don't need a scrollbar, fallback to the gutter color.
// If the scrollbar is required change it's color based on activity.
color: scrollBar.size < 1.0 ? scrollBar.active ? RustColors.scrollbar_active : RustColors.scrollbar : RustColors.scrollbar_gutter
// Smooth transition between color changes based on the state above.
Behavior on color {
ColorAnimation {
duration: 1000
}
}
// Fade the scrollbar when inactive.
opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.35
2025-03-29 17:59:17 -04:00
Behavior on opacity {
OpacityAnimator {
2025-03-30 11:20:21 -04:00
duration: 500
2025-03-29 17:59:17 -04:00
}
}
}
}
}