FIXME: crash when add or remove entry

This commit is contained in:
zxkmm 2025-04-13 20:23:23 +08:00
parent 5f33b7f02e
commit 61378c98aa
3 changed files with 210 additions and 62 deletions

View File

@ -42,35 +42,35 @@ __attribute__((section(".external_app.app_waterfall_designer.application_informa
/*.bitmap_data = */ {
0x00,
0x00,
0xC0,
0x01,
0x80,
0x00,
0x80,
0x20,
0x60,
0x13,
0x10,
0x0C,
0x88,
0x08,
0x84,
0x10,
0x84,
0x10,
0xC2,
0x21,
0x84,
0x10,
0x04,
0x10,
0x08,
0x08,
0x10,
0x04,
0x60,
0x00,
0xFE,
0x7F,
0x03,
0x80,
0xC0,
0x53,
0xD5,
0xAB,
0xCA,
0x53,
0xD5,
0xAB,
0xCA,
0x53,
0xD5,
0xAB,
0xCA,
0x53,
0xD5,
0x03,
0xC0,
0xFF,
0xFF,
0xFB,
0xD7,
0xFE,
0x7F,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::cyan().v,

View File

@ -27,6 +27,8 @@
#include "file_path.hpp"
#include "ui_fileman.hpp"
#include "file_reader.hpp"
#include "ui_textentry.hpp"
#include "usb_serial_asyncmsg.hpp"
using namespace portapack;
@ -94,9 +96,7 @@ WaterfallDesignerView::WaterfallDesignerView(NavigationView& nav)
};
button_new.on_select = [this]() {
profile_levels.clear();
current_profile_path = "";
refresh_menu_view();
on_create_new_profile();
};
button_open.on_select = [this]() {
@ -108,10 +108,39 @@ WaterfallDesignerView::WaterfallDesignerView(NavigationView& nav)
};
button_add_level.on_select = [this]() {
portapack::async_tx_enabled = true;
UsbSerialAsyncmsg::asyncmsg("-------- pl");
for (auto& line : profile_levels) {
UsbSerialAsyncmsg::asyncmsg(line);
}
UsbSerialAsyncmsg::asyncmsg("-------- pl end");
UsbSerialAsyncmsg::asyncmsg("-------- index");
UsbSerialAsyncmsg::asyncmsg(to_string_dec_uint(menu_view.highlighted_index()));
UsbSerialAsyncmsg::asyncmsg("-------- index end");
UsbSerialAsyncmsg::asyncmsg("\n\n\n\n\n");
on_add_level();
};
button_remove_level.on_select = [this]() {
portapack::async_tx_enabled = true;
UsbSerialAsyncmsg::asyncmsg("-------- pl");
for (auto& line : profile_levels) {
UsbSerialAsyncmsg::asyncmsg(line);
}
UsbSerialAsyncmsg::asyncmsg("-------- pl end");
UsbSerialAsyncmsg::asyncmsg("-------- index");
UsbSerialAsyncmsg::asyncmsg(to_string_dec_uint(menu_view.highlighted_index()));
UsbSerialAsyncmsg::asyncmsg("-------- index end");
UsbSerialAsyncmsg::asyncmsg("\n\n\n\n\n");
on_remove_level();
};
@ -125,6 +154,23 @@ WaterfallDesignerView::WaterfallDesignerView(NavigationView& nav)
nav_.pop();
};
menu_view.on_highlight = [this]() {
portapack::async_tx_enabled = true;
UsbSerialAsyncmsg::asyncmsg("-------- pl");
for (auto& line : profile_levels) {
UsbSerialAsyncmsg::asyncmsg(line);
}
UsbSerialAsyncmsg::asyncmsg("-------- pl end");
UsbSerialAsyncmsg::asyncmsg("-------- index");
UsbSerialAsyncmsg::asyncmsg(to_string_dec_uint(menu_view.highlighted_index()));
UsbSerialAsyncmsg::asyncmsg("-------- index end");
UsbSerialAsyncmsg::asyncmsg("\n\n\n\n\n");
};
receiver_model.enable();
option_bandwidth.set_by_value(capture_rate);
@ -132,6 +178,12 @@ WaterfallDesignerView::WaterfallDesignerView(NavigationView& nav)
nav.display_modal("Error", message);
};
button_save.hidden(true);
button_add_level.hidden(true);
button_remove_level.hidden(true);
button_edit_color.hidden(true);
button_apply_setting.hidden(true);
refresh_menu_view();
}
@ -144,7 +196,7 @@ WaterfallDesignerView::WaterfallDesignerView(
}
WaterfallDesignerView::~WaterfallDesignerView() {
if(!if_apply_setting) restore_current_profile();
if (!if_apply_setting) restore_current_profile();
receiver_model.disable();
baseband::shutdown();
}
@ -200,6 +252,12 @@ void WaterfallDesignerView::on_profile_changed(std::filesystem::path new_profile
}
}
button_save.hidden(false);
button_add_level.hidden(false);
button_remove_level.hidden(false);
button_edit_color.hidden(false);
button_apply_setting.hidden(false);
refresh_menu_view();
on_apply_current_to_wtf();
}
@ -253,17 +311,17 @@ void WaterfallDesignerView::refresh_menu_view() {
}
void WaterfallDesignerView::on_apply_current_to_wtf() {
std::filesystem::path current_path = "waterfall.txt";
copy_file(current_profile_path, current_path);
std::filesystem::path system_read_path = "waterfall.txt";
copy_file(current_profile_path, system_read_path);
remove_child(waterfall.get());
waterfall.reset();
waterfall = std::make_unique<spectrum::WaterfallView>();
add_child(waterfall.get());
ui::Rect waterfall_rect{0, header_height, screen_rect().width(), screen_rect().height() - header_height};
waterfall->set_parent_rect(waterfall_rect);
set_dirty();
}
@ -297,18 +355,32 @@ void WaterfallDesignerView::on_save_profile() {
}
void WaterfallDesignerView::on_add_level() {
// new view to let user add
if (menu_view.highlighted_index() >= profile_levels.size()) return;
if (profile_levels[menu_view.highlighted_index()].empty()) return;
if (profile_levels[menu_view.highlighted_index()][0] == '#') return;
if (profile_levels[menu_view.highlighted_index()].find(',') == std::string::npos) return;
size_t insert_pos = menu_view.highlighted_index();
std::string new_entry = "0,128,128,128";
profile_levels.insert(profile_levels.begin() + insert_pos, new_entry);
refresh_menu_view();
on_edit_color();
}
void WaterfallDesignerView::on_remove_level() {
// remove entrance from vec
if (menu_view.highlighted_index() >= profile_levels.size()) return;
if (profile_levels[menu_view.highlighted_index()].empty()) return;
if (profile_levels[menu_view.highlighted_index()][0] == '#') return;
if (profile_levels[menu_view.highlighted_index()].find(',') == std::string::npos) return;
profile_levels.erase(profile_levels.begin() + menu_view.highlighted_index());
refresh_menu_view();
}
void WaterfallDesignerView::on_edit_color() {
if (menu_view.highlighted_index() >= profile_levels.size()) return;
if (profile_levels[menu_view.highlighted_index()].empty()) return;
if (profile_levels[menu_view.highlighted_index()][0] == '#') return;
if (profile_levels[menu_view.highlighted_index()].find(',') == std::string::npos) return;
auto color_picker_view = nav_.push<WaterfallDesignerColorPickerView>(profile_levels[menu_view.highlighted_index()]);
color_picker_view->on_save = [this](std::string new_color) {
profile_levels[menu_view.highlighted_index()] = new_color;
@ -331,7 +403,32 @@ void WaterfallDesignerView::restore_current_profile() {
}
void WaterfallDesignerView::on_apply_setting() {
}
void WaterfallDesignerView::on_create_new_profile() {
text_prompt(
nav_,
file_name_buffer,
32 - 4, // fat32
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
if (buffer.empty()) return;
if (buffer.length() < 4 || buffer.substr(buffer.length() - 4) != ".txt") {
buffer += ".txt";
}
File new_file;
auto error = new_file.create(waterfalls_dir / buffer);
if (error) {
nav_.display_modal("Err", "create file err");
return;
}
profile_levels.clear();
current_profile_path = waterfalls_dir / buffer;
on_profile_changed(current_profile_path);
});
}
WaterfallDesignerColorPickerView::WaterfallDesignerColorPickerView(NavigationView& nav, std::string color_str)
@ -341,14 +438,20 @@ WaterfallDesignerColorPickerView::WaterfallDesignerColorPickerView(NavigationVie
&field_red,
&field_green,
&field_blue,
&field_step,
&field_index,
&progressbar,
&button_save});
progressbar.set_max(UINT8_MAX);
size_t pos = 0;
size_t next_pos = 0;
// index
next_pos = color_str.find(',', pos);
if (next_pos != std::string::npos) {
index_ = static_cast<uint8_t>(std::stoi(color_str.substr(pos, next_pos - pos)));
pos = next_pos + 1;
}
@ -372,18 +475,19 @@ WaterfallDesignerColorPickerView::WaterfallDesignerColorPickerView(NavigationVie
field_red.set_value(red_);
field_green.set_value(green_);
field_blue.set_value(blue_);
field_index.set_value(index_);
// cb
field_red.on_change = [this](int32_t) {
update_color();
update_color_index();
};
field_green.on_change = [this](int32_t) {
update_color();
update_color_index();
};
field_blue.on_change = [this](int32_t) {
update_color();
update_color_index();
};
button_save.on_select = [this](Button&) {
@ -391,39 +495,59 @@ WaterfallDesignerColorPickerView::WaterfallDesignerColorPickerView(NavigationVie
nav_.pop();
};
update_color();
field_index.on_change = [this](int32_t) {
update_color_index();
};
field_step.on_change = [this](int32_t) {
field_red.set_step(field_step.value());
field_green.set_step(field_step.value());
field_blue.set_step(field_step.value());
field_index.set_step(field_step.value());
};
update_color_index();
}
void WaterfallDesignerColorPickerView::focus() {
button_save.focus();
}
void WaterfallDesignerColorPickerView::update_color() {
void WaterfallDesignerColorPickerView::update_color_index() {
index_ = static_cast<uint8_t>(field_index.value());
red_ = static_cast<uint8_t>(field_red.value());
green_ = static_cast<uint8_t>(field_green.value());
blue_ = static_cast<uint8_t>(field_blue.value());
const Rect preview_rect{screen_width - 48, 1 * 16, 40, 40};
painter.fill_rectangle(
{preview_rect.left() , preview_rect.top() , preview_rect.width() , preview_rect.height() },
Painter painter_instance_2;
painter_instance_2.fill_rectangle(
{preview_rect.left(), preview_rect.top(), preview_rect.width(), preview_rect.height()},
ui::Color(red_, green_, blue_));
}
void WaterfallDesignerColorPickerView::paint(Painter& painter) {
// this is not duplicated code.
// because need to display color when enter,
// but it is too early to call update_color() in the constructor.
const Rect preview_rect{screen_width - 48, 1 * 16, 40, 40};
painter.fill_rectangle(
{preview_rect.left(), preview_rect.top(), preview_rect.width(), preview_rect.height()},
ui::Color(red_, green_, blue_));
}
std::string WaterfallDesignerColorPickerView::build_color_str() {
size_t index_pos = color_str_.find(',');
if (index_pos != std::string::npos) {
return color_str_.substr(0, index_pos + 1) +
std::to_string(red_) + "," +
std::to_string(green_) + "," +
std::to_string(blue_);
return color_str_.substr(0, index_pos + 1) +
to_string_dec_uint(red_) + "," +
to_string_dec_uint(green_) + "," +
to_string_dec_uint(blue_);
}
return "0," + std::to_string(red_) + "," + std::to_string(green_) + "," + std::to_string(blue_);
return to_string_dec_uint(index_) + "," + to_string_dec_uint(red_) + "," + to_string_dec_uint(green_) + "," + to_string_dec_uint(blue_);
}
} /* namespace ui::external_app::waterfall_designer */

View File

@ -54,42 +54,64 @@ class WaterfallDesignerColorPickerView : public View {
private:
NavigationView& nav_;
std::string color_str_;
uint8_t index_{0};
uint8_t red_{0};
uint8_t green_{0};
uint8_t blue_{0};
void update_color();
void update_color_index();
std::string build_color_str();
Painter painter;
Labels labels{
{{0 * 8, 0 * 16}, "Red", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 2 * 16}, "Green", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 4 * 16}, "Blue", Theme::getInstance()->fg_light->foreground}};
{{0 * 8, 0 * 16}, "Index", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 2 * 16}, "Red", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 4 * 16}, "Green", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 6 * 16}, "Blue", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 8 * 16}, "Step", Theme::getInstance()->fg_light->foreground}};
NumberField field_red{
NumberField field_index{
{0 * 8, 1 * 16},
3,
{0, 255},
1,
' '};
NumberField field_green{
NumberField field_red{
{0 * 8, 3 * 16},
3,
{0, 255},
1,
' '};
NumberField field_blue{
NumberField field_green{
{0 * 8, 5 * 16},
3,
{0, 255},
1,
' '};
NumberField field_blue{
{0 * 8, 7 * 16},
3,
{0, 255},
1,
' '};
NumberField field_step{
{0 * 8, 9 * 16},
3,
{0, 255},
1,
' '};
ProgressBar progressbar{
{0 * 8,
screen_height - 4 * 16 - 2 * 16 - 1 * 16,
screen_width,
2 * 16}};
Button button_save{
{0, 7 * 16, screen_width, 2 * 16},
{0, screen_height - 4 * 16, screen_width, 4 * 16},
"Save"};
};
@ -181,7 +203,7 @@ class WaterfallDesignerView : public View {
NewButton button_edit_color{
{20 * 8, 8 * 16, 4 * 8, 32},
{},
&bitmap_icon_paint,
&bitmap_icon_notepad,
Theme::getInstance()->fg_blue->foreground};
NewButton button_apply_setting{
@ -192,6 +214,7 @@ class WaterfallDesignerView : public View {
void backup_current_profile();
void restore_current_profile();
void on_create_new_profile();
void on_open_profile();
void on_profile_changed(std::filesystem::path new_profile_path);
void on_save_profile();
@ -211,7 +234,7 @@ class WaterfallDesignerView : public View {
however if you don't push the apply (play) btn, it would resotore in distructor,
if you push apply, it would apply and exit*/
std::vector<std::string> profile_levels{"0,0,0,0", "86,0,0,255", "171,0,255,0", "255,255,0,0", "255,255,255,255"};
std::vector<std::string> profile_levels{};
static constexpr ui::Dim header_height = 10 * 16;
@ -224,6 +247,7 @@ class WaterfallDesignerView : public View {
3};
std::unique_ptr<spectrum::WaterfallView> waterfall{};
std::string file_name_buffer{}; // needed by text_prompy
MessageHandlerRegistration message_handler_freqchg{
Message::ID::FreqChangeCommand,