mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-10 16:49:36 +00:00
Multi screen support, with dyn alignment (#2801)
This commit is contained in:
@@ -272,14 +272,14 @@ void RecentEntriesTable<AISRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
const Style& style,
|
||||
RecentEntriesColumns&) {
|
||||
std::string line = ais::format::mmsi(entry.mmsi) + " ";
|
||||
if (!entry.name.empty()) {
|
||||
line += ais::format::text(entry.name);
|
||||
} else {
|
||||
line += ais::format::text(entry.call_sign);
|
||||
}
|
||||
|
||||
line.resize(target_rect.width() / 8, ' ');
|
||||
painter.draw_string(target_rect.location(), style, line);
|
||||
}
|
||||
|
||||
@@ -137,10 +137,10 @@ class AISRecentEntryDetailView : public View {
|
||||
AISRecentEntry entry_{};
|
||||
|
||||
Button button_done{
|
||||
{125, 224, 96, 24},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(6), UI_POS_Y(14), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Done"};
|
||||
Button button_see_map{
|
||||
{19, 224, 96, 24},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y(14), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"See on map"};
|
||||
GeoMapView* geomap_view{nullptr};
|
||||
bool send_updates{false};
|
||||
@@ -179,9 +179,9 @@ class AISAppView : public View {
|
||||
AISRecentEntries recent{};
|
||||
std::unique_ptr<AISLogger> logger{};
|
||||
|
||||
const RecentEntriesColumns columns{{
|
||||
RecentEntriesColumns columns{{
|
||||
{"MMSI", 9},
|
||||
{"Name/Call", 20},
|
||||
{"Name/Call", 0},
|
||||
}};
|
||||
AISRecentEntriesView recent_entries_view{columns, recent};
|
||||
AISRecentEntryDetailView recent_entry_detail_view{nav_};
|
||||
@@ -189,11 +189,11 @@ class AISAppView : public View {
|
||||
static constexpr auto header_height = 1 * 16;
|
||||
|
||||
Text label_channel{
|
||||
{0 * 8, 0 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), 2 * 8, 1 * 16},
|
||||
"Ch"};
|
||||
|
||||
OptionsField options_channel{
|
||||
{3 * 8, 0 * 16},
|
||||
{3 * 8, UI_POS_Y(0)},
|
||||
3,
|
||||
{
|
||||
{"87B", 161975000},
|
||||
@@ -201,23 +201,23 @@ class AISAppView : public View {
|
||||
}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{13 * 8, UI_POS_Y(0)}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{15 * 8, UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4},
|
||||
{UI_POS_X(21), UI_POS_Y(0), UI_POS_WIDTH_REMAINING(23), 4},
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4},
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(23), 4},
|
||||
};
|
||||
SignalToken signal_token_tick_second{};
|
||||
uint8_t timer_seconds = 0;
|
||||
|
||||
@@ -43,19 +43,19 @@ class AMOptionsView : public View {
|
||||
|
||||
private:
|
||||
Text label_config{
|
||||
{0 * 8, 0 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
"BW",
|
||||
};
|
||||
|
||||
OptionsField options_config{
|
||||
{3 * 8, 0 * 16},
|
||||
{UI_POS_X(3), UI_POS_Y(0)},
|
||||
6, // Max option length
|
||||
{
|
||||
// Using common messages from freqman_ui.cpp
|
||||
}};
|
||||
|
||||
OptionsField zoom_config{
|
||||
{23 * 8, 0 * 16},
|
||||
{UI_POS_X_RIGHT(7), UI_POS_Y(0)},
|
||||
7,
|
||||
{{"ZOOM x1", 0},
|
||||
{"ZOOM x2", 6}} // offset index AM modes array FIR filters.
|
||||
@@ -68,19 +68,19 @@ class AMFMAptOptionsView : public View {
|
||||
|
||||
private:
|
||||
Text label_config{
|
||||
{0 * 8, 0 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
"BW",
|
||||
};
|
||||
|
||||
OptionsField options_config{
|
||||
{3 * 8, 0 * 16},
|
||||
{UI_POS_X(3), UI_POS_Y(0)},
|
||||
17, // Max option length chars "USB+FM(Wefax Apt)"
|
||||
{
|
||||
// Using common messages from freqman_ui.cpp In HF USB , Here we only need USB Audio demod, + post-FM demod fsubcarrier FM tone to get APT signal.
|
||||
}};
|
||||
|
||||
OptionsField zoom_config{
|
||||
{23 * 8, 0 * 16},
|
||||
{UI_POS_X_RIGHT(7), UI_POS_Y(0)},
|
||||
7,
|
||||
{{"ZOOM x1", 0},
|
||||
{"ZOOM x2", 6}} // offset index array filters.
|
||||
@@ -93,21 +93,21 @@ class NBFMOptionsView : public View {
|
||||
|
||||
private:
|
||||
Text label_config{
|
||||
{0 * 8, 0 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
"BW",
|
||||
};
|
||||
OptionsField options_config{
|
||||
{3 * 8, 0 * 16},
|
||||
{UI_POS_X(3), UI_POS_Y(0)},
|
||||
3, // Max option length
|
||||
{
|
||||
// Using common messages from freqman_ui.cpp
|
||||
}};
|
||||
|
||||
Text text_squelch{
|
||||
{7 * 8, 0 * 16, 8 * 8, 1 * 16},
|
||||
{UI_POS_X(7), UI_POS_Y(0), UI_POS_WIDTH(8), UI_POS_HEIGHT(1)},
|
||||
"SQ /99"};
|
||||
NumberField field_squelch{
|
||||
{10 * 8, 0 * 16},
|
||||
{UI_POS_X(10), UI_POS_Y(0)},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
@@ -121,11 +121,11 @@ class WFMOptionsView : public View {
|
||||
|
||||
private:
|
||||
Text label_config{
|
||||
{0 * 8, 0 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
"BW",
|
||||
};
|
||||
OptionsField options_config{
|
||||
{3 * 8, 0 * 16},
|
||||
{UI_POS_X(3), UI_POS_Y(0)},
|
||||
4, // Max option length
|
||||
{
|
||||
// Using common messages from freqman_ui.cpp
|
||||
@@ -138,11 +138,11 @@ class WFMAMAptOptionsView : public View {
|
||||
|
||||
private:
|
||||
Text label_config{
|
||||
{0 * 8, 0 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
"BW",
|
||||
};
|
||||
OptionsField options_config{
|
||||
{3 * 8, 0 * 16},
|
||||
{UI_POS_X(3), UI_POS_Y(0)},
|
||||
16, // Max option char length "80k-NOAA Apt LPF" , example.
|
||||
{
|
||||
// Using common messages from freqman_ui.cpp
|
||||
@@ -155,11 +155,11 @@ class SPECOptionsView : public View {
|
||||
|
||||
private:
|
||||
Text label_config{
|
||||
{0 * 8, 0 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
"BW",
|
||||
};
|
||||
OptionsField options_config{
|
||||
{3 * 8, 0 * 16},
|
||||
{UI_POS_X(3), UI_POS_Y(0)},
|
||||
4,
|
||||
{
|
||||
{"20m ", 20000000},
|
||||
@@ -172,20 +172,20 @@ class SPECOptionsView : public View {
|
||||
}};
|
||||
|
||||
Text text_speed{
|
||||
{9 * 8, 0 * 16, 8 * 8, 1 * 16},
|
||||
{UI_POS_X(9), UI_POS_Y(0), UI_POS_WIDTH(8), UI_POS_HEIGHT(1)},
|
||||
"SP /63"};
|
||||
NumberField field_speed{
|
||||
{12 * 8, 0 * 16},
|
||||
{UI_POS_X(12), UI_POS_Y(0)},
|
||||
2,
|
||||
{0, 63},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
Text text_rx_cal{
|
||||
{19 * 8, 0 * 16, 11 * 8, 1 * 16}, // 18 (x col.) x char_size, 12 (length) x 8 blanking space to delete previous chars.
|
||||
{UI_POS_X(19), UI_POS_Y(0), UI_POS_WIDTH(11), UI_POS_HEIGHT(1)}, // 18 (x col.) x char_size, 12 (length) x 8 blanking space to delete previous chars.
|
||||
"Rx_IQ_CAL "};
|
||||
NumberField field_rx_iq_phase_cal{
|
||||
{screen_width - 2 * 8, 0 * 16},
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)},
|
||||
2,
|
||||
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
|
||||
1,
|
||||
@@ -244,34 +244,34 @@ class AnalogAudioView : public View {
|
||||
{"previous_zoom"sv, &previous_zoom}, // we are saving and restoring AMFM ZOOM factor from Settings.
|
||||
}};
|
||||
|
||||
const Rect options_view_rect{0 * 8, 1 * 16, screen_width, 1 * 16};
|
||||
const Rect nbfm_view_rect{0 * 8, 1 * 16, 18 * 8, 1 * 16};
|
||||
const Rect options_view_rect{UI_POS_X(0), UI_POS_Y(1), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)};
|
||||
const Rect nbfm_view_rect{UI_POS_X(0), UI_POS_Y(1), UI_POS_WIDTH(18), UI_POS_HEIGHT(1)};
|
||||
|
||||
size_t spec_bw_index = 0;
|
||||
uint32_t spec_bw = 20000000;
|
||||
uint16_t spec_trigger = 63;
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 0, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
||||
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
||||
|
||||
Audio audio{
|
||||
{21 * 8, 10, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 10, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{5 * 8, 0 * 16},
|
||||
{UI_POS_X(5), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{UI_POS_X(15), UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
|
||||
OptionsField options_modulation{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
4,
|
||||
{
|
||||
{" AM ", toUType(ReceiverModel::Mode::AMAudio)},
|
||||
@@ -283,16 +283,16 @@ class AnalogAudioView : public View {
|
||||
}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
|
||||
Text text_ctcss{
|
||||
{16 * 8, 1 * 16, 14 * 8, 1 * 16},
|
||||
{UI_POS_X(16), UI_POS_Y(1), UI_POS_WIDTH(14), UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
|
||||
std::unique_ptr<Widget> options_widget{};
|
||||
|
||||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, screen_width, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(2), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)},
|
||||
u"AUD",
|
||||
u"AUDIO",
|
||||
RecordView::FileType::WAV,
|
||||
|
||||
@@ -131,7 +131,7 @@ class BLECommView : public View {
|
||||
static constexpr auto header_height = 5 * 16;
|
||||
|
||||
OptionsField options_channel{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), 0 * 8},
|
||||
5,
|
||||
{{"Ch.37 ", 37},
|
||||
{"Ch.38", 38},
|
||||
@@ -139,17 +139,17 @@ class BLECommView : public View {
|
||||
{"Auto", 40}}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{6 * 8, 0 * 16},
|
||||
{6 * 8, UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{16 * 8, 0 * 16}};
|
||||
{16 * 8, UI_POS_Y(0)}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{21 * 8, 0 * 16}};
|
||||
{21 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RSSI rssi{
|
||||
{24 * 8, 0, 6 * 8, 4}};
|
||||
@@ -164,7 +164,7 @@ class BLECommView : public View {
|
||||
true};
|
||||
|
||||
Labels label_packets_sent{
|
||||
{{0 * 8, 4 * 8}, "Packets Left:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 4 * 8}, "Packets Left:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_packets_sent{
|
||||
{13 * 8, 2 * 16, 12 * 8, 16},
|
||||
|
||||
@@ -181,21 +181,16 @@ void RecentEntriesTable<BleRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
std::string line{};
|
||||
line.reserve(30);
|
||||
|
||||
line.reserve(40);
|
||||
if (!entry.nameString.empty() && entry.include_name) {
|
||||
line = entry.nameString;
|
||||
|
||||
if (line.length() < 17) {
|
||||
line += pad_string_with_spaces(17 - line.length());
|
||||
} else {
|
||||
line = truncate(line, 17);
|
||||
}
|
||||
} else {
|
||||
line = to_string_mac_address(entry.packetData.macAddress, 6, false);
|
||||
}
|
||||
line.resize(columns.at(0).second, ' ');
|
||||
|
||||
std::string hitsStr;
|
||||
|
||||
|
||||
@@ -155,42 +155,42 @@ class BleRecentEntryDetailView : public View {
|
||||
static constexpr uint8_t total_data_lines{5};
|
||||
|
||||
Labels label_mac_address{
|
||||
{{0 * 8, 0 * 16}, "Mac Address:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Mac Address:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_mac_address{
|
||||
{12 * 8, 0 * 16, 17 * 8, 16},
|
||||
{UI_POS_X(12), UI_POS_Y(0), UI_POS_WIDTH(17), UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Labels label_pdu_type{
|
||||
{{0 * 8, 1 * 16}, "PDU Type:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(1)}, "PDU Type:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_pdu_type{
|
||||
{9 * 8, 1 * 16, 17 * 8, 16},
|
||||
{9 * 8, UI_POS_Y(1), 17 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Labels label_vendor{
|
||||
{{0 * 8, 2 * 16}, "Vendor:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(2)}, "Vendor:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_vendor{
|
||||
{7 * 8, 2 * 16, 23 * 8, 16},
|
||||
{7 * 8, UI_POS_Y(2), 23 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 3 * 16}, "Len", Theme::getInstance()->fg_light->foreground},
|
||||
{{5 * 8, 3 * 16}, "Type", Theme::getInstance()->fg_light->foreground},
|
||||
{{10 * 8, 3 * 16}, "Value", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(3)}, "Len", Theme::getInstance()->fg_light->foreground},
|
||||
{{5 * 8, UI_POS_Y(3)}, "Type", Theme::getInstance()->fg_light->foreground},
|
||||
{{10 * 8, UI_POS_Y(3)}, "Value", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Button button_send{
|
||||
{19, 224, 96, 24},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), 224, 96, 24},
|
||||
"Send"};
|
||||
|
||||
Button button_done{
|
||||
{125, 224, 96, 24},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), 224, 96, 24},
|
||||
"Done"};
|
||||
|
||||
Button button_save{
|
||||
{72, 264, 96, 24},
|
||||
{UI_POS_X_CENTER(12), 264, 96, 24},
|
||||
"Save"};
|
||||
|
||||
bool send_updates{false};
|
||||
@@ -294,7 +294,7 @@ class BLERxView : public View {
|
||||
static constexpr auto switch_button_height = 3 * 16;
|
||||
|
||||
OptionsField options_channel{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
5,
|
||||
{{"Ch.37", 37},
|
||||
{"Ch.38", 38},
|
||||
@@ -302,29 +302,29 @@ class BLERxView : public View {
|
||||
{"Auto", 40}}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{6 * 8, 0 * 16},
|
||||
{UI_POS_X(6), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{16 * 8, 0 * 16}};
|
||||
{UI_POS_X(16), UI_POS_Y(0)}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{18 * 8, 0 * 16}};
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{21 * 8, 0 * 16}};
|
||||
{UI_POS_X(21), UI_POS_Y(0)}};
|
||||
|
||||
RSSI rssi{
|
||||
{24 * 8, 0, 6 * 8, 4}};
|
||||
{UI_POS_X(24), 0, UI_POS_WIDTH_REMAINING(6), 4}};
|
||||
|
||||
Channel channel{
|
||||
{24 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(24), 5, UI_POS_WIDTH_REMAINING(6), 4}};
|
||||
|
||||
Labels label_sort{
|
||||
{{0 * 8, 2 * 8}, "Sort:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(1)}, "Sort:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_sort{
|
||||
{5 * 8, 2 * 8},
|
||||
{5 * 8, UI_POS_Y(1)},
|
||||
4,
|
||||
{{"MAC", 0},
|
||||
{"Hits", 1},
|
||||
@@ -334,11 +334,11 @@ class BLERxView : public View {
|
||||
{"Info", 5}}};
|
||||
|
||||
Button button_filter{
|
||||
{11 * 8, 2 * 8, 7 * 8, 16},
|
||||
{11 * 8, UI_POS_Y(1), 7 * 8, 16},
|
||||
"Filter:"};
|
||||
|
||||
OptionsField options_filter{
|
||||
{18 * 8 + 2, 2 * 8},
|
||||
{18 * 8 + 2, UI_POS_Y(1)},
|
||||
7,
|
||||
{{"Data", 0},
|
||||
{"MAC", 1},
|
||||
@@ -354,7 +354,7 @@ class BLERxView : public View {
|
||||
true};
|
||||
|
||||
Checkbox check_name{
|
||||
{0 * 8, 4 * 8 + 2},
|
||||
{UI_POS_X(0), 4 * 8 + 2},
|
||||
3,
|
||||
"Name",
|
||||
true};
|
||||
@@ -378,7 +378,7 @@ class BLERxView : public View {
|
||||
true};
|
||||
|
||||
Button button_find{
|
||||
{0 * 8, 10 * 8 - 2, 4 * 8, 16},
|
||||
{UI_POS_X(0), 10 * 8 - 2, 4 * 8, 16},
|
||||
"Find"};
|
||||
|
||||
Labels label_found{
|
||||
@@ -389,15 +389,15 @@ class BLERxView : public View {
|
||||
"0/0"};
|
||||
|
||||
Button button_clear_list{
|
||||
{2 * 8, 320 - (16 + 32), 7 * 8, 32},
|
||||
{2 * 8, screen_height - (16 + 32), 7 * 8, 32},
|
||||
"Clear"};
|
||||
|
||||
Button button_save_list{
|
||||
{11 * 8, 320 - (16 + 32), 11 * 8, 32},
|
||||
{UI_POS_X_CENTER(11), screen_height - (16 + 32), 11 * 8, 32},
|
||||
"Export CSV"};
|
||||
|
||||
Button button_switch{
|
||||
{240 - 6 * 8, 320 - (16 + 32), 4 * 8, 32},
|
||||
{UI_POS_X_RIGHT(6), screen_height - (16 + 32), 4 * 8, 32},
|
||||
"Tx"};
|
||||
|
||||
std::string str_log{""};
|
||||
@@ -407,7 +407,7 @@ class BLERxView : public View {
|
||||
BleRecentEntries tempList{};
|
||||
|
||||
RecentEntriesColumns columns{{
|
||||
{"Name", 17},
|
||||
{"Name", 0},
|
||||
{"Hits", 7},
|
||||
{"dBm", 4},
|
||||
}};
|
||||
|
||||
@@ -190,24 +190,24 @@ class BLETxView : public View {
|
||||
static constexpr auto switch_button_height = 6 * 16;
|
||||
|
||||
Button button_open{
|
||||
{0 * 8, 0 * 16, 10 * 8, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), 10 * 8, 2 * 16},
|
||||
"Open file"};
|
||||
|
||||
Text text_filename{
|
||||
{11 * 8, 0 * 16, 12 * 8, 16},
|
||||
{11 * 8, UI_POS_Y(0), UI_POS_WIDTH_REMAINING(11), 16},
|
||||
"-"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{11 * 8, 1 * 16, 9 * 8, 16}};
|
||||
{11 * 8, 1 * 16, UI_POS_WIDTH_REMAINING(11 + 10), 16}};
|
||||
|
||||
Checkbox check_rand_mac{
|
||||
{21 * 8, 1 * 16},
|
||||
{UI_POS_X_RIGHT(9), 1 * 16},
|
||||
6,
|
||||
"?? Mac",
|
||||
true};
|
||||
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, 2 * 16},
|
||||
{UI_POS_X(0), 2 * 16},
|
||||
nav_};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
@@ -215,19 +215,19 @@ class BLETxView : public View {
|
||||
/*short_ui*/ true};
|
||||
|
||||
Checkbox check_loop{
|
||||
{21 * 8, 2 * 16},
|
||||
{UI_POS_X_RIGHT(9), 2 * 16},
|
||||
4,
|
||||
"Loop",
|
||||
true};
|
||||
|
||||
ImageButton button_play{
|
||||
{28 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X_RIGHT(2), 2 * 16, 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
Labels label_speed{
|
||||
{{0 * 8, 6 * 8}, "Speed:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 6 * 8}, "Speed:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_speed{
|
||||
{7 * 8, 6 * 8},
|
||||
@@ -259,7 +259,7 @@ class BLETxView : public View {
|
||||
{"CONNECT_REQ", PKT_TYPE_CONNECT_REQ}}};
|
||||
|
||||
Labels label_marked_data{
|
||||
{{0 * 8, 4 * 16}, "Marked Data:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 4 * 16}, "Marked Data:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField marked_data_sequence{
|
||||
{12 * 8, 8 * 8},
|
||||
@@ -269,42 +269,42 @@ class BLETxView : public View {
|
||||
{"Random", 2}}};
|
||||
|
||||
Labels label_packet_index{
|
||||
{{0 * 8, 12 * 8}, "Packet Index:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 12 * 8}, "Packet Index:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_packet_index{
|
||||
{13 * 8, 6 * 16, 12 * 8, 16},
|
||||
"-"};
|
||||
|
||||
Labels label_packets_sent{
|
||||
{{0 * 8, 14 * 8}, "Repeat Count:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 14 * 8}, "Repeat Count:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_packets_sent{
|
||||
{13 * 8, 7 * 16, 12 * 8, 16},
|
||||
"-"};
|
||||
|
||||
Labels label_mac_address{
|
||||
{{0 * 8, 16 * 8}, "Mac Address:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 16 * 8}, "Mac Address:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_mac_address{
|
||||
{12 * 8, 8 * 16, 20 * 8, 16},
|
||||
"-"};
|
||||
|
||||
Labels label_data_packet{
|
||||
{{0 * 8, 9 * 16}, "Packet Data:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 9 * 16}, "Packet Data:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
TextViewer dataEditView{
|
||||
{0, 9 * 18, 240, 240}};
|
||||
|
||||
Button button_clear_marked{
|
||||
{1 * 8, 14 * 16, 13 * 8, 3 * 8},
|
||||
{UI_POS_X(1), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(13), UI_POS_HEIGHT(1.5)},
|
||||
"Clear Marked"};
|
||||
|
||||
Button button_save_packet{
|
||||
{1 * 8, 16 * 16, 13 * 8, 2 * 16},
|
||||
{UI_POS_X(1), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(13), UI_POS_HEIGHT(2)},
|
||||
"Save Packet"};
|
||||
|
||||
Button button_switch{
|
||||
{16 * 8, 16 * 16, 13 * 8, 2 * 16},
|
||||
{UI_POS_X_RIGHT(14), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(13), UI_POS_HEIGHT(2)},
|
||||
"Switch to Rx"};
|
||||
|
||||
std::string str_log{""};
|
||||
|
||||
@@ -65,31 +65,31 @@ class CaptureAppView : public View {
|
||||
}};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Rate:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "Rate:", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 1 * 16}, "Format:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
RSSI rssi{
|
||||
{24 * 8, 0, 6 * 8, 4}};
|
||||
{UI_POS_X(24), 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
|
||||
Channel channel{
|
||||
{24 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(24), 5, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
FrequencyStepView field_frequency_step{
|
||||
{10 * 8, 0 * 16}};
|
||||
{10 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{16 * 8, 0 * 16}};
|
||||
{16 * 8, UI_POS_Y(0)}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{21 * 8, 0 * 16}};
|
||||
{21 * 8, UI_POS_Y(0)}};
|
||||
|
||||
OptionsField option_bandwidth{
|
||||
{5 * 8, 1 * 16},
|
||||
@@ -109,7 +109,7 @@ class CaptureAppView : public View {
|
||||
/*small*/ true};
|
||||
|
||||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, screen_width, 1 * 16},
|
||||
{UI_POS_X(0), 2 * 16, screen_width, 1 * 16},
|
||||
u"BBD_????.*",
|
||||
captures_dir,
|
||||
RecordView::FileType::RawS16,
|
||||
|
||||
@@ -183,7 +183,7 @@ class POCSAGSettingsView : public View {
|
||||
true /*explicit_edit*/};
|
||||
|
||||
Button button_save{
|
||||
{11 * 8, 16 * 16, 10 * 8, 2 * 16},
|
||||
{UI_POS_X_CENTER(10), UI_POS_Y(16), 10 * 8, 2 * 16},
|
||||
"Save"};
|
||||
};
|
||||
|
||||
@@ -236,30 +236,30 @@ class POCSAGAppView : public View {
|
||||
uint16_t packet_count = 0;
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), 0 * 8},
|
||||
nav_};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{11 * 8, 0 * 16}};
|
||||
{11 * 8, UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{
|
||||
{13 * 8, 0 * 16}};
|
||||
{13 * 8, UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{
|
||||
{16 * 8, 0 * 16}};
|
||||
{16 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RSSI rssi{
|
||||
{19 * 8 - 4, 3, 6 * 8, 4}};
|
||||
{19 * 8 - 4, 3, UI_POS_WIDTH_REMAINING(26), 4}};
|
||||
Audio audio{
|
||||
{19 * 8 - 4, 8, 6 * 8, 4}};
|
||||
{19 * 8 - 4, 8, UI_POS_WIDTH_REMAINING(26), 4}};
|
||||
|
||||
NumberField field_squelch{
|
||||
{25 * 8, 0 * 16},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(0)},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
' ',
|
||||
true /*wrap*/};
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
Image image_status{
|
||||
{0 * 8 + 4, 1 * 16 + 2, 16, 16},
|
||||
|
||||
@@ -51,7 +51,8 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
Color target_color;
|
||||
std::string entry_string;
|
||||
|
||||
@@ -70,9 +71,11 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
||||
target_color = Theme::getInstance()->fg_medium->foreground;
|
||||
};
|
||||
|
||||
entry_string +=
|
||||
(entry.callsign.empty() ? entry.icao_str + " " : entry.callsign + " ") +
|
||||
to_string_dec_uint((unsigned int)(entry.pos.altitude / 100), 4);
|
||||
std::string ipc = (entry.callsign.empty() ? entry.icao_str + " " : entry.callsign + " ");
|
||||
uint8_t firstcolwidth = columns.at(0).second;
|
||||
ipc.resize(firstcolwidth, ' '); // Make sure this is always match the first column's width that is dynamic.
|
||||
|
||||
entry_string += ipc + to_string_dec_uint((unsigned int)(entry.pos.altitude / 100), 4);
|
||||
|
||||
if (entry.velo.type == SPD_IAS && entry.pos.alt_valid) { // IAS can be converted to TAS
|
||||
// It is generally accepted that for every thousand feet of altitude,
|
||||
@@ -100,7 +103,7 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
||||
entry_string);
|
||||
|
||||
if (entry.pos.pos_valid)
|
||||
painter.draw_bitmap(target_rect.location() + Point(8 * 8, 0),
|
||||
painter.draw_bitmap(target_rect.location() + Point(firstcolwidth * 8 - 8, 0),
|
||||
bitmap_target, target_color, style.background);
|
||||
}
|
||||
|
||||
@@ -409,7 +412,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
|
||||
&status_good_frame,
|
||||
&field_volume});
|
||||
|
||||
recent_entries_view.set_parent_rect({0, 16, screen_width, 272});
|
||||
recent_entries_view.set_parent_rect({0, 16, screen_width, UI_POS_HEIGHT_REMAINING(2)});
|
||||
recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) {
|
||||
detail_key = entry.key();
|
||||
details_view = nav.push<ADSBRxDetailsView>(entry);
|
||||
|
||||
@@ -208,54 +208,54 @@ class ADSBRxAircraftDetailsView : public View {
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "ICAO:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Registration:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Manufacturer:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Model:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 8 * 16}, "Number of engines:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 9 * 16}, "Engine type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 11 * 16}, "Owner:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 13 * 16}, "Operator:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 1 * 16}, "ICAO:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 2 * 16}, "Registration:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Manufacturer:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 5 * 16}, "Model:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 8 * 16}, "Number of engines:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 9 * 16}, "Engine type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 11 * 16}, "Owner:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 13 * 16}, "Operator:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_icao_address{
|
||||
{5 * 8, 1 * 16, 6 * 8, 16},
|
||||
{5 * 8, 1 * 16, 6 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_registration{
|
||||
{13 * 8, 2 * 16, 8 * 8, 16},
|
||||
{13 * 8, 2 * 16, 8 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_manufacturer{
|
||||
{0 * 8, 4 * 16, 19 * 8, 16},
|
||||
{UI_POS_X(0), 4 * 16, 19 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_model{
|
||||
{0 * 8, 6 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 6 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_type{
|
||||
{5 * 8, 7 * 16, 22 * 8, 16},
|
||||
{5 * 8, 7 * 16, 22 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_number_of_engines{
|
||||
{18 * 8, 8 * 16, screen_width, 16},
|
||||
{18 * 8, 8 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_engine_type{
|
||||
{0 * 8, 10 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 10 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_owner{
|
||||
{0 * 8, 12 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 12 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_operator{
|
||||
{0 * 8, 14 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 14 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Button button_close{
|
||||
{9 * 8, 16 * 16, 12 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(12), UI_POS_Y(16), UI_POS_WIDTH(12), UI_POS_HEIGHT(3)},
|
||||
"Back"};
|
||||
};
|
||||
|
||||
@@ -299,55 +299,55 @@ class ADSBRxDetailsView : public View {
|
||||
bool airline_checked{false};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "ICAO:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "ICAO:", Theme::getInstance()->fg_light->foreground},
|
||||
{{13 * 8, 1 * 16}, "Callsign:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Last seen:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Airline:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Country:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 13 * 16}, "Even position frame:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 15 * 16}, "Odd position frame:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 2 * 16}, "Last seen:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Airline:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 5 * 16}, "Country:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 13 * 16}, "Even position frame:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 15 * 16}, "Odd position frame:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_icao_address{
|
||||
{5 * 8, 1 * 16, 6 * 8, 16},
|
||||
{5 * 8, 1 * 16, 6 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_callsign{
|
||||
{22 * 8, 1 * 16, 8 * 8, 16},
|
||||
{22 * 8, 1 * 16, 8 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_last_seen{
|
||||
{11 * 8, 2 * 16, 19 * 8, 16},
|
||||
{11 * 8, 2 * 16, 19 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_airline{
|
||||
{0 * 8, 4 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 4 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_country{
|
||||
{8 * 8, 5 * 16, 22 * 8, 16},
|
||||
{8 * 8, 5 * 16, 22 * 8, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_infos{
|
||||
{0 * 8, 6 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 6 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_info2{
|
||||
{0 * 8, 7 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 7 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Text text_frame_pos_even{
|
||||
{0 * 8, 14 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 14 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
Text text_frame_pos_odd{
|
||||
{0 * 8, 16 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 16 * 16, screen_width, UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Button button_aircraft_details{
|
||||
{2 * 8, 9 * 16, 12 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_X(8), UI_POS_Y(9), UI_POS_WIDTH(12), UI_POS_HEIGHT(3)},
|
||||
"A/C details"};
|
||||
|
||||
Button button_see_map{
|
||||
{16 * 8, 9 * 16, 12 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_X(8), UI_POS_Y(9), UI_POS_WIDTH(12), UI_POS_HEIGHT(3)},
|
||||
"See on map"};
|
||||
|
||||
MessageHandlerRegistration message_handler_gps{
|
||||
@@ -403,8 +403,8 @@ class ADSBRxView : public View {
|
||||
static constexpr uint8_t max_update_entries = 16;
|
||||
|
||||
/* Recent Entries */
|
||||
const RecentEntriesColumns columns{
|
||||
{{"ICAO/Call", 9},
|
||||
RecentEntriesColumns columns{
|
||||
{{"ICAO/Call", 0},
|
||||
{"Lvl", 3},
|
||||
{"Spd", 3},
|
||||
{"Amp", 3},
|
||||
@@ -424,33 +424,33 @@ class ADSBRxView : public View {
|
||||
ADSBRxDetailsView* details_view{nullptr};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 8}, "LNA: VGA: AMP:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "LNA: VGA: AMP:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{4 * 8, 0 * 16}};
|
||||
{UI_POS_X(4), UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{11 * 8, 0 * 16}};
|
||||
{UI_POS_X(11), UI_POS_Y(0)}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{18 * 8, 0 * 16}};
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
|
||||
RSSI rssi{
|
||||
{20 * 8, 4, 7 * 8, 8},
|
||||
{UI_POS_X(20), 4, UI_POS_WIDTH_REMAINING(23), 8},
|
||||
};
|
||||
|
||||
ActivityDot status_frame{
|
||||
{27 * 8 + 2, 5, 2, 2},
|
||||
{UI_POS_X_RIGHT(3) + 2, 5, 2, 2},
|
||||
Theme::getInstance()->bg_darkest->foreground,
|
||||
};
|
||||
|
||||
ActivityDot status_good_frame{
|
||||
{27 * 8 + 2, 9, 2, 2},
|
||||
{UI_POS_X_RIGHT(3) + 2, 9, 2, 2},
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame{
|
||||
Message::ID::ADSBFrame,
|
||||
|
||||
@@ -42,7 +42,8 @@ void RecentEntriesTable<APRSRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
Color target_color;
|
||||
// auto entry_age = entry.age;
|
||||
|
||||
@@ -51,8 +52,8 @@ void RecentEntriesTable<APRSRecentEntries>::draw(
|
||||
std::string entry_string = "";
|
||||
|
||||
entry_string += entry.source_formatted;
|
||||
entry_string.append(10 - entry.source_formatted.size(), ' ');
|
||||
entry_string += " ";
|
||||
entry_string.resize(columns.at(0).second, ' ');
|
||||
entry_string += " ";
|
||||
entry_string += (entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+");
|
||||
entry_string += " ";
|
||||
entry_string += entry.time_string;
|
||||
|
||||
@@ -134,14 +134,14 @@ class APRSDetailsView : public View {
|
||||
bool send_updates{false};
|
||||
|
||||
Console console{
|
||||
{0, 0 * 16, screen_width, 224}};
|
||||
{UI_POS_X(0), UI_POS_Y(0), screen_width, screen_height - 80}};
|
||||
|
||||
Button button_done{
|
||||
{160, 14 * 16, 8 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(4) - UI_POS_WIDTH(8), UI_POS_Y(14), UI_POS_WIDTH(8), UI_POS_HEIGHT(3)},
|
||||
"Close"};
|
||||
|
||||
Button button_see_map{
|
||||
{80, 14 * 16, 8 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(4) + UI_POS_WIDTH(8), UI_POS_Y(14), UI_POS_WIDTH(8), UI_POS_HEIGHT(3)},
|
||||
"Map"};
|
||||
};
|
||||
|
||||
@@ -161,10 +161,10 @@ class APRSTableView : public View {
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
const RecentEntriesColumns columns{{{"Source", 9},
|
||||
{"Loc", 6},
|
||||
{"Hits", 4},
|
||||
{"Time", 8}}};
|
||||
RecentEntriesColumns columns{{{"Source", 0},
|
||||
{"Loc", 6},
|
||||
{"Hits", 4},
|
||||
{"Time", 8}}};
|
||||
APRSRecentEntries recent{};
|
||||
RecentEntriesView<RecentEntries<APRSRecentEntry>> recent_entries_view{columns, recent};
|
||||
APRSDetailsView details_view{nav_};
|
||||
@@ -209,21 +209,21 @@ class APRSRxView : public View {
|
||||
std::string str_log{""};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{UI_POS_X(13), UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{UI_POS_X(15), UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 0, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
OptionsField options_region{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
3,
|
||||
{{"MAN", 0},
|
||||
{"NA ", 1},
|
||||
@@ -237,11 +237,11 @@ class APRSRxView : public View {
|
||||
{"ISS", 9}}};
|
||||
|
||||
FrequencyField field_frequency{
|
||||
{3 * 8, 0 * 16}};
|
||||
{UI_POS_X(3), UI_POS_Y(0)}};
|
||||
|
||||
// DEBUG
|
||||
RecordView record_view{
|
||||
{0 * 8, 1 * 16, screen_width, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(1), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)},
|
||||
u"AFS_????.WAV",
|
||||
aprs_dir,
|
||||
RecordView::FileType::WAV,
|
||||
@@ -249,7 +249,7 @@ class APRSRxView : public View {
|
||||
4};
|
||||
|
||||
Console console{
|
||||
{0, 2 * 16, screen_width, screen_height - 80}};
|
||||
{UI_POS_X(0), UI_POS_Y(2), UI_POS_MAXWIDTH, screen_height - 80}};
|
||||
|
||||
std::unique_ptr<APRSLogger> logger{};
|
||||
};
|
||||
@@ -265,7 +265,7 @@ class APRSRXView : public View {
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
Rect view_rect = {0, 3 * 8, screen_width, screen_height - 40};
|
||||
Rect view_rect = {UI_POS_X(0), 3 * 8, UI_POS_MAXWIDTH, screen_height - 40};
|
||||
|
||||
APRSRxView view_stream{nav_, view_rect};
|
||||
APRSTableView view_table{nav_, view_rect};
|
||||
|
||||
@@ -61,9 +61,9 @@ class APRSTXView : public View {
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Source: SSID:", Theme::getInstance()->fg_light->foreground}, // 6 alphanum + SSID
|
||||
{{0 * 8, 2 * 16}, " Dest.: SSID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "Info field:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "Source: SSID:", Theme::getInstance()->fg_light->foreground}, // 6 alphanum + SSID
|
||||
{{UI_POS_X(0), 2 * 16}, " Dest.: SSID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 4 * 16}, "Info field:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
SymField sym_source{
|
||||
@@ -91,14 +91,14 @@ class APRSTXView : public View {
|
||||
' '};
|
||||
|
||||
Text text_payload{
|
||||
{0 * 8, 5 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 5 * 16, screen_width, 16},
|
||||
"-"};
|
||||
Button button_set{
|
||||
{0 * 8, 6 * 16, 80, 32},
|
||||
{UI_POS_X(0), 6 * 16, 80, 32},
|
||||
"Set"};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
5000,
|
||||
0 // disable setting bandwith, since APRS used fixed 10k bandwidth
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ class BattinfoView : public View {
|
||||
"Volt"};
|
||||
|
||||
Button button_exit{
|
||||
{72, 17 * 16, 96, 32},
|
||||
{UI_POS_X_CENTER(12), 17 * 16, UI_POS_WIDTH(12), UI_POS_HEIGHT(3)},
|
||||
"Back"};
|
||||
static msg_t static_fn(void* arg);
|
||||
Thread* thread{nullptr};
|
||||
|
||||
@@ -1,342 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_bht_tx.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void BHTView::focus() {
|
||||
tx_view.focus();
|
||||
}
|
||||
|
||||
void BHTView::start_tx() {
|
||||
baseband::shutdown();
|
||||
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
|
||||
if (target_system == XYLOS) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
|
||||
view_xylos.generate_message();
|
||||
|
||||
// if (tx_mode == SINGLE) {
|
||||
progressbar.set_max(XY_TONE_COUNT);
|
||||
/*} else if (tx_mode == SCAN) {
|
||||
progressbar.set_max(XY_TONE_COUNT * view_xylos.get_scan_remaining());
|
||||
}*/
|
||||
|
||||
transmitter_model.set_sampling_rate(TONES_SAMPLERATE);
|
||||
transmitter_model.enable();
|
||||
|
||||
// Setup tones
|
||||
for (size_t c = 0; c < ccir_deltas.size(); c++)
|
||||
baseband::set_tone(c, ccir_deltas[c], XY_TONE_DURATION);
|
||||
|
||||
baseband::set_tones_config(transmitter_model.channel_bandwidth(), XY_SILENCE, XY_TONE_COUNT, false, false);
|
||||
|
||||
} else if (target_system == EPAR) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_ook);
|
||||
|
||||
auto bitstream_length = view_EPAR.generate_message();
|
||||
|
||||
// if (tx_mode == SINGLE) {
|
||||
progressbar.set_max(2 * EPAR_REPEAT_COUNT);
|
||||
/*} else if (tx_mode == SCAN) {
|
||||
progressbar.set_max(2 * EPAR_REPEAT_COUNT * view_EPAR.get_scan_remaining());
|
||||
}*/
|
||||
|
||||
transmitter_model.set_sampling_rate(OOK_SAMPLERATE);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_ook_data(
|
||||
bitstream_length,
|
||||
EPAR_BIT_DURATION,
|
||||
EPAR_REPEAT_COUNT,
|
||||
encoder_defs[ENCODER_UM3750].pause_symbols);
|
||||
}
|
||||
}
|
||||
|
||||
void BHTView::stop_tx() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
tx_mode = IDLE;
|
||||
tx_view.set_transmitting(false);
|
||||
progressbar.set_value(0);
|
||||
}
|
||||
|
||||
void BHTView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
if (target_system == XYLOS) {
|
||||
if (done) {
|
||||
if (tx_mode == SINGLE) {
|
||||
if (checkbox_flashing.value()) {
|
||||
// TODO: Thread !
|
||||
chThdSleepMilliseconds(field_speed.value() * 1000); // Dirty :(
|
||||
view_xylos.flip_relays();
|
||||
start_tx();
|
||||
} else
|
||||
stop_tx();
|
||||
} else if (tx_mode == SCAN) {
|
||||
if (view_xylos.increment_address())
|
||||
start_tx();
|
||||
else
|
||||
stop_tx(); // Reached end of scan range
|
||||
}
|
||||
} else
|
||||
progressbar.set_value(progress);
|
||||
} else if (target_system == EPAR) {
|
||||
if (done) {
|
||||
if (!view_EPAR.half) {
|
||||
view_EPAR.half = true;
|
||||
start_tx(); // Start second half of transmission
|
||||
} else {
|
||||
view_EPAR.half = false;
|
||||
if (tx_mode == SINGLE) {
|
||||
if (checkbox_flashing.value()) {
|
||||
// TODO: Thread !
|
||||
chThdSleepMilliseconds(field_speed.value() * 1000); // Dirty :(
|
||||
view_EPAR.flip_relays();
|
||||
start_tx();
|
||||
} else
|
||||
stop_tx();
|
||||
} else if (tx_mode == SCAN) {
|
||||
if (view_EPAR.increment_address())
|
||||
start_tx();
|
||||
else
|
||||
stop_tx(); // Reached end of scan range
|
||||
}
|
||||
}
|
||||
} else
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
}
|
||||
|
||||
BHTView::~BHTView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
BHTView::BHTView(NavigationView& nav) {
|
||||
add_children({&tab_view,
|
||||
&labels,
|
||||
&view_xylos,
|
||||
&view_EPAR,
|
||||
&checkbox_scan,
|
||||
&checkbox_flashing,
|
||||
&field_speed,
|
||||
&progressbar,
|
||||
&tx_view});
|
||||
|
||||
field_speed.set_value(1);
|
||||
|
||||
tx_view.on_edit_frequency = [this, &nav]() {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
transmitter_model.set_target_frequency(f);
|
||||
};
|
||||
};
|
||||
|
||||
tx_view.on_start = [this]() {
|
||||
if (tx_mode == IDLE) {
|
||||
if (checkbox_scan.value()) {
|
||||
tx_mode = SCAN;
|
||||
} else {
|
||||
tx_mode = SINGLE;
|
||||
}
|
||||
|
||||
progressbar.set_value(0);
|
||||
tx_view.set_transmitting(true);
|
||||
target_system = (target_system_t)tab_view.selected();
|
||||
view_EPAR.half = false;
|
||||
|
||||
start_tx();
|
||||
}
|
||||
};
|
||||
|
||||
tx_view.on_stop = [this]() {
|
||||
stop_tx();
|
||||
};
|
||||
}
|
||||
|
||||
bool EPARView::increment_address() {
|
||||
auto city_code = field_city.value();
|
||||
|
||||
if (city_code < EPAR_MAX_CITY) {
|
||||
field_city.set_value(city_code + 1);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t EPARView::get_scan_remaining() {
|
||||
return EPAR_MAX_CITY - field_city.value();
|
||||
}
|
||||
|
||||
void EPARView::flip_relays() {
|
||||
// Invert first relay's state
|
||||
relay_states[0].set_selected_index(relay_states[0].selected_index() ^ 1);
|
||||
}
|
||||
|
||||
size_t EPARView::generate_message() {
|
||||
// R2, then R1
|
||||
return gen_message_ep(field_city.value(), field_group.selected_index_value(),
|
||||
half ? 0 : 1, relay_states[half].selected_index());
|
||||
}
|
||||
|
||||
EPARView::EPARView(
|
||||
Rect parent_rect)
|
||||
: View(parent_rect) {
|
||||
hidden(true);
|
||||
|
||||
add_children({&labels,
|
||||
&field_city,
|
||||
&field_group});
|
||||
|
||||
field_city.set_value(0);
|
||||
field_group.set_selected_index(2);
|
||||
field_city.on_change = [this](int32_t) { generate_message(); };
|
||||
field_group.on_change = [this](size_t, int32_t) { generate_message(); };
|
||||
|
||||
const auto relay_state_fn = [this](size_t, OptionsField::value_t) {
|
||||
generate_message();
|
||||
};
|
||||
|
||||
size_t n = 0;
|
||||
for (auto& relay_state : relay_states) {
|
||||
relay_state.set_parent_rect({static_cast<Coord>(90 + (n * 36)),
|
||||
80,
|
||||
24, 24});
|
||||
relay_state.set_options(relay_options);
|
||||
relay_state.on_change = relay_state_fn; // NB: set after set_options to avoid startup call.
|
||||
add_child(&relay_state);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
void EPARView::focus() {
|
||||
field_city.focus();
|
||||
}
|
||||
|
||||
void XylosView::flip_relays() {
|
||||
// Invert first relay's state if not ignored
|
||||
size_t rs = relay_states[0].selected_index();
|
||||
|
||||
if (rs > 0)
|
||||
relay_states[0].set_selected_index(rs ^ 3);
|
||||
}
|
||||
|
||||
bool XylosView::increment_address() {
|
||||
auto city_code = field_city.value();
|
||||
|
||||
if (city_code < XY_MAX_CITY) {
|
||||
field_city.set_value(city_code + 1);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t XylosView::get_scan_remaining() {
|
||||
return XY_MAX_CITY - field_city.value();
|
||||
}
|
||||
|
||||
void XylosView::generate_message() {
|
||||
gen_message_xy(field_header_a.value(), field_header_b.value(), field_city.value(), field_family.value(),
|
||||
checkbox_wcsubfamily.value(), field_subfamily.value(), checkbox_wcid.value(), field_receiver.value(),
|
||||
relay_states[0].selected_index(), relay_states[1].selected_index(),
|
||||
relay_states[2].selected_index(), relay_states[3].selected_index());
|
||||
}
|
||||
|
||||
XylosView::XylosView(
|
||||
Rect parent_rect)
|
||||
: View(parent_rect) {
|
||||
hidden(true);
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&field_header_a,
|
||||
&field_header_b,
|
||||
&field_city,
|
||||
&field_family,
|
||||
&field_subfamily,
|
||||
&checkbox_wcsubfamily,
|
||||
&field_receiver,
|
||||
&checkbox_wcid,
|
||||
//&button_seq,
|
||||
});
|
||||
|
||||
field_header_a.set_value(0);
|
||||
field_header_b.set_value(0);
|
||||
field_city.set_value(10);
|
||||
field_family.set_value(1);
|
||||
field_subfamily.set_value(1);
|
||||
field_receiver.set_value(1);
|
||||
|
||||
const auto field_fn = [this](int32_t) {
|
||||
generate_message();
|
||||
};
|
||||
|
||||
field_header_a.on_change = field_fn;
|
||||
field_header_b.on_change = field_fn;
|
||||
field_city.on_change = field_fn;
|
||||
field_family.on_change = field_fn;
|
||||
field_subfamily.on_change = field_fn;
|
||||
field_receiver.on_change = field_fn;
|
||||
|
||||
checkbox_wcsubfamily.on_select = [this](Checkbox&, bool v) {
|
||||
field_subfamily.set_focusable(!v);
|
||||
generate_message();
|
||||
};
|
||||
|
||||
checkbox_wcid.on_select = [this](Checkbox&, bool v) {
|
||||
field_receiver.set_focusable(!v);
|
||||
generate_message();
|
||||
};
|
||||
|
||||
checkbox_wcsubfamily.set_value(true);
|
||||
checkbox_wcid.set_value(true);
|
||||
|
||||
const auto relay_state_fn = [this](size_t, OptionsField::value_t) {
|
||||
generate_message();
|
||||
};
|
||||
|
||||
size_t n = 0;
|
||||
for (auto& relay_state : relay_states) {
|
||||
relay_state.set_parent_rect({static_cast<Coord>(54 + (n * 36)),
|
||||
134,
|
||||
24, 24});
|
||||
relay_state.set_options(relay_options);
|
||||
relay_state.on_change = relay_state_fn; // NB: set after set_options to avoid startup call.
|
||||
add_child(&relay_state);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
void XylosView::focus() {
|
||||
field_city.focus();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_tabview.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_transmitter.hpp"
|
||||
|
||||
#include "bht.hpp"
|
||||
#include "bitmap.hpp"
|
||||
#include "message.hpp"
|
||||
#include "transmitter_model.hpp"
|
||||
#include "encoders.hpp"
|
||||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class XylosView : public View {
|
||||
public:
|
||||
XylosView(Rect parent_rect);
|
||||
|
||||
void focus() override;
|
||||
|
||||
void flip_relays();
|
||||
void generate_message();
|
||||
bool increment_address();
|
||||
uint32_t get_scan_remaining();
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{8 * 8, 1 * 8}, "Header:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 3 * 8}, "City code:", Theme::getInstance()->fg_light->foreground},
|
||||
{{7 * 8, 5 * 8}, "Family:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 7 * 8 + 2}, "Subfamily:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 11 * 8}, "Receiver ID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 14 * 8}, "Relay:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
NumberField field_header_a{
|
||||
{16 * 8, 1 * 8},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
'0'};
|
||||
NumberField field_header_b{
|
||||
{18 * 8, 1 * 8},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
'0'};
|
||||
|
||||
NumberField field_city{
|
||||
{16 * 8, 3 * 8},
|
||||
2,
|
||||
{0, XY_MAX_CITY},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_family{
|
||||
{16 * 8, 5 * 8},
|
||||
1,
|
||||
{0, 9},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_subfamily{
|
||||
{16 * 8, 7 * 8 + 2},
|
||||
1,
|
||||
{0, 9},
|
||||
1,
|
||||
' '};
|
||||
|
||||
Checkbox checkbox_wcsubfamily{
|
||||
{20 * 8, 6 * 8 + 6},
|
||||
3,
|
||||
"All"};
|
||||
|
||||
NumberField field_receiver{
|
||||
{16 * 8, 11 * 8},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
'0'};
|
||||
Checkbox checkbox_wcid{
|
||||
{20 * 8, 10 * 8 + 4},
|
||||
3,
|
||||
"All"};
|
||||
|
||||
std::array<ImageOptionsField, 4> relay_states{};
|
||||
|
||||
ImageOptionsField::options_t relay_options = {
|
||||
{&bitmap_bulb_ignore, 0},
|
||||
{&bitmap_bulb_off, 1},
|
||||
{&bitmap_bulb_on, 2}};
|
||||
};
|
||||
|
||||
class EPARView : public View {
|
||||
public:
|
||||
EPARView(Rect parent_rect);
|
||||
|
||||
void focus() override;
|
||||
|
||||
void flip_relays();
|
||||
size_t generate_message();
|
||||
bool increment_address();
|
||||
uint32_t get_scan_remaining();
|
||||
|
||||
bool half{false};
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{4 * 8, 1 * 8}, "City code:", Theme::getInstance()->fg_light->foreground},
|
||||
{{8 * 8, 3 * 8}, "Group:", Theme::getInstance()->fg_light->foreground},
|
||||
{{8 * 8, 7 * 8}, "Relay:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
NumberField field_city{
|
||||
{16 * 8, 1 * 8},
|
||||
3,
|
||||
{0, EPAR_MAX_CITY},
|
||||
1,
|
||||
'0'};
|
||||
|
||||
OptionsField field_group{
|
||||
{16 * 8, 3 * 8},
|
||||
2,
|
||||
{{"A ", 2}, // See receiver PCB
|
||||
{"B ", 1},
|
||||
{"C ", 0},
|
||||
{"TP", 3}}};
|
||||
|
||||
std::array<ImageOptionsField, 2> relay_states{};
|
||||
|
||||
ImageOptionsField::options_t relay_options = {
|
||||
{&bitmap_bulb_off, 0},
|
||||
{&bitmap_bulb_on, 1}};
|
||||
};
|
||||
|
||||
class BHTView : public View {
|
||||
public:
|
||||
BHTView(NavigationView& nav);
|
||||
~BHTView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "BHT TX"; };
|
||||
|
||||
private:
|
||||
TxRadioState radio_state_{};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_bht", app_settings::Mode::TX};
|
||||
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
void start_tx();
|
||||
void stop_tx();
|
||||
|
||||
enum target_system_t {
|
||||
XYLOS = 0,
|
||||
EPAR = 1
|
||||
};
|
||||
|
||||
target_system_t target_system = {};
|
||||
|
||||
enum tx_modes {
|
||||
IDLE = 0,
|
||||
SINGLE,
|
||||
SCAN
|
||||
};
|
||||
|
||||
tx_modes tx_mode = IDLE;
|
||||
|
||||
Rect view_rect = {0, 3 * 8, screen_width, 176};
|
||||
|
||||
XylosView view_xylos{view_rect};
|
||||
EPARView view_EPAR{view_rect};
|
||||
|
||||
TabView tab_view{
|
||||
{"Xylos", Theme::getInstance()->fg_cyan->foreground, &view_xylos},
|
||||
{"EPAR", Theme::getInstance()->fg_green->foreground, &view_EPAR}};
|
||||
|
||||
Labels labels{
|
||||
{{29 * 8, 14 * 16 + 4}, "s", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Checkbox checkbox_scan{
|
||||
{1 * 8, 25 * 8},
|
||||
4,
|
||||
"Scan"};
|
||||
|
||||
Checkbox checkbox_flashing{
|
||||
{16 * 8, 25 * 8},
|
||||
8,
|
||||
"Flashing"};
|
||||
NumberField field_speed{
|
||||
{26 * 8, 25 * 8 + 4},
|
||||
2,
|
||||
{1, 99},
|
||||
1,
|
||||
' '};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 8, 29 * 8, screen_width, 16},
|
||||
};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
10000,
|
||||
12};
|
||||
|
||||
MessageHandlerRegistration message_handler_tx_progress{
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||
this->on_tx_progress(message.progress, message.done);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -63,22 +63,22 @@ class BTLERxView : public View {
|
||||
static constexpr uint8_t channel_number = 37;
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{UI_POS_X(13), UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{UI_POS_X(15), UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{UI_POS_X(21), UI_POS_Y(0), UI_POS_WIDTH_REMAINING(21), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(21), 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
Button button_modem_setup{
|
||||
{screen_width - 12 * 8, 1 * 16, 96, 24},
|
||||
{screen_width - 12 * 8, UI_POS_Y(1), 96, 24},
|
||||
"Modem setup"};
|
||||
|
||||
Console console{
|
||||
|
||||
@@ -242,9 +242,9 @@ class DebugControlsView : public View {
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{8 * 8, 1 * 16}, "Controls State", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{0 * 8, 11 * 16}, "Dial:", Theme::getInstance()->fg_medium->foreground},
|
||||
{{0 * 8, 14 * 16}, "Long-Press Mode:", Theme::getInstance()->fg_medium->foreground}};
|
||||
{{UI_POS_X_CENTER(14), 1 * 16}, "Controls State", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{UI_POS_X(0), 11 * 16}, "Dial:", Theme::getInstance()->fg_medium->foreground},
|
||||
{{UI_POS_X(0), 14 * 16}, "Long-Press Mode:", Theme::getInstance()->fg_medium->foreground}};
|
||||
|
||||
ControlsSwitchesWidget switches_widget{
|
||||
{80, 80, 80, 112},
|
||||
@@ -259,7 +259,7 @@ class DebugControlsView : public View {
|
||||
}};
|
||||
|
||||
Button button_done{
|
||||
{72, 264, 96, 24},
|
||||
{UI_POS_X_CENTER(12), 264, 96, 24},
|
||||
"Done"};
|
||||
};
|
||||
|
||||
@@ -271,28 +271,28 @@ class DebugMemoryDumpView : public View {
|
||||
|
||||
private:
|
||||
Button button_dump{
|
||||
{72, 4 * 16, 96, 24},
|
||||
{UI_POS_X_CENTER(12), 4 * 16, 96, 24},
|
||||
"Dump"};
|
||||
|
||||
Button button_read{
|
||||
{16, 11 * 16, 96, 24},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(10), 11 * 16, 96, 24},
|
||||
"Read"};
|
||||
|
||||
Button button_write{
|
||||
{128, 11 * 16, 96, 24},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(10), 11 * 16, 96, 24},
|
||||
"Write"};
|
||||
|
||||
Button button_done{
|
||||
{128, screen_height - 80, 96, 24},
|
||||
{UI_POS_X_RIGHT(12), UI_POS_Y_BOTTOM(3), 96, 24},
|
||||
"Done"};
|
||||
|
||||
Labels labels{
|
||||
{{5 * 8, 1 * 16}, "Dump Range to File", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{0 * 8, 2 * 16}, "Starting Address: 0x", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Byte Count: 0x", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 2 * 16}, "Starting Address: 0x", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Byte Count: 0x", Theme::getInstance()->fg_light->foreground},
|
||||
{{3 * 8, 8 * 16}, "Read/Write Single Word", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{0 * 8, 9 * 16}, "Memory Address: 0x", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 10 * 16}, "Data Value: 0x", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 9 * 16}, "Memory Address: 0x", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 10 * 16}, "Data Value: 0x", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
SymField field_starting_address{
|
||||
{20 * 8, 2 * 16},
|
||||
|
||||
@@ -12,7 +12,7 @@ BatteryCapacityView::RegisterEntry BatteryCapacityView::get_entry(size_t index)
|
||||
|
||||
BatteryCapacityView::BatteryCapacityView(NavigationView& nav) {
|
||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||
name_texts[i].set_parent_rect({0 * 8, static_cast<int>((i + 1) * 16), 8 * 8, 16});
|
||||
name_texts[i].set_parent_rect({UI_POS_X(0), static_cast<int>((i + 1) * 16), 8 * 8, 16});
|
||||
addr_texts[i].set_parent_rect({9 * 8, static_cast<int>((i + 1) * 16), 4 * 8, 16});
|
||||
hex_texts[i].set_parent_rect({14 * 8, static_cast<int>((i + 1) * 16), 6 * 8, 16});
|
||||
value_texts[i].set_parent_rect({21 * 8, static_cast<int>((i + 1) * 16), 10 * 8, 16});
|
||||
|
||||
@@ -24,18 +24,18 @@ class BatteryCapacityView : public View {
|
||||
static RegisterEntry get_entry(size_t index);
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Reg", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{9 * 8, 0 * 16}, "Addr", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{14 * 8, 0 * 16}, "Hex", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{21 * 8, 0 * 16}, "Value", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Reg", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{9 * 8, UI_POS_Y(0)}, "Addr", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{14 * 8, UI_POS_Y(0)}, "Hex", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{21 * 8, UI_POS_Y(0)}, "Value", Theme::getInstance()->fg_yellow->foreground},
|
||||
};
|
||||
std::array<Text, 16> name_texts = {};
|
||||
std::array<Text, 16> addr_texts = {};
|
||||
std::array<Text, 16> hex_texts = {};
|
||||
std::array<Text, 16> value_texts = {};
|
||||
|
||||
Text page_text{{144, 284, 80, 16}, "Page 1/1"};
|
||||
Button button_done{{16, 280, 96, 24}, "Done"};
|
||||
Text page_text{{144, UI_POS_Y_BOTTOM(3), 80, 16}, "Page 1/1"};
|
||||
Button button_done{{16, UI_POS_Y_BOTTOM(3), 96, 24}, "Done"};
|
||||
|
||||
void update_values();
|
||||
void populate_page(int start_index);
|
||||
|
||||
@@ -216,10 +216,10 @@ class EncodersView : public View {
|
||||
"Ready"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{2 * 8, 13 * 16 + 20, 208, 16}};
|
||||
{2 * 8, 13 * 16 + 20, UI_POS_WIDTH_REMAINING(4), 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
50000,
|
||||
9};
|
||||
|
||||
|
||||
@@ -294,6 +294,7 @@ FileManBaseView::FileManBaseView(
|
||||
std::string filter)
|
||||
: nav_{nav},
|
||||
extension_filter{filter} {
|
||||
max_filename_length = screen_width / 8 - 10;
|
||||
add_children({&labels,
|
||||
&text_current,
|
||||
&button_exit});
|
||||
@@ -403,7 +404,7 @@ void FileManBaseView::refresh_list() {
|
||||
menu_view.clear();
|
||||
|
||||
for (const auto& entry : entry_list) {
|
||||
auto entry_name = std::string{entry.path.length() <= 20 ? entry.path : entry.path.substr(0, 20)};
|
||||
auto entry_name = std::string{entry.path.length() <= max_filename_length ? entry.path : entry.path.substr(0, max_filename_length)};
|
||||
|
||||
if (entry.is_directory) {
|
||||
std::string size_str{};
|
||||
@@ -414,7 +415,7 @@ void FileManBaseView::refresh_list() {
|
||||
}
|
||||
|
||||
menu_view.add_item(
|
||||
{entry_name.substr(0, max_filename_length) + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
{entry_name.substr(0, max_filename_length) + std::string((max_filename_length + 1) - entry_name.length(), ' ') + size_str,
|
||||
Theme::getInstance()->fg_yellow->foreground,
|
||||
&bitmap_icon_dir,
|
||||
[this](KeyEvent key) {
|
||||
@@ -427,7 +428,7 @@ void FileManBaseView::refresh_list() {
|
||||
auto size_str = to_string_file_size(entry.size);
|
||||
|
||||
menu_view.add_item(
|
||||
{entry_name.substr(0, max_filename_length) + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
{entry_name.substr(0, max_filename_length) + std::string((max_filename_length + 1) - entry_name.length(), ' ') + size_str,
|
||||
assoc.color,
|
||||
assoc.icon,
|
||||
[this](KeyEvent key) {
|
||||
@@ -486,7 +487,7 @@ FileLoadView::FileLoadView(
|
||||
add_children({&menu_view});
|
||||
|
||||
// Resize menu view to fill screen
|
||||
menu_view.set_parent_rect({0, 3 * 8, screen_width, 29 * 8});
|
||||
menu_view.set_parent_rect({0, 3 * 8, screen_width, UI_POS_HEIGHT_REMAINING(4.5)});
|
||||
|
||||
refresh_list();
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class FileManBaseView : public View {
|
||||
uint8_t pagination = 0;
|
||||
uint8_t nb_pages = 1;
|
||||
bool restoring_navigation = false;
|
||||
static constexpr size_t max_filename_length = 20;
|
||||
size_t max_filename_length = 20;
|
||||
static constexpr size_t max_items_loaded = 75; // too memory hungry, so won't sort it
|
||||
static constexpr size_t items_per_page = 20;
|
||||
|
||||
@@ -122,16 +122,16 @@ class FileManBaseView : public View {
|
||||
{{0, 0}, "Path:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_current{
|
||||
{6 * 8, 0 * 8, 24 * 8, 16},
|
||||
{UI_POS_X(6), UI_POS_Y(0), UI_POS_WIDTH_REMAINING(6), UI_POS_HEIGHT(1)},
|
||||
"",
|
||||
};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 2 * 8, screen_width, 26 * 8},
|
||||
{0, UI_POS_Y(1), UI_POS_MAXWIDTH, UI_POS_HEIGHT_REMAINING(7)},
|
||||
true};
|
||||
|
||||
Button button_exit{
|
||||
{22 * 8, 34 * 8, 8 * 8, 32},
|
||||
{UI_POS_X_RIGHT(8), UI_POS_Y_BOTTOM(3), 8 * 8, UI_POS_HEIGHT(2)},
|
||||
"Exit"};
|
||||
};
|
||||
|
||||
@@ -230,66 +230,66 @@ class FileManagerView : public FileManBaseView {
|
||||
bool selected_is_valid() const;
|
||||
|
||||
Text text_date{
|
||||
{0 * 8, 26 * 8, 28 * 8, 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(6), 28 * 8, UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
|
||||
NewButton button_rename{
|
||||
{0 * 8, 29 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_rename,
|
||||
Theme::getInstance()->fg_blue->foreground};
|
||||
|
||||
NewButton button_delete{
|
||||
{9 * 8, 34 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(9), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_trash,
|
||||
Theme::getInstance()->fg_red->foreground};
|
||||
|
||||
NewButton button_clean{
|
||||
{13 * 8, 34 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(13), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_clean,
|
||||
Theme::getInstance()->fg_red->foreground};
|
||||
|
||||
NewButton button_cut{
|
||||
{9 * 8, 29 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(9), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_cut,
|
||||
Theme::getInstance()->fg_dark->foreground};
|
||||
|
||||
NewButton button_copy{
|
||||
{13 * 8, 29 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(13), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_copy,
|
||||
Theme::getInstance()->fg_dark->foreground};
|
||||
|
||||
NewButton button_paste{
|
||||
{17 * 8, 29 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(17), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_paste,
|
||||
Theme::getInstance()->fg_dark->foreground};
|
||||
|
||||
NewButton button_new_dir{
|
||||
{22 * 8, 29 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(22), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_new_dir,
|
||||
Theme::getInstance()->fg_green->foreground};
|
||||
|
||||
NewButton button_new_file{
|
||||
{26 * 8, 29 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(26), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_new_file,
|
||||
Theme::getInstance()->fg_green->foreground};
|
||||
|
||||
NewButton button_open_notepad{
|
||||
{0 * 8, 34 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_notepad,
|
||||
Theme::getInstance()->fg_orange->foreground};
|
||||
|
||||
NewButton button_rename_timestamp{
|
||||
|
||||
{4 * 8, 29 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(4), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_options_datetime,
|
||||
Theme::getInstance()->fg_blue->foreground,
|
||||
@@ -297,13 +297,13 @@ class FileManagerView : public FileManBaseView {
|
||||
|
||||
NewButton button_open_iq_trim{
|
||||
|
||||
{4 * 8, 34 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(4), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_trim,
|
||||
Theme::getInstance()->fg_orange->foreground};
|
||||
|
||||
NewButton button_show_hidden_files{
|
||||
{17 * 8, 34 * 8, 4 * 8, 32},
|
||||
{UI_POS_X(17), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_hide,
|
||||
Theme::getInstance()->fg_dark->foreground};
|
||||
|
||||
@@ -130,6 +130,12 @@ bool FlashUtilityView::endsWith(const std::u16string& str, const std::u16string&
|
||||
}
|
||||
}
|
||||
|
||||
void FlashUtilityView::wait_till_loaded() {
|
||||
while (!isLoaded) {
|
||||
chThdSleepMilliseconds(50);
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path FlashUtilityView::extract_tar(std::filesystem::path::string_type path, ui::Painter& painter) {
|
||||
//
|
||||
painter.fill_rectangle(
|
||||
|
||||
@@ -49,6 +49,7 @@ class FlashUtilityView : public View {
|
||||
|
||||
std::string title() const override { return "Flash Utility"; };
|
||||
bool flash_firmware(std::filesystem::path::string_type path);
|
||||
void wait_till_loaded();
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
@@ -60,13 +61,21 @@ class FlashUtilityView : public View {
|
||||
{{4, 4}, "Select firmware to flash:", Theme::getInstance()->bg_darkest->foreground}};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 2 * 8, screen_width, 26 * 8},
|
||||
{0, UI_POS_Y(1), screen_width, UI_POS_HEIGHT_REMAINING(2)},
|
||||
true};
|
||||
|
||||
std::filesystem::path extract_tar(std::filesystem::path::string_type path, ui::Painter& painter); // extracts the tar file, and returns the firmware.bin path from it. empty string if no fw
|
||||
void firmware_selected(std::filesystem::path::string_type path);
|
||||
|
||||
bool endsWith(const std::u16string& str, const std::u16string& suffix);
|
||||
bool isLoaded = false;
|
||||
uint8_t refreshcnt = 0;
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
refreshcnt++;
|
||||
if (refreshcnt > 5) isLoaded = true;
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -72,7 +72,7 @@ class FreqManBaseView : public View {
|
||||
{0, 3 * 8, screen_width, 12 * 16 + 2 /* 2 Keeps text out of border. */}};
|
||||
|
||||
Button button_exit{
|
||||
{15 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
{UI_POS_X_RIGHT(14), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(14), UI_POS_HEIGHT(2)},
|
||||
"Exit"};
|
||||
|
||||
protected:
|
||||
@@ -97,14 +97,14 @@ class FrequencySaveView : public FreqManBaseView {
|
||||
0};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 6 * 16}, "Description:", Theme::getInstance()->bg_darkest->foreground}};
|
||||
{{UI_POS_X(0), 6 * 16}, "Description:", Theme::getInstance()->bg_darkest->foreground}};
|
||||
|
||||
TextField field_description{
|
||||
{0 * 8, 7 * 16, screen_width, 1 * 16},
|
||||
{UI_POS_X(0), 7 * 16, screen_width, 1 * 16},
|
||||
""};
|
||||
|
||||
Button button_save{
|
||||
{0 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(14), UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
};
|
||||
|
||||
@@ -134,44 +134,44 @@ class FrequencyManagerView : public FreqManBaseView {
|
||||
void on_del_entry();
|
||||
|
||||
NewButton button_add_category{
|
||||
{23 * 8, 0 * 16, 7 * 4, 20},
|
||||
{UI_POS_X_RIGHT(8), UI_POS_Y(0), 7 * 4, 20},
|
||||
{},
|
||||
&bitmap_icon_new_file,
|
||||
Theme::getInstance()->bg_darkest->foreground,
|
||||
true};
|
||||
|
||||
NewButton button_del_category{
|
||||
{26 * 8 + 4, 0 * 16, 7 * 4, 20},
|
||||
{UI_POS_X_RIGHT(4), UI_POS_Y(0), 7 * 4, 20},
|
||||
{},
|
||||
&bitmap_icon_trash,
|
||||
Theme::getInstance()->fg_red->foreground,
|
||||
true};
|
||||
|
||||
Button button_edit_entry{
|
||||
{0 * 8, 14 * 16 - 4, 15 * 8, 1 * 16 + 4},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(6.5) + 4, 15 * 8, 1 * 16 + 4},
|
||||
"Edit"};
|
||||
|
||||
Rectangle rect_padding{
|
||||
{15 * 8, 14 * 16 - 4, 15 * 8, 1 * 16 + 4},
|
||||
{15 * 8, UI_POS_Y_BOTTOM(6.5), 15 * 8, 1 * 16 + 4},
|
||||
Theme::getInstance()->fg_medium->background};
|
||||
|
||||
Button button_edit_freq{
|
||||
{0 * 8, 15 * 16, 15 * 8, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(5), 15 * 8, 2 * 16},
|
||||
"Frequency"};
|
||||
|
||||
Button button_edit_desc{
|
||||
{0 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(3), 15 * 8, 2 * 16},
|
||||
"Description"};
|
||||
|
||||
NewButton button_add_entry{
|
||||
{15 * 8, 15 * 16, 7 * 8 + 4, 2 * 16},
|
||||
{15 * 8, UI_POS_Y_BOTTOM(5), 7 * 8 + 4, 2 * 16},
|
||||
{},
|
||||
&bitmap_icon_add,
|
||||
Theme::getInstance()->bg_darkest->foreground,
|
||||
true};
|
||||
|
||||
NewButton button_del_entry{
|
||||
{22 * 8 + 4, 15 * 16, 7 * 8 + 4, 2 * 16},
|
||||
{22 * 8 + 4, UI_POS_Y_BOTTOM(5), 7 * 8 + 4, 2 * 16},
|
||||
{},
|
||||
&bitmap_icon_delete,
|
||||
Theme::getInstance()->fg_red->foreground,
|
||||
@@ -201,14 +201,14 @@ class FrequencyEditView : public View {
|
||||
|
||||
Labels labels{
|
||||
{{5 * 8, 1 * 16}, "Edit Frequency Entry", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{0 * 8, 3 * 16}, "Entry Type :", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "Frequency A:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Frequency B:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 6 * 16}, "Modulation :", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "Bandwidth :", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 8 * 16}, "Step :", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 9 * 16}, "Tone Freq :", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 10 * 16}, "Description:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Entry Type :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 4 * 16}, "Frequency A:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 5 * 16}, "Frequency B:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 6 * 16}, "Modulation :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "Bandwidth :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 8 * 16}, "Step :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 9 * 16}, "Tone Freq :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 10 * 16}, "Description:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
OptionsField field_type{
|
||||
@@ -243,11 +243,11 @@ class FrequencyEditView : public View {
|
||||
{}};
|
||||
|
||||
Button button_save{
|
||||
{0 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(3), 15 * 8, 2 * 16},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{15 * 8, 17 * 16, 15 * 8, 2 * 16},
|
||||
{UI_POS_X_RIGHT(15), UI_POS_Y_BOTTOM(3), 15 * 8, 2 * 16},
|
||||
"Cancel"};
|
||||
};
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class TrimProgressUI {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
p.fill_rectangle({0 * 8, 4 * 16, screen_width, 3 * 16}, Theme::getInstance()->bg_darkest->background);
|
||||
p.fill_rectangle({UI_POS_X(0), 4 * 16, screen_width, 3 * 16}, Theme::getInstance()->bg_darkest->background);
|
||||
}
|
||||
|
||||
auto get_callback() {
|
||||
@@ -100,22 +100,22 @@ class IQTrimView : public View {
|
||||
TrimProgressUI progress_ui{};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Capture File:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 6 * 16}, "Start :", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "End :", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 8 * 16}, "Samples:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 9 * 16}, "Max Pwr:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 10 * 16}, "Cutoff :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Capture File:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 6 * 16}, "Start :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "End :", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 8 * 16}, "Samples:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 9 * 16}, "Max Pwr:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 10 * 16}, "Cutoff :", Theme::getInstance()->fg_light->foreground},
|
||||
{{12 * 8, 10 * 16}, "%", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 12 * 16}, "Amplify:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 12 * 16}, "Amplify:", Theme::getInstance()->fg_light->foreground},
|
||||
{{10 * 8, 12 * 16}, "x", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
TextField field_path{
|
||||
{0 * 8, 1 * 16, screen_width, 1 * 16},
|
||||
{UI_POS_X(0), 1 * 16, screen_width, 1 * 16},
|
||||
"Open File..."};
|
||||
|
||||
Point pos_lines{0 * 8, 4 * 16};
|
||||
Point pos_lines{UI_POS_X(0), 4 * 16};
|
||||
Dim height_lines{2 * 16};
|
||||
|
||||
NumberField field_start{
|
||||
@@ -155,7 +155,7 @@ class IQTrimView : public View {
|
||||
' '};
|
||||
|
||||
Button button_trim{
|
||||
{20 * 8, 16 * 16, 8 * 8, 2 * 16},
|
||||
{UI_POS_X_CENTER(8), UI_POS_Y_BOTTOM(3), 8 * 8, 2 * 16},
|
||||
"Trim"};
|
||||
};
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ class GlassView : public View {
|
||||
uint8_t ignore_dc = 0;
|
||||
|
||||
Labels labels{
|
||||
{{0, 0 * 16}, "MIN: MAX: LNA VGA ", Theme::getInstance()->fg_light->foreground},
|
||||
{{0, UI_POS_Y(0)}, "MIN: MAX: LNA VGA ", Theme::getInstance()->fg_light->foreground},
|
||||
{{0, 1 * 16}, "RANGE: FILTER: AMP:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0, 2 * 16}, "P:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0, 3 * 16}, "MARKER: MHz RXIQCAL", Theme::getInstance()->fg_light->foreground},
|
||||
@@ -178,24 +178,24 @@ class GlassView : public View {
|
||||
{{0, 4 * 16}, "RES: VOL:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
NumberField field_frequency_min{
|
||||
{4 * 8, 0 * 16},
|
||||
{4 * 8, UI_POS_Y(0)},
|
||||
4,
|
||||
{0, 7199},
|
||||
1, // number of steps by encoder delta
|
||||
' '};
|
||||
|
||||
NumberField field_frequency_max{
|
||||
{13 * 8, 0 * 16},
|
||||
{13 * 8, UI_POS_Y(0)},
|
||||
4,
|
||||
{1, 7200},
|
||||
1, // number of steps by encoder delta
|
||||
' '};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{21 * 8, 0 * 16}};
|
||||
{21 * 8, UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{27 * 8, 0 * 16}};
|
||||
{27 * 8, UI_POS_Y(0)}};
|
||||
|
||||
TextField field_range{
|
||||
{6 * 8, 1 * 16, 6 * 8, 16},
|
||||
@@ -298,7 +298,7 @@ class GlassView : public View {
|
||||
"RST"};
|
||||
|
||||
Text freq_stats{
|
||||
{0 * 8, 5 * 16, screen_width - 10 * 8, 8},
|
||||
{UI_POS_X(0), 5 * 16, screen_width - 10 * 8, 8},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_spectrum_config{
|
||||
|
||||
@@ -170,7 +170,7 @@ class MicTXView : public View {
|
||||
{{17 * 8, 1 * 8}, "ALC", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
VuMeter vumeter{
|
||||
{0 * 8, 1 * 8, 2 * 8, 33 * 8},
|
||||
{UI_POS_X(0), 1 * 8, 2 * 8, 33 * 8},
|
||||
12,
|
||||
true};
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class ModemSetupView : public View {
|
||||
"SET"};
|
||||
|
||||
Button button_save{
|
||||
{9 * 8, 250, 96, 40},
|
||||
{UI_POS_X_CENTER(12), 250, UI_POS_WIDTH(12), 40},
|
||||
"Save"};
|
||||
};
|
||||
|
||||
|
||||
@@ -387,7 +387,6 @@ PlaylistView::PlaylistView(
|
||||
&button_next,
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
ensure_directory(playlist_dir);
|
||||
waterfall.show_audio_spectrum_view(false);
|
||||
|
||||
|
||||
@@ -107,24 +107,24 @@ class PlaylistView : public View {
|
||||
void handle_replay_thread_done(uint32_t return_code);
|
||||
|
||||
Text text_filename{
|
||||
{0 * 8, 0 * 16, screen_width, 16}};
|
||||
{UI_POS_X(0), UI_POS_Y(0), screen_width, 16}};
|
||||
|
||||
FrequencyField field_frequency{
|
||||
{0 * 8, 1 * 16}};
|
||||
{UI_POS_X(0), 1 * 16}};
|
||||
|
||||
Text text_sample_rate{
|
||||
{10 * 8, 1 * 16, 7 * 8, 16}};
|
||||
|
||||
ProgressBar progressbar_track{
|
||||
{18 * 8, 1 * 16, 12 * 8, 8 + 1}};
|
||||
{18 * 8, 1 * 16, UI_POS_WIDTH_REMAINING(19), 8 + 1}};
|
||||
|
||||
// (-1) to overlap with progressbar_track so there's
|
||||
// only 1 pixel between them instead of 2.
|
||||
ProgressBar progressbar_transmit{
|
||||
{18 * 8, 3 * 8 - 1, 12 * 8, 8}};
|
||||
{18 * 8, 3 * 8 - 1, UI_POS_WIDTH_REMAINING(19), 8}};
|
||||
|
||||
Text text_duration{
|
||||
{0 * 8, 2 * 16, 5 * 8, 16}};
|
||||
{UI_POS_X(0), 2 * 16, 5 * 8, 16}};
|
||||
|
||||
// TODO: delay duration field.
|
||||
|
||||
@@ -133,7 +133,7 @@ class PlaylistView : public View {
|
||||
/*short_ui*/ true};
|
||||
|
||||
Checkbox check_loop{
|
||||
{21 * 8, 2 * 16},
|
||||
{UI_POS_X_RIGHT(9), 2 * 16},
|
||||
4,
|
||||
"Loop",
|
||||
true};
|
||||
@@ -145,7 +145,7 @@ class PlaylistView : public View {
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
Text text_track{
|
||||
{0 * 8, 3 * 16, screen_width, 16}};
|
||||
{UI_POS_X(0), 3 * 16, screen_width, 16}};
|
||||
|
||||
NewButton button_prev{
|
||||
{2 * 8, 4 * 16, 4 * 8, 2 * 16},
|
||||
|
||||
@@ -85,7 +85,7 @@ class POCSAGTXView : public View {
|
||||
{{6 * 8, 8 * 8}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 10 * 8}, "Function:", Theme::getInstance()->fg_light->foreground},
|
||||
{{5 * 8, 12 * 8}, "Phase:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 14 * 8}, "Message:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 14 * 8}, "Message:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_bitrate{
|
||||
{11 * 8, 4 * 8},
|
||||
@@ -122,21 +122,21 @@ class POCSAGTXView : public View {
|
||||
}};
|
||||
|
||||
Text text_message{
|
||||
{0 * 8, 16 * 8, screen_width, 16},
|
||||
{UI_POS_X(0), 16 * 8, screen_width, 16},
|
||||
""};
|
||||
Text text_message_l2{
|
||||
{0 * 8, 18 * 8, screen_width, 16},
|
||||
{UI_POS_X(0), 18 * 8, screen_width, 16},
|
||||
""};
|
||||
|
||||
Button button_message{
|
||||
{0 * 8, 20 * 8, 14 * 8, 32},
|
||||
{UI_POS_X(0), 20 * 8, 14 * 8, 32},
|
||||
"Set message"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{16, 210, 208, 16}};
|
||||
{16, 210, UI_POS_WIDTH_REMAINING(4), 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
10000,
|
||||
9};
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class RDSRadioTextView : public OptionTabView {
|
||||
{1 * 8, 4 * 16, 28 * 8, 16},
|
||||
"-"};
|
||||
Button button_set{
|
||||
{88, 6 * 16, 64, 32},
|
||||
{UI_POS_X_CENTER(8), 6 * 16, UI_POS_WIDTH(8), 32},
|
||||
"Set"};
|
||||
};
|
||||
|
||||
@@ -92,7 +92,7 @@ class RDSDateTimeView : public OptionTabView {
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{44, 5 * 16}, "Not yet implemented", Theme::getInstance()->error_dark->foreground}};
|
||||
{{UI_POS_X_CENTER(19), 5 * 16}, "Not yet implemented", Theme::getInstance()->error_dark->foreground}};
|
||||
};
|
||||
|
||||
class RDSAudioView : public OptionTabView {
|
||||
@@ -101,7 +101,7 @@ class RDSAudioView : public OptionTabView {
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{44, 5 * 16}, "Not yet implemented", Theme::getInstance()->error_dark->foreground}};
|
||||
{{UI_POS_X_CENTER(19), 5 * 16}, "Not yet implemented", Theme::getInstance()->error_dark->foreground}};
|
||||
};
|
||||
|
||||
class RDSThread {
|
||||
@@ -174,7 +174,7 @@ class RDSView : public View {
|
||||
{"Audio", Theme::getInstance()->fg_orange->foreground, &view_audio}};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 28}, "Program type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 28}, "Program type:", Theme::getInstance()->fg_light->foreground},
|
||||
//{ { 14 * 8, 16 + 8 }, "CC:", Theme::getInstance()->fg_light->foreground },
|
||||
{{2 * 8, 28 + 16}, "Program ID:", Theme::getInstance()->fg_light->foreground},
|
||||
//{ { 13 * 8, 32 + 8 }, "Cov:",Theme::getInstance()->fg_light->foreground },
|
||||
@@ -319,7 +319,7 @@ class RDSView : public View {
|
||||
"TP"};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
50000,
|
||||
9};
|
||||
|
||||
|
||||
@@ -217,23 +217,24 @@ class ReconView : public View {
|
||||
std::unique_ptr<RecordView> record_view{};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "LNA: VGA: AMP: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(6), UI_POS_Y(0)}, "VOL: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{3 * 8, 8 * 16}, "START END", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, (22 * 8)}, " S: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, (24 * 8) + 4}, "NBLCKS:x W,L: , ", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, (26 * 8) + 4}, "MODE: , SQUELCH: ", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), (22 * 8)}, " S: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), (24 * 8) + 4}, "NBLCKS:x W,L: , ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), (26 * 8) + 4}, "MODE: , SQUELCH: ", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{4 * 8, 0 * 16}};
|
||||
{4 * 8, UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{11 * 8, 0 * 16}};
|
||||
{11 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{24 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
Text file_name{
|
||||
// show file used
|
||||
@@ -297,7 +298,7 @@ class ReconView : public View {
|
||||
"CONFIG"};
|
||||
|
||||
ButtonWithEncoder button_manual_start{
|
||||
{0 * 8, 9 * 16, 11 * 8, 28},
|
||||
{UI_POS_X(0), 9 * 16, 11 * 8, 28},
|
||||
""};
|
||||
|
||||
ButtonWithEncoder button_manual_end{
|
||||
@@ -305,7 +306,7 @@ class ReconView : public View {
|
||||
""};
|
||||
|
||||
OptionsField field_recon_match_mode{
|
||||
{0 * 8, 11 * 16},
|
||||
{UI_POS_X(0), 11 * 16},
|
||||
16, // CONTINUOUS MATCH MODE / SPARSE TIMED MATCH MODE
|
||||
{
|
||||
{"MATCH:CONTINOUS", 0},
|
||||
@@ -363,15 +364,15 @@ class ReconView : public View {
|
||||
};
|
||||
|
||||
ButtonWithEncoder button_pause{
|
||||
{0, (15 * 16) - 4, 72, 28},
|
||||
{0, (15 * 16) - 4, UI_POS_WIDTH(9), 28},
|
||||
"PAUSE"};
|
||||
|
||||
Button button_audio_app{
|
||||
{84, (15 * 16) - 4, 72, 28},
|
||||
{UI_POS_X_CENTER(9), (15 * 16) - 4, UI_POS_WIDTH(9), 28},
|
||||
"AUDIO"};
|
||||
|
||||
ButtonWithEncoder button_add{
|
||||
{168, (15 * 16) - 4, 72, 28},
|
||||
{UI_POS_X_RIGHT(9), (15 * 16) - 4, UI_POS_WIDTH(9), 28},
|
||||
"<STORE>"};
|
||||
|
||||
Button button_dir{
|
||||
@@ -383,15 +384,15 @@ class ReconView : public View {
|
||||
"RST"};
|
||||
|
||||
Button button_mic_app{
|
||||
{84, (35 * 8) - 4, 72, 28},
|
||||
{UI_POS_X_CENTER(9), (35 * 8) - 4, UI_POS_WIDTH(9), 28},
|
||||
"MIC TX"};
|
||||
|
||||
ButtonWithEncoder button_remove{
|
||||
{168, (35 * 8) - 4, 72, 28},
|
||||
{UI_POS_X_RIGHT(9), (35 * 8) - 4, UI_POS_WIDTH(9), 28},
|
||||
"<REMOVE>"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 8, screen_height / 2 - 16, screen_width, 32}};
|
||||
{UI_POS_X(0), screen_height / 2 - 16, screen_width, 32}};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
{11 * 8, 2 * 16},
|
||||
|
||||
@@ -225,7 +225,7 @@ class ReconSetupView : public View {
|
||||
{"More", Theme::getInstance()->fg_green->foreground, &viewMore}};
|
||||
|
||||
Button button_save{
|
||||
{9 * 8, 255, 14 * 8, 40},
|
||||
{UI_POS_X_CENTER(18), 255, UI_POS_WIDTH(18), 40},
|
||||
"SAVE"};
|
||||
};
|
||||
|
||||
|
||||
@@ -46,15 +46,15 @@ class SdOverUsbView : public View {
|
||||
NavigationView& nav_;
|
||||
|
||||
Labels labels{
|
||||
{{3 * 8, 2 * 16}, "Click Run to start the", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{3 * 8, 3 * 16}, "USB Mass Storage Mode.", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{3 * 8, 5 * 16}, "It can take up to 20s", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{3 * 8, 6 * 16}, "for the drive to be", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{3 * 8, 7 * 16}, "available.", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{UI_POS_X_CENTER(22), 2 * 16}, "Click Run to start the", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{UI_POS_X_CENTER(22), 3 * 16}, "USB Mass Storage Mode.", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{UI_POS_X_CENTER(21), 5 * 16}, "It can take up to 20s", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{UI_POS_X_CENTER(19), 6 * 16}, "for the drive to be", Theme::getInstance()->bg_darkest->foreground},
|
||||
{{UI_POS_X_CENTER(10), 7 * 16}, "available.", Theme::getInstance()->bg_darkest->foreground},
|
||||
};
|
||||
|
||||
Button button_run{
|
||||
{9 * 8, 15 * 16, 12 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(12), 15 * 16, 12 * 8, 3 * 16},
|
||||
"Run"};
|
||||
};
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ void RecentEntriesTable<SearchRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
std::string str_duration = "";
|
||||
|
||||
if (entry.duration < 600)
|
||||
@@ -50,9 +51,10 @@ void RecentEntriesTable<SearchRecentEntries>::draw(
|
||||
else
|
||||
str_duration = to_string_dec_uint(entry.duration / 600) + "m" + to_string_dec_uint((entry.duration / 10) % 60) + "s";
|
||||
|
||||
str_duration.resize(target_rect.width() / 8, ' ');
|
||||
|
||||
painter.draw_string(target_rect.location(), style, to_string_short_freq(entry.frequency) + " " + entry.time + " " + str_duration);
|
||||
str_duration.resize(11, ' ');
|
||||
std::string freq = to_string_short_freq(entry.frequency);
|
||||
freq.resize(columns.at(0).second, ' ');
|
||||
painter.draw_string(target_rect.location(), style, freq + " " + entry.time + " " + str_duration);
|
||||
}
|
||||
|
||||
/* SearchView ********************************************/
|
||||
@@ -60,6 +62,7 @@ void RecentEntriesTable<SearchRecentEntries>::draw(
|
||||
SearchView::SearchView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
spectrum_row.resize(240);
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
||||
|
||||
if (!gradient.load_file(default_gradient_file)) {
|
||||
@@ -86,7 +89,7 @@ SearchView::SearchView(
|
||||
|
||||
baseband::set_spectrum(SEARCH_SLICE_WIDTH, 31);
|
||||
|
||||
recent_entries_view.set_parent_rect({0, 28 * 8, screen_width, 12 * 8});
|
||||
recent_entries_view.set_parent_rect({0, 28 * 8, screen_width, screen_height - 28 * 8});
|
||||
recent_entries_view.on_select = [this, &nav](const SearchRecentEntry& entry) {
|
||||
nav.push<FrequencySaveView>(entry.frequency);
|
||||
};
|
||||
@@ -160,9 +163,8 @@ void SearchView::do_detection() {
|
||||
// Display spectrum
|
||||
bin_skip_acc = 0;
|
||||
pixel_index = 0;
|
||||
display.draw_pixels(
|
||||
{{0, 88}, {(Dim)spectrum_row.size(), 1}},
|
||||
spectrum_row);
|
||||
uint16_t center_align_start = (screen_width - spectrum_row.size()) / 2;
|
||||
display.draw_pixels({{center_align_start, 88}, {(Dim)spectrum_row.size(), 1}}, spectrum_row);
|
||||
|
||||
mean_power = mean_acc / (SEARCH_BIN_NB_NO_DC * slices_nb);
|
||||
mean_acc = 0;
|
||||
@@ -249,7 +251,7 @@ void SearchView::do_detection() {
|
||||
// Refresh red tick
|
||||
portapack::display.fill_rectangle({last_tick_pos, 90, 1, 6}, Theme::getInstance()->fg_red->background);
|
||||
if (bin_max > -1) {
|
||||
last_tick_pos = (Coord)(bin_max / slices_nb);
|
||||
last_tick_pos = (Coord)(bin_max / slices_nb) + center_align_start;
|
||||
portapack::display.fill_rectangle({last_tick_pos, 90, 1, 6}, Theme::getInstance()->fg_red->foreground);
|
||||
}
|
||||
}
|
||||
@@ -398,7 +400,7 @@ void SearchView::add_spectrum_pixel(Color color) {
|
||||
|
||||
bin_skip_acc -= 0x10000;
|
||||
|
||||
if (pixel_index < screen_width)
|
||||
if (pixel_index < spectrum_row.size())
|
||||
spectrum_row[pixel_index++] = color;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ class SearchView : public View {
|
||||
uint32_t bin_skip_acc = 0;
|
||||
uint32_t bin_skip_frac = 0;
|
||||
uint32_t pixel_index = 0;
|
||||
std::array<Color, 240> spectrum_row{};
|
||||
std::vector<Color> spectrum_row{};
|
||||
ChannelSpectrumFIFO* fifo = nullptr;
|
||||
|
||||
uint8_t detect_timer = 0;
|
||||
@@ -174,81 +174,82 @@ class SearchView : public View {
|
||||
void on_range_changed();
|
||||
void add_spectrum_pixel(Color color);
|
||||
|
||||
const RecentEntriesColumns columns{{{"Frequency", 9},
|
||||
{"Time", 8},
|
||||
{"Duration", 11}}};
|
||||
RecentEntriesColumns columns{{{"Frequency", 0},
|
||||
{"Time", 8},
|
||||
{"Duration", 11}}};
|
||||
SearchRecentEntries recent{};
|
||||
RecentEntriesView<RecentEntries<SearchRecentEntry>> recent_entries_view{columns, recent};
|
||||
|
||||
Labels labels{
|
||||
{{1 * 8, 0}, "Min: Max: LNA VGA", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 4 * 8}, "Trig: /255 Mean: /255", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 6 * 8}, "Slices: /32 Rate: Hz", Theme::getInstance()->fg_light->foreground},
|
||||
{{6 * 8, 10 * 8}, "Timer Status", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 25 * 8}, "Accuracy +/-4.9kHz", Theme::getInstance()->fg_light->foreground},
|
||||
{{26 * 8, 25 * 8}, "MHz", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(1), UI_POS_Y(0)}, "Min: Max: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(7), UI_POS_Y(0)}, "LNA VGA", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(1), UI_POS_Y(2)}, "Trig: /255", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(12), UI_POS_Y(2)}, "Mean: /255", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(1), UI_POS_Y(3)}, "Slices: /32", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(10), UI_POS_Y(3)}, "Rate: Hz", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(6), UI_POS_Y(5)}, "Timer Status", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(1), 25 * 8}, "Accuracy +/-4.9kHz", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(4), 25 * 8}, "MHz", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Checkbox check_log{
|
||||
{24 * 8, 10 * 8},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(5)},
|
||||
3,
|
||||
"LOG",
|
||||
true};
|
||||
|
||||
FrequencyField field_frequency_min{
|
||||
{1 * 8, 1 * 16}};
|
||||
{UI_POS_X(1), UI_POS_Y(1)}};
|
||||
FrequencyField field_frequency_max{
|
||||
{11 * 8, 1 * 16}};
|
||||
{UI_POS_X(11), UI_POS_Y(1)}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{22 * 8, 1 * 16}};
|
||||
{UI_POS_X_RIGHT(7), UI_POS_Y(1)}};
|
||||
VGAGainField field_vga{
|
||||
{26 * 8, 1 * 16}};
|
||||
{UI_POS_X_RIGHT(3), UI_POS_Y(1)}};
|
||||
|
||||
NumberField field_threshold{
|
||||
{6 * 8, 2 * 16},
|
||||
{UI_POS_X(6), UI_POS_Y(2)},
|
||||
3,
|
||||
{5, 255},
|
||||
5,
|
||||
' '};
|
||||
Text text_mean{
|
||||
{22 * 8, 2 * 16, 3 * 8, 16},
|
||||
{UI_POS_X_RIGHT(7), UI_POS_Y(2), UI_POS_WIDTH(3), UI_POS_HEIGHT(1)},
|
||||
"---"};
|
||||
Text text_slices{
|
||||
{8 * 8, 3 * 16, 2 * 8, 16},
|
||||
{UI_POS_X(8), UI_POS_Y(3), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
"--"};
|
||||
Text text_rate{
|
||||
{24 * 8, 3 * 16, 3 * 8, 16},
|
||||
{UI_POS_X_RIGHT(5), UI_POS_Y(3), UI_POS_WIDTH(3), UI_POS_HEIGHT(1)},
|
||||
"---"};
|
||||
|
||||
VuMeter vu_max{
|
||||
{1 * 8, 11 * 8 - 4, 3 * 8, 48},
|
||||
{UI_POS_X(1), 11 * 8 - 4, 3 * 8, 48},
|
||||
18,
|
||||
false};
|
||||
|
||||
ProgressBar progress_timers{
|
||||
{6 * 8, 12 * 8, 6 * 8, 16}};
|
||||
{UI_POS_X(6), UI_POS_Y(6), UI_POS_WIDTH(6), UI_POS_HEIGHT(1)}};
|
||||
Text text_infos{
|
||||
{13 * 8, 12 * 8, 15 * 8, 16},
|
||||
{UI_POS_X(13), UI_POS_Y(6), UI_POS_WIDTH(15), UI_POS_HEIGHT(1)},
|
||||
"Listening"};
|
||||
|
||||
Checkbox check_snap{
|
||||
{6 * 8, 15 * 8},
|
||||
{UI_POS_X(6), 15 * 8},
|
||||
7,
|
||||
"Snap to:",
|
||||
true};
|
||||
OptionsField options_snap{
|
||||
{17 * 8, 15 * 8}, // Position
|
||||
7, // Length
|
||||
{ // Options
|
||||
{UI_POS_X(17), 15 * 8}, // Position
|
||||
7, // Length
|
||||
{ // Options
|
||||
{"25kHz ", 25'000},
|
||||
{"12.5kHz", 12'500},
|
||||
{"8.33kHz", 8'333},
|
||||
{"2.5kHz", 2'500},
|
||||
{"500Hz", 500}}};
|
||||
|
||||
BigFrequency big_display{
|
||||
{4, 9 * 16, 28 * 8, 52},
|
||||
0};
|
||||
BigFrequency big_display{{UI_POS_X_CENTER(28), UI_POS_Y(9), UI_POS_WIDTH(28), 52}, 0};
|
||||
|
||||
MessageHandlerRegistration message_handler_spectrum_config{
|
||||
Message::ID::ChannelSpectrumConfig,
|
||||
|
||||
@@ -40,6 +40,7 @@ using namespace lpc43xx;
|
||||
|
||||
#include "audio.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_io.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "file.hpp"
|
||||
@@ -759,7 +760,7 @@ AppSettingsView::AppSettingsView(
|
||||
add_children({&labels,
|
||||
&menu_view});
|
||||
|
||||
menu_view.set_parent_rect({0, 3 * 8, screen_width, 33 * 8});
|
||||
menu_view.set_parent_rect({0, 3 * 8, screen_width, UI_POS_HEIGHT_REMAINING(3)});
|
||||
|
||||
ensure_directory(settings_dir);
|
||||
|
||||
@@ -810,9 +811,12 @@ SetDisplayView::SetDisplayView(NavigationView& nav) {
|
||||
&field_fake_brightness,
|
||||
&button_save,
|
||||
&button_cancel,
|
||||
&checkbox_ips_screen_switch,
|
||||
&checkbox_brightness_switch});
|
||||
|
||||
if (portapack::device_type == portapack::DeviceType::DEV_PORTAPACK) {
|
||||
add_child(&checkbox_ips_screen_switch);
|
||||
}
|
||||
|
||||
field_fake_brightness.set_by_value(pmem::fake_brightness_level());
|
||||
checkbox_brightness_switch.set_value(pmem::apply_fake_brightness());
|
||||
checkbox_ips_screen_switch.set_value(pmem::config_lcd_normally_black());
|
||||
|
||||
@@ -72,8 +72,8 @@ class SetDateTimeView : public View {
|
||||
{{1 * 8, 5 * 16 - 2}, "YYYY-MM-DD HH:MM:SS DoW DoY", Theme::getInstance()->fg_medium->foreground},
|
||||
{{5 * 8, 6 * 16}, "- - : :", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 11 * 16}, "DST adds 1 hour to RTC time.", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 12 * 16}, "Start: 0:00 on Nth DDD in", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 13 * 16}, "End: 1:00 on Nth DDD in", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 12 * 16}, "Start: 0:00 on Nth DDD in", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 13 * 16}, "End: 1:00 on Nth DDD in", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
NumberField field_year{
|
||||
{1 * 8, 6 * 16},
|
||||
@@ -170,10 +170,10 @@ class SetDateTimeView : public View {
|
||||
{}};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Save"};
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Cancel"};
|
||||
|
||||
void form_init(const SetDateTimeModel& model);
|
||||
@@ -253,10 +253,10 @@ class SetRadioView : public View {
|
||||
"Disable external TCXO"};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Save"};
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
|
||||
@@ -372,11 +372,11 @@ class SetUIView : public View {
|
||||
&bitmap_sd_card_ok};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(16) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Cancel"};
|
||||
};
|
||||
|
||||
@@ -391,28 +391,28 @@ class SetSDCardView : public View {
|
||||
private:
|
||||
Labels labels{
|
||||
// 01234567890123456789012345678
|
||||
{{1 * 8, 120 - 48}, " HIGH SPEED SDCARD IO ", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 120 - 32}, " May or may not work !! ", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X_CENTER(26), 120 - 48}, " HIGH SPEED SDCARD IO ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(26), 120 - 32}, " May or may not work !! ", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Checkbox checkbox_sdcard_speed{
|
||||
{2 * 8, 120},
|
||||
{UI_POS_X_CENTER(26), 120},
|
||||
20,
|
||||
"enable high speed IO"};
|
||||
|
||||
Button button_test_sdcard_high_speed{
|
||||
{2 * 8, 152, 27 * 8, 32},
|
||||
{UI_POS_X_CENTER(27), 152, UI_POS_WIDTH(27), UI_POS_HEIGHT(2)},
|
||||
"TEST BUTTON (NO PMEM SAVE)"};
|
||||
|
||||
Text text_sdcard_test_status{
|
||||
{2 * 8, 198, 28 * 8, 16},
|
||||
{UI_POS_X_CENTER(28), 198, UI_POS_WIDTH(28), UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(16) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Cancel"};
|
||||
};
|
||||
|
||||
@@ -455,7 +455,7 @@ class SetConverterSettingsView : public View {
|
||||
{8 * 8, 10 * 16}};
|
||||
|
||||
Button button_return{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Return",
|
||||
};
|
||||
};
|
||||
@@ -498,7 +498,7 @@ class SetFrequencyCorrectionView : public View {
|
||||
{8 * 8, 10 * 16}};
|
||||
|
||||
Button button_return{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12), UI_POS_Y_BOTTOM(4), 12 * 8, UI_POS_HEIGHT(2)},
|
||||
"Return",
|
||||
};
|
||||
};
|
||||
@@ -536,11 +536,11 @@ class SetAudioView : public View {
|
||||
"Beep on RX packets"};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
@@ -559,11 +559,11 @@ class SetEncoderDialView : public View {
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Sensitivity to dial rotation", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 1 * 16}, "position (x steps per 360):", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Sensitivity to dial rotation", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "position (x steps per 360):", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 3 * 16}, "Sensitivity:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "Rotation rate (default 1", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 8 * 16}, "means no rate dependency):", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "Rotation rate (default 1", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 8 * 16}, "means no rate dependency):", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 10 * 16}, "Rate multiplier:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 14 * 16}, "Direction:", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
@@ -606,11 +606,11 @@ class SetEncoderDialView : public View {
|
||||
"-"};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
@@ -649,11 +649,11 @@ class SetButtonsView : public View {
|
||||
{"FAST", true}}};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
@@ -674,7 +674,7 @@ class SetPersistentMemoryView : public View {
|
||||
};
|
||||
|
||||
Text text_pmem_status{
|
||||
{1 * 8, 4 * 16 + 8, 28 * 8, 16},
|
||||
{UI_POS_X_CENTER(28), 4 * 16 + 8, 28 * 8, 16},
|
||||
""};
|
||||
|
||||
Checkbox check_use_sdcard_for_pmem{
|
||||
@@ -683,19 +683,19 @@ class SetPersistentMemoryView : public View {
|
||||
"Use SD card for P.Mem"};
|
||||
|
||||
Button button_save_mem_to_file{
|
||||
{1 * 8, 8 * 16, 28 * 8, 2 * 16},
|
||||
{UI_POS_X_CENTER(28), 8 * 16, 28 * 8, 2 * 16},
|
||||
"Save P.Mem to SD card"};
|
||||
|
||||
Button button_load_mem_from_file{
|
||||
{1 * 8, 10 * 16 + 2, 28 * 8, 2 * 16},
|
||||
{UI_POS_X_CENTER(28), 10 * 16 + 2, 28 * 8, 2 * 16},
|
||||
"Load P.Mem from SD Card"};
|
||||
|
||||
Button button_load_mem_defaults{
|
||||
{1 * 8, 12 * 16 + 4, 28 * 8, 2 * 16},
|
||||
{UI_POS_X_CENTER(28), 12 * 16 + 4, 28 * 8, 2 * 16},
|
||||
"Reset P.Mem to defaults"};
|
||||
|
||||
Button button_return{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Return",
|
||||
};
|
||||
};
|
||||
@@ -713,7 +713,7 @@ class AppSettingsView : public View {
|
||||
{{0, 4}, "Select file to edit:", Theme::getInstance()->bg_darkest->foreground}};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 2 * 8, screen_width, 26 * 8},
|
||||
{0, 2 * 8, screen_width, UI_POS_HEIGHT_REMAINING(3)},
|
||||
true};
|
||||
};
|
||||
|
||||
@@ -738,11 +738,11 @@ class SetConfigModeView : public View {
|
||||
"Config Mode enable"};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
@@ -784,11 +784,11 @@ class SetDisplayView : public View {
|
||||
"IPS Screen"};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(16) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
@@ -841,19 +841,19 @@ class SetTouchscreenThresholdView : public View {
|
||||
};
|
||||
|
||||
Button button_autodetect{
|
||||
{2 * 8, 13 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), 13 * 16, 12 * 8, 32},
|
||||
"Auto Detect"};
|
||||
Button button_reset{
|
||||
{16 * 8, 13 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), 13 * 16, 12 * 8, 32},
|
||||
"Reset",
|
||||
};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), 16 * 16, 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), 16 * 16, 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
|
||||
@@ -876,14 +876,14 @@ class SetMenuColorView : public View {
|
||||
void paint_sample();
|
||||
|
||||
Labels labels{
|
||||
{{3 * 8, 1 * 16}, "Menu Button Color Scheme", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(25), 1 * 16}, "Menu Button Color Scheme", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 8 * 16}, "Red Level:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 9 * 16}, "Green Level:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 10 * 16}, "Blue Level:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
NewButton button_sample{
|
||||
{8 * 8, 4 * 16, 14 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(14), 4 * 16, 14 * 8, 3 * 16},
|
||||
"New Color",
|
||||
&bitmap_icon_brightness,
|
||||
};
|
||||
@@ -913,16 +913,16 @@ class SetMenuColorView : public View {
|
||||
};
|
||||
|
||||
Button button_reset{
|
||||
{2 * 8, 13 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(7), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Reset",
|
||||
};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
@@ -941,12 +941,8 @@ class SetThemeView : public View {
|
||||
{{1 * 8, 1 * 16}, "Select a theme.", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 2 * 16}, "Restart PP to fully apply!", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
OptionsField options{
|
||||
{0 * 8, 4 * 16},
|
||||
{UI_POS_X(0), 4 * 16},
|
||||
(size_t)(screen_width / 8),
|
||||
{
|
||||
{"Default - Grey", 0},
|
||||
@@ -963,8 +959,12 @@ class SetThemeView : public View {
|
||||
23,
|
||||
"Set Menu color too"};
|
||||
|
||||
Button button_save{
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Cancel",
|
||||
};
|
||||
};
|
||||
@@ -988,10 +988,6 @@ class SetBatteryView : public View {
|
||||
|
||||
Labels labels2{{{1 * 8, 11 * 16}, "Reset IC's learned params.", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Checkbox checkbox_overridebatt{
|
||||
{2 * 8, 4 * 16},
|
||||
23,
|
||||
@@ -1003,12 +999,16 @@ class SetBatteryView : public View {
|
||||
"Charge hint"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Cancel",
|
||||
};
|
||||
|
||||
Button button_save{
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
|
||||
Button button_reset{
|
||||
{2 * 8, 13 * 16, 12 * 8, 32},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(7), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)},
|
||||
"Reset",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -127,7 +127,7 @@ class SigGenView : public View {
|
||||
{"Pulse CW 25%", 7}}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
10000,
|
||||
12};
|
||||
|
||||
|
||||
@@ -96,42 +96,42 @@ class SondeView : public View {
|
||||
Labels labels{
|
||||
{{4 * 8, 2 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{6 * 8, 3 * 16}, "ID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "DateTime:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 4 * 16}, "DateTime:", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
{{3 * 8, 5 * 16}, "Vbatt:", Theme::getInstance()->fg_light->foreground},
|
||||
{{3 * 8, 6 * 16}, "Frame:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 7 * 16}, "Temp:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 8 * 16}, "Humidity:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 8 * 16}, "Humidity:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), 0 * 8},
|
||||
nav_};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{13 * 8, UI_POS_Y(0)}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{15 * 8, UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{21 * 8, 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4},
|
||||
{21 * 8, 5, UI_POS_WIDTH_REMAINING(24), 4},
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
Checkbox check_log{
|
||||
{22 * 8, 8 * 16},
|
||||
{UI_POS_X_RIGHT(8), UI_POS_Y(8)},
|
||||
3,
|
||||
"Log"};
|
||||
|
||||
Checkbox check_crc{
|
||||
{22 * 8, 10 * 16},
|
||||
{UI_POS_X_RIGHT(8), UI_POS_Y(10)},
|
||||
3,
|
||||
"CRC"};
|
||||
|
||||
@@ -169,11 +169,11 @@ class SondeView : public View {
|
||||
GeoPos::spd_unit::HIDDEN};
|
||||
|
||||
Button button_see_qr{
|
||||
{2 * 8, 15 * 16, 12 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 3 * 16},
|
||||
"See QR"};
|
||||
|
||||
Button button_see_map{
|
||||
{16 * 8, 15 * 16, 12 * 8, 3 * 16},
|
||||
{UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 3 * 16},
|
||||
"See on map"};
|
||||
|
||||
GeoMapView* geomap_view_{nullptr};
|
||||
|
||||
@@ -262,17 +262,14 @@ void RecentEntriesTable<ui::SubGhzDRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
std::string line{};
|
||||
line.reserve(30);
|
||||
|
||||
line = SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)entry.sensorType);
|
||||
line = line + " " + to_string_hex(entry.data << 32);
|
||||
if (line.length() < 19) {
|
||||
line += SubGhzDView::pad_string_with_spaces(19 - line.length());
|
||||
} else {
|
||||
line = truncate(line, 19);
|
||||
}
|
||||
line.resize(columns.at(0).second, ' ');
|
||||
std::string ageStr = to_string_dec_uint(entry.age);
|
||||
std::string bitsStr = to_string_dec_uint(entry.bits);
|
||||
line += SubGhzDView::pad_string_with_spaces(5 - bitsStr.length()) + bitsStr;
|
||||
|
||||
@@ -122,18 +122,18 @@ class SubGhzDView : public View {
|
||||
SubGhzDRecentEntries recent{};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{13 * 8, UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{15 * 8, UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{21 * 8, 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4},
|
||||
{21 * 8, 5, UI_POS_WIDTH_REMAINING(24), 4},
|
||||
};
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
SignalToken signal_token_tick_second{};
|
||||
@@ -152,8 +152,8 @@ class SubGhzDView : public View {
|
||||
|
||||
std::unique_ptr<SubGhzDLogger> logger{};
|
||||
|
||||
const RecentEntriesColumns columns{{
|
||||
{"Type", 19},
|
||||
RecentEntriesColumns columns{{
|
||||
{"Type", 0},
|
||||
{"Bits", 4},
|
||||
{"Age", 3},
|
||||
}};
|
||||
@@ -191,16 +191,16 @@ class SubGhzDRecentEntryDetailView : public View {
|
||||
uint32_t cnt = SD_NO_CNT;
|
||||
uint32_t seed = 0;
|
||||
|
||||
Text text_type{{0 * 8, 1 * 16, 15 * 8, 16}, "?"};
|
||||
Text text_type{{UI_POS_X(0), 1 * 16, 15 * 8, 16}, "?"};
|
||||
Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, screen_width, screen_height - (4 * 16) - 36}};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Serial: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Data:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 2 * 16}, "Serial: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Data:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Button button_done{
|
||||
|
||||
@@ -76,29 +76,29 @@ class TestView : public View {
|
||||
bool logging{false};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Data:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 1 * 16}, "Data:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), 0 * 8},
|
||||
nav_};
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{13 * 8, UI_POS_Y(0)}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{15 * 8, UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4},
|
||||
};
|
||||
|
||||
Text text_debug_a{
|
||||
{0 * 8, 4 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 4 * 16, screen_width, 16},
|
||||
"..."};
|
||||
Text text_debug_b{
|
||||
{0 * 8, 5 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 5 * 16, screen_width, 16},
|
||||
"..."};
|
||||
|
||||
Button button_cal{
|
||||
|
||||
@@ -427,7 +427,7 @@ void TextViewer::set_font_zoom(bool zoom) {
|
||||
/* TextEditorMenu ***************************************************/
|
||||
|
||||
TextEditorMenu::TextEditorMenu()
|
||||
: View{{7 * 4, 9 * 4, 25 * 8, 25 * 8}} {
|
||||
: View{{UI_POS_X_CENTER(25), 9 * 4, 25 * 8, 25 * 8}} {
|
||||
add_children(
|
||||
{
|
||||
&rect_frame,
|
||||
|
||||
@@ -164,7 +164,7 @@ class TextEditorMenu : public View {
|
||||
void hide_children(bool hidden);
|
||||
|
||||
Rectangle rect_frame{
|
||||
{0 * 8, 0 * 8, 23 * 8, 23 * 8},
|
||||
{UI_POS_X(0), 0 * 8, 23 * 8, 23 * 8},
|
||||
Theme::getInstance()->fg_dark->foreground};
|
||||
|
||||
NewButton button_home{
|
||||
@@ -267,23 +267,23 @@ class TextEditorView : public View {
|
||||
|
||||
TextViewer viewer{
|
||||
/* 272 = screen_height - 16 (top bar) - 32 (bottom controls) */
|
||||
{0, 0, screen_width, 272}};
|
||||
{0, 0, screen_width, UI_POS_HEIGHT_REMAINING(4)}};
|
||||
|
||||
TextEditorMenu menu{};
|
||||
|
||||
NewButton button_menu{
|
||||
{26 * 8, 34 * 8, 4 * 8, 4 * 8},
|
||||
{UI_POS_X_RIGHT(4), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
{},
|
||||
&bitmap_icon_controls,
|
||||
Theme::getInstance()->bg_dark->background,
|
||||
/*vcenter*/ true};
|
||||
|
||||
Text text_position{
|
||||
{0 * 8, 34 * 8, 26 * 8, 2 * 8},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH_REMAINING(5), UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
|
||||
Text text_size{
|
||||
{0 * 8, 36 * 8, 26 * 8, 2 * 8},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(2), UI_POS_WIDTH_REMAINING(5), UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
};
|
||||
|
||||
|
||||
@@ -162,16 +162,16 @@ class TouchTunesView : public View {
|
||||
{{18 * 8 + 4, 18 * 8}, "V"},
|
||||
{{22 * 8, 18 * 8}, "F4"},
|
||||
|
||||
{{0 * 8, 5 * 8}, "1"},
|
||||
{{UI_POS_X(0), 5 * 8}, "1"},
|
||||
{{4 * 8, 5 * 8}, "2"},
|
||||
{{8 * 8, 5 * 8}, "3"},
|
||||
{{0 * 8, 10 * 8}, "4"},
|
||||
{{UI_POS_X(0), 10 * 8}, "4"},
|
||||
{{4 * 8, 10 * 8}, "5"},
|
||||
{{8 * 8, 10 * 8}, "6"},
|
||||
{{0 * 8, 15 * 8}, "7"},
|
||||
{{UI_POS_X(0), 15 * 8}, "7"},
|
||||
{{4 * 8, 15 * 8}, "8"},
|
||||
{{8 * 8, 15 * 8}, "9"},
|
||||
{{0 * 8, 20 * 8}, "*"},
|
||||
{{UI_POS_X(0), 20 * 8}, "*"},
|
||||
{{4 * 8, 20 * 8}, "0"},
|
||||
{{8 * 8, 20 * 8}, "#"},
|
||||
|
||||
|
||||
@@ -270,16 +270,13 @@ void RecentEntriesTable<ui::WeatherRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
std::string line{};
|
||||
line.reserve(30);
|
||||
|
||||
line = WeatherView::getWeatherSensorTypeName((FPROTO_WEATHER_SENSOR)entry.sensorType);
|
||||
if (line.length() < 10) {
|
||||
line += WeatherView::pad_string_with_spaces(10 - line.length());
|
||||
} else {
|
||||
line = truncate(line, 10);
|
||||
}
|
||||
line.resize(columns.at(0).second, ' ');
|
||||
|
||||
std::string temp = (weather_units_fahr ? to_string_decimal((entry.temp * 9 / 5) + 32, 1) : to_string_decimal(entry.temp, 1));
|
||||
std::string humStr = (entry.humidity != WS_NO_HUMIDITY) ? to_string_dec_uint(entry.humidity) + "%" : "-";
|
||||
|
||||
@@ -134,28 +134,28 @@ class WeatherView : public View {
|
||||
WeatherRecentEntries recent{};
|
||||
|
||||
OptionsField options_temperature{
|
||||
{10 * 8, 0 * 16},
|
||||
{10 * 8, UI_POS_Y(0)},
|
||||
2,
|
||||
{{STR_DEGREES_C, 0},
|
||||
{STR_DEGREES_F, 1}}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{13 * 8, UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{15 * 8, UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{21 * 8, 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4},
|
||||
{21 * 8, 5, UI_POS_WIDTH_REMAINING(24), 4},
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
SignalToken signal_token_tick_second{};
|
||||
@@ -174,8 +174,8 @@ class WeatherView : public View {
|
||||
|
||||
std::unique_ptr<WeatherLogger> logger{};
|
||||
|
||||
const RecentEntriesColumns columns{{
|
||||
{"Type", 10},
|
||||
RecentEntriesColumns columns{{
|
||||
{"Type", 0},
|
||||
{"Temp", 5},
|
||||
{"Hum", 4},
|
||||
{"Ch", 3},
|
||||
@@ -218,14 +218,14 @@ class WeatherRecentEntryDetailView : public View {
|
||||
Text text_age{{10 * 8, 7 * 16, 10 * 8, 16}, "?"};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Weather Station", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 1 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Id: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Temp:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "Humidity:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Channel:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 6 * 16}, "Battery:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "Age:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Weather Station", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 2 * 16}, "Id: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Temp:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 4 * 16}, "Humidity:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 5 * 16}, "Channel:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 6 * 16}, "Battery:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "Age:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Button button_done{
|
||||
|
||||
Reference in New Issue
Block a user