mirror of
				https://github.com/AlexandreRouma/SDRPlusPlus.git
				synced 2025-10-31 00:48:11 +01:00 
			
		
		
		
	Added VFO coloring option
This commit is contained in:
		| @@ -195,7 +195,8 @@ private: | ||||
|         // Setup device parameters | ||||
|         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_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(_this->openDev, BLADERF_CHANNEL_RX(0), _this->testGain); | ||||
|  | ||||
| @@ -280,7 +281,8 @@ private: | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_balderf_bw_sel_", _this->name), &_this->bwId, _this->bandwidthsTxt.c_str())) { | ||||
|             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 | ||||
|         } | ||||
|   | ||||
| @@ -174,6 +174,8 @@ int sdrpp_main(int argc, char *argv[]) { | ||||
|  | ||||
|     defConfig["vfoOffsets"] = json::object(); | ||||
|  | ||||
|     defConfig["vfoColors"]["Radio"] = "#FFFFFF"; | ||||
|  | ||||
| #ifdef _WIN32 | ||||
|     defConfig["modulesDirectory"] = "./modules"; | ||||
|     defConfig["resourcesDirectory"] = "./res"; | ||||
| @@ -193,7 +195,7 @@ int sdrpp_main(int argc, char *argv[]) { | ||||
|     // Fix missing elements in config | ||||
|     for (auto const& item : defConfig.items()) { | ||||
|         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()]; | ||||
|         } | ||||
|     } | ||||
| @@ -202,7 +204,7 @@ int sdrpp_main(int argc, char *argv[]) { | ||||
|     auto items = core::configManager.conf.items(); | ||||
|     for (auto const& item : items) { | ||||
|         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()); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -32,6 +32,7 @@ | ||||
| #include <options.h> | ||||
| #include <gui/colormaps.h> | ||||
| #include <gui/widgets/snr_meter.h> | ||||
| #include <gui/menus/vfo_color.h> | ||||
|  | ||||
| int fftSize = 8192 * 8; | ||||
|  | ||||
| @@ -135,6 +136,7 @@ void windowInit() { | ||||
|     gui::menu.registerEntry("Scripting", scriptingmenu::draw, NULL); | ||||
|     gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL); | ||||
|     gui::menu.registerEntry("Display", displaymenu::draw, NULL); | ||||
|     gui::menu.registerEntry("VFO Color", vfo_color_menu::draw, NULL); | ||||
|      | ||||
|     gui::freqSelect.init(); | ||||
|  | ||||
| @@ -214,6 +216,7 @@ void windowInit() { | ||||
|     scriptingmenu::init(); | ||||
|     bandplanmenu::init(); | ||||
|     displaymenu::init(); | ||||
|     vfo_color_menu::init(); | ||||
|  | ||||
|     // TODO for 0.2.5 | ||||
|     // Add "select file" option for the file source | ||||
|   | ||||
							
								
								
									
										137
									
								
								core/src/gui/menus/vfo_color.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								core/src/gui/menus/vfo_color.cpp
									
									
									
									
									
										Normal 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(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										6
									
								
								core/src/gui/menus/vfo_color.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								core/src/gui/menus/vfo_color.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| namespace vfo_color_menu { | ||||
|     void init(); | ||||
|     void draw(void* ctx); | ||||
| } | ||||
| @@ -194,7 +194,7 @@ namespace ImGui { | ||||
|  | ||||
|         if (IS_IN_AREA(mPos, wfMin, wfMax)) { | ||||
|             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)); | ||||
|             } | ||||
|         } | ||||
| @@ -1115,7 +1115,7 @@ namespace ImGui { | ||||
|     } | ||||
|  | ||||
|     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) { | ||||
|             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 (IS_IN_AREA(mousePos, rbwSelMin, rbwSelMax)) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); } | ||||
|             else if (IS_IN_AREA(mousePos, wfRbwSelMin, wfRbwSelMax)) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); } | ||||
|         }         | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     void WaterFall::showWaterfall() { | ||||
|   | ||||
| @@ -61,6 +61,8 @@ namespace ImGui { | ||||
|         double minBandwidth; | ||||
|         double maxBandwidth; | ||||
|         bool bandwidthLocked; | ||||
|  | ||||
|         ImU32 color = IM_COL32(255, 255, 255, 50); | ||||
|     }; | ||||
|  | ||||
|     class WaterFall { | ||||
|   | ||||
| @@ -73,6 +73,14 @@ double VFOManager::VFO::getBandwidth() { | ||||
|     return wtfVFO->bandwidth; | ||||
| } | ||||
|  | ||||
| void VFOManager::VFO::setColor(ImU32 color) { | ||||
|     wtfVFO->color = color; | ||||
| } | ||||
|  | ||||
| std::string VFOManager::VFO::getName() { | ||||
|     return name; | ||||
| } | ||||
|  | ||||
| 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); | ||||
|     vfos[name] = vfo; | ||||
|     vfoCreatedEvent.emit(vfo); | ||||
|     return vfo; | ||||
| } | ||||
|  | ||||
| @@ -97,6 +106,7 @@ void VFOManager::deleteVFO(VFOManager::VFO* vfo) { | ||||
|     if (name == "") { | ||||
|         return; | ||||
|     } | ||||
|     vfoDeletedEvent.emit(vfo); | ||||
|     vfos.erase(name); | ||||
|     delete vfo; | ||||
| } | ||||
| @@ -164,6 +174,17 @@ double VFOManager::getBandwidth(std::string name) { | ||||
|     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) { | ||||
|     for (auto const& [name, vfo] : vfos) { | ||||
|         if (vfo->wtfVFO->centerOffsetChanged) { | ||||
| @@ -171,4 +192,4 @@ void VFOManager::updateFromWaterfall(ImGui::WaterFall* wtf) { | ||||
|             vfo->dspVFO->setOffset(vfo->wtfVFO->centerOffset); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -2,6 +2,7 @@ | ||||
| #include <dsp/vfo.h> | ||||
| #include <gui/widgets/waterfall.h> | ||||
| #include <gui/gui.h> | ||||
| #include <utils/event.h> | ||||
|  | ||||
| class VFOManager { | ||||
| public: | ||||
| @@ -22,6 +23,8 @@ public: | ||||
|         void setBandwidthLimits(double minBandwidth, double maxBandwidth, bool bandwidthLocked); | ||||
|         bool getBandwidthChanged(bool erase = true); | ||||
|         double getBandwidth(); | ||||
|         void setColor(ImU32 color); | ||||
|         std::string getName(); | ||||
|  | ||||
|         dsp::stream<dsp::complex_t>* output; | ||||
|  | ||||
| @@ -46,9 +49,15 @@ public: | ||||
|     void setBandwidthLimits(std::string name, double minBandwidth, double maxBandwidth, bool bandwidthLocked); | ||||
|     bool getBandwidthChanged(std::string name, bool erase = true); | ||||
|     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); | ||||
|  | ||||
|     Event<VFOManager::VFO*> vfoCreatedEvent; | ||||
|     Event<VFOManager::VFO*> vfoDeletedEvent; | ||||
|  | ||||
| private: | ||||
|     std::map<std::string, VFO*> vfos; | ||||
| }; | ||||
| @@ -161,10 +161,18 @@ private: | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|  | ||||
|         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::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); | ||||
|         if (ImGui::Combo(CONCAT("##_rtltcp_sr_", _this->name), &_this->srId, _this->srTxt.c_str())) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user