diff options
Diffstat (limited to 'examples/quickcontrols/filesystemexplorer/FileSystemModule/qml')
9 files changed, 831 insertions, 0 deletions
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml new file mode 100644 index 000000000..178bf03e4 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml @@ -0,0 +1,93 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls.Basic +import FileSystemModule + +ApplicationWindow { + id: root + width: 650 + height: 550 + flags: Qt.Window | Qt.FramelessWindowHint + color: Colors.surface1 + + menuBar: MyMenuBar { + id: menuBar + + dragWindow: root + implicitHeight: 27 + infoText: "About Qt" + } + + Image { + id: logo + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 20 + + source: "../icons/qt_logo.svg" + sourceSize.width: 80 + sourceSize.height: 80 + fillMode: Image.PreserveAspectFit + + smooth: true + antialiasing: true + asynchronous: true + } + + ScrollView { + anchors.top: logo.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 20 + + TextArea { + selectedTextColor: Colors.textFile + selectionColor: Colors.selection + horizontalAlignment: Text.AlignHCenter + textFormat: Text.RichText + + text: qsTr("<h3>About Qt</h3>" + + "<p>This program uses Qt version %1.</p>" + + "<p>Qt is a C++ toolkit for cross-platform application " + + "development.</p>" + + "<p>Qt provides single-source portability across all major desktop " + + "operating systems. It is also available for embedded Linux and other " + + "embedded and mobile operating systems.</p>" + + "<p>Qt is available under multiple licensing options designed " + + "to accommodate the needs of our various users.</p>" + + "<p>Qt licensed under our commercial license agreement is appropriate " + + "for development of proprietary/commercial software where you do not " + + "want to share any source code with third parties or otherwise cannot " + + "comply with the terms of GNU (L)GPL.</p>" + + "<p>Qt licensed under GNU (L)GPL is appropriate for the " + + "development of Qt applications provided you can comply with the terms " + + "and conditions of the respective licenses.</p>" + + "<p>Please see <a href=\"http://%2/\">%2</a> " + + "for an overview of Qt licensing.</p>" + + "<p>Copyright (C) %3 The Qt Company Ltd and other " + + "contributors.</p>" + + "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>" + + "<p>Qt is The Qt Company Ltd product developed as an open source " + + "project. See <a href=\"http://%4/\">%4</a> for more information.</p>") + .arg(Application.version).arg("qt.io/licensing").arg("2023").arg("qt.io") + color: Colors.textFile + wrapMode: Text.WordWrap + readOnly: true + antialiasing: true + background: null + + onLinkActivated: function(link) { + Qt.openUrlExternally(link) + } + } + } + + ResizeButton { + resizeWindow: root + } +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml new file mode 100644 index 000000000..285667773 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml @@ -0,0 +1,23 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +pragma Singleton + +QtObject { + readonly property color background: "#292828" + readonly property color surface1: "#171819" + readonly property color surface2: "#090A0C" + readonly property color text: "#D4BE98" + readonly property color textFile: "#E1D2B7" + readonly property color disabledText: "#2C313A" + readonly property color selection: "#4B4A4A" + readonly property color active: "#292828" + readonly property color inactive: "#383737" + readonly property color folder: "#383737" + readonly property color icon: "#383737" + readonly property color iconIndicator: "#D5B35D" + readonly property color color1: "#A7B464" + readonly property color color2: "#D3869B" +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml new file mode 100644 index 000000000..80f7c04c5 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml @@ -0,0 +1,160 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import FileSystemModule + +pragma ComponentBehavior: Bound + +// This is the text editor that displays the currently open file, including +// their corresponding line numbers. +Rectangle { + id: root + + required property string currentFilePath + required property bool showLineNumbers + property alias text: textArea + property int currentLineNumber: -1 + property int rowHeight: Math.ceil(fontMetrics.lineSpacing) + + color: Colors.background + + onWidthChanged: textArea.update() + onHeightChanged: textArea.update() + + RowLayout { + anchors.fill: parent + // 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 + + // Calculate the width based on the logarithmic scale. + Layout.preferredWidth: fontMetrics.averageCharacterWidth + * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10 + Layout.fillHeight: true + + interactive: false + contentY: editorFlickable.contentY + visible: textArea.text !== "" && root.showLineNumbers + + Column { + anchors.fill: parent + Repeater { + id: repeatedLineNumbers + + model: LineNumberModel { + lineCount: textArea.text !== "" ? textArea.lineCount : 0 + } + + delegate: Item { + required property int index + + width: parent.width + height: root.rowHeight + Label { + id: numbers + + text: parent.index + 1 + + width: parent.width + height: parent.height + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + color: (root.currentLineNumber === parent.index) + ? Colors.iconIndicator : Qt.darker(Colors.text, 2) + font: textArea.font + } + Rectangle { + id: indicator + + anchors.left: numbers.right + width: 1 + height: parent.height + color: Qt.darker(Colors.text, 3) + } + } + } + } + } + + Flickable { + id: editorFlickable + + property alias textArea: textArea + + // 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 { + implicitWidth: scrollBar.interactive ? 8 : 4 + implicitHeight: scrollBar.interactive ? 8 : 4 + + opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0 + color: Colors.background + Behavior on opacity { + OpacityAnimator { + duration: 500 + } + } + } + contentItem: Rectangle { + implicitWidth: scrollBar.interactive ? 8 : 4 + implicitHeight: scrollBar.interactive ? 8 : 4 + opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0 + color: Colors.color1 + Behavior on opacity { + OpacityAnimator { + duration: 1000 + } + } + } + } + + Layout.fillHeight: true + Layout.fillWidth: true + ScrollBar.horizontal: MyScrollBar {} + ScrollBar.vertical: MyScrollBar {} + + boundsBehavior: Flickable.StopAtBounds + + TextArea.flickable: TextArea { + id: textArea + anchors.fill: parent + + focus: false + topPadding: 0 + leftPadding: 10 + + text: FileSystemModel.readFile(root.currentFilePath) + tabStopDistance: fontMetrics.averageCharacterWidth * 4 + + // Grab the current line number from the C++ interface. + onCursorPositionChanged: { + root.currentLineNumber = FileSystemModel.currentLineNumber( + textArea.textDocument, textArea.cursorPosition) + } + + color: Colors.textFile + selectedTextColor: Colors.textFile + selectionColor: Colors.selection + + textFormat: TextEdit.PlainText + renderType: Text.QtRendering + selectByMouse: true + antialiasing: true + background: null + } + + FontMetrics { + id: fontMetrics + font: textArea.font + } + } + } +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml new file mode 100644 index 000000000..db955168c --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml @@ -0,0 +1,156 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Effects +import QtQuick.Controls.Basic +import FileSystemModule + +pragma ComponentBehavior: Bound + +// This is the file system view which gets populated by the C++ model. +Rectangle { + id: root + + signal fileClicked(string filePath) + property alias rootIndex: fileSystemTreeView.rootIndex + + TreeView { + id: fileSystemTreeView + + property int lastIndex: -1 + + anchors.fill: parent + model: FileSystemModel + rootIndex: FileSystemModel.rootIndex + boundsBehavior: Flickable.StopAtBounds + boundsMovement: Flickable.StopAtBounds + clip: true + + Component.onCompleted: fileSystemTreeView.toggleExpanded(0) + + // The delegate represents a single entry in the filesystem. + delegate: TreeViewDelegate { + id: treeDelegate + indentation: 8 + implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250 + implicitHeight: 25 + + // Since we have the 'ComponentBehavior Bound' pragma, we need to + // require these properties from our model. This is a convenient way + // to bind the properties provided by the model's role names. + required property int index + required property url filePath + required property string fileName + + indicator: Image { + id: directoryIcon + + x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation) + anchors.verticalCenter: parent.verticalCenter + source: treeDelegate.hasChildren ? (treeDelegate.expanded + ? "../icons/folder_open.svg" : "../icons/folder_closed.svg") + : "../icons/generic_file.svg" + sourceSize.width: 20 + sourceSize.height: 20 + fillMode: Image.PreserveAspectFit + + smooth: true + antialiasing: true + asynchronous: true + } + + contentItem: Text { + text: treeDelegate.fileName + color: Colors.text + } + + background: Rectangle { + color: (treeDelegate.index === fileSystemTreeView.lastIndex) + ? Colors.selection + : (hoverHandler.hovered ? Colors.active : "transparent") + } + + // We color the directory icons with this MultiEffect, where we overlay + // the colorization color ontop of the SVG icons. + MultiEffect { + id: iconOverlay + + anchors.fill: directoryIcon + source: directoryIcon + colorization: 1.0 + brightness: 1.0 + colorizationColor: { + const isFile = treeDelegate.index === fileSystemTreeView.lastIndex + && !treeDelegate.hasChildren; + if (isFile) + return Qt.lighter(Colors.folder, 3) + + const isExpandedFolder = treeDelegate.expanded && treeDelegate.hasChildren; + if (isExpandedFolder) + return Colors.color2 + else + return Colors.folder + } + } + + HoverHandler { + id: hoverHandler + } + + TapHandler { + acceptedButtons: Qt.LeftButton | Qt.RightButton + onSingleTapped: (eventPoint, button) => { + switch (button) { + case Qt.LeftButton: + fileSystemTreeView.toggleExpanded(treeDelegate.row) + fileSystemTreeView.lastIndex = treeDelegate.index + // If this model item doesn't have children, it means it's + // representing a file. + if (!treeDelegate.hasChildren) + root.fileClicked(treeDelegate.filePath) + break; + case Qt.RightButton: + if (treeDelegate.hasChildren) + contextMenu.popup(); + break; + } + } + } + + MyMenu { + id: contextMenu + Action { + text: qsTr("Set as root index") + onTriggered: { + fileSystemTreeView.rootIndex = fileSystemTreeView.index(treeDelegate.row, 0) + } + } + Action { + text: qsTr("Reset root index") + onTriggered: fileSystemTreeView.rootIndex = undefined + } + } + } + + // Provide our own custom ScrollIndicator for the TreeView. + ScrollIndicator.vertical: ScrollIndicator { + active: true + implicitWidth: 15 + + contentItem: Rectangle { + implicitWidth: 6 + implicitHeight: 6 + + color: Colors.color1 + opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0 + + Behavior on opacity { + OpacityAnimator { + duration: 500 + } + } + } + } + } +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml new file mode 100644 index 000000000..1f1d30c56 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml @@ -0,0 +1,45 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls.Basic +import FileSystemModule + +Menu { + id: root + + delegate: MenuItem { + id: menuItem + contentItem: Item { + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 5 + + text: menuItem.text + color: enabled ? Colors.text : Colors.disabledText + } + Rectangle { + id: indicator + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + width: 6 + height: parent.height + + visible: menuItem.highlighted + color: Colors.color2 + } + } + background: Rectangle { + implicitWidth: 210 + implicitHeight: 35 + color: menuItem.highlighted ? Colors.active : "transparent" + } + } + background: Rectangle { + implicitWidth: 210 + implicitHeight: 35 + color: Colors.surface2 + } +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml new file mode 100644 index 000000000..4874a2c03 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml @@ -0,0 +1,177 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic +import FileSystemModule + +// The MenuBar also serves as a controller for our window as we don't use any decorations. +MenuBar { + id: root + + required property ApplicationWindow dragWindow + property alias infoText: windowInfo.text + + // Customization of the top level menus inside the MenuBar + delegate: MenuBarItem { + id: menuBarItem + + contentItem: Text { + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + text: menuBarItem.text + font: menuBarItem.font + elide: Text.ElideRight + color: menuBarItem.highlighted ? Colors.textFile : Colors.text + opacity: enabled ? 1.0 : 0.3 + } + + background: Rectangle { + id: background + + color: menuBarItem.highlighted ? Colors.selection : "transparent" + Rectangle { + id: indicator + + width: 0; height: 3 + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + color: Colors.color1 + states: State { + name: "active" + when: menuBarItem.highlighted + PropertyChanges { + indicator.width: background.width - 2 + } + } + transitions: Transition { + NumberAnimation { + properties: "width" + duration: 175 + } + } + } + } + } + // We use the contentItem property as a place to attach our window decorations. Beneath + // the usual menu entries within a MenuBar, it includes a centered information text, along + // with the minimize, maximize, and close buttons. + contentItem: RowLayout { + id: windowBar + + Layout.fillWidth: true + Layout.fillHeight: true + + spacing: root.spacing + Repeater { + id: menuBarItems + + Layout.alignment: Qt.AlignLeft + model: root.contentModel + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Text { + id: windowInfo + + width: parent.width; height: parent.height + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + leftPadding: windowActions.width + color: Colors.text + clip: true + } + } + + RowLayout { + id: windowActions + + Layout.alignment: Qt.AlignRight + Layout.fillHeight: true + + spacing: 0 + + component InteractionButton: Rectangle { + id: interactionButton + + signal action() + property alias hovered: hoverHandler.hovered + + Layout.fillHeight: true + Layout.preferredWidth: height + + color: hovered ? Colors.background : "transparent" + HoverHandler { + id: hoverHandler + } + TapHandler { + id: tapHandler + onTapped: interactionButton.action() + } + } + + InteractionButton { + id: minimize + + onAction: root.dragWindow.showMinimized() + Rectangle { + anchors.centerIn: parent + color: parent.hovered ? Colors.iconIndicator : Colors.icon + height: 2 + width: parent.height - 14 + } + } + + InteractionButton { + id: maximize + + onAction: root.dragWindow.showMaximized() + Rectangle { + anchors.fill: parent + anchors.margins: 7 + border.color: parent.hovered ? Colors.iconIndicator : Colors.icon + border.width: 2 + color: "transparent" + } + } + + InteractionButton { + id: close + + color: hovered ? "#ec4143" : "transparent" + onAction: root.dragWindow.close() + Rectangle { + anchors.centerIn: parent + width: parent.height - 8; height: 2 + + rotation: 45 + antialiasing: true + transformOrigin: Item.Center + color: parent.hovered ? Colors.iconIndicator : Colors.icon + + Rectangle { + anchors.centerIn: parent + width: parent.height + height: parent.width + + antialiasing: true + color: parent.color + } + } + } + } + } + + background: Rectangle { + color: Colors.surface2 + // Make the empty space drag the specified root window. + WindowDragHandler { + dragWindow: root.dragWindow + } + } +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml new file mode 100644 index 000000000..0df65bf82 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml @@ -0,0 +1,23 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick.Controls +import FileSystemModule + +Button { + required property ApplicationWindow resizeWindow + + icon.width: 20; icon.height: 20 + anchors.right: parent.right + anchors.bottom: parent.bottom + rightPadding: 3 + bottomPadding: 3 + + icon.source: "../icons/resize.svg" + icon.color: hovered ? Colors.iconIndicator : Colors.icon + + background: null + checkable: false + display: AbstractButton.IconOnly + onPressed: resizeWindow.startSystemResize(Qt.BottomEdge | Qt.RightEdge) +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml new file mode 100644 index 000000000..aac530394 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml @@ -0,0 +1,138 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic +import FileSystemModule + +Rectangle { + id: root + + property alias currentTabIndex: topBar.currentIndex + required property ApplicationWindow dragWindow + readonly property int tabBarSpacing: 10 + + color: Colors.surface2 + + component SidebarEntry: Button { + id: sidebarButton + + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + + icon.color: down || checked ? Colors.iconIndicator : Colors.icon + icon.width: 27 + icon.height: 27 + + topPadding: 0 + rightPadding: 0 + bottomPadding: 0 + leftPadding: 0 + background: null + + Rectangle { + id: indicator + + anchors.verticalCenter: parent.verticalCenter + x: 2 + width: 4 + height: sidebarButton.icon.height * 1.2 + + visible: sidebarButton.checked + color: Colors.color1 + } + } + + // TabBar is designed to be horizontal, whereas we need a vertical bar. + // We can easily achieve that by using a Container. + component TabBar: Container { + id: tabBarComponent + + Layout.fillWidth: true + // ButtonGroup ensures that only one button can be checked at a time. + ButtonGroup { + buttons: tabBarComponent.contentChildren + + // We have to manage the currentIndex ourselves, which we do by setting it to the index + // of the currently checked button. We use setCurrentIndex instead of setting the + // currentIndex property to avoid breaking bindings. See "Managing the Current Index" + // in Container's documentation for more information. + onCheckedButtonChanged: tabBarComponent.setCurrentIndex( + Math.max(0, buttons.indexOf(checkedButton))) + } + + contentItem: ColumnLayout { + spacing: tabBarComponent.spacing + Repeater { + model: tabBarComponent.contentModel + } + } + } + + ColumnLayout { + anchors.fill: root + anchors.topMargin: root.tabBarSpacing + anchors.bottomMargin: root.tabBarSpacing + + spacing: root.tabBarSpacing + TabBar { + id: topBar + + spacing: root.tabBarSpacing + // Shows help text when clicked. + SidebarEntry { + id: infoTab + icon.source: "../icons/light_bulb.svg" + checkable: true + checked: true + } + + // Shows the file system when clicked. + SidebarEntry { + id: filesystemTab + + icon.source: "../icons/read.svg" + checkable: true + } + } + + // This item acts as a spacer to expand between the checkable and non-checkable buttons. + Item { + Layout.fillHeight: true + Layout.fillWidth: true + + // Make the empty space drag our main window. + WindowDragHandler { + dragWindow: root.dragWindow + } + } + + TabBar { + id: bottomBar + + spacing: root.tabBarSpacing + // Opens the Qt website in the system's web browser. + SidebarEntry { + id: qtWebsiteButton + icon.source: "../icons/globe.svg" + checkable: false + onClicked: Qt.openUrlExternally("https://www.qt.io/") + } + + // Opens the About Qt Window. + SidebarEntry { + id: aboutQtButton + + icon.source: "../icons/info_sign.svg" + checkable: false + onClicked: aboutQtWindow.visible = !aboutQtWindow.visible + } + } + } + + About { + id: aboutQtWindow + visible: false + } +} diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/WindowDragHandler.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/WindowDragHandler.qml new file mode 100644 index 000000000..0e140aca3 --- /dev/null +++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/WindowDragHandler.qml @@ -0,0 +1,16 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls + +// Allows dragging the window when placed on an unused section of the UI. +DragHandler { + + required property ApplicationWindow dragWindow + + target: null + onActiveChanged: { + if (active) dragWindow.startSystemMove() + } +} |