removed scrolling due to bug + Fixed file source

This commit is contained in:
Ryzerth 2021-02-07 23:47:17 +01:00
parent 49ec3d68d2
commit 9df90e5e75
37 changed files with 11910 additions and 3792 deletions

View File

@ -16,6 +16,7 @@ add_subdirectory("core")
# Base modules # Base modules
add_subdirectory("radio") add_subdirectory("radio")
add_subdirectory("recorder") add_subdirectory("recorder")
add_subdirectory("file_source")
# Source modules # Source modules
if (OPT_BUILD_RTL_TCP_SOURCE) if (OPT_BUILD_RTL_TCP_SOURCE)

View File

@ -8,7 +8,7 @@
#include <config.h> #include <config.h>
#include <options.h> #include <options.h>
#include <libairspy/airspy.h> #include <libairspy/airspy.h>
#include <gui/widgets/scroll_behavior.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -406,7 +406,7 @@ private:
ImGui::Text("Gain"); ImGui::Text("Gain");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderInt(CONCAT("##_airspy_sens_gain_", _this->name), &_this->sensitiveGain, 0, 21) || ImGui::AllowScrollwheelStSz<int>(_this->sensitiveGain, 1, 0, 21)) { if (ImGui::SliderInt(CONCAT("##_airspy_sens_gain_", _this->name), &_this->sensitiveGain, 0, 21)) {
if (_this->running) { if (_this->running) {
airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain); airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
} }
@ -421,7 +421,7 @@ private:
ImGui::Text("Gain"); ImGui::Text("Gain");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderInt(CONCAT("##_airspy_lin_gain_", _this->name), &_this->linearGain, 0, 21) || ImGui::AllowScrollwheelStSz<int>(_this->linearGain, 1, 0, 21)) { if (ImGui::SliderInt(CONCAT("##_airspy_lin_gain_", _this->name), &_this->linearGain, 0, 21)) {
if (_this->running) { if (_this->running) {
airspy_set_linearity_gain(_this->openDev, _this->linearGain); airspy_set_linearity_gain(_this->openDev, _this->linearGain);
} }
@ -441,7 +441,7 @@ private:
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(pos); ImGui::SetCursorPosX(pos);
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderInt(CONCAT("##_airspy_lna_gain_", _this->name), &_this->lnaGain, 0, 15) || ImGui::AllowScrollwheelStSz<int>(_this->lnaGain, 1, 0, 15)) { if (ImGui::SliderInt(CONCAT("##_airspy_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) {
if (_this->running) { if (_this->running) {
airspy_set_lna_gain(_this->openDev, _this->lnaGain); airspy_set_lna_gain(_this->openDev, _this->lnaGain);
} }
@ -458,7 +458,7 @@ private:
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(pos); ImGui::SetCursorPosX(pos);
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderInt(CONCAT("##_airspy_mix_gain_", _this->name), &_this->mixerGain, 0, 15) || ImGui::AllowScrollwheelStSz<int>(_this->mixerGain, 1, 0, 15)) { if (ImGui::SliderInt(CONCAT("##_airspy_mix_gain_", _this->name), &_this->mixerGain, 0, 15)) {
if (_this->running) { if (_this->running) {
airspy_set_mixer_gain(_this->openDev, _this->mixerGain); airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
} }
@ -474,7 +474,7 @@ private:
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(pos); ImGui::SetCursorPosX(pos);
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderInt(CONCAT("##_airspy_vga_gain_", _this->name), &_this->vgaGain, 0, 15) || ImGui::AllowScrollwheelStSz<int>(_this->vgaGain, 1, 0, 15)) { if (ImGui::SliderInt(CONCAT("##_airspy_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) {
if (_this->running) { if (_this->running) {
airspy_set_vga_gain(_this->openDev, _this->vgaGain); airspy_set_vga_gain(_this->openDev, _this->vgaGain);
} }

View File

@ -26,7 +26,7 @@ namespace LoadingScreen {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 20.0f));
ImGui::OpenPopup("Credits"); ImGui::OpenPopup("Credits");
ImGui::PushStyleColor(ImGuiCol_ModalWindowDarkening, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::BeginPopupModal("Credits", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground); ImGui::BeginPopupModal("Credits", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground);
ImGui::PushFont(style::hugeFont); ImGui::PushFont(style::hugeFont);

View File

@ -32,10 +32,12 @@
#include <gui/dialogs/loading_screen.h> #include <gui/dialogs/loading_screen.h>
#include <options.h> #include <options.h>
#include <gui/colormaps.h> #include <gui/colormaps.h>
#include <gui/widgets/scroll_behavior.h>
#include <gui/widgets/file_select.h> #include <gui/widgets/file_select.h>
FileSelect fileSelect("%ROOT/recordings", "Alllll\0*.*\0Text\0*.TXT\0"); #include <gui/widgets/folder_select.h>
FileSelect fileSelect("D:/Downloads/unicast.wav");
FolderSelect foldSelect("%ROOT/recordings");
// const int FFTSizes[] = { // const int FFTSizes[] = {
// 65536, // 65536,
@ -114,11 +116,21 @@ bool centerTuning = false;
dsp::stream<dsp::complex_t> dummyStream; dsp::stream<dsp::complex_t> dummyStream;
bool demoWindow = false; bool demoWindow = false;
COMDLG_FILTERSPEC rgSpec[] ={
{ L"Wav File", L"*.wav" },
{ L"All", L"*.*" },
};
void windowInit() { void windowInit() {
LoadingScreen::show("Initializing UI"); LoadingScreen::show("Initializing UI");
gui::waterfall.init(); gui::waterfall.init();
gui::waterfall.setRawFFTSize(fftSize); gui::waterfall.setRawFFTSize(fftSize);
// TEMP TEST
fileSelect.setWindowsFilter(rgSpec, 2);
// ==========
tempFFT = new float[fftSize]; tempFFT = new float[fftSize];
FFTdata = new float[fftSize]; FFTdata = new float[fftSize];
@ -558,6 +570,9 @@ void drawWindow() {
ImGui::Checkbox("Show demo window", &demoWindow); ImGui::Checkbox("Show demo window", &demoWindow);
ImGui::Checkbox("Experimental zoom", &experimentalZoom); ImGui::Checkbox("Experimental zoom", &experimentalZoom);
fileSelect.render("##_testfile"); fileSelect.render("##_testfile");
foldSelect.render("##_testfold");
ImGui::Text("ImGui version: %s", ImGui::GetVersion());
ImGui::Spacing(); ImGui::Spacing();
} }
@ -589,8 +604,7 @@ void drawWindow() {
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Zoom").x / 2.0)); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Zoom").x / 2.0));
ImGui::Text("Zoom"); ImGui::Text("Zoom");
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
if (ImGui::VSliderFloat("##_7_", ImVec2(20.0, 150.0), &bw, gui::waterfall.getBandwidth(), 1000.0, "", (experimentalZoom ? 2.0 : 1.0)) || if (ImGui::VSliderFloat("##_7_", ImVec2(20.0, 150.0), &bw, gui::waterfall.getBandwidth(), 1000.0, "", (experimentalZoom ? 2.0 : 1.0))) {
ImGui::AllowScrollwheel<float>(bw, 20, gui::waterfall.getBandwidth(), 1000.0)) {
gui::waterfall.setViewBandwidth(bw); gui::waterfall.setViewBandwidth(bw);
if (vfo != NULL) { if (vfo != NULL) {
gui::waterfall.setViewOffset(vfo->centerOffset); // center vfo on screen gui::waterfall.setViewOffset(vfo->centerOffset); // center vfo on screen
@ -602,7 +616,7 @@ void drawWindow() {
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Max").x / 2.0)); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Max").x / 2.0));
ImGui::Text("Max"); ImGui::Text("Max");
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
if (ImGui::VSliderFloat("##_8_", ImVec2(20.0, 150.0), &fftMax, 0.0, -100.0, "") || ImGui::AllowScrollwheel<float>(fftMax, 20, -100, 0)) { if (ImGui::VSliderFloat("##_8_", ImVec2(20.0, 150.0), &fftMax, 0.0, -100.0, "")) {
fftMax = std::max<float>(fftMax, fftMin + 10); fftMax = std::max<float>(fftMax, fftMin + 10);
core::configManager.aquire(); core::configManager.aquire();
core::configManager.conf["max"] = fftMax; core::configManager.conf["max"] = fftMax;
@ -614,7 +628,7 @@ void drawWindow() {
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Min").x / 2.0)); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Min").x / 2.0));
ImGui::Text("Min"); ImGui::Text("Min");
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
if (ImGui::VSliderFloat("##_9_", ImVec2(20.0, 150.0), &fftMin, 0.0, -100.0, "") || ImGui::AllowScrollwheel<float>(fftMin, 20, -100, 0)) { if (ImGui::VSliderFloat("##_9_", ImVec2(20.0, 150.0), &fftMin, 0.0, -100.0, "")) {
fftMin = std::min<float>(fftMax - 10, fftMin); fftMin = std::min<float>(fftMax - 10, fftMin);
core::configManager.aquire(); core::configManager.aquire();
core::configManager.conf["min"] = fftMin; core::configManager.conf["min"] = fftMin;

View File

@ -99,7 +99,7 @@ namespace style {
colors[ImGuiCol_PlotHistogram] = ImVec4(0.73f, 0.60f, 0.15f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.73f, 0.60f, 0.15f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.87f, 0.87f, 0.87f, 0.35f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.87f, 0.87f, 0.87f, 0.35f);
colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); colors[ImGuiCol_NavHighlight] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);

View File

@ -3,14 +3,14 @@
#include <options.h> #include <options.h>
#include <filesystem> #include <filesystem>
FileSelect::FileSelect(std::string defaultPath, char* filter) { FileSelect::FileSelect(std::string defaultPath) {
path = defaultPath; path = defaultPath;
strcpy(_filter, filter);
pathValid = std::filesystem::is_regular_file(path); pathValid = std::filesystem::is_regular_file(path);
strcpy(strPath, path.c_str()); strcpy(strPath, path.c_str());
} }
void FileSelect::render(std::string id) { bool FileSelect::render(std::string id) {
bool _pathChanged = false;
#ifdef _WIN32 #ifdef _WIN32
float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); float menuColumnWidth = ImGui::GetContentRegionAvailWidth();
float buttonWidth = ImGui::CalcTextSize("...").x + 20.0f; float buttonWidth = ImGui::CalcTextSize("...").x + 20.0f;
@ -59,6 +59,15 @@ void FileSelect::render(std::string id) {
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }
#endif #endif
_pathChanged |= pathChanged;
pathChanged = false;
return _pathChanged;
}
void FileSelect::setPath(std::string path) {
this->path = path;
pathValid = std::filesystem::is_regular_file(path);
strcpy(strPath, path.c_str());
} }
std::string FileSelect::expandString(std::string input) { std::string FileSelect::expandString(std::string input) {
@ -70,45 +79,35 @@ bool FileSelect::pathIsValid() {
return pathValid; return pathValid;
} }
bool FileSelect::pathChanged() { #ifdef _WIN32
if (_pathChanged) {
_pathChanged = false; void FileSelect::setWindowsFilter(COMDLG_FILTERSPEC* filt, int n) {
return true; filter = filt;
} filterCount = n;
return false;
} }
#ifdef _WIN32
void FileSelect::windowsWorker() { void FileSelect::windowsWorker() {
OPENFILENAMEA ofn; // common dialog box structure IFileOpenDialog *pFileOpen;
char szFile[2048]; // buffer for file name HRESULT hr;
HWND hwnd; // owner window
HANDLE hf; // file handle
// Initialize OPENFILENAME // Create the FileOpenDialog object.
ZeroMemory(&ofn, sizeof(ofn)); hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = GetFocus(); if (filter != NULL) { pFileOpen->SetFileTypes(filterCount, filter); }
ofn.lpstrFile = (LPSTR)szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = (LPCSTR)_filter;
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXTENSIONDIFFERENT;
// Display the Open dialog box. hr = pFileOpen->Show(NULL);
if (SUCCEEDED(hr)) {
if (GetOpenFileNameA(&ofn)==TRUE) { PWSTR pszFilePath;
strcpy(strPath, szFile); IShellItem *pItem;
_pathChanged = true; hr = pFileOpen->GetResult(&pItem);
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
wcstombs(strPath, pszFilePath, 2048);
CoTaskMemFree(pszFilePath);
path = std::string(strPath);
pathChanged = true;
} }
pathValid = std::filesystem::is_regular_file(strPath); pathValid = std::filesystem::is_regular_file(path);
dialogOpen = false; dialogOpen = false;
} }
#endif #endif

View File

@ -7,28 +7,35 @@
#ifdef _WIN32 #ifdef _WIN32
#include <Windows.h> #include <Windows.h>
#include <thread> #include <thread>
#include <ShObjIdl.h>
#endif #endif
class FileSelect { class FileSelect {
public: public:
FileSelect(std::string defaultPath, char* filter = "All\0*.*"); FileSelect(std::string defaultPath);
void render(std::string id); bool render(std::string id);
void setPath(std::string path);
bool pathIsValid(); bool pathIsValid();
bool pathChanged();
std::string expandString(std::string input); std::string expandString(std::string input);
std::string path = ""; std::string path = "";
#ifdef _WIN32
void setWindowsFilter(COMDLG_FILTERSPEC* filt, int n);
#endif
private: private:
#ifdef _WIN32 #ifdef _WIN32
void windowsWorker(); void windowsWorker();
std::thread workerThread; std::thread workerThread;
COMDLG_FILTERSPEC* filter = NULL;
int filterCount = 0;
#endif #endif
char _filter[2048]; char _filter[2048];
bool pathValid = false; bool pathValid = false;
bool dialogOpen = false; bool dialogOpen = false;
char strPath[2048]; char strPath[2048];
bool _pathChanged = false; bool pathChanged = false;
}; };

View File

@ -0,0 +1,108 @@
#include <gui/widgets/folder_select.h>
#include <regex>
#include <options.h>
#include <filesystem>
FolderSelect::FolderSelect(std::string defaultPath) {
setPath(defaultPath);
}
bool FolderSelect::render(std::string id) {
bool _pathChanged = false;
#ifdef _WIN32
float menuColumnWidth = ImGui::GetContentRegionAvailWidth();
float buttonWidth = ImGui::CalcTextSize("...").x + 20.0f;
bool lastPathValid = pathValid;
if (!lastPathValid) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
}
ImGui::SetNextItemWidth(menuColumnWidth - buttonWidth);
if (ImGui::InputText(id.c_str(), strPath, 2047)) {
path = std::string(strPath);
std::string expandedPath = expandString(strPath);
if (!std::filesystem::is_directory(expandedPath)) {
pathValid = false;
}
else {
pathValid = true;
_pathChanged = true;
}
}
if (!lastPathValid) {
ImGui::PopStyleColor();
}
ImGui::SameLine();
if (ImGui::Button(("..." + id + "_winselect").c_str(), ImVec2(buttonWidth - 8.0f, 0)) && !dialogOpen) {
dialogOpen = true;
if (workerThread.joinable()) { workerThread.join(); }
workerThread = std::thread(&FolderSelect::windowsWorker, this);
}
#else
bool lastPathValid = pathValid;
if (!lastPathValid) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
}
if (ImGui::InputText(id.c_str(), strPath, 2047)) {
path = std::string(strPath);
std::string expandedPath = expandString(strPath);
if (!std::filesystem::is_directory(expandedPath)) {
pathValid = false;
}
else {
pathValid = true;
_pathChanged = true;
}
}
if (!lastPathValid) {
ImGui::PopStyleColor();
}
#endif
_pathChanged |= pathChanged;
pathChanged = false;
return _pathChanged;
}
void FolderSelect::setPath(std::string path) {
this->path = path;
std::string expandedPath = expandString(path);
pathValid = std::filesystem::is_directory(expandedPath);
strcpy(strPath, path.c_str());
}
std::string FolderSelect::expandString(std::string input) {
input = std::regex_replace(input, std::regex("%ROOT%"), options::opts.root);
return std::regex_replace(input, std::regex("//"), "/");
}
bool FolderSelect::pathIsValid() {
return pathValid;
}
#ifdef _WIN32
void FolderSelect::windowsWorker() {
IFileOpenDialog *pFileOpen;
HRESULT hr;
// Create the FileOpenDialog object.
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
DWORD options;
pFileOpen->GetOptions(&options);
pFileOpen->SetOptions(options | FOS_PICKFOLDERS);
hr = pFileOpen->Show(NULL);
if (SUCCEEDED(hr)) {
PWSTR pszFilePath;
IShellItem *pItem;
hr = pFileOpen->GetResult(&pItem);
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
wcstombs(strPath, pszFilePath, 2048);
CoTaskMemFree(pszFilePath);
path = std::string(strPath);
pathChanged = true;
}
pathValid = std::filesystem::is_directory(path);
dialogOpen = false;
}
#endif

View File

@ -0,0 +1,35 @@
#pragma once
#include <imgui.h>
#include <imgui_internal.h>
#include <stdint.h>
#include <string>
#ifdef _WIN32
#include <Windows.h>
#include <ShlObj_core.h>
#include <thread>
#endif
class FolderSelect {
public:
FolderSelect(std::string defaultPath);
bool render(std::string id);
void setPath(std::string path);
bool pathIsValid();
std::string expandString(std::string input);
std::string path = "";
private:
#ifdef _WIN32
void windowsWorker();
std::thread workerThread;
#endif
bool pathValid = false;
bool dialogOpen = false;
char strPath[2048];
bool pathChanged = false;
};

View File

@ -1,21 +0,0 @@
#pragma once
#include <algorithm>
namespace ImGui {
template<class T>
inline bool AllowScrollwheel(T& value, int stepCount, T min, T max) {
if(!ImGui::IsItemHovered()) { return false; }
T lastVal = value;
T step = (max - min) / (T)stepCount;
value = std::clamp<T>(value + ((T)ImGui::GetIO().MouseWheel * step), (min < max) ? min : max, (max > min) ? max : min);
return (value != lastVal);
}
template<class T>
inline bool AllowScrollwheelStSz(T& value, T step, T min, T max) {
if(!ImGui::IsItemHovered()) { return false; }
T lastVal = value;
value = std::clamp<T>(value + ((T)ImGui::GetIO().MouseWheel * step), (min < max) ? min : max, (max > min) ? max : min);
return (value != lastVal);
}
}

View File

@ -1,7 +1,7 @@
#include <gui/widgets/stepped_slider.h> #include <gui/widgets/stepped_slider.h>
#include <imgui.h> #include <imgui.h>
#include <imgui_internal.h> #include <imgui_internal.h>
#include <gui/widgets/scroll_behavior.h>
namespace ImGui { namespace ImGui {
bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format) { bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format) {
@ -16,7 +16,6 @@ namespace ImGui {
const int countValues = int((v_max-v_min)/v_step); const int countValues = int((v_max-v_min)/v_step);
int v_i = int((*v - v_min)/v_step); int v_i = int((*v - v_min)/v_step);
bool value_changed = ImGui::SliderInt(label, &v_i, 0, countValues, text_buf); bool value_changed = ImGui::SliderInt(label, &v_i, 0, countValues, text_buf);
value_changed |= ImGui::AllowScrollwheelStSz<int>(v_i, 1, 0, countValues);
// Remap from [0,N] to [v_min,v_max] // Remap from [0,N] to [v_min,v_max]
*v = v_min + float(v_i) * v_step; *v = v_min + float(v_i) * v_step;

View File

@ -3,10 +3,11 @@
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h) // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include //-----------------------------------------------------------------------------
// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -30,7 +31,7 @@
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty. //#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements. //---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
@ -48,7 +49,7 @@
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR //#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support full unicode code points. //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32 //#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
@ -58,8 +59,8 @@
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library. //---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. // Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
// #define IMGUI_USE_STB_SPRINTF // #define IMGUI_USE_STB_SPRINTF
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
@ -75,12 +76,12 @@
*/ */
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices). // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. // Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int //#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList; //struct ImDrawList;
//struct ImDrawCmd; //struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// dear imgui: Platform Binding for GLFW // dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+) // (Requires: GLFW 3.1+)
@ -9,9 +9,9 @@
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
@ -143,7 +143,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
g_Window = window; g_Window = window;
g_Time = 0.0; g_Time = 0.0;
// Setup back-end capabilities flags // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
@ -345,7 +345,7 @@ static void ImGui_ImplGlfw_UpdateGamepads()
void ImGui_ImplGlfw_NewFrame() void ImGui_ImplGlfw_NewFrame()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing) // Setup display size (every frame to accommodate for window resizing)
int w, h; int w, h;
@ -358,7 +358,7 @@ void ImGui_ImplGlfw_NewFrame()
// Setup time step // Setup time step
double current_time = glfwGetTime(); double current_time = glfwGetTime();
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time; g_Time = current_time;
ImGui_ImplGlfw_UpdateMousePosAndButtons(); ImGui_ImplGlfw_UpdateMousePosAndButtons();
@ -366,4 +366,4 @@ void ImGui_ImplGlfw_NewFrame()
// Update game controllers (if enabled and available) // Update game controllers (if enabled and available)
ImGui_ImplGlfw_UpdateGamepads(); ImGui_ImplGlfw_UpdateGamepads();
} }

View File

@ -1,4 +1,4 @@
// dear imgui: Platform Binding for GLFW // dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
@ -8,9 +8,9 @@
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. // [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// About GLSL version: // About GLSL version:
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
@ -32,4 +32,4 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);

View File

@ -1,18 +1,23 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x // - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX. // 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix. // 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset. // 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
@ -24,7 +29,7 @@
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop. // 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
// 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. // 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). // 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. // 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. // 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
@ -80,7 +85,6 @@
#include <stdint.h> // intptr_t #include <stdint.h> // intptr_t
#endif #endif
// GL includes // GL includes
#if defined(IMGUI_IMPL_OPENGL_ES2) #if defined(IMGUI_IMPL_OPENGL_ES2)
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
@ -101,6 +105,8 @@
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code. #include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code. #include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
#include <glad/gl.h> // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
#ifndef GLFW_INCLUDE_NONE #ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. #define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
@ -121,10 +127,18 @@ using namespace gl;
#endif #endif
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have. // Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2) #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0 #define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
#else #endif
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1
// Desktop GL 3.3+ has glBindSampler()
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
#endif
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
#endif #endif
// OpenGL Data // OpenGL Data
@ -141,18 +155,25 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{ {
// Query for GL version (e.g. 320 for GL 3.2) // Query for GL version (e.g. 320 for GL 3.2)
#if !defined(IMGUI_IMPL_OPENGL_ES2) #if !defined(IMGUI_IMPL_OPENGL_ES2)
GLint major, minor; GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor); glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0 && minor == 0)
{
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
const char* gl_version = (const char*)glGetString(GL_VERSION);
sscanf(gl_version, "%d.%d", &major, &minor);
}
g_GlVersion = (GLuint)(major * 100 + minor * 10); g_GlVersion = (GLuint)(major * 100 + minor * 10);
#else #else
g_GlVersion = 200; // GLES 2 g_GlVersion = 200; // GLES 2
#endif #endif
// Setup back-end capabilities flags // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl3"; io.BackendRendererName = "imgui_impl_opengl3";
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 320) if (g_GlVersion >= 320)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#endif #endif
@ -176,7 +197,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
strcpy(g_GlslVersionString, glsl_version); strcpy(g_GlslVersionString, glsl_version);
strcat(g_GlslVersionString, "\n"); strcat(g_GlslVersionString, "\n");
// Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected. // Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it! // The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
// If auto-detection fails or doesn't select the same GL loader file as used by your application, // If auto-detection fails or doesn't select the same GL loader file as used by your application,
// you are likely to get a crash below. // you are likely to get a crash below.
@ -189,6 +210,8 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
gl_loader = "GLEW"; gl_loader = "GLEW";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
gl_loader = "GLAD"; gl_loader = "GLAD";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
gl_loader = "GLAD2";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
gl_loader = "glbinding2"; gl_loader = "glbinding2";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
@ -199,7 +222,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
gl_loader = "none"; gl_loader = "none";
#endif #endif
// Make a dummy GL call (we don't actually need the result) // Make an arbitrary GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
GLint current_texture; GLint current_texture;
@ -227,14 +250,19 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (g_GlVersion >= 310)
glDisable(GL_PRIMITIVE_RESTART);
#endif
#ifdef GL_POLYGON_MODE #ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif #endif
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
bool clip_origin_lower_left = true;
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) #if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
bool clip_origin_lower_left = true;
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin); GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
if (current_clip_origin == GL_UPPER_LEFT) if (current_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false; clip_origin_lower_left = false;
@ -247,7 +275,9 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y; float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
#endif
const float ortho_projection[4][4] = const float ortho_projection[4][4] =
{ {
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
@ -258,8 +288,10 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
glUseProgram(g_ShaderHandle); glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0); glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#ifdef GL_SAMPLER_BINDING
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (g_GlVersion >= 330)
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
#endif #endif
(void)vertex_array_object; (void)vertex_array_object;
@ -279,8 +311,8 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
} }
// OpenGL3 Render function. // OpenGL3 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. // This is in order to be able to run within an OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{ {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
@ -294,8 +326,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program); GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture); GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
#ifdef GL_SAMPLER_BINDING #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
GLuint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); GLuint last_sampler; if (g_GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
#endif #endif
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer); GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2 #ifndef IMGUI_IMPL_OPENGL_ES2
@ -315,7 +347,11 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
#endif
// Setup desired GL state // Setup desired GL state
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
@ -367,7 +403,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Bind texture, Draw // Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 320) if (g_GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset); glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else else
@ -386,8 +422,9 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Restore modified GL state // Restore modified GL state
glUseProgram(last_program); glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture); glBindTexture(GL_TEXTURE_2D, last_texture);
#ifdef GL_SAMPLER_BINDING #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
glBindSampler(0, last_sampler); if (g_GlVersion >= 330)
glBindSampler(0, last_sampler);
#endif #endif
glActiveTexture(last_active_texture); glActiveTexture(last_active_texture);
#ifndef IMGUI_IMPL_OPENGL_ES2 #ifndef IMGUI_IMPL_OPENGL_ES2
@ -399,7 +436,12 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
#endif
#ifdef GL_POLYGON_MODE #ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
#endif #endif

View File

@ -1,15 +1,15 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x // - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// About Desktop OpenGL function loaders: // About Desktop OpenGL function loaders:
// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. // Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
@ -49,6 +49,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ && !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
@ -68,6 +69,8 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
#define IMGUI_IMPL_OPENGL_LOADER_GLEW #define IMGUI_IMPL_OPENGL_LOADER_GLEW
#elif __has_include(<glad/glad.h>) #elif __has_include(<glad/glad.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLAD #define IMGUI_IMPL_OPENGL_LOADER_GLAD
#elif __has_include(<glad/gl.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLAD2
#elif __has_include(<GL/gl3w.h>) #elif __has_include(<GL/gl3w.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GL3W #define IMGUI_IMPL_OPENGL_LOADER_GL3W
#elif __has_include(<glbinding/glbinding.h>) #elif __has_include(<glbinding/glbinding.h>)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -148,6 +148,8 @@
// STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right
// STB_TEXTEDIT_K_UP keyboard input to move cursor up // STB_TEXTEDIT_K_UP keyboard input to move cursor up
// STB_TEXTEDIT_K_DOWN keyboard input to move cursor down // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page
// STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME
// STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END
// STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME
@ -170,14 +172,10 @@
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
// //
// Todo:
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page
//
// Keyboard input must be encoded as a single integer value; e.g. a character code // Keyboard input must be encoded as a single integer value; e.g. a character code
// and some bitflags that represent shift states. to simplify the interface, SHIFT must // and some bitflags that represent shift states. to simplify the interface, SHIFT must
// be a bitflag, so we can test the shifted state of cursor movements to allow selection, // be a bitflag, so we can test the shifted state of cursor movements to allow selection,
// i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. // i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.
// //
// You can encode other things, such as CONTROL or ALT, in additional bits, and // You can encode other things, such as CONTROL or ALT, in additional bits, and
// then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example,
@ -337,6 +335,10 @@ typedef struct
// each textfield keeps its own insert mode state. to keep an app-wide // each textfield keeps its own insert mode state. to keep an app-wide
// insert mode, copy this value in/out of the app state // insert mode, copy this value in/out of the app state
int row_count_per_page;
// page size in number of row.
// this value MUST be set to >0 for pageup or pagedown in multilines documents.
///////////////////// /////////////////////
// //
// private data // private data
@ -855,12 +857,16 @@ retry:
break; break;
case STB_TEXTEDIT_K_DOWN: case STB_TEXTEDIT_K_DOWN:
case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
case STB_TEXTEDIT_K_PGDOWN:
case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
StbFindState find; StbFindState find;
StbTexteditRow row; StbTexteditRow row;
int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
int row_count = is_page ? state->row_count_per_page : 1;
if (state->single_line) { if (!is_page && state->single_line) {
// on windows, up&down in single-line behave like left&right // on windows, up&down in single-line behave like left&right
key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
goto retry; goto retry;
@ -869,17 +875,25 @@ retry:
if (sel) if (sel)
stb_textedit_prep_selection_at_cursor(state); stb_textedit_prep_selection_at_cursor(state);
else if (STB_TEXT_HAS_SELECTION(state)) else if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_last(str,state); stb_textedit_move_to_last(str, state);
// compute current position of cursor point // compute current position of cursor point
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
// now find character position down a row for (j = 0; j < row_count; ++j) {
if (find.length) { float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float x;
int start = find.first_char + find.length; int start = find.first_char + find.length;
if (find.length == 0)
break;
// [DEAR IMGUI]
// going down while being on the last line shouldn't bring us to that line end
if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
break;
// now find character position down a row
state->cursor = start; state->cursor = start;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0; x = row.x0;
@ -901,17 +915,25 @@ retry:
if (sel) if (sel)
state->select_end = state->cursor; state->select_end = state->cursor;
// go to next line
find.first_char = find.first_char + find.length;
find.length = row.num_chars;
} }
break; break;
} }
case STB_TEXTEDIT_K_UP: case STB_TEXTEDIT_K_UP:
case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
case STB_TEXTEDIT_K_PGUP:
case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
StbFindState find; StbFindState find;
StbTexteditRow row; StbTexteditRow row;
int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
int row_count = is_page ? state->row_count_per_page : 1;
if (state->single_line) { if (!is_page && state->single_line) {
// on windows, up&down become left&right // on windows, up&down become left&right
key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
goto retry; goto retry;
@ -926,11 +948,14 @@ retry:
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
// can only go up if there's a previous row for (j = 0; j < row_count; ++j) {
if (find.prev_first != find.first_char) { float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
// can only go up if there's a previous row
if (find.prev_first == find.first_char)
break;
// now find character position up a row // now find character position up a row
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float x;
state->cursor = find.prev_first; state->cursor = find.prev_first;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0; x = row.x0;
@ -952,6 +977,14 @@ retry:
if (sel) if (sel)
state->select_end = state->cursor; state->select_end = state->cursor;
// go to previous line
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
--prev_scan;
find.first_char = find.prev_first;
find.prev_first = prev_scan;
} }
break; break;
} }
@ -1075,10 +1108,6 @@ retry:
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
} }
// @TODO:
// STB_TEXTEDIT_K_PGUP - move cursor up a page
// STB_TEXTEDIT_K_PGDOWN - move cursor down a page
} }
} }
@ -1134,7 +1163,7 @@ static void stb_textedit_discard_redo(StbUndoState *state)
state->undo_rec[i].char_storage += n; state->undo_rec[i].char_storage += n;
} }
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point' // now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
// {DEAR IMGUI] // [DEAR IMGUI]
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
@ -1350,6 +1379,7 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin
state->initialized = 1; state->initialized = 1;
state->single_line = (unsigned char) is_single_line; state->single_line = (unsigned char) is_single_line;
state->insert_mode = 0; state->insert_mode = 0;
state->row_count_per_page = 0;
} }
// API initialize // API initialize

View File

@ -3,7 +3,7 @@
#include <imgui/imgui.h> #include <imgui/imgui.h>
#include <gui/style.h> #include <gui/style.h>
#include <gui/icons.h> #include <gui/icons.h>
#include <gui/widgets/scroll_behavior.h>
#include <core.h> #include <core.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -217,7 +217,7 @@ void SinkManager::showVolumeSlider(std::string name, std::string prefix, float w
ImGui::SetNextItemWidth(width - height - 8); ImGui::SetNextItemWidth(width - height - 8);
ImGui::SetCursorPosY(ypos + ((height - sliderHeight) / 2.0f) + btwBorder); ImGui::SetCursorPosY(ypos + ((height - sliderHeight) / 2.0f) + btwBorder);
if (ImGui::SliderFloat((prefix + name).c_str(), &stream->guiVolume, 0.0f, 1.0f, "") || ImGui::AllowScrollwheel<float>(stream->guiVolume, 20, 0, 1)) { if (ImGui::SliderFloat((prefix + name).c_str(), &stream->guiVolume, 0.0f, 1.0f, "")) {
stream->setVolume(stream->guiVolume); stream->setVolume(stream->guiVolume);
core::configManager.aquire(); core::configManager.aquire();
saveStreamConfig(name); saveStreamConfig(name);

View File

@ -5,19 +5,22 @@
#include <signal_path/signal_path.h> #include <signal_path/signal_path.h>
#include <wavreader.h> #include <wavreader.h>
#include <core.h> #include <core.h>
#include <gui/widgets/file_select.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())
MOD_INFO { SDRPP_MOD_INFO {
/* Name: */ "fike_source", /* Name: */ "file_source",
/* Description: */ "File input module for SDR++", /* Description: */ "Wav file source module for SDR++",
/* Author: */ "Ryzerth", /* Author: */ "Ryzerth",
/* Version: */ "0.1.0" /* Version: */ 0, 1, 1,
/* Max instances */ 1
}; };
class FileSourceModule {
class FileSourceModule : public ModuleManager::Instance {
public: public:
FileSourceModule(std::string name) { FileSourceModule(std::string name) : fileSelect("") {
this->name = name; this->name = name;
handler.ctx = this; handler.ctx = this;
@ -30,10 +33,6 @@ public:
handler.stream = &stream; handler.stream = &stream;
sigpath::sourceManager.registerSource("File", &handler); sigpath::sourceManager.registerSource("File", &handler);
reader = new WavReader("D:/satpic/raw_recordings/NOAA-18_09-08-2018_21-39-00_baseband_NR.wav");
spdlog::info("Samplerate: {0}, Bit depth: {1}, Channel count: {2}", reader->getSampleRate(), reader->getBitDepth(), reader->getChannelCount());
spdlog::info("FileSourceModule '{0}': Instance created!", name); spdlog::info("FileSourceModule '{0}': Instance created!", name);
} }
@ -41,10 +40,22 @@ public:
spdlog::info("FileSourceModule '{0}': Instance deleted!", name); spdlog::info("FileSourceModule '{0}': Instance deleted!", name);
} }
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
bool isEnabled() {
return enabled;
}
private: private:
static void menuSelected(void* ctx) { static void menuSelected(void* ctx) {
FileSourceModule* _this = (FileSourceModule*)ctx; FileSourceModule* _this = (FileSourceModule*)ctx;
core::setInputSampleRate(_this->reader->getSampleRate()); core::setInputSampleRate(_this->sampleRate);
spdlog::info("FileSourceModule '{0}': Menu Select!", _this->name); spdlog::info("FileSourceModule '{0}': Menu Select!", _this->name);
} }
@ -55,15 +66,22 @@ private:
static void start(void* ctx) { static void start(void* ctx) {
FileSourceModule* _this = (FileSourceModule*)ctx; FileSourceModule* _this = (FileSourceModule*)ctx;
if (_this->running) { return; }
if (_this->reader == NULL) { return; }
_this->running = true;
_this->workerThread = std::thread(worker, _this); _this->workerThread = std::thread(worker, _this);
spdlog::info("FileSourceModule '{0}': Start!", _this->name); spdlog::info("FileSourceModule '{0}': Start!", _this->name);
} }
static void stop(void* ctx) { static void stop(void* ctx) {
FileSourceModule* _this = (FileSourceModule*)ctx; FileSourceModule* _this = (FileSourceModule*)ctx;
if (!_this->running) { return; }
if (_this->reader == NULL) { return; }
_this->stream.stopWriter(); _this->stream.stopWriter();
_this->workerThread.join(); _this->workerThread.join();
_this->stream.clearWriteStop(); _this->stream.clearWriteStop();
_this->running = false;
_this->reader->rewind();
spdlog::info("FileSourceModule '{0}': Stop!", _this->name); spdlog::info("FileSourceModule '{0}': Stop!", _this->name);
} }
@ -74,7 +92,27 @@ private:
static void menuHandler(void* ctx) { static void menuHandler(void* ctx) {
FileSourceModule* _this = (FileSourceModule*)ctx; FileSourceModule* _this = (FileSourceModule*)ctx;
ImGui::Text("Hi from %s!", _this->name.c_str());
if (_this->fileSelect.render("##file_source_" + _this->name)) {
if (_this->fileSelect.pathIsValid()) {
if (_this->reader != NULL) {
_this->reader->close();
delete _this->reader;
}
try {
_this->reader = new WavReader(_this->fileSelect.path);
if (_this->reader->isValid() && _this->reader->getBitDepth() == 16 && _this->reader->getChannelCount() == 2) {
_this->sampleRate = _this->reader->getSampleRate();
core::setInputSampleRate(_this->sampleRate);
}
else {
_this->reader->close();
delete _this->reader;
}
}
catch (std::exception e) {}
}
}
} }
static void worker(void* ctx) { static void worker(void* ctx) {
@ -85,22 +123,24 @@ private:
while (true) { while (true) {
_this->reader->readSamples(inBuf, blockSize * 2 * sizeof(int16_t)); _this->reader->readSamples(inBuf, blockSize * 2 * sizeof(int16_t));
if (_this->stream.aquire() < 0) { break; };
for (int i = 0; i < blockSize; i++) { for (int i = 0; i < blockSize; i++) {
_this->stream.data[i].q = (float)inBuf[i * 2] / (float)0x7FFF; _this->stream.writeBuf[i].q = (float)inBuf[i * 2] / (float)0x7FFF;
_this->stream.data[i].i = (float)inBuf[(i * 2) + 1] / (float)0x7FFF; _this->stream.writeBuf[i].i = (float)inBuf[(i * 2) + 1] / (float)0x7FFF;
} }
_this->stream.write(blockSize); if (!_this->stream.swap(blockSize)) { break; };
//std::this_thread::sleep_for(std::chrono::milliseconds(5));
} }
delete[] inBuf; delete[] inBuf;
} }
FileSelect fileSelect;
std::string name; std::string name;
dsp::stream<dsp::complex_t> stream; dsp::stream<dsp::complex_t> stream;
SourceManager::SourceHandler handler; SourceManager::SourceHandler handler;
WavReader* reader; WavReader* reader = NULL;
bool running = false;
bool enabled = true;
float sampleRate = 48000;
std::thread workerThread; std::thread workerThread;
}; };
@ -116,6 +156,6 @@ MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
delete (FileSourceModule*)instance; delete (FileSourceModule*)instance;
} }
MOD_EXPORT void _STOP_() { MOD_EXPORT void _END_() {
// Do your one shutdown here // Do your one shutdown here
} }

View File

@ -2,6 +2,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <fstream> #include <fstream>
#define WAV_SIGNATURE "RIFF" #define WAV_SIGNATURE "RIFF"
@ -15,6 +16,10 @@ public:
WavReader(std::string path) { WavReader(std::string path) {
file = std::ifstream(path.c_str(), std::ios::binary); file = std::ifstream(path.c_str(), std::ios::binary);
file.read((char*)&hdr, sizeof(WavHeader_t)); file.read((char*)&hdr, sizeof(WavHeader_t));
valid = false;
if (memcmp(hdr.signature, "RIFF", 4) != 0) { return; }
if (memcmp(hdr.fileType, "WAVE", 4) != 0) { return; }
valid = true;
} }
uint16_t getBitDepth() { uint16_t getBitDepth() {
@ -29,13 +34,26 @@ public:
return hdr.sampleRate; return hdr.sampleRate;
} }
bool isValid() {
return valid;
}
void readSamples(void* data, size_t size) { void readSamples(void* data, size_t size) {
file.read((char*)data, size); char* _data = (char*)data;
file.read(_data, size);
int read = file.gcount();
if (read < size) {
file.seekg(sizeof(WavHeader_t));
file.read(&_data[read], size - read);
}
bytesRead += size; bytesRead += size;
} }
void rewind() {
file.seekg(sizeof(WavHeader_t));
}
void close() { void close() {
file.close(); file.close();
} }
@ -56,6 +74,7 @@ private:
uint32_t dataSize; uint32_t dataSize;
}; };
bool valid = false;
std::ifstream file; std::ifstream file;
size_t bytesRead = 0; size_t bytesRead = 0;
WavHeader_t hdr; WavHeader_t hdr;

View File

@ -8,7 +8,7 @@
#include <iio.h> #include <iio.h>
#include <ad9361.h> #include <ad9361.h>
#include <options.h> #include <options.h>
#include <gui/widgets/scroll_behavior.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -193,7 +193,7 @@ private:
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (_this->gainMode) { style::beginDisabled(); } if (_this->gainMode) { style::beginDisabled(); }
if (ImGui::SliderFloat(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 76) || ImGui::AllowScrollwheel<float>(_this->gain, 19, 0, 76)) { if (ImGui::SliderFloat(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 76)) {
if (_this->running) { if (_this->running) {
iio_channel_attr_write_longlong(iio_device_find_channel(_this->phy, "voltage0", false),"hardwaregain", round(_this->gain)); iio_channel_attr_write_longlong(iio_device_find_channel(_this->phy, "voltage0", false),"hardwaregain", round(_this->gain));
} }

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class AMDemodulator : public Demodulator { class AMDemodulator : public Demodulator {
public: public:
@ -119,7 +119,7 @@ public:
float menuWidth = ImGui::GetContentRegionAvailWidth(); float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::InputFloat(("##_radio_am_bw_" + uiPrefix).c_str(), &bw, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_am_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) {
bw = std::clamp<float>(bw, bwMin, bwMax); bw = std::clamp<float>(bw, bwMin, bwMax);
setBandwidth(bw); setBandwidth(bw);
_config->aquire(); _config->aquire();
@ -130,7 +130,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_am_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_am_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["AM"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["AM"]["snapInterval"] = snapInterval;
@ -140,7 +140,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_am_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_am_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["AM"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["AM"]["squelchLevel"] = squelchLevel;

View File

@ -10,7 +10,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class CWDemodulator : public Demodulator { class CWDemodulator : public Demodulator {
public: public:
@ -127,7 +127,7 @@ public:
float menuWidth = ImGui::GetContentRegionAvailWidth(); float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::InputFloat(("##_radio_cw_bw_" + uiPrefix).c_str(), &bw, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_cw_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) {
bw = std::clamp<float>(bw, bwMin, bwMax); bw = std::clamp<float>(bw, bwMin, bwMax);
setBandwidth(bw); setBandwidth(bw);
_config->aquire(); _config->aquire();
@ -138,7 +138,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_cw_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_cw_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["CW"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["CW"]["snapInterval"] = snapInterval;
@ -148,7 +148,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_cw_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_cw_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["CW"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["CW"]["squelchLevel"] = squelchLevel;

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class DSBDemodulator : public Demodulator { class DSBDemodulator : public Demodulator {
public: public:
@ -119,7 +119,7 @@ public:
float menuWidth = ImGui::GetContentRegionAvailWidth(); float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::InputFloat(("##_radio_dsb_bw_" + uiPrefix).c_str(), &bw, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_dsb_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) {
bw = std::clamp<float>(bw, bwMin, bwMax); bw = std::clamp<float>(bw, bwMin, bwMax);
setBandwidth(bw); setBandwidth(bw);
_config->aquire(); _config->aquire();
@ -130,7 +130,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_dsb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_dsb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["DSB"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["DSB"]["snapInterval"] = snapInterval;
@ -140,7 +140,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_dsb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_dsb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["DSB"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["DSB"]["squelchLevel"] = squelchLevel;

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class FMDemodulator : public Demodulator { class FMDemodulator : public Demodulator {
public: public:
@ -115,7 +115,7 @@ public:
float menuWidth = ImGui::GetContentRegionAvailWidth(); float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::InputFloat(("##_radio_fm_bw_" + uiPrefix).c_str(), &bw, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_fm_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) {
bw = std::clamp<float>(bw, bwMin, bwMax); bw = std::clamp<float>(bw, bwMin, bwMax);
setBandwidth(bw); setBandwidth(bw);
_config->aquire(); _config->aquire();
@ -126,7 +126,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_fm_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_fm_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["FM"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["FM"]["snapInterval"] = snapInterval;
@ -136,7 +136,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_fm_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_fm_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["FM"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["FM"]["squelchLevel"] = squelchLevel;

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class LSBDemodulator : public Demodulator { class LSBDemodulator : public Demodulator {
public: public:
@ -119,7 +119,7 @@ public:
float menuWidth = ImGui::GetContentRegionAvailWidth(); float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::InputFloat(("##_radio_lsb_bw_" + uiPrefix).c_str(), &bw, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_lsb_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) {
bw = std::clamp<float>(bw, bwMin, bwMax); bw = std::clamp<float>(bw, bwMin, bwMax);
setBandwidth(bw); setBandwidth(bw);
_config->aquire(); _config->aquire();
@ -130,7 +130,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_lsb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_lsb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["LSB"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["LSB"]["snapInterval"] = snapInterval;
@ -140,7 +140,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_lsb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_lsb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["LSB"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["LSB"]["squelchLevel"] = squelchLevel;

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class RAWDemodulator : public Demodulator { class RAWDemodulator : public Demodulator {
public: public:
@ -93,7 +93,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_raw_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_raw_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["RAW"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["RAW"]["snapInterval"] = snapInterval;
@ -103,7 +103,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_raw_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_raw_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["RAW"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["RAW"]["squelchLevel"] = squelchLevel;

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class USBDemodulator : public Demodulator { class USBDemodulator : public Demodulator {
public: public:
@ -119,7 +119,7 @@ public:
float menuWidth = ImGui::GetContentRegionAvailWidth(); float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::InputFloat(("##_radio_usb_bw_" + uiPrefix).c_str(), &bw, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_usb_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) {
bw = std::clamp<float>(bw, bwMin, bwMax); bw = std::clamp<float>(bw, bwMin, bwMax);
setBandwidth(bw); setBandwidth(bw);
_config->aquire(); _config->aquire();
@ -130,7 +130,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_usb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_usb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["USB"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["USB"]["snapInterval"] = snapInterval;
@ -140,7 +140,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_usb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_usb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["USB"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["USB"]["squelchLevel"] = squelchLevel;

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <config.h> #include <config.h>
#include <imgui.h> #include <imgui.h>
#include <gui/widgets/scroll_behavior.h>
class WFMDemodulator : public Demodulator { class WFMDemodulator : public Demodulator {
public: public:
@ -128,7 +128,7 @@ public:
float menuWidth = ImGui::GetContentRegionAvailWidth(); float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::InputFloat(("##_radio_wfm_bw_" + uiPrefix).c_str(), &bw, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_wfm_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) {
bw = std::clamp<float>(bw, bwMin, bwMax); bw = std::clamp<float>(bw, bwMin, bwMax);
setBandwidth(bw); setBandwidth(bw);
_config->aquire(); _config->aquire();
@ -139,7 +139,7 @@ public:
ImGui::Text("Snap Interval"); ImGui::Text("Snap Interval");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputFloat(("##_radio_wfm_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, 0)) { if (ImGui::InputFloat(("##_radio_wfm_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) {
setSnapInterval(snapInterval); setSnapInterval(snapInterval);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["WFM"]["snapInterval"] = snapInterval; _config->conf[uiPrefix]["WFM"]["snapInterval"] = snapInterval;
@ -160,7 +160,7 @@ public:
ImGui::Text("Squelch"); ImGui::Text("Squelch");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_wfm_sqelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB") || ImGui::AllowScrollwheel<float>(squelchLevel, 20, -100, 0)) { if (ImGui::SliderFloat(("##_radio_wfm_sqelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel); squelch.setLevel(squelchLevel);
_config->aquire(); _config->aquire();
_config->conf[uiPrefix]["WFM"]["squelchLevel"] = squelchLevel; _config->conf[uiPrefix]["WFM"]["squelchLevel"] = squelchLevel;

View File

@ -15,6 +15,7 @@
#include <gui/widgets/volume_meter.h> #include <gui/widgets/volume_meter.h>
#include <regex> #include <regex>
#include <options.h> #include <options.h>
#include <gui/widgets/folder_select.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())
SDRPP_MOD_INFO { SDRPP_MOD_INFO {
@ -41,10 +42,10 @@ std::string genFileName(std::string prefix) {
class RecorderModule : public ModuleManager::Instance { class RecorderModule : public ModuleManager::Instance {
public: public:
RecorderModule(std::string name) { RecorderModule(std::string name) : folderSelect("%ROOT%/recordings") {
this->name = name; this->name = name;
strcpy(recPath, "%ROOT%/recordings"); recPath = "%ROOT%/recordings";
// Init audio path // Init audio path
vol.init(&dummyStream, 1.0f); vol.init(&dummyStream, 1.0f);
@ -135,27 +136,12 @@ private:
if (_this->recording) { style::endDisabled(); } if (_this->recording) { style::endDisabled(); }
// Recording path // Recording path
ImGui::SetNextItemWidth(menuColumnWidth); if (_this->folderSelect.render("##_recorder_fold_" + _this->name)) {
bool lastPathValid = _this->pathValid; if (_this->folderSelect.pathIsValid()) {
if (!lastPathValid) { _this->recPath = _this->folderSelect.path;
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
}
if (ImGui::InputText(CONCAT("##_recorder_path_", _this->name), _this->recPath, 4095)) {
std::string expandedPath = expandString(_this->recPath);
if (!std::filesystem::exists(expandedPath)) {
_this->pathValid = false;
}
else if (!std::filesystem::is_directory(expandedPath)) {
_this->pathValid = false;
}
else {
_this->pathValid = true;
// Save config here
} }
} }
if (!lastPathValid) { _this->pathValid = _this->folderSelect.pathIsValid();
ImGui::PopStyleColor();
}
// Mode specific menu // Mode specific menu
if (_this->recMode) { if (_this->recMode) {
@ -172,7 +158,7 @@ private:
if (ImGui::Button(CONCAT("Record##_recorder_rec_", name), ImVec2(menuColumnWidth, 0))) { if (ImGui::Button(CONCAT("Record##_recorder_rec_", name), ImVec2(menuColumnWidth, 0))) {
recording = true; recording = true;
samplesWritten = 0; samplesWritten = 0;
std::string expandedPath = expandString(std::string(recPath) + genFileName("/baseband_")); std::string expandedPath = expandString(recPath + genFileName("/baseband_"));
sampleRate = sigpath::signalPath.getSampleRate(); sampleRate = sigpath::signalPath.getSampleRate();
basebandWriter = new WavWriter(expandedPath, 16, 2, sigpath::signalPath.getSampleRate()); basebandWriter = new WavWriter(expandedPath, 16, 2, sigpath::signalPath.getSampleRate());
basebandHandler.start(); basebandHandler.start();
@ -225,7 +211,7 @@ private:
if (ImGui::Button(CONCAT("Record##_recorder_rec_", name), ImVec2(menuColumnWidth, 0))) { if (ImGui::Button(CONCAT("Record##_recorder_rec_", name), ImVec2(menuColumnWidth, 0))) {
recording = true; recording = true;
samplesWritten = 0; samplesWritten = 0;
std::string expandedPath = expandString(std::string(recPath) + genFileName("/audio_")); std::string expandedPath = expandString(recPath + genFileName("/audio_"));
sampleRate = sigpath::sinkManager.getStreamSampleRate(selectedStreamName); sampleRate = sigpath::sinkManager.getStreamSampleRate(selectedStreamName);
audioWriter = new WavWriter(expandedPath, 16, 2, sigpath::sinkManager.getStreamSampleRate(selectedStreamName)); audioWriter = new WavWriter(expandedPath, 16, 2, sigpath::sinkManager.getStreamSampleRate(selectedStreamName));
audioHandler.start(); audioHandler.start();
@ -273,7 +259,7 @@ private:
std::string name; std::string name;
bool enabled = true; bool enabled = true;
char recPath[1024]; std::string recPath = "";
bool recMode = 1; bool recMode = 1;
bool recording = false; bool recording = false;
@ -288,6 +274,8 @@ private:
dsp::stream<dsp::stereo_t> dummyStream; dsp::stream<dsp::stereo_t> dummyStream;
FolderSelect folderSelect;
// Audio path // Audio path
dsp::stream<dsp::stereo_t>* audioInput; dsp::stream<dsp::stereo_t>* audioInput;
dsp::Volume<dsp::stereo_t> vol; dsp::Volume<dsp::stereo_t> vol;