From f01eadd3530e61063b43aa615123dcd82ce3d239 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Mon, 29 Jun 2015 22:31:24 +0200 Subject: Added vim-like UI normal and insert modes Normal mode allows for selecting the a terminal or newline text input. Insert mode sets the keyboard focus to the currently selected item. This transforms _MetaTerm_ into a fully keyboard driven application. --- EmbeddedTerminal.qml | 20 ++++---- MetaTerm.qml | 83 +++++++++++++++++++++++++++++++-- TerminalItem.qml | 128 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 178 insertions(+), 53 deletions(-) diff --git a/EmbeddedTerminal.qml b/EmbeddedTerminal.qml index e02ba61..f4f104e 100644 --- a/EmbeddedTerminal.qml +++ b/EmbeddedTerminal.qml @@ -12,7 +12,8 @@ Item { width: container.width height: container.height - function focus() { terminal.forceActiveFocus() } + function select() { highlighter.select() } + function deselect() { highlighter.deselect() } Row { id: container @@ -23,7 +24,7 @@ Item { width: 10 height: terminal.height - color: "#aadb0f" + color: "#909636" Behavior on opacity { NumberAnimation { @@ -32,8 +33,10 @@ Item { } } - function focus() { opacity = 1 } - function unfocus() { opacity = 0 } + function select() { opacity = 1 } + function deselect() { opacity = 0 } + function focus() { color = "#352F6A" } + function unfocus() { color = "#909636" } } Rectangle { @@ -66,16 +69,15 @@ Item { } } + onTermGetFocus: highlighter.focus() + onTermLostFocus: highlighter.unfocus() + MouseArea { anchors.fill: parent - acceptedButtons: Qt.LeftButton - onClicked: parent.forceActiveFocus(); + acceptedButtons: Qt.NoButton onWheel: { } } - onTermGetFocus: highlighter.focus() - onTermLostFocus: highlighter.unfocus() - Component.onCompleted: { terminal.forceActiveFocus(); session.startShellProgram(); diff --git a/MetaTerm.qml b/MetaTerm.qml index f95baa7..913f514 100644 --- a/MetaTerm.qml +++ b/MetaTerm.qml @@ -2,11 +2,15 @@ import QtQuick 2.0 import QMLTermWidget 1.0 import QtQuick.Controls 1.2 + Rectangle { + id: root anchors.fill: parent color: "#161616" + property string uiMode : "insert" + Flickable { id: terminalListFlickable boundsBehavior: Flickable.StopAtBounds @@ -37,16 +41,26 @@ Rectangle { function nextItem() { if ( activeItem < (children.length - 1) ) { - children[++activeItem].focus(); + children[ activeItem].deselect(); + children[++activeItem].select(); } } function prevItem() { if ( activeItem > 0 ) { - children[--activeItem].focus(); + children[ activeItem].deselect(); + children[--activeItem].select(); } } + function focusItem() { + children[activeItem].forceActiveFocus(); + } + + function unfocusItem() { + children[activeItem].unfocus(); + } + TerminalItem { width: terminalListFlickable.width onExecuted: terminalList.createItem() @@ -57,20 +71,81 @@ Rectangle { contentWidth: terminalList.width } + Action { + id: insertTerminalAction + shortcut: "i" + onTriggered: { + switch ( uiMode ) { + case "normal": { + uiMode = "insert"; + terminalList.focusItem(); + break; + } + default: { + break; + } + } + + console.log(uiMode); + } + } + + Action { + id: escapeTerminalAction + shortcut: "Shift+ESC" + onTriggered: { + switch ( uiMode ) { + case "insert": { + uiMode = "normal"; + root.forceActiveFocus(); + terminalList.unfocusItem(); + break; + } + default: { + break; + } + } + + console.log(uiMode); + } + } + Action { id: nextTerminalAction shortcut: "j" - onTriggered: terminalList.nextItem() + onTriggered: { + switch ( uiMode ) { + case "normal": { + terminalList.nextItem(); + break; + } + default: { + break; + } + } + } } Action { id: prevTerminalAction shortcut: "k" - onTriggered: terminalList.prevItem() + onTriggered: { + switch ( uiMode ) { + case "normal": { + terminalList.prevItem(); + break; + } + default: { + break; + } + } + } } ScrollBar { flickable: terminalListFlickable handleSize: 10 } + + Component.onCompleted: terminalList.focusItem() } diff --git a/TerminalItem.qml b/TerminalItem.qml index 9fce337..883d911 100644 --- a/TerminalItem.qml +++ b/TerminalItem.qml @@ -8,60 +8,108 @@ Item { height: elementList.height - function focus() { + function select() { if ( command.readOnly ) { - elementList.children[1].focus(); + elementList.children[1].select(); } else { - command.forceActiveFocus(); + highlighter.select(); } } - 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" - }); - } + function deselect() { + if ( command.readOnly ) { + elementList.children[1].deselect(); + } else { + highlighter.deselect(); + } + } - if ( terminal.status == Component.Ready ) { - instantiateTerminal(); - } else { - terminal.statusChanged.connect(instantiateTerminal); - } + function forceActiveFocus() { + if ( command.readOnly ) { + scope.forceActiveFocus(); + } else { + scope.forceActiveFocus(); + highlighter.select(); + highlighter.focus(); + } + } + + function unfocus() { + if ( !command.readOnly ) { + highlighter.unfocus(); } + } - RowLayout { - width: terminalItem.width + FocusScope { + id: scope - Text { - text: "> " - font.pointSize: 18 - color: "white" + 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); + } } - TextInput { - id: command + 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 + font.pointSize: 18 + color: "white" + selectedTextColor: "#161616" + selectionColor: "white" + selectByMouse: true + focus: true - Layout.fillWidth: true + Layout.fillWidth: true - onAccepted: { - if ( !readOnly ) { - readOnly = true; - elementList.createTerminal(text); - terminalItem.executed(); + onAccepted: { + if ( !readOnly ) { + readOnly = true; + focus = false; + elementList.createTerminal(text); + terminalItem.executed(); + highlighter.deselect(); + } } } } -- cgit v1.2.3