diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index 606458190..24856c66f 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -140,7 +140,7 @@ FrequencySaveView::FrequencySaveView( button_edit.on_select = [this, &nav](Button&) { temp_buffer_ = entry_.description; - text_prompt(nav_, temp_buffer_, 30, [this](std::string& new_desc) { + text_prompt(nav_, temp_buffer_, desc_edit_max, [this](std::string& new_desc) { entry_.description = new_desc; refresh_ui(); }); @@ -189,7 +189,7 @@ FrequencyLoadView::FrequencyLoadView( /* FrequencyManagerView **********************************/ void FrequencyManagerView::on_edit_freq() { - // TODO: range edit support? + // TODO: range edit support. auto freq_edit_view = nav_.push(current_entry().frequency_a); freq_edit_view->on_changed = [this](rf::Frequency f) { auto entry = current_entry(); @@ -201,7 +201,7 @@ void FrequencyManagerView::on_edit_freq() { void FrequencyManagerView::on_edit_desc() { temp_buffer_ = current_entry().description; - text_prompt(nav_, temp_buffer_, 28, [this](std::string& new_desc) { + text_prompt(nav_, temp_buffer_, desc_edit_max, [this](std::string& new_desc) { auto entry = current_entry(); entry.description = std::move(new_desc); db_.replace_entry(current_index(), entry); @@ -211,7 +211,7 @@ void FrequencyManagerView::on_edit_desc() { void FrequencyManagerView::on_add_category() { temp_buffer_.clear(); - text_prompt(nav_, temp_buffer_, 12, [this](std::string& new_name) { + text_prompt(nav_, temp_buffer_, 20, [this](std::string& new_name) { if (!new_name.empty()) { create_freqman_file(new_name); refresh_categories(); @@ -249,7 +249,7 @@ void FrequencyManagerView::on_del_entry() { return; nav_.push( - "Delete", "Delete" + pretty_string(current_entry(), 23) + "\nAre you sure?", YESNO, + "Delete", "Delete " + trim(pretty_string(current_entry(), 23)) + "\nAre you sure?", YESNO, [this](bool choice) { if (choice) { db_.delete_entry(current_index()); diff --git a/firmware/application/apps/ui_freqman.hpp b/firmware/application/apps/ui_freqman.hpp index dbf6e9236..d32e6c945 100644 --- a/firmware/application/apps/ui_freqman.hpp +++ b/firmware/application/apps/ui_freqman.hpp @@ -79,6 +79,7 @@ class FreqManBaseView : public View { protected: /* Static so selected category is persisted across UI instances. */ static size_t current_category_index; + static constexpr size_t desc_edit_max = 0x80; }; // TODO: support for new category. diff --git a/firmware/application/freqman_db.cpp b/firmware/application/freqman_db.cpp index fba166d4a..06755a170 100644 --- a/firmware/application/freqman_db.cpp +++ b/firmware/application/freqman_db.cpp @@ -200,9 +200,12 @@ std::string pretty_string(const freqman_entry& entry, size_t max_length) { to_string_dec_uint(entry.frequency_b / 1'000'000) + "M: " + entry.description; break; case freqman_type::HamRadio: - str = "" + to_string_dec_uint(entry.frequency_a / 1'000'000) + "M," + + str = "R:" + to_string_dec_uint(entry.frequency_a / 1'000'000) + "M,T:" + to_string_dec_uint(entry.frequency_b / 1'000'000) + "M: " + entry.description; break; + case freqman_type::Raw: + str = entry.description; + break; default: str = "UNK:" + entry.description; break; @@ -244,8 +247,10 @@ std::string to_freqman_string(const freqman_entry& entry) { if (is_valid(entry.tone)) append_field("c", tonekey::tone_key_value_string(entry.tone)); break; + case freqman_type::Raw: + return entry.description; default: - return {}; // TODO: Comment type with description? + return {}; }; if (is_valid(entry.modulation) && entry.modulation < freqman_modulations.size()) { @@ -429,6 +434,11 @@ freqman_entry FreqmanDB::operator[](FileWrapper::Line line) const { freqman_entry entry; if (parse_freqman_entry(*line_text, entry)) return entry; + else { + entry.type = freqman_type::Raw; + entry.description = trim(*line_text); + return entry; + } } return {}; @@ -444,7 +454,7 @@ void FreqmanDB::insert_entry(const freqman_entry& entry, FileWrapper::Line line) void FreqmanDB::replace_entry(FileWrapper::Line line, const freqman_entry& entry) { auto range = wrapper_->line_range(line); if (!range) - return; // TODO: Message? + return; // Don't overwrite the '\n'. range->end--; diff --git a/firmware/application/freqman_db.hpp b/firmware/application/freqman_db.hpp index 974d96fea..6058fd834 100644 --- a/firmware/application/freqman_db.hpp +++ b/firmware/application/freqman_db.hpp @@ -59,6 +59,7 @@ enum class freqman_type : uint8_t { Single, // f= Range, // a=,b= HamRadio, // r=,t= + Raw, // line content in description Unknown, }; @@ -140,9 +141,9 @@ enum class freqman_type : uint8_t { /* Freqman Entry *******************************/ struct freqman_entry { - int64_t frequency_a{0}; // 'f=freq' or 'a=freq_start' or 'r=recv_freq' - int64_t frequency_b{0}; // 'b=freq_end' or 't=tx_freq' - std::string description{0}; // 'd=desc' + int64_t frequency_a{0}; // 'f=freq' or 'a=freq_start' or 'r=recv_freq' + int64_t frequency_b{0}; // 'b=freq_end' or 't=tx_freq' + std::string description{}; // 'd=desc' freqman_type type{freqman_type::Unknown}; freqman_index_t modulation{freqman_invalid_index}; freqman_index_t bandwidth{freqman_invalid_index}; diff --git a/firmware/application/ui/ui_freqlist.cpp b/firmware/application/ui/ui_freqlist.cpp index 6c112e5ea..9db0f3ab5 100644 --- a/firmware/application/ui/ui_freqlist.cpp +++ b/firmware/application/ui/ui_freqlist.cpp @@ -56,16 +56,19 @@ void FreqManUIList::paint(Painter& painter) { auto text = std::string{}; auto index = start_index_ + offset; auto line_position = rect.location() + Point{4, 1 + (int)offset * char_height}; - - // Highlight the selected item. - auto style = (offset == selected_index_) ? &Styles::bg_white : base_style; + auto is_selected = offset == selected_index_; + auto style = base_style; if (index < db_->entry_count()) { auto entry = (*db_)[index]; // db_ is directly backed by a file, so invalid lines cannot be - // pre-filtered. Just show an empty 'slot' in this case. + // pre-filtered. Show an empty entry if 'Unknown'. if (entry.type != freqman_type::Unknown) text = pretty_string(entry, line_max_length); + + // Otherwise, if 'Raw' indicate an invalid entry by color. + if (entry.type == freqman_type::Raw) + style = &Styles::light_grey; } // Pad right with ' ' so trailing chars are cleaned up. @@ -73,7 +76,8 @@ void FreqManUIList::paint(Painter& painter) { if (text.length() < line_max_length) text.resize(line_max_length, ' '); - painter.draw_string(line_position, *style, text); + painter.draw_string( + line_position, (is_selected ? style->invert() : *style), text); } // Draw a bounding rectangle when focused. diff --git a/firmware/test/application/test_string_format.cpp b/firmware/test/application/test_string_format.cpp index 99c79ab7b..898f731a2 100644 --- a/firmware/test/application/test_string_format.cpp +++ b/firmware/test/application/test_string_format.cpp @@ -47,3 +47,7 @@ TEST_CASE("trim removes whitespace.") { TEST_CASE("trim returns empty for only whitespace.") { CHECK(trim(" \n").empty()); } + +TEST_CASE("trim empty returns empty.") { + CHECK(trim("").empty()); +}