Skip to content

Commit 5c88012

Browse files
committed
GPU Display Improvemnts: bind middle mouse button, better error messages, improve console usage
1 parent 7d6c946 commit 5c88012

13 files changed

Lines changed: 94 additions & 31 deletions

‎GPU/GPUTracking/display/GPUDisplay.cxx‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ void GPUDisplay::DrawGLScene_cameraAndAnimation(bool suspended, float animateTim
256256
{
257257
HighResTimer timer(mUpdateVertexLists && mChain->GetProcessingSettings().debugLevel >= 2);
258258
int32_t mMouseWheelTmp = mFrontend->mMouseWheel;
259+
if (mCfgC.showConsole && mMouseWheelTmp) { // Scrolls the console instead of zooming, one line per step (100)
260+
mFrontend->mConsole->scroll(mMouseWheelTmp / 100 ? mMouseWheelTmp / 100 : (mMouseWheelTmp > 0) - (mMouseWheelTmp < 0));
261+
mMouseWheelTmp = 0;
262+
}
259263
mFrontend->mMouseWheel = 0;
260264
bool lookOrigin = mCfgR.camLookOrigin ^ mFrontend->mKeys[mFrontend->mKeyDownMap[mFrontend->KEY_MAP_FOCUS_ORIGIN]];
261265
bool yUp = mCfgR.camYUp ^ mFrontend->mKeys[mFrontend->mKeyDownMap[mFrontend->KEY_MAP_FOCUS_ORIENT_UP]] ^ lookOrigin;
@@ -308,7 +312,7 @@ void GPUDisplay::DrawGLScene_cameraAndAnimation(bool suspended, float animateTim
308312
float rotPitch = rotatescalefactor * mFPSScale * 2 * (mFrontend->mKeys[mFrontend->mKeyDownMap[mFrontend->KEY_MAP_ROTATE_PITCH_DOWN]] - mFrontend->mKeys[mFrontend->mKeyDownMap[mFrontend->KEY_MAP_ROTATE_PITCH_UP]]) * (!mFrontend->mKeys[mFrontend->KEY_SHIFT]);
309313

310314
float mouseScale = 1920.f / std::max<float>(1920.f, mBackend->mScreenWidth);
311-
if (mFrontend->mMouseDnR && mFrontend->mMouseDn) {
315+
if ((mFrontend->mMouseDnR && mFrontend->mMouseDn) || mFrontend->mMouseDnM) {
312316
moveZ += -scalefactor * mouseScale * ((float)mFrontend->mMouseMvY - (float)mFrontend->mMouseDnY) / 4;
313317
rotRoll += -rotatescalefactor * mouseScale * ((float)mFrontend->mMouseMvX - (float)mFrontend->mMouseDnX);
314318
} else if (mFrontend->mMouseDnR) {
@@ -430,7 +434,7 @@ void GPUDisplay::DrawGLScene_cameraAndAnimation(bool suspended, float animateTim
430434
calcXYZ(&mViewMatrix->Elements[0][0]);
431435
}
432436

433-
if (mFrontend->mMouseDn || mFrontend->mMouseDnR) {
437+
if (mFrontend->mMouseDn || mFrontend->mMouseDnR || mFrontend->mMouseDnM) {
434438
mFrontend->mMouseDnX = mFrontend->mMouseMvX;
435439
mFrontend->mMouseDnY = mFrontend->mMouseMvY;
436440
}
@@ -740,9 +744,16 @@ void GPUDisplay::DrawGLScene_internal(bool suspended, float animateTime, bool re
740744
showInfo(info);
741745
}
742746
if (consoleFraction > 0.f) {
743-
const double consoleTime = mConsoleTimer.GetCurrentElapsedTime();
744-
const bool cursor = mCfgC.showConsole && consoleTime >= mConfig.internal.consoleDelay && std::fmod(consoleTime - mConfig.internal.consoleDelay, 1.0) < 0.5; // Only when fully open, blinking, the timer runs while the console is open
745-
mBackend->GLDrawConsole(consoleFraction, mFrontend->mConsole->mConsoleHistory, mFrontend->mConsole->shownText(), cursor ? (int32_t)mFrontend->mConsole->mConsoleTextPos : -1);
747+
const bool open = mCfgC.showConsole && mConsoleTimer.GetCurrentElapsedTime() >= mConfig.internal.consoleDelay; // Cursor only when fully open
748+
if (!open) {
749+
mConsoleCursorTimer.Reset();
750+
} else if (!mConsoleCursorTimer.IsRunning() || mConsoleCursorPos != mFrontend->mConsole->mConsoleTextPos) { // Blinking restarts visible when the cursor moves
751+
mConsoleCursorTimer.ResetStart();
752+
mConsoleCursorPos = mFrontend->mConsole->mConsoleTextPos;
753+
}
754+
const bool cursor = open && std::fmod(mConsoleCursorTimer.GetCurrentElapsedTime(), 1.0) < 0.5;
755+
auto& console = *mFrontend->mConsole;
756+
console.mVisibleLines = mBackend->GLDrawConsole(consoleFraction, console.mConsoleHistory, console.shownText(), cursor ? (int32_t)console.mConsoleTextPos : -1, console.mScroll);
746757
}
747758
if (drawText) {
748759
mBackend->finishText();

‎GPU/GPUTracking/display/GPUDisplay.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ class GPUDisplay : public GPUDisplayInterface
333333
std::string mGUIInfoText; // Latest info message (SetInfo) for the Qt GUI
334334
uint64_t mGUIInfoTextCounter = 0; // Number of info messages, the GUI shows a new one for some seconds
335335
HighResTimer mInfoText2Timer, mInfoHelpTimer, mConsoleTimer; // mConsoleTimer: opening / closing animation of the console
336+
HighResTimer mConsoleCursorTimer; // Blinking of the console cursor, started when the console is fully open, restarted when the cursor moves
337+
uint32_t mConsoleCursorPos = 0; // Cursor position at the last restart of mConsoleCursorTimer
336338
bool mConsoleShown = false; // showConsole of the last checkAndApplyConfigChanges
337339

338340
std::vector<threadVertexBuffer> mThreadBuffers;

‎GPU/GPUTracking/display/backend/GPUDisplayBackend.cxx‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,10 @@ void GPUDisplayBackend::GLDrawLine(float x0, float y0, float x1, float y1, float
220220
GLDrawQuad({{x0 + nx, y0 + ny}, {x0 - nx, y0 - ny}, {x1 - nx, y1 - ny}, {x1 + nx, y1 + ny}}, color);
221221
}
222222

223-
void GPUDisplayBackend::GLDrawConsole(float verticalFraction, std::span<const std::string> previous, const std::string& current, int32_t cursorPos)
223+
uint32_t GPUDisplayBackend::GLDrawConsole(float verticalFraction, std::span<const std::string> previous, const std::string& current, int32_t cursorPos, uint32_t scroll)
224224
{
225225
if (!mFreetypeInitialized) {
226-
return;
226+
return 1;
227227
}
228228
const float scale = mDisplay->frontend()->getDisplayScale();
229229
const float colorValue = mDisplay->cfgL().invertColors ? 0.f : 1.f;
@@ -239,12 +239,17 @@ void GPUDisplayBackend::GLDrawConsole(float verticalFraction, std::span<const st
239239
const size_t maxChars = mFontCharWidth > 0.f ? std::max(0.f, (width / scale - 2 * MARGIN) / mFontCharWidth) : SIZE_MAX; // Longer lines are cut
240240
float y = bottom + (0.5f + MARGIN) * scale + descent; // Baseline of the lowest line, MARGIN above the line (half its width)
241241
if (cursorPos >= 0 && (size_t)cursorPos < maxChars && mFontCharWidth > 0.f) { // Monospace font: position from the character width
242-
GLPrintText("_", (MARGIN + cursorPos * mFontCharWidth) * scale, y, textColor, scale / mFontRasterScale, 0);
243-
}
244-
for (size_t i = 0; i <= previous.size() && y + lineHeight - descent <= top; i++, y += lineHeight) {
245-
const std::string& text = i == 0 ? current : previous[previous.size() - i];
242+
const float x0 = (MARGIN + cursorPos * mFontCharWidth) * scale, x1 = x0 + mFontCharWidth * scale;
243+
const float y1 = y - 0.5f * descent, y0 = y1 - 3.f * scale;
244+
GLDrawQuad({{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}}, textColor); // Solid underline, 3 logical pixels, below the baseline
245+
}
246+
const uint32_t nFit = std::max(1.f, std::floor((top - y + descent) / lineHeight) - 1.f); // Lines above the current one that fit, as in the loop
247+
scroll = std::min<size_t>(scroll, previous.size());
248+
for (size_t i = 0; i <= previous.size() - scroll && y + lineHeight - descent <= top; i++, y += lineHeight) {
249+
const std::string& text = i == 0 ? current : previous[previous.size() - scroll - i];
246250
if (!text.empty() && maxChars) {
247251
GLPrintText(text.c_str(), MARGIN * scale, y, textColor, scale / mFontRasterScale, std::min(text.size(), maxChars));
248252
}
249253
}
254+
return nFit;
250255
}

‎GPU/GPUTracking/display/backend/GPUDisplayBackend.h‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ class GPUDisplayBackend
101101
const char* backendName() const { return mBackendName; }
102102
virtual void resizeScene(uint32_t width, uint32_t height) {}
103103
virtual size_t needMultiVBO() { return 0; }
104-
virtual void GLPrintText(const char* s, float x, float y, float* color, float scale, uint32_t nCharacters) = 0; // nCharacters > 0: at most that many characters, otherwise until the terminating 0
105-
virtual void GLDrawQuad(const float (&corners)[4][2], const float* color) = 0; // Filled quad with the corners counterclockwise, in pixels with y from the bottom, drawn with the text (SOLID_GLYPH)
106-
void GLDrawLine(float x0, float y0, float x1, float y1, float width, const float* color); // As GLDrawQuad
107-
void GLDrawConsole(float verticalFraction, std::span<const std::string> previous, const std::string& current, int32_t cursorPos); // Console over the top verticalFraction of the window: current text in the lowest line, previous ones above (last one lowest), cursor _ at cursorPos (< 0: none)
104+
virtual void GLPrintText(const char* s, float x, float y, float* color, float scale, uint32_t nCharacters) = 0; // nCharacters > 0: at most that many characters, otherwise until the terminating 0
105+
virtual void GLDrawQuad(const float (&corners)[4][2], const float* color) = 0; // Filled quad with the corners counterclockwise, in pixels with y from the bottom, drawn with the text (SOLID_GLYPH)
106+
void GLDrawLine(float x0, float y0, float x1, float y1, float width, const float* color); // As GLDrawQuad
107+
uint32_t GLDrawConsole(float verticalFraction, std::span<const std::string> previous, const std::string& current, int32_t cursorPos, uint32_t scroll); // Console over the top verticalFraction of the window: current text in the lowest line, previous ones above (last one lowest, the last scroll ones skipped), cursor underline at cursorPos (< 0: none); returns the number of previous lines that fit
108108
static GPUDisplayBackend* getBackend(const char* type);
109109
std::vector<char> getPixels();
110110
virtual float getYFactor() const { return 1.0f; }

‎GPU/GPUTracking/display/frontend/GPUDisplayConsole.cxx‎

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,38 @@
2525

2626
using namespace o2::gpu;
2727

28+
namespace
29+
{
30+
struct consoleArgumentError : public std::runtime_error { // Wrong arguments for an existing command, what(): the error, usage: the argument types
31+
consoleArgumentError(const std::string& cmd, const std::string& error, const std::string& types) : std::runtime_error(error), command(cmd), usage("[")
32+
{
33+
static constexpr std::pair<char, const char*> names[] = {{'s', "string"}, {'i', "int"}, {'d', "double"}, {'a', "any"}, {'+', "[optional]"}};
34+
for (char t : types) {
35+
for (const auto& [c, name] : names) {
36+
usage += c == t ? std::string(usage.size() > 1 ? " " : "") + name : "";
37+
}
38+
}
39+
usage += "]";
40+
}
41+
std::string command, usage;
42+
};
43+
} // namespace
44+
2845
GPUDisplayConsole::GPUDisplayConsole(const std::string& title) : mConsoleHistory{title} {}
2946

30-
void GPUDisplayConsole::handleConsoleKey(uint8_t key)
47+
void GPUDisplayConsole::scroll(int32_t lines)
3148
{
49+
const int64_t maxScroll = std::max<int64_t>(0, (int64_t)mConsoleHistory.size() - mVisibleLines);
50+
mScroll = std::clamp<int64_t>((int64_t)mScroll + lines, 0, maxScroll);
51+
}
52+
53+
void GPUDisplayConsole::handleConsoleKey(uint8_t key, bool shift)
54+
{
55+
if (key == KEY_PAGEUP || key == KEY_PAGEDOWN || (shift && (key == KEY_UP || key == KEY_DOWN))) { // Half a page / one line
56+
const int32_t lines = key == KEY_PAGEUP || key == KEY_PAGEDOWN ? std::max<int32_t>(1, mVisibleLines / 2) : 1;
57+
scroll(key == KEY_PAGEUP || key == KEY_UP ? lines : -lines);
58+
return;
59+
}
3260
const uint32_t nHistory = mConsoleHistory.size();
3361
auto isOutput = [this](uint32_t i) { return mConsoleHistory[i].size() && mConsoleHistory[i][0] == ' '; }; // Indented output of commands, not selectable
3462
if (key == KEY_UP || key == KEY_DOWN) { // Entry 0 is the title, not selectable
@@ -43,13 +71,13 @@ void GPUDisplayConsole::handleConsoleKey(uint8_t key)
4371
}
4472
mConsoleTextCurrent = i < nHistory ? i : 0;
4573
}
46-
mConsoleTextPos = 0;
74+
mConsoleTextPos = shownText().size(); // At the end, as when editing the entry starts
4775
return;
4876
} else if (key == KEY_ENTER) {
4977
std::string command = mConsoleTextCurrent ? mConsoleHistory[mConsoleTextCurrent] : mConsoleText;
5078
command.erase(0, std::min(command.size(), command.find_first_not_of(' '))); // Leading spaces would mark it as output in the history
5179
mConsoleText.clear();
52-
mConsoleTextCurrent = mConsoleTextPos = 0;
80+
mConsoleTextCurrent = mConsoleTextPos = mScroll = 0;
5381
if (!command.empty()) {
5482
consoleAppend(command); // Before its output
5583
handleConsoleCommand(command);
@@ -184,7 +212,7 @@ std::tuple<const GPUDisplayConsole::GPUDisplayConsoleCommand&, std::vector<GPUDi
184212
const bool more = types.size() && types.back() == '+';
185213
const size_t nFixed = types.size() - more, nArgs = tokens.size() - 1;
186214
if (nArgs < nFixed || (!more && nArgs > nFixed)) {
187-
throw std::runtime_error(name + ": " + std::to_string(nFixed) + (more ? " or more" : "") + " arguments expected, got " + std::to_string(nArgs));
215+
throw consoleArgumentError(name, std::to_string(nFixed) + (more ? " or more" : "") + " arguments expected, got " + std::to_string(nArgs), types);
188216
}
189217
auto autoType = [](const std::string& text, bool plain) -> consoleArg { // int64_t for [+-]digits, double for other decimal numbers (also with exponent, as saveSettings writes them), string otherwise or if plain text
190218
const char *begin = text.c_str() + (text[0] == '+' || text[0] == '-'), *end = text.c_str() + text.size();
@@ -204,12 +232,12 @@ std::tuple<const GPUDisplayConsole::GPUDisplayConsoleCommand&, std::vector<GPUDi
204232
const char type = i < nFixed ? types[i] : '+';
205233
consoleArg value = type == 's' ? consoleArg(text) : autoType(text, plain);
206234
if (type == 'i' && !std::holds_alternative<int64_t>(value)) {
207-
throw std::runtime_error(name + ": argument " + std::to_string(i + 1) + " (" + text + ") must be an integer");
235+
throw consoleArgumentError(name, "argument " + std::to_string(i + 1) + " (" + text + ") must be an integer", types);
208236
} else if (type == 'd') {
209237
if (std::holds_alternative<int64_t>(value)) {
210238
value = (double)std::get<int64_t>(value);
211239
} else if (!std::holds_alternative<double>(value)) {
212-
throw std::runtime_error(name + ": argument " + std::to_string(i + 1) + " (" + text + ") must be a number");
240+
throw consoleArgumentError(name, "argument " + std::to_string(i + 1) + " (" + text + ") must be a number", types);
213241
}
214242
} else if (type != 's' && type != 'i' && type != 'a' && type != '+') {
215243
throw std::runtime_error(name + ": invalid argument types " + types);
@@ -230,6 +258,9 @@ void GPUDisplayConsole::handleConsoleCommand(std::string_view cmd)
230258
auto parsed = parseConsoleCommand(cmd);
231259
command = &std::get<0>(parsed);
232260
args = std::move(std::get<1>(parsed));
261+
} catch (const consoleArgumentError& e) {
262+
consolePrint("Invalid arguments for %s: %s %s", e.command.c_str(), e.what(), e.usage.c_str());
263+
return;
233264
} catch (const std::runtime_error& e) {
234265
consolePrint("Invalid command: %s", e.what());
235266
return;

‎GPU/GPUTracking/display/frontend/GPUDisplayConsole.h‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ class GPUDisplayConsole : public GPUDisplayFrontendKeyVars // Text console of th
4141
};
4242
GPUDisplayConsole(const std::string& title); // First history entry, not selectable
4343

44-
void handleConsoleKey(uint8_t key); // Key typed while the console is shown
44+
void handleConsoleKey(uint8_t key, bool shift); // Key typed while the console is shown
45+
void scroll(int32_t lines); // Scrolls the history up (> 0) or down, limited to its lines
4546
void handleConsoleCommand(std::string_view cmd); // Runs the command named by the first token, error if unknown
4647
void runScript(std::string_view script); // Queues the lines (separated by \n / \r) as console commands before the remaining script lines, runs them up to a wait
4748
void runScriptFile(const std::string& filename); // runScript with the content of the file
@@ -76,6 +77,8 @@ class GPUDisplayConsole : public GPUDisplayFrontendKeyVars // Text console of th
7677
std::vector<std::string> mConsoleHistory; // Title, then commands entered in the console and their output (indented)
7778
std::string mConsoleText; // Text being typed in the console
7879
uint32_t mConsoleTextCurrent = 0; // Entry of mConsoleHistory shown in the console (selected with up / down, the title entry 0 is not selectable), 0 for mConsoleText
80+
uint32_t mScroll = 0; // History lines scrolled up (the lowest ones not shown), reset by enter
81+
uint32_t mVisibleLines = 1; // History lines fitting into the console, set when it is drawn
7982
uint32_t mConsoleTextPos = 0; // Cursor position in the shown text (left / right), the character there is the current one
8083
};
8184
} // namespace o2::gpu

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface, public GPUDisplay
116116
// Keyboard / Mouse actions
117117
bool mMouseDn = false; // Mouse button down
118118
bool mMouseDnR = false; // Right mouse button down
119-
bool mMouseDnM = false; // Middle mouse button down (not used yet)
119+
bool mMouseDnM = false; // Middle mouse button down, as left + right
120120
float mMouseDnX, mMouseDnY; // X/Y position where mouse button was pressed
121121
float mMouseMvX, mMouseMvY; // Current mouse pointer position
122122
int32_t mMouseWheel = 0; // Incremental value of mouse wheel, ca +/- 100 per wheel tick

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendConfig.cxx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ void GPUDisplay::HandleKey(uint8_t key, bool external, bool bypassConsole)
720720
{
721721
if (mCfgC.showConsole && !bypassConsole && mFrontend->mConfiguration->keyRTTIIndex(key) != mFrontend->mConfiguration->getRTTIIndex(*this, &GPUDisplayControl::showConsole)) { // All keys except the one toggling the console go to the console
722722
if (!external) {
723-
mFrontend->mConsole->handleConsoleKey(key);
723+
mFrontend->mConsole->handleConsoleKey(key, mFrontend->mKeys[mFrontend->KEY_SHIFT]);
724724
}
725725
return;
726726
}

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ void GPUDisplayFrontendGlfw::key_callback(GLFWwindow* window, int32_t key, int32
170170
int32_t handleKey = 0, keyPress = 0;
171171
GetKey(key, scancode, mods, handleKey, keyPress);
172172
if (handleKey < 32) {
173-
if (action == GLFW_PRESS || action == GLFW_REPEAT) { // Repeat as the other frontends (e.g. backspace in the console), characters are repeated by char_callback
174-
me->mKeys[keyPress] = !me->consoleShown();
173+
if (action == GLFW_PRESS || action == GLFW_REPEAT) { // Repeat as the other frontends (e.g. backspace in the console), characters are repeated by char_callback
174+
me->mKeys[keyPress] = keyPress == KEY_SHIFT || !me->consoleShown(); // Held keys only without console, SHIFT also with it (scrolling)
175175
me->HandleKey(handleKey);
176176
} else if (action == GLFW_RELEASE) {
177177
me->mKeys[keyPress] = false;
@@ -203,7 +203,7 @@ void GPUDisplayFrontendGlfw::char_callback(GLFWwindow* window, uint32_t codepoin
203203
keyPress += 'A' - 'a';
204204
}
205205
me->mGLFWKeyDownMap[me->mLastKeyDown] = keyPress;
206-
me->mKeys[keyPress] = !me->consoleShown();
206+
me->mKeys[keyPress] = keyPress == KEY_SHIFT || !me->consoleShown(); // Held keys only without console, SHIFT also with it (scrolling)
207207
me->HandleKey(codepoint);
208208
}
209209
}

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void GPUDisplayFrontendGlut::keyboardFunc(int32_t key, bool special, bool down)
134134
{
135135
int32_t handleKey = 0, keyPress = 0;
136136
GetKey(key, handleKey, keyPress, special);
137-
mKeys[keyPress] = down && !consoleShown();
137+
mKeys[keyPress] = down && (keyPress == KEY_SHIFT || !consoleShown()); // Held keys only without console, SHIFT also with it (scrolling)
138138
if (down) {
139139
HandleKey(handleKey);
140140
}

0 commit comments

Comments
 (0)