Add ClideEditorView.

This commit is contained in:
2026-02-06 19:32:02 -05:00
parent 67bf82d0cb
commit 125041f469
4 changed files with 148 additions and 133 deletions

View File

@@ -7,6 +7,7 @@ fn main() {
"qml/ClideTreeView.qml",
"qml/ClideProjectView.qml",
"qml/ClideEditor.qml",
"qml/ClideEditorView.qml",
"qml/ClideMenuBar.qml",
"qml/ClideLogger.qml",
"qml/Components/ClideScrollBar.qml",

View File

@@ -9,160 +9,128 @@ import QtQuick.Layouts
import clide.module 1.0
import Logger 1.0
SplitView {
id: root
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
// 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
Layout.fillHeight: true
Layout.fillWidth: false
// 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.
Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
contentY: editorFlickable.contentY
interactive: false
Layout.fillHeight: true
Layout.fillWidth: true
orientation: Qt.Vertical
Column {
anchors.fill: parent
topPadding: textArea.topPadding
// Customized handle to drag between the Editor and the Console.
handle: ClideHandle {
pressed: SplitHandle.pressed
hovered: SplitHandle.hovered
}
Repeater {
id: repeatedLineNumbers
Component.onCompleted: {
// Show logging is working.
Logger.info("Info logs");
Logger.warn("Warning logs");
Logger.debug("Debug logs");
Logger.error("Error logs");
Logger.trace("Trace logs");
}
// TODO: Bug where text wrapping shows as new line number.
model: textArea.lineCount
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
// This Item is used for each line number in the gutter.
delegate: Item {
required property int index
Layout.fillHeight: true
Layout.fillWidth: false
// 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.
Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
contentY: editorFlickable.contentY
interactive: false
// Calculates the height of each line in the text area.
height: textArea.contentHeight / textArea.lineCount
width: parent.width
Column {
anchors.fill: parent
topPadding: textArea.topPadding
// Show the line number.
Label {
id: numbers
Repeater {
id: repeatedLineNumbers
color: RustColors.linenumber
font: textArea.font
height: parent.height
horizontalAlignment: Text.AlignLeft
text: parent.index + 1
verticalAlignment: Text.AlignVCenter
width: parent.width - indicator.width
// TODO: Bug where text wrapping shows as new line number.
model: textArea.lineCount
// This Item is used for each line number in the gutter.
delegate: Item {
required property int index
// Calculates the height of each line in the text area.
height: textArea.contentHeight / textArea.lineCount
width: parent.width
// Show the line number.
Label {
id: numbers
color: RustColors.linenumber
font: textArea.font
height: parent.height
horizontalAlignment: Text.AlignLeft
text: parent.index + 1
verticalAlignment: Text.AlignVCenter
width: parent.width - indicator.width
background: Rectangle {
color: RustColors.terminal_background
}
background: Rectangle {
color: RustColors.terminal_background
}
// Draw edge along the right side of the line number.
Rectangle {
id: indicator
}
// Draw edge along the right side of the line number.
Rectangle {
id: indicator
anchors.left: numbers.right
color: RustColors.linenumber
height: parent.height
width: 1
}
anchors.left: numbers.right
color: RustColors.linenumber
height: parent.height
width: 1
}
}
}
}
Flickable {
id: editorFlickable
}
Flickable {
id: editorFlickable
Layout.fillHeight: true
Layout.fillWidth: true
boundsBehavior: Flickable.StopAtBounds
height: 650
Layout.fillHeight: true
Layout.fillWidth: true
boundsBehavior: Flickable.StopAtBounds
height: 650
ScrollBar.horizontal: ClideScrollBar {
}
ScrollBar.vertical: ClideScrollBar {
}
TextArea.flickable: TextArea {
id: textArea
ScrollBar.horizontal: ClideScrollBar {
}
ScrollBar.vertical: ClideScrollBar {
}
TextArea.flickable: TextArea {
id: textArea
antialiasing: true
focus: true
persistentSelection: true
selectByMouse: true
selectedTextColor: RustColors.editor_highlighted_text
selectionColor: RustColors.editor_highlight
text: FileSystem.readFile(root.filePath)
textFormat: Qt.AutoText
wrapMode: TextArea.Wrap
antialiasing: true
focus: true
persistentSelection: true
selectByMouse: true
selectedTextColor: RustColors.editor_highlighted_text
selectionColor: RustColors.editor_highlight
text: FileSystem.readFile(root.filePath)
textFormat: Qt.AutoText
wrapMode: TextArea.Wrap
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()
// }
// }
onLinkActivated: function (link) {
Qt.openUrlExternally(link);
}
FontMetrics {
id: fontMetrics
// 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()
// }
// }
}
font: textArea.font
}
FontMetrics {
id: fontMetrics
font: textArea.font
}
}
ClideLogger {
id: areaConsole
}
}

46
qml/ClideEditorView.qml Normal file
View File

@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import clide.module 1.0
import Logger 1.0
SplitView {
id: root
// 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
Layout.fillHeight: true
Layout.fillWidth: true
orientation: Qt.Vertical
// Customized handle to drag between the Editor and the Console.
handle: ClideHandle {
pressed: SplitHandle.pressed
hovered: SplitHandle.hovered
}
Component.onCompleted: {
// Show logging is working.
Logger.info("Info logs");
Logger.warn("Warning logs");
Logger.debug("Debug logs");
Logger.error("Error logs");
Logger.trace("Trace logs");
}
ClideEditor{
id: clideEditor
}
ClideLogger {
id: areaConsole
}
}

View File

@@ -100,7 +100,7 @@ SplitView {
}
}
}
ClideEditor {
ClideEditorView {
id: clideEditor
SplitView.fillWidth: true