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
This commit is contained in:
furrtek 2017-09-20 07:50:59 +01:00
parent 37ce81383d
commit c0f51c2690
11 changed files with 162 additions and 143 deletions

View File

@ -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

View File

@ -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);
}
};

View File

@ -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<void(void)> on_select_entry { nullptr };
std::function<void(bool)> on_refresh_widgets { nullptr };
std::vector<fileman_entry> 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"

View File

@ -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&) {

View File

@ -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 }
};
};

View File

@ -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_????");

View File

@ -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<void(bool)> on_choice);
void display_modal(const std::string& title, const std::string& message, const modal_t type, const std::function<void(bool)> on_choice = nullptr);
void focus() override;

View File

@ -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<void(std::string *)> on_done) {
if (persistent_memory::ui_config_textentry() == 0) {
//if (persistent_memory::ui_config_textentry() == 0) {
auto te_view = nav.push<AlphanumView>(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<HandWriteView>(str, max_length);
te_view->on_changed = [on_done](std::string * value) {
if (on_done)
on_done(value);
};
}
}*/
}
void TextEntryView::update_text() {

View File

@ -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<char, 7> 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 };
}
}
}

View File

@ -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<Label> labels_;
};
class LiveDateTime : public Widget {
public:
LiveDateTime(Rect parent_rect);
~LiveDateTime();
void paint(Painter& painter) override;
std::string& string() {
return text;
}
private:
void on_tick_second();
rtc::RTC datetime { };
SignalToken signal_token_tick_second { };
std::string text { };
};
class BigFrequency : public Widget {
public:
BigFrequency(Rect parent_rect, rf::Frequency frequency);
@ -246,6 +266,8 @@ public:
private:
rf::Frequency _frequency;
static constexpr Dim digit_width = 32;
const uint8_t segment_font[11] = {
0b00111111, // 0: ABCDEF
0b00000110, // 1: AB
@ -259,6 +281,16 @@ private:
0b01101111, // 9: ABCDFG
0b01000000 // -: G
};
const Rect segments[7] = {
{{4, 0}, {20, 4}},
{{24, 4}, {4, 20}},
{{24, 28}, {4, 20}},
{{4, 48}, {20, 4}},
{{0, 28}, {4, 20}},
{{0, 4}, {4, 20}},
{{4, 24}, {20, 4}}
};
};
class ProgressBar : public Widget {

Binary file not shown.