diff --git a/shell/qml/Main.qml b/shell/qml/Main.qml index c586700..4211f68 100644 --- a/shell/qml/Main.qml +++ b/shell/qml/Main.qml @@ -3,12 +3,14 @@ import QtQuick.Window import NomadInput 1.0 QtObject { + // this is our top screen, for now, though in the future I would like to have it configurable which screen does which. + // I'll burn that bridge when I get to it property Window topWindow: Window { - width: 960 + width: 960 // this resolution size is for development. I'd like to have a cleaner way to develop for 1080p without getting a dedicated monitor for testing nomad on my dev computer height: 540 visible: true - title: "nomad-top" - property string lastInputText: "none" + title: "nomad-top" // this is necesarry for Sway, which auto-assigns the windows + property string lastInputText: "none" // I've never really integrated NomadInput into this debug section in the top half and now I'm too lazy to. it's just a placeholder anyway. Connections { target: inputManager @@ -21,7 +23,7 @@ QtObject { } } - Rectangle { + Rectangle { // just a placeholder for the top screen until we do something better anchors.fill: parent color: "#181818" @@ -45,19 +47,10 @@ QtObject { } property Window bottomWindow: Window { - width: 620 + width: 620 // again, half-resolution height: 540 visible: true - title: "nomad-bottom" - - readonly property var mainMenuNavRegions: ({ - DockMenu: 0, - GamesList: 1, - Count: 2 - }) - - property int focusRegion: bottomWindow.mainMenuNavRegions.GamesList - property int dockMenuIndex: 0 + title: "nomad-bottom" // window titling for Sway auto-assign NavigationManager { id: navigationManager @@ -67,6 +60,8 @@ QtObject { Connections { target: inputManager + // you don't wanna know what this used to look like :dread: + // just checks if our navigation is directional, and, if so, moves the selection in that direction function onActionPressed(action) { switch (action) { case InputManager.Up: @@ -85,7 +80,8 @@ QtObject { anchors.fill: parent color: "#181818" - Text { + // top text where a menu dock will probably be eventually + Text { anchors.top: parent.top anchors.topMargin: 30 anchors.horizontalCenter: parent.horizontalCenter @@ -95,6 +91,8 @@ QtObject { font.pixelSize: 24 } + // this is the game carousel. mostly self explanatory, but I wanna point out that the local index for this listView does probably still matter. + // I got rid of dedicated menu indexing for the dock, but I think it still matters here, for the sake of auto-scrolling ListView { id: gamesList @@ -102,23 +100,25 @@ QtObject { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter + // TODO: Tune this stuff !!! it feels just slightly janky and off for now, game cards don't align when scrolling, they go all the way out + // to the edge with no spacing at all when on the leftmost or rightmost cards, and vertical navigation from the dock feels *wrong*, idk, + // fix it sometime. height: 140 - orientation: ListView.Horizontal preferredHighlightBegin: 200 preferredHighlightEnd: 420 highlightRangeMode: ListView.ApplyRange spacing: 20 - model: 20 + model: 20 // this is a placeholder for now, I don't know how I really want to handle max game carousel size yet. another time. - Component.onCompleted: { + Component.onCompleted: { // on startup, this should select the first game in the list. if (currentItem) { navigationManager.focusItem(currentItem) } } - delegate: Rectangle { + delegate: Rectangle { // TODO: design a real game card QML to replace this placeholder id: gameTile width: 110 @@ -126,7 +126,7 @@ QtObject { color: navigationManager.currentItem === gameTile ? "blue" : "white" - function navFocus() { + function onNavigationFocused() { gamesList.currentIndex = index } @@ -168,8 +168,9 @@ QtObject { color: navigationManager.currentItem === dockButton ? "blue" : "white" - function navFocus() { - bottomWindow.dockMenuIndex = index + function onNavigationFocused() { + // there used to be code here when my navigation was worse. I bet I'll need it eventually tho + // this entire section is a placeholder dock button anyway though. } Component.onCompleted: { diff --git a/shell/qml/NavigationManager.qml b/shell/qml/NavigationManager.qml index eaa5199..3b411a0 100644 --- a/shell/qml/NavigationManager.qml +++ b/shell/qml/NavigationManager.qml @@ -1,13 +1,18 @@ import QtQuick import NomadInput 1.0 +// NavigationManager +// This thing's job is to keep track of the "physical" logcation of every UI element that can be navigated to, and allow for directional +// navigation of the on-screen UI. It requires every selectable object on-screen to register itself so that we can keep track of what is +// where, so much of it's functionality is registering and unregistering and reviewing that registry of items. QtObject { id: manager - property Item rootItem: null - property list items + property Item rootItem: null // this is necesarry for the sake of having a global co-ordinate system by which to keep track of stuff + property list items property var currentItem: null + // set the focus on a particular item in the registry function focusItem(item) { if (!item) { return @@ -15,8 +20,9 @@ QtObject { currentItem = item - if (typeof item.navFocus === "function") { - item.navFocus() + // this is a little helper function that is called on anything that's focused (Assuming the object has such a function). + if (typeof item.onNavigationFocused === "function") { + item.onNavigationFocused() } } @@ -25,6 +31,7 @@ QtObject { return } + // double check that we haven't registered this yet for (let i = 0; i < items.length; i++) { if (items[i] === item) { return @@ -53,13 +60,18 @@ QtObject { } function move(action) { + // just to make sure everything is set up right if (!currentItem || !rootItem) { return } + // this is our direction vector by which to move. + // since I made it like this, I could probably put analog directions into this easily. + // don't know if I would actually want to, but I probably could easily. let dx = 0 let dy = 0 + // analog input aside, this just takes our cardinal input directiosn and sets the vector accordingly switch(action) { case InputManager.Left: dx = -1 @@ -81,14 +93,17 @@ QtObject { return } + // we want the center point of the actual item, not just the coordinates it's set to. better for directionality. let currentCenter = currentItem.mapToItem(rootItem, currentItem.width / 2, currentItem.height / 2) let bestItem = null let bestScore = Infinity + // sorts through all our items to see which is closest for (let i = 0; i < items.length; i++) { let candidate = items[i] + // sanity checks if (!candidate) { continue } @@ -101,6 +116,7 @@ QtObject { continue } + // we want the center point of the item, just like before let candidateCenter = candidate.mapToItem(rootItem, candidate.width / 2, candidate.height / 2) let differenceX = candidateCenter.x - currentCenter.x @@ -109,31 +125,28 @@ QtObject { let forwardDistance let sidewaysDistance - if (dx !== 0) { + if (dx !== 0) { // Horizontal directions forwardDistance = differenceX * dx sidewaysDistance = Math.abs(differenceY) - } else { + } else { // vectical directions forwardDistance = differenceY * dy sidewaysDistance = Math.abs(differenceX) } - if (forwardDistance <= 0) { + if (forwardDistance <= 0) { // if it's on the wrong side of the object just discard it continue } - let score = forwardDistance + sidewaysDistance * 2 + let score = forwardDistance + sidewaysDistance * 2 // this might need to be tuned later. prioritizes vertical alignment if (score < bestScore) { bestScore = score bestItem = candidate } - console.log("candidate:", candidate, "center:", candidateCenter.x, candidateCenter.y, "difference:", differenceX, differenceY) } if (bestItem) { focusItem(bestItem) } - - console.log("MOVE", inputManager.actionName(action), "current:", currentItem, "center:", currentCenter.x, currentCenter.y) } } \ No newline at end of file diff --git a/shell/src/input/InputManager.cpp b/shell/src/input/InputManager.cpp index 36ebdd7..9137c6b 100644 --- a/shell/src/input/InputManager.cpp +++ b/shell/src/input/InputManager.cpp @@ -3,6 +3,9 @@ #include #include +// InputManager is intended to make all input detection standard across all input devices that +// nomad supports, turning them into generic input commands for other parts of the program to +// follow. It emits signals when inputs are pressed and when inputs are released bool InputManager::eventFilter(QObject *watched, QEvent *event) { // filter for keyboard presses and releases @@ -17,6 +20,7 @@ bool InputManager::eventFilter(QObject *watched, QEvent *event) // translate to nomad Action Action action; + // hard-coded keyboard binding. may or may not ever make it configurable. switch (keyEvent->key()) { case Qt::Key_Up: action = Action::Up; @@ -115,6 +119,7 @@ bool InputManager::eventFilter(QObject *watched, QEvent *event) return true; } +// defines our list of actions QString InputManager::actionName(Action action) const { switch (action) { diff --git a/shell/src/main.cpp b/shell/src/main.cpp index d524dd0..80a894c 100644 --- a/shell/src/main.cpp +++ b/shell/src/main.cpp @@ -6,26 +6,31 @@ int main(int argc, char *argv[]) { + // creates our Qt GUI app QGuiApplication app(argc, argv); + // creats InputManager and installs it as an application-wide event filter so it can observe input events before normal delivery InputManager inputManager; app.installEventFilter(&inputManager); - qmlRegisterUncreatableMetaObject( - InputManager::staticMetaObject, - "NomadInput", - 1, 0, - "InputManager", - "InputManager is created by nomad" - ); + // Expose InputManager's Qt meta-object to QML under the NomadInput module, for ease of reading code. + // This lets us refer to inputs as InputManager.Left, InputManager.Right, et cetera + // QML isn't allowed to create it's own + qmlRegisterUncreatableMetaObject(InputManager::staticMetaObject, "NomadInput", 1, 0, "InputManager", "InputManager is created by nomad"); + // start up the QML engine QQmlApplicationEngine engine; + // make our InputManager instance available to QML for signals engine.rootContext()->setContextProperty("inputManager", &inputManager); + // load our Main.qml into the engine to start things off engine.loadFromModule("nomad", "Main"); - if (engine.rootObjects().isEmpty()) + // makes sure we've got QML objects + if (engine.rootObjects().isEmpty()) { return -1; + } + // Start the event loop and keeps nomad running until it exits return app.exec(); } \ No newline at end of file