From f537c7896e63bb57114de24ee34b1e69f9ba86ef Mon Sep 17 00:00:00 2001 From: Kyle Reed <3761006+kallanreed@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:51:28 -0700 Subject: [PATCH] Scanner persisted freq file, TextField for current item (#1403) * Don't truncate string passed to Text widget * Focus TextField on touch like other fields * TextField for current, save last opened freq file --- firmware/application/apps/ui_scanner.cpp | 57 +++++++++++++----------- firmware/application/apps/ui_scanner.hpp | 16 ++++--- firmware/common/ui_widget.cpp | 16 +++++-- firmware/common/ui_widget.hpp | 5 +++ 4 files changed, 58 insertions(+), 36 deletions(-) diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index 63e64e65..2f0718ba 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -31,8 +31,6 @@ namespace fs = std::filesystem; namespace ui { -static const fs::path default_scan_file{u"FREQMAN/SCANNER.TXT"}; - ScannerThread::ScannerThread(std::vector frequency_list) : frequency_list_{std::move(frequency_list)} { _manual_search = false; @@ -234,7 +232,7 @@ void ScannerView::handle_retune(int64_t freq, uint32_t freq_idx) { if (!manual_search) { if (entries.size() > 0) - text_current_index.set(to_string_dec_uint(freq_idx + 1, 3)); + field_current_index.set_text(to_string_dec_uint(freq_idx + 1, 3)); if (freq_idx < entries.size() && entries[freq_idx].description.size() > 1) text_current_desc.set(entries[freq_idx].description); // Show description from file @@ -243,9 +241,20 @@ void ScannerView::handle_retune(int64_t freq, uint32_t freq_idx) { } } +void ScannerView::handle_encoder(EncoderEvent delta) { + auto index_step = delta > 0 ? 1 : -1; + + if (scan_thread) + scan_thread->set_index_stepper(index_step); + + // Restart browse timer when frequency changes. + if (browse_timer != 0) + browse_timer = 1; +} + std::string ScannerView::loaded_filename() const { - auto filename = loaded_path.filename().string(); - if (filename.length() > 23) { // Truncate and add ellipses if long file name + auto filename = freqman_file; + if (filename.length() > 23) { // Truncate long file name. filename.resize(22); filename = filename + "+"; } @@ -266,7 +275,7 @@ ScannerView::~ScannerView() { } void ScannerView::show_max_index() { // show total number of freqs to scan - text_current_index.set("---"); + field_current_index.set_text("---"); if (entries.size() == FREQMAN_MAX_PER_FILE) { text_max_index.set_style(&Styles::red); @@ -293,7 +302,7 @@ ScannerView::ScannerView( &button_load, &button_clear, &rssi, - &text_current_index, + &field_current_index, &text_max_index, &text_current_desc, &big_display, @@ -336,14 +345,14 @@ ScannerView::ScannerView( }; }; - // Button to clear in-memory frequency list + // Button to clear in-memory frequency list. button_clear.on_select = [this, &nav](Button&) { if (scan_thread && entries.size()) { scan_thread->stop(); // STOP SCANNER THREAD entries.clear(); show_max_index(); // UPDATE new list size on screen - text_current_index.set(""); + field_current_index.set_text(""); text_current_desc.set(loaded_filename()); scan_thread->set_freq_lock(0); // Reset the scanner lock @@ -351,7 +360,7 @@ ScannerView::ScannerView( } }; - // Button to configure starting frequency for a manual range search + // Button to configure starting frequency for a manual range search. button_manual_start.on_select = [this, &nav](Button& button) { auto new_view = nav_.push(frequency_range.min); new_view->on_changed = [this, &button](rf::Frequency f) { @@ -360,7 +369,7 @@ ScannerView::ScannerView( }; }; - // Button to configure ending frequency for a manual range search + // Button to configure ending frequency for a manual range search. button_manual_end.on_select = [this, &nav](Button& button) { auto new_view = nav.push(frequency_range.max); new_view->on_changed = [this, &button](rf::Frequency f) { @@ -369,7 +378,7 @@ ScannerView::ScannerView( }; }; - // Button to pause/resume scan (note that some other buttons will trigger resume also) + // Button to pause/resume scan (note that some other buttons will trigger resume also). button_pause.on_select = [this](ButtonWithEncoder&) { if (userpause) user_resume(); @@ -380,19 +389,14 @@ ScannerView::ScannerView( } }; - // Encoder dial causes frequency change when focus is on pause button + // Encoder dial causes frequency change when focus is on pause button or current index. button_pause.on_change = [this]() { - int32_t encoder_delta{(button_pause.get_encoder_delta() > 0) ? 1 : -1}; - - if (scan_thread) - scan_thread->set_index_stepper(encoder_delta); - - // Restart browse timer when frequency changes - if (browse_timer != 0) - browse_timer = 1; - + handle_encoder(button_pause.get_encoder_delta()); button_pause.set_encoder_delta(0); }; + field_current_index.on_encoder_change = [this](TextField&, EncoderEvent delta) { + handle_encoder(delta); + }; // Button to switch to Audio app button_audio_app.on_select = [this](Button&) { @@ -485,7 +489,7 @@ ScannerView::ScannerView( // Button to add current frequency (found during Search) to the Scan Frequency List button_add.on_select = [this](Button&) { FreqmanDB db; - if (db.open(loaded_path, /*create*/ true)) { + if (db.open(get_freqman_path(freqman_file), /*create*/ true)) { freqman_entry entry{ .frequency_a = current_frequency, .type = freqman_type::Single, @@ -511,7 +515,7 @@ ScannerView::ScannerView( } } } else { - nav_.display_modal("Error", "Cannot open " + loaded_path.filename().string() + "\nfor appending freq."); + nav_.display_modal("Error", "Cannot open " + freqman_file + ".TXT\nfor appending freq."); bigdisplay_update(-1); // Need to poke this control after displaying modal? } }; @@ -531,7 +535,7 @@ ScannerView::ScannerView( receiver_model.set_squelch_level(0); // LOAD FREQUENCIES - frequency_file_load(default_scan_file); + frequency_file_load(get_freqman_path(freqman_file)); } void ScannerView::frequency_file_load(const fs::path& path) { @@ -542,12 +546,11 @@ void ScannerView::frequency_file_load(const fs::path& path) { FreqmanDB db; if (!db.open(path)) { text_current_desc.set("NO " + path.filename().string()); - loaded_path = default_scan_file; return; } entries.clear(); - loaded_path = path; + freqman_file = path.stem().string(); Optional range; for (auto entry : db) { diff --git a/firmware/application/apps/ui_scanner.hpp b/firmware/application/apps/ui_scanner.hpp index c2bc4c3e..8df6c5eb 100644 --- a/firmware/application/apps/ui_scanner.hpp +++ b/firmware/application/apps/ui_scanner.hpp @@ -110,6 +110,8 @@ class ScannerView : public View { std::string title() const override { return "Scanner"; }; private: + static constexpr const char* default_freqman_file = "SCANNER"; + RxRadioState radio_state_{}; // Settings @@ -117,6 +119,7 @@ class ScannerView : public View { uint32_t lock_wait{2}; int32_t squelch{-30}; scanner_range_t frequency_range{0, MAX_UFREQ}; + std::string freqman_file{default_freqman_file}; app_settings::SettingsManager settings_{ "rx_scanner"sv, app_settings::Mode::RX, @@ -126,6 +129,7 @@ class ScannerView : public View { {"scanner_squelch"sv, &squelch}, {"range_min"sv, &frequency_range.min}, {"range_max"sv, &frequency_range.max}, + {"file"sv, &freqman_file}, }}; NavigationView& nav_; @@ -142,7 +146,7 @@ class ScannerView : public View { void update_squelch_while_paused(int32_t max_db); void on_statistics_update(const ChannelStatistics& statistics); void handle_retune(int64_t freq, uint32_t freq_idx); - + void handle_encoder(EncoderEvent delta); std::string loaded_filename() const; uint32_t browse_timer{0}; @@ -151,7 +155,6 @@ class ScannerView : public View { int32_t bigdisplay_current_color{-2}; rf::Frequency bigdisplay_current_frequency{0}; - std::filesystem::path loaded_path{}; std::vector entries{}; uint32_t current_index{0}; rf::Frequency current_frequency{0}; @@ -223,8 +226,9 @@ class ScannerView : public View { {0 * 16, 2 * 16, 15 * 16, 8}, }; - Text text_current_index{ + TextField field_current_index{ {0, 3 * 16, 3 * 8, 16}, + {}, }; Text text_max_index{ @@ -235,9 +239,9 @@ class ScannerView : public View { {0, 4 * 16, 240 - 6 * 8, 16}, }; - BigFrequency big_display{// Show frequency in glamour - {4, 6 * 16, 28 * 8, 52}, - 0}; + BigFrequency big_display{ + {4, 6 * 16, 28 * 8, 52}, + 0}; Button button_manual_start{ {0 * 8, 11 * 16, 11 * 8, 28}, diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index a38d9e1b..3ede238d 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -366,16 +366,17 @@ void Text::paint(Painter& painter) { const auto rect = screen_rect(); auto s = has_focus() ? style().invert() : style(); auto max_len = (unsigned)rect.width() / s.font.char_width(); + auto text_view = std::string_view{text}; painter.fill_rectangle(rect, s.background); - if (text.length() > max_len) - text.resize(max_len); + if (text_view.length() > max_len) + text_view = text_view.substr(0, max_len); painter.draw_string( rect.location(), s, - text); + text_view); } /* Labels ****************************************************************/ @@ -1773,6 +1774,15 @@ bool TextField::on_encoder(EncoderEvent delta) { return false; } +bool TextField::on_touch(TouchEvent event) { + if (event.type == TouchEvent::Type::Start) { + focus(); + return true; + } + + return false; +} + /* NumberField ***********************************************************/ NumberField::NumberField( diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 2f2d68a6..2268f3f6 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -208,6 +208,10 @@ class Text : public Widget { void paint(Painter& painter) override; protected: + // NB: Don't truncate this string. The UI will only render + // as many characters as will fit in its rectange. + // Apps expect to be able to retrieve this string to avoid + // needing to hold additional copies in memory. std::string text; }; @@ -703,6 +707,7 @@ class TextField : public Text { bool on_key(KeyEvent key) override; bool on_encoder(EncoderEvent delta) override; + bool on_touch(TouchEvent event) override; private: using Text::set;