Compare commits
5 Commits
4aad91416e
...
1b60947177
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b60947177 | |||
| f918d65888 | |||
| aa42ec6072 | |||
| 6f2a655497 | |||
| c0f38b531d |
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -295,6 +295,7 @@ dependencies = [
|
|||||||
"cxx-qt",
|
"cxx-qt",
|
||||||
"cxx-qt-build",
|
"cxx-qt-build",
|
||||||
"cxx-qt-lib",
|
"cxx-qt-lib",
|
||||||
|
"devicons",
|
||||||
"dirs",
|
"dirs",
|
||||||
"edtui",
|
"edtui",
|
||||||
"log",
|
"log",
|
||||||
@@ -667,6 +668,15 @@ dependencies = [
|
|||||||
"syn 2.0.114",
|
"syn 2.0.114",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "devicons"
|
||||||
|
version = "0.6.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830e47e2f330cf4fdd5a958dcef921b9523ffc21ab6713aa5e77ba2cce03904b"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ tui-logger = "0.18.1"
|
|||||||
edtui = "0.11.1"
|
edtui = "0.11.1"
|
||||||
strum = "0.27.2"
|
strum = "0.27.2"
|
||||||
uuid = { version = "1.19.0", features = ["v4"] }
|
uuid = { version = "1.19.0", features = ["v4"] }
|
||||||
|
devicons = "0.6.12"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
# The link_qt_object_files feature is required for statically linking Qt 6.
|
# The link_qt_object_files feature is required for statically linking Qt 6.
|
||||||
|
|||||||
3
build.rs
3
build.rs
@@ -12,6 +12,9 @@ fn main() {
|
|||||||
"qml/ClideLogger.qml",
|
"qml/ClideLogger.qml",
|
||||||
"qml/Components/ClideScrollBar.qml",
|
"qml/Components/ClideScrollBar.qml",
|
||||||
"qml/Components/ClideHandle.qml",
|
"qml/Components/ClideHandle.qml",
|
||||||
|
"qml/Components/ClideMenu.qml",
|
||||||
|
"qml/Components/ClideMenuItem.qml",
|
||||||
|
"qml/Components/ClideBreadCrumbs.qml",
|
||||||
"qml/Logger/Logger.qml",
|
"qml/Logger/Logger.qml",
|
||||||
]))
|
]))
|
||||||
// Link Qt's Network library
|
// Link Qt's Network library
|
||||||
|
|||||||
@@ -10,128 +10,116 @@ import clide.module 1.0
|
|||||||
MenuBar {
|
MenuBar {
|
||||||
// Background for this MenuBar.
|
// Background for this MenuBar.
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
border.color: RustColors.explorer_background
|
|
||||||
color: RustColors.menubar
|
color: RustColors.menubar
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// File Menu
|
// File Menu
|
||||||
Action {
|
|
||||||
id: actionNewProject
|
|
||||||
|
|
||||||
text: qsTr("&New Project...")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionOpen
|
|
||||||
|
|
||||||
text: qsTr("&Open...")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionSave
|
|
||||||
|
|
||||||
text: qsTr("&Save")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionExit
|
|
||||||
|
|
||||||
text: qsTr("&Exit")
|
|
||||||
|
|
||||||
onTriggered: Qt.quit()
|
|
||||||
}
|
|
||||||
ClideMenu {
|
ClideMenu {
|
||||||
title: qsTr("&File")
|
title: qsTr("&File")
|
||||||
|
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionNewProject
|
action: Action {
|
||||||
|
id: actionNewProject
|
||||||
|
|
||||||
|
text: qsTr("&New Project...")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionOpen
|
action: Action {
|
||||||
|
id: actionOpen
|
||||||
|
|
||||||
|
text: qsTr("&Open...")
|
||||||
|
}
|
||||||
|
|
||||||
onTriggered: FileSystem.setDirectory(FileSystem.filePath)
|
onTriggered: FileSystem.setDirectory(FileSystem.filePath)
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionSave
|
action: Action {
|
||||||
|
id: actionSave
|
||||||
|
|
||||||
|
text: qsTr("&Save")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MenuSeparator {
|
MenuSeparator {
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
border.color: color
|
border.color: color
|
||||||
color: RustColors.explorer_background
|
color: Qt.darker(RustColors.menubar, 1)
|
||||||
implicitHeight: 3
|
implicitHeight: 3
|
||||||
implicitWidth: 200
|
implicitWidth: 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionExit
|
action: Action {
|
||||||
|
id: actionExit
|
||||||
|
|
||||||
|
text: qsTr("&Exit")
|
||||||
|
|
||||||
|
onTriggered: Qt.quit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Edit Menu
|
// Edit Menu
|
||||||
Action {
|
|
||||||
id: actionUndo
|
|
||||||
|
|
||||||
text: qsTr("&Undo")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionRedo
|
|
||||||
|
|
||||||
text: qsTr("&Redo")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionCut
|
|
||||||
|
|
||||||
text: qsTr("&Cut")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionCopy
|
|
||||||
|
|
||||||
text: qsTr("&Copy")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionPaste
|
|
||||||
|
|
||||||
text: qsTr("&Paste")
|
|
||||||
}
|
|
||||||
ClideMenu {
|
ClideMenu {
|
||||||
title: qsTr("&Edit")
|
title: qsTr("&Edit")
|
||||||
|
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionUndo
|
action: Action {
|
||||||
|
id: actionUndo
|
||||||
|
|
||||||
|
text: qsTr("&Undo")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionRedo
|
action: Action {
|
||||||
|
id: actionRedo
|
||||||
|
|
||||||
|
text: qsTr("&Redo")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionCut
|
action: Action {
|
||||||
|
id: actionCut
|
||||||
|
|
||||||
|
text: qsTr("&Cut")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionCopy
|
action: Action {
|
||||||
|
id: actionCopy
|
||||||
|
|
||||||
|
text: qsTr("&Copy")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionPaste
|
action: Action {
|
||||||
|
id: actionPaste
|
||||||
|
|
||||||
|
text: qsTr("&Paste")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// View Menu
|
// View Menu
|
||||||
Action {
|
|
||||||
id: actionToolWindows
|
|
||||||
|
|
||||||
text: qsTr("&Tool Windows")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionAppearance
|
|
||||||
|
|
||||||
text: qsTr("&Appearance")
|
|
||||||
}
|
|
||||||
ClideMenu {
|
ClideMenu {
|
||||||
title: qsTr("&View")
|
title: qsTr("&View")
|
||||||
|
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionToolWindows
|
action: Action {
|
||||||
|
id: actionAppearance
|
||||||
|
|
||||||
|
text: qsTr("&Appearance")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionAppearance
|
action: Action {
|
||||||
|
id: actionToolWindows
|
||||||
|
|
||||||
|
text: qsTr("&Tool Windows")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,51 +129,25 @@ MenuBar {
|
|||||||
id: clideAbout
|
id: clideAbout
|
||||||
|
|
||||||
}
|
}
|
||||||
Action {
|
|
||||||
id: actionDocumentation
|
|
||||||
|
|
||||||
text: qsTr("&Documentation")
|
|
||||||
}
|
|
||||||
Action {
|
|
||||||
id: actionAbout
|
|
||||||
|
|
||||||
text: qsTr("&About")
|
|
||||||
|
|
||||||
// Toggle the about window with the menu item is clicked.
|
|
||||||
onTriggered: clideAbout.visible = !clideAbout.visible
|
|
||||||
}
|
|
||||||
ClideMenu {
|
ClideMenu {
|
||||||
title: qsTr("&Help")
|
title: qsTr("&Help")
|
||||||
|
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionDocumentation
|
action: Action {
|
||||||
|
id: actionDocumentation
|
||||||
|
|
||||||
|
text: qsTr("&Documentation")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClideMenuItem {
|
ClideMenuItem {
|
||||||
action: actionAbout
|
action: Action {
|
||||||
}
|
id: actionAbout
|
||||||
}
|
|
||||||
|
|
||||||
// Base settings for each Menu.
|
text: qsTr("&About")
|
||||||
component ClideMenu: Menu {
|
|
||||||
background: Rectangle {
|
|
||||||
color: RustColors.explorer_background
|
|
||||||
implicitWidth: 100
|
|
||||||
radius: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base settings for each MenuItem.
|
// Toggle the about window with the menu item is clicked.
|
||||||
component ClideMenuItem: MenuItem {
|
onTriggered: clideAbout.visible = !clideAbout.visible
|
||||||
id: root
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
color: root.hovered ? RustColors.hovered : RustColors.unhovered
|
|
||||||
radius: 1.0
|
|
||||||
}
|
|
||||||
contentItem: IconLabel {
|
|
||||||
color: "black"
|
|
||||||
font.family: "Helvetica"
|
|
||||||
text: root.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,38 +48,17 @@ SplitView {
|
|||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
// TODO: Make a ClideBreadCrumb element to support select parent paths as root
|
ClideBreadCrumbs {
|
||||||
Rectangle {
|
id: breadCrumb
|
||||||
color: RustColors.explorer_background
|
|
||||||
height: 25
|
|
||||||
width: navigationView.width
|
|
||||||
|
|
||||||
Text {
|
Layout.bottomMargin: 5
|
||||||
id: breadCrumb
|
Layout.leftMargin: 15
|
||||||
|
Layout.topMargin: 5
|
||||||
|
path: clideTreeView.rootDirectory
|
||||||
|
|
||||||
anchors.fill: parent
|
onCrumbClicked: path => {
|
||||||
color: RustColors.explorer_text
|
Logger.trace("Crumb clicked: " + path);
|
||||||
elide: Text.ElideLeft
|
clideTreeView.rootDirectory = path;
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
text: clideTreeView.rootDirectory
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
TapHandler {
|
|
||||||
acceptedButtons: Qt.RightButton
|
|
||||||
|
|
||||||
onSingleTapped: (eventPoint, button) => contextMenu.popup()
|
|
||||||
}
|
|
||||||
Menu {
|
|
||||||
id: contextMenu
|
|
||||||
|
|
||||||
Action {
|
|
||||||
text: qsTr("Reset root index")
|
|
||||||
|
|
||||||
onTriggered: {
|
|
||||||
Logger.log("Resetting root directory: " + clideTreeView.originalRootDirectory);
|
|
||||||
clideTreeView.rootDirectory = clideTreeView.originalRootDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClideTreeView {
|
ClideTreeView {
|
||||||
@@ -95,7 +74,7 @@ SplitView {
|
|||||||
onFileClicked: path => clideEditor.filePath = path
|
onFileClicked: path => clideEditor.filePath = path
|
||||||
onRootDirectoryChanged: {
|
onRootDirectoryChanged: {
|
||||||
Logger.log("Setting root directory: " + clideTreeView.rootDirectory);
|
Logger.log("Setting root directory: " + clideTreeView.rootDirectory);
|
||||||
breadCrumb.text = clideTreeView.rootDirectory;
|
breadCrumb.path = clideTreeView.rootDirectory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ TreeView {
|
|||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
boundsMovement: Flickable.StopAtBounds
|
boundsMovement: Flickable.StopAtBounds
|
||||||
clip: true
|
clip: true
|
||||||
leftMargin: 5
|
leftMargin: 25
|
||||||
model: FileSystem
|
model: FileSystem
|
||||||
rootIndex: FileSystem.setDirectory(fileSystemTreeView.rootDirectory)
|
rootIndex: FileSystem.setDirectory(fileSystemTreeView.rootDirectory)
|
||||||
|
|
||||||
@@ -57,38 +57,43 @@ TreeView {
|
|||||||
indentation: 12
|
indentation: 12
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: current ? RustColors.explorer_text_selected : "transparent"
|
color: current ? RustColors.explorer_folder_open : "transparent"
|
||||||
radius: 2.5
|
radius: 2.5
|
||||||
}
|
}
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
|
anchors.left: directoryIcon.right
|
||||||
|
anchors.leftMargin: 5
|
||||||
color: RustColors.explorer_text
|
color: RustColors.explorer_text
|
||||||
text: treeDelegate.fileName
|
text: treeDelegate.fileName
|
||||||
}
|
}
|
||||||
indicator: Image {
|
indicator: Label {
|
||||||
id: directoryIcon
|
id: directoryIcon
|
||||||
|
|
||||||
function setSourceImage() {
|
|
||||||
let folderOpen = "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M88.7 223.8L0 375.8 0 96C0 60.7 28.7 32 64 32l117.5 0c17 0 33.3 6.7 45.3 18.7l26.5 26.5c12 12 28.3 18.7 45.3 18.7L416 96c35.3 0 64 28.7 64 64l0 32-336 0c-22.8 0-43.8 12.1-55.3 31.8zm27.6 16.1C122.1 230 132.6 224 144 224l400 0c11.5 0 22 6.1 27.7 16.1s5.7 22.2-.1 32.1l-112 192C453.9 474 443.4 480 432 480L32 480c-11.5 0-22-6.1-27.7-16.1s-5.7-22.2 .1-32.1l112-192z\"/></svg>";
|
|
||||||
let folderClosed = "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z\"/></svg>";
|
|
||||||
let file = "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 288c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128z\"/></svg>";
|
|
||||||
// If the item has children, it's a directory.
|
|
||||||
if (treeDelegate.hasChildren) {
|
|
||||||
return treeDelegate.expanded ? folderOpen : folderClosed;
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
asynchronous: true
|
font.family: localFont.font.family
|
||||||
fillMode: Image.PreserveAspectFit
|
font.pixelSize: 18
|
||||||
smooth: true
|
smooth: true
|
||||||
source: setSourceImage()
|
text: fileSystemTreeView.model.icon(filePath)
|
||||||
sourceSize.height: 15
|
x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation) + (indicator.visible ? indicator.width : 0)
|
||||||
sourceSize.width: 15
|
|
||||||
x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FontLoader {
|
||||||
|
id: localFont
|
||||||
|
|
||||||
|
source: "qrc:/fonts/saucecodepro-xlight.ttf"
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: indicator
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
font.family: localFont.font.family
|
||||||
|
font.pixelSize: 10
|
||||||
|
font.weight: localFont.font.weight
|
||||||
|
text: expanded ? "⮟" : "⮞"
|
||||||
|
visible: isTreeNode && hasChildren
|
||||||
|
x: padding + (depth * indentation)
|
||||||
|
}
|
||||||
MultiEffect {
|
MultiEffect {
|
||||||
id: iconOverlay
|
id: iconOverlay
|
||||||
|
|
||||||
@@ -120,10 +125,8 @@ TreeView {
|
|||||||
case Qt.LeftButton:
|
case Qt.LeftButton:
|
||||||
if (treeDelegate.hasChildren) {
|
if (treeDelegate.hasChildren) {
|
||||||
fileSystemTreeView.toggleExpanded(treeDelegate.row);
|
fileSystemTreeView.toggleExpanded(treeDelegate.row);
|
||||||
// fileSystemTreeView.lastIndex = treeDelegate.index
|
|
||||||
} else {
|
} else {
|
||||||
// If this model item doesn't have children, it means it's
|
// If this model item doesn't have children, it means it's representing a file.
|
||||||
// representing a file.
|
|
||||||
fileSystemTreeView.fileClicked(treeDelegate.filePath);
|
fileSystemTreeView.fileClicked(treeDelegate.filePath);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -133,24 +136,28 @@ TreeView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Menu {
|
ClideMenu {
|
||||||
id: contextMenu
|
id: contextMenu
|
||||||
|
|
||||||
Action {
|
ClideMenuItem {
|
||||||
enabled: treeDelegate.hasChildren
|
action: Action {
|
||||||
text: qsTr("Set as root index")
|
enabled: treeDelegate.hasChildren
|
||||||
|
text: qsTr("Set root")
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
Logger.debug("Setting new root directory: " + treeDelegate.filePath);
|
Logger.debug("Setting new root directory: " + treeDelegate.filePath);
|
||||||
fileSystemTreeView.rootDirectory = treeDelegate.filePath;
|
fileSystemTreeView.rootDirectory = treeDelegate.filePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action {
|
ClideMenuItem {
|
||||||
text: qsTr("Reset root index")
|
action: Action {
|
||||||
|
text: qsTr("Reset root")
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
Logger.log("Resetting root directory: " + fileSystemTreeView.originalRootDirectory);
|
Logger.log("Resetting root directory: " + fileSystemTreeView.originalRootDirectory);
|
||||||
fileSystemTreeView.rootDirectory = fileSystemTreeView.originalRootDirectory;
|
fileSystemTreeView.rootDirectory = fileSystemTreeView.originalRootDirectory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
109
qml/Components/ClideBreadCrumbs.qml
Normal file
109
qml/Components/ClideBreadCrumbs.qml
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import clide.module 1.0
|
||||||
|
import Logger 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var fullPaths: []
|
||||||
|
required property string path
|
||||||
|
property var segments: []
|
||||||
|
|
||||||
|
signal crumbClicked(string path)
|
||||||
|
|
||||||
|
function rebuildSegments() {
|
||||||
|
var cleaned = path;
|
||||||
|
if (cleaned.endsWith("/"))
|
||||||
|
cleaned = cleaned.slice(0, -1);
|
||||||
|
var parts = cleaned.split("/");
|
||||||
|
root.segments = [];
|
||||||
|
root.fullPaths = [];
|
||||||
|
var current = "";
|
||||||
|
Logger.trace("Building segments for path: " + cleaned);
|
||||||
|
for (var i = 0; i < parts.length; ++i) {
|
||||||
|
if (parts[i] === "") {
|
||||||
|
current = "/";
|
||||||
|
root.segments.push("/");
|
||||||
|
root.fullPaths.push("/");
|
||||||
|
} else {
|
||||||
|
if (current === "/")
|
||||||
|
current += parts[i];
|
||||||
|
else
|
||||||
|
current += "/" + parts[i];
|
||||||
|
Logger.trace("Pushing path: " + parts[i] + " Current: " + current);
|
||||||
|
root.segments.push(parts[i]);
|
||||||
|
root.fullPaths.push(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rep.model = root.segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.leftMargin: 20
|
||||||
|
height: breadcrumbRow.implicitHeight
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Component.onCompleted: rebuildSegments()
|
||||||
|
onPathChanged: rebuildSegments()
|
||||||
|
|
||||||
|
Flow {
|
||||||
|
id: breadcrumbRow
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: rep
|
||||||
|
|
||||||
|
model: root.segments
|
||||||
|
|
||||||
|
delegate: Text {
|
||||||
|
id: linkText
|
||||||
|
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
function getText() {
|
||||||
|
if (modelData === "/") {
|
||||||
|
return modelData;
|
||||||
|
}
|
||||||
|
Logger.trace("Getting valid text:" + modelData);
|
||||||
|
return modelData + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
color: mouseArea.containsMouse ? "#2a7fff" : RustColors.explorer_text
|
||||||
|
font.underline: mouseArea.containsMouse
|
||||||
|
text: getText()
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
console.log("Breadcrumb clicked:", root.fullPaths[root.segments.indexOf(modelData)]);
|
||||||
|
root.crumbClicked(root.fullPaths[root.segments.indexOf(modelData)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
|
||||||
|
onSingleTapped: (eventPoint, button) => contextMenu.popup()
|
||||||
|
}
|
||||||
|
ClideMenu {
|
||||||
|
id: contextMenu
|
||||||
|
|
||||||
|
ClideMenuItem {
|
||||||
|
action: Action {
|
||||||
|
text: qsTr("Reset root")
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
Logger.log("Resetting root directory: " + clideTreeView.originalRootDirectory);
|
||||||
|
clideTreeView.rootDirectory = clideTreeView.originalRootDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
qml/Components/ClideMenu.qml
Normal file
14
qml/Components/ClideMenu.qml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls.Basic
|
||||||
|
|
||||||
|
import clide.module 1.0
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
background: Rectangle {
|
||||||
|
border.color: RustColors.hovered
|
||||||
|
border.width: 10
|
||||||
|
color: RustColors.menubar
|
||||||
|
implicitWidth: 100
|
||||||
|
radius: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
18
qml/Components/ClideMenuItem.qml
Normal file
18
qml/Components/ClideMenuItem.qml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls.Basic
|
||||||
|
|
||||||
|
import clide.module 1.0
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: root.hovered ? RustColors.hovered : RustColors.unhovered
|
||||||
|
radius: 1.0
|
||||||
|
}
|
||||||
|
contentItem: IconLabel {
|
||||||
|
color: "black"
|
||||||
|
font.family: "Helvetica"
|
||||||
|
text: root.text
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
ClideScrollBar ClideScrollBar.qml
|
ClideScrollBar ClideScrollBar.qml
|
||||||
ClideHandle ClideHandle.qml
|
ClideHandle ClideHandle.qml
|
||||||
|
ClideMenu ClideMenu.qml
|
||||||
|
ClideMenuItem ClideMenuItem.qml
|
||||||
|
ClideBreadCrumbs ClideBreadCrumbs.qml
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/images">
|
<qresource prefix="/images">
|
||||||
<file alias="kilroy.png">images/kilroy-256.png</file>
|
<file alias="kilroy.png">resources/images/kilroy-256.png</file>
|
||||||
|
</qresource>
|
||||||
|
<qresource prefix="/fonts">
|
||||||
|
<file alias="saucecodepro.ttf">resources/SauceCodeProNerdFont-Black.ttf</file>
|
||||||
|
<file alias="saucecodepro-light.ttf">resources/SauceCodeProNerdFont-Light.ttf</file>
|
||||||
|
<file alias="saucecodepro-xlight.ttf">resources/SauceCodeProNerdFont-ExtraLight.ttf</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
BIN
resources/SauceCodeProNerdFont-Black.ttf
Normal file
BIN
resources/SauceCodeProNerdFont-Black.ttf
Normal file
Binary file not shown.
BIN
resources/SauceCodeProNerdFont-ExtraLight.ttf
Normal file
BIN
resources/SauceCodeProNerdFont-ExtraLight.ttf
Normal file
Binary file not shown.
BIN
resources/SauceCodeProNerdFont-Light.ttf
Normal file
BIN
resources/SauceCodeProNerdFont-Light.ttf
Normal file
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@@ -103,7 +103,7 @@ impl Default for RustColorsImpl {
|
|||||||
explorer_text_selected: QColor::try_from("#262626").unwrap(),
|
explorer_text_selected: QColor::try_from("#262626").unwrap(),
|
||||||
explorer_background: QColor::try_from("#1E1F22").unwrap(),
|
explorer_background: QColor::try_from("#1E1F22").unwrap(),
|
||||||
explorer_folder: QColor::try_from("#54585b").unwrap(),
|
explorer_folder: QColor::try_from("#54585b").unwrap(),
|
||||||
explorer_folder_open: QColor::try_from("#2b2b2b").unwrap(),
|
explorer_folder_open: QColor::try_from("#393B40").unwrap(),
|
||||||
terminal_background: QColor::try_from("#111111").unwrap(),
|
terminal_background: QColor::try_from("#111111").unwrap(),
|
||||||
info_log: QColor::try_from("#C4FFFF").unwrap(),
|
info_log: QColor::try_from("#C4FFFF").unwrap(),
|
||||||
debug_log: QColor::try_from("#9148AF").unwrap(),
|
debug_log: QColor::try_from("#9148AF").unwrap(),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: GNU General Public License v3.0 or later
|
// SPDX-License-Identifier: GNU General Public License v3.0 or later
|
||||||
|
|
||||||
use cxx_qt_lib::{QModelIndex, QString};
|
use cxx_qt_lib::{QModelIndex, QString};
|
||||||
|
use devicons::FileIcon;
|
||||||
use dirs;
|
use dirs;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@@ -52,6 +53,9 @@ pub mod qobject {
|
|||||||
#[qinvokable]
|
#[qinvokable]
|
||||||
#[cxx_name = "setDirectory"]
|
#[cxx_name = "setDirectory"]
|
||||||
fn set_directory(self: Pin<&mut FileSystem>, path: &QString) -> QModelIndex;
|
fn set_directory(self: Pin<&mut FileSystem>, path: &QString) -> QModelIndex;
|
||||||
|
|
||||||
|
#[qinvokable]
|
||||||
|
fn icon(self: Pin<&mut FileSystem>, path: &QString) -> QString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +107,7 @@ impl qobject::FileSystem {
|
|||||||
|
|
||||||
append_highlighted_html_for_styled_line(
|
append_highlighted_html_for_styled_line(
|
||||||
®ions[..],
|
®ions[..],
|
||||||
IncludeBackground::Yes,
|
IncludeBackground::No,
|
||||||
&mut output,
|
&mut output,
|
||||||
)
|
)
|
||||||
.expect("Failed to insert highlighted html");
|
.expect("Failed to insert highlighted html");
|
||||||
@@ -139,4 +143,15 @@ impl qobject::FileSystem {
|
|||||||
self.set_root_path(&QString::from(homedir))
|
self.set_root_path(&QString::from(homedir))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(self: std::pin::Pin<&mut Self>, path: &QString) -> QString {
|
||||||
|
let str = path.to_string();
|
||||||
|
if Path::new(&str).is_dir() {
|
||||||
|
// Ensures directories are given a folder icon and not mistakenly resolved to a language.
|
||||||
|
// For example, a directory named `cpp` would otherwise return a C++ icon.
|
||||||
|
return QString::from(FileIcon::from("dir/").to_string())
|
||||||
|
}
|
||||||
|
let icon = FileIcon::from(str);
|
||||||
|
QString::from(icon.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user