#include #include #include #include #include #include #include #include #include #include SDRPP_MOD_INFO { /* Name: */ "frequency_manager", /* Description: */ "Frequency manager module for SDR++", /* Author: */ "Ryzerth;zimm", /* Version: */ 0, 3, 0, /* Max instances */ -1 }; struct FrequencyBookmark { double frequency; double bandwidth; int mode; bool selected; }; class FrequencyManagerModule : public ModuleManager::Instance { public: FrequencyManagerModule(std::string name) { this->name = name; gui::menu.registerEntry(name, menuHandler, this, NULL); } ~FrequencyManagerModule() { gui::menu.removeEntry(name); } void enable() { enabled = true; } void disable() { enabled = false; } bool isEnabled() { return enabled; } private: static std::string freqToStr(double freq) { char str[128]; if (freq >= 1000000.0) { sprintf(str, "%.06lf", freq / 1000000.0); int len = strlen(str) - 1; while ((str[len] == '0' || str[len] == '.') && len > 0) { len--; } return std::string(str).substr(0, len + 1) + "MHz"; } else if (freq >= 1000.0) { sprintf(str, "%.06lf", freq / 1000.0); int len = strlen(str) - 1; while ((str[len] == '0' || str[len] == '.') && len > 0) { len--; } return std::string(str).substr(0, len + 1) + "KHz"; } else { sprintf(str, "%.06lf", freq); int len = strlen(str) - 1; while ((str[len] == '0' || str[len] == '.') && len > 0) { len--; } return std::string(str).substr(0, len + 1) + "Hz"; } } static void applyBookmark(FrequencyBookmark bm, std::string vfoName) { if (vfoName == "") { // TODO: Replace with proper tune call gui::waterfall.setCenterFrequency(bm.frequency); gui::waterfall.centerFreqMoved = true; } else { } } bool bookmarkEditDialog(FrequencyBookmark& bm) { bool open = true; std::string id = "Edit##freq_manager_edit_popup_" + name; ImGui::OpenPopup(id.c_str()); FrequencyBookmark tmp = bm; if (ImGui::BeginPopup(id.c_str(), ImGuiWindowFlags_NoResize)) { if (ImGui::Button("Apply")) { bm = tmp; open = false; } ImGui::SameLine(); if (ImGui::Button("Cancel")) { open = false; } ImGui::EndPopup(); } return open; } static void menuHandler(void* ctx) { FrequencyManagerModule* _this = (FrequencyManagerModule*)ctx; float menuWidth = ImGui::GetContentRegionAvailWidth(); // TODO: Replace with something that won't iterate every frame std::vector selectedNames; for (auto& [name, bm] : _this->bookmarks) { if (bm.selected) { selectedNames.push_back(name); } } //Draw buttons on top of the list ImGui::BeginTable(("freq_manager_btn_table"+_this->name).c_str(), 3); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); if (ImGui::Button(("Add##_freq_mgr_add_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { // If there's no VFO selected, just save the center freq FrequencyBookmark bm; if (gui::waterfall.selectedVFO == "") { bm.frequency = gui::waterfall.getCenterFrequency(); bm.bandwidth = 0; bm.mode = -1; } else { bm.frequency = gui::waterfall.getCenterFrequency() + sigpath::vfoManager.getOffset(gui::waterfall.selectedVFO); bm.bandwidth = sigpath::vfoManager.getBandwidth(gui::waterfall.selectedVFO); bm.mode = -1; if (core::modComManager.getModuleName(gui::waterfall.selectedVFO) == "radio") { int mode; core::modComManager.callInterface(gui::waterfall.selectedVFO, RADIO_IFACE_CMD_GET_MODE, NULL, &mode); bm.mode = mode; } } bm.selected = false; char name[1024]; sprintf(name, "Test Bookmark (%d)", _this->testN); _this->bookmarks[name] = bm; _this->testN++; _this->editOpen = true; _this->editedBookmarkName = name; } ImGui::TableSetColumnIndex(1); if (ImGui::Button(("Remove##_freq_mgr_rem_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { for (auto& name : selectedNames) { _this->bookmarks.erase(name); } } ImGui::TableSetColumnIndex(2); if (selectedNames.size() != 1) { style::beginDisabled(); } if (ImGui::Button(("Edit##_freq_mgr_edt_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { _this->editOpen = true; _this->editedBookmarkName = selectedNames[0]; } if (selectedNames.size() != 1) { style::endDisabled(); } ImGui::EndTable(); // Bookmark list ImGui::BeginTable(("freq_manager_bkm_table"+_this->name).c_str(), 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(0, 300)); ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("Bookmark", ImGuiTableColumnFlags_WidthStretch); ImGui::TableHeadersRow(); for (auto& [name, bm] : _this->bookmarks) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImVec2 min = ImGui::GetCursorPos(); ImGui::Selectable((name + "##_freq_mgr_bkm_name_" + _this->name).c_str(), &bm.selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SelectOnClick); if (ImGui::TableGetHoveredColumn() >= 0 && ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { applyBookmark(bm, gui::waterfall.selectedVFO); } ImGui::TableSetColumnIndex(1); ImGui::Text(freqToStr(bm.frequency).c_str()); ImVec2 max = ImGui::GetCursorPos(); } ImGui::EndTable(); if (selectedNames.size() != 1) { style::beginDisabled(); } if (ImGui::Button(("Apply##_freq_mgr_apply_" + _this->name).c_str(), ImVec2(menuWidth, 0))) { FrequencyBookmark& bm = _this->bookmarks[selectedNames[0]]; applyBookmark(bm, gui::waterfall.selectedVFO); bm.selected = false; } if (selectedNames.size() != 1) { style::endDisabled(); } if (_this->editOpen) { FrequencyBookmark& bm = _this->bookmarks[_this->editedBookmarkName]; _this->editOpen = _this->bookmarkEditDialog(bm); } if (_this->addOpen) { FrequencyBookmark& bm = _this->bookmarks[_this->editedBookmarkName]; _this->addOpen = _this->bookmarkEditDialog(bm); } } std::string name; bool enabled = true; bool editOpen = false; bool addOpen = false; std::map bookmarks; std::string editedBookmarkName = ""; int testN = 0; }; MOD_EXPORT void _INIT_() { // Nothing here (testing) } MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { return new FrequencyManagerModule(name); } MOD_EXPORT void _DELETE_INSTANCE_(void* instance) { delete (FrequencyManagerModule*)instance; } MOD_EXPORT void _END_() { // Nothing here }