visualeventoverlay.cpp 6.16 KB
Newer Older
1
/*
2
  SPDX-FileCopyrightText: 2009 Eike Hein <hein@kde.org>
3

4
  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5
6
7
8
9
10
11
*/

#include "visualeventoverlay.h"
#include "sessionstack.h"
#include "settings.h"
#include "terminal.h"

Jekyll Wu's avatar
Jekyll Wu committed
12
#include <KColorScheme>
13
14
15
16

#include <QPainter>
#include <QTimer>

Alexander Lohnau's avatar
Alexander Lohnau committed
17
18
EventRect::EventRect(const QPoint &topLeft, const QPoint &bottomRight, EventType type, EventFlags flags)
    : QRect(topLeft, bottomRight)
19
20
21
22
23
24
25
26
27
28
29
30
{
    m_eventType = type;

    m_eventFlags = flags;

    m_timeStamp.start();
}

EventRect::~EventRect()
{
}

Alexander Lohnau's avatar
Alexander Lohnau committed
31
bool EventRect::operator==(const EventRect &eventRect) const
32
33
34
35
36
37
38
39
40
41
{
    if (m_eventType == eventRect.eventType() && eventRect.testFlag(EventRect::Singleton))
        return true;

    if (m_eventType != eventRect.eventType())
        return false;

    return ::operator==(*this, eventRect);
}

Alexander Lohnau's avatar
Alexander Lohnau committed
42
bool EventRect::operator<(const EventRect &eventRect) const
43
44
45
46
47
48
49
50
51
52
53
{
    if (!testFlag(EventRect::Exclusive) && eventRect.testFlag(EventRect::Exclusive))
        return false;
    if (m_eventType < eventRect.eventType())
        return true;
    else if (m_timeStamp < eventRect.timeStamp())
        return true;

    return false;
}

Alexander Lohnau's avatar
Alexander Lohnau committed
54
55
VisualEventOverlay::VisualEventOverlay(SessionStack *parent)
    : QWidget(parent)
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
{
    m_sessionStack = parent;

    setAutoFillBackground(false);

    setAttribute(Qt::WA_TranslucentBackground, true);

    setFocusPolicy(Qt::NoFocus);
    setAttribute(Qt::WA_TransparentForMouseEvents, true);

    m_cleanupTimer = new QTimer(this);
    m_cleanupTimer->setSingleShot(true);
    connect(m_cleanupTimer, SIGNAL(timeout()), this, SLOT(cleanupOverlay()));

    m_cleanupTimerCeiling = 0;

    hide();
}

VisualEventOverlay::~VisualEventOverlay()
{
}

Alexander Lohnau's avatar
Alexander Lohnau committed
79
void VisualEventOverlay::highlightTerminal(Terminal *terminal, bool persistent)
80
81
82
83
{
    if (!persistent && Settings::terminalHighlightDuration() == 0)
        return;

Alexander Lohnau's avatar
Alexander Lohnau committed
84
85
    if (isHidden())
        show();
86
87

    EventRect::EventFlags flags = EventRect::Singleton | EventRect::Exclusive;
Alexander Lohnau's avatar
Alexander Lohnau committed
88
89
    if (persistent)
        flags |= EventRect::Persistent;
90
91
92
93
94
95
96
97
98

    terminalEvent(terminal, EventRect::TerminalHighlight, flags);

    if (!persistent)
        scheduleCleanup(Settings::terminalHighlightDuration());
}

void VisualEventOverlay::removeTerminalHighlight()
{
Alexander Lohnau's avatar
Alexander Lohnau committed
99
100
    if (!m_eventRects.count())
        return;
101
102
103

    QMutableListIterator<EventRect> i(m_eventRects);

Alexander Lohnau's avatar
Alexander Lohnau committed
104
    while (i.hasNext()) {
105
106
107
108
109
110
111
112
113
114
        if (i.next().eventType() == EventRect::TerminalHighlight)
            i.remove();
    }

    if (m_sessionStack->requiresVisualEventOverlay())
        update();
    else
        hide();
}

Alexander Lohnau's avatar
Alexander Lohnau committed
115
void VisualEventOverlay::indicateKeyboardInputBlocked(Terminal *terminal)
116
117
118
119
120
121
122
123
124
{
    if (Settings::keyboardInputBlockIndicatorDuration() == 0)
        return;

    terminalEvent(terminal, EventRect::KeyboardInputBlocked);

    scheduleCleanup(Settings::keyboardInputBlockIndicatorDuration());
}

Alexander Lohnau's avatar
Alexander Lohnau committed
125
void VisualEventOverlay::terminalEvent(Terminal *terminal, EventRect::EventType type, EventRect::EventFlags flags)
126
127
{
    QRect partRect(terminal->partWidget()->rect());
Alexander Lohnau's avatar
Alexander Lohnau committed
128
    const QWidget *partWidget = terminal->partWidget();
129
130
131
132
133
134
135
136
137

    QPoint topLeft(partWidget->mapTo(parentWidget(), partRect.topLeft()));
    QPoint bottomRight(partWidget->mapTo(parentWidget(), partRect.bottomRight()));

    EventRect eventRect(topLeft, bottomRight, type, flags);

    m_eventRects.removeAll(eventRect);
    m_eventRects.append(eventRect);

138
    std::sort(m_eventRects.begin(), m_eventRects.end());
139
140
141
142

    update();
}

Alexander Lohnau's avatar
Alexander Lohnau committed
143
void VisualEventOverlay::paintEvent(QPaintEvent *)
144
{
Alexander Lohnau's avatar
Alexander Lohnau committed
145
146
    if (!m_eventRects.count())
        return;
147
148
149
150
151
152
153
154

    QPainter painter(this);

    m_time.start();
    bool painted = false;

    QListIterator<EventRect> i(m_eventRects);

Alexander Lohnau's avatar
Alexander Lohnau committed
155
156
    while (i.hasNext()) {
        const EventRect &eventRect = i.next();
157
158
159
160

        painted = false;

        if (eventRect.eventType() == EventRect::TerminalHighlight
Alexander Lohnau's avatar
Alexander Lohnau committed
161
            && (eventRect.timeStamp().msecsTo(m_time) <= Settings::terminalHighlightDuration() || eventRect.testFlag(EventRect::Persistent))) {
162
163
164
165
            KStatefulBrush terminalHighlightBrush(KColorScheme::View, KColorScheme::HoverColor);

            painter.setOpacity(Settings::terminalHighlightOpacity());

Laurent Montel's avatar
Laurent Montel committed
166
            painter.fillRect(eventRect, terminalHighlightBrush.brush(palette()));
167
168

            painted = true;
Alexander Lohnau's avatar
Alexander Lohnau committed
169
170
        } else if (eventRect.eventType() == EventRect::KeyboardInputBlocked
                   && eventRect.timeStamp().msecsTo(m_time) <= Settings::keyboardInputBlockIndicatorDuration()) {
171
172
173
174
175
176
177
            painter.setOpacity(Settings::keyboardInputBlockIndicatorOpacity());

            painter.fillRect(eventRect, Settings::keyboardInputBlockIndicatorColor());

            painted = true;
        }

Alexander Lohnau's avatar
Alexander Lohnau committed
178
        if (painted && i.hasNext() && eventRect.testFlag(EventRect::Exclusive)) {
179
180
181
182
183
184
185
186
            if (!painter.hasClipping())
                painter.setClipRect(rect());

            painter.setClipRegion(painter.clipRegion().subtracted(eventRect));
        }
    }
}

Alexander Lohnau's avatar
Alexander Lohnau committed
187
void VisualEventOverlay::showEvent(QShowEvent *)
188
189
190
191
192
193
{
    resize(parentWidget()->rect().size());

    raise();
}

Alexander Lohnau's avatar
Alexander Lohnau committed
194
void VisualEventOverlay::hideEvent(QHideEvent *)
195
196
197
198
199
200
201
202
203
204
{
    m_cleanupTimer->stop();

    m_eventRects.clear();
}

void VisualEventOverlay::scheduleCleanup(int in)
{
    int left = m_cleanupTimerCeiling - m_cleanupTimerStarted.elapsed();

Alexander Lohnau's avatar
Alexander Lohnau committed
205
    if (in > left) {
206
207
208
209
210
211
212
213
        m_cleanupTimerCeiling = in;
        m_cleanupTimerStarted.start();
        m_cleanupTimer->start(in);
    }
}

void VisualEventOverlay::cleanupOverlay()
{
Alexander Lohnau's avatar
Alexander Lohnau committed
214
    if (m_eventRects.count()) {
215
216
217
218
        m_time.start();

        QMutableListIterator<EventRect> i(m_eventRects);

Alexander Lohnau's avatar
Alexander Lohnau committed
219
220
        while (i.hasNext()) {
            const EventRect &eventRect = i.next();
221

Alexander Lohnau's avatar
Alexander Lohnau committed
222
223
            if (eventRect.eventType() == EventRect::TerminalHighlight && eventRect.timeStamp().msecsTo(m_time) >= Settings::terminalHighlightDuration()
                && !eventRect.testFlag(EventRect::Persistent)) {
224
                i.remove();
Alexander Lohnau's avatar
Alexander Lohnau committed
225
226
            } else if (eventRect.eventType() == EventRect::KeyboardInputBlocked
                       && eventRect.timeStamp().msecsTo(m_time) >= Settings::keyboardInputBlockIndicatorDuration()) {
227
228
229
230
231
232
233
234
235
236
                i.remove();
            }
        }
    }

    if (m_sessionStack->requiresVisualEventOverlay())
        update();
    else
        hide();
}