From 1cbc8ec6f5ff2d95785d43d5fa697cadcb5085b9 Mon Sep 17 00:00:00 2001 From: AlexandreRouma Date: Wed, 16 Oct 2024 18:31:14 +0200 Subject: [PATCH] add copy/paste support to the frequency selector --- core/src/gui/widgets/frequency_select.cpp | 34 ++++++- core/src/utils/hrfreq.cpp | 113 ++++++++++++++++++++++ core/src/utils/hrfreq.h | 19 ++++ 3 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 core/src/utils/hrfreq.cpp create mode 100644 core/src/utils/hrfreq.h diff --git a/core/src/gui/widgets/frequency_select.cpp b/core/src/gui/widgets/frequency_select.cpp index 78794cd0..07f4dfbd 100644 --- a/core/src/gui/widgets/frequency_select.cpp +++ b/core/src/gui/widgets/frequency_select.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS @@ -90,6 +91,7 @@ void FrequencySelect::moveCursorToDigit(int i) { void FrequencySelect::draw() { auto window = ImGui::GetCurrentWindow(); + auto io = ImGui::GetIO(); widgetPos = ImGui::GetWindowContentRegionMin(); ImVec2 cursorPos = ImGui::GetCursorPos(); widgetPos.x += window->Pos.x + cursorPos.x; @@ -132,7 +134,7 @@ void FrequencySelect::draw() { ImVec2 mousePos = ImGui::GetMousePos(); bool leftClick = ImGui::IsMouseClicked(ImGuiMouseButton_Left); bool rightClick = ImGui::IsMouseClicked(ImGuiMouseButton_Right); - int mw = ImGui::GetIO().MouseWheel; + int mw = io.MouseWheel; bool onDigit = false; bool hovered = false; @@ -174,7 +176,7 @@ void FrequencySelect::draw() { moveCursorToDigit(i + 1); } - auto chars = ImGui::GetIO().InputQueueCharacters; + auto chars = io.InputQueueCharacters; // For each keyboard characters, type it for (int j = 0; j < chars.Size; j++) { @@ -194,6 +196,34 @@ void FrequencySelect::draw() { } } digitHovered = hovered; + + if (isInArea(mousePos, digitTopMins[0], digitBottomMaxs[11])) { + bool shortcutKey = io.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl); + bool ctrlOnly = (io.KeyMods == ImGuiKeyModFlags_Ctrl); + bool shiftOnly = (io.KeyMods == ImGuiKeyModFlags_Shift); + bool copy = ((shortcutKey && ImGui::IsKeyPressed(ImGuiKey_C)) || (ctrlOnly && ImGui::IsKeyPressed(ImGuiKey_Insert))); + bool paste = ((shortcutKey && ImGui::IsKeyPressed(ImGuiKey_V)) || (shiftOnly && ImGui::IsKeyPressed(ImGuiKey_Insert))); + if (copy) { + // Convert the freqency to a string + std::string freqStr = hrfreq::toString(frequency); + + // Write it to the clipboard + ImGui::SetClipboardText(freqStr.c_str()); + } + if (paste) { + // Attempt to parse the clipboard as a number + const char* clip = ImGui::GetClipboardText(); + + // If the clipboard is not empty, attempt to parse it + if (clip) { + double newFreq; + if (hrfreq::fromString(clip, newFreq)) { + setFrequency(abs(newFreq)); + frequencyChanged = true; + } + } + } + } } uint64_t freq = 0; diff --git a/core/src/utils/hrfreq.cpp b/core/src/utils/hrfreq.cpp new file mode 100644 index 00000000..f61554ca --- /dev/null +++ b/core/src/utils/hrfreq.cpp @@ -0,0 +1,113 @@ +#include "hrfreq.h" +#include + +namespace hrfreq { + + + std::string toString(double freq) { + // Determine the scale + int maxDecimals = 0; + const char* suffix = "Hz"; + if (freq >= 1e9) { + freq /= 1e9; + maxDecimals = 9; + suffix = "GHz"; + } + else if (freq >= 1e6) { + freq /= 1e6; + maxDecimals = 6; + suffix = "MHz"; + } + else if (freq >= 1e3) { + freq /= 1e3; + maxDecimals = 3; + suffix = "KHz"; + } + + // Convert to string (TODO: Not sure if limiting the decimals rounds) + char numBuf[128]; + int numLen = sprintf(numBuf, "%0.*lf", maxDecimals, freq); + + // Remove the useless zeros + for (int i = numLen-1; i >= 0; i--) { + if (numBuf[i] != '0' && numBuf[i] != '.') { break; } + numBuf[i] = 0; + } + + // Concat the suffix + char finalBuf[128]; + sprintf(finalBuf, "%s%s", numBuf, suffix); + + // Return the final string + return finalBuf; + } + + bool isNumeric(char c) { + return std::isdigit(c) || c == '+' || c == '-' || c == '.' || c == ','; + } + + bool fromString(const std::string& str, double& freq) { + // Skip non-numeric characters + int i = 0; + char c; + for (; i < str.size(); i++) { + if (isNumeric(str[i])) { break; } + } + + // Extract the numeric part + std::string numeric; + for (; i < str.size(); i++) { + // Get the character + c = str[i]; + + // If it's a letter, stop + if (std::isalpha(c)) { break; } + + // If isn't numeric, skip it + if (!isNumeric(c)) { continue; } + + // Add the character to the numeric string + numeric += c; + } + + // Attempt to parse the numeric part + double num; + try { + num = std::stod(numeric); + } + catch (const std::exception& e) { + flog::error("Failed to parse numeric part: '{}'", numeric); + return false; + } + + // If no more text is available, assume the numeric part gives a frequency in Hz + if (i == str.size()) { + flog::warn("No unit given, assuming it's Hz"); + freq = num; + return true; + } + + // Scale the numeric value depending on the first scale character + char scale = std::toupper(str[i]); + switch (scale) { + case 'G': + num *= 1e9; + break; + case 'M': + num *= 1e6; + break; + case 'K': + num *= 1e3; + break; + case 'H': + break; + default: + flog::warn("Unknown frequency scale: '{}'", scale); + break; + } + + // Return the frequency + freq = num; + return true; // TODO + } +} \ No newline at end of file diff --git a/core/src/utils/hrfreq.h b/core/src/utils/hrfreq.h new file mode 100644 index 00000000..24901e9f --- /dev/null +++ b/core/src/utils/hrfreq.h @@ -0,0 +1,19 @@ +#pragma once +#include + +namespace hrfreq { + /** + * Convert a frequency to a human-readable string. + * @param freq Frequency in Hz. + * @return Human-readable representation of the frequency. + */ + std::string toString(double freq); + + /** + * Convert a human-readable representation of a frequency to a frequency value. + * @param str String containing the human-readable frequency. + * @param freq Value to write the decoded frequency to. + * @return True on success, false otherwise. + */ + bool fromString(const std::string& str, double& freq); +} \ No newline at end of file