mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-15 05:47:38 +00:00
Freqman UI (#1255)
* FreqmanDB direct file * Clear UI for short lists * Final touches on freqlist UI. * Support vertical alignment in NewButton * New buttons in FreqMan * Wiring up UI to filewrapper actions * Work around empty file
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -22,278 +23,284 @@
|
||||
|
||||
#include "ui_freqman.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "event_m0.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace portapack;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace ui {
|
||||
|
||||
static int32_t current_category_id = 0;
|
||||
/* FreqManBaseView ***************************************/
|
||||
|
||||
size_t FreqManBaseView::current_category_index = 0;
|
||||
|
||||
FreqManBaseView::FreqManBaseView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
add_children({&options_category,
|
||||
&label_category,
|
||||
&button_exit});
|
||||
add_children(
|
||||
{&label_category,
|
||||
&options_category,
|
||||
&button_exit});
|
||||
|
||||
// initialize
|
||||
refresh_list();
|
||||
options_category.on_change = [this](size_t category_id, int32_t) {
|
||||
change_category(category_id);
|
||||
options_category.on_change = [this](size_t new_index, int32_t) {
|
||||
change_category(new_index);
|
||||
};
|
||||
options_category.set_selected_index(current_category_id);
|
||||
|
||||
button_exit.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
refresh_categories();
|
||||
};
|
||||
|
||||
void FreqManBaseView::focus() {
|
||||
button_exit.focus();
|
||||
|
||||
// TODO: Shouldn't be on focus.
|
||||
if (error_ == ERROR_ACCESS) {
|
||||
nav_.display_modal("Error", "File acces error", ABORT, nullptr);
|
||||
nav_.display_modal("Error", "File access error", ABORT, nullptr);
|
||||
} else if (error_ == ERROR_NOFILES) {
|
||||
nav_.display_modal("Error", "No database files\nin /freqman", ABORT, nullptr);
|
||||
nav_.display_modal("Error", "No database files\nin /FREQMAN", ABORT, nullptr);
|
||||
} else {
|
||||
options_category.focus();
|
||||
}
|
||||
}
|
||||
|
||||
void FreqManBaseView::get_freqman_files() {
|
||||
// Assume this does change much, clear will preserve the existing alloc.
|
||||
file_list.clear();
|
||||
void FreqManBaseView::change_category(size_t new_index) {
|
||||
if (categories().empty())
|
||||
return;
|
||||
|
||||
auto files = scan_root_files(u"FREQMAN", u"*.TXT");
|
||||
|
||||
for (auto file : files) {
|
||||
std::string file_name = file.stem().string();
|
||||
// don't propose tmp / hidden files in freqman's list
|
||||
if (file_name.length() && file_name[0] != '.') {
|
||||
file_list.emplace_back(std::move(file_name));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void FreqManBaseView::change_category(int32_t category_id) {
|
||||
current_category_id = category_id;
|
||||
|
||||
if (file_list.empty()) return;
|
||||
|
||||
if (!load_freqman_file(file_list[categories[category_id].second], database, {})) {
|
||||
current_category_index = new_index;
|
||||
if (!db_.open(get_freqman_path(current_category()))) {
|
||||
error_ = ERROR_ACCESS;
|
||||
}
|
||||
freqlist_view.set_db(database);
|
||||
text_empty.hidden(!database.empty());
|
||||
set_dirty();
|
||||
|
||||
freqlist_view.set_db(db_);
|
||||
}
|
||||
|
||||
void FreqManBaseView::refresh_list() {
|
||||
categories.clear();
|
||||
get_freqman_files();
|
||||
void FreqManBaseView::refresh_categories() {
|
||||
OptionsField::options_t new_categories;
|
||||
|
||||
for (size_t n = 0; n < file_list.size(); n++)
|
||||
categories.emplace_back(std::make_pair(file_list[n].substr(0, 14), n));
|
||||
scan_root_files(
|
||||
freqman_dir, u"*.TXT", [&new_categories](const fs::path& path) {
|
||||
// Skip temp/hidden files.
|
||||
if (path.empty() || path.native()[0] == u'.')
|
||||
return;
|
||||
|
||||
// Alphabetical sort
|
||||
std::sort(categories.begin(), categories.end(), [](auto& left, auto& right) {
|
||||
// The UI layer will truncate long file names when displaying.
|
||||
new_categories.emplace_back(path.stem().string(), new_categories.size());
|
||||
});
|
||||
|
||||
// Alphabetically sort the categories.
|
||||
std::sort(new_categories.begin(), new_categories.end(), [](auto& left, auto& right) {
|
||||
return left.first < right.first;
|
||||
});
|
||||
|
||||
options_category.set_options(categories);
|
||||
if ((unsigned)current_category_id >= categories.size())
|
||||
current_category_id = categories.size() - 1;
|
||||
// Preserve last selection; ensure in range.
|
||||
current_category_index = clip(current_category_index, 0u, new_categories.size());
|
||||
auto saved_index = current_category_index;
|
||||
options_category.set_options(std::move(new_categories));
|
||||
options_category.set_selected_index(saved_index);
|
||||
}
|
||||
|
||||
void FrequencySaveView::save_current_file() {
|
||||
save_freqman_file(file_list[categories[current_category_id].second], database);
|
||||
nav_.pop();
|
||||
void FreqManBaseView::refresh_list(int delta_selected) {
|
||||
// Update the index and ensures in bounds.
|
||||
freqlist_view.set_index(freqlist_view.get_index() + delta_selected);
|
||||
freqlist_view.set_dirty();
|
||||
}
|
||||
|
||||
void FrequencySaveView::on_save_name() {
|
||||
text_prompt(nav_, desc_buffer, 28, [this](std::string& buffer) {
|
||||
database.push_back(std::make_unique<freqman_entry>(freqman_entry{value_, 0, buffer, freqman_type::Single}));
|
||||
save_current_file();
|
||||
});
|
||||
}
|
||||
|
||||
void FrequencySaveView::on_save_timestamp() {
|
||||
database.push_back(std::make_unique<freqman_entry>(freqman_entry{value_, 0, live_timestamp.string(), freqman_type::Single}));
|
||||
save_current_file();
|
||||
}
|
||||
/* FrequencySaveView *************************************/
|
||||
|
||||
FrequencySaveView::FrequencySaveView(
|
||||
NavigationView& nav,
|
||||
const rf::Frequency value)
|
||||
: FreqManBaseView(nav),
|
||||
value_(value) {
|
||||
desc_buffer.reserve(28);
|
||||
: FreqManBaseView(nav) {
|
||||
add_children(
|
||||
{&labels,
|
||||
&big_display,
|
||||
&button_clear,
|
||||
&button_edit,
|
||||
&button_save,
|
||||
&text_description});
|
||||
|
||||
// Todo: add back ?
|
||||
/*for (size_t n = 0; n < database.size(); n++) {
|
||||
if (database[n].value == value_) {
|
||||
error_ = ERROR_DUPLICATE;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
entry_.type = freqman_type::Single;
|
||||
entry_.frequency_a = value;
|
||||
entry_.description = to_string_timestamp(rtc_time::now());
|
||||
refresh_ui();
|
||||
|
||||
add_children({&labels,
|
||||
&big_display,
|
||||
&button_save_name,
|
||||
&button_save_timestamp,
|
||||
&live_timestamp});
|
||||
|
||||
big_display.set(value);
|
||||
|
||||
button_save_name.on_select = [this, &nav](Button&) {
|
||||
on_save_name();
|
||||
};
|
||||
button_save_timestamp.on_select = [this, &nav](Button&) {
|
||||
on_save_timestamp();
|
||||
button_clear.on_select = [this, &nav](Button&) {
|
||||
entry_.description = "";
|
||||
refresh_ui();
|
||||
};
|
||||
|
||||
options_category.on_change = [this, value](size_t category_id, int32_t) {
|
||||
change_category(category_id);
|
||||
big_display.set(value);
|
||||
button_edit.on_select = [this, &nav](Button&) {
|
||||
temp_buffer_ = entry_.description;
|
||||
text_prompt(nav_, temp_buffer_, 30, [this](std::string& new_desc) {
|
||||
entry_.description = new_desc;
|
||||
refresh_ui();
|
||||
});
|
||||
};
|
||||
|
||||
button_save.on_select = [this, &nav](Button&) {
|
||||
db_.insert_entry(entry_, db_.entry_count());
|
||||
nav_.pop();
|
||||
};
|
||||
}
|
||||
|
||||
void FrequencyLoadView::refresh_widgets(const bool v) {
|
||||
freqlist_view.hidden(v);
|
||||
text_empty.hidden(!v);
|
||||
// display.fill_rectangle(freqlist_view.screen_rect(), Color::black());
|
||||
set_dirty();
|
||||
void FrequencySaveView::refresh_ui() {
|
||||
big_display.set(entry_.frequency_a);
|
||||
text_description.set(entry_.description);
|
||||
}
|
||||
|
||||
/* FrequencyLoadView *************************************/
|
||||
|
||||
FrequencyLoadView::FrequencyLoadView(
|
||||
NavigationView& nav)
|
||||
: FreqManBaseView(nav) {
|
||||
on_refresh_widgets = [this](bool v) {
|
||||
refresh_widgets(v);
|
||||
};
|
||||
add_children({&freqlist_view});
|
||||
|
||||
add_children({&freqlist_view,
|
||||
&text_empty});
|
||||
// Resize to fill screen. +2 keeps text out of border.
|
||||
freqlist_view.set_parent_rect({0, 3 * 8, screen_width, 15 * 16 + 2});
|
||||
|
||||
// Resize menu view to fill screen
|
||||
freqlist_view.set_parent_rect({0, 3 * 8, 240, 30 * 8});
|
||||
freqlist_view.on_select = [&nav, this](size_t index) {
|
||||
auto entry = db_[index];
|
||||
// TODO: Maybe return center of range if user choses a range when the app
|
||||
// needs a unique frequency, instead of frequency_a?
|
||||
auto has_range = entry.type == freqman_type::Range ||
|
||||
entry.type == freqman_type::HamRadio;
|
||||
|
||||
freqlist_view.on_select = [&nav, this](FreqManUIList&) {
|
||||
auto& entry = database[freqlist_view.get_index()];
|
||||
if (entry->type == freqman_type::Range) {
|
||||
if (on_range_loaded)
|
||||
on_range_loaded(entry->frequency_a, entry->frequency_b);
|
||||
else if (on_frequency_loaded)
|
||||
on_frequency_loaded(entry->frequency_a);
|
||||
// TODO: Maybe return center of range if user choses a range when the app
|
||||
// needs a unique frequency, instead of frequency_a?
|
||||
// TODO: HamRadio?
|
||||
} else {
|
||||
if (on_frequency_loaded)
|
||||
on_frequency_loaded(entry->frequency_a);
|
||||
}
|
||||
if (on_range_loaded && has_range)
|
||||
on_range_loaded(entry.frequency_a, entry.frequency_b);
|
||||
else if (on_frequency_loaded)
|
||||
on_frequency_loaded(entry.frequency_a);
|
||||
|
||||
nav_.pop(); // NB: this will call dtor.
|
||||
};
|
||||
freqlist_view.on_leave = [this]() {
|
||||
button_exit.focus();
|
||||
};
|
||||
}
|
||||
|
||||
void FrequencyManagerView::on_edit_freq(rf::Frequency f) {
|
||||
database[freqlist_view.get_index()]->frequency_a = f;
|
||||
save_freqman_file(file_list[categories[current_category_id].second], database);
|
||||
change_category(current_category_id);
|
||||
/* FrequencyManagerView **********************************/
|
||||
|
||||
void FrequencyManagerView::on_edit_freq() {
|
||||
// TODO: range edit support?
|
||||
auto freq_edit_view = nav_.push<FrequencyKeypadView>(current_entry().frequency_a);
|
||||
freq_edit_view->on_changed = [this](rf::Frequency f) {
|
||||
auto entry = current_entry();
|
||||
entry.frequency_a = f;
|
||||
db_.replace_entry(current_index(), entry);
|
||||
freqlist_view.set_dirty();
|
||||
};
|
||||
}
|
||||
|
||||
void FrequencyManagerView::on_edit_desc(NavigationView& nav) {
|
||||
text_prompt(nav, desc_buffer, 28, [this](std::string& buffer) {
|
||||
database[freqlist_view.get_index()]->description = std::move(buffer);
|
||||
save_freqman_file(file_list[categories[current_category_id].second], database);
|
||||
change_category(current_category_id);
|
||||
void FrequencyManagerView::on_edit_desc() {
|
||||
temp_buffer_ = current_entry().description;
|
||||
text_prompt(nav_, temp_buffer_, 28, [this](std::string& new_desc) {
|
||||
auto entry = current_entry();
|
||||
entry.description = std::move(new_desc);
|
||||
db_.replace_entry(current_index(), entry);
|
||||
freqlist_view.set_dirty();
|
||||
});
|
||||
}
|
||||
|
||||
void FrequencyManagerView::on_new_category(NavigationView& nav) {
|
||||
text_prompt(nav, desc_buffer, 12, [this](std::string& buffer) {
|
||||
File freqman_file;
|
||||
create_freqman_file(buffer, freqman_file);
|
||||
refresh_list();
|
||||
change_category(current_category_id);
|
||||
void FrequencyManagerView::on_add_category() {
|
||||
temp_buffer_.clear();
|
||||
text_prompt(nav_, temp_buffer_, 12, [this](std::string& new_name) {
|
||||
if (!new_name.empty()) {
|
||||
create_freqman_file(new_name);
|
||||
refresh_categories();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FrequencyManagerView::on_delete() {
|
||||
if (database.empty()) {
|
||||
delete_freqman_file(file_list[categories[current_category_id].second]);
|
||||
refresh_list();
|
||||
} else {
|
||||
database.erase(database.begin() + freqlist_view.get_index());
|
||||
save_freqman_file(file_list[categories[current_category_id].second], database);
|
||||
}
|
||||
change_category(current_category_id);
|
||||
void FrequencyManagerView::on_del_category() {
|
||||
nav_.push<ModalMessageView>(
|
||||
"Delete", "Delete " + current_category() + "\nAre you sure?", YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
db_.close(); // Ensure file is closed.
|
||||
auto path = get_freqman_path(current_category());
|
||||
delete_file(path);
|
||||
refresh_categories();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FrequencyManagerView::refresh_widgets(const bool v) {
|
||||
button_edit_freq.hidden(v);
|
||||
button_edit_desc.hidden(v);
|
||||
button_delete.hidden(v);
|
||||
text_empty.hidden(!v);
|
||||
freqlist_view.hidden(v);
|
||||
labels.hidden(v);
|
||||
// display.fill_rectangle(freqlist_view.screen_rect(), Color::black());
|
||||
set_dirty();
|
||||
void FrequencyManagerView::on_add_entry() {
|
||||
freqman_entry entry{
|
||||
.frequency_a = 100'000'000,
|
||||
.description = std::string{"Entry "} + to_string_dec_uint(db_.entry_count()),
|
||||
.type = freqman_type::Single,
|
||||
};
|
||||
|
||||
// Add will insert below the currently selected item.
|
||||
db_.insert_entry(entry, current_index() + 1);
|
||||
refresh_list(1);
|
||||
}
|
||||
|
||||
FrequencyManagerView::~FrequencyManagerView() {
|
||||
// save_freqman_file(file_list[categories[current_category_id].second], database);
|
||||
void FrequencyManagerView::on_del_entry() {
|
||||
if (db_.empty())
|
||||
return;
|
||||
|
||||
nav_.push<ModalMessageView>(
|
||||
"Delete", "Delete" + pretty_string(current_entry(), 23) + "\nAre you sure?", YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
db_.delete_entry(current_index());
|
||||
refresh_list();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
FrequencyManagerView::FrequencyManagerView(
|
||||
NavigationView& nav)
|
||||
: FreqManBaseView(nav) {
|
||||
on_refresh_widgets = [this](bool v) {
|
||||
refresh_widgets(v);
|
||||
add_children(
|
||||
{&freqlist_view,
|
||||
&labels,
|
||||
&button_add_category,
|
||||
&button_del_category,
|
||||
&button_edit_freq,
|
||||
&button_edit_desc,
|
||||
&button_add_entry,
|
||||
&button_del_entry});
|
||||
|
||||
freqlist_view.on_select = [this](size_t) {
|
||||
button_edit_freq.focus();
|
||||
};
|
||||
|
||||
add_children({&labels,
|
||||
&button_new_category,
|
||||
&freqlist_view,
|
||||
&text_empty,
|
||||
&button_edit_freq,
|
||||
&button_edit_desc,
|
||||
&button_delete});
|
||||
|
||||
freqlist_view.on_select = [this](FreqManUIList&) {
|
||||
// Allows for quickly exiting control.
|
||||
freqlist_view.on_leave = [this]() {
|
||||
button_edit_freq.focus();
|
||||
};
|
||||
|
||||
button_new_category.on_select = [this, &nav](Button&) {
|
||||
desc_buffer = "";
|
||||
on_new_category(nav);
|
||||
button_add_category.on_select = [this]() {
|
||||
on_add_category();
|
||||
};
|
||||
|
||||
button_edit_freq.on_select = [this, &nav](Button&) {
|
||||
if (database.empty())
|
||||
database.push_back(std::make_unique<freqman_entry>(freqman_entry{0, 0, "", freqman_type::Single}));
|
||||
|
||||
auto new_view = nav.push<FrequencyKeypadView>(database[freqlist_view.get_index()]->frequency_a);
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
on_edit_freq(f);
|
||||
};
|
||||
button_del_category.on_select = [this]() {
|
||||
on_del_category();
|
||||
};
|
||||
|
||||
button_edit_desc.on_select = [this, &nav](Button&) {
|
||||
if (database.empty())
|
||||
database.push_back(std::make_unique<freqman_entry>(freqman_entry{0, 0, "", freqman_type::Single}));
|
||||
|
||||
desc_buffer = database[freqlist_view.get_index()]->description;
|
||||
on_edit_desc(nav);
|
||||
button_edit_freq.on_select = [this](Button&) {
|
||||
on_edit_freq();
|
||||
};
|
||||
|
||||
button_delete.on_select = [this, &nav](Button&) {
|
||||
on_delete();
|
||||
button_edit_desc.on_select = [this](Button&) {
|
||||
on_edit_desc();
|
||||
};
|
||||
|
||||
button_add_entry.on_select = [this]() {
|
||||
on_add_entry();
|
||||
};
|
||||
|
||||
button_del_entry.on_select = [this]() {
|
||||
on_del_entry();
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -20,15 +21,16 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "freqman.hpp"
|
||||
#include "freqman_db.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_freqlist.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "freqman.hpp"
|
||||
#include "ui_freqlist.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@@ -40,74 +42,77 @@ class FreqManBaseView : public View {
|
||||
void focus() override;
|
||||
|
||||
protected:
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
using options_t = std::vector<option_t>;
|
||||
using options_t = OptionsField::options_t;
|
||||
|
||||
NavigationView& nav_;
|
||||
freqman_error error_{NO_ERROR};
|
||||
options_t categories{};
|
||||
std::function<void(void)> on_select_frequency{nullptr};
|
||||
std::function<void(bool)> on_refresh_widgets{nullptr};
|
||||
|
||||
void get_freqman_files();
|
||||
void change_category(int32_t category_id);
|
||||
void refresh_list();
|
||||
void change_category(size_t new_index);
|
||||
/* Access the categories directly from the OptionsField.
|
||||
* This avoids holding multiple copies of the file list. */
|
||||
const options_t& categories() const { return options_category.options(); }
|
||||
const auto& current_category() const { return options_category.selected_index_name(); }
|
||||
auto current_index() const { return freqlist_view.get_index(); }
|
||||
freqman_entry current_entry() const { return db_[current_index()]; }
|
||||
void refresh_categories();
|
||||
void refresh_list(int delta_selected = 0);
|
||||
|
||||
freqman_db database{};
|
||||
std::vector<std::string> file_list{};
|
||||
FreqmanDB db_{};
|
||||
|
||||
/* The top section (category) is 20px tall. */
|
||||
Labels label_category{
|
||||
{{0, 4}, "Category:", Color::light_grey()}};
|
||||
{{0, 2}, "Category:", Color::light_grey()}};
|
||||
|
||||
OptionsField options_category{
|
||||
{9 * 8, 4},
|
||||
14,
|
||||
{9 * 8, 2},
|
||||
14 /* length */,
|
||||
{}};
|
||||
|
||||
FreqManUIList freqlist_view{
|
||||
{0, 3 * 8, 240, 23 * 8}};
|
||||
|
||||
Text text_empty{
|
||||
{7 * 8, 12 * 8, 16 * 8, 16},
|
||||
"Empty category !",
|
||||
};
|
||||
{0, 3 * 8, screen_width, 12 * 16 + 2 /* 2 Keeps text out of border. */}};
|
||||
|
||||
Button button_exit{
|
||||
{16 * 8, 34 * 8, 14 * 8, 4 * 8},
|
||||
{15 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
"Exit"};
|
||||
|
||||
private:
|
||||
protected:
|
||||
/* Static so selected category is persisted across UI instances. */
|
||||
static size_t current_category_index;
|
||||
};
|
||||
|
||||
// TODO: support for new category.
|
||||
class FrequencySaveView : public FreqManBaseView {
|
||||
public:
|
||||
FrequencySaveView(NavigationView& nav, const rf::Frequency value);
|
||||
|
||||
std::string title() const override { return "Save freq."; };
|
||||
std::string title() const override { return "Save freq"; };
|
||||
|
||||
private:
|
||||
std::string desc_buffer{};
|
||||
rf::Frequency value_{};
|
||||
std::string temp_buffer_{};
|
||||
freqman_entry entry_{};
|
||||
|
||||
void on_save_name();
|
||||
void on_save_timestamp();
|
||||
void save_current_file();
|
||||
void refresh_ui();
|
||||
|
||||
BigFrequency big_display{
|
||||
{4, 2 * 16, 28 * 8, 32},
|
||||
{0, 2 * 16, 28 * 8, 4 * 16},
|
||||
0};
|
||||
|
||||
Labels labels{
|
||||
{{1 * 8, 12 * 8}, "Save as:", Color::white()}};
|
||||
{{0 * 8, 6 * 16}, "Description:", Color::white()}};
|
||||
|
||||
Button button_save_name{
|
||||
{1 * 8, 17 * 8, 12 * 8, 48},
|
||||
"Name (set)"};
|
||||
Button button_save_timestamp{
|
||||
{1 * 8, 25 * 8, 12 * 8, 48},
|
||||
"Timestamp:"};
|
||||
LiveDateTime live_timestamp{
|
||||
{14 * 8, 27 * 8, 16 * 8, 16}};
|
||||
Text text_description{{0 * 8, 7 * 16, 30 * 8, 1 * 16}};
|
||||
|
||||
Button button_clear{
|
||||
{4 * 8, 10 * 16, 10 * 8, 2 * 16},
|
||||
"Clear"};
|
||||
|
||||
Button button_edit{
|
||||
{16 * 8, 10 * 16, 10 * 8, 2 * 16},
|
||||
"Edit"};
|
||||
|
||||
Button button_save{
|
||||
{0 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
"Save"};
|
||||
};
|
||||
|
||||
class FrequencyLoadView : public FreqManBaseView {
|
||||
@@ -116,46 +121,62 @@ class FrequencyLoadView : public FreqManBaseView {
|
||||
std::function<void(rf::Frequency, rf::Frequency)> on_range_loaded{};
|
||||
|
||||
FrequencyLoadView(NavigationView& nav);
|
||||
|
||||
std::string title() const override { return "Load freq."; };
|
||||
|
||||
private:
|
||||
void refresh_widgets(const bool v);
|
||||
std::string title() const override { return "Load freq"; };
|
||||
};
|
||||
|
||||
class FrequencyManagerView : public FreqManBaseView {
|
||||
public:
|
||||
FrequencyManagerView(NavigationView& nav);
|
||||
~FrequencyManagerView();
|
||||
|
||||
std::string title() const override { return "Freqman"; };
|
||||
|
||||
private:
|
||||
std::string desc_buffer{};
|
||||
std::string temp_buffer_{};
|
||||
|
||||
void refresh_widgets(const bool v);
|
||||
void on_edit_freq(rf::Frequency f);
|
||||
void on_edit_desc(NavigationView& nav);
|
||||
void on_new_category(NavigationView& nav);
|
||||
void on_delete();
|
||||
void on_edit_freq();
|
||||
void on_edit_desc();
|
||||
void on_add_category();
|
||||
void on_del_category();
|
||||
void on_add_entry();
|
||||
void on_del_entry();
|
||||
|
||||
Labels labels{
|
||||
{{4 * 8 + 4, 26 * 8}, "Edit:", Color::light_grey()}};
|
||||
{{5 * 8, 14 * 16 - 4}, "Edit:", Color::light_grey()}};
|
||||
|
||||
Button button_new_category{
|
||||
{23 * 8, 2, 7 * 8, 20},
|
||||
"New"};
|
||||
NewButton button_add_category{
|
||||
{23 * 8, 0 * 16, 7 * 4, 20},
|
||||
{},
|
||||
&bitmap_icon_new_file,
|
||||
Color::white(),
|
||||
true};
|
||||
|
||||
NewButton button_del_category{
|
||||
{26 * 8 + 4, 0 * 16, 7 * 4, 20},
|
||||
{},
|
||||
&bitmap_icon_trash,
|
||||
Color::red(),
|
||||
true};
|
||||
|
||||
Button button_edit_freq{
|
||||
{0 * 8, 29 * 8, 14 * 8, 32},
|
||||
{0 * 8, 15 * 16, 15 * 8, 2 * 16},
|
||||
"Frequency"};
|
||||
|
||||
Button button_edit_desc{
|
||||
{0 * 8, 34 * 8, 14 * 8, 32},
|
||||
{0 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
"Description"};
|
||||
|
||||
Button button_delete{
|
||||
{16 * 8, 29 * 8, 14 * 8, 32},
|
||||
"Delete"};
|
||||
NewButton button_add_entry{
|
||||
{15 * 8, 15 * 16, 7 * 8 + 4, 2 * 16},
|
||||
{},
|
||||
&bitmap_icon_add,
|
||||
Color::white(),
|
||||
true};
|
||||
|
||||
NewButton button_del_entry{
|
||||
{22 * 8 + 4, 15 * 16, 7 * 8 + 4, 2 * 16},
|
||||
{},
|
||||
&bitmap_icon_delete,
|
||||
Color::red(),
|
||||
true};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
@@ -137,8 +137,8 @@ bool ReconView::recon_save_freq(const std::string& freq_file_path, size_t freq_i
|
||||
entry.bandwidth = last_entry.bandwidth;
|
||||
entry.type = freqman_type::Single;
|
||||
|
||||
std::string frequency_to_add;
|
||||
get_freq_string(entry, frequency_to_add);
|
||||
// TODO: Use FreqmanDB
|
||||
auto frequency_to_add = to_freqman_string(entry);
|
||||
|
||||
auto result = recon_file.open(freq_file_path); // First recon if freq is already in txt
|
||||
if (!result.is_valid()) {
|
||||
@@ -607,6 +607,7 @@ ReconView::ReconView(NavigationView& nav)
|
||||
};
|
||||
|
||||
button_remove.on_select = [this](ButtonWithEncoder&) {
|
||||
// TODO: Use FreqmanDB
|
||||
if (frequency_list.size() > 0) {
|
||||
if (!manual_mode) {
|
||||
// scanner or recon (!scanner) mode
|
||||
@@ -629,8 +630,7 @@ ReconView::ReconView(NavigationView& nav)
|
||||
auto result = freqman_file.create(freq_file_path);
|
||||
if (!result.is_valid()) {
|
||||
for (size_t n = 0; n < frequency_list.size(); n++) {
|
||||
std::string line;
|
||||
get_freq_string(*frequency_list[n], line);
|
||||
auto line = to_freqman_string(*frequency_list[n]);
|
||||
freqman_file.write_line(line);
|
||||
}
|
||||
}
|
||||
@@ -640,7 +640,6 @@ ReconView::ReconView(NavigationView& nav)
|
||||
File recon_file{};
|
||||
File tmp_recon_file{};
|
||||
std::string tmp_freq_file_path{freq_file_path + ".TMP"};
|
||||
std::string frequency_to_add{};
|
||||
|
||||
freqman_entry entry = current_entry();
|
||||
entry.frequency_a = freq;
|
||||
@@ -649,7 +648,7 @@ ReconView::ReconView(NavigationView& nav)
|
||||
entry.bandwidth = last_entry.bandwidth;
|
||||
entry.type = freqman_type::Single;
|
||||
|
||||
get_freq_string(entry, frequency_to_add);
|
||||
auto frequency_to_add = to_freqman_string(entry);
|
||||
|
||||
delete_file(tmp_freq_file_path);
|
||||
auto result = tmp_recon_file.create(tmp_freq_file_path); // First recon if freq is already in txt
|
||||
@@ -833,7 +832,7 @@ ReconView::ReconView(NavigationView& nav)
|
||||
open_view->on_changed = [this](std::vector<std::string> result) {
|
||||
input_file = result[0];
|
||||
output_file = result[1];
|
||||
freq_file_path = "/FREQMAN/" + output_file + ".TXT";
|
||||
freq_file_path = get_freqman_path(output_file).string();
|
||||
recon_save_config_to_sd();
|
||||
|
||||
autosave = persistent_memory::recon_autosave_freqs();
|
||||
@@ -892,7 +891,7 @@ ReconView::ReconView(NavigationView& nav)
|
||||
|
||||
// Loading input and output file from settings
|
||||
recon_load_config_from_sd();
|
||||
freq_file_path = "/FREQMAN/" + output_file + ".TXT";
|
||||
freq_file_path = get_freqman_path(output_file).string();
|
||||
|
||||
field_recon_match_mode.set_selected_index(recon_match_mode);
|
||||
field_squelch.set_value(squelch);
|
||||
|
@@ -21,12 +21,13 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_recon_settings.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_recon_settings.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "freqman_db.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
@@ -55,11 +56,9 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st
|
||||
|
||||
button_load_freqs.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->push_dir(freqman_dir);
|
||||
open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) {
|
||||
std::string dir_filter = "FREQMAN/";
|
||||
std::string str_file_path = new_file_path.string();
|
||||
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
|
||||
// get the filename without txt extension so we can use load_freqman_file fcn
|
||||
if (new_file_path.native().find(freqman_dir.native()) == 0) {
|
||||
_input_file = new_file_path.stem().string();
|
||||
text_input_file.set(_input_file);
|
||||
} else {
|
||||
|
@@ -314,17 +314,13 @@ ScannerView::ScannerView(
|
||||
// Button to load txt files from the FREQMAN folder
|
||||
button_load.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->on_changed = [this](std::filesystem::path new_file_path) {
|
||||
std::string dir_filter = "FREQMAN/";
|
||||
std::string str_file_path = new_file_path.string();
|
||||
|
||||
if (str_file_path.find(dir_filter) != std::string::npos) { // assert file from the FREQMAN folder
|
||||
open_view->push_dir(freqman_dir);
|
||||
open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) {
|
||||
if (new_file_path.native().find(freqman_dir.native()) == 0) {
|
||||
scan_pause();
|
||||
// get the filename without txt extension so we can use load_freqman_file fcn
|
||||
std::string str_file_name = new_file_path.stem().string();
|
||||
frequency_file_load(str_file_name, true);
|
||||
frequency_file_load(new_file_path.stem().string(), true);
|
||||
} else {
|
||||
nav_.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -494,6 +490,7 @@ ScannerView::ScannerView(
|
||||
bigdisplay_update(BDC_GREY); // Back to grey color
|
||||
};
|
||||
|
||||
// TODO: remove this parsing?
|
||||
// Button to add current frequency (found during Search) to the Scan Frequency List
|
||||
button_add.on_select = [this](Button&) {
|
||||
File scanner_file;
|
||||
|
Reference in New Issue
Block a user