mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-10 08:39:29 +00:00
Multi screen support, with dyn alignment (#2801)
This commit is contained in:
+6
-6
@@ -67,18 +67,18 @@ class ACARSAppView : public View {
|
||||
uint32_t packet_counter{0};
|
||||
|
||||
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), 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), 0 * 8},
|
||||
nav_};
|
||||
Checkbox check_log{
|
||||
{16 * 8, 1 * 16},
|
||||
|
||||
+2
-2
@@ -62,7 +62,7 @@ class ADSBPositionView : public OptionTabView {
|
||||
GeoPos::HIDDEN};
|
||||
|
||||
Button button_set_map{
|
||||
{8 * 8, 6 * 16, 14 * 8, 2 * 16},
|
||||
{UI_POS_X_CENTER(14), 6 * 16, 14 * 8, 2 * 16},
|
||||
"Set from map"};
|
||||
};
|
||||
|
||||
@@ -244,7 +244,7 @@ class ADSBTxView : public View {
|
||||
"-"};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
1000000,
|
||||
0};
|
||||
|
||||
|
||||
+9
-9
@@ -73,31 +73,31 @@ class AFSKRxView : public View {
|
||||
bool logging{false};
|
||||
|
||||
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), 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
Checkbox check_log{
|
||||
{0 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 1 * 16},
|
||||
3,
|
||||
LanguageHelper::currentMessages[LANG_LOG],
|
||||
false};
|
||||
|
||||
Text text_debug{
|
||||
{0 * 8, 12 + 2 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 12 + 2 * 16, screen_width, 16},
|
||||
LanguageHelper::currentMessages[LANG_DEBUG]};
|
||||
|
||||
Button button_modem_setup{
|
||||
|
||||
@@ -58,8 +58,8 @@ class AnalogTvView : public View {
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_tv", app_settings::Mode::RX};
|
||||
|
||||
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), 1 * 16, screen_width, 1 * 16};
|
||||
const Rect nbfm_view_rect{UI_POS_X(0), 1 * 16, 18 * 8, 1 * 16};
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
@@ -71,17 +71,17 @@ class AnalogTvView : public View {
|
||||
{21 * 8, 10, 6 * 8, 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{5 * 8, 0 * 16},
|
||||
{5 * 8, UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
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)}};
|
||||
|
||||
OptionsField options_modulation{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
4,
|
||||
{
|
||||
{"TV ", toUType(ReceiverModel::Mode::WidebandFMAudio)},
|
||||
@@ -90,7 +90,7 @@ class AnalogTvView : public View {
|
||||
}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{27 * 8, 0 * 16}};
|
||||
{27 * 8, UI_POS_Y(0)}};
|
||||
|
||||
std::unique_ptr<Widget> options_widget{};
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ class WhipCalcView : public View {
|
||||
{0, 6 * 16, screen_width, 160}};
|
||||
|
||||
Button button_exit{
|
||||
{72, 17 * 16, 96, 32},
|
||||
{UI_POS_X_RIGHT(12), UI_POS_Y_BOTTOM(3), 96, 32},
|
||||
"Back"};
|
||||
};
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ AppManagerView::AppManagerView(NavigationView& nav)
|
||||
&button_set_cancel_autostart,
|
||||
&button_clean_autostart});
|
||||
|
||||
menu_view.set_parent_rect({0, 2 * 8, screen_width, 24 * 8});
|
||||
menu_view.set_parent_rect({0, 2 * 8, screen_width, UI_POS_HEIGHT_REMAINING(7)});
|
||||
|
||||
menu_view.on_highlight = [this]() {
|
||||
if (menu_view.highlighted_index() >= app_list_index) {
|
||||
|
||||
@@ -43,28 +43,28 @@ class AppManagerView : public View {
|
||||
uint16_t app_list_index{0};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "App list:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "App list:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
MenuView menu_view{};
|
||||
|
||||
Text text_app_info{
|
||||
{0, 27 * 8, screen_width, 16},
|
||||
{0, UI_POS_Y_BOTTOM(6), screen_width, UI_POS_HEIGHT(1)},
|
||||
"Highlight an app"};
|
||||
|
||||
Button button_hide_unhide{
|
||||
{0, 29 * 8, screen_width / 2 - 1, 32},
|
||||
{0, UI_POS_Y_BOTTOM(5), screen_width / 2 - 1, UI_POS_HEIGHT(2)},
|
||||
"Hide/Show"};
|
||||
|
||||
Button button_clean_hide{
|
||||
{screen_width / 2 + 2, 29 * 8, screen_width / 2 - 2, 32},
|
||||
{screen_width / 2 + 2, UI_POS_Y_BOTTOM(5), screen_width / 2 - 2, UI_POS_HEIGHT(2)},
|
||||
"Clean Hidden"};
|
||||
|
||||
Button button_set_cancel_autostart{
|
||||
{0, screen_height - 32 - 16, screen_width / 2 - 1, 32},
|
||||
{0, screen_height - 32 - 16, screen_width / 2 - 1, UI_POS_HEIGHT(2)},
|
||||
"Set Autostart"};
|
||||
|
||||
Button button_clean_autostart{
|
||||
{screen_width / 2 + 2, screen_height - 32 - 16, screen_width / 2 - 2, 32},
|
||||
{screen_width / 2 + 2, screen_height - 32 - 16, screen_width / 2 - 2, UI_POS_HEIGHT(2)},
|
||||
"Del Autostart"};
|
||||
|
||||
std::string get_app_info(uint16_t index, bool is_display_name);
|
||||
|
||||
@@ -44,13 +44,13 @@ class AudioTestView : public View {
|
||||
bool beep{false};
|
||||
|
||||
Labels labels{
|
||||
{{7 * 8, 3 * 16}, "Audio Beep Test", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 6 * 16}, "Sample Rate (Hz):", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(16), 3 * 16}, "Audio Beep Test", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 6 * 16}, "Sample Rate (Hz):", Theme::getInstance()->fg_light->foreground},
|
||||
{{25 * 8, 7 * 16}, "Step:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 8 * 16}, "Frequency (Hz):", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 10 * 16}, "Duration (ms):", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 8 * 16}, "Frequency (Hz):", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 10 * 16}, "Duration (ms):", Theme::getInstance()->fg_light->foreground},
|
||||
{{25 * 8, 10 * 16}, "0=con", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 12 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 12 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_sample_rate{
|
||||
{18 * 8, 6 * 16},
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 "bht.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
namespace ui::external_app::bht_tx {
|
||||
|
||||
size_t gen_message_ep(uint8_t city_code, size_t family_code_ep, uint32_t relay_number, uint32_t relay_state) {
|
||||
size_t c;
|
||||
const encoder_def_t* um3750_def;
|
||||
uint8_t bits[12];
|
||||
std::string ep_fragments;
|
||||
|
||||
// Pre-allocate to avoid fragmentation.
|
||||
ep_fragments.reserve(384);
|
||||
|
||||
// Repeated 2x 26 times
|
||||
// Whole frame + space = 128ms, data only = 64ms
|
||||
|
||||
um3750_def = &encoder_defs[ENCODER_UM3750];
|
||||
|
||||
// City code is bit-reversed
|
||||
for (c = 0; c < 8; c++)
|
||||
bits[c] = (city_code >> c) & 1;
|
||||
|
||||
bits[8] = (family_code_ep >> 1) & 1;
|
||||
bits[9] = family_code_ep & 1;
|
||||
bits[10] = relay_number & 1;
|
||||
bits[11] = relay_state ? 1 : 0;
|
||||
|
||||
// Text for display
|
||||
// for (c = 0; c < 12; c++)
|
||||
// ep_message[c] = bits[c] + '0';
|
||||
|
||||
c = 0;
|
||||
for (auto ch : um3750_def->word_format) {
|
||||
if (ch == 'S')
|
||||
ep_fragments += um3750_def->sync;
|
||||
else
|
||||
ep_fragments += um3750_def->bit_format[bits[c++]];
|
||||
}
|
||||
|
||||
// Return bitstream length
|
||||
return make_bitstream(ep_fragments);
|
||||
}
|
||||
|
||||
std::string gen_message_xy(const std::string& ascii_code) {
|
||||
std::string local_code = ascii_code;
|
||||
uint8_t ccir_message[XY_TONE_COUNT];
|
||||
uint8_t translate;
|
||||
uint32_t c;
|
||||
|
||||
// Replace repeats with E code
|
||||
for (c = 1; c < XY_TONE_COUNT; c++)
|
||||
if (local_code[c] == local_code[c - 1]) local_code[c] = 'E';
|
||||
|
||||
for (c = 0; c < XY_TONE_COUNT; c++) {
|
||||
if (local_code[c] <= '9')
|
||||
translate = local_code[c] - '0';
|
||||
else
|
||||
translate = local_code[c] - 'A' + 10;
|
||||
ccir_message[c] = (translate < 16) ? translate : 0; // Sanitize
|
||||
}
|
||||
|
||||
// Copy for baseband
|
||||
memcpy(shared_memory.bb_data.tones_data.message, ccir_message, XY_TONE_COUNT);
|
||||
|
||||
// Return as text for display
|
||||
return local_code;
|
||||
}
|
||||
|
||||
std::string gen_message_xy(size_t header_code_a, size_t header_code_b, size_t city_code, size_t family_code, bool subfamily_wc, size_t subfamily_code, bool id_wc, size_t receiver_code, size_t relay_state_A, size_t relay_state_B, size_t relay_state_C, size_t relay_state_D) {
|
||||
uint8_t ccir_message[XY_TONE_COUNT];
|
||||
size_t c;
|
||||
|
||||
// Header
|
||||
ccir_message[0] = (header_code_a / 10);
|
||||
ccir_message[1] = (header_code_a % 10);
|
||||
ccir_message[2] = (header_code_b / 10);
|
||||
ccir_message[3] = (header_code_b % 10);
|
||||
|
||||
// Addresses
|
||||
ccir_message[4] = (city_code / 10);
|
||||
ccir_message[5] = (city_code % 10);
|
||||
ccir_message[6] = family_code;
|
||||
|
||||
if (subfamily_wc)
|
||||
ccir_message[7] = 0xA; // Wildcard
|
||||
else
|
||||
ccir_message[7] = subfamily_code;
|
||||
|
||||
if (id_wc) {
|
||||
ccir_message[8] = 0xA; // Wildcard
|
||||
ccir_message[9] = 0xA; // Wildcard
|
||||
} else {
|
||||
ccir_message[8] = (receiver_code / 10);
|
||||
ccir_message[9] = (receiver_code % 10);
|
||||
}
|
||||
|
||||
ccir_message[10] = 0xB;
|
||||
|
||||
// Relay states
|
||||
ccir_message[11] = relay_state_A;
|
||||
ccir_message[12] = relay_state_B;
|
||||
ccir_message[13] = relay_state_C;
|
||||
ccir_message[14] = relay_state_D;
|
||||
|
||||
ccir_message[15] = 0xB;
|
||||
|
||||
// End
|
||||
for (c = 16; c < XY_TONE_COUNT; c++)
|
||||
ccir_message[c] = 0;
|
||||
|
||||
// Replace repeats with E code
|
||||
for (c = 1; c < XY_TONE_COUNT; c++)
|
||||
if (ccir_message[c] == ccir_message[c - 1]) ccir_message[c] = 0xE;
|
||||
|
||||
// Copy for baseband
|
||||
memcpy(shared_memory.bb_data.tones_data.message, ccir_message, XY_TONE_COUNT);
|
||||
|
||||
// Return as text for display
|
||||
return ccir_to_ascii(ccir_message);
|
||||
}
|
||||
|
||||
std::string ccir_to_ascii(uint8_t* ccir) {
|
||||
std::string ascii;
|
||||
|
||||
for (size_t c = 0; c < XY_TONE_COUNT; c++) {
|
||||
if (ccir[c] > 9)
|
||||
ascii += (char)(ccir[c] - 10 + 'A');
|
||||
else
|
||||
ascii += (char)(ccir[c] + '0');
|
||||
}
|
||||
|
||||
return ascii;
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::bht_tx
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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_navigation.hpp"
|
||||
|
||||
#include "tonesets.hpp"
|
||||
#include "encoders.hpp"
|
||||
|
||||
using namespace encoders;
|
||||
|
||||
namespace ui::external_app::bht_tx {
|
||||
|
||||
#define XY_TONE_DURATION ((TONES_SAMPLERATE * 0.1) - 1) // 100ms
|
||||
#define XY_SILENCE (TONES_SAMPLERATE * 0.4) // 400ms
|
||||
#define XY_TONE_COUNT 20
|
||||
#define XY_MAX_CITY 99
|
||||
|
||||
#define EPAR_BIT_DURATION (OOK_SAMPLERATE / 580)
|
||||
#define EPAR_REPEAT_COUNT 26
|
||||
#define EPAR_MAX_CITY 255
|
||||
|
||||
struct bht_city {
|
||||
std::string name;
|
||||
uint8_t freq_index;
|
||||
bool recent;
|
||||
};
|
||||
|
||||
size_t gen_message_ep(uint8_t city_code, size_t family_code_ep, uint32_t relay_state_A, uint32_t relay_state_B);
|
||||
std::string gen_message_xy(const std::string& code);
|
||||
std::string gen_message_xy(size_t header_code_a, size_t header_code_b, size_t city_code, size_t family_code, bool subfamily_wc, size_t subfamily_code, bool id_wc, size_t receiver_code, size_t relay_state_A, size_t relay_state_B, size_t relay_state_C, size_t relay_state_D);
|
||||
std::string ccir_to_ascii(uint8_t* ccir);
|
||||
|
||||
} // namespace ui::external_app::bht_tx
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2024 EPIRB Decoder Implementation
|
||||
*
|
||||
* 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_bht_tx.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::bht_tx {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<BHTView>();
|
||||
}
|
||||
} // namespace ui::external_app::bht_tx
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_bht_tx.application_information"), used)) application_information_t _application_information_bht_tx = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::bht_tx::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "BHT TX",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0xE0,
|
||||
0x07,
|
||||
0xF8,
|
||||
0x08,
|
||||
0x9C,
|
||||
0x07,
|
||||
0x0C,
|
||||
0x00,
|
||||
0x8E,
|
||||
0x0A,
|
||||
0x46,
|
||||
0x12,
|
||||
0x26,
|
||||
0x22,
|
||||
0x06,
|
||||
0x02,
|
||||
0x06,
|
||||
0x00,
|
||||
0x06,
|
||||
0x00,
|
||||
0x06,
|
||||
0x00,
|
||||
0x06,
|
||||
0x00,
|
||||
0x06,
|
||||
0x00,
|
||||
0x06,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::TX,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_tones */ {'P', 'T', 'O', 'N'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* 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::external_app::bht_tx {
|
||||
|
||||
void BHTView::focus() {
|
||||
tx_view.focus();
|
||||
}
|
||||
|
||||
void BHTView::start_tx() {
|
||||
baseband::shutdown();
|
||||
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
|
||||
if (target_system == XYLOS) {
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
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::external_app::bht_tx
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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::external_app::bht_tx {
|
||||
|
||||
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{
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(5), screen_width, 16},
|
||||
};
|
||||
|
||||
TransmitterView tx_view{
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
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::external_app::bht_tx
|
||||
+24
-24
@@ -70,7 +70,7 @@ void BlackjackView::frame_sync() {
|
||||
}
|
||||
|
||||
void BlackjackView::clear_screen() {
|
||||
painter.fill_rectangle({0, 0, 240, 320}, Color::black());
|
||||
painter.fill_rectangle({0, 0, screen_width, screen_height}, Color::black());
|
||||
}
|
||||
|
||||
void BlackjackView::init_deck() {
|
||||
@@ -265,24 +265,24 @@ void BlackjackView::draw_menu_static() {
|
||||
auto style_text = *ui::Theme::getInstance()->fg_light;
|
||||
auto style_rules = *ui::Theme::getInstance()->fg_cyan;
|
||||
|
||||
painter.draw_string({84, 20}, style_title, "BLACKJACK");
|
||||
painter.draw_string({UI_POS_X_CENTER(10), 20}, style_title, "BLACKJACK");
|
||||
|
||||
// Draw rules
|
||||
painter.draw_string({70, 55}, style_rules, "-- RULES --");
|
||||
painter.draw_string({61, 75}, style_text, "Get close to 21");
|
||||
painter.draw_string({61, 90}, style_text, "without going over");
|
||||
painter.draw_string({61, 110}, style_text, "Dealer hits on 16");
|
||||
painter.draw_string({61, 125}, style_text, "Dealer stays on 17");
|
||||
painter.draw_string({61, 145}, style_text, "Blackjack pays 1:1");
|
||||
painter.draw_string({UI_POS_X_CENTER(12), 55}, style_rules, "-- RULES --");
|
||||
painter.draw_string({UI_POS_X_CENTER(16), 75}, style_text, "Get close to 21");
|
||||
painter.draw_string({UI_POS_X_CENTER(19), 90}, style_text, "without going over");
|
||||
painter.draw_string({UI_POS_X_CENTER(18), 110}, style_text, "Dealer hits on 16");
|
||||
painter.draw_string({UI_POS_X_CENTER(19), 125}, style_text, "Dealer stays on 17");
|
||||
painter.draw_string({UI_POS_X_CENTER(19), 145}, style_text, "Blackjack pays 1:1");
|
||||
|
||||
// Controls
|
||||
painter.draw_string({65, 175}, style_rules, "-- CONTROLS --");
|
||||
painter.draw_string({61, 195}, style_text, "SELECT: Start/Hit");
|
||||
painter.draw_string({61, 210}, style_text, "LEFT: Stats");
|
||||
painter.draw_string({61, 225}, style_text, "RIGHT: Exit/Stay");
|
||||
painter.draw_string({UI_POS_X_CENTER(15), 175}, style_rules, "-- CONTROLS --");
|
||||
painter.draw_string({UI_POS_X_CENTER(18), 195}, style_text, "SELECT: Start/Hit");
|
||||
painter.draw_string({UI_POS_X_CENTER(12), 210}, style_text, "LEFT: Stats");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 225}, style_text, "RIGHT: Exit/Stay");
|
||||
|
||||
// Draw high score
|
||||
painter.draw_string({61, 250}, style_text, "High Score: $" + std::to_string(high_score));
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 250}, style_text, "High Score: $" + std::to_string(high_score));
|
||||
}
|
||||
|
||||
void BlackjackView::draw_menu() {
|
||||
@@ -293,10 +293,10 @@ void BlackjackView::draw_menu() {
|
||||
|
||||
if (blink_state) {
|
||||
auto style = *ui::Theme::getInstance()->fg_yellow;
|
||||
painter.draw_string({55, 280}, style, "* PRESS SELECT *");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 280}, style, "* PRESS SELECT *");
|
||||
} else {
|
||||
// Clear just the text area
|
||||
painter.fill_rectangle({55, 278, 130, 20}, Color::black());
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(17), 278, 130, 20}, Color::black());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,27 +308,27 @@ void BlackjackView::draw_stats() {
|
||||
auto style_text = *ui::Theme::getInstance()->fg_light;
|
||||
auto style_value = *ui::Theme::getInstance()->fg_yellow;
|
||||
|
||||
painter.draw_string({75, 30}, style_title, "STATISTICS");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 30}, style_title, "STATISTICS");
|
||||
|
||||
painter.draw_string({30, 80}, style_text, "Wins:");
|
||||
painter.draw_string({150, 80}, style_value, std::to_string(wins));
|
||||
painter.draw_string({UI_POS_X_CENTER(5), 80}, style_value, std::to_string(wins));
|
||||
|
||||
painter.draw_string({30, 100}, style_text, "Losses:");
|
||||
painter.draw_string({150, 100}, style_value, std::to_string(losses));
|
||||
painter.draw_string({UI_POS_X_CENTER(5), 100}, style_value, std::to_string(losses));
|
||||
|
||||
// Win percentage
|
||||
uint32_t total = wins + losses;
|
||||
if (total > 0) {
|
||||
uint32_t win_pct = (wins * 100) / total;
|
||||
painter.draw_string({30, 120}, style_text, "Win %:");
|
||||
painter.draw_string({150, 120}, style_value, std::to_string(win_pct) + "%");
|
||||
painter.draw_string({UI_POS_X_CENTER(5), 120}, style_value, std::to_string(win_pct) + "%");
|
||||
}
|
||||
|
||||
painter.draw_string({30, 160}, style_text, "High Score:");
|
||||
painter.draw_string({150, 160}, style_value, "$" + std::to_string(high_score));
|
||||
painter.draw_string({UI_POS_X_CENTER(5), 160}, style_value, "$" + std::to_string(high_score));
|
||||
|
||||
painter.draw_string({30, 180}, style_text, "Cash:");
|
||||
painter.draw_string({150, 180}, style_value, "$" + std::to_string(cash));
|
||||
painter.draw_string({UI_POS_X_CENTER(5), 180}, style_value, "$" + std::to_string(cash));
|
||||
|
||||
painter.draw_string({40, 250}, style_text, "SELECT: Back");
|
||||
}
|
||||
@@ -416,7 +416,7 @@ void BlackjackView::draw_game() {
|
||||
}
|
||||
|
||||
// Draw result
|
||||
painter.draw_string({60, 270}, *style_result, result);
|
||||
painter.draw_string({UI_POS_X_CENTER(result.length()), 270}, *style_result, result);
|
||||
|
||||
// Draw compact bet selector in top right area
|
||||
auto style_bet = *ui::Theme::getInstance()->fg_cyan;
|
||||
@@ -620,8 +620,8 @@ void BlackjackView::draw_card(int x, int y, uint8_t card, bool hidden) {
|
||||
void BlackjackView::draw_hand(int x, int y, uint8_t* cards, uint8_t count, bool is_dealer) {
|
||||
// Calculate total width needed
|
||||
const int card_width = 60;
|
||||
const int overlap = 40; // Amount of overlap when cards need to fit
|
||||
const int max_width = 230 - x; // Available width on screen
|
||||
const int overlap = 40; // Amount of overlap when cards need to fit
|
||||
const int max_width = screen_width - 10 - x; // Available width on screen
|
||||
|
||||
int spacing;
|
||||
if (count == 1) {
|
||||
|
||||
@@ -141,7 +141,7 @@ class BlackjackView : public View {
|
||||
{"highscore"sv, &high_score}}};
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
{screen_width, 0, 0, 0},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
|
||||
+3
-3
@@ -104,10 +104,10 @@ class BLESpamView : public View {
|
||||
4'000'000 /* sampling rate */
|
||||
};
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
TransmitterView2 tx_view{
|
||||
{11 * 8, 0 * 16},
|
||||
{11 * 8, UI_POS_Y(0)},
|
||||
/*short_ui*/ true};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_blespam", app_settings::Mode::TX};
|
||||
@@ -122,7 +122,7 @@ class BLESpamView : public View {
|
||||
{0, 70, screen_width, 220}};
|
||||
#endif
|
||||
OptionsField options_atkmode{
|
||||
{0 * 8, 2 * 8},
|
||||
{UI_POS_X(0), 2 * 8},
|
||||
10,
|
||||
{{"Android", 0},
|
||||
{"iOs", 1},
|
||||
|
||||
+11
-11
@@ -333,11 +333,11 @@ void BreakoutView::show_menu() {
|
||||
auto style_blue = *ui::Theme::getInstance()->fg_blue;
|
||||
auto style_cyan = *ui::Theme::getInstance()->fg_cyan;
|
||||
|
||||
painter.draw_string({50, 40}, style_yellow, "*** BREAKOUT ***");
|
||||
painter.draw_string({20, 100}, style_blue, "========================");
|
||||
painter.draw_string({30, 130}, style_cyan, "ROTARY: MOVE PADDLE");
|
||||
painter.draw_string({30, 160}, style_cyan, "SELECT: START/LAUNCH");
|
||||
painter.draw_string({20, 190}, style_blue, "========================");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 40}, style_yellow, "*** BREAKOUT ***");
|
||||
painter.draw_string({UI_POS_X_CENTER(25), 100}, style_blue, "========================");
|
||||
painter.draw_string({UI_POS_X_CENTER(20), 130}, style_cyan, "ROTARY: MOVE PADDLE");
|
||||
painter.draw_string({UI_POS_X_CENTER(21), 160}, style_cyan, "SELECT: START/LAUNCH");
|
||||
painter.draw_string({UI_POS_X_CENTER(25), 190}, style_blue, "========================");
|
||||
}
|
||||
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
@@ -346,10 +346,10 @@ void BreakoutView::show_menu() {
|
||||
menu_blink_counter = 0;
|
||||
menu_blink_state = !menu_blink_state;
|
||||
|
||||
painter.fill_rectangle({56, 228, 128, 20}, Color::black());
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(17), 228, 128, 20}, Color::black());
|
||||
|
||||
if (menu_blink_state) {
|
||||
painter.draw_string({56, 230}, style_red, "* PRESS SELECT *");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 230}, style_red, "* PRESS SELECT *");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,8 +362,8 @@ void BreakoutView::show_game_over() {
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
auto style_yellow = *ui::Theme::getInstance()->fg_yellow;
|
||||
|
||||
painter.draw_string({90, 100}, style_red, "GAME OVER");
|
||||
painter.draw_string({50, 150}, style_yellow, "SCORE: " + std::to_string(score));
|
||||
painter.draw_string({UI_POS_X_CENTER(10), 100}, style_red, "GAME OVER");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 150}, style_yellow, "SCORE: " + std::to_string(score));
|
||||
}
|
||||
|
||||
auto style_green = *ui::Theme::getInstance()->fg_green;
|
||||
@@ -372,10 +372,10 @@ void BreakoutView::show_game_over() {
|
||||
gameover_blink_counter = 0;
|
||||
gameover_blink_state = !gameover_blink_state;
|
||||
|
||||
painter.fill_rectangle({72, 198, 96, 20}, Color::black());
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(13), 198, 96, 20}, Color::black());
|
||||
|
||||
if (gameover_blink_state) {
|
||||
painter.draw_string({72, 200}, style_green, "PRESS SELECT");
|
||||
painter.draw_string({UI_POS_X_CENTER(13), 200}, style_green, "PRESS SELECT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -48,25 +48,25 @@ class CalculatorView : public View {
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
Button button_F{{0 * 8, 11 * 16, 6 * 8, 16 + 8}, "F"};
|
||||
Button button_7{{8 * 8, 11 * 16, 6 * 8, 16 + 8}, "7"};
|
||||
Button button_8{{16 * 8, 11 * 16, 6 * 8, 16 + 8}, "8"};
|
||||
Button button_9{{24 * 8, 11 * 16, 6 * 8, 16 + 8}, "9"};
|
||||
Button button_E{{0 * 8, 13 * 16, 6 * 8, 16 + 8}, "E"};
|
||||
Button button_4{{8 * 8, 13 * 16, 6 * 8, 16 + 8}, "4"};
|
||||
Button button_5{{16 * 8, 13 * 16, 6 * 8, 16 + 8}, "5"};
|
||||
Button button_6{{24 * 8, 13 * 16, 6 * 8, 16 + 8}, "6"};
|
||||
Button button_N{{0 * 8, 15 * 16, 6 * 8, 16 + 8}, "N"};
|
||||
Button button_1{{8 * 8, 15 * 16, 6 * 8, 16 + 8}, "1"};
|
||||
Button button_2{{16 * 8, 15 * 16, 6 * 8, 16 + 8}, "2"};
|
||||
Button button_3{{24 * 8, 15 * 16, 6 * 8, 16 + 8}, "3"};
|
||||
Button button_C{{0 * 8, 17 * 16, 6 * 8, 16 + 8}, "C"};
|
||||
Button button_0{{8 * 8, 17 * 16, 6 * 8, 16 + 8}, "0"};
|
||||
Button button_P{{16 * 8, 17 * 16, 6 * 8, 16 + 8}, "."};
|
||||
Button button_D{{24 * 8, 17 * 16, 6 * 8, 16 + 8}, "D"};
|
||||
Button button_F{{UI_POS_X_TABLE(4, 0), UI_POS_Y_BOTTOM(9), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "F"};
|
||||
Button button_7{{UI_POS_X_TABLE(4, 1), UI_POS_Y_BOTTOM(9), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "7"};
|
||||
Button button_8{{UI_POS_X_TABLE(4, 2), UI_POS_Y_BOTTOM(9), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "8"};
|
||||
Button button_9{{UI_POS_X_TABLE(4, 3), UI_POS_Y_BOTTOM(9), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "9"};
|
||||
Button button_E{{UI_POS_X_TABLE(4, 0), UI_POS_Y_BOTTOM(7), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "E"};
|
||||
Button button_4{{UI_POS_X_TABLE(4, 1), UI_POS_Y_BOTTOM(7), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "4"};
|
||||
Button button_5{{UI_POS_X_TABLE(4, 2), UI_POS_Y_BOTTOM(7), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "5"};
|
||||
Button button_6{{UI_POS_X_TABLE(4, 3), UI_POS_Y_BOTTOM(7), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "6"};
|
||||
Button button_N{{UI_POS_X_TABLE(4, 0), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "N"};
|
||||
Button button_1{{UI_POS_X_TABLE(4, 1), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "1"};
|
||||
Button button_2{{UI_POS_X_TABLE(4, 2), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "2"};
|
||||
Button button_3{{UI_POS_X_TABLE(4, 3), UI_POS_Y_BOTTOM(5), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "3"};
|
||||
Button button_C{{UI_POS_X_TABLE(4, 0), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "C"};
|
||||
Button button_0{{UI_POS_X_TABLE(4, 1), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "0"};
|
||||
Button button_P{{UI_POS_X_TABLE(4, 2), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "."};
|
||||
Button button_D{{UI_POS_X_TABLE(4, 3), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(6), UI_POS_HEIGHT(1.5)}, "D"};
|
||||
|
||||
Console console{
|
||||
{0 * 8, 0 * 16, screen_width, 10 * 16}};
|
||||
{UI_POS_X(0), UI_POS_Y(0), screen_width, UI_POS_HEIGHT_REMAINING(10)}};
|
||||
|
||||
void on_button_press(uint8_t button);
|
||||
void update_button_labels();
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ class CoasterPagerView : public View {
|
||||
""};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
10000,
|
||||
12};
|
||||
|
||||
|
||||
+9
-9
@@ -53,38 +53,38 @@ class CVSSpamView : public View {
|
||||
std::vector<std::filesystem::path> file_list{};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 0, screen_width, 180},
|
||||
{0, 0, screen_width, UI_POS_HEIGHT_REMAINING(12)},
|
||||
true};
|
||||
|
||||
Text text_empty{
|
||||
{7 * 8, 12 * 8, 16 * 8, 16},
|
||||
{UI_POS_X_CENTER(16), 12 * 8, UI_POS_WIDTH(16), UI_POS_HEIGHT(1)},
|
||||
"Empty directory!"};
|
||||
|
||||
Button button_prev_page{
|
||||
{0, 180, 50, 32},
|
||||
{0, UI_POS_Y_BOTTOM(10), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
"<"};
|
||||
|
||||
Button button_next_page{
|
||||
{190, 180, 50, 32},
|
||||
{UI_POS_X_RIGHT(3), UI_POS_Y_BOTTOM(10), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)},
|
||||
">"};
|
||||
|
||||
Text page_info{
|
||||
{95, 188, 50, 16}};
|
||||
{UI_POS_X_CENTER(7), UI_POS_Y_BOTTOM(9.5), UI_POS_WIDTH(7), UI_POS_HEIGHT(1)}};
|
||||
|
||||
Button button_send{
|
||||
{0, 212, 75, 36},
|
||||
{0, UI_POS_Y_BOTTOM(8), UI_POS_WIDTH(9), UI_POS_HEIGHT(2)},
|
||||
"CALL"};
|
||||
|
||||
Button button_chaos{
|
||||
{82, 212, 75, 36},
|
||||
{UI_POS_X_CENTER(9), UI_POS_Y_BOTTOM(8), UI_POS_WIDTH(9), UI_POS_HEIGHT(2)},
|
||||
"CHAOS"};
|
||||
|
||||
Button button_stop{
|
||||
{165, 212, 75, 36},
|
||||
{UI_POS_X_RIGHT(9), UI_POS_Y_BOTTOM(8), UI_POS_WIDTH(9), UI_POS_HEIGHT(2)},
|
||||
LanguageHelper::currentMessages[LANG_STOP]};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0, 256, screen_width, 44}};
|
||||
{0, UI_POS_Y_BOTTOM(6), screen_width, UI_POS_HEIGHT(5)}};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal{
|
||||
Message::ID::RequestSignal,
|
||||
|
||||
@@ -44,11 +44,11 @@ class DebugDumpView : public View {
|
||||
NavigationView& nav_;
|
||||
|
||||
Text dump_output{
|
||||
{0 * 8, 19 * 8, screen_width, 16},
|
||||
{UI_POS_X(0), 19 * 8, screen_width, 16},
|
||||
""};
|
||||
|
||||
Button button_exit{
|
||||
{22 * 8, 34 * 8, 8 * 8, 32},
|
||||
{UI_POS_X_CENTER(8), UI_POS_Y_BOTTOM(4), 8 * 8, 32},
|
||||
"Exit"};
|
||||
};
|
||||
|
||||
|
||||
@@ -77,7 +77,9 @@ class DetectorRxView : public View {
|
||||
}};
|
||||
|
||||
Labels labels{
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "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},
|
||||
};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{UI_POS_X(4), UI_POS_Y(0)}};
|
||||
@@ -89,7 +91,7 @@ class DetectorRxView : public View {
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{UI_POS_X(24), UI_POS_Y(0)}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
OptionsField field_mode{
|
||||
{UI_POS_X(0), UI_POS_Y(1)},
|
||||
|
||||
+12
-12
@@ -178,12 +178,12 @@ void DinoGameView::show_menu() {
|
||||
auto style_title = *ui::Theme::getInstance()->fg_light;
|
||||
|
||||
// Draw title
|
||||
painter.draw_string({80, 60}, style_title, "DINO GAME");
|
||||
painter.draw_string({UI_POS_X_CENTER(10), 60}, style_title, "DINO GAME");
|
||||
|
||||
// Draw instructions
|
||||
painter.draw_string({45, 130}, style, "SELECT: Jump/Start");
|
||||
painter.draw_string({65, 150}, style, "DOWN: Duck");
|
||||
painter.draw_string({50, 170}, style, "Avoid obstacles!");
|
||||
painter.draw_string({UI_POS_X_CENTER(19), 130}, style, "SELECT: Jump/Start");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 150}, style, "DOWN: Duck");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 170}, style, "Avoid obstacles!");
|
||||
|
||||
// Draw high score
|
||||
draw_high_score();
|
||||
@@ -209,9 +209,9 @@ void DinoGameView::show_menu() {
|
||||
blink_counter = 0;
|
||||
blink_state = !blink_state;
|
||||
|
||||
painter.fill_rectangle({55, 258, 130, 20}, Color::black());
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(17), 258, 130, 20}, Color::black());
|
||||
if (blink_state) {
|
||||
painter.draw_string({55, 260}, style_prompt, "* PRESS SELECT *");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 260}, style_prompt, "* PRESS SELECT *");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,19 +234,19 @@ void DinoGameView::show_game_over() {
|
||||
auto style_score = *ui::Theme::getInstance()->fg_medium;
|
||||
|
||||
// Game over text
|
||||
painter.draw_string({85, 70}, style, "GAME OVER");
|
||||
painter.draw_string({UI_POS_X_CENTER(10), 70}, style, "GAME OVER");
|
||||
|
||||
// Show final score
|
||||
std::string score_text = "SCORE: " + score_to_string(score);
|
||||
int score_x = (240 - score_text.length() * 8) / 2;
|
||||
int score_x = (screen_width - score_text.length() * 8) / 2;
|
||||
painter.draw_string({score_x, 90}, style_score, score_text);
|
||||
|
||||
painter.draw_string({65, 110}, style, "SELECT TO RETRY");
|
||||
painter.draw_string({UI_POS_X_CENTER(16), 110}, style, "SELECT TO RETRY");
|
||||
|
||||
// Update high score
|
||||
if (score > highScore) {
|
||||
highScore = score;
|
||||
painter.draw_string({55, 130}, style, "NEW HIGH SCORE!");
|
||||
painter.draw_string({UI_POS_X_CENTER(16), 130}, style, "NEW HIGH SCORE!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -743,8 +743,8 @@ void DinoGameView::draw_current_score() {
|
||||
|
||||
void DinoGameView::draw_high_score() {
|
||||
auto style = *ui::Theme::getInstance()->fg_light;
|
||||
painter.fill_rectangle({152, 28, 100, 14}, Color::black());
|
||||
painter.draw_string({152, 30}, style, "HI " + score_to_string(highScore));
|
||||
painter.fill_rectangle({UI_POS_X_RIGHT(9), 28, UI_POS_WIDTH(9), 18}, Color::black());
|
||||
painter.draw_string({UI_POS_X_RIGHT(9), 30}, style, "HI " + score_to_string(highScore));
|
||||
}
|
||||
|
||||
void DinoGameView::jump() {
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ class DinoGameView : public View {
|
||||
bool easy_mode = false;
|
||||
|
||||
Button button_difficulty{
|
||||
{70, 195, 100, 20},
|
||||
{UI_POS_X_CENTER(13), 195, 13 * 8, 20},
|
||||
"Mode: HARD"};
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
|
||||
+13
-13
@@ -197,11 +197,11 @@ class EPIRBAppView : public ui::View {
|
||||
static constexpr auto header_height = 4 * 16;
|
||||
|
||||
ui::Text label_frequency{
|
||||
{0 * 8, 0 * 16, 4 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), 4 * 8, 1 * 16},
|
||||
"Freq"};
|
||||
|
||||
ui::OptionsField options_frequency{
|
||||
{5 * 8, 0 * 16},
|
||||
{5 * 8, UI_POS_Y(0)},
|
||||
7,
|
||||
{
|
||||
{"406.028", 406028000},
|
||||
@@ -212,26 +212,26 @@ class EPIRBAppView : public ui::View {
|
||||
}};
|
||||
|
||||
ui::RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{13 * 8, UI_POS_Y(0)}};
|
||||
|
||||
ui::LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{15 * 8, UI_POS_Y(0)}};
|
||||
|
||||
ui::VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{18 * 8, UI_POS_Y(0)}};
|
||||
|
||||
ui::RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
|
||||
ui::AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{UI_POS_X(21), 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
|
||||
ui::Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
|
||||
ui::AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
|
||||
// Status display
|
||||
ui::Text label_status{
|
||||
{0 * 8, 1 * 16, 15 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 1 * 16, 15 * 8, 1 * 16},
|
||||
"Listening..."};
|
||||
|
||||
ui::Text label_beacons_count{
|
||||
@@ -239,12 +239,12 @@ class EPIRBAppView : public ui::View {
|
||||
"Beacons: 0"};
|
||||
|
||||
ui::Text label_packet_stats{
|
||||
{0 * 8, 3 * 16, 29 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 3 * 16, 29 * 8, 1 * 16},
|
||||
""};
|
||||
|
||||
// Latest beacon info display
|
||||
ui::Text label_latest{
|
||||
{0 * 8, 2 * 16, 8 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 2 * 16, 8 * 8, 1 * 16},
|
||||
"Latest:"};
|
||||
|
||||
ui::Text text_latest_info{
|
||||
|
||||
+5
-2
@@ -175,8 +175,11 @@ void RecentEntriesTable<ui::external_app::ert_app::ERTRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
std::string line = ert::format::id(entry.id) + " " + ert::format::commodity_type(entry.commodity_type) + " " + ert::format::consumption(entry.last_consumption) + " ";
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
std::string lid = ert::format::id(entry.id);
|
||||
lid.resize(columns.at(0).second, ' ');
|
||||
std::string line = lid + " " + ert::format::commodity_type(entry.commodity_type) + " " + ert::format::consumption(entry.last_consumption) + " ";
|
||||
|
||||
line += (entry.packet_type == ert::Packet::Type::SCM) ? ert::format::tamper_flags_scm(entry.last_tamper_flags) : ert::format::tamper_flags(entry.last_tamper_flags);
|
||||
line += (entry.received_count > 99) ? " ++" : to_string_dec_uint(entry.received_count, 3);
|
||||
|
||||
+8
-8
@@ -136,8 +136,8 @@ class ERTAppView : public View {
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_ert", app_settings::Mode::RX};
|
||||
|
||||
const RecentEntriesColumns columns{{
|
||||
{"ID", 10},
|
||||
RecentEntriesColumns columns{{
|
||||
{"ID", 0},
|
||||
{"Ty", 2},
|
||||
{"Consumpt", 8},
|
||||
{"Tamp", 4},
|
||||
@@ -148,24 +148,24 @@ class ERTAppView : public View {
|
||||
static constexpr auto header_height = 1 * 16;
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
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},
|
||||
{UI_POS_X(21), 0, UI_POS_WIDTH_REMAINING(24), 4},
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::ERTPacket,
|
||||
|
||||
@@ -249,6 +249,11 @@ set(EXTCPPSRC
|
||||
#game2048
|
||||
external/game2048/main.cpp
|
||||
external/game2048/ui_game2048.cpp
|
||||
|
||||
#bht_tx
|
||||
external/bht_tx/main.cpp
|
||||
external/bht_tx/ui_bht_tx.cpp
|
||||
external/bht_tx/bht.cpp
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -312,4 +317,5 @@ set(EXTAPPLIST
|
||||
epirb_rx
|
||||
soundboard
|
||||
game2048
|
||||
bht_tx
|
||||
)
|
||||
|
||||
+9
@@ -83,6 +83,7 @@ MEMORY
|
||||
ram_external_app_epirb_rx (rwx) : org = 0xADEA0000, len = 32k
|
||||
ram_external_app_soundboard (rwx) : org = 0xADEB0000, len = 32k
|
||||
ram_external_app_game2048 (rwx) : org = 0xADEC0000, len = 32k
|
||||
ram_external_app_bht_tx (rwx) : org = 0xADED0000, len = 32k
|
||||
|
||||
|
||||
}
|
||||
@@ -449,5 +450,13 @@ SECTIONS
|
||||
*(*ui*external_app*game2048*);
|
||||
} > ram_external_app_game2048
|
||||
|
||||
|
||||
.external_app_bht_tx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_bht_tx.application_information));
|
||||
*(*ui*external_app*bht_tx*);
|
||||
} > ram_external_app_bht_tx
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -56,16 +56,16 @@ class ExtSensorsView : public View {
|
||||
uint16_t prev_scan_int = 0;
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 3 * 16}, "GPS:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "ORI:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "ENV:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 3 * 16}, "GPS:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 5 * 16}, "ORI:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "ENV:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_info{{0 * 8, 0 * 8, screen_width, 16 * 1}, "Connect a compatible module..."};
|
||||
Text text_gps{{5 * 8, 3 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_orientation{{5 * 8, 5 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_envl3{{1 * 8, 11 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_info{{UI_POS_X(0), 0 * 8, screen_width, 16 * 1}, "Connect a compatible module..."};
|
||||
Text text_gps{{5 * 8, 3 * 16, UI_POS_WIDTH_REMAINING(6), UI_POS_HEIGHT(1)}, "-"};
|
||||
Text text_orientation{{5 * 8, 5 * 16, UI_POS_WIDTH_REMAINING(6), UI_POS_HEIGHT(1)}, "-"};
|
||||
Text text_envl1{{5 * 8, 7 * 16, UI_POS_WIDTH_REMAINING(6), UI_POS_HEIGHT(1)}, "-"};
|
||||
Text text_envl2{{1 * 8, 9 * 16, UI_POS_WIDTH_REMAINING(6), UI_POS_HEIGHT(1)}, "-"};
|
||||
Text text_envl3{{1 * 8, 11 * 16, UI_POS_WIDTH_REMAINING(6), UI_POS_HEIGHT(1)}, "-"};
|
||||
Console console{
|
||||
{1, 13 * 16, screen_width - 1, screen_height - 13 * 16}};
|
||||
|
||||
|
||||
@@ -49,10 +49,10 @@ class FlipperTxView : public View {
|
||||
};
|
||||
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
TransmitterView2 tx_view{
|
||||
{11 * 8, 0 * 16},
|
||||
{11 * 8, UI_POS_Y(0)},
|
||||
/*short_ui*/ true};
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
|
||||
+16
-16
@@ -121,18 +121,18 @@ class FmRadioView : public View {
|
||||
{"theme"sv, ¤t_theme}}};
|
||||
|
||||
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), 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
OptionsField field_bw{
|
||||
@@ -171,16 +171,16 @@ class FmRadioView : public View {
|
||||
|
||||
GraphEq gr{{2, FMR_BTNGRID_TOP, UI_POS_MAXWIDTH - 4, UI_POS_MAXHEIGHT - FMR_BTNGRID_TOP}, true};
|
||||
|
||||
Button btn_fav_0{{2, FMR_BTNGRID_TOP + 0 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_1{{2 + 15 * 8, FMR_BTNGRID_TOP + 0 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_2{{2, FMR_BTNGRID_TOP + 1 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_3{{2 + 15 * 8, FMR_BTNGRID_TOP + 1 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_4{{2, FMR_BTNGRID_TOP + 2 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_5{{2 + 15 * 8, FMR_BTNGRID_TOP + 2 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_6{{2, FMR_BTNGRID_TOP + 3 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_7{{2 + 15 * 8, FMR_BTNGRID_TOP + 3 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_8{{2, FMR_BTNGRID_TOP + 4 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_9{{2 + 15 * 8, FMR_BTNGRID_TOP + 4 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_0{{UI_POS_X_CENTER(10) - UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 0 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_1{{UI_POS_X_CENTER(10) + UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 0 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_2{{UI_POS_X_CENTER(10) - UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 1 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_3{{UI_POS_X_CENTER(10) + UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 1 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_4{{UI_POS_X_CENTER(10) - UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 2 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_5{{UI_POS_X_CENTER(10) + UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 2 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_6{{UI_POS_X_CENTER(10) - UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 3 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_7{{UI_POS_X_CENTER(10) + UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 3 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_8{{UI_POS_X_CENTER(10) - UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 4 * 34, 10 * 8, 28}, "---"};
|
||||
Button btn_fav_9{{UI_POS_X_CENTER(10) + UI_POS_WIDTH(8), FMR_BTNGRID_TOP + 4 * 34, 10 * 8, 28}, "---"};
|
||||
|
||||
Button btn_fav_save{{2, FMR_BTNGRID_TOP + 6 * 34, 7 * 8, 1 * 28}, "Save"};
|
||||
bool save_fav = false;
|
||||
|
||||
@@ -49,7 +49,7 @@ class DebugFontsView : public View {
|
||||
void paint_zoomed_text(Painter& painter);
|
||||
|
||||
NumberField field_cursor{
|
||||
{0 * 8, 0 * 8},
|
||||
{UI_POS_X(0), 0 * 8},
|
||||
4,
|
||||
{0, 1000},
|
||||
1,
|
||||
@@ -61,7 +61,7 @@ class DebugFontsView : public View {
|
||||
1,
|
||||
' '};
|
||||
Text text_address{
|
||||
{screen_width / 2, 0 * 16, screen_width / 2, 16},
|
||||
{screen_width / 2, UI_POS_Y(0), screen_width / 2, 16},
|
||||
"0x20",
|
||||
};
|
||||
NavigationView& nav_;
|
||||
|
||||
+7
-7
@@ -54,23 +54,23 @@ class FoxhuntRxView : public View {
|
||||
"rx_foxhunt", app_settings::Mode::RX};
|
||||
|
||||
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), 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
// Power: -XXX db
|
||||
Text freq_stats_db{
|
||||
{0 * 8, 2 * 16 + 4, 14 * 8, 14},
|
||||
{UI_POS_X(0), 2 * 16 + 4, 14 * 8, 14},
|
||||
};
|
||||
RSSIGraph rssi_graph{
|
||||
{0, 50, screen_width, 30},
|
||||
|
||||
+11
-10
@@ -27,6 +27,7 @@ namespace ui::external_app::game2048 {
|
||||
Game2048View::Game2048View(NavigationView& nav)
|
||||
: nav_(nav), score(0), best_score(0), game_state(STATE_PLAYING) {
|
||||
add_children({&dummy});
|
||||
TILE_SIZE = (screen_width - 2 * BOARD_START_X - (GRID_SIZE + 1) * TILE_MARGIN) / GRID_SIZE;
|
||||
init_game();
|
||||
}
|
||||
|
||||
@@ -301,11 +302,11 @@ void Game2048View::draw_game() {
|
||||
void Game2048View::show_game_over() {
|
||||
if (show_you_won_you_lost_slow_down_cunter++ % 1000 != 0) return;
|
||||
// slow down otherwies it repaint even faster than it finished paint full stuff
|
||||
painter.fill_rectangle({40, 100, 160, 100}, Color::black());
|
||||
painter.draw_rectangle({40, 100, 160, 100}, Color::white());
|
||||
painter.draw_string({80, 115}, *Theme::getInstance()->bg_darkest, "GAME OVER");
|
||||
painter.draw_string({70, 135}, *Theme::getInstance()->bg_darkest, "Press SELECT");
|
||||
painter.draw_string({75, 155}, *Theme::getInstance()->bg_darkest, "to restart");
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(20), 100, 160, 100}, Color::black());
|
||||
painter.draw_rectangle({UI_POS_X_CENTER(20), 100, 160, 100}, Color::white());
|
||||
painter.draw_string({UI_POS_X_CENTER(10), 115}, *Theme::getInstance()->bg_darkest, "GAME OVER");
|
||||
painter.draw_string({UI_POS_X_CENTER(13), 135}, *Theme::getInstance()->bg_darkest, "Press SELECT");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 155}, *Theme::getInstance()->bg_darkest, "to restart");
|
||||
need_repaint = false;
|
||||
need_repaint_bg_frame = true;
|
||||
}
|
||||
@@ -313,11 +314,11 @@ void Game2048View::show_game_over() {
|
||||
void Game2048View::show_you_won() {
|
||||
if (show_you_won_you_lost_slow_down_cunter++ % 1000 != 0) return;
|
||||
// slow down otherwies it repaint even faster than it finished paint full stuff
|
||||
painter.fill_rectangle({40, 100, 160, 100}, Color::black());
|
||||
painter.draw_rectangle({40, 100, 160, 100}, Color::white());
|
||||
painter.draw_string({80, 115}, *Theme::getInstance()->bg_darkest, "YOU WON!");
|
||||
painter.draw_string({70, 135}, *Theme::getInstance()->bg_darkest, "Press SELECT");
|
||||
painter.draw_string({75, 155}, *Theme::getInstance()->bg_darkest, "to restart");
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(20), 100, 160, 100}, Color::black());
|
||||
painter.draw_rectangle({UI_POS_X_CENTER(20), 100, 160, 100}, Color::white());
|
||||
painter.draw_string({UI_POS_X_CENTER(9), 115}, *Theme::getInstance()->bg_darkest, "YOU WON!");
|
||||
painter.draw_string({UI_POS_X_CENTER(13), 135}, *Theme::getInstance()->bg_darkest, "Press SELECT");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 155}, *Theme::getInstance()->bg_darkest, "to restart");
|
||||
need_repaint = false;
|
||||
need_repaint_bg_frame = true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,6 @@
|
||||
namespace ui::external_app::game2048 {
|
||||
|
||||
#define GRID_SIZE 4
|
||||
#define TILE_SIZE 50
|
||||
#define TILE_MARGIN 5
|
||||
#define BOARD_START_X 15
|
||||
#define BOARD_START_Y 35
|
||||
@@ -63,6 +62,7 @@ class Game2048View : public View {
|
||||
Painter painter{};
|
||||
|
||||
int grid[GRID_SIZE][GRID_SIZE];
|
||||
int TILE_SIZE = 50;
|
||||
int score;
|
||||
int best_score;
|
||||
GameState game_state;
|
||||
|
||||
+5
-5
@@ -68,12 +68,12 @@ class gfxEQView : public View {
|
||||
ColorTheme{Color(64, 64, 64), Color(255, 0, 0)},
|
||||
ColorTheme{Color(255, 192, 0), Color(0, 64, 128)}};
|
||||
|
||||
ButtonWithEncoder button_frequency{{0 * 8, 0 * 16 + 4, 11 * 8, 1 * 8}, ""};
|
||||
RFAmpField field_rf_amp{{13 * 8, 0 * 16}};
|
||||
LNAGainField field_lna{{15 * 8, 0 * 16}};
|
||||
VGAGainField field_vga{{18 * 8, 0 * 16}};
|
||||
ButtonWithEncoder button_frequency{{UI_POS_X(0), UI_POS_Y(0) + 4, 11 * 8, 1 * 8}, ""};
|
||||
RFAmpField field_rf_amp{{13 * 8, UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{{15 * 8, UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{{18 * 8, UI_POS_Y(0)}};
|
||||
Button button_mood{{21 * 8, 0, 6 * 8, 16}, "MOOD"};
|
||||
AudioVolumeField field_volume{{screen_width - 2 * 8, 0 * 16}};
|
||||
AudioVolumeField field_volume{{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
GraphEq gr{{2, UI_POS_DEFAULT_HEIGHT, UI_POS_MAXWIDTH - 4, UI_POS_HEIGHT_REMAINING(2)}, false};
|
||||
|
||||
rf::Frequency frequency_value{93100000};
|
||||
|
||||
+5
-5
@@ -82,24 +82,24 @@ class GpsSimAppView : public View {
|
||||
bool ready_signal{false};
|
||||
|
||||
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), 12 * 8, 16},
|
||||
"-"};
|
||||
Text text_sample_rate{
|
||||
{24 * 8, 0 * 16, 6 * 8, 16},
|
||||
{24 * 8, UI_POS_Y(0), 6 * 8, 16},
|
||||
"-"};
|
||||
|
||||
Text text_duration{
|
||||
{11 * 8, 1 * 16, 6 * 8, 16},
|
||||
"-"};
|
||||
ProgressBar progressbar{
|
||||
{18 * 8, 1 * 16, 12 * 8, 16}};
|
||||
{18 * 8, 1 * 16, UI_POS_WIDTH_REMAINING(18), 16}};
|
||||
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, 2 * 16},
|
||||
{UI_POS_X(0), 2 * 16},
|
||||
nav_};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
|
||||
+27
-27
@@ -88,55 +88,55 @@ class HopperView : public View {
|
||||
false};
|
||||
|
||||
NewButton button_load_list{
|
||||
{0 * 8, 9 * 16 + 4, 4 * 8, 32},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(10), 4 * 8, 32},
|
||||
{},
|
||||
&bitmap_icon_load,
|
||||
Color::dark_blue(),
|
||||
/*vcenter*/ true};
|
||||
|
||||
NewButton button_save_list{
|
||||
{4 * 8, 9 * 16 + 4, 4 * 8, 32},
|
||||
{4 * 8, UI_POS_Y_BOTTOM(10), 4 * 8, 32},
|
||||
{},
|
||||
&bitmap_icon_save,
|
||||
Color::dark_blue(),
|
||||
/*vcenter*/ true};
|
||||
|
||||
NewButton button_add_freq{
|
||||
{8 * 8 + 4, 9 * 16 + 4, 4 * 8, 32},
|
||||
{8 * 8 + 4, UI_POS_Y_BOTTOM(10), 4 * 8, 32},
|
||||
{},
|
||||
&bitmap_icon_add,
|
||||
Color::dark_green(),
|
||||
/*vcenter*/ true};
|
||||
|
||||
NewButton button_delete_freq{
|
||||
{12 * 8 + 4, 9 * 16 + 4, 4 * 8, 32},
|
||||
{12 * 8 + 4, UI_POS_Y_BOTTOM(10), 4 * 8, 32},
|
||||
{},
|
||||
&bitmap_icon_trash,
|
||||
Color::dark_red(),
|
||||
/*vcenter*/ true};
|
||||
|
||||
NewButton button_clear{
|
||||
{screen_width - 4 * 8, 9 * 16 + 4, 4 * 8, 32},
|
||||
{screen_width - 4 * 8, UI_POS_Y_BOTTOM(10), 4 * 8, 32},
|
||||
{},
|
||||
&bitmap_icon_tools_wipesd,
|
||||
Color::red(),
|
||||
/*vcenter*/ true};
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 23 * 8}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 25 * 8}, "Speed:", Theme::getInstance()->fg_light->foreground},
|
||||
{{3 * 8, 27 * 8}, "Hop:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 29 * 8}, "TX:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 31 * 8}, "Sle3p:", Theme::getInstance()->fg_light->foreground}, // euquiq: Token of appreciation to TheSle3p, which made this ehnancement a reality with his bounty.
|
||||
{{0 * 8, 33 * 8}, "Jitter:", Theme::getInstance()->fg_light->foreground}, // Maybe the repository curator can keep the "mystype" for some versions.
|
||||
{{11 * 8, 29 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 31 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 33 * 8}, "/60", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 35 * 8}, "Gain:", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 35 * 8}, "A:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{2 * 8, UI_POS_Y_BOTTOM(8)}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, UI_POS_Y_BOTTOM(7)}, "Speed:", Theme::getInstance()->fg_light->foreground},
|
||||
{{3 * 8, UI_POS_Y_BOTTOM(6)}, "Hop:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, UI_POS_Y_BOTTOM(5)}, "TX:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, UI_POS_Y_BOTTOM(4)}, "Sle3p:", Theme::getInstance()->fg_light->foreground}, // euquiq: Token of appreciation to TheSle3p, which made this ehnancement a reality with his bounty.
|
||||
{{UI_POS_X(0), UI_POS_Y_BOTTOM(3)}, "Jitter:", Theme::getInstance()->fg_light->foreground}, // Maybe the repository curator can keep the "mystype" for some versions.
|
||||
{{11 * 8, UI_POS_Y_BOTTOM(5)}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, UI_POS_Y_BOTTOM(4)}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, UI_POS_Y_BOTTOM(3)}, "/60", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, UI_POS_Y_BOTTOM(2)}, "Gain:", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, UI_POS_Y_BOTTOM(2)}, "A:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_type{
|
||||
{7 * 8, 23 * 8},
|
||||
{7 * 8, UI_POS_Y_BOTTOM(8)},
|
||||
8,
|
||||
{
|
||||
{"Rand FSK", 0},
|
||||
@@ -153,14 +153,14 @@ class HopperView : public View {
|
||||
}};
|
||||
|
||||
Text text_range_number{
|
||||
{16 * 8, 23 * 8, 2 * 8, 16},
|
||||
{16 * 8, UI_POS_Y_BOTTOM(8), 2 * 8, 16},
|
||||
"--"};
|
||||
Text text_range_total{
|
||||
{18 * 8, 23 * 8, 3 * 8, 16},
|
||||
{18 * 8, UI_POS_Y_BOTTOM(8), 3 * 8, 16},
|
||||
"/--"};
|
||||
|
||||
OptionsField options_speed{
|
||||
{7 * 8, 25 * 8},
|
||||
{7 * 8, UI_POS_Y_BOTTOM(7)},
|
||||
6,
|
||||
{{"10Hz ", 10},
|
||||
{"100Hz ", 100},
|
||||
@@ -169,7 +169,7 @@ class HopperView : public View {
|
||||
{"100kHz", 100000}}};
|
||||
|
||||
OptionsField options_hop{
|
||||
{7 * 8, 27 * 8},
|
||||
{7 * 8, UI_POS_Y_BOTTOM(6)},
|
||||
6,
|
||||
{{"0ms !!", 0},
|
||||
{"1ms ", 1},
|
||||
@@ -182,7 +182,7 @@ class HopperView : public View {
|
||||
{"10s ", 10000}}};
|
||||
|
||||
NumberField field_timetx{
|
||||
{7 * 8, 29 * 8},
|
||||
{7 * 8, UI_POS_Y_BOTTOM(5)},
|
||||
3,
|
||||
{1, 180},
|
||||
1,
|
||||
@@ -190,7 +190,7 @@ class HopperView : public View {
|
||||
};
|
||||
|
||||
NumberField field_timepause{
|
||||
{8 * 8, 31 * 8},
|
||||
{8 * 8, UI_POS_Y_BOTTOM(4)},
|
||||
2,
|
||||
{1, 60},
|
||||
1,
|
||||
@@ -198,7 +198,7 @@ class HopperView : public View {
|
||||
};
|
||||
|
||||
NumberField field_jitter{
|
||||
{8 * 8, 33 * 8},
|
||||
{8 * 8, UI_POS_Y_BOTTOM(3)},
|
||||
2,
|
||||
{1, 60},
|
||||
1,
|
||||
@@ -206,7 +206,7 @@ class HopperView : public View {
|
||||
};
|
||||
|
||||
NumberField field_gain{
|
||||
{8 * 8, 35 * 8},
|
||||
{8 * 8, UI_POS_Y_BOTTOM(2)},
|
||||
2,
|
||||
{0, 47},
|
||||
1,
|
||||
@@ -214,7 +214,7 @@ class HopperView : public View {
|
||||
};
|
||||
|
||||
NumberField field_amp{
|
||||
{13 * 8, 35 * 8},
|
||||
{13 * 8, UI_POS_Y_BOTTOM(2)},
|
||||
1,
|
||||
{0, 1},
|
||||
1,
|
||||
@@ -222,7 +222,7 @@ class HopperView : public View {
|
||||
};
|
||||
|
||||
Button button_transmit{
|
||||
{148, 216, 80, 80},
|
||||
{148, UI_POS_Y_BOTTOM(6), 80, 80},
|
||||
LanguageHelper::currentMessages[LANG_START]};
|
||||
|
||||
MessageHandlerRegistration message_handler_retune{
|
||||
|
||||
+2
-2
@@ -57,7 +57,7 @@ class RangeView : public View {
|
||||
"Load range"};
|
||||
|
||||
Button button_start{
|
||||
{0 * 8, 11 * 8, 11 * 8, 28},
|
||||
{UI_POS_X(0), 11 * 8, 11 * 8, 28},
|
||||
""};
|
||||
|
||||
Button button_stop{
|
||||
@@ -144,7 +144,7 @@ class JammerView : public View {
|
||||
{{3 * 8, 27 * 8}, "Hop:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 29 * 8}, "TX:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 31 * 8}, "Sleep:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 33 * 8}, "Jitter:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 33 * 8}, "Jitter:", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 29 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 31 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 33 * 8}, "/60", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
+3
-3
@@ -106,14 +106,14 @@ class KeyfobView : public View {
|
||||
SymField::Type::Hex};
|
||||
|
||||
Text text_status{
|
||||
{2 * 8, 13 * 16, 128, 16},
|
||||
{2 * 8, UI_POS_Y_BOTTOM(7), 128, 16},
|
||||
"Ready"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{2 * 8, 13 * 16 + 20, 208, 16}};
|
||||
{2 * 8, UI_POS_Y_BOTTOM(6), UI_POS_WIDTH_REMAINING(4), 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
0,
|
||||
15,
|
||||
true};
|
||||
|
||||
+2
-2
@@ -145,10 +145,10 @@ class LCRView : public View {
|
||||
{2 * 8, 27 * 8 + 4, 26 * 8, 16},
|
||||
LanguageHelper::currentMessages[LANG_READY]};
|
||||
ProgressBar progress{
|
||||
{2 * 8, 29 * 8 + 4, 26 * 8, 16}};
|
||||
{2 * 8, 29 * 8 + 4, UI_POS_WIDTH_REMAINING(4), 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
10000,
|
||||
12};
|
||||
|
||||
|
||||
+10
-10
@@ -80,21 +80,21 @@ class LevelView : public View {
|
||||
}};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 1 * 16}, "BW: MODE: S: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "LNA: VGA: AMP: VOL: ", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "BW: MODE: S: ", 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}};
|
||||
{24 * 8, UI_POS_Y(0)}};
|
||||
|
||||
OptionsField field_bw{
|
||||
{3 * 8, 1 * 16},
|
||||
@@ -112,7 +112,7 @@ class LevelView : public View {
|
||||
{}};
|
||||
|
||||
ButtonWithEncoder button_frequency{
|
||||
{0 * 8, 2 * 16 + 8, 15 * 8, 1 * 8},
|
||||
{UI_POS_X(0), 2 * 16 + 8, 15 * 8, 1 * 8},
|
||||
""};
|
||||
|
||||
OptionsField field_audio_mode{
|
||||
@@ -135,12 +135,12 @@ class LevelView : public View {
|
||||
|
||||
// RSSI: XX/XX/XXX
|
||||
Text freq_stats_rssi{
|
||||
{0 * 8, 3 * 16 + 4, 15 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 3 * 16 + 4, 15 * 8, 1 * 16},
|
||||
};
|
||||
|
||||
// Power: -XXX db
|
||||
Text freq_stats_db{
|
||||
{0 * 8, 4 * 16 + 4, 15 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 4 * 16 + 4, 15 * 8, 1 * 16},
|
||||
};
|
||||
|
||||
OptionsField peak_mode{
|
||||
@@ -169,7 +169,7 @@ class LevelView : public View {
|
||||
|
||||
// RxSat: XX%
|
||||
Text freq_stats_rx{
|
||||
{0 * 8, 5 * 16 + 4, 10 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 5 * 16 + 4, 10 * 8, 1 * 16},
|
||||
};
|
||||
|
||||
Text text_ctcss{
|
||||
|
||||
+4
-4
@@ -93,8 +93,8 @@ class LGEView : public View {
|
||||
{{2 * 8, 3 * 8}, "Room:", Theme::getInstance()->fg_light->foreground},
|
||||
{{14 * 8, 3 * 8}, "Text:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 5 * 8}, "Team:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 8}, "Player:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 10 * 8}, "Vest:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 8}, "Player:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 10 * 8}, "Vest:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 12 * 8}, "ID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{3 * 8, 14 * 8}, "Pow: /10", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 16 * 8}, "Time: x100ms", Theme::getInstance()->fg_light->foreground}};
|
||||
@@ -171,10 +171,10 @@ class LGEView : public View {
|
||||
'0'};
|
||||
|
||||
Console console{
|
||||
{0, 18 * 8, screen_width, 7 * 16}};
|
||||
{0, 18 * 8, screen_width, UI_POS_Y_BOTTOM(4) - 18 * 8}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
10000,
|
||||
12};
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ class McuTemperatureView : public View {
|
||||
|
||||
private:
|
||||
Text text_title{
|
||||
{76, 16, screen_width, 16},
|
||||
{UI_POS_X_CENTER(11), 16, UI_POS_WIDTH(11), 16},
|
||||
"Temperature",
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ class McuTemperatureView : public View {
|
||||
};
|
||||
|
||||
Button button_done{
|
||||
{72, screen_height - 56, 96, 24},
|
||||
{UI_POS_X_CENTER(12), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(12), 24},
|
||||
"Done"};
|
||||
};
|
||||
|
||||
|
||||
@@ -60,13 +60,13 @@ class MetronomeView : public View {
|
||||
uint32_t current_beat_{0};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "BPM:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Accent Beep Tune:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Unaccent Beep Tune:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "Rhythm:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "BPM:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 2 * 16}, "Accent Beep Tune:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Unaccent Beep Tune:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 4 * 16}, "Rhythm:", Theme::getInstance()->fg_light->foreground},
|
||||
{{(sizeof("Rhythm:") + 1) * 8 + 4 * 8, 4 * 16}, "/", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Beep Flash Duration:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 6 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 5 * 16}, "Beep Flash Duration:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 6 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
NumberField field_bpm{
|
||||
{(sizeof("BPM:") + 1) * 8, 1 * 16},
|
||||
|
||||
+2
-2
@@ -171,10 +171,10 @@ class MorseView : public View {
|
||||
"Set message"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{2 * 8, 28 * 8, 208, 16}};
|
||||
{2 * 8, 28 * 8, UI_POS_WIDTH_REMAINING(4), 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
10000,
|
||||
12};
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class NoaaAptRxView : public View {
|
||||
VGAGainField field_vga{
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
RSSI rssi{
|
||||
{UI_POS_X(21), UI_POS_Y(0), UI_POS_WIDTH(6), 4}};
|
||||
{UI_POS_X(21), UI_POS_Y(0), UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
@@ -114,7 +114,7 @@ class NoaaAptRxView : public View {
|
||||
};
|
||||
|
||||
Button button_ss{
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(1), UI_POS_WIDTH(5), UI_POS_DEFAULT_HEIGHT},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(1), UI_POS_WIDTH(6), UI_POS_HEIGHT(2)},
|
||||
LanguageHelper::currentMessages[LANG_START]};
|
||||
|
||||
MessageHandlerRegistration message_handler_stats{
|
||||
|
||||
+6
-6
@@ -62,18 +62,18 @@ class NRFRxView : public View {
|
||||
uint32_t prev_value{0};
|
||||
|
||||
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(22), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
{21 * 8, 5, UI_POS_WIDTH_REMAINING(22), 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
Button button_modem_setup{
|
||||
|
||||
+15
-15
@@ -93,8 +93,8 @@ class OOKEditorAppView : public View {
|
||||
{{"ook_editor_tx_freq"sv, &ook_editor_tx_freq}}};
|
||||
|
||||
// UI components for frequency and transmitter view.
|
||||
FrequencyField field_frequency{{0 * 8, 0 * 16}};
|
||||
TransmitterView2 tx_view{{20 * 7, 0 * 16}, true};
|
||||
FrequencyField field_frequency{{UI_POS_X(0), UI_POS_Y(0)}};
|
||||
TransmitterView2 tx_view{{UI_POS_X_RIGHT(9), UI_POS_Y(0)}, true};
|
||||
|
||||
// Labels for various fields such as sample rate and repeat count.
|
||||
Labels label_step{{{170, 20}, "Step:", Theme::getInstance()->fg_light->foreground}};
|
||||
@@ -120,17 +120,17 @@ class OOKEditorAppView : public View {
|
||||
NumberField field_repeat{{210, 40}, 3, {1, 999}, 1, '0', false};
|
||||
|
||||
// Text field to display the payload data.
|
||||
Text text_payload{{0 * 8, 100, screen_width, 16}, ""};
|
||||
Text text_payload{{UI_POS_X(0), 100, screen_width, 16}, ""};
|
||||
|
||||
// Buttons for setting configurations, opening files, and starting transmission.
|
||||
Button button_set{{0, 125, 60, 28}, LanguageHelper::currentMessages[LANG_SET]};
|
||||
Button button_open{{68, 125, 80, 28}, LanguageHelper::currentMessages[LANG_OPEN_FILE]};
|
||||
Button button_save{{154, 125, 80, 28}, LanguageHelper::currentMessages[LANG_SAVE_FILE]};
|
||||
Button button_bug_key{{0, 125 + 28 + 3, screen_width, 28}, "Bug Key"};
|
||||
Button button_send_stop{{80, 273, 80, 32}, LanguageHelper::currentMessages[LANG_SEND]};
|
||||
Button button_send_stop{{UI_POS_X_CENTER(10), 273, UI_POS_WIDTH(10), 32}, LanguageHelper::currentMessages[LANG_SEND]};
|
||||
|
||||
// Progress bar to display transmission progress.
|
||||
ProgressBar progressbar{{2 * 8, 250, 208, 16}};
|
||||
ProgressBar progressbar{{2 * 8, 250, UI_POS_WIDTH_REMAINING(4), 16}};
|
||||
|
||||
// Waveform display using waveform buffer and yellow theme color.
|
||||
Waveform waveform{{0, 208, screen_width, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
|
||||
@@ -167,11 +167,11 @@ class OOKEditorBugKeyView : public View {
|
||||
std::string build_payload();
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Primary Step", Theme::getInstance()->fg_light->foreground},
|
||||
{{(screen_width / 2), 0 * 16}, "Secondary Step", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Primary Step", Theme::getInstance()->fg_light->foreground},
|
||||
{{(screen_width / 2), UI_POS_Y(0)}, "Secondary Step", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
NumberField field_primary_step{
|
||||
{0 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 1 * 16},
|
||||
3,
|
||||
{0, 550},
|
||||
1,
|
||||
@@ -185,30 +185,30 @@ class OOKEditorBugKeyView : public View {
|
||||
' '};
|
||||
|
||||
Console console{
|
||||
{0, 3 * 16, screen_width, screen_height - 10 * 16}};
|
||||
{0, UI_POS_Y(3), screen_width, UI_POS_HEIGHT_REMAINING(10)}};
|
||||
|
||||
Button button_insert_low_level_long{
|
||||
{0 * 8, 13 * 16, screen_width / 2, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(7), screen_width / 2, UI_POS_HEIGHT(2)},
|
||||
"00"};
|
||||
|
||||
Button button_insert_low_level_short{
|
||||
{0 * 8, 15 * 16, screen_width / 2, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(5), screen_width / 2, UI_POS_HEIGHT(2)},
|
||||
"0"};
|
||||
|
||||
Button button_insert_high_level_long{
|
||||
{(screen_width / 2), 13 * 16, screen_width / 2, 2 * 16},
|
||||
{(screen_width / 2), UI_POS_Y_BOTTOM(7), screen_width / 2, UI_POS_HEIGHT(2)},
|
||||
"11"};
|
||||
|
||||
Button button_insert_high_level_short{
|
||||
{(screen_width / 2), 15 * 16, screen_width / 2, 2 * 16},
|
||||
{(screen_width / 2), UI_POS_Y_BOTTOM(5), screen_width / 2, UI_POS_HEIGHT(2)},
|
||||
"1"};
|
||||
|
||||
Button button_delete{
|
||||
{1, 17 * 16, screen_width / 2 - 4, 2 * 16},
|
||||
{1, UI_POS_Y_BOTTOM(3), screen_width / 2 - 4, UI_POS_HEIGHT(2)},
|
||||
"<Backspace"};
|
||||
|
||||
Button button_save{
|
||||
{1 + screen_width / 2 + 1, 17 * 16, screen_width / 2 - 4, 2 * 16},
|
||||
{1 + screen_width / 2 + 1, UI_POS_Y_BOTTOM(3), screen_width / 2 - 4, UI_POS_HEIGHT(2)},
|
||||
"Save"};
|
||||
};
|
||||
|
||||
|
||||
+6
-6
@@ -45,18 +45,18 @@ class OOKBruteView : public View {
|
||||
};
|
||||
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
TransmitterView2 tx_view{
|
||||
{11 * 8, 0 * 16},
|
||||
{11 * 8, UI_POS_Y(0)},
|
||||
/*short_ui*/ true};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_ookbrute", app_settings::Mode::TX};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 2 * 16}, "Start Position:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "Stop Position:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 13 * 16}, "Encoder Type:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 2 * 16}, "Start Position:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "Stop Position:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 13 * 16}, "Encoder Type:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Button button_startstop{
|
||||
{8, screen_height - 48 - 16, screen_width - 2 * 8, 48},
|
||||
@@ -71,7 +71,7 @@ class OOKBruteView : public View {
|
||||
"Input Stop Pos"};
|
||||
|
||||
NumberField field_start{
|
||||
{0 * 8, 3 * 16},
|
||||
{UI_POS_X(0), 3 * 16},
|
||||
8,
|
||||
{0, 2500},
|
||||
1,
|
||||
|
||||
@@ -52,7 +52,7 @@ PlaylistEditorView::PlaylistEditorView(NavigationView& nav)
|
||||
&button_insert,
|
||||
&button_save_playlist});
|
||||
|
||||
menu_view.set_parent_rect({0, 2 * 8, screen_width, 24 * 8});
|
||||
menu_view.set_parent_rect({0, 2 * 8, screen_width, UI_POS_HEIGHT_REMAINING(9)});
|
||||
|
||||
menu_view.on_highlight = [this]() {
|
||||
text_hint.set("Edit:" +
|
||||
|
||||
@@ -48,40 +48,40 @@ class PlaylistEditorView : public View {
|
||||
bool ever_opened = false;
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "PPL file:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "PPL file:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Button button_new{
|
||||
{(sizeof("PPL file:") + 1) * 8, 0 * 16, 8 * 5, 16},
|
||||
{(sizeof("PPL file:") + 1) * 8, UI_POS_Y(0), 8 * 5, 16},
|
||||
"New"};
|
||||
|
||||
Text text_current_ppl_file{
|
||||
{sizeof("PPL file:") * 8, 0 * 16, screen_width - (int)sizeof("PPL file:") * 8, 16},
|
||||
{sizeof("PPL file:") * 8, UI_POS_Y(0), screen_width - (int)sizeof("PPL file:") * 8, 16},
|
||||
""};
|
||||
|
||||
MenuView menu_view{};
|
||||
|
||||
Text text_hint{
|
||||
{0, 27 * 8, screen_width, 16},
|
||||
{0, UI_POS_Y_BOTTOM(6), screen_width, 16},
|
||||
"Open a PPL file"};
|
||||
|
||||
Text text_ppl_name{
|
||||
{0, 27 * 8, screen_width, 16},
|
||||
{0, UI_POS_Y_BOTTOM(6), screen_width, 16},
|
||||
"Highlight an app"};
|
||||
|
||||
Button button_open_playlist{
|
||||
{0, 29 * 8, screen_width / 2 - 1, 32},
|
||||
{0, UI_POS_Y_BOTTOM(5), screen_width / 2 - 1, 32},
|
||||
"Open PPL"};
|
||||
|
||||
Button button_edit{
|
||||
{screen_width / 2 + 2, 29 * 8, screen_width / 2 - 2, 32},
|
||||
{screen_width / 2 + 2, UI_POS_Y_BOTTOM(5), screen_width / 2 - 2, 32},
|
||||
"Edit Item"};
|
||||
|
||||
Button button_insert{
|
||||
{0, screen_height - 32 - 16, screen_width / 2 - 1, 32},
|
||||
{0, UI_POS_Y_BOTTOM(3), screen_width / 2 - 1, 32},
|
||||
"Ins. After"};
|
||||
|
||||
Button button_save_playlist{
|
||||
{screen_width / 2 + 2, screen_height - 32 - 16, screen_width / 2 - 2, 32},
|
||||
{screen_width / 2 + 2, UI_POS_Y_BOTTOM(3), screen_width / 2 - 2, 32},
|
||||
"Save PPL"};
|
||||
|
||||
void open_file();
|
||||
@@ -122,7 +122,7 @@ class PlaylistItemEditView : public View {
|
||||
std::string build_item() const;
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Path:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "Path:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 5 * 16}, "Delay(ms):", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
TextField field_path{
|
||||
|
||||
@@ -98,9 +98,9 @@ class RandomPasswordView : public View {
|
||||
"rx_passgen", app_settings::Mode::RX};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "------------seeds-------------", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "-----------password-----------", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16 - 2}, "digits:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(30), UI_POS_Y(0)}, "------------seeds-------------", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(30), 3 * 16}, "-----------password-----------", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16 - 2}, "digits:", Theme::getInstance()->fg_light->foreground},
|
||||
{{screen_width / 2, 7 * 16 - 2}, "method:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
@@ -112,12 +112,12 @@ class RandomPasswordView : public View {
|
||||
{18 * 8, 1 * 16}};
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 1 * 16 + 0, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 1 * 16 + 0, UI_POS_WIDTH_REMAINING(21), 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 1 * 16 + 5, 6 * 8, 4}};
|
||||
{UI_POS_X(21), 1 * 16 + 5, UI_POS_WIDTH_REMAINING(21), 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 1 * 16},
|
||||
{UI_POS_X(0), 1 * 16},
|
||||
nav_};
|
||||
|
||||
Button button_modem_setup{
|
||||
@@ -180,7 +180,7 @@ class RandomPasswordView : public View {
|
||||
LanguageHelper::currentMessages[LANG_SAVE]};
|
||||
|
||||
Button button_flood{
|
||||
{0 * 8, 15 * 16 + 18, screen_width / 2, 22},
|
||||
{UI_POS_X(0), 15 * 16 + 18, screen_width / 2, 22},
|
||||
LanguageHelper::currentMessages[LANG_FLOOD]};
|
||||
|
||||
Button button_send{
|
||||
@@ -188,7 +188,7 @@ class RandomPasswordView : public View {
|
||||
"Send pwd"};
|
||||
|
||||
Button button_refresh{
|
||||
{0 * 8, 17 * 16 + 10, screen_width / 2, 22},
|
||||
{UI_POS_X(0), 17 * 16 + 10, screen_width / 2, 22},
|
||||
"Generate"};
|
||||
|
||||
Button button_show_qr{
|
||||
|
||||
+10
-10
@@ -208,7 +208,7 @@ class RemoteEntryEditView : public View {
|
||||
{{2 * 8, 5 * 16}, "Icon:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 6 * 16}, "FG Color:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 7 * 16}, "BG Color:", Theme::getInstance()->fg_light->foreground},
|
||||
{{8 * 8, 9 * 16}, "Button preview", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(14), 9 * 16}, "Button preview", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
TextField field_name{{8 * 8, 1 * 16, 20 * 8, 1 * 16}, {}};
|
||||
@@ -244,7 +244,7 @@ class RemoteEntryEditView : public View {
|
||||
/*loop*/ true};
|
||||
|
||||
RemoteButton button_preview{
|
||||
{10 * 8, 11 * 16 - 8, 10 * 8, 50},
|
||||
{UI_POS_X_CENTER(10), 11 * 16 - 8, 10 * 8, 50},
|
||||
&entry_};
|
||||
|
||||
NewButton button_delete{
|
||||
@@ -253,7 +253,7 @@ class RemoteEntryEditView : public View {
|
||||
&bitmap_icon_trash,
|
||||
Color::red()};
|
||||
|
||||
Button button_done{{11 * 8, 16 * 16, 8 * 8, 2 * 16}, "Done"};
|
||||
Button button_done{{UI_POS_X_CENTER(10), 16 * 16, 10 * 8, 2 * 16}, "Done"};
|
||||
};
|
||||
|
||||
/* App that allows for buttons to be bound to captures for playback. */
|
||||
@@ -328,39 +328,39 @@ class RemoteAppView : public View {
|
||||
bool ready_signal_{}; // Used to signal ReplayThread ready.
|
||||
|
||||
TextField field_title{
|
||||
{0 * 8, 0 * 16 + 2, screen_width, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0) + 2, screen_width, 1 * 16},
|
||||
{}};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
{0 * 8, 17 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(3)},
|
||||
/*short_ui*/ true};
|
||||
|
||||
Checkbox check_loop{
|
||||
{10 * 8, 17 * 16},
|
||||
{10 * 8, UI_POS_Y_BOTTOM(3)},
|
||||
4,
|
||||
"Loop",
|
||||
/*small*/ true};
|
||||
|
||||
TextField field_filename{
|
||||
{0 * 8, 18 * 16, 17 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(2), 17 * 8, 1 * 16},
|
||||
{}};
|
||||
|
||||
NewButton button_add{
|
||||
{17 * 8 + 4, 17 * 16, 4 * 8, 2 * 16},
|
||||
{17 * 8 + 4, UI_POS_Y_BOTTOM(3), 4 * 8, 2 * 16},
|
||||
"",
|
||||
&bitmap_icon_add,
|
||||
Color::orange(),
|
||||
/*vcenter*/ true};
|
||||
|
||||
NewButton button_new{
|
||||
{22 * 8, 17 * 16, 4 * 8, 2 * 16},
|
||||
{22 * 8, UI_POS_Y_BOTTOM(3), 4 * 8, 2 * 16},
|
||||
"",
|
||||
&bitmap_icon_new_file,
|
||||
Color::dark_blue(),
|
||||
/*vcenter*/ true};
|
||||
|
||||
NewButton button_open{
|
||||
{26 * 8, 17 * 16, 4 * 8, 2 * 16},
|
||||
{26 * 8, UI_POS_Y_BOTTOM(3), 4 * 8, 2 * 16},
|
||||
"",
|
||||
&bitmap_icon_load,
|
||||
Color::dark_blue(),
|
||||
|
||||
+37
-33
@@ -173,33 +173,37 @@ class ScannerView : public View {
|
||||
};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 1 * 16}, "BW: SQ: Wsa: Wsl:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 10 * 16}, "SRCH START SEARCH END SWITCH", 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},
|
||||
{{UI_POS_X(0), UI_POS_Y(1)}, "BW: SQ: Wsa: Wsl:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(13), UI_POS_Y(1)}, "Wsa: Wsl:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(10)}, "SRCH START", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(10) + 8, UI_POS_Y(10)}, "SEARCH END", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(6), UI_POS_Y(10)}, "SWITCH", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
{{0 * 8, (26 * 8) + 4}, "MODE:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), (26 * 8) + 4}, "MODE:", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, (26 * 8) + 4}, "STEP:", 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)}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{24 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
OptionsField field_bw{
|
||||
{3 * 8, 1 * 16},
|
||||
{UI_POS_X(3), UI_POS_Y(1)},
|
||||
6,
|
||||
{}};
|
||||
|
||||
NumberField field_squelch{
|
||||
{13 * 8, 1 * 16},
|
||||
{UI_POS_X(13), UI_POS_Y(1)},
|
||||
3,
|
||||
{-90, 20},
|
||||
1,
|
||||
@@ -208,7 +212,7 @@ class ScannerView : public View {
|
||||
|
||||
NumberField field_browse_wait{
|
||||
// Signal-Active wait timer - time to wait before moving on even when signal locked
|
||||
{21 * 8, 1 * 16},
|
||||
{UI_POS_X_RIGHT(9), UI_POS_Y(1)},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
@@ -217,7 +221,7 @@ class ScannerView : public View {
|
||||
|
||||
NumberField field_lock_wait{
|
||||
// Signal-Lost wait timer - time to wait before moving on after losing signal lock
|
||||
{screen_width - 2 * 8, 1 * 16},
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(1)},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
@@ -225,20 +229,20 @@ class ScannerView : public View {
|
||||
};
|
||||
|
||||
RSSI rssi{
|
||||
{0 * 16, 2 * 16, 15 * 16, 8},
|
||||
{UI_POS_X(0), UI_POS_Y(2), UI_POS_WIDTH_REMAINING(6), 8},
|
||||
};
|
||||
|
||||
TextField field_current_index{
|
||||
{0, 3 * 16, 3 * 8, 16},
|
||||
{UI_POS_X(0), UI_POS_Y(3), 3 * 8, 16},
|
||||
{},
|
||||
};
|
||||
|
||||
Text text_max_index{
|
||||
{4 * 8, 3 * 16, 18 * 8, 16},
|
||||
{UI_POS_X(4), UI_POS_Y(3), 18 * 8, 16},
|
||||
};
|
||||
|
||||
Text text_current_desc{
|
||||
{0, 4 * 16, screen_width - 6 * 8, 16},
|
||||
{UI_POS_X(0), UI_POS_Y(4), UI_POS_WIDTH_REMAINING(6), UI_POS_HEIGHT(1)},
|
||||
};
|
||||
|
||||
BigFrequency big_display{
|
||||
@@ -246,15 +250,15 @@ class ScannerView : public View {
|
||||
0};
|
||||
|
||||
Button button_manual_start{
|
||||
{0 * 8, 11 * 16, 11 * 8, 28},
|
||||
{UI_POS_X(0), UI_POS_Y(11), UI_POS_WIDTH(10), 28},
|
||||
""};
|
||||
|
||||
Button button_manual_end{
|
||||
{12 * 8, 11 * 16, 11 * 8, 28},
|
||||
{UI_POS_X_CENTER(10) + 8, UI_POS_Y(11), UI_POS_WIDTH(10), 28},
|
||||
""};
|
||||
|
||||
Button button_manual_search{
|
||||
{24 * 8, 11 * 16, 6 * 8, 28},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(11), UI_POS_WIDTH(6), 28},
|
||||
""};
|
||||
|
||||
OptionsField field_mode{
|
||||
@@ -273,34 +277,34 @@ class ScannerView : public View {
|
||||
{0, (15 * 16) - 4, 72, 28},
|
||||
"<PAUSE>"};
|
||||
|
||||
Button button_audio_app{
|
||||
{UI_POS_X_CENTER(9), (15 * 16) - 4, UI_POS_WIDTH(9), 28},
|
||||
"AUDIO"};
|
||||
|
||||
Button button_add{
|
||||
{UI_POS_X_RIGHT(9), (15 * 16) - 4, UI_POS_WIDTH(9), 28},
|
||||
"ADD FQ"};
|
||||
|
||||
Button button_dir{
|
||||
{0, (35 * 8) - 4, 72, 28},
|
||||
"REVERSE"};
|
||||
|
||||
Button button_audio_app{
|
||||
{84, (15 * 16) - 4, 72, 28},
|
||||
"AUDIO"};
|
||||
|
||||
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"};
|
||||
|
||||
Button button_add{
|
||||
{168, (15 * 16) - 4, 72, 28},
|
||||
"ADD FQ"};
|
||||
Button button_remove{
|
||||
{UI_POS_X_RIGHT(9), (35 * 8) - 4, UI_POS_WIDTH(9), 28},
|
||||
"DEL FQ"};
|
||||
|
||||
Button button_load{
|
||||
{24 * 8, 3 * 16 - 10, 6 * 8, 22},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(3) - 10, UI_POS_WIDTH(6), 22},
|
||||
"LOAD"};
|
||||
|
||||
Button button_clear{
|
||||
{24 * 8, 4 * 16, 6 * 8, 22},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(4), UI_POS_WIDTH(6), 22},
|
||||
"MCLR"};
|
||||
|
||||
Button button_remove{
|
||||
{168, (35 * 8) - 4, 72, 28},
|
||||
"DEL FQ"};
|
||||
|
||||
std::unique_ptr<ScannerThread> scan_thread{};
|
||||
|
||||
MessageHandlerRegistration message_handler_retune{
|
||||
|
||||
@@ -62,19 +62,19 @@ class ShoppingCartLock : public View {
|
||||
true};
|
||||
|
||||
Text text_empty{
|
||||
{40, 70, 160, 16},
|
||||
{UI_POS_X_CENTER(20), 70, 160, 16},
|
||||
"RocketGod was here"};
|
||||
|
||||
Button button_lock{
|
||||
{40, 165, 160, 35},
|
||||
{UI_POS_X_CENTER(20), 165, 160, 35},
|
||||
LanguageHelper::currentMessages[LANG_LOCK]};
|
||||
|
||||
Button button_unlock{
|
||||
{40, 205, 160, 35},
|
||||
{UI_POS_X_CENTER(20), 205, 160, 35},
|
||||
LanguageHelper::currentMessages[LANG_UNLOCK]};
|
||||
|
||||
Button button_stop{
|
||||
{40, 245, 160, 35},
|
||||
{UI_POS_X_CENTER(20), 245, 160, 35},
|
||||
LanguageHelper::currentMessages[LANG_STOP]};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal{
|
||||
|
||||
+9
-9
@@ -175,7 +175,7 @@ void SnakeView::erase_food() {
|
||||
|
||||
void SnakeView::draw_score() {
|
||||
auto style = *ui::Theme::getInstance()->fg_blue;
|
||||
painter.draw_string({5, 5}, style, "Score: " + std::to_string(score));
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 5}, style, "Score: " + std::to_string(score));
|
||||
}
|
||||
|
||||
void SnakeView::draw_borders() {
|
||||
@@ -189,11 +189,11 @@ void SnakeView::show_menu() {
|
||||
auto style_yellow = *ui::Theme::getInstance()->fg_yellow;
|
||||
auto style_green = *ui::Theme::getInstance()->fg_green;
|
||||
auto style_blue = *ui::Theme::getInstance()->fg_blue;
|
||||
painter.draw_string({50, 40}, style_yellow, "* * * SNAKE * * *");
|
||||
painter.draw_string({0, 120}, style_blue, "USE THE D-PAD TO MOVE");
|
||||
painter.draw_string({0, 150}, style_blue, "EAT THE RED SQUARES TO GROW");
|
||||
painter.draw_string({0, 180}, style_blue, "DON'T HIT THE WALLS OR SELF");
|
||||
painter.draw_string({15, 240}, style_green, "** PRESS SELECT TO START **");
|
||||
painter.draw_string({UI_POS_X_CENTER(18), 40}, style_yellow, "* * * SNAKE * * *");
|
||||
painter.draw_string({UI_POS_X_CENTER(22), 120}, style_blue, "USE THE D-PAD TO MOVE");
|
||||
painter.draw_string({UI_POS_X_CENTER(28), 150}, style_blue, "EAT THE RED SQUARES TO GROW");
|
||||
painter.draw_string({UI_POS_X_CENTER(28), 180}, style_blue, "DON'T HIT THE WALLS OR SELF");
|
||||
painter.draw_string({UI_POS_X_CENTER(28), 240}, style_green, "** PRESS SELECT TO START **");
|
||||
}
|
||||
|
||||
void SnakeView::show_game_over() {
|
||||
@@ -202,9 +202,9 @@ void SnakeView::show_game_over() {
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
auto style_yellow = *ui::Theme::getInstance()->fg_yellow;
|
||||
auto style_green = *ui::Theme::getInstance()->fg_green;
|
||||
painter.draw_string({75, 90}, style_red, "GAME OVER");
|
||||
painter.draw_string({74, 150}, style_yellow, "SCORE: " + std::to_string(score));
|
||||
painter.draw_string({20, 220}, style_green, "PRESS SELECT TO RESTART");
|
||||
painter.draw_string({UI_POS_X_CENTER(10), 90}, style_red, "GAME OVER");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 150}, style_yellow, "SCORE: " + std::to_string(score));
|
||||
painter.draw_string({UI_POS_X_CENTER(24), 220}, style_green, "PRESS SELECT TO RESTART");
|
||||
wait(1);
|
||||
}
|
||||
|
||||
|
||||
+14
-14
@@ -95,25 +95,25 @@ class SoundBoardView : public View {
|
||||
void update_config();
|
||||
|
||||
Labels labels{
|
||||
{{24 * 8, 180}, "Vol:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0, 180}, "Key:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{24 * 8, UI_POS_Y_BOTTOM(9)}, "Vol:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0, UI_POS_Y_BOTTOM(9)}, "Key:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Button button_next_page{
|
||||
{30 * 7, 25 * 8, 10 * 3, 2 * 14},
|
||||
{UI_POS_X_RIGHT(4), UI_POS_Y_BOTTOM(8), 10 * 3, 2 * 14},
|
||||
"=>"};
|
||||
|
||||
Button button_prev_page{
|
||||
{17 * 10, 25 * 8, 10 * 3, 2 * 14},
|
||||
{UI_POS_X_RIGHT(8), UI_POS_Y_BOTTOM(8), 10 * 3, 2 * 14},
|
||||
"<="};
|
||||
|
||||
Text page_info{
|
||||
{0, 29 * 8, screen_width, 16}};
|
||||
{0, UI_POS_Y_BOTTOM(6), screen_width, 16}};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 0, screen_width, 175},
|
||||
{0, 0, screen_width, UI_POS_Y_BOTTOM(9)},
|
||||
true};
|
||||
Text text_empty{
|
||||
{7 * 8, 12 * 8, 16 * 8, 16},
|
||||
{UI_POS_X_CENTER(16), 12 * 8, 16 * 8, 16},
|
||||
"Empty directory !",
|
||||
};
|
||||
|
||||
@@ -126,31 +126,31 @@ class SoundBoardView : public View {
|
||||
};*/
|
||||
|
||||
OptionsField options_tone_key{
|
||||
{4 * 8, 180},
|
||||
{4 * 8, UI_POS_Y_BOTTOM(9)},
|
||||
18,
|
||||
{}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 180}};
|
||||
{screen_width - 2 * 8, UI_POS_Y_BOTTOM(9)}};
|
||||
Text text_volume_disabled{
|
||||
{screen_width - 2 * 8, 180, 3 * 8, 16},
|
||||
{screen_width - 2 * 8, UI_POS_Y_BOTTOM(9), 3 * 8, 16},
|
||||
"--"};
|
||||
|
||||
Checkbox check_loop{
|
||||
{0, 25 * 8 + 4},
|
||||
{0, UI_POS_Y_BOTTOM(8)},
|
||||
4,
|
||||
"Loop"};
|
||||
|
||||
Checkbox check_random{
|
||||
{10 * 7, 25 * 8 + 4},
|
||||
{10 * 7, UI_POS_Y_BOTTOM(8)},
|
||||
6,
|
||||
"Random"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 8, 31 * 8 + 2, screen_width, 4}};
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(4.5) + 2, screen_width, 4}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
5000,
|
||||
12};
|
||||
|
||||
|
||||
@@ -183,20 +183,23 @@ void SpectrumPainterView::focus() {
|
||||
void SpectrumPainterView::paint(Painter& painter) {
|
||||
View::paint(painter);
|
||||
|
||||
size_t c;
|
||||
Point pos = {0, screen_pos().y() + 8 + footer_location};
|
||||
|
||||
for (c = 0; c < 20; c++) {
|
||||
uint16_t c;
|
||||
Point pos = {0, UI_POS_Y_BOTTOM(1)};
|
||||
Point pos2 = {0, UI_POS_Y_BOTTOM(4)};
|
||||
// 24*8 pxstripes
|
||||
for (c = 0; c < screen_width / 24 + 1; c++) {
|
||||
painter.draw_bitmap(
|
||||
pos,
|
||||
bitmap_stripes,
|
||||
Theme::getInstance()->fg_yellow->foreground,
|
||||
Theme::getInstance()->fg_yellow->background);
|
||||
if (c != 9)
|
||||
pos += {24, 0};
|
||||
else
|
||||
pos = {0, screen_pos().y() + 8 + footer_location + 32 + 8};
|
||||
painter.draw_bitmap(
|
||||
pos2,
|
||||
bitmap_stripes,
|
||||
Theme::getInstance()->fg_yellow->foreground,
|
||||
Theme::getInstance()->fg_yellow->background);
|
||||
pos += {24, 0};
|
||||
pos2 += {24, 0};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::spainter
|
||||
|
||||
+11
-11
@@ -89,57 +89,57 @@ class SpectrumPainterView : public View {
|
||||
|
||||
static constexpr int32_t footer_location = 15 * 16 + 8;
|
||||
ProgressBar progressbar{
|
||||
{4, footer_location - 16, screen_width - 8, 16}};
|
||||
{4, UI_POS_Y_BOTTOM(6) - 3, screen_width - 8, 16}};
|
||||
|
||||
Labels labels{
|
||||
{{10 * 8, footer_location + 1 * 16}, "GAIN A:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, footer_location + 2 * 16}, "BW: Du: P:", Theme::getInstance()->fg_light->foreground},
|
||||
{{10 * 8, UI_POS_Y_BOTTOM(4)}, "GAIN A:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, UI_POS_Y_BOTTOM(3)}, "BW: Du: P:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, footer_location + 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(4)},
|
||||
nav_};
|
||||
|
||||
NumberField field_rfgain{
|
||||
{14 * 8, footer_location + 1 * 16},
|
||||
{14 * 8, UI_POS_Y_BOTTOM(4)},
|
||||
2,
|
||||
{0, 47},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_rfamp{
|
||||
{19 * 8, footer_location + 1 * 16},
|
||||
{19 * 8, UI_POS_Y_BOTTOM(4)},
|
||||
2,
|
||||
{0, 14},
|
||||
14,
|
||||
' '};
|
||||
|
||||
Checkbox check_loop{
|
||||
{21 * 8, footer_location + 1 * 16},
|
||||
{21 * 8, UI_POS_Y_BOTTOM(4)},
|
||||
4,
|
||||
LanguageHelper::currentMessages[LANG_LOOP],
|
||||
true};
|
||||
|
||||
ImageButton button_play{
|
||||
{screen_width - 2 * 8, footer_location + 1 * 16, 2 * 8, 1 * 16},
|
||||
{screen_width - 2 * 8, UI_POS_Y_BOTTOM(4), 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
OptionsField option_bandwidth{
|
||||
{4 * 8, footer_location + 2 * 16},
|
||||
{4 * 8, UI_POS_Y_BOTTOM(3)},
|
||||
5,
|
||||
{}};
|
||||
|
||||
NumberField field_duration{
|
||||
{13 * 8, footer_location + 2 * 16},
|
||||
{13 * 8, UI_POS_Y_BOTTOM(3)},
|
||||
3,
|
||||
{1, 999},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_pause{
|
||||
{19 * 8, footer_location + 2 * 16},
|
||||
{19 * 8, UI_POS_Y_BOTTOM(3)},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
|
||||
@@ -58,7 +58,7 @@ class SpectrumInputImageView : public View {
|
||||
uint32_t data_start{0};
|
||||
|
||||
Button button_load_image{
|
||||
{0 * 8, 11 * 16 - 4, screen_width, 28},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(10), screen_width, 28},
|
||||
"Load Image ..."};
|
||||
|
||||
bool drawBMP_scaled(const ui::Rect r, const std::string file);
|
||||
|
||||
@@ -53,43 +53,43 @@ class SpectrumInputTextView : public View {
|
||||
void on_set_text(NavigationView& nav);
|
||||
|
||||
Text text_message_0{
|
||||
{0 * 8, 0 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0), screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_1{
|
||||
{0 * 8, 1 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 1 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_2{
|
||||
{0 * 8, 2 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 2 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_3{
|
||||
{0 * 8, 3 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 3 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_4{
|
||||
{0 * 8, 4 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 4 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_5{
|
||||
{0 * 8, 5 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 5 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_6{
|
||||
{0 * 8, 6 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 6 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_7{
|
||||
{0 * 8, 7 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 7 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_8{
|
||||
{0 * 8, 8 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 8 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
Text text_message_9{
|
||||
{0 * 8, 9 * 16, screen_width, 16},
|
||||
{UI_POS_X(0), 9 * 16, screen_width, 16},
|
||||
""};
|
||||
|
||||
std::array<Text*, 10> text_message{{
|
||||
@@ -106,7 +106,7 @@ class SpectrumInputTextView : public View {
|
||||
}};
|
||||
|
||||
Button button_message{
|
||||
{0 * 8, 11 * 16 - 4, screen_width, 28},
|
||||
{UI_POS_X(0), UI_POS_Y_BOTTOM(10), screen_width, 28},
|
||||
"Set message"};
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -93,10 +93,10 @@ class SSTVTXView : public View {
|
||||
{}};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{16, 25 * 8, 208, 16}};
|
||||
{16, 25 * 8, UI_POS_WIDTH_REMAINING(4), 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
10000,
|
||||
12};
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ class StopwatchView : public View {
|
||||
/* m m s s ms ms ms*/
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "TOTAL:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "LAP:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 1 * 16}, "TOTAL:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 7 * 16}, "LAP:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
OptionsField options_ms_display_level{
|
||||
@@ -71,15 +71,15 @@ class StopwatchView : public View {
|
||||
Painter painter;
|
||||
|
||||
Button button_run_stop{
|
||||
{72, 210, 96, 24},
|
||||
{UI_POS_X_CENTER(12), 210, 96, 24},
|
||||
"START"};
|
||||
|
||||
Button button_reset_lap{
|
||||
{72, screen_height - 80, 96, 24},
|
||||
{UI_POS_X_CENTER(12), screen_height - 80, 96, 24},
|
||||
"RESET"};
|
||||
|
||||
Button button_done{
|
||||
{72, screen_height - 50, 96, 24},
|
||||
{UI_POS_X_CENTER(12), screen_height - 50, 96, 24},
|
||||
"EXIT"};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
|
||||
+6
-2
@@ -198,8 +198,12 @@ void RecentEntriesTable<ui::external_app::tpmsrx::TPMSRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style) {
|
||||
std::string line = ui::external_app::tpmsrx::format::type(entry.type) + " " + ui::external_app::tpmsrx::format::id(entry.id);
|
||||
const Style& style,
|
||||
RecentEntriesColumns& columns) {
|
||||
std::string line = ui::external_app::tpmsrx::format::type(entry.type) + " ";
|
||||
std::string lid = ui::external_app::tpmsrx::format::id(entry.id);
|
||||
lid.resize(columns.at(1).second, ' ');
|
||||
line += lid;
|
||||
|
||||
if (entry.last_pressure.is_valid()) {
|
||||
line += " " + ui::external_app::tpmsrx::format::pressure(entry.last_pressure.value());
|
||||
|
||||
+12
-14
@@ -134,19 +134,17 @@ class TPMSAppView : public View {
|
||||
ui::Rect view_normal_rect{};
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4},
|
||||
{UI_POS_X(21), 0, UI_POS_WIDTH_REMAINING(24), 4},
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4},
|
||||
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(24), 4},
|
||||
};
|
||||
AudioVolumeField field_volume{
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
// "315 MHz" TPMS sensors transmit at either 314.9 or 315 MHz but we should pick up either
|
||||
OptionsField options_band{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
5,
|
||||
{
|
||||
{"314.9", 314900000},
|
||||
@@ -155,32 +153,32 @@ class TPMSAppView : public View {
|
||||
}};
|
||||
|
||||
OptionsField options_pressure{
|
||||
{6 * 8, 0 * 16},
|
||||
{6 * 8, UI_POS_Y(0)},
|
||||
3,
|
||||
{{"kPa", 0},
|
||||
{"PSI", 1}}};
|
||||
|
||||
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)}};
|
||||
|
||||
TPMSRecentEntries recent{};
|
||||
std::unique_ptr<TPMSLogger> logger{};
|
||||
|
||||
const RecentEntriesColumns columns{{
|
||||
RecentEntriesColumns columns{{
|
||||
{"Tp", 2},
|
||||
{"ID", 8},
|
||||
{"ID", 0},
|
||||
{"Pres", 4},
|
||||
{"Temp", 4},
|
||||
{"Cnt", 3},
|
||||
|
||||
+6
-6
@@ -69,11 +69,11 @@ class TunerView : public View {
|
||||
bool current_note_playing{false};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Instrument:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Note:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Note Frequency:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 4 * 16}, "Note Octave Shift:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 1 * 16}, "Instrument:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 2 * 16}, "Note:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Note Frequency:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 4 * 16}, "Note Octave Shift:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 5 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_note_frequency{
|
||||
{(sizeof("Note Frequency:") + 1) * 8, 3 * 16, (int)screen_width - (int)(sizeof("Note Frequency:") + 1) * 8, 16},
|
||||
@@ -102,7 +102,7 @@ class TunerView : public View {
|
||||
{}};
|
||||
|
||||
NewButton button_play_stop{
|
||||
{0 * 8, 16 * 16, screen_width, screen_height - 16 * 16},
|
||||
{UI_POS_X(0), 16 * 16, screen_width, screen_height - 16 * 16},
|
||||
{},
|
||||
&bitmap_icon_replay,
|
||||
Theme::getInstance()->fg_red->foreground};
|
||||
|
||||
@@ -48,16 +48,16 @@ class WardriveMapView : public View {
|
||||
const std::filesystem::path flippersub_dir = u"subghz";
|
||||
NavigationView& nav_;
|
||||
|
||||
Text text_info{{0 * 8, 0 * 8, 20 * 8, 16 * 1}, "0 / 30"};
|
||||
Text text_notfound{{0 * 8, 0 * 8, screen_width, 16 * 1}, "No GeoTagged captures found"};
|
||||
Text text_info{{UI_POS_X(0), 0 * 8, 20 * 8, 16 * 1}, "0 / 30"};
|
||||
Text text_notfound{{UI_POS_X(0), 0 * 8, screen_width, 16 * 1}, "No GeoTagged captures found"};
|
||||
GeoPos geopos{
|
||||
{0, 20},
|
||||
GeoPos::alt_unit::METERS,
|
||||
GeoPos::spd_unit::HIDDEN};
|
||||
GeoMap geomap{{0, 75, screen_width, screen_height - 75}};
|
||||
|
||||
Button btn_back{{22 * 8, 0 * 8, 3 * 8, 16}, "<-"};
|
||||
Button btn_next{{26 * 8, 0 * 8, 3 * 8, 16}, "->"};
|
||||
Button btn_back{{UI_POS_X_RIGHT(8), 0 * 8, 3 * 8, 16}, "<-"};
|
||||
Button btn_next{{UI_POS_X_RIGHT(4), 0 * 8, 3 * 8, 16}, "->"};
|
||||
|
||||
void on_gps(const GPSPosDataMessage* msg);
|
||||
void on_orientation(const OrientationDataMessage* msg);
|
||||
|
||||
+18
-12
@@ -49,26 +49,26 @@ void ViewWavView::refresh_waveform() {
|
||||
|
||||
uint8_t bits_per_sample = wav_reader->bits_per_sample();
|
||||
|
||||
for (size_t i = 0; i < 240; i++) {
|
||||
for (size_t i = 0; i < screen_width; i++) {
|
||||
wav_reader->data_seek(position + (i * scale));
|
||||
if (bits_per_sample == 8) {
|
||||
uint8_t sample;
|
||||
wav_reader->read(&sample, 1);
|
||||
waveform_buffer[i] = (sample - 0x80) * 256;
|
||||
} else {
|
||||
wav_reader->read(&waveform_buffer[i], 2);
|
||||
wav_reader->read(&waveform_buffer.data()[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
waveform.set_dirty();
|
||||
|
||||
// Window
|
||||
uint64_t w_start = (position * 240) / wav_reader->sample_count();
|
||||
uint64_t w_width = (scale * 240) / (wav_reader->sample_count() / 240);
|
||||
display.fill_rectangle({0, 10 * 16 + 1, 240, 16}, Theme::getInstance()->bg_darkest->background);
|
||||
uint64_t w_start = (position * screen_width) / wav_reader->sample_count();
|
||||
uint64_t w_width = (scale * screen_width) / (wav_reader->sample_count() / screen_width);
|
||||
display.fill_rectangle({0, 10 * 16 + 1, screen_width, 16}, Theme::getInstance()->bg_darkest->background);
|
||||
display.fill_rectangle({(Coord)w_start, 21 * 8, (Dim)w_width + 1, 8}, Theme::getInstance()->bg_darkest->foreground);
|
||||
display.draw_line({0, 10 * 16 + 1}, {(Coord)w_start, 21 * 8}, Theme::getInstance()->bg_darkest->foreground);
|
||||
display.draw_line({239, 10 * 16 + 1}, {(Coord)(w_start + w_width), 21 * 8}, Theme::getInstance()->bg_darkest->foreground);
|
||||
display.draw_line({screen_width - 1, 10 * 16 + 1}, {(Coord)(w_start + w_width), 21 * 8}, Theme::getInstance()->bg_darkest->foreground);
|
||||
}
|
||||
|
||||
void ViewWavView::refresh_measurements() {
|
||||
@@ -82,11 +82,11 @@ void ViewWavView::refresh_measurements() {
|
||||
|
||||
void ViewWavView::paint(Painter& painter) {
|
||||
// Waveform limits
|
||||
painter.draw_hline({0, 6 * 16 - 1}, 240, Theme::getInstance()->bg_medium->background);
|
||||
painter.draw_hline({0, 10 * 16}, 240, Theme::getInstance()->bg_medium->background);
|
||||
painter.draw_hline({0, 6 * 16 - 1}, screen_width, Theme::getInstance()->bg_medium->background);
|
||||
painter.draw_hline({0, 10 * 16}, screen_width, Theme::getInstance()->bg_medium->background);
|
||||
|
||||
// Overall amplitude view, 0~127 to 0~255 color index
|
||||
for (size_t i = 0; i < 240; i++)
|
||||
for (size_t i = 0; i < screen_width; i++)
|
||||
painter.draw_vline({(Coord)i, 11 * 16}, 8, spectrum_rgb2_lut[amplitude_buffer[i] << 1]);
|
||||
}
|
||||
|
||||
@@ -128,10 +128,10 @@ void ViewWavView::load_wav(std::filesystem::path file_path) {
|
||||
text_title.set(wav_reader->title());
|
||||
|
||||
// Fill amplitude buffer, world's worst downsampling
|
||||
uint64_t skip = wav_reader->sample_count() / (240 * subsampling_factor);
|
||||
uint64_t skip = wav_reader->sample_count() / (screen_width * subsampling_factor);
|
||||
uint8_t bits_per_sample = wav_reader->bits_per_sample();
|
||||
|
||||
for (size_t i = 0; i < 240; i++) {
|
||||
for (size_t i = 0; i < screen_width; i++) {
|
||||
average = 0;
|
||||
|
||||
for (size_t s = 0; s < subsampling_factor; s++) {
|
||||
@@ -163,7 +163,7 @@ void ViewWavView::reset_controls() {
|
||||
field_pos_seconds.set_range(0, wav_reader->ms_duration() / 1000);
|
||||
field_pos_milliseconds.set_range(0, (wav_reader->ms_duration() < 1000) ? wav_reader->ms_duration() % 1000 : 999);
|
||||
field_pos_samples.set_range(0, wav_reader->sample_count() - 1);
|
||||
field_scale.set_range(1, std::min(99999ul, wav_reader->sample_count() / 240));
|
||||
field_scale.set_range(1, std::min(99999ul, wav_reader->sample_count() / screen_width));
|
||||
}
|
||||
|
||||
bool ViewWavView::is_active() {
|
||||
@@ -262,6 +262,12 @@ void ViewWavView::on_playback_progress(const uint32_t progress) {
|
||||
ViewWavView::ViewWavView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
waveform_buffer.resize(screen_width);
|
||||
amplitude_buffer.resize(screen_width);
|
||||
waveform.set_length(screen_width);
|
||||
waveform.set_data((int16_t*)waveform_buffer.data());
|
||||
for (auto& v : waveform_buffer) v = 0;
|
||||
for (auto& v : amplitude_buffer) v = 0;
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
wav_reader = std::make_unique<WAVFileReader>();
|
||||
|
||||
|
||||
+23
-22
@@ -73,8 +73,8 @@ class ViewWavView : public View {
|
||||
|
||||
std::unique_ptr<WAVFileReader> wav_reader{};
|
||||
|
||||
int16_t waveform_buffer[240]{};
|
||||
uint8_t amplitude_buffer[240]{};
|
||||
std::vector<int16_t> waveform_buffer{};
|
||||
std::vector<uint8_t> amplitude_buffer{};
|
||||
int32_t scale{1};
|
||||
uint64_t ns_per_pixel{};
|
||||
uint64_t position{};
|
||||
@@ -83,53 +83,54 @@ class ViewWavView : public View {
|
||||
bool waveform_update_needed{false};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "File:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "File:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 1 * 16}, "-bit mono", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 2 * 16}, "Title:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "Duration:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 12 * 16}, "Position: . s Scale:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 13 * 16}, " Sample:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 14 * 16}, "Cursor A:", Theme::getInstance()->fg_darkcyan->foreground},
|
||||
{{0 * 8, 15 * 16}, "Cursor B:", Theme::getInstance()->fg_magenta->foreground},
|
||||
{{0 * 8, 16 * 16}, "Delta:", Theme::getInstance()->fg_light->foreground},
|
||||
{{24 * 8, 18 * 16}, "Vol:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), 2 * 16}, "Title:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 3 * 16}, "Duration:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 12 * 16}, "Position: . s Scale:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 13 * 16}, " Sample:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 14 * 16}, "Cursor A:", Theme::getInstance()->fg_darkcyan->foreground},
|
||||
{{UI_POS_X(0), 15 * 16}, "Cursor B:", Theme::getInstance()->fg_magenta->foreground},
|
||||
{{UI_POS_X(0), 16 * 16}, "Delta:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_RIGHT(6), UI_POS_Y_BOTTOM(2)}, "Vol:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_filename{
|
||||
{5 * 8, 0 * 16, 18 * 8, 16},
|
||||
{UI_POS_X(5), UI_POS_Y(0), UI_POS_WIDTH_REMAINING(12), UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
Text text_samplerate{
|
||||
{12 * 8, 1 * 16, 10 * 8, 16},
|
||||
{12 * 8, 1 * 16, 10 * 8, UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
Text text_title{
|
||||
{6 * 8, 2 * 16, 17 * 8, 16},
|
||||
{6 * 8, 2 * 16, 17 * 8, UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
Text text_duration{
|
||||
{9 * 8, 3 * 16, 20 * 8, 16},
|
||||
{9 * 8, 3 * 16, 20 * 8, UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
Text text_bits_per_sample{
|
||||
{0 * 8, 1 * 16, 2 * 8, 16},
|
||||
{UI_POS_X(0), 1 * 16, 2 * 8, UI_POS_HEIGHT(1)},
|
||||
"16"};
|
||||
Button button_open{
|
||||
{24 * 8, 8, 6 * 8, 2 * 16},
|
||||
{UI_POS_X_RIGHT(6), 8, UI_POS_WIDTH(6), UI_POS_HEIGHT(2)},
|
||||
"Open"};
|
||||
ImageButton button_play{
|
||||
{24 * 8, 17 * 16, 2 * 8, 1 * 16},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y_BOTTOM(3), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 18 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y_BOTTOM(2)}};
|
||||
|
||||
Waveform waveform{
|
||||
{0, 5 * 16, screen_width, 64},
|
||||
waveform_buffer,
|
||||
{0, UI_POS_Y(5), screen_width, UI_POS_HEIGHT(4)},
|
||||
waveform_buffer.data(),
|
||||
240,
|
||||
0,
|
||||
false,
|
||||
Theme::getInstance()->bg_darkest->foreground};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 8, 11 * 16, screen_width, 4}};
|
||||
{UI_POS_X(0), 11 * 16, screen_width, 4}};
|
||||
|
||||
NumberField field_pos_seconds{
|
||||
{9 * 8, 12 * 16},
|
||||
|
||||
+8
-8
@@ -84,18 +84,18 @@ class WeFaxRxView : 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), 0, UI_POS_WIDTH_REMAINING(24), 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
Labels labels{
|
||||
@@ -124,11 +124,11 @@ class WeFaxRxView : public View {
|
||||
}};
|
||||
|
||||
Text txt_status{
|
||||
{0 * 8, 2 * 16, 20 * 8, 16},
|
||||
{UI_POS_X(0), 2 * 16, 20 * 8, 16},
|
||||
};
|
||||
|
||||
Button button_ss{
|
||||
{190, 2 * 16, 5 * 8, 16},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(2), UI_POS_WIDTH(6), UI_POS_HEIGHT(1)},
|
||||
LanguageHelper::currentMessages[LANG_START]};
|
||||
|
||||
MessageHandlerRegistration message_handler_stats{
|
||||
|
||||
Reference in New Issue
Block a user