diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 26996e89..ecefb2fd 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -125,6 +125,7 @@ set(SOURCES src/overlay/fps.c src/overlay/graphs.c + src/overlay/help.c ) # Force cimgui to build as a static library. diff --git a/client/include/app.h b/client/include/app.h index a147bb7c..41837523 100644 --- a/client/include/app.h +++ b/client/include/app.h @@ -138,9 +138,4 @@ void app_releaseKeybind(KeybindHandle * handle); */ void app_releaseAllKeybinds(void); -/** - * Changes whether the help message is displayed or not. - */ -void app_showHelp(bool show); - #endif diff --git a/client/include/overlay_utils.h b/client/include/overlay_utils.h index 4ef7994e..282c9c42 100644 --- a/client/include/overlay_utils.h +++ b/client/include/overlay_utils.h @@ -27,7 +27,10 @@ extern "C" { #endif +typedef struct ImVec2 ImVec2; + void overlayGetImGuiRect(struct Rect * rect); +ImVec2 * overlayGetScreenSize(void); void imGuiResetStyle(void); #ifdef __cplusplus diff --git a/client/src/app.c b/client/src/app.c index 8c793b8e..b302d0df 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -429,7 +429,6 @@ void app_handleRenderEvent(const uint64_t timeUs) if (g_state.escapeHelp) { g_state.escapeHelp = false; - app_showHelp(false); } } else @@ -437,7 +436,6 @@ void app_handleRenderEvent(const uint64_t timeUs) if (!g_state.escapeHelp && timeUs - g_state.escapeTime > g_params.helpMenuDelayUs) { g_state.escapeHelp = true; - app_showHelp(true); } } } @@ -562,58 +560,6 @@ void app_releaseAllKeybinds(void) } } -static char * build_help_str() -{ - size_t size = 50; - size_t offset = 0; - char * buffer = malloc(size); - - if (!buffer) - return NULL; - - const char * escapeName = xfree86_to_display[g_params.escapeKey]; - - offset += snprintf(buffer, size, "%s %-10s Toggle capture mode\n", escapeName, ""); - if (offset >= size) - { - DEBUG_ERROR("Help string somehow overflowed. This should be impossible."); - return NULL; - } - - for (int i = 0; i < KEY_MAX; ++i) - { - if (g_state.keyDescription[i]) - { - const char * keyName = xfree86_to_display[i]; - const char * desc = g_state.keyDescription[i]; - int needed = snprintf(buffer + offset, size - offset, "%s+%-10s %s\n", escapeName, keyName, desc); - if (offset + needed < size) - offset += needed; - else - { - size = size * 2 + needed; - void * new = realloc(buffer, size); - if (!new) { - free(buffer); - DEBUG_ERROR("Out of memory when constructing help text"); - return NULL; - } - buffer = new; - offset += snprintf(buffer + offset, size - offset, "%s+%-10s %s\n", escapeName, keyName, desc); - } - } - } - - return buffer; -} - -void app_showHelp(bool show) -{ - char * help = show ? build_help_str() : NULL; - g_state.lgr->on_help(g_state.lgrData, help); - free(help); -} - GraphHandle app_registerGraph(const char * name, RingBuffer buffer) { return overlayGraph_register(name, buffer); diff --git a/client/src/main.c b/client/src/main.c index 33fcd033..5c164ec5 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -776,6 +776,7 @@ static int lg_run(void) g_state.overlays = ll_new(); app_registerOverlay(&LGOverlayFPS , NULL); app_registerOverlay(&LGOverlayGraphs, NULL); + app_registerOverlay(&LGOverlayHelp , NULL); // initialize metrics ringbuffers g_state.renderTimings = ringbuffer_new(256, sizeof(float)); diff --git a/client/src/overlay/help.c b/client/src/overlay/help.c new file mode 100644 index 00000000..ed89174b --- /dev/null +++ b/client/src/overlay/help.c @@ -0,0 +1,140 @@ +/** + * Looking Glass + * Copyright (C) 2017-2021 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "interface/overlay.h" +#include "cimgui.h" +#include "overlay_utils.h" + +#include "common/debug.h" + +#include "../kb.h" +#include "../main.h" + +struct HelpData +{ + char * helpText; +}; + +static bool help_init(void ** udata, void * params) +{ + *udata = calloc(1, sizeof(struct HelpData)); + if (!udata) + { + DEBUG_ERROR("Out of memory"); + return false; + } + return true; +} + +static void help_free(void * udata) +{ + free(udata); +} + +static char * buildHelpText(void) +{ + size_t size = 50; + size_t offset = 0; + char * buffer = malloc(size); + + if (!buffer) + return NULL; + + const char * escapeName = xfree86_to_display[g_params.escapeKey]; + + offset += snprintf(buffer, size, "%s %-10s Toggle capture mode\n", escapeName, ""); + if (offset >= size) + { + DEBUG_ERROR("Help string somehow overflowed. This should be impossible."); + return NULL; + } + + for (int i = 0; i < KEY_MAX; ++i) + { + if (g_state.keyDescription[i]) + { + const char * keyName = xfree86_to_display[i]; + const char * desc = g_state.keyDescription[i]; + int needed = snprintf(buffer + offset, size - offset, "%s+%-10s %s\n", escapeName, keyName, desc); + if (offset + needed < size) + offset += needed; + else + { + size = size * 2 + needed; + void * new = realloc(buffer, size); + if (!new) { + free(buffer); + DEBUG_ERROR("Out of memory when constructing help text"); + return NULL; + } + buffer = new; + offset += snprintf(buffer + offset, size - offset, "%s+%-10s %s\n", escapeName, keyName, desc); + } + } + } + + return buffer; +} + +static int help_render(void * udata, bool interactive, struct Rect * windowRects, + int maxRects) +{ + struct HelpData * data = udata; + + if (!g_state.escapeHelp) + { + if (data->helpText) + { + free(data->helpText); + data->helpText = NULL; + } + return 0; + } + + if (!data->helpText) + data->helpText = buildHelpText(); + + ImVec2 * screen = overlayGetScreenSize(); + igSetNextWindowBgAlpha(0.6f); + igSetNextWindowPos((ImVec2) { 0.0f, screen->y }, 0, (ImVec2) { 0.0f, 1.0f }); + + igBegin( + "Help", + NULL, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar + ); + + igText("%s", data->helpText); + + overlayGetImGuiRect(windowRects); + igEnd(); + + return 1; +} + +struct LG_OverlayOps LGOverlayHelp = +{ + .name = "Help", + .init = help_init, + .free = help_free, + .render = help_render +}; diff --git a/client/src/overlay_utils.c b/client/src/overlay_utils.c index 2785eb60..56e13cfc 100644 --- a/client/src/overlay_utils.c +++ b/client/src/overlay_utils.c @@ -21,6 +21,7 @@ #include "overlay_utils.h" #include "cimgui.h" +#include "main.h" void overlayGetImGuiRect(struct Rect * rect) { @@ -35,3 +36,8 @@ void overlayGetImGuiRect(struct Rect * rect) rect->w = size.x; rect->h = size.y; } + +ImVec2 * overlayGetScreenSize(void) +{ + return &g_state.io->DisplaySize; +} diff --git a/client/src/overlays.h b/client/src/overlays.h index 24b88c99..e121472b 100644 --- a/client/src/overlays.h +++ b/client/src/overlays.h @@ -25,6 +25,7 @@ extern struct LG_OverlayOps LGOverlayFPS; extern struct LG_OverlayOps LGOverlayGraphs; +extern struct LG_OverlayOps LGOverlayHelp; GraphHandle overlayGraph_register(const char * name, RingBuffer buffer); void overlayGraph_unregister();