aboutsummaryrefslogtreecommitdiffstats
path: root/plugin/cursornavigation.cpp
blob: 5cb954559bc025f3b7d0c1b82cfe57b103106b87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "cursornavigation.h"
#include "cursornavigationalgorithm.h"
#include "spatialnavigation4dir.h"
#include <QQuickWindow>
#include <QQuickItem>

const char CursorNavigation::windowPropertyName[] = "cursor_navigation";

CursorNavigation::CursorNavigation(QQuickWindow *parent)
:QObject(parent)
,m_inputAdapter(parent, this)
,m_currentItem(nullptr)
{
    m_algorithms.push_back(new SpatialNavigation4Dir(&m_itemRegister));
}

bool CursorNavigation::inputCommand(CursorNavigationCommand cmd)
{
    QQuickItem *nextItem;

    for (auto alg : m_algorithms) {
        nextItem = alg->getNextCandidate(m_itemRegister.items(), m_currentItem, cmd);
        if (nextItem)
            break;
    }

    if (nextItem) {
        if (m_currentItem) {
            CursorNavigationAttached *current=cursorNavigationAttachment(m_currentItem);
            Q_ASSERT(current);
            current->setHasCursor(false);
        }
        CursorNavigationAttached *next=cursorNavigationAttachment(nextItem);
        Q_ASSERT(next);
        next->setHasCursor(true);
        m_currentItem = nextItem;
    }
}

CursorNavigationAttached *CursorNavigation::qmlAttachedProperties(QObject *object)
{
    // if the object is a window, use its contentItem instead
    if (auto win = qobject_cast<QQuickWindow *>(object)) {
        object = win->contentItem();
    }

    if (!qobject_cast<QQuickItem *>(object)) {
        qWarning("Cannot manage focus for a non-Item!");
        return nullptr;
    }

    QQuickItem *item = static_cast<QQuickItem *>(object);

    // TODO: what if an object, with an already attached object, gets reparented (say, in another window?)
    // with or without a focus system.

    return new CursorNavigationAttached(item);
}

CursorNavigation *CursorNavigation::cursorNavigationForWindow(QQuickWindow *window)
{
    if (!window)
        return nullptr;

    const QVariant &oldCursorNavigation = window->property(windowPropertyName);
    if (!oldCursorNavigation.isNull())
        return oldCursorNavigation.value<CursorNavigation *>();

    CursorNavigation *cursorNavigation = new CursorNavigation(window);
    window->setProperty(windowPropertyName, QVariant::fromValue(cursorNavigation));

    //why would the context property be needed?
    /*if (QQmlEngine *engine = cn->qmlEngine(window)) {
        engine->rootContext()->setContextProperty("_cursorNavigation", cn);
    } else {
        qDebug() << "Couldn't find QQmlEngine";
    }*/

    return cursorNavigation;
}

CursorNavigationAttached *CursorNavigation::cursorNavigationAttachment(QQuickItem *item)
{
    Q_ASSERT(item);
    return static_cast<CursorNavigationAttached *>(qmlAttachedPropertiesObject<CursorNavigation>(item, false));
}