From 78966dc00419a4f5fe5fec4725062a4a0f380228 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Sun, 5 Jul 2015 15:11:13 +0200 Subject: Embedded QML into C++ application --- EmbeddedTerminal.qml | 88 ------------------------- MetaTerm.pro | 7 ++ MetaTerm.qml | 168 ----------------------------------------------- ScrollBar.qml | 78 ---------------------- TerminalItem.qml | 118 --------------------------------- main.cpp | 19 ++++++ qml/EmbeddedTerminal.qml | 88 +++++++++++++++++++++++++ qml/ScrollBar.qml | 78 ++++++++++++++++++++++ qml/TerminalItem.qml | 118 +++++++++++++++++++++++++++++++++ qml/main.qml | 168 +++++++++++++++++++++++++++++++++++++++++++++++ qml/ui.qrc | 8 +++ 11 files changed, 486 insertions(+), 452 deletions(-) delete mode 100644 EmbeddedTerminal.qml create mode 100644 MetaTerm.pro delete mode 100644 MetaTerm.qml delete mode 100644 ScrollBar.qml delete mode 100644 TerminalItem.qml create mode 100644 main.cpp create mode 100644 qml/EmbeddedTerminal.qml create mode 100644 qml/ScrollBar.qml create mode 100644 qml/TerminalItem.qml create mode 100644 qml/main.qml create mode 100644 qml/ui.qrc diff --git a/EmbeddedTerminal.qml b/EmbeddedTerminal.qml deleted file mode 100644 index f4f104e..0000000 --- a/EmbeddedTerminal.qml +++ /dev/null @@ -1,88 +0,0 @@ -import QtQuick 2.0 -import QMLTermWidget 1.0 -import QtQuick.Controls 1.2 - -Item { - id: embeddedTerminal - property string program - property string workingDirectory - property int columns - property int lines - - width: container.width - height: container.height - - function select() { highlighter.select() } - function deselect() { highlighter.deselect() } - - Row { - id: container - - Rectangle { - id: highlighter - - width: 10 - height: terminal.height - - color: "#909636" - - Behavior on opacity { - NumberAnimation { - duration: 300 - easing.type: Easing.OutCubic - } - } - - function select() { opacity = 1 } - function deselect() { opacity = 0 } - function focus() { color = "#352F6A" } - function unfocus() { color = "#909636" } - } - - Rectangle { - width: terminal.width - height: terminal.height - - color: "#ffffff" - - QMLTermWidget { - id: terminal - - font.family: "Monospace" - font.pointSize: 8 - - width: fontMetrics.width * embeddedTerminal.columns - height: fontMetrics.height * embeddedTerminal.lines - - session: QMLTermSession { - initialWorkingDirectory: embeddedTerminal.workingDirectory - - shellProgram: { - return (embeddedTerminal.program).split(" ")[0]; - } - - shellProgramArgs: { - var elements = (embeddedTerminal.program).split(" "); - elements.shift(); - - return elements; - } - } - - onTermGetFocus: highlighter.focus() - onTermLostFocus: highlighter.unfocus() - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - onWheel: { } - } - - Component.onCompleted: { - terminal.forceActiveFocus(); - session.startShellProgram(); - } - } - } - } -} diff --git a/MetaTerm.pro b/MetaTerm.pro new file mode 100644 index 0000000..532ba39 --- /dev/null +++ b/MetaTerm.pro @@ -0,0 +1,7 @@ +TEMPLATE = app + +QT += qml quick widgets + +SOURCES += main.cpp + +RESOURCES += qml/ui.qrc diff --git a/MetaTerm.qml b/MetaTerm.qml deleted file mode 100644 index 9ee41a3..0000000 --- a/MetaTerm.qml +++ /dev/null @@ -1,168 +0,0 @@ -import QtQuick 2.0 -import QMLTermWidget 1.0 -import QtQuick.Controls 1.2 - - -Rectangle { - id: root - anchors.fill: parent - - color: "#161616" - - Component.onCompleted: terminalList.focusCurrent() - - Flickable { - id: terminalListFlickable - anchors.fill: parent - - boundsBehavior: Flickable.StopAtBounds - contentHeight: terminalList.height - contentWidth: terminalList.width - pixelAligned: true - - Column { - id: terminalList - spacing: 10 - - property int activeItem : 0 - - onHeightChanged: scrollTo(activeItem) - - function createItem() { - var terminalItem = Qt.createComponent("TerminalItem.qml"); - var instantiateTerminal = function() { - var instance = terminalItem.createObject(terminalList, { - "width": terminalListFlickable.width - }); - instance.onExecuted.connect(createItem); - } - - if ( terminalItem.status == Component.Ready ) { - instantiateTerminal(); - } else { - terminalItem.statusChanged.connect(instantiateTerminal); - } - } - - function scrollTo(index) { - if ( terminalList.height >= terminalListFlickable.height ) { - var offset = children[index].y - + (children[index].height / 2) - - (terminalListFlickable.height / 2); - - var bound = terminalList.height - - terminalListFlickable.height; - - if ( offset < 0 ) { - terminalListFlickable.contentY = 0; - } else if ( offset >= bound ) { - terminalListFlickable.contentY = bound; - } else { - terminalListFlickable.contentY = offset; - } - } - } - - function selectItem(index) { - children[activeItem].deselect(); - children[index ].select(); - - activeItem = index; - - scrollTo(index); - } - - function selectNext() { - if ( activeItem < (children.length - 1) ) { - selectItem(activeItem + 1); - } else { - insertTerminalAction.trigger(); - } - } - - function selectPrev() { - if ( activeItem > 0 ) { - selectItem(activeItem - 1); - } - } - - function focusCurrent() { - children[activeItem].forceActiveFocus(); - } - - function unfocusCurrent() { - children[activeItem].unfocus(); - } - - TerminalItem { - width: terminalListFlickable.width - onExecuted: terminalList.createItem() - } - } - } - - Action { - id: insertTerminalAction - shortcut: "i" - enabled: false - onTriggered: { - escapeTerminalAction.enabled = true; - insertTerminalAction.enabled = false; - nextTerminalAction.enabled = false; - prevTerminalAction.enabled = false; - lastTerminalAction.enabled = false; - firstTerminalAction.enabled = false; - - terminalList.focusCurrent(); - } - } - - Action { - id: escapeTerminalAction - shortcut: "Shift+ESC" - onTriggered: { - escapeTerminalAction.enabled = false; - insertTerminalAction.enabled = true; - nextTerminalAction.enabled = true; - prevTerminalAction.enabled = true; - lastTerminalAction.enabled = true; - firstTerminalAction.enabled = true; - - root.forceActiveFocus(); - terminalList.unfocusCurrent(); - } - } - - Action { - id: nextTerminalAction - shortcut: "j" - enabled: false - onTriggered: terminalList.selectNext() - } - - Action { - id: prevTerminalAction - shortcut: "k" - enabled: false - onTriggered: terminalList.selectPrev() - } - - Action { - id: lastTerminalAction - shortcut: "Shift+G" - enabled: false - onTriggered: terminalList.selectItem(terminalList.children.length - 1) - } - - Action { - id: firstTerminalAction - shortcut: "g" - enabled: false - onTriggered: terminalList.selectItem(0) - } - - ScrollBar { - flickable: terminalListFlickable - handleSize: 10 - } -} diff --git a/ScrollBar.qml b/ScrollBar.qml deleted file mode 100644 index 18f149c..0000000 --- a/ScrollBar.qml +++ /dev/null @@ -1,78 +0,0 @@ -import QtQuick 2.0; - -Item { - id: scrollbar - width: (handleSize + 2) - visible: (flickable.visibleArea.heightRatio < 1.0) - - anchors { - top: flickable.top - right: flickable.right - bottom: flickable.bottom - } - - property Flickable flickable - property int handleSize - - Item { - id: bar - - anchors.fill: parent - - Rectangle { - anchors.fill: parent - color: "black" - opacity: 0.5 - } - - MouseArea { - id: control - anchors.fill: parent - - drag { - target: handle - minimumY: 0 - maximumY: (bar.height - handle.height) - axis: Drag.YAxis - } - - onClicked: { - flickable.contentY = (mouse.y / bar.height * (flickable.contentHeight - flickable.height)); - } - } - - Item { - id: handle; - height: Math.max(20, (flickable.visibleArea.heightRatio * bar.height)) - - anchors { - left: parent.left - right: parent.right - } - - Rectangle { - id: backHandle - anchors { - fill: parent - margins: 1 - } - - color: (control.pressed ? "gray" : "white") - } - } - } - - Binding { - target: handle - property: "y" - value: (flickable.contentY * control.drag.maximumY / (flickable.contentHeight - flickable.height)) - when: (!control.drag.active) - } - - Binding { - target: flickable - property: "contentY" - value: (handle.y * (flickable.contentHeight - flickable.height) / control.drag.maximumY) - when: (control.drag.active || control.pressed) - } -} diff --git a/TerminalItem.qml b/TerminalItem.qml deleted file mode 100644 index 883d911..0000000 --- a/TerminalItem.qml +++ /dev/null @@ -1,118 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.1 - -Item { - id: terminalItem - signal executed - - height: elementList.height - - function select() { - if ( command.readOnly ) { - elementList.children[1].select(); - } else { - highlighter.select(); - } - } - - function deselect() { - if ( command.readOnly ) { - elementList.children[1].deselect(); - } else { - highlighter.deselect(); - } - } - - function forceActiveFocus() { - if ( command.readOnly ) { - scope.forceActiveFocus(); - } else { - scope.forceActiveFocus(); - highlighter.select(); - highlighter.focus(); - } - } - - function unfocus() { - if ( !command.readOnly ) { - highlighter.unfocus(); - } - } - - FocusScope { - id: scope - - Column { - id: elementList - - function createTerminal(program) { - var terminal = Qt.createComponent("EmbeddedTerminal.qml"); - var instantiateTerminal = function() { - terminal.createObject(elementList, { - "columns": 90, - "lines": 20, - "program": program, - "workingDirectory": "$HOME", - "focus": true - }); - } - - if ( terminal.status == Component.Ready ) { - instantiateTerminal(); - } else { - terminal.statusChanged.connect(instantiateTerminal); - } - } - - RowLayout { - width: terminalItem.width - - Rectangle { - id: highlighter - - width: 10 - height: command.height - opacity: 0 - - color: "#909636" - - Behavior on opacity { - NumberAnimation { - duration: 300 - easing.type: Easing.OutCubic - } - } - - function select() { opacity = 1 } - function deselect() { opacity = 0 } - function focus() { color = "#352F6A" } - function unfocus() { color = "#909636" } - } - - TextInput { - id: command - - font.pointSize: 18 - color: "white" - selectedTextColor: "#161616" - selectionColor: "white" - selectByMouse: true - focus: true - - Layout.fillWidth: true - - onAccepted: { - if ( !readOnly ) { - readOnly = true; - focus = false; - elementList.createTerminal(text); - terminalItem.executed(); - highlighter.deselect(); - } - } - } - } - } - } -} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..8f7eafc --- /dev/null +++ b/main.cpp @@ -0,0 +1,19 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QQmlApplicationEngine engine; + + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + QObject::connect( + static_cast(&engine), + SIGNAL(quit()), + static_cast(&app), + SLOT(quit()) + ); + + return app.exec(); +} diff --git a/qml/EmbeddedTerminal.qml b/qml/EmbeddedTerminal.qml new file mode 100644 index 0000000..f4f104e --- /dev/null +++ b/qml/EmbeddedTerminal.qml @@ -0,0 +1,88 @@ +import QtQuick 2.0 +import QMLTermWidget 1.0 +import QtQuick.Controls 1.2 + +Item { + id: embeddedTerminal + property string program + property string workingDirectory + property int columns + property int lines + + width: container.width + height: container.height + + function select() { highlighter.select() } + function deselect() { highlighter.deselect() } + + Row { + id: container + + Rectangle { + id: highlighter + + width: 10 + height: terminal.height + + color: "#909636" + + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + } + + function select() { opacity = 1 } + function deselect() { opacity = 0 } + function focus() { color = "#352F6A" } + function unfocus() { color = "#909636" } + } + + Rectangle { + width: terminal.width + height: terminal.height + + color: "#ffffff" + + QMLTermWidget { + id: terminal + + font.family: "Monospace" + font.pointSize: 8 + + width: fontMetrics.width * embeddedTerminal.columns + height: fontMetrics.height * embeddedTerminal.lines + + session: QMLTermSession { + initialWorkingDirectory: embeddedTerminal.workingDirectory + + shellProgram: { + return (embeddedTerminal.program).split(" ")[0]; + } + + shellProgramArgs: { + var elements = (embeddedTerminal.program).split(" "); + elements.shift(); + + return elements; + } + } + + onTermGetFocus: highlighter.focus() + onTermLostFocus: highlighter.unfocus() + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + onWheel: { } + } + + Component.onCompleted: { + terminal.forceActiveFocus(); + session.startShellProgram(); + } + } + } + } +} diff --git a/qml/ScrollBar.qml b/qml/ScrollBar.qml new file mode 100644 index 0000000..18f149c --- /dev/null +++ b/qml/ScrollBar.qml @@ -0,0 +1,78 @@ +import QtQuick 2.0; + +Item { + id: scrollbar + width: (handleSize + 2) + visible: (flickable.visibleArea.heightRatio < 1.0) + + anchors { + top: flickable.top + right: flickable.right + bottom: flickable.bottom + } + + property Flickable flickable + property int handleSize + + Item { + id: bar + + anchors.fill: parent + + Rectangle { + anchors.fill: parent + color: "black" + opacity: 0.5 + } + + MouseArea { + id: control + anchors.fill: parent + + drag { + target: handle + minimumY: 0 + maximumY: (bar.height - handle.height) + axis: Drag.YAxis + } + + onClicked: { + flickable.contentY = (mouse.y / bar.height * (flickable.contentHeight - flickable.height)); + } + } + + Item { + id: handle; + height: Math.max(20, (flickable.visibleArea.heightRatio * bar.height)) + + anchors { + left: parent.left + right: parent.right + } + + Rectangle { + id: backHandle + anchors { + fill: parent + margins: 1 + } + + color: (control.pressed ? "gray" : "white") + } + } + } + + Binding { + target: handle + property: "y" + value: (flickable.contentY * control.drag.maximumY / (flickable.contentHeight - flickable.height)) + when: (!control.drag.active) + } + + Binding { + target: flickable + property: "contentY" + value: (handle.y * (flickable.contentHeight - flickable.height) / control.drag.maximumY) + when: (control.drag.active || control.pressed) + } +} diff --git a/qml/TerminalItem.qml b/qml/TerminalItem.qml new file mode 100644 index 0000000..6c19c45 --- /dev/null +++ b/qml/TerminalItem.qml @@ -0,0 +1,118 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 + +Item { + id: terminalItem + signal executed + + height: elementList.height + + function select() { + if ( command.readOnly ) { + elementList.children[1].select(); + } else { + highlighter.select(); + } + } + + function deselect() { + if ( command.readOnly ) { + elementList.children[1].deselect(); + } else { + highlighter.deselect(); + } + } + + function forceActiveFocus() { + if ( command.readOnly ) { + scope.forceActiveFocus(); + } else { + scope.forceActiveFocus(); + highlighter.select(); + highlighter.focus(); + } + } + + function unfocus() { + if ( !command.readOnly ) { + highlighter.unfocus(); + } + } + + FocusScope { + id: scope + + Column { + id: elementList + + function createTerminal(program) { + var terminal = Qt.createComponent("qrc:/EmbeddedTerminal.qml"); + var instantiateTerminal = function() { + terminal.createObject(elementList, { + "columns": 90, + "lines": 20, + "program": program, + "workingDirectory": "$HOME", + "focus": true + }); + } + + if ( terminal.status === Component.Ready ) { + instantiateTerminal(); + } else { + terminal.statusChanged.connect(instantiateTerminal); + } + } + + RowLayout { + width: terminalItem.width + + Rectangle { + id: highlighter + + width: 10 + height: command.height + opacity: 0 + + color: "#909636" + + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + } + + function select() { opacity = 1 } + function deselect() { opacity = 0 } + function focus() { color = "#352F6A" } + function unfocus() { color = "#909636" } + } + + TextInput { + id: command + + font.pointSize: 18 + color: "white" + selectedTextColor: "#161616" + selectionColor: "white" + selectByMouse: true + focus: true + + Layout.fillWidth: true + + onAccepted: { + if ( !readOnly ) { + readOnly = true; + focus = false; + elementList.createTerminal(text); + terminalItem.executed(); + highlighter.deselect(); + } + } + } + } + } + } +} diff --git a/qml/main.qml b/qml/main.qml new file mode 100644 index 0000000..1e0db9d --- /dev/null +++ b/qml/main.qml @@ -0,0 +1,168 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Controls 1.2 + +ApplicationWindow { + id: root + + visible: true + + color: "#161616" + + Component.onCompleted: terminalList.focusCurrent() + + Flickable { + id: terminalListFlickable + anchors.fill: parent + + boundsBehavior: Flickable.StopAtBounds + contentHeight: terminalList.height + contentWidth: terminalList.width + pixelAligned: true + + Column { + id: terminalList + spacing: 10 + + property int activeItem : 0 + + onHeightChanged: scrollTo(activeItem) + + function createItem() { + var terminalItem = Qt.createComponent("qrc:/TerminalItem.qml"); + var instantiateTerminal = function() { + var instance = terminalItem.createObject(terminalList, { + "width": terminalListFlickable.width + }); + instance.onExecuted.connect(createItem); + } + + if ( terminalItem.status === Component.Ready ) { + instantiateTerminal(); + } else { + terminalItem.statusChanged.connect(instantiateTerminal); + } + } + + function scrollTo(index) { + if ( terminalList.height >= terminalListFlickable.height ) { + var offset = children[index].y + + (children[index].height / 2) + - (terminalListFlickable.height / 2); + + var bound = terminalList.height + - terminalListFlickable.height; + + if ( offset < 0 ) { + terminalListFlickable.contentY = 0; + } else if ( offset >= bound ) { + terminalListFlickable.contentY = bound; + } else { + terminalListFlickable.contentY = offset; + } + } + } + + function selectItem(index) { + children[activeItem].deselect(); + children[index ].select(); + + activeItem = index; + + scrollTo(index); + } + + function selectNext() { + if ( activeItem < (children.length - 1) ) { + selectItem(activeItem + 1); + } else { + insertTerminalAction.trigger(); + } + } + + function selectPrev() { + if ( activeItem > 0 ) { + selectItem(activeItem - 1); + } + } + + function focusCurrent() { + children[activeItem].forceActiveFocus(); + } + + function unfocusCurrent() { + children[activeItem].unfocus(); + } + + TerminalItem { + width: terminalListFlickable.width + onExecuted: terminalList.createItem() + } + } + } + + Action { + id: insertTerminalAction + shortcut: "i" + enabled: false + onTriggered: { + escapeTerminalAction.enabled = true; + insertTerminalAction.enabled = false; + nextTerminalAction.enabled = false; + prevTerminalAction.enabled = false; + lastTerminalAction.enabled = false; + firstTerminalAction.enabled = false; + + terminalList.focusCurrent(); + } + } + + Action { + id: escapeTerminalAction + shortcut: "Shift+ESC" + onTriggered: { + escapeTerminalAction.enabled = false; + insertTerminalAction.enabled = true; + nextTerminalAction.enabled = true; + prevTerminalAction.enabled = true; + lastTerminalAction.enabled = true; + firstTerminalAction.enabled = true; + + terminalList.forceActiveFocus(); + terminalList.unfocusCurrent(); + } + } + + Action { + id: nextTerminalAction + shortcut: "j" + enabled: false + onTriggered: terminalList.selectNext() + } + + Action { + id: prevTerminalAction + shortcut: "k" + enabled: false + onTriggered: terminalList.selectPrev() + } + + Action { + id: lastTerminalAction + shortcut: "Shift+G" + enabled: false + onTriggered: terminalList.selectItem(terminalList.children.length - 1) + } + + Action { + id: firstTerminalAction + shortcut: "g" + enabled: false + onTriggered: terminalList.selectItem(0) + } + + ScrollBar { + flickable: terminalListFlickable + handleSize: 10 + } +} diff --git a/qml/ui.qrc b/qml/ui.qrc new file mode 100644 index 0000000..8339fa2 --- /dev/null +++ b/qml/ui.qrc @@ -0,0 +1,8 @@ + + + main.qml + TerminalItem.qml + EmbeddedTerminal.qml + ScrollBar.qml + + -- cgit v1.2.3