Added VFO coloring option

This commit is contained in:
Ryzerth 2021-05-04 20:41:23 +02:00
parent 9a1850bd61
commit 1eca58605c
10 changed files with 200 additions and 10 deletions

View File

@ -195,7 +195,8 @@ private:
// Setup device parameters // Setup device parameters
bladerf_set_sample_rate(_this->openDev, BLADERF_CHANNEL_RX(0), _this->sampleRate, NULL); bladerf_set_sample_rate(_this->openDev, BLADERF_CHANNEL_RX(0), _this->sampleRate, NULL);
bladerf_set_frequency(_this->openDev, BLADERF_CHANNEL_RX(0), _this->freq); bladerf_set_frequency(_this->openDev, BLADERF_CHANNEL_RX(0), _this->freq);
bladerf_set_bandwidth(_this->openDev, BLADERF_CHANNEL_RX(0), (_this->bwId == _this->bandwidths.size()) ? _this->sampleRate : _this->bandwidths[_this->bwId], NULL); bladerf_set_bandwidth(_this->openDev, BLADERF_CHANNEL_RX(0), (_this->bwId == _this->bandwidths.size()) ?
std::clamp<uint64_t>(_this->sampleRate, _this->bwRange->min, _this->bwRange->max) : _this->bandwidths[_this->bwId], NULL);
bladerf_set_gain_mode(_this->openDev, BLADERF_CHANNEL_RX(0), BLADERF_GAIN_MANUAL); bladerf_set_gain_mode(_this->openDev, BLADERF_CHANNEL_RX(0), BLADERF_GAIN_MANUAL);
bladerf_set_gain(_this->openDev, BLADERF_CHANNEL_RX(0), _this->testGain); bladerf_set_gain(_this->openDev, BLADERF_CHANNEL_RX(0), _this->testGain);
@ -280,7 +281,8 @@ private:
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::Combo(CONCAT("##_balderf_bw_sel_", _this->name), &_this->bwId, _this->bandwidthsTxt.c_str())) { if (ImGui::Combo(CONCAT("##_balderf_bw_sel_", _this->name), &_this->bwId, _this->bandwidthsTxt.c_str())) {
if (_this->running) { if (_this->running) {
bladerf_set_bandwidth(_this->openDev, BLADERF_CHANNEL_RX(0), (_this->bwId == _this->bandwidths.size()) ? _this->sampleRate : _this->bandwidths[_this->bwId], NULL); bladerf_set_bandwidth(_this->openDev, BLADERF_CHANNEL_RX(0), (_this->bwId == _this->bandwidths.size()) ?
std::clamp<uint64_t>(_this->sampleRate, _this->bwRange->min, _this->bwRange->max) : _this->bandwidths[_this->bwId], NULL);
} }
// Save config // Save config
} }

View File

@ -174,6 +174,8 @@ int sdrpp_main(int argc, char *argv[]) {
defConfig["vfoOffsets"] = json::object(); defConfig["vfoOffsets"] = json::object();
defConfig["vfoColors"]["Radio"] = "#FFFFFF";
#ifdef _WIN32 #ifdef _WIN32
defConfig["modulesDirectory"] = "./modules"; defConfig["modulesDirectory"] = "./modules";
defConfig["resourcesDirectory"] = "./res"; defConfig["resourcesDirectory"] = "./res";
@ -193,7 +195,7 @@ int sdrpp_main(int argc, char *argv[]) {
// Fix missing elements in config // Fix missing elements in config
for (auto const& item : defConfig.items()) { for (auto const& item : defConfig.items()) {
if (!core::configManager.conf.contains(item.key())) { if (!core::configManager.conf.contains(item.key())) {
spdlog::warn("Missing key in config {0}, repairing", item.key()); spdlog::info("Missing key in config {0}, repairing", item.key());
core::configManager.conf[item.key()] = defConfig[item.key()]; core::configManager.conf[item.key()] = defConfig[item.key()];
} }
} }
@ -202,7 +204,7 @@ int sdrpp_main(int argc, char *argv[]) {
auto items = core::configManager.conf.items(); auto items = core::configManager.conf.items();
for (auto const& item : items) { for (auto const& item : items) {
if (!defConfig.contains(item.key())) { if (!defConfig.contains(item.key())) {
spdlog::warn("Unused key in config {0}, repairing", item.key()); spdlog::info("Unused key in config {0}, repairing", item.key());
core::configManager.conf.erase(item.key()); core::configManager.conf.erase(item.key());
} }
} }

View File

@ -32,6 +32,7 @@
#include <options.h> #include <options.h>
#include <gui/colormaps.h> #include <gui/colormaps.h>
#include <gui/widgets/snr_meter.h> #include <gui/widgets/snr_meter.h>
#include <gui/menus/vfo_color.h>
int fftSize = 8192 * 8; int fftSize = 8192 * 8;
@ -135,6 +136,7 @@ void windowInit() {
gui::menu.registerEntry("Scripting", scriptingmenu::draw, NULL); gui::menu.registerEntry("Scripting", scriptingmenu::draw, NULL);
gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL); gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL);
gui::menu.registerEntry("Display", displaymenu::draw, NULL); gui::menu.registerEntry("Display", displaymenu::draw, NULL);
gui::menu.registerEntry("VFO Color", vfo_color_menu::draw, NULL);
gui::freqSelect.init(); gui::freqSelect.init();
@ -214,6 +216,7 @@ void windowInit() {
scriptingmenu::init(); scriptingmenu::init();
bandplanmenu::init(); bandplanmenu::init();
displaymenu::init(); displaymenu::init();
vfo_color_menu::init();
// TODO for 0.2.5 // TODO for 0.2.5
// Add "select file" option for the file source // Add "select file" option for the file source

View File

@ -0,0 +1,137 @@
#include <gui/menus/vfo_color.h>
#include <gui/gui.h>
#include <gui/widgets/waterfall.h>
#include <signal_path/signal_path.h>
#include <string>
#include <core.h>
#include <map>
namespace vfo_color_menu {
std::map<std::string, ImVec4> vfoColors;
std::string openName = "";
EventHandler<VFOManager::VFO*> vfoAddHndl;
void vfoAddHandler(VFOManager::VFO* vfo, void* ctx) {
std::string name = vfo->getName();
if (vfoColors.find(name) != vfoColors.end()) {
ImVec4 col = vfoColors[name];
vfo->setColor(IM_COL32((int)roundf(col.x * 255), (int)roundf(col.y * 255), (int)roundf(col.z * 255), 50));
return;
}
vfo->setColor(IM_COL32(255, 255, 255, 50));
vfoColors[name] = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
}
void init() {
// Load colors from config
bool modified = false;
core::configManager.aquire();
json conf = core::configManager.conf["vfoColors"];
for (auto& [name, val] : conf.items()) {
// If not a string, repair with default
if (!val.is_string()) {
core::configManager.conf["vfoColors"][name] = "#FFFFFF";
vfoColors[name] = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
modified = true;
if (sigpath::vfoManager.vfoExists(name)) {
sigpath::vfoManager.setColor(name, IM_COL32(255, 255, 255, 50));
}
continue;
}
// If not a valid hex color, repair with default
std::string col = val;
if (col[0] != '#' || !std::all_of(col.begin() + 1, col.end(), ::isxdigit)) {
core::configManager.conf["vfoColors"][name] = "#FFFFFF";
vfoColors[name] = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
modified = true;
if (sigpath::vfoManager.vfoExists(name)) {
sigpath::vfoManager.setColor(name, IM_COL32(255, 255, 255, 50));
}
continue;
}
// Since the color is valid, decode it and set the vfo's color
float r, g, b;
r = std::stoi(col.substr(1, 2), NULL, 16);
g = std::stoi(col.substr(3, 2), NULL, 16);
b = std::stoi(col.substr(5, 2), NULL, 16);
vfoColors[name] = ImVec4(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
if (sigpath::vfoManager.vfoExists(name)) {
sigpath::vfoManager.setColor(name, IM_COL32((int)roundf(r), (int)roundf(g), (int)roundf(b), 50));
}
}
// Iterate existing VFOs and set their color if in the config, if not set to default
for (auto& [name, vfo] : gui::waterfall.vfos) {
if (vfoColors.find(name) == vfoColors.end()) {
vfoColors[name] = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
vfo->color = IM_COL32(255, 255, 255, 50);
modified = true;
}
}
vfoAddHndl.handler = vfoAddHandler;
sigpath::vfoManager.vfoCreatedEvent.bindHandler(vfoAddHndl);
core::configManager.release(modified);
}
void draw(void* ctx) {
ImGui::BeginTable("VFO Color Buttons Table", 2);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
if (ImGui::Button("Auto Color##vfo_color", ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) {
float delta = 1.0f / (float)gui::waterfall.vfos.size();
float hue = 0;
for (auto& [name, vfo] : gui::waterfall.vfos) {
float r, g, b;
ImGui::ColorConvertHSVtoRGB(hue, 0.5f, 1.0f, r, g, b);
vfoColors[name] = ImVec4(r, g, b, 1.0f);
vfo->color = IM_COL32((int)roundf(r * 255), (int)roundf(g * 255), (int)roundf(b * 255), 50);
hue += delta;
core::configManager.aquire();
char buf[16];
sprintf(buf, "#%02X%02X%02X", (int)roundf(r * 255), (int)roundf(g * 255), (int)roundf(b * 255));
core::configManager.conf["vfoColors"][name] = buf;
core::configManager.release(true);
}
}
ImGui::TableSetColumnIndex(1);
if (ImGui::Button("Clear All##vfo_color", ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) {
for (auto& [name, vfo] : gui::waterfall.vfos) {
vfoColors[name] = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
vfo->color = IM_COL32(255, 255, 255, 50);
core::configManager.aquire();
char buf[16];
core::configManager.conf["vfoColors"][name] = "#FFFFFF";
core::configManager.release(true);
}
}
ImGui::EndTable();
ImGui::BeginTable("VFO Color table", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders);
for (auto& [name, vfo] : gui::waterfall.vfos) {
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImVec4 col(1.0f, 1.0f, 1.0f, 1.0f);
if (vfoColors.find(name) != vfoColors.end()) {
col = vfoColors[name];
}
if (ImGui::ColorEdit3(("##vfo_color_"+name).c_str(), (float*)&col, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) {
vfoColors[name] = col;
vfo->color = IM_COL32((int)roundf(col.x * 255), (int)roundf(col.y * 255), (int)roundf(col.z * 255), 50);
core::configManager.aquire();
char buf[16];
sprintf(buf, "#%02X%02X%02X", (int)roundf(col.x * 255), (int)roundf(col.y * 255), (int)roundf(col.z * 255));
core::configManager.conf["vfoColors"][name] = buf;
core::configManager.release(true);
}
ImGui::SameLine();
ImGui::Text(name.c_str());
}
ImGui::EndTable();
}
}

View File

@ -0,0 +1,6 @@
#pragma once
namespace vfo_color_menu {
void init();
void draw(void* ctx);
}

View File

@ -194,7 +194,7 @@ namespace ImGui {
if (IS_IN_AREA(mPos, wfMin, wfMax)) { if (IS_IN_AREA(mPos, wfMin, wfMax)) {
for (auto const& [name, vfo] : vfos) { for (auto const& [name, vfo] : vfos) {
window->DrawList->AddRectFilled(vfo->wfRectMin, vfo->wfRectMax, IM_COL32(255, 255, 255, 50)); window->DrawList->AddRectFilled(vfo->wfRectMin, vfo->wfRectMax, vfo->color);
window->DrawList->AddLine(vfo->wfLineMin, vfo->wfLineMax, (name == selectedVFO) ? IM_COL32(255, 0, 0, 255) : IM_COL32(255, 255, 0, 255)); window->DrawList->AddLine(vfo->wfLineMin, vfo->wfLineMax, (name == selectedVFO) ? IM_COL32(255, 0, 0, 255) : IM_COL32(255, 255, 0, 255));
} }
} }
@ -1115,7 +1115,7 @@ namespace ImGui {
} }
void WaterfallVFO::draw(ImGuiWindow* window, bool selected) { void WaterfallVFO::draw(ImGuiWindow* window, bool selected) {
window->DrawList->AddRectFilled(rectMin, rectMax, IM_COL32(255, 255, 255, 50)); window->DrawList->AddRectFilled(rectMin, rectMax, color);
if (lineVisible) { if (lineVisible) {
window->DrawList->AddLine(lineMin, lineMax, selected ? IM_COL32(255, 0, 0, 255) : IM_COL32(255, 255, 0, 255)); window->DrawList->AddLine(lineMin, lineMax, selected ? IM_COL32(255, 0, 0, 255) : IM_COL32(255, 255, 0, 255));
} }
@ -1128,7 +1128,7 @@ namespace ImGui {
if (reference != REF_UPPER && !bandwidthLocked) { if (reference != REF_UPPER && !bandwidthLocked) {
if (IS_IN_AREA(mousePos, rbwSelMin, rbwSelMax)) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); } if (IS_IN_AREA(mousePos, rbwSelMin, rbwSelMax)) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); }
else if (IS_IN_AREA(mousePos, wfRbwSelMin, wfRbwSelMax)) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); } else if (IS_IN_AREA(mousePos, wfRbwSelMin, wfRbwSelMax)) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); }
} }
}; };
void WaterFall::showWaterfall() { void WaterFall::showWaterfall() {

View File

@ -61,6 +61,8 @@ namespace ImGui {
double minBandwidth; double minBandwidth;
double maxBandwidth; double maxBandwidth;
bool bandwidthLocked; bool bandwidthLocked;
ImU32 color = IM_COL32(255, 255, 255, 50);
}; };
class WaterFall { class WaterFall {

View File

@ -73,6 +73,14 @@ double VFOManager::VFO::getBandwidth() {
return wtfVFO->bandwidth; return wtfVFO->bandwidth;
} }
void VFOManager::VFO::setColor(ImU32 color) {
wtfVFO->color = color;
}
std::string VFOManager::VFO::getName() {
return name;
}
VFOManager::VFOManager() { VFOManager::VFOManager() {
} }
@ -83,6 +91,7 @@ VFOManager::VFO* VFOManager::createVFO(std::string name, int reference, double o
} }
VFOManager::VFO* vfo = new VFO(name, reference, offset, bandwidth, sampleRate, minBandwidth, maxBandwidth, bandwidthLocked); VFOManager::VFO* vfo = new VFO(name, reference, offset, bandwidth, sampleRate, minBandwidth, maxBandwidth, bandwidthLocked);
vfos[name] = vfo; vfos[name] = vfo;
vfoCreatedEvent.emit(vfo);
return vfo; return vfo;
} }
@ -97,6 +106,7 @@ void VFOManager::deleteVFO(VFOManager::VFO* vfo) {
if (name == "") { if (name == "") {
return; return;
} }
vfoDeletedEvent.emit(vfo);
vfos.erase(name); vfos.erase(name);
delete vfo; delete vfo;
} }
@ -164,6 +174,17 @@ double VFOManager::getBandwidth(std::string name) {
return vfos[name]->getBandwidth(); return vfos[name]->getBandwidth();
} }
void VFOManager::setColor(std::string name, ImU32 color) {
if (vfos.find(name) == vfos.end()) {
return;
}
return vfos[name]->setColor(color);
}
bool VFOManager::vfoExists(std::string name) {
return (vfos.find(name) != vfos.end());
}
void VFOManager::updateFromWaterfall(ImGui::WaterFall* wtf) { void VFOManager::updateFromWaterfall(ImGui::WaterFall* wtf) {
for (auto const& [name, vfo] : vfos) { for (auto const& [name, vfo] : vfos) {
if (vfo->wtfVFO->centerOffsetChanged) { if (vfo->wtfVFO->centerOffsetChanged) {
@ -171,4 +192,4 @@ void VFOManager::updateFromWaterfall(ImGui::WaterFall* wtf) {
vfo->dspVFO->setOffset(vfo->wtfVFO->centerOffset); vfo->dspVFO->setOffset(vfo->wtfVFO->centerOffset);
} }
} }
} }

View File

@ -2,6 +2,7 @@
#include <dsp/vfo.h> #include <dsp/vfo.h>
#include <gui/widgets/waterfall.h> #include <gui/widgets/waterfall.h>
#include <gui/gui.h> #include <gui/gui.h>
#include <utils/event.h>
class VFOManager { class VFOManager {
public: public:
@ -22,6 +23,8 @@ public:
void setBandwidthLimits(double minBandwidth, double maxBandwidth, bool bandwidthLocked); void setBandwidthLimits(double minBandwidth, double maxBandwidth, bool bandwidthLocked);
bool getBandwidthChanged(bool erase = true); bool getBandwidthChanged(bool erase = true);
double getBandwidth(); double getBandwidth();
void setColor(ImU32 color);
std::string getName();
dsp::stream<dsp::complex_t>* output; dsp::stream<dsp::complex_t>* output;
@ -46,9 +49,15 @@ public:
void setBandwidthLimits(std::string name, double minBandwidth, double maxBandwidth, bool bandwidthLocked); void setBandwidthLimits(std::string name, double minBandwidth, double maxBandwidth, bool bandwidthLocked);
bool getBandwidthChanged(std::string name, bool erase = true); bool getBandwidthChanged(std::string name, bool erase = true);
double getBandwidth(std::string name); double getBandwidth(std::string name);
void setColor(std::string name, ImU32 color);
std::string getName();
bool vfoExists(std::string name);
void updateFromWaterfall(ImGui::WaterFall* wtf); void updateFromWaterfall(ImGui::WaterFall* wtf);
Event<VFOManager::VFO*> vfoCreatedEvent;
Event<VFOManager::VFO*> vfoDeletedEvent;
private: private:
std::map<std::string, VFO*> vfos; std::map<std::string, VFO*> vfos;
}; };

View File

@ -161,10 +161,18 @@ private:
if (_this->running) { style::beginDisabled(); } if (_this->running) { style::beginDisabled(); }
ImGui::SetNextItemWidth(menuWidth - portWidth); ImGui::SetNextItemWidth(menuWidth - portWidth);
ImGui::InputText(CONCAT("##_ip_select_", _this->name), _this->ip, 1024); if (ImGui::InputText(CONCAT("##_ip_select_", _this->name), _this->ip, 1024)) {
config.aquire();
config.conf["host"] = std::string(_this->ip);
config.release(true);
}
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(portWidth); ImGui::SetNextItemWidth(portWidth);
ImGui::InputInt(CONCAT("##_port_select_", _this->name), &_this->port, 0); if (ImGui::InputInt(CONCAT("##_port_select_", _this->name), &_this->port, 0)) {
config.aquire();
config.conf["port"] = _this->port;
config.release(true);
}
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::Combo(CONCAT("##_rtltcp_sr_", _this->name), &_this->srId, _this->srTxt.c_str())) { if (ImGui::Combo(CONCAT("##_rtltcp_sr_", _this->name), &_this->srId, _this->srTxt.c_str())) {