TUI #1
2
build.rs
2
build.rs
@ -12,6 +12,8 @@ fn main() {
|
|||||||
uri: "clide.module",
|
uri: "clide.module",
|
||||||
rust_files: &["src/main.rs"],
|
rust_files: &["src/main.rs"],
|
||||||
qml_files: &["qml/main.qml",
|
qml_files: &["qml/main.qml",
|
||||||
|
"qml/ProjectView/ClideProjectView.qml",
|
||||||
|
"qml/Editor/ClideEditor.qml",
|
||||||
"qml/Menu/ClideMenu.qml",
|
"qml/Menu/ClideMenu.qml",
|
||||||
"qml/Menu/ClideMenuBar.qml",
|
"qml/Menu/ClideMenuBar.qml",
|
||||||
"qml/Menu/ClideMenuBarItem.qml"],
|
"qml/Menu/ClideMenuBarItem.qml"],
|
||||||
|
|||||||
200
qml/Editor/ClideEditor.qml
Normal file
200
qml/Editor/ClideEditor.qml
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
qml/ProjectView/ClideProjectView.qml
Normal file
54
qml/ProjectView/ClideProjectView.qml
Normal file
@ -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 {
|
||||||
|
}
|
||||||
|
}
|
||||||
239
qml/main.qml
239
qml/main.qml
@ -4,6 +4,7 @@ import QtQuick.Layouts
|
|||||||
import QtQuick.Dialogs
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
import "Menu"
|
import "Menu"
|
||||||
|
import "ProjectView"
|
||||||
|
|
||||||
import clide.module 1.0
|
import clide.module 1.0
|
||||||
|
|
||||||
@ -27,243 +28,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
title: qsTr("Error")
|
title: qsTr("Error")
|
||||||
}
|
}
|
||||||
RowLayout {
|
ClideProjectView {
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user