Project
Loading...
Searching...
No Matches
GPUDisplayGUI.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
15#include "GPUDisplayGUI.h"
16#include "GPUDisplayFrontend.h"
17#include "ui_GPUDisplayGUI.h"
18
19#include <QKeyEvent>
20#include <QSignalBlocker>
21
22#include <chrono>
23#include <cmath>
24
25using namespace o2::gpu;
26
27GPUDisplayGUI::GPUDisplayGUI(GPUDisplayGUIChannel& channel, QWidget* parent) : QMainWindow(parent), mUi(std::make_unique<Ui::GPUDisplayGUI>()), mChannel(channel)
28{
29 mUi->setupUi(this);
30 {
31 std::lock_guard lock(mChannel.mutex);
32 setWindowTitle(QString::fromStdString(mChannel.windowName + " GUI"));
33 }
34 connect(mUi->lineWidthSlider, &QSlider::valueChanged, this, [this](int32_t value) {
35 mUpdate.lineWidth = value * 0.1f;
36 mUi->lineWidthValue->setNum(*mUpdate.lineWidth);
37 });
38 connect(&mTimer, &QTimer::timeout, this, &GPUDisplayGUI::timerTick);
39 mTimer.start(std::chrono::milliseconds(10));
40}
41
43
44void GPUDisplayGUI::timerTick()
45{
46 std::unique_lock lock(mChannel.mutex);
47 mChannel.guiSleeping = false;
48 if (mUpdate.empty()) { // Display processes the update we went to sleep with, wait for the reply (with new changes we would not apply it anyway)
49 mChannel.stateUpdated.wait_for(lock, mChannel.replyTimeout, [this] { return !mChannel.displayProcessingCurrentUpdate || mChannel.stop; });
50 }
51 if (!mUpdate.empty() && mLastSentId - mLastAppliedId >= mChannel.maxUpdatesAhead) { // Too far ahead of the display, wait for the reply to the last update
52 mChannel.stateUpdated.wait_for(lock, mChannel.replyTimeout, [this] { return mChannel.state.appliedUpdate == mLastSentId || mChannel.stop; });
53 }
54 if (mChannel.stop) {
55 lock.unlock();
56 close();
57 return;
58 }
59
60 const bool newState = mChannel.state.counter != mState.counter;
61 if (newState) {
62 mState = mChannel.state;
63 if (mState.appliedUpdate == mLastSentId) {
64 mLastAppliedId = mLastSentId;
65 }
66 }
67 const bool apply = newState && mUpdate.empty() && mState.appliedUpdate == mLastSentId; // State contains all our updates, and we have no unsent changes
68 if (!mUpdate.empty() && mLastSentId - mLastAppliedId < mChannel.maxUpdatesAhead) {
69 if (mChannel.update) { // Previous update not yet picked up by the display, merge
70 auto& update = *mChannel.update;
71 update.keys.insert(update.keys.end(), mUpdate.keys.begin(), mUpdate.keys.end());
72 if (mUpdate.lineWidth) {
73 update.lineWidth = mUpdate.lineWidth;
74 }
75 } else {
76 mChannel.update = std::move(mUpdate);
77 }
78 mChannel.update->id = ++mLastSentId;
79 mChannel.guiSleeping = true;
80 mUpdate = {};
81 }
82 lock.unlock();
83
84 if (apply) {
85 applySettings();
86 }
87}
88
89void GPUDisplayGUI::applySettings()
90{
91 const QSignalBlocker blocker(mUi->lineWidthSlider); // Not a user change
92 mUi->lineWidthSlider->setValue(std::lround(mState.cfg.cfgL.lineWidth * 10.f));
93 mUi->lineWidthValue->setNum(mState.cfg.cfgL.lineWidth);
94}
95
97{
98 setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
99 show();
100 raise();
101 activateWindow();
102}
103
105{
106 const int32_t key = translateKey(event);
107 if (key < 0) {
108 QMainWindow::keyPressEvent(event);
109 return;
110 }
111 mUpdate.keys.emplace_back(key);
112}
113
114int32_t GPUDisplayGUI::translateKey(const QKeyEvent* event)
115{
116 switch (event->key()) {
117 case Qt::Key_Up:
119 case Qt::Key_Down:
121 case Qt::Key_Left:
123 case Qt::Key_Right:
125 case Qt::Key_PageUp:
127 case Qt::Key_PageDown:
129 case Qt::Key_Home:
131 case Qt::Key_End:
133 case Qt::Key_Insert:
135 case Qt::Key_Escape:
137 case Qt::Key_Return:
138 case Qt::Key_Enter:
140 default:
141 break;
142 }
143 if (event->key() >= Qt::Key_F1 && event->key() <= Qt::Key_F12) {
144 static_assert(GPUDisplayFrontend::KEY_F12 - GPUDisplayFrontend::KEY_F1 == Qt::Key_F12 - Qt::Key_F1);
145 return GPUDisplayFrontend::KEY_F1 + (event->key() - Qt::Key_F1);
146 }
147 const QString text = event->text();
148 if (text.size() == 1 && text[0].unicode() >= 32 && text[0].unicode() < 127) { // Printable ASCII, with shift applied
149 return text[0].unicode();
150 }
151 return -1;
152}
StringRef key
static constexpr int32_t KEY_F12
static constexpr int32_t KEY_END
static constexpr int32_t KEY_PAGEDOWN
static constexpr int32_t KEY_LEFT
static constexpr int32_t KEY_ENTER
static constexpr int32_t KEY_F1
static constexpr int32_t KEY_INSERT
static constexpr int32_t KEY_PAGEUP
static constexpr int32_t KEY_HOME
static constexpr int32_t KEY_UP
static constexpr int32_t KEY_DOWN
static constexpr int32_t KEY_RIGHT
static constexpr int32_t KEY_ESCAPE
void keyPressEvent(QKeyEvent *event) override
GPUDisplayGUI(GPUDisplayGUIChannel &channel, QWidget *parent=nullptr)
struct _cl_event * event
Definition glcorearb.h:2982
GLsizei const GLfloat * value
Definition glcorearb.h:819
std::chrono::milliseconds replyTimeout
std::condition_variable stateUpdated