From 70e9f79c8a4ada6923c5a3fa0d93d6e84c37e2b1 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Sat, 29 Mar 2025 17:59:17 -0400 Subject: [PATCH] Separate ProjectView and Editor. --- build.rs | 2 + qml/Editor/ClideEditor.qml | 200 ++++++++++++++++++++++ qml/ProjectView/ClideProjectView.qml | 54 ++++++ qml/main.qml | 239 +-------------------------- 4 files changed, 258 insertions(+), 237 deletions(-) create mode 100644 qml/Editor/ClideEditor.qml create mode 100644 qml/ProjectView/ClideProjectView.qml diff --git a/build.rs b/build.rs index 4ddd535..83e59a6 100644 --- a/build.rs +++ b/build.rs @@ -12,6 +12,8 @@ fn main() { uri: "clide.module", rust_files: &["src/main.rs"], qml_files: &["qml/main.qml", + "qml/ProjectView/ClideProjectView.qml", + "qml/Editor/ClideEditor.qml", "qml/Menu/ClideMenu.qml", "qml/Menu/ClideMenuBar.qml", "qml/Menu/ClideMenuBarItem.qml"], diff --git a/qml/Editor/ClideEditor.qml b/qml/Editor/ClideEditor.qml new file mode 100644 index 0000000..c91bd04 --- /dev/null +++ b/qml/Editor/ClideEditor.qml @@ -0,0 +1,200 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import clide.module 1.0 + +SplitView { + Layout.fillHeight: true + Layout.fillWidth: true + orientation: Qt.Vertical + + // Customized handle to drag between the Editor and the Console. + handle: Rectangle { + border.color: SplitHandle.hovered ? "#2b2b2b" : "#3c3f41" + color: SplitHandle.pressed ? "#4b4f51" : "#3c3f41" + implicitHeight: 8 + opacity: SplitHandle.hovered || areaConsole.height < 15 ? 1.0 : 0.0 + + Behavior on opacity { + OpacityAnimator { + duration: 1400 + } + } + } + + 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 + + // Calculate the width based on the logarithmic scale. + Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(areaText.lineCount)) + 1) + 10 + contentY: editorFlickable.contentY + interactive: false + visible: true + + Column { + anchors.fill: parent + + Repeater { + id: repeatedLineNumbers + + delegate: Item { + required property int index + + height: Math.ceil(fontMetrics.lineSpacing) + width: parent.width + + Label { + id: numbers + + color: "white" + font: areaText.font + height: parent.height + horizontalAlignment: Text.AlignLeft + text: parent.index + 1 + verticalAlignment: Text.AlignVCenter + width: parent.width + } + Rectangle { + id: indicator + + anchors.left: numbers.right + color: Qt.darker("#FFF", 3) + height: parent.height + width: 1 + } + } + model: LineCount { + id: lineCountModel + + // This count sets the max line numbers shown in the gutter. + count: areaText.lineCount + } + } + } + } + Flickable { + id: editorFlickable + + property alias areaText: areaText + + Layout.fillHeight: true + Layout.fillWidth: true + boundsBehavior: Flickable.StopAtBounds + height: 650 + + ScrollBar.horizontal: MyScrollBar { + } + ScrollBar.vertical: MyScrollBar { + } + TextArea.flickable: TextArea { + id: areaText + + + color: "#ccced3" + focus: true + persistentSelection: true + selectByMouse: true + // selectedTextColor: control.palette.highlightedText + // selectionColor: control.palette.highlight + textFormat: Qt.AutoText + wrapMode: TextArea.Wrap + + onTextChanged: { + console.log("Updated line count: " + areaText.lineCount) + } + + background: Rectangle { + color: "#2b2b2b" + } + + 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 + + font: areaText.font + } + } + } + TextArea { + id: areaConsole + + height: 100 + placeholderText: qsTr("Placeholder for bash terminal.") + placeholderTextColor: "white" + readOnly: true + wrapMode: TextArea.Wrap + background: Rectangle { + color: "#2b2b2b" + implicitHeight: 100 + // border.color: control.enabled ? "#21be2b" : "transparent" + } + } + + // 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 { + color: "#3b3b3b" + implicitHeight: scrollBar.interactive ? 8 : 4 + implicitWidth: scrollBar.interactive ? 8 : 4 + opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0 + + Behavior on opacity { + OpacityAnimator { + duration: 500 + } + } + } + + // Scroll bar + contentItem: Rectangle { + color: "#4b4f51" + implicitHeight: scrollBar.interactive ? 8 : 4 + implicitWidth: scrollBar.interactive ? 8 : 4 + opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.2 + + Behavior on opacity { + OpacityAnimator { + duration: 1000 + } + } + } + } +} diff --git a/qml/ProjectView/ClideProjectView.qml b/qml/ProjectView/ClideProjectView.qml new file mode 100644 index 0000000..abee55a --- /dev/null +++ b/qml/ProjectView/ClideProjectView.qml @@ -0,0 +1,54 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../Editor" + +SplitView { + Layout.fillHeight: true + Layout.fillWidth: true + anchors.fill: parent + + // Customized handle to drag between the Navigation and the Editor. + handle: Rectangle { + border.color: SplitHandle.hovered ? "#303234" : "#3c3f41" + color: SplitHandle.pressed ? "#4b4f51" : "#3c3f41" + implicitWidth: 8 + opacity: SplitHandle.hovered || navigationView.width < 15 ? 1.0 : 0.0 + + Behavior on opacity { + OpacityAnimator { + duration: 1400 + } + } + } + + Rectangle { + id: navigationView + + SplitView.fillHeight: true + SplitView.preferredWidth: 200 + color: "#303234" + + StackLayout { + anchors.fill: parent + + // Shows the help text. + TextArea { + placeholderText: qsTr("File system view placeholder") + placeholderTextColor: "white" + readOnly: true + wrapMode: TextArea.Wrap + } + + // TODO: Shows the files on the file system. + // ClideTreeView { + // id: fileSystemView + // color: Colors.surface1 + // onFileClicked: path => root.currentFilePath = path + // } + } + } + ClideEditor { + } +} diff --git a/qml/main.qml b/qml/main.qml index 5f4f592..2632981 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts import QtQuick.Dialogs import "Menu" +import "ProjectView" import clide.module 1.0 @@ -27,243 +28,7 @@ ApplicationWindow { title: qsTr("Error") } - RowLayout { - anchors.fill: parent - spacing: 0 - - SplitView { - Layout.fillHeight: true - Layout.fillWidth: true - - // Customized handle to drag between the Navigation and the Editor. - handle: Rectangle { - border.color: SplitHandle.hovered ? "#303234" : "#3c3f41" - color: SplitHandle.pressed ? "#4b4f51" : "#3c3f41" - implicitWidth: 8 - opacity: SplitHandle.hovered || navigationView.width < 15 ? 1.0 : 0.0 - - Behavior on opacity { - OpacityAnimator { - duration: 1400 - } - } - } - - Rectangle { - id: navigationView - - SplitView.fillHeight: true - SplitView.preferredWidth: 200 - color: "#303234" - - StackLayout { - anchors.fill: parent - - // Shows the help text. - TextArea { - placeholderText: qsTr("File system view placeholder") - placeholderTextColor: "white" - readOnly: true - wrapMode: TextArea.Wrap - } - - // TODO: Shows the files on the file system. - // ClideProjectView { - // id: fileSystemView - // color: Colors.surface1 - // onFileClicked: path => root.currentFilePath = path - // } - } - } - SplitView { - Layout.fillHeight: true - Layout.fillWidth: true - orientation: Qt.Vertical - - // Customized handle to drag between the Navigation and the Editor. - handle: Rectangle { - border.color: SplitHandle.hovered ? "#2b2b2b" : "#3c3f41" - color: SplitHandle.pressed ? "#4b4f51" : "#3c3f41" - implicitHeight: 8 - opacity: SplitHandle.hovered || navigationView.width < 15 ? 1.0 : 0.0 - - Behavior on opacity { - OpacityAnimator { - duration: 1400 - } - } - } - - 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 - - // Calculate the width based on the logarithmic scale. - Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(areaText.lineCount)) + 1) + 10 - contentY: editorFlickable.contentY - interactive: false - visible: true - - Column { - anchors.fill: parent - - Repeater { - id: repeatedLineNumbers - - delegate: Item { - required property int index - - height: Math.ceil(fontMetrics.lineSpacing) - width: parent.width - - Label { - id: numbers - - color: "white" - font: areaText.font - height: parent.height - horizontalAlignment: Text.AlignLeft - text: parent.index + 1 - verticalAlignment: Text.AlignVCenter - width: parent.width - } - Rectangle { - id: indicator - - anchors.left: numbers.right - color: Qt.darker("#FFF", 3) - height: parent.height - width: 1 - } - } - model: LineCount { - id: lineCountModel - - // This count sets the max line numbers shown in the gutter. - count: areaText.lineCount - } - } - } - } - Flickable { - id: editorFlickable - - height: 650 - - property alias areaText: areaText - - Layout.fillHeight: true - Layout.fillWidth: true - boundsBehavior: Flickable.StopAtBounds - - ScrollBar.horizontal: MyScrollBar { - } - ScrollBar.vertical: MyScrollBar { - } - TextArea.flickable: TextArea { - id: areaText - - color: "#ccced3" - focus: true - persistentSelection: true - selectByMouse: true - // selectedTextColor: control.palette.highlightedText - // selectionColor: control.palette.highlight - textFormat: Qt.AutoText - wrapMode: TextArea.Wrap - - background: Rectangle { - color: "#2b2b2b" - } - - 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 - - font: areaText.font - } - } - } - TextArea { - id: areaConsole - - height: 100 - placeholderText: qsTr("Placeholder for bash terminal.") - placeholderTextColor: "white" - readOnly: true - wrapMode: TextArea.Wrap - - background: Rectangle { - color: "#2b2b2b" - implicitHeight: 100 - // border.color: control.enabled ? "#21be2b" : "transparent" - } - } - } - } - } - - // 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 - - background: Rectangle { - color: "#2b2b2b" - implicitHeight: scrollBar.interactive ? 8 : 4 - implicitWidth: scrollBar.interactive ? 8 : 4 - opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0 - - Behavior on opacity { - OpacityAnimator { - duration: 500 - } - } - } - contentItem: Rectangle { - color: "#4b4f51" - implicitHeight: scrollBar.interactive ? 8 : 4 - implicitWidth: scrollBar.interactive ? 8 : 4 - opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0 - - Behavior on opacity { - OpacityAnimator { - duration: 1000 - } - } - } + ClideProjectView { } }