From c0f51c26900a1ccab80fa0b8bf70e9a849dacca7 Mon Sep 17 00:00:00 2001 From: furrtek Date: Wed, 20 Sep 2017 07:50:59 +0100 Subject: [PATCH] Date and time display widget Disabled handwriting text input (not that useful for now) Bugfix: Trim long filenames in fileman Slight cleanup of 7-seg display widget --- firmware/application/CMakeLists.txt | 2 +- firmware/application/ui_fileman.cpp | 86 ++++++++++--------------- firmware/application/ui_fileman.hpp | 27 +++----- firmware/application/ui_freqman.cpp | 23 +------ firmware/application/ui_freqman.hpp | 22 ++----- firmware/application/ui_navigation.cpp | 14 ++-- firmware/application/ui_navigation.hpp | 10 +-- firmware/application/ui_textentry.cpp | 10 +-- firmware/common/ui_widget.cpp | 79 +++++++++++++++++------ firmware/common/ui_widget.hpp | 32 +++++++++ firmware/portapack-h1-havoc.bin | Bin 900360 -> 902808 bytes 11 files changed, 162 insertions(+), 143 deletions(-) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index d40f64ece..7b49448a3 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -177,7 +177,7 @@ set(CPPSRC ui_font_fixed_8x16.cpp ui_freqman.cpp ui_geomap.cpp - ui_handwrite.cpp + # ui_handwrite.cpp ui_jammer.cpp ui_lcr.cpp ui_menu.cpp diff --git a/firmware/application/ui_fileman.cpp b/firmware/application/ui_fileman.cpp index 287b48c4d..2a2cfb982 100644 --- a/firmware/application/ui_fileman.cpp +++ b/firmware/application/ui_fileman.cpp @@ -36,6 +36,7 @@ void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_p entry_list.clear(); + // List all directories and files, put directories up top for (const auto& entry : std::filesystem::directory_iterator(dir_path, u"*")) { if (std::filesystem::is_regular_file(entry.status())) { entry_list.push_back({ entry.path(), (uint32_t)entry.size(), false }); @@ -45,14 +46,14 @@ void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_p } } -std::filesystem::path FileManBaseView::get_absolute_path() { - std::string current_path_str = current_path.string(); +std::filesystem::path FileManBaseView::get_selected_path() { + std::string selected_path_str = current_path.string(); - if (current_path_str.back() != '/') - current_path_str += '/'; - current_path_str += (entry_list[menu_view.highlighted()].entry_path.string()); + if (selected_path_str.back() != '/') + selected_path_str += '/'; + selected_path_str += (entry_list[menu_view.highlighted()].entry_path.string()); - return current_path_str; + return selected_path_str; } FileManBaseView::FileManBaseView( @@ -62,13 +63,22 @@ FileManBaseView::FileManBaseView( load_directory_contents(current_path); if (!entry_list.size()) - error_ = true; + empty_root = true; add_children({ &labels, &text_current, &button_exit }); + + // Go back one level on left + menu_view.on_left = [&nav, this]() { + std::string current_path_str = current_path.string(); + + current_path_str = current_path_str.substr(0, current_path_str.find_last_of('/')); + load_directory_contents(current_path_str); + refresh_list(); + }; button_exit.on_select = [this, &nav](Button&) { nav.pop(); @@ -76,8 +86,7 @@ FileManBaseView::FileManBaseView( }; void FileManBaseView::focus() { - - if (error_) { + if (empty_root) { button_exit.focus(); nav_.display_modal("Error", "No files in root.", ABORT, nullptr); } else { @@ -91,16 +100,18 @@ void FileManBaseView::refresh_list() { size_t file_size; if (!entry_list.size()) { + // Hide widgets, show warning if (on_refresh_widgets) on_refresh_widgets(true); } else { + // Hide warning, show widgets if (on_refresh_widgets) on_refresh_widgets(false); menu_view.clear(); for (size_t n = 0; n < entry_list.size(); n++) { - auto entry_name = entry_list[n].entry_path.filename().string(); + auto entry_name = entry_list[n].entry_path.filename().string().substr(0, 20); if (entry_list[n].is_directory) { @@ -145,47 +156,28 @@ void FileManBaseView::refresh_list() { } } -void FileSaveView::on_save_name() { - /*text_prompt(nav_, &filename_buffer, 8, [this](std::string * buffer) { - //database.entries.push_back({ value_, "", *buffer }); - //save_freqman_file(entry_list[current_category_id], database); +/*void FileSaveView::on_save_name() { + text_prompt(nav_, &filename_buffer, 8, [this](std::string * buffer) { nav_.pop(); - });*/ -} - -void FileSaveView::on_tick_second() { - rtcGetTime(&RTCD1, &datetime); - str_timestamp = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " + - to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0'); - text_timestamp.set(str_timestamp); -} - -FileSaveView::~FileSaveView() { - rtc_time::signal_tick_second -= signal_token_tick_second; + }); } FileSaveView::FileSaveView( NavigationView& nav ) : FileManBaseView(nav) { - filename_buffer.reserve(8); - - signal_token_tick_second = rtc_time::signal_tick_second += [this]() { - this->on_tick_second(); - }; + name_buffer.clear(); add_children({ &text_save, &button_save_name, - &text_timestamp + &live_timestamp }); - on_tick_second(); - button_save_name.on_select = [this, &nav](Button&) { on_save_name(); }; -} +}*/ void FileLoadView::refresh_widgets(const bool v) { menu_view.hidden(v); @@ -224,15 +216,15 @@ FileLoadView::FileLoadView( } void FileManagerView::on_rename(NavigationView& nav) { - text_prompt(nav, &filename_buffer, 12, [this](std::string * buffer) { - rename_file(get_absolute_path(), *buffer); + text_prompt(nav, &name_buffer, 12, [this](std::string * buffer) { + rename_file(get_selected_path(), *buffer); load_directory_contents(current_path); refresh_list(); }); } void FileManagerView::on_delete() { - delete_file(get_absolute_path()); + delete_file(get_selected_path()); load_directory_contents(current_path); refresh_list(); } @@ -259,7 +251,6 @@ FileManagerView::FileManagerView( }; add_children({ - //&labels, &menu_view, &text_empty, &button_rename, @@ -267,29 +258,20 @@ FileManagerView::FileManagerView( &button_delete }); - // Go back one level on left - menu_view.on_left = [&nav, this]() { - std::string current_path_str = current_path.string(); - - current_path_str = current_path_str.substr(0, current_path_str.find_last_of('/')); - load_directory_contents(current_path_str); - refresh_list(); - }; - refresh_list(); on_select_entry = [this]() { if (entry_list[menu_view.highlighted()].is_directory) { - load_directory_contents(get_absolute_path()); + load_directory_contents(get_selected_path()); refresh_list(); } else button_rename.focus(); }; button_new_dir.on_select = [this, &nav](Button&) { - filename_buffer = ""; + name_buffer.clear(); - text_prompt(nav, &filename_buffer, 12, [this](std::string * buffer) { + text_prompt(nav, &name_buffer, 12, [this](std::string * buffer) { std::string path_str = *buffer; make_new_directory(current_path.string() + '/' + path_str); @@ -300,7 +282,7 @@ FileManagerView::FileManagerView( button_rename.on_select = [this, &nav](Button&) { if (!entry_list[menu_view.highlighted()].is_directory) { - filename_buffer = entry_list[menu_view.highlighted()].entry_path.filename().string(); + name_buffer = entry_list[menu_view.highlighted()].entry_path.filename().string(); on_rename(nav); } }; diff --git a/firmware/application/ui_fileman.hpp b/firmware/application/ui_fileman.hpp index 791da01fa..bc9f80e9d 100644 --- a/firmware/application/ui_fileman.hpp +++ b/firmware/application/ui_fileman.hpp @@ -27,7 +27,6 @@ #include "file.hpp" #include "ui_navigation.hpp" #include "ui_textentry.hpp" -#include "rtc_time.hpp" namespace ui { @@ -46,7 +45,7 @@ public: void focus() override; void load_directory_contents(const std::filesystem::path& dir_path); - std::filesystem::path get_absolute_path(); + std::filesystem::path get_selected_path(); std::string title() const override { return "File manager"; }; @@ -55,7 +54,7 @@ protected: const std::string suffix[5] = { "B", "kB", "MB", "GB", "??" }; - bool error_ { false }; + bool empty_root { false }; std::function on_select_entry { nullptr }; std::function on_refresh_widgets { nullptr }; std::vector entry_list { }; @@ -87,20 +86,15 @@ protected: }; }; -class FileSaveView : public FileManBaseView { +/*class FileSaveView : public FileManBaseView { public: FileSaveView(NavigationView& nav); ~FileSaveView(); private: - std::string filename_buffer { }; - rtc::RTC datetime { }; - std::string str_timestamp { }; + std::string name_buffer { }; void on_save_name(); - void on_tick_second(); - - SignalToken signal_token_tick_second { }; Text text_save { { 4 * 8, 15 * 8, 8 * 8, 16 }, @@ -110,11 +104,10 @@ private: { 4 * 8, 18 * 8, 12 * 8, 32 }, "Name (set)" }; - Text text_timestamp { - { 17 * 8, 24 * 8, 11 * 8, 16 }, - "MM/DD HH:MM", + LiveDateTime live_timestamp { + { 17 * 8, 24 * 8, 11 * 8, 16 } }; -}; +};*/ class FileLoadView : public FileManBaseView { public: @@ -132,16 +125,12 @@ public: ~FileManagerView(); private: - std::string filename_buffer { }; + std::string name_buffer { }; void refresh_widgets(const bool v); void on_rename(NavigationView& nav); void on_delete(); - /*Labels labels { - { { 4 * 8 + 4, 26 * 8 }, "Edit:", Color::light_grey() } - };*/ - Button button_rename { { 0 * 8, 28 * 8, 14 * 8, 32 }, "Rename" diff --git a/firmware/application/ui_freqman.cpp b/firmware/application/ui_freqman.cpp index 6c0dfab60..d712d1cc4 100644 --- a/firmware/application/ui_freqman.cpp +++ b/firmware/application/ui_freqman.cpp @@ -134,22 +134,11 @@ void FrequencySaveView::on_save_name() { } void FrequencySaveView::on_save_timestamp() { - database.entries.push_back({ value_, "", str_timestamp }); + database.entries.push_back({ value_, "", live_timestamp.string() }); save_freqman_file(file_list[current_category_id], database); nav_.pop(); } -void FrequencySaveView::on_tick_second() { - rtcGetTime(&RTCD1, &datetime); - str_timestamp = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " + - to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0'); - text_timestamp.set(str_timestamp); -} - -FrequencySaveView::~FrequencySaveView() { - rtc_time::signal_tick_second -= signal_token_tick_second; -} - FrequencySaveView::FrequencySaveView( NavigationView& nav, const rf::Frequency value @@ -166,20 +155,14 @@ FrequencySaveView::FrequencySaveView( } }*/ - signal_token_tick_second = rtc_time::signal_tick_second += [this]() { - this->on_tick_second(); - }; - add_children({ + &labels, &big_display, - &text_save, &button_save_name, &button_save_timestamp, - &text_timestamp + &live_timestamp }); - on_tick_second(); - big_display.set(value); button_save_name.on_select = [this, &nav](Button&) { diff --git a/firmware/application/ui_freqman.hpp b/firmware/application/ui_freqman.hpp index 6e8da9002..65ff734bc 100644 --- a/firmware/application/ui_freqman.hpp +++ b/firmware/application/ui_freqman.hpp @@ -28,7 +28,6 @@ #include "ui_receiver.hpp" #include "ui_textentry.hpp" #include "freqman.hpp" -#include "rtc_time.hpp" namespace ui { @@ -89,40 +88,33 @@ protected: class FrequencySaveView : public FreqManBaseView { public: FrequencySaveView(NavigationView& nav, const rf::Frequency value); - ~FrequencySaveView(); private: std::string desc_buffer { }; - rtc::RTC datetime { }; rf::Frequency value_ { }; - std::string str_timestamp { }; void on_save_name(); void on_save_timestamp(); - void on_tick_second(); - - SignalToken signal_token_tick_second { }; BigFrequency big_display { { 4, 2 * 16, 28 * 8, 32 }, 0 }; - Text text_save { - { 4 * 8, 15 * 8, 8 * 8, 16 }, - "Save as:", + Labels labels { + { { 2 * 8, 14 * 8 }, "Save as:", Color::white() } }; + Button button_save_name { - { 4 * 8, 18 * 8, 12 * 8, 32 }, + { 2 * 8, 17 * 8, 14 * 8, 48 }, "Name (set)" }; Button button_save_timestamp { - { 4 * 8, 23 * 8, 12 * 8, 32 }, + { 2 * 8, 25 * 8, 14 * 8, 48 }, "Timestamp:" }; - Text text_timestamp { - { 17 * 8, 24 * 8, 11 * 8, 16 }, - "MM/DD HH:MM", + LiveDateTime live_timestamp { + { 17 * 8, 27 * 8, 11 * 8, 16 } }; }; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 16c6439af..1f6327b3e 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -87,7 +87,7 @@ SystemStatusView::SystemStatusView() { &button_back, &title, &button_stealth, - &button_textentry, + //&button_textentry, &button_camera, &button_sleep, &sd_card_status_view, @@ -96,10 +96,10 @@ SystemStatusView::SystemStatusView() { button_back.id = -1; // Special ID used by FocusManager title.set_style(&style_systemstatus); - if (!portapack::persistent_memory::ui_config_textentry()) + /*if (!portapack::persistent_memory::ui_config_textentry()) button_textentry.set_bitmap(&bitmap_icon_keyboard); else - button_textentry.set_bitmap(&bitmap_icon_unistroke); + button_textentry.set_bitmap(&bitmap_icon_unistroke);*/ if (portapack::persistent_memory::stealth_mode()) button_stealth.set_foreground(ui::Color::green()); @@ -113,9 +113,9 @@ SystemStatusView::SystemStatusView() { this->on_stealth(); }; - button_textentry.on_select = [this](ImageButton&) { + /*button_textentry.on_select = [this](ImageButton&) { this->on_textentry(); - }; + };*/ button_camera.on_select = [this](ImageButton&) { this->on_camera(); @@ -154,7 +154,7 @@ void SystemStatusView::on_stealth() { button_stealth.set_dirty(); } -void SystemStatusView::on_textentry() { +/*void SystemStatusView::on_textentry() { uint8_t cfg; cfg = portapack::persistent_memory::ui_config_textentry(); @@ -164,7 +164,7 @@ void SystemStatusView::on_textentry() { button_textentry.set_bitmap(&bitmap_icon_unistroke); else button_textentry.set_bitmap(&bitmap_icon_keyboard); -} +}*/ void SystemStatusView::on_camera() { auto path = next_filename_stem_matching_pattern(u"SCR_????"); diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 67b6a9633..f2504e05b 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -83,18 +83,18 @@ private: }; ImageButton button_stealth { - { 152, 0, 2 * 8, 1 * 16 }, + { 170, 0, 2 * 8, 1 * 16 }, &bitmap_icon_stealth, Color::light_grey(), Color::dark_grey() }; - ImageButton button_textentry { + /*ImageButton button_textentry { { 170, 0, 2 * 8, 1 * 16 }, &bitmap_icon_unistroke, Color::white(), Color::dark_grey() - }; + };*/ ImageButton button_camera { { 188, 0, 2 * 8, 1 * 16 }, @@ -115,7 +115,7 @@ private: }; void on_stealth(); - void on_textentry(); + //void on_textentry(); void on_camera(); }; @@ -143,7 +143,7 @@ public: void pop_modal(); void display_modal(const std::string& title, const std::string& message); - void display_modal(const std::string& title, const std::string& message, const modal_t type, const std::function on_choice); + void display_modal(const std::string& title, const std::string& message, const modal_t type, const std::function on_choice = nullptr); void focus() override; diff --git a/firmware/application/ui_textentry.cpp b/firmware/application/ui_textentry.cpp index 0e51e271a..fe478546b 100644 --- a/firmware/application/ui_textentry.cpp +++ b/firmware/application/ui_textentry.cpp @@ -21,28 +21,28 @@ */ #include "ui_textentry.hpp" -#include "portapack_persistent_memory.hpp" -#include "ui_handwrite.hpp" +//#include "portapack_persistent_memory.hpp" #include "ui_alphanum.hpp" +//#include "ui_handwrite.hpp" using namespace portapack; namespace ui { void text_prompt(NavigationView& nav, std::string * str, const size_t max_length, const std::function on_done) { - if (persistent_memory::ui_config_textentry() == 0) { + //if (persistent_memory::ui_config_textentry() == 0) { auto te_view = nav.push(str, max_length); te_view->on_changed = [on_done](std::string * value) { if (on_done) on_done(value); }; - } else { + /*} else { auto te_view = nav.push(str, max_length); te_view->on_changed = [on_done](std::string * value) { if (on_done) on_done(value); }; - } + }*/ } void TextEntryView::update_text() { diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 7a6a10efb..d7b197140 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -405,6 +405,45 @@ void Labels::paint(Painter& painter) { } } +/* LiveDateTime **********************************************************/ + +void LiveDateTime::on_tick_second() { + rtcGetTime(&RTCD1, &datetime); + + text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " + + to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0'); + + set_dirty(); +} + +LiveDateTime::LiveDateTime( + Rect parent_rect +) : Widget { parent_rect } +{ + signal_token_tick_second = rtc_time::signal_tick_second += [this]() { + this->on_tick_second(); + }; +} + +LiveDateTime::~LiveDateTime() { + rtc_time::signal_tick_second -= signal_token_tick_second; +} + +void LiveDateTime::paint(Painter& painter) { + const auto rect = screen_rect(); + const auto s = style(); + + on_tick_second(); + + painter.fill_rectangle(rect, s.background); + + painter.draw_string( + rect.location(), + s, + text + ); +} + /* BigFrequency **********************************************************/ BigFrequency::BigFrequency( @@ -422,21 +461,22 @@ void BigFrequency::set(const rf::Frequency frequency) { void BigFrequency::paint(Painter& painter) { uint32_t i, digit_def; - char digits[7]; + std::array digits; char digit; - Coord digit_x, digit_y; + Point digit_pos; ui::Color segment_color; const auto rect = screen_rect(); // Erase - painter.fill_rectangle({{0, rect.location().y()}, {240, 52}}, ui::Color::black()); + painter.fill_rectangle({ { 0, rect.location().y() }, { 240, 52 } }, ui::Color::black()); + // Prepare digits if (!_frequency) { - for (i = 0; i < 7; i++) // ----.------ - digits[i] = 10; + digits.fill(10); // ----.--- + digit_pos = { 0, rect.location().y() }; } else { - _frequency /= 1000; // GMMM.KKKuuu + _frequency /= 1000; // GMMM.KKK(uuu) for (i = 0; i < 7; i++) { digits[6 - i] = _frequency % 10; @@ -444,37 +484,38 @@ void BigFrequency::paint(Painter& painter) { } // Remove leading zeros - for (i = 0; i < 7; i++) { + for (i = 0; i < 3; i++) { if (!digits[i]) digits[i] = 16; // "Don't draw" code else break; } + + digit_pos = { (240 - ((7 * digit_width) + 8) - (i * digit_width)) / 2, rect.location().y() }; } segment_color = style().foreground; // Draw - digit_x = rect.location().x(); // 7 * 32 + 8 = 232 (4 px margins) for (i = 0; i < 7; i++) { digit = digits[i]; - digit_y = rect.location().y(); + if (digit < 16) { digit_def = segment_font[(uint8_t)digit]; - if (digit_def & 0x01) painter.fill_rectangle({{digit_x + 4, digit_y}, {20, 4}}, segment_color); - if (digit_def & 0x02) painter.fill_rectangle({{digit_x + 24, digit_y + 4}, {4, 20}}, segment_color); - if (digit_def & 0x04) painter.fill_rectangle({{digit_x + 24, digit_y + 28}, {4, 20}}, segment_color); - if (digit_def & 0x08) painter.fill_rectangle({{digit_x + 4, digit_y + 48}, {20, 4}}, segment_color); - if (digit_def & 0x10) painter.fill_rectangle({{digit_x, digit_y + 28}, {4, 20}}, segment_color); - if (digit_def & 0x20) painter.fill_rectangle({{digit_x, digit_y + 4}, {4, 20}}, segment_color); - if (digit_def & 0x40) painter.fill_rectangle({{digit_x + 4, digit_y + 24}, {20, 4}}, segment_color); + + for (size_t s = 0; s < 7; s++) { + if (digit_def & 1) + painter.fill_rectangle({ digit_pos + segments[s].location(), segments[s].size() }, segment_color); + digit_def >>= 1; + } } + if (i == 3) { // Dot - painter.fill_rectangle({{digit_x + 34, digit_y + 48}, {4, 4}}, segment_color); - digit_x += 40; + painter.fill_rectangle({ digit_pos + Point(34, 48), { 4, 4 } }, segment_color); + digit_pos += { (digit_width + 8), 0 }; } else { - digit_x += 32; + digit_pos += { digit_width, 0 }; } } } diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 437b3958d..e4382559d 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -28,6 +28,7 @@ #include "ui_painter.hpp" #include "ui_focus.hpp" #include "ui_font_fixed_8x16.hpp" +#include "rtc_time.hpp" #include "radio.hpp" #include "portapack.hpp" @@ -235,6 +236,25 @@ private: std::vector