From a1d7cf2b86f67640f607b75a0be4a41810e25460 Mon Sep 17 00:00:00 2001 From: Totoo Date: Thu, 22 May 2025 17:24:53 +0200 Subject: [PATCH] Prepare for display orientation part 1 (#2661) --- firmware/application/apps/ble_comm_app.hpp | 2 +- firmware/application/apps/ble_rx_app.hpp | 8 +- firmware/application/apps/ble_tx_app.hpp | 4 +- firmware/application/apps/soundboard_app.hpp | 2 +- firmware/application/apps/ui_about_simple.hpp | 8 +- firmware/application/apps/ui_adsb_rx.cpp | 2 +- firmware/application/apps/ui_aprs_rx.cpp | 4 +- firmware/application/apps/ui_aprs_rx.hpp | 6 +- firmware/application/apps/ui_bht_tx.hpp | 2 +- .../application/apps/ui_bmp_file_viewer.hpp | 2 +- firmware/application/apps/ui_btle_rx.hpp | 4 +- firmware/application/apps/ui_debug.cpp | 6 +- firmware/application/apps/ui_debug.hpp | 6 +- firmware/application/apps/ui_encoders.hpp | 4 +- .../apps/ui_external_module_view.hpp | 2 +- firmware/application/apps/ui_fileman.cpp | 2 +- firmware/application/apps/ui_fileman.hpp | 2 +- .../application/apps/ui_flash_utility.cpp | 2 +- .../application/apps/ui_flash_utility.hpp | 2 +- firmware/application/apps/ui_iq_trim.cpp | 1 + firmware/application/apps/ui_iq_trim.hpp | 2 +- .../application/apps/ui_looking_glass_app.cpp | 61 +++++----- .../application/apps/ui_looking_glass_app.hpp | 17 ++- firmware/application/apps/ui_rds.hpp | 2 +- firmware/application/apps/ui_recon.cpp | 4 +- firmware/application/apps/ui_recon.hpp | 14 +-- .../application/apps/ui_recon_settings.hpp | 6 +- firmware/application/apps/ui_settings.cpp | 2 +- firmware/application/apps/ui_settings.hpp | 4 +- firmware/application/apps/ui_sigfrx.cpp | 4 +- firmware/application/apps/ui_ss_viewer.cpp | 2 +- firmware/application/apps/ui_subghzd.hpp | 2 +- firmware/application/apps/ui_test.cpp | 4 +- .../external/acars_rx/acars_app.hpp | 2 +- .../external/adsbtx/ui_adsb_tx.hpp | 2 +- .../external/afsk_rx/ui_afsk_rx.hpp | 2 +- .../external/antenna_length/ui_whipcalc.hpp | 2 +- .../external/blespam/ui_blespam.hpp | 2 +- .../external/breakout/ui_breakout.cpp | 22 ++-- .../external/breakout/ui_breakout.hpp | 4 +- .../external/cvs_spam/cvs_spam.hpp | 4 +- .../application/external/doom/ui_doom.cpp | 15 ++- .../application/external/doom/ui_doom.hpp | 2 +- .../external/foxhunt/ui_foxhunt_rx.hpp | 4 +- .../application/external/gfxeq/ui_gfxeq.cpp | 6 +- .../application/external/gfxeq/ui_gfxeq.hpp | 4 +- .../application/external/jammer/ui_jammer.cpp | 2 +- .../application/external/level/ui_level.hpp | 4 +- .../mcu_temperature/mcu_temperature.hpp | 6 +- .../external/noaaapt_rx/ui_noaaapt_rx.cpp | 2 +- .../application/external/nrf_rx/ui_nrf_rx.hpp | 4 +- .../external/ook_editor/ui_ook_editor.hpp | 2 +- .../playlist_editor/ui_playlist_editor.hpp | 2 +- .../external/protoview/ui_protoview.hpp | 8 +- .../random_password/ui_random_password.hpp | 2 +- .../application/external/remote/ui_remote.hpp | 12 +- .../external/scanner/ui_scanner.hpp | 2 +- .../external/sd_wipe/ui_sd_wipe.hpp | 2 +- .../shoppingcart_lock/shoppingcart_lock.hpp | 2 +- .../application/external/snake/ui_snake.cpp | 93 +++++--------- .../application/external/snake/ui_snake.hpp | 113 +++++++++--------- .../external/spainter/ui_spectrum_painter.cpp | 2 +- .../external/spainter/ui_spectrum_painter.hpp | 2 +- .../spainter/ui_spectrum_painter_image.cpp | 4 +- .../spainter/ui_spectrum_painter_text.cpp | 2 +- .../external/stopwatch/ui_stopwatch.hpp | 4 +- .../application/external/tetris/ui_tetris.cpp | 8 +- .../application/external/tetris/ui_tetris.hpp | 2 +- .../application/external/tuner/ui_tuner.hpp | 4 +- .../external/wardrivemap/ui_wardrivemap.hpp | 2 +- .../external/wav_view/ui_view_wav.hpp | 2 +- .../external/wefax_rx/ui_wefax_rx.cpp | 2 +- firmware/application/ui/ui_btngrid.cpp | 24 +++- firmware/application/ui/ui_btngrid.hpp | 16 ++- firmware/application/ui/ui_receiver.hpp | 2 +- firmware/application/ui/ui_tabview.cpp | 2 +- firmware/application/ui_navigation.cpp | 8 +- firmware/application/ui_navigation.hpp | 6 +- firmware/application/ui_sd_card_debug.hpp | 30 ++--- firmware/application/usb_serial_shell.cpp | 8 +- firmware/common/lcd_ili9341.hpp | 19 ++- firmware/common/png_writer.cpp | 56 ++++++++- firmware/common/png_writer.hpp | 5 +- firmware/common/ui.cpp | 3 + firmware/common/ui.hpp | 4 +- 85 files changed, 405 insertions(+), 334 deletions(-) diff --git a/firmware/application/apps/ble_comm_app.hpp b/firmware/application/apps/ble_comm_app.hpp index 246d08c08..43b07b4be 100644 --- a/firmware/application/apps/ble_comm_app.hpp +++ b/firmware/application/apps/ble_comm_app.hpp @@ -170,7 +170,7 @@ class BLECommView : public View { "-"}; Console console{ - {0, 4 * 16, 240, 240}}; + {0, 4 * 16, ui::screen_width, ui::screen_height - 80}}; std::string str_log{""}; bool logging{false}; diff --git a/firmware/application/apps/ble_rx_app.hpp b/firmware/application/apps/ble_rx_app.hpp index 1f406ffba..95eec5032 100644 --- a/firmware/application/apps/ble_rx_app.hpp +++ b/firmware/application/apps/ble_rx_app.hpp @@ -341,18 +341,18 @@ class BLERxView : public View { true}; // Console console{ - // {0, 10 * 8, 240, 240}}; + // {0, 10 * 8, screen_height, screen_height-80}}; Button button_clear_list{ - {2 * 8, 320 - (16 + 32), 7 * 8, 32}, + {2 * 8, screen_height - (16 + 32), 7 * 8, 32}, "Clear"}; Button button_save_list{ - {11 * 8, 320 - (16 + 32), 11 * 8, 32}, + {11 * 8, screen_height - (16 + 32), 11 * 8, 32}, "Export CSV"}; Button button_switch{ - {240 - 6 * 8, 320 - (16 + 32), 4 * 8, 32}, + {screen_width - 6 * 8, screen_height - (16 + 32), 4 * 8, 32}, "Tx"}; std::string str_log{""}; diff --git a/firmware/application/apps/ble_tx_app.hpp b/firmware/application/apps/ble_tx_app.hpp index 534201b71..e42b64578 100644 --- a/firmware/application/apps/ble_tx_app.hpp +++ b/firmware/application/apps/ble_tx_app.hpp @@ -288,10 +288,10 @@ class BLETxView : public View { {{0 * 8, 9 * 16}, "Packet Data:", Theme::getInstance()->fg_light->foreground}}; Console console{ - {0, 9 * 18, 240, 240}}; + {0, 9 * 18, screen_width, screen_height - 80}}; TextViewer dataEditView{ - {0, 9 * 18, 240, 240}}; + {0, 9 * 18, screen_width, screen_height - 80}}; Button button_clear_marked{ {1 * 8, 14 * 16, 13 * 8, 3 * 8}, diff --git a/firmware/application/apps/soundboard_app.hpp b/firmware/application/apps/soundboard_app.hpp index 44479ed38..6dc3d17a4 100644 --- a/firmware/application/apps/soundboard_app.hpp +++ b/firmware/application/apps/soundboard_app.hpp @@ -110,7 +110,7 @@ class SoundBoardView : public View { {0, 29 * 8, 30 * 8, 16}}; MenuView menu_view{ - {0, 0, 240, 175}, + {0, 0, screen_width, 175}, true}; Text text_empty{ {7 * 8, 12 * 8, 16 * 8, 16}, diff --git a/firmware/application/apps/ui_about_simple.hpp b/firmware/application/apps/ui_about_simple.hpp index 637a03127..3c0a349d0 100644 --- a/firmware/application/apps/ui_about_simple.hpp +++ b/firmware/application/apps/ui_about_simple.hpp @@ -6,6 +6,10 @@ #include +/* + TODO: Now it is dyn width. There should be an algorithm to fill the menu based on it's size. +*/ + namespace ui { class AboutView : public View { public: @@ -22,11 +26,11 @@ class AboutView : public View { uint16_t frame_sync_count{0}; void on_frame_sync(); MenuView menu_view{ - {0, 0, 240, 264}, + {0, 0, screen_width, screen_height - 56}, true}; Button button_ok{ - {240 / 3, 270, 240 / 3, 24}, + {screen_width / 3, screen_height - 50, screen_width / 3, 24}, "OK", }; diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index eb2f330f5..83a60eedc 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -409,7 +409,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { &status_good_frame, &field_volume}); - recent_entries_view.set_parent_rect({0, 16, 240, 272}); + recent_entries_view.set_parent_rect({0, 16, screen_width, 272}); recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) { detail_key = entry.key(); details_view = nav.push(entry); diff --git a/firmware/application/apps/ui_aprs_rx.cpp b/firmware/application/apps/ui_aprs_rx.cpp index 5a4ad63ca..e24fdcdc3 100644 --- a/firmware/application/apps/ui_aprs_rx.cpp +++ b/firmware/application/apps/ui_aprs_rx.cpp @@ -247,8 +247,8 @@ APRSTableView::APRSTableView(NavigationView& nav, Rect parent_rec) details_view.hidden(true); - recent_entries_view.set_parent_rect({0, 0, 240, 280}); - details_view.set_parent_rect({0, 0, 240, 280}); + recent_entries_view.set_parent_rect({0, 0, screen_width, screen_width - 40}); + details_view.set_parent_rect({0, 0, screen_width, screen_width - 40}); recent_entries_view.on_select = [this](const APRSRecentEntry& entry) { this->on_show_detail(entry); diff --git a/firmware/application/apps/ui_aprs_rx.hpp b/firmware/application/apps/ui_aprs_rx.hpp index 84b41da9d..8b86d47aa 100644 --- a/firmware/application/apps/ui_aprs_rx.hpp +++ b/firmware/application/apps/ui_aprs_rx.hpp @@ -134,7 +134,7 @@ class APRSDetailsView : public View { bool send_updates{false}; Console console{ - {0, 0 * 16, 240, 224}}; + {0, 0 * 16, screen_width, 224}}; Button button_done{ {160, 14 * 16, 8 * 8, 3 * 16}, @@ -249,7 +249,7 @@ class APRSRxView : public View { 4}; Console console{ - {0, 2 * 16, 240, 240}}; + {0, 2 * 16, screen_width, screen_height - 80}}; std::unique_ptr logger{}; }; @@ -265,7 +265,7 @@ class APRSRXView : public View { private: NavigationView& nav_; - Rect view_rect = {0, 3 * 8, 240, 280}; + Rect view_rect = {0, 3 * 8, screen_width, screen_height - 40}; APRSRxView view_stream{nav_, view_rect}; APRSTableView view_table{nav_, view_rect}; diff --git a/firmware/application/apps/ui_bht_tx.hpp b/firmware/application/apps/ui_bht_tx.hpp index 0aecd2915..63b5cc367 100644 --- a/firmware/application/apps/ui_bht_tx.hpp +++ b/firmware/application/apps/ui_bht_tx.hpp @@ -189,7 +189,7 @@ class BHTView : public View { tx_modes tx_mode = IDLE; - Rect view_rect = {0, 3 * 8, 240, 176}; + Rect view_rect = {0, 3 * 8, screen_width, 176}; XylosView view_xylos{view_rect}; EPARView view_EPAR{view_rect}; diff --git a/firmware/application/apps/ui_bmp_file_viewer.hpp b/firmware/application/apps/ui_bmp_file_viewer.hpp index c9bd57c41..9afc6bbe3 100644 --- a/firmware/application/apps/ui_bmp_file_viewer.hpp +++ b/firmware/application/apps/ui_bmp_file_viewer.hpp @@ -42,7 +42,7 @@ class BMPFileViewer : public View { private: NavigationView& nav_; std::filesystem::path path_{}; - BMPViewer bmp{{0, 0, 240, 320}}; + BMPViewer bmp{{0, 0, screen_width, screen_height}}; }; } // namespace ui diff --git a/firmware/application/apps/ui_btle_rx.hpp b/firmware/application/apps/ui_btle_rx.hpp index 963bfa1bf..70f4edc93 100644 --- a/firmware/application/apps/ui_btle_rx.hpp +++ b/firmware/application/apps/ui_btle_rx.hpp @@ -78,11 +78,11 @@ class BTLERxView : public View { nav_}; Button button_modem_setup{ - {240 - 12 * 8, 1 * 16, 96, 24}, + {screen_width - 12 * 8, 1 * 16, 96, 24}, "Modem setup"}; Console console{ - {0, 4 * 16, 240, 240}}; + {0, 4 * 16, screen_width, screen_height - 80}}; MessageHandlerRegistration message_handler_packet{ Message::ID::AFSKData, diff --git a/firmware/application/apps/ui_debug.cpp b/firmware/application/apps/ui_debug.cpp index a3b3ec493..b12ce79f0 100644 --- a/firmware/application/apps/ui_debug.cpp +++ b/firmware/application/apps/ui_debug.cpp @@ -202,10 +202,10 @@ RegistersView::RegistersView( }; button_done.on_select = [&nav](Button&) { nav.pop(); }; - registers_widget.set_parent_rect({0, 48, 240, 192}); + registers_widget.set_parent_rect({0, 48, screen_width, 192}); registers_widget.set_page(0); - text_title.set_parent_rect({(240 - static_cast(title.size()) * 8) / 2, 16, + text_title.set_parent_rect({(screen_width - static_cast(title.size()) * 8) / 2, 16, static_cast(title.size()) * 8, 16}); text_title.set(title); @@ -482,7 +482,7 @@ DebugPmemView::DebugPmemView(NavigationView& nav) : registers_widget(RegistersWidgetConfig{CT_PMEM, PMEM_SIZE_BYTES, page_size, 8}) { add_children({®isters_widget, &text_checksum, &text_checksum2, &button_ok}); - registers_widget.set_parent_rect({0, 32, 240, 192}); + registers_widget.set_parent_rect({0, 32, screen_width, 192}); text_checksum.set("Size: " + to_string_dec_uint(portapack::persistent_memory::data_size(), 3) + " CRC: " + to_string_hex(portapack::persistent_memory::pmem_stored_checksum(), 8)); text_checksum2.set("Calculated CRC: " + to_string_hex(portapack::persistent_memory::pmem_calculated_checksum(), 8)); diff --git a/firmware/application/apps/ui_debug.hpp b/firmware/application/apps/ui_debug.hpp index 6c7b0c43b..519d94f2f 100644 --- a/firmware/application/apps/ui_debug.hpp +++ b/firmware/application/apps/ui_debug.hpp @@ -283,7 +283,7 @@ class DebugMemoryDumpView : public View { "Write"}; Button button_done{ - {128, 240, 96, 24}, + {128, screen_height - 80, 96, 24}, "Done"}; Labels labels{ @@ -332,7 +332,7 @@ class DebugPmemView : public View { Text text_checksum2{{16, 248, 208, 16}}; Button button_ok{ - {240 / 3, 270, 240 / 3, 24}, + {screen_width / 3, 270, screen_width / 3, 24}, "OK", }; @@ -364,7 +364,7 @@ public: private: Console console { - { 8, 16, 224, 240 } + { 8, 16, 224, screen_height-80 } }; Button button_exit { diff --git a/firmware/application/apps/ui_encoders.hpp b/firmware/application/apps/ui_encoders.hpp index e164d23bc..7c32584aa 100644 --- a/firmware/application/apps/ui_encoders.hpp +++ b/firmware/application/apps/ui_encoders.hpp @@ -124,7 +124,7 @@ class EncodersConfigView : public View { ""}; Waveform waveform{ - {0, 17 * 8, 240, 32}, + {0, 17 * 8, screen_width, 32}, waveform_buffer, 0, 0, @@ -201,7 +201,7 @@ class EncodersView : public View { void start_tx(const bool scan); void on_tx_progress(const uint32_t progress, const bool done); - Rect view_rect = {0, 4 * 8, 240, 168}; + Rect view_rect = {0, 4 * 8, screen_width, 168}; EncodersConfigView view_config{nav_, view_rect}; EncodersScanView view_scan{nav_, view_rect}; diff --git a/firmware/application/apps/ui_external_module_view.hpp b/firmware/application/apps/ui_external_module_view.hpp index f09cf2f28..f91cd4541 100644 --- a/firmware/application/apps/ui_external_module_view.hpp +++ b/firmware/application/apps/ui_external_module_view.hpp @@ -84,7 +84,7 @@ class ExternalModuleView : public View { Text text_app5_name{{24, 160, 200, 16}}; Button dummy{ - {240, 0, 0, 0}, + {screen_width, 0, 0, 0}, ""}; SignalToken signal_token_tick_second{}; diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index ec4e949ac..a728b697a 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -455,7 +455,7 @@ FileLoadView::FileLoadView( add_children({&menu_view}); // Resize menu view to fill screen - menu_view.set_parent_rect({0, 3 * 8, 240, 29 * 8}); + menu_view.set_parent_rect({0, 3 * 8, screen_width, 29 * 8}); refresh_list(); diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 3a4e8da07..e6468bcb7 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -125,7 +125,7 @@ class FileManBaseView : public View { }; MenuView menu_view{ - {0, 2 * 8, 240, 26 * 8}, + {0, 2 * 8, screen_width, 26 * 8}, true}; Button button_exit{ diff --git a/firmware/application/apps/ui_flash_utility.cpp b/firmware/application/apps/ui_flash_utility.cpp index 623dfebfd..64c10f618 100644 --- a/firmware/application/apps/ui_flash_utility.cpp +++ b/firmware/application/apps/ui_flash_utility.cpp @@ -80,7 +80,7 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav) add_children({&labels, &menu_view}); - menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8}); + menu_view.set_parent_rect({0, 3 * 8, screen_width, 33 * 8}); ensure_directory(apps_dir); ensure_directory(firmware_dir); diff --git a/firmware/application/apps/ui_flash_utility.hpp b/firmware/application/apps/ui_flash_utility.hpp index 626a4ff40..6b623bc34 100644 --- a/firmware/application/apps/ui_flash_utility.hpp +++ b/firmware/application/apps/ui_flash_utility.hpp @@ -60,7 +60,7 @@ class FlashUtilityView : public View { {{4, 4}, "Select firmware to flash:", Theme::getInstance()->bg_darkest->foreground}}; MenuView menu_view{ - {0, 2 * 8, 240, 26 * 8}, + {0, 2 * 8, screen_width, 26 * 8}, true}; std::filesystem::path extract_tar(std::filesystem::path::string_type path, ui::Painter& painter); // extracts the tar file, and returns the firmware.bin path from it. empty string if no fw diff --git a/firmware/application/apps/ui_iq_trim.cpp b/firmware/application/apps/ui_iq_trim.cpp index 44583d650..d5cbffd4d 100644 --- a/firmware/application/apps/ui_iq_trim.cpp +++ b/firmware/application/apps/ui_iq_trim.cpp @@ -34,6 +34,7 @@ namespace ui { IQTrimView::IQTrimView(NavigationView& nav) : nav_{nav} { + power_buckets_.resize(screen_width); add_children({ &labels, &field_path, diff --git a/firmware/application/apps/ui_iq_trim.hpp b/firmware/application/apps/ui_iq_trim.hpp index dd990f4a0..dff8f0f67 100644 --- a/firmware/application/apps/ui_iq_trim.hpp +++ b/firmware/application/apps/ui_iq_trim.hpp @@ -96,7 +96,7 @@ class IQTrimView : public View { std::filesystem::path path_{}; Optional info_{}; - std::array power_buckets_{}; + std::vector power_buckets_{}; TrimProgressUI progress_ui{}; Labels labels{ diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 2603560a7..187c5f75c 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -94,10 +94,10 @@ void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint rf::Frequency GlassView::get_freq_from_bin_pos(uint8_t pos) { rf::Frequency freq_at_pos = 0; if (mode == LOOKING_GLASS_SINGLEPASS) { - // starting from the middle, minus 8 ignored bin on each side. Since pos is [-120,120] after the (pos - 120), it's divided by SCREEN_W(240)/2 => 120 - freq_at_pos = f_center_ini + ((pos - 120) * ((looking_glass_range - ((16 * looking_glass_range) / SPEC_NB_BINS)) / 2)) / (SCREEN_W / 2); + // starting from the middle, minus 8 ignored bin on each side. Since pos is [-120,120] after the (pos - 120), it's divided by screen_width(240)/2 => 120 + freq_at_pos = f_center_ini + ((pos - 120) * ((looking_glass_range - ((16 * looking_glass_range) / SPEC_NB_BINS)) / 2)) / (screen_width / 2); } else - freq_at_pos = f_min + (2 * offset * each_bin_size) + (pos * looking_glass_range) / SCREEN_W; + freq_at_pos = f_min + (2 * offset * each_bin_size) + (pos * looking_glass_range) / screen_width; return freq_at_pos; } @@ -122,7 +122,7 @@ void GlassView::reset_live_view() { // Clear screen in peak mode. if (live_frequency_view == 2) - display.fill_rectangle({{0, 108 + 16}, {SCREEN_W, SCREEN_H - (108 + 16)}}, {0, 0, 0}); + display.fill_rectangle({{0, 108 + 16}, {screen_width, screen_height - (108 + 16)}}, {0, 0, 0}); } void GlassView::add_spectrum_pixel(uint8_t power) { @@ -130,7 +130,7 @@ void GlassView::add_spectrum_pixel(uint8_t power) { spectrum_data[pixel_index] = (live_frequency_integrate * spectrum_data[pixel_index] + power) / (live_frequency_integrate + 1); // smoothing pixel_index++; - if (pixel_index == SCREEN_W) // got an entire waterfall line + if (pixel_index == screen_width) // got an entire waterfall line { if (live_frequency_view > 0) { constexpr int rssi_sample_range = SPEC_NB_BINS; @@ -140,22 +140,22 @@ void GlassView::add_spectrum_pixel(uint8_t power) { constexpr int raw_min = rssi_sample_range * rssi_voltage_min / adc_voltage_max; constexpr int raw_max = rssi_sample_range * rssi_voltage_max / adc_voltage_max; constexpr int raw_delta = raw_max - raw_min; - const range_t y_max_range{0, 320 - (108 + 16)}; + const range_t y_max_range{0, screen_height - (108 + 16)}; // drawing and keeping track of max freq - for (uint16_t xpos = 0; xpos < SCREEN_W; xpos++) { + for (uint16_t xpos = 0; xpos < screen_width; xpos++) { // save max powerwull freq if (spectrum_data[xpos] > max_freq_power) { max_freq_power = spectrum_data[xpos]; max_freq_hold = get_freq_from_bin_pos(xpos); } - int16_t point = y_max_range.clip(((spectrum_data[xpos] - raw_min) * (320 - (108 + 16))) / raw_delta); + int16_t point = y_max_range.clip(((spectrum_data[xpos] - raw_min) * (screen_height - (108 + 16))) / raw_delta); uint8_t color_gradient = (point * 255) / 212; // clear if not in peak view if (live_frequency_view != 2) { - display.fill_rectangle({{xpos, 108 + 16}, {1, SCREEN_H - point}}, {0, 0, 0}); + display.fill_rectangle({{xpos, 108 + 16}, {1, screen_height - point}}, {0, 0, 0}); } - display.fill_rectangle({{xpos, SCREEN_H - point}, {1, point}}, {color_gradient, 0, uint8_t(255 - color_gradient)}); + display.fill_rectangle({{xpos, screen_height - point}, {1, point}}, {color_gradient, 0, uint8_t(255 - color_gradient)}); } if (last_max_freq != max_freq_hold) { last_max_freq = max_freq_hold; @@ -163,7 +163,7 @@ void GlassView::add_spectrum_pixel(uint8_t power) { } plot_marker(marker_pixel_index); } else { - display.draw_pixels({{0, display.scroll(1)}, {SCREEN_W, 1}}, spectrum_row); // new line at top, one less var, speedier + display.draw_pixels({{0, display.scroll(1)}, {screen_width, 1}}, spectrum_row); // new line at top, one less var, speedier } pixel_index = 0; // Start New cascade line } @@ -199,7 +199,7 @@ bool GlassView::process_bins(uint8_t* powerlevel) { void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) { baseband::spectrum_streaming_stop(); // Convert bins of this spectrum slice into a representative max_power and when enough, into pixels - // we actually need SCREEN_W (240) of those bins + // we actually need screen_width (240) of those bins for (uint8_t bin = 0; bin < bin_length; bin++) { get_max_power(spectrum, bin, max_power); if (max_power > range_max_power) @@ -238,7 +238,7 @@ void GlassView::on_hide() { } void GlassView::on_show() { - display.scroll_set_area(109, 319); // Restart scroll on the correct coordinates + display.scroll_set_area(109, screen_height - 1); // Restart scroll on the correct coordinates baseband::spectrum_streaming_start(); } @@ -253,11 +253,11 @@ void GlassView::on_range_changed() { // if the view is done in one pass, show it like in analog_audio_app mode = LOOKING_GLASS_SINGLEPASS; offset = 2; - bin_length = SCREEN_W; + bin_length = screen_width; ignore_dc = 0; looking_glass_bandwidth = looking_glass_range; looking_glass_sampling_rate = looking_glass_range; - each_bin_size = looking_glass_bandwidth / SCREEN_W; + each_bin_size = looking_glass_bandwidth / screen_width; looking_glass_step = looking_glass_bandwidth; f_center_ini = f_min + (looking_glass_bandwidth / 2); // Initial center frequency for sweep } else { @@ -269,7 +269,7 @@ void GlassView::on_range_changed() { if (mode == LOOKING_GLASS_FASTSCAN) { offset = 2; ignore_dc = 4; - bin_length = SCREEN_W; + bin_length = screen_width; } else { // if( mode == LOOKING_GLASS_SLOWSCAN ) offset = 2; bin_length = 80; @@ -279,7 +279,7 @@ void GlassView::on_range_changed() { f_center_ini = f_min - (offset * each_bin_size) + (looking_glass_bandwidth / 2); // Initial center frequency for sweep } search_span = looking_glass_range / MHZ_DIV; - marker_pixel_step = looking_glass_range / SCREEN_W; // Each pixel value in Hz + marker_pixel_step = looking_glass_range / screen_width; // Each pixel value in Hz pixel_index = 0; max_power = 0; @@ -304,10 +304,10 @@ void GlassView::plot_marker(uint8_t pos) { { shift_y = 16; } - portapack::display.fill_rectangle({0, 100 + shift_y, SCREEN_W, 8}, Theme::getInstance()->bg_darkest->background); // Clear old marker and whole marker rectangle btw - portapack::display.fill_rectangle({pos - 2, 100 + shift_y, 5, 3}, Theme::getInstance()->fg_red->foreground); // Red marker top - portapack::display.fill_rectangle({pos - 1, 103 + shift_y, 3, 3}, Theme::getInstance()->fg_red->foreground); // Red marker middle - portapack::display.fill_rectangle({pos, 106 + shift_y, 1, 2}, Theme::getInstance()->fg_red->foreground); // Red marker bottom + portapack::display.fill_rectangle({0, 100 + shift_y, screen_width, 8}, Theme::getInstance()->bg_darkest->background); // Clear old marker and whole marker rectangle btw + portapack::display.fill_rectangle({pos - 2, 100 + shift_y, 5, 3}, Theme::getInstance()->fg_red->foreground); // Red marker top + portapack::display.fill_rectangle({pos - 1, 103 + shift_y, 3, 3}, Theme::getInstance()->fg_red->foreground); // Red marker middle + portapack::display.fill_rectangle({pos, 106 + shift_y, 1, 2}, Theme::getInstance()->fg_red->foreground); // Red marker bottom } void GlassView::update_min(int32_t v) { @@ -358,7 +358,8 @@ GlassView::GlassView( NavigationView& nav) : nav_(nav) { baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum); - + spectrum_row.resize(screen_width); + spectrum_data.resize(screen_width); if (!gradient.load_file(default_gradient_file)) { gradient.set_default(); } @@ -437,11 +438,11 @@ GlassView::GlassView( freq_stats.hidden(true); button_jump.hidden(true); button_rst.hidden(true); - display.scroll_set_area(109, 319); // Restart scroll on the correct coordinates. + display.scroll_set_area(109, screen_height - 1); // Restart scroll on the correct coordinates. break; case 1: // LEVEL - display.fill_rectangle({{0, 108}, {SCREEN_W, 24}}, {0, 0, 0}); + display.fill_rectangle({{0, 108}, {screen_width, 24}}, {0, 0, 0}); display.scroll_disable(); level_integration.hidden(false); freq_stats.hidden(false); @@ -451,7 +452,7 @@ GlassView::GlassView( case 2: // PEAK default: - display.fill_rectangle({{0, 108}, {SCREEN_W, 24}}, {0, 0, 0}); + display.fill_rectangle({{0, 108}, {screen_width, 24}}, {0, 0, 0}); display.scroll_disable(); level_integration.hidden(false); freq_stats.hidden(false); @@ -491,9 +492,9 @@ GlassView::GlassView( field_marker.on_encoder_change = [this](TextField&, EncoderEvent delta) { if ((marker_pixel_index + delta) < 0) - marker_pixel_index = marker_pixel_index + delta + SCREEN_W; - else if ((marker_pixel_index + delta) > SCREEN_W) - marker_pixel_index = marker_pixel_index + delta - SCREEN_W; + marker_pixel_index = marker_pixel_index + delta + screen_width; + else if ((marker_pixel_index + delta) > screen_width) + marker_pixel_index = marker_pixel_index + delta - screen_width; else marker_pixel_index = marker_pixel_index + delta; on_marker_change(); @@ -531,7 +532,7 @@ GlassView::GlassView( }; set_spec_iq_phase_calibration_value(get_spec_iq_phase_calibration_value()); // initialize iq_phase_calibration in radio - display.scroll_set_area(109, 319); + display.scroll_set_area(109, screen_height - 1); // Restart scroll on the correct coordinates // trigger: // Discord User jteich: WidebandSpectrum::on_message to set the trigger value. In WidebandSpectrum::execute, @@ -539,7 +540,7 @@ GlassView::GlassView( // at which time it pushes the buffer up with channel_spectrum.feed baseband::set_spectrum(looking_glass_bandwidth, trigger); - marker_pixel_index = SCREEN_W / 2; + marker_pixel_index = screen_width / 2; on_range_changed(); // Force a UI update. receiver_model.set_sampling_rate(looking_glass_sampling_rate); // 20mhz diff --git a/firmware/application/apps/ui_looking_glass_app.hpp b/firmware/application/apps/ui_looking_glass_app.hpp index 42d13164b..9ddfd18fc 100644 --- a/firmware/application/apps/ui_looking_glass_app.hpp +++ b/firmware/application/apps/ui_looking_glass_app.hpp @@ -51,9 +51,6 @@ namespace ui { #define LOOKING_GLASS_SINGLEPASS 2 // one spectrum line number of bins #define SPEC_NB_BINS 256 -// screen dimensions -#define SCREEN_W 240 -#define SCREEN_H 320 class GlassView : public View { public: @@ -155,8 +152,8 @@ class GlassView : public View { uint8_t min_color_power{0}; // Filter cutoff level. uint32_t pixel_index{0}; - std::array spectrum_row{}; - std::array spectrum_data{}; + std::vector spectrum_row{}; + std::vector spectrum_data{}; ChannelSpectrumFIFO* fifo{}; int32_t steps = 1; @@ -168,7 +165,7 @@ class GlassView : public View { rf::Frequency max_freq_hold = 0; rf::Frequency last_max_freq = 0; int16_t max_freq_power = -1000; - uint8_t bin_length = SCREEN_W; + uint8_t bin_length = screen_width; uint8_t offset = 0; uint8_t ignore_dc = 0; @@ -222,7 +219,7 @@ class GlassView : public View { {}}; ButtonWithEncoder button_beep_squelch{ - {240 - 8 * 8, 2 * 16 + 4, 8 * 8, 1 * 8}, + {screen_width - 8 * 8, 2 * 16 + 4, 8 * 8, 1 * 8}, ""}; TextField field_marker{ @@ -293,15 +290,15 @@ class GlassView : public View { }}; Button button_jump{ - {SCREEN_W - 4 * 8, 5 * 16, 4 * 8, 16}, + {screen_width - 4 * 8, 5 * 16, 4 * 8, 16}, "JMP"}; Button button_rst{ - {SCREEN_W - 9 * 8, 5 * 16, 4 * 8, 16}, + {screen_width - 9 * 8, 5 * 16, 4 * 8, 16}, "RST"}; Text freq_stats{ - {0 * 8, 5 * 16, SCREEN_W - 10 * 8, 8}, + {0 * 8, 5 * 16, screen_width - 10 * 8, 8}, ""}; MessageHandlerRegistration message_handler_spectrum_config{ diff --git a/firmware/application/apps/ui_rds.hpp b/firmware/application/apps/ui_rds.hpp index aebd8deb4..40e9d285f 100644 --- a/firmware/application/apps/ui_rds.hpp +++ b/firmware/application/apps/ui_rds.hpp @@ -160,7 +160,7 @@ class RDSView : public View { void start_tx(); - Rect view_rect = {0, 8 * 8, 240, 192}; + Rect view_rect = {0, 8 * 8, screen_width, 192}; RDSPSNView view_PSN{nav_, view_rect}; RDSRadioTextView view_radiotext{nav_, view_rect}; diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 5a7d9b233..7e1a8f150 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -1404,8 +1404,8 @@ void ReconView::start_repeat() { std::string delay_message = "TX DELAY: " + to_string_dec_uint(delay) + "s"; // update display information - p.fill_rectangle({0, (SCREEN_H / 2) - 16, SCREEN_W, 64}, Theme::getInstance()->fg_light->foreground); - p.draw_string({(SCREEN_W / 2) - 7 * 8, SCREEN_H / 2}, *Theme::getInstance()->fg_red, delay_message); + p.fill_rectangle({0, (screen_height / 2) - 16, screen_width, 64}, Theme::getInstance()->fg_light->foreground); + p.draw_string({(screen_width / 2) - 7 * 8, screen_height / 2}, *Theme::getInstance()->fg_red, delay_message); // sleep 1 second chThdSleepMilliseconds(1000); diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index a127801c8..e610b2438 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -237,15 +237,15 @@ class ReconView : public View { Text file_name{ // show file used - {0, 1 * 16, SCREEN_W, 16}, + {0, 1 * 16, screen_width, 16}, }; Text desc_cycle{ - {0, 2 * 16, SCREEN_W, 16}, + {0, 2 * 16, screen_width, 16}, }; RSSI rssi{ - {0 * 16, 3 * 16 + 2, SCREEN_W - 8 * 8 + 4, 12}, + {0 * 16, 3 * 16 + 2, screen_width - 8 * 8 + 4, 12}, }; ButtonWithEncoder text_cycle{ @@ -285,15 +285,15 @@ class ReconView : public View { // Button can be RECON or SCANNER Button button_scanner_mode{ - {SCREEN_W - 7 * 8, 3 * 16, 7 * 8, 28}, + {screen_width - 7 * 8, 3 * 16, 7 * 8, 28}, "RECON"}; Button button_loop_config{ - {SCREEN_W - 7 * 8, 5 * 16, 7 * 8, 28}, + {screen_width - 7 * 8, 5 * 16, 7 * 8, 28}, "[LOOP]"}; Button button_config{ - {SCREEN_W - 7 * 8, 7 * 16, 7 * 8, 28}, + {screen_width - 7 * 8, 7 * 16, 7 * 8, 28}, "CONFIG"}; ButtonWithEncoder button_manual_start{ @@ -391,7 +391,7 @@ class ReconView : public View { ""}; ProgressBar progressbar{ - {0 * 8, SCREEN_H / 2 - 16, SCREEN_W, 32}}; + {0 * 8, screen_height / 2 - 16, screen_width, 32}}; TransmitterView2 tx_view{ {11 * 8, 2 * 16}, diff --git a/firmware/application/apps/ui_recon_settings.hpp b/firmware/application/apps/ui_recon_settings.hpp index eb5d257ec..fe4393369 100644 --- a/firmware/application/apps/ui_recon_settings.hpp +++ b/firmware/application/apps/ui_recon_settings.hpp @@ -57,10 +57,6 @@ #define RECON_MIN_LOCK_DURATION 100 // have to be >= and a multiple of STATS_UPDATE_INTERVAL #define RECON_DEF_WAIT_DURATION 1000 // will be incremented/decremented by STATS_UPDATE_INTERVAL steps -// screen size helper -#define SCREEN_W 240 -// #define SCREEN_H 320 - // recon settings nb params #define RECON_SETTINGS_NB_PARAMS 7 @@ -219,7 +215,7 @@ class ReconSetupView : public View { std::string input_file{"RECON"}; std::string output_file{"RECON_RESULTS"}; - Rect view_rect{0, 3 * 8, SCREEN_W, 230}; + Rect view_rect{0, 3 * 8, screen_width, 230}; ReconSetupViewMain viewMain{nav_, view_rect, input_file, output_file}; ReconSetupViewMore viewMore{nav_, view_rect}; diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 2766b6a65..295e83478 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -759,7 +759,7 @@ AppSettingsView::AppSettingsView( add_children({&labels, &menu_view}); - menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8}); + menu_view.set_parent_rect({0, 3 * 8, screen_width, 33 * 8}); ensure_directory(settings_dir); diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index b4a198c8d..050785cfb 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -713,7 +713,7 @@ class AppSettingsView : public View { {{0, 4}, "Select file to edit:", Theme::getInstance()->bg_darkest->foreground}}; MenuView menu_view{ - {0, 2 * 8, 240, 26 * 8}, + {0, 2 * 8, screen_width, 26 * 8}, true}; }; @@ -947,7 +947,7 @@ class SetThemeView : public View { OptionsField options{ {0 * 8, 4 * 16}, - screen_width / 8, + (size_t)(screen_width / 8), { {"Default - Grey", 0}, {"Yellow", 1}, diff --git a/firmware/application/apps/ui_sigfrx.cpp b/firmware/application/apps/ui_sigfrx.cpp index e04933060..516e898fc 100644 --- a/firmware/application/apps/ui_sigfrx.cpp +++ b/firmware/application/apps/ui_sigfrx.cpp @@ -57,7 +57,7 @@ void SIGFRXView::paint(Painter& painter) { uint8_t i, xp; // portapack::display.draw_bmp_from_bmp_hex_arr({0, 302-160}, fox_bmp); - portapack::display.fill_rectangle({0, 16, 240, 160 - 16}, Theme::getInstance()->bg_darkest->foreground); + portapack::display.fill_rectangle({0, 16, screen_width, 160 - 16}, Theme::getInstance()->bg_darkest->foreground); for (i = 0; i < 6; i++) { xp = sigfrx_marks[i * 3]; painter.draw_string({(ui::Coord)sigfrx_marks[(i * 3) + 1], 144 - 20}, style_white, to_string_dec_uint(sigfrx_marks[(i * 3) + 2])); @@ -66,7 +66,7 @@ void SIGFRXView::paint(Painter& painter) { } void SIGFRXView::on_channel_spectrum(const ChannelSpectrum& spectrum) { - portapack::display.fill_rectangle({0, 144, 240, 4}, Theme::getInstance()->bg_darkest->foreground); + portapack::display.fill_rectangle({0, 144, screen_width, 4}, Theme::getInstance()->bg_darkest->foreground); uint8_t xmax = 0, imax = 0; size_t i; diff --git a/firmware/application/apps/ui_ss_viewer.cpp b/firmware/application/apps/ui_ss_viewer.cpp index a0741041f..4cb41c429 100644 --- a/firmware/application/apps/ui_ss_viewer.cpp +++ b/firmware/application/apps/ui_ss_viewer.cpp @@ -66,7 +66,7 @@ void ScreenshotViewer::paint(Painter& painter) { constexpr size_t read_chunk = 80; // NB: must be a factor of pixel_width. constexpr size_t buffer_size = sizeof(ColorRGB888) * read_chunk; uint8_t buffer[buffer_size]; - std::array pixel_data; + std::vector pixel_data(screen_width); // Seek past all the headers. file.seek(43); diff --git a/firmware/application/apps/ui_subghzd.hpp b/firmware/application/apps/ui_subghzd.hpp index afdf79e20..d0e6621f6 100644 --- a/firmware/application/apps/ui_subghzd.hpp +++ b/firmware/application/apps/ui_subghzd.hpp @@ -192,7 +192,7 @@ class SubGhzDRecentEntryDetailView : public View { Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"}; Console console{ - {0, 4 * 16, 240, screen_height - (4 * 16) - 36}}; + {0, 4 * 16, screen_width, screen_height - (4 * 16) - 36}}; Labels labels{ {{0 * 8, 0 * 16}, "Type:", Theme::getInstance()->fg_light->foreground}, diff --git a/firmware/application/apps/ui_test.cpp b/firmware/application/apps/ui_test.cpp index 1029ac866..348577af1 100644 --- a/firmware/application/apps/ui_test.cpp +++ b/firmware/application/apps/ui_test.cpp @@ -99,8 +99,8 @@ void TestView::on_packet(const testapp::Packet& packet) { display.draw_pixel(Point(cur_x, 4 * 16 + (256 - ((raw_alt - cal_value) / 4))), Color::white()); cur_x++; - if (cur_x >= 240) { - display.fill_rectangle(Rect(0, 5 * 16, 240, 256), Color::black()); + if (cur_x >= screen_width) { + display.fill_rectangle(Rect(0, 5 * 16, screen_width, 256), Color::black()); cur_x = 0; } diff --git a/firmware/application/external/acars_rx/acars_app.hpp b/firmware/application/external/acars_rx/acars_app.hpp index ac99e7045..5e1ef99df 100644 --- a/firmware/application/external/acars_rx/acars_app.hpp +++ b/firmware/application/external/acars_rx/acars_app.hpp @@ -87,7 +87,7 @@ class ACARSAppView : public View { true}; Console console{ - {0, 3 * 16, 240, 256}}; + {0, 3 * 16, screen_width, 256}}; AudioVolumeField field_volume{ {28 * 8, 1 * 16}}; diff --git a/firmware/application/external/adsbtx/ui_adsb_tx.hpp b/firmware/application/external/adsbtx/ui_adsb_tx.hpp index d39af7809..245ffd43e 100644 --- a/firmware/application/external/adsbtx/ui_adsb_tx.hpp +++ b/firmware/application/external/adsbtx/ui_adsb_tx.hpp @@ -218,7 +218,7 @@ class ADSBTxView : public View { void start_tx(); void generate_frames(); - Rect view_rect = {0, 7 * 8, 240, 192}; + Rect view_rect = {0, 7 * 8, screen_width, 192}; ADSBPositionView view_position{nav_, view_rect}; ADSBCallsignView view_callsign{nav_, view_rect}; diff --git a/firmware/application/external/afsk_rx/ui_afsk_rx.hpp b/firmware/application/external/afsk_rx/ui_afsk_rx.hpp index 2ebcd08ea..75618e6c1 100644 --- a/firmware/application/external/afsk_rx/ui_afsk_rx.hpp +++ b/firmware/application/external/afsk_rx/ui_afsk_rx.hpp @@ -105,7 +105,7 @@ class AFSKRxView : public View { LanguageHelper::currentMessages[LANG_MODEM_SETUP]}; Console console{ - {0, 4 * 16, 240, screen_width}}; + {0, 4 * 16, screen_width, screen_width}}; void on_data_afsk(const AFSKDataMessage& message); diff --git a/firmware/application/external/antenna_length/ui_whipcalc.hpp b/firmware/application/external/antenna_length/ui_whipcalc.hpp index 42520fd87..78fa3f56a 100644 --- a/firmware/application/external/antenna_length/ui_whipcalc.hpp +++ b/firmware/application/external/antenna_length/ui_whipcalc.hpp @@ -86,7 +86,7 @@ class WhipCalcView : public View { {13 * 8, 4 * 16, 10 * 16, 16}, "-"}; Console console{ - {0, 6 * 16, 240, 160}}; + {0, 6 * 16, screen_width, 160}}; Button button_exit{ {72, 17 * 16, 96, 32}, diff --git a/firmware/application/external/blespam/ui_blespam.hpp b/firmware/application/external/blespam/ui_blespam.hpp index e5831d2f7..73640328b 100644 --- a/firmware/application/external/blespam/ui_blespam.hpp +++ b/firmware/application/external/blespam/ui_blespam.hpp @@ -119,7 +119,7 @@ class BLESpamView : public View { #ifdef BLESPMUSECONSOLE Console console{ - {0, 70, 240, 220}}; + {0, 70, screen_width, 220}}; #endif OptionsField options_atkmode{ {0 * 8, 2 * 8}, diff --git a/firmware/application/external/breakout/ui_breakout.cpp b/firmware/application/external/breakout/ui_breakout.cpp index 5dc736ff4..2287a457f 100644 --- a/firmware/application/external/breakout/ui_breakout.cpp +++ b/firmware/application/external/breakout/ui_breakout.cpp @@ -12,8 +12,8 @@ namespace ui::external_app::breakout { Ticker game_timer; -int paddle_x = (SCREEN_WIDTH - PADDLE_WIDTH) / 2; -float ball_x = SCREEN_WIDTH / 2; +int paddle_x = 0; +float ball_x = 0; float ball_y = GAME_AREA_BOTTOM - PADDLE_HEIGHT - BALL_SIZE - 1; float ball_dx = 1.5f; float ball_dy = -2.0f; @@ -105,7 +105,7 @@ void game_timer_check() { } void init_game() { - paddle_x = (SCREEN_WIDTH - PADDLE_WIDTH) / 2; + paddle_x = (screen_width - PADDLE_WIDTH) / 2; score = 0; lives = 3; level = 1; @@ -157,7 +157,7 @@ void draw_screen() { } void draw_borders() { - rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER); + rect(0, GAME_AREA_TOP - 1, screen_width, GAME_AREA_TOP, COLOR_BORDER); } void draw_bricks() { @@ -218,14 +218,14 @@ void move_paddle_left() { } void move_paddle_right() { - if (paddle_x < SCREEN_WIDTH - PADDLE_WIDTH) { + if (paddle_x < screen_width - PADDLE_WIDTH) { fillrect(paddle_x, PADDLE_Y, paddle_x + PADDLE_WIDTH, PADDLE_Y + PADDLE_HEIGHT, COLOR_BACKGROUND); if (ball_attached) { fillrect(ball_x, ball_y, ball_x + BALL_SIZE, ball_y + BALL_SIZE, COLOR_BACKGROUND); } paddle_x += 10; - if (paddle_x > SCREEN_WIDTH - PADDLE_WIDTH) paddle_x = SCREEN_WIDTH - PADDLE_WIDTH; + if (paddle_x > screen_width - PADDLE_WIDTH) paddle_x = screen_width - PADDLE_WIDTH; if (ball_attached) { ball_x = paddle_x + (PADDLE_WIDTH / 2) - (BALL_SIZE / 2); @@ -277,8 +277,8 @@ void update_game() { if (ball_x < 0) { ball_x = 0; ball_dx = -ball_dx; - } else if (ball_x > SCREEN_WIDTH - BALL_SIZE) { - ball_x = SCREEN_WIDTH - BALL_SIZE; + } else if (ball_x > screen_width - BALL_SIZE) { + ball_x = screen_width - BALL_SIZE; ball_dx = -ball_dx; } @@ -381,7 +381,7 @@ void init_menu() { auto style_blue = *ui::Theme::getInstance()->fg_blue; auto style_cyan = *ui::Theme::getInstance()->fg_cyan; - int16_t screen_width = 240; + int16_t screen_width = ui::screen_width; int16_t title_x = (screen_width - 17 * 8) / 2; int16_t divider_width = 24 * 8; int16_t divider_x = (screen_width - divider_width) / 2; @@ -428,7 +428,7 @@ void init_game_over() { auto style_red = *ui::Theme::getInstance()->fg_red; auto style_yellow = *ui::Theme::getInstance()->fg_yellow; - int16_t screen_width = 240; + // int16_t screen_width = screen_width; int16_t title_width = 9 * 8; int16_t title_x = (screen_width - title_width) / 2; int16_t score_text_width = (16 + std::to_string(score).length()) * 8; @@ -484,6 +484,8 @@ void reset_game() { BreakoutView::BreakoutView(NavigationView& nav) : nav_{nav} { + paddle_x = (screen_width - PADDLE_WIDTH) / 2; + ball_x = screen_width / 2; add_children({&dummy}); game_timer.attach(&game_timer_check, 1.0 / 60.0); } diff --git a/firmware/application/external/breakout/ui_breakout.hpp b/firmware/application/external/breakout/ui_breakout.hpp index eab2a5316..1ff303595 100644 --- a/firmware/application/external/breakout/ui_breakout.hpp +++ b/firmware/application/external/breakout/ui_breakout.hpp @@ -56,8 +56,6 @@ class Ticker { void detach(); }; -#define SCREEN_WIDTH 240 -#define SCREEN_HEIGHT 320 #define PADDLE_WIDTH 40 #define PADDLE_HEIGHT 10 #define BALL_SIZE 8 @@ -141,7 +139,7 @@ class BreakoutView : public View { NavigationView& nav_; Button dummy{ - {240, 0, 0, 0}, + {screen_width, 0, 0, 0}, ""}; MessageHandlerRegistration message_handler_frame_sync{ diff --git a/firmware/application/external/cvs_spam/cvs_spam.hpp b/firmware/application/external/cvs_spam/cvs_spam.hpp index b1528562f..07396df9b 100644 --- a/firmware/application/external/cvs_spam/cvs_spam.hpp +++ b/firmware/application/external/cvs_spam/cvs_spam.hpp @@ -53,7 +53,7 @@ class CVSSpamView : public View { std::vector file_list{}; MenuView menu_view{ - {0, 0, 240, 180}, + {0, 0, screen_width, 180}, true}; Text text_empty{ @@ -84,7 +84,7 @@ class CVSSpamView : public View { LanguageHelper::currentMessages[LANG_STOP]}; ProgressBar progressbar{ - {0, 256, 240, 44}}; + {0, 256, screen_width, 44}}; MessageHandlerRegistration message_handler_fifo_signal{ Message::ID::RequestSignal, diff --git a/firmware/application/external/doom/ui_doom.cpp b/firmware/application/external/doom/ui_doom.cpp index 2cb0f2063..dc63b60a8 100644 --- a/firmware/application/external/doom/ui_doom.cpp +++ b/firmware/application/external/doom/ui_doom.cpp @@ -12,11 +12,11 @@ namespace ui::external_app::doom { //clang-format off -#define SCREEN_WIDTH 240 -#define SCREEN_HEIGHT 320 -#define RENDER_HEIGHT 280 -#define HALF_WIDTH (SCREEN_WIDTH / 2) -#define HALF_HEIGHT (RENDER_HEIGHT / 2) +int SCREEN_WIDTH = 0; +int SCREEN_HEIGHT = 0; +int RENDER_HEIGHT = 0; +int HALF_WIDTH = 0; +int HALF_HEIGHT = 0; #define LEVEL_WIDTH_BASE 6 #define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) #define LEVEL_HEIGHT 57 @@ -1001,6 +1001,11 @@ void render_map(Painter& painter, bool full_clear, int16_t x_start = 0, int16_t DoomView::DoomView(NavigationView& nav) : nav_{nav} { + SCREEN_WIDTH = screen_width; + SCREEN_HEIGHT = screen_height; + RENDER_HEIGHT = screen_height - 40; + HALF_WIDTH = screen_width / 2; + HALF_HEIGHT = RENDER_HEIGHT / 2; add_children({&dummy}); game_timer.attach(&game_timer_check, 1.0 / 60.0); } diff --git a/firmware/application/external/doom/ui_doom.hpp b/firmware/application/external/doom/ui_doom.hpp index b07d96bfd..6fa4fcc9c 100644 --- a/firmware/application/external/doom/ui_doom.hpp +++ b/firmware/application/external/doom/ui_doom.hpp @@ -70,7 +70,7 @@ class DoomView : public View { private: NavigationView& nav_; - Button dummy{{240, 0, 0, 0}, ""}; + Button dummy{{screen_width, 0, 0, 0}, ""}; bool initialized{false}; bool prev_velocity_moving{false}; MessageHandlerRegistration message_handler_frame_sync{ diff --git a/firmware/application/external/foxhunt/ui_foxhunt_rx.hpp b/firmware/application/external/foxhunt/ui_foxhunt_rx.hpp index ed61336fd..c90fab7ff 100644 --- a/firmware/application/external/foxhunt/ui_foxhunt_rx.hpp +++ b/firmware/application/external/foxhunt/ui_foxhunt_rx.hpp @@ -73,7 +73,7 @@ class FoxhuntRxView : public View { {0 * 8, 2 * 16 + 4, 14 * 8, 14}, }; RSSIGraph rssi_graph{ - {0, 50, 240, 30}, + {0, 50, screen_width, 30}, }; Button clear_markers{ @@ -84,7 +84,7 @@ class FoxhuntRxView : public View { {2, 18, 7 * 8, 16}, "Mark"}; - GeoMap geomap{{0, 80, 240, 240}}; + GeoMap geomap{{0, 80, screen_width, screen_height - 80}}; MessageHandlerRegistration message_handler_gps{ Message::ID::GPSPosData, diff --git a/firmware/application/external/gfxeq/ui_gfxeq.cpp b/firmware/application/external/gfxeq/ui_gfxeq.cpp index 9a903e461..9672c46f5 100644 --- a/firmware/application/external/gfxeq/ui_gfxeq.cpp +++ b/firmware/application/external/gfxeq/ui_gfxeq.cpp @@ -165,12 +165,12 @@ void gfxEQView::render_equalizer(Painter& painter) { if (prev_bar_heights[bar] > active_segments) { int clear_height = (prev_bar_heights[bar] - active_segments) * SEGMENT_HEIGHT; - int clear_y = SCREEN_HEIGHT - prev_bar_heights[bar] * SEGMENT_HEIGHT; + int clear_y = screen_height - prev_bar_heights[bar] * SEGMENT_HEIGHT; painter.fill_rectangle({x, clear_y, BAR_WIDTH, clear_height}, Color(0, 0, 0)); } for (int seg = 0; seg < active_segments; seg++) { - int y = SCREEN_HEIGHT - (seg + 1) * SEGMENT_HEIGHT; + int y = screen_height - (seg + 1) * SEGMENT_HEIGHT; if (y < header_height) break; Color segment_color = (seg >= active_segments - 2 && seg < active_segments) ? theme.peak_color : theme.base_color; @@ -183,7 +183,7 @@ void gfxEQView::render_equalizer(Painter& painter) { void gfxEQView::paint(Painter& painter) { if (needs_background_redraw) { - painter.fill_rectangle({0, header_height, SCREEN_WIDTH, RENDER_HEIGHT}, Color(0, 0, 0)); + painter.fill_rectangle({0, header_height, screen_width, RENDER_HEIGHT}, Color(0, 0, 0)); needs_background_redraw = false; } render_equalizer(painter); diff --git a/firmware/application/external/gfxeq/ui_gfxeq.hpp b/firmware/application/external/gfxeq/ui_gfxeq.hpp index f2fd0d1fe..7cd34f499 100644 --- a/firmware/application/external/gfxeq/ui_gfxeq.hpp +++ b/firmware/application/external/gfxeq/ui_gfxeq.hpp @@ -40,12 +40,10 @@ class gfxEQView : public View { private: static constexpr ui::Dim header_height = 2 * 16; - static constexpr int SCREEN_WIDTH = 240; - static constexpr int SCREEN_HEIGHT = 320; static constexpr int RENDER_HEIGHT = 288; static constexpr int NUM_BARS = 11; static constexpr int BAR_SPACING = 2; - static constexpr int BAR_WIDTH = (SCREEN_WIDTH - (BAR_SPACING * (NUM_BARS - 1))) / NUM_BARS; + int BAR_WIDTH = (screen_width - (BAR_SPACING * (NUM_BARS - 1))) / NUM_BARS; static constexpr int HORIZONTAL_OFFSET = 2; static constexpr int SEGMENT_HEIGHT = 10; diff --git a/firmware/application/external/jammer/ui_jammer.cpp b/firmware/application/external/jammer/ui_jammer.cpp index c8c43f819..b26c1f670 100644 --- a/firmware/application/external/jammer/ui_jammer.cpp +++ b/firmware/application/external/jammer/ui_jammer.cpp @@ -330,7 +330,7 @@ void JammerView::on_timer() { JammerView::JammerView( NavigationView& nav) : nav_{nav} { - Rect view_rect = {0, 3 * 8, 240, 80}; + Rect view_rect = {0, 3 * 8, screen_width, 80}; // baseband::run_image(portapack::spi_flash::image_tag_jammer); baseband::run_prepared_image(portapack::memory::map::m4_code.base()); diff --git a/firmware/application/external/level/ui_level.hpp b/firmware/application/external/level/ui_level.hpp index d6ef23719..e08a46087 100644 --- a/firmware/application/external/level/ui_level.hpp +++ b/firmware/application/external/level/ui_level.hpp @@ -178,12 +178,12 @@ class LevelView : public View { RSSIGraph rssi_graph{ // 240x320 => - {0, 6 * 16 + 8, 240 - 5 * 8, 320 - (6 * 16)}, + {0, 6 * 16 + 8, screen_width - 5 * 8, screen_height - (6 * 16)}, }; RSSI rssi{ // 240x320 => - {240 - 5 * 8, 6 * 16 + 8, 5 * 8, 320 - (6 * 16)}, + {screen_width - 5 * 8, 6 * 16 + 8, 5 * 8, screen_height - (6 * 16)}, }; void handle_coded_squelch(const uint32_t value); diff --git a/firmware/application/external/mcu_temperature/mcu_temperature.hpp b/firmware/application/external/mcu_temperature/mcu_temperature.hpp index a8cbb617f..217ab9a25 100644 --- a/firmware/application/external/mcu_temperature/mcu_temperature.hpp +++ b/firmware/application/external/mcu_temperature/mcu_temperature.hpp @@ -72,16 +72,16 @@ class McuTemperatureView : public View { private: Text text_title{ - {76, 16, 240, 16}, + {76, 16, screen_width, 16}, "Temperature", }; McuTemperatureWidget temperature_widget{ - {0, 40, 240, 180}, + {0, 40, screen_width, 180}, }; Button button_done{ - {72, 264, 96, 24}, + {72, screen_height - 56, 96, 24}, "Done"}; }; diff --git a/firmware/application/external/noaaapt_rx/ui_noaaapt_rx.cpp b/firmware/application/external/noaaapt_rx/ui_noaaapt_rx.cpp index b93dd3362..10c490b68 100644 --- a/firmware/application/external/noaaapt_rx/ui_noaaapt_rx.cpp +++ b/firmware/application/external/noaaapt_rx/ui_noaaapt_rx.cpp @@ -131,7 +131,7 @@ void NoaaAptRxView::on_status(NoaaAptRxStatusDataMessage msg) { // this stores and displays the image. keep it as simple as you can. a bit more complexity will kill the sync void NoaaAptRxView::on_image(NoaaAptRxImageDataMessage msg) { - if ((line_num) >= 320 - NOAA_IMG_START_ROW * 16) line_num = 0; // for draw reset + if ((line_num) >= screen_height - NOAA_IMG_START_ROW * 16) line_num = 0; // for draw reset for (uint16_t i = 0; i < msg.cnt; i += 1) { Color pxl = {msg.image[i], msg.image[i], msg.image[i]}; diff --git a/firmware/application/external/nrf_rx/ui_nrf_rx.hpp b/firmware/application/external/nrf_rx/ui_nrf_rx.hpp index 15b255253..0401604bd 100644 --- a/firmware/application/external/nrf_rx/ui_nrf_rx.hpp +++ b/firmware/application/external/nrf_rx/ui_nrf_rx.hpp @@ -77,11 +77,11 @@ class NRFRxView : public View { nav_}; Button button_modem_setup{ - {240 - 12 * 8, 1 * 16, 96, 24}, + {screen_width - 12 * 8, 1 * 16, 96, 24}, LanguageHelper::currentMessages[LANG_MODEM_SETUP]}; Console console{ - {0, 4 * 16, 240, 240}}; + {0, 4 * 16, screen_width, screen_height - 80}}; MessageHandlerRegistration message_handler_packet{ Message::ID::AFSKData, diff --git a/firmware/application/external/ook_editor/ui_ook_editor.hpp b/firmware/application/external/ook_editor/ui_ook_editor.hpp index e972ca5c2..443c80896 100644 --- a/firmware/application/external/ook_editor/ui_ook_editor.hpp +++ b/firmware/application/external/ook_editor/ui_ook_editor.hpp @@ -134,7 +134,7 @@ class OOKEditorAppView : public View { ProgressBar progressbar{{2 * 8, 250, 208, 16}}; // Waveform display using waveform buffer and yellow theme color. - Waveform waveform{{0, 208, 240, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground}; + Waveform waveform{{0, 208, screen_width, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground}; }; /******** bug key input view **********/ diff --git a/firmware/application/external/playlist_editor/ui_playlist_editor.hpp b/firmware/application/external/playlist_editor/ui_playlist_editor.hpp index 124f8fe6c..c8d70f532 100644 --- a/firmware/application/external/playlist_editor/ui_playlist_editor.hpp +++ b/firmware/application/external/playlist_editor/ui_playlist_editor.hpp @@ -56,7 +56,7 @@ class PlaylistEditorView : public View { "New"}; Text text_current_ppl_file{ - {sizeof("PPL file:") * 8, 0 * 16, screen_width - sizeof("PPL file:") * 8, 16}, + {sizeof("PPL file:") * 8, 0 * 16, screen_width - (int)sizeof("PPL file:") * 8, 16}, ""}; MenuView menu_view{}; diff --git a/firmware/application/external/protoview/ui_protoview.hpp b/firmware/application/external/protoview/ui_protoview.hpp index b356bcf8c..60300ff96 100644 --- a/firmware/application/external/protoview/ui_protoview.hpp +++ b/firmware/application/external/protoview/ui_protoview.hpp @@ -111,7 +111,7 @@ class ProtoView : public View { LanguageHelper::currentMessages[LANG_PAUSE]}; Waveform waveform{ - {0, 8 * 8, 240, 50}, + {0, 8 * 8, screen_width, 50}, waveform_buffer, 0, 0, @@ -119,7 +119,7 @@ class ProtoView : public View { Theme::getInstance()->fg_yellow->foreground}; Waveform waveform2{ - {0, 8 * 8 + 55, 240, 50}, + {0, 8 * 8 + 55, screen_width, 50}, &waveform_buffer[MAXDRAWCNTPERWF], 0, 0, @@ -127,7 +127,7 @@ class ProtoView : public View { Theme::getInstance()->fg_yellow->foreground}; Waveform waveform3{ - {0, 8 * 8 + 110, 240, 50}, + {0, 8 * 8 + 110, screen_width, 50}, &waveform_buffer[MAXDRAWCNTPERWF * 2], 0, 0, @@ -135,7 +135,7 @@ class ProtoView : public View { Theme::getInstance()->fg_yellow->foreground}; Waveform waveform4{ - {0, 8 * 8 + 165, 240, 50}, + {0, 8 * 8 + 165, screen_width, 50}, &waveform_buffer[MAXDRAWCNTPERWF * 3], 0, 0, diff --git a/firmware/application/external/random_password/ui_random_password.hpp b/firmware/application/external/random_password/ui_random_password.hpp index 24ebb63e5..8586a9733 100644 --- a/firmware/application/external/random_password/ui_random_password.hpp +++ b/firmware/application/external/random_password/ui_random_password.hpp @@ -203,7 +203,7 @@ class RandomPasswordView : public View { ' '}; OptionsField field_method{ - {(screen_width / 2) + (sizeof("method:") - 1) * 8, 7 * 16 - 2}, + {(screen_width / 2) + (int)(sizeof("method:") - 1) * 8, 7 * 16 - 2}, sizeof("R+L+R+H"), {{"R+L+R", Method::RADIO_LCG_ROLL}, {"R+L+R+H", Method::RADIO_LCG_ROLL_HASH}}}; diff --git a/firmware/application/external/remote/ui_remote.hpp b/firmware/application/external/remote/ui_remote.hpp index e61834f44..b269bf958 100644 --- a/firmware/application/external/remote/ui_remote.hpp +++ b/firmware/application/external/remote/ui_remote.hpp @@ -292,12 +292,12 @@ class RemoteAppView : public View { bool is_sending() const { return replay_thread_ != nullptr; } void show_error(const std::string& msg) const; - static constexpr Dim button_rows = 4; - static constexpr Dim button_cols = 3; - static constexpr uint8_t max_buttons = button_rows * button_cols; - static constexpr Dim button_area_height = 200; - static constexpr Dim button_width = screen_width / button_cols; - static constexpr Dim button_height = button_area_height / button_rows; + Dim button_rows = 4; + Dim button_cols = 3; + uint8_t max_buttons = button_rows * button_cols; + Dim button_area_height = 200; + Dim button_width = screen_width / button_cols; + Dim button_height = button_area_height / button_rows; // This value is mysterious... why? static constexpr uint32_t baseband_bandwidth = 2'500'000; diff --git a/firmware/application/external/scanner/ui_scanner.hpp b/firmware/application/external/scanner/ui_scanner.hpp index 588f62010..71ff204ab 100644 --- a/firmware/application/external/scanner/ui_scanner.hpp +++ b/firmware/application/external/scanner/ui_scanner.hpp @@ -238,7 +238,7 @@ class ScannerView : public View { }; Text text_current_desc{ - {0, 4 * 16, 240 - 6 * 8, 16}, + {0, 4 * 16, screen_width - 6 * 8, 16}, }; BigFrequency big_display{ diff --git a/firmware/application/external/sd_wipe/ui_sd_wipe.hpp b/firmware/application/external/sd_wipe/ui_sd_wipe.hpp index 886d97d60..4ffc88b8d 100644 --- a/firmware/application/external/sd_wipe/ui_sd_wipe.hpp +++ b/firmware/application/external/sd_wipe/ui_sd_wipe.hpp @@ -85,7 +85,7 @@ class WipeSDView : public View { {2 * 8, 19 * 8, 26 * 8, 24}}; Button dummy{ - {240, 0, 0, 0}, + {screen_width, 0, 0, 0}, ""}; }; diff --git a/firmware/application/external/shoppingcart_lock/shoppingcart_lock.hpp b/firmware/application/external/shoppingcart_lock/shoppingcart_lock.hpp index dc88d2cdd..8bbb54e5e 100644 --- a/firmware/application/external/shoppingcart_lock/shoppingcart_lock.hpp +++ b/firmware/application/external/shoppingcart_lock/shoppingcart_lock.hpp @@ -58,7 +58,7 @@ class ShoppingCartLock : public View { void restart_playback(); MenuView menu_view{ - {0, 0, 240, 150}, + {0, 0, screen_width, 150}, true}; Text text_empty{ diff --git a/firmware/application/external/snake/ui_snake.cpp b/firmware/application/external/snake/ui_snake.cpp index 3912c5658..5e9f3ca4a 100644 --- a/firmware/application/external/snake/ui_snake.cpp +++ b/firmware/application/external/snake/ui_snake.cpp @@ -10,81 +10,54 @@ namespace ui::external_app::snake { -Ticker game_timer; - -int snake_x[GRID_WIDTH * GRID_HEIGHT]; -int snake_y[GRID_WIDTH * GRID_HEIGHT]; -int snake_length = 1; -int snake_dx = 1; -int snake_dy = 0; -int food_x, food_y; -int score = 0; -int game_state = STATE_MENU; -bool initialized = false; - -const Color pp_colors[] = { - Color::white(), - Color::blue(), - Color::yellow(), - Color::purple(), - Color::green(), - Color::red(), - Color::magenta(), - Color::orange(), - Color::black(), -}; - -Painter painter; - -bool but_RIGHT = false; -bool but_LEFT = false; -bool but_SELECT = false; - -static Callback game_update_callback = nullptr; -static uint32_t game_update_timeout = 0; -static uint32_t game_update_counter = 0; - -void cls() { +void SnakeView::cls() { painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black()); } -void background(int color) { +void SnakeView::background(int color) { (void)color; } -void fillrect(int x1, int y1, int x2, int y2, int color) { +void SnakeView::fillrect(int x1, int y1, int x2, int y2, int color) { painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]); } -void rect(int x1, int y1, int x2, int y2, int color) { +void SnakeView::rect(int x1, int y1, int x2, int y2, int color) { painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]); } -void check_game_timer() { +void SnakeView::check_game_timer() { if (game_update_callback) { if (++game_update_counter >= game_update_timeout) { game_update_counter = 0; - game_update_callback(); + game_timer_check(); } } } -void Ticker::attach(Callback func, double delay_sec) { - game_update_callback = func; +void SnakeView::attach(double delay_sec) { + game_update_callback = true; game_update_timeout = delay_sec * 60; } -void Ticker::detach() { - game_update_callback = nullptr; +void SnakeView::detach() { + game_update_callback = false; } -void game_timer_check() { +void SnakeView::game_timer_check() { if (game_state == STATE_PLAYING) { update_game(); } } -void init_game() { +void SnakeView::init_game() { + SCREEN_WIDTH = screen_width; + SCREEN_HEIGHT = screen_height; + GAME_AREA_HEIGHT = (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2); + GRID_WIDTH = ((SCREEN_WIDTH - 2) / SNAKE_SIZE); + GRID_HEIGHT = (GAME_AREA_HEIGHT / SNAKE_SIZE); + snake_x.resize(GRID_WIDTH * GRID_HEIGHT); + snake_y.resize(GRID_WIDTH * GRID_HEIGHT); snake_x[0] = GRID_WIDTH / 2; snake_y[0] = GRID_HEIGHT / 2; snake_length = 1; @@ -99,7 +72,7 @@ void init_game() { } } -void spawn_food() { +void SnakeView::spawn_food() { bool valid; do { food_x = rand() % GRID_WIDTH; @@ -114,7 +87,7 @@ void spawn_food() { } while (!valid); } -void update_game() { +void SnakeView::update_game() { int new_x = snake_x[0] + snake_dx; int new_y = snake_y[0] + snake_dy; bool ate_food = (new_x == food_x && new_y == food_y); @@ -152,7 +125,7 @@ void update_game() { } } -bool check_collision() { +bool SnakeView::check_collision() { if (snake_x[0] < 0 || snake_x[0] >= GRID_WIDTH || snake_y[0] < 0 || snake_y[0] >= GRID_HEIGHT) { return true; } @@ -164,7 +137,7 @@ bool check_collision() { return false; } -void draw_screen() { +void SnakeView::draw_screen() { cls(); background(COLOR_BACKGROUND); draw_borders(); @@ -173,44 +146,44 @@ void draw_screen() { draw_score(); } -void draw_snake() { +void SnakeView::draw_snake() { fillrect(1 + snake_x[0] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE, 1 + snake_x[0] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE); } -void draw_full_snake() { +void SnakeView::draw_full_snake() { for (int i = 0; i < snake_length; i++) { fillrect(1 + snake_x[i] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE, 1 + snake_x[i] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE); } } -void erase_tail(int x, int y) { +void SnakeView::erase_tail(int x, int y) { fillrect(1 + x * SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE, 1 + x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND); } -void draw_food() { +void SnakeView::draw_food() { fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE, 1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_FOOD); } -void erase_food() { +void SnakeView::erase_food() { fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE, 1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND); } -void draw_score() { +void SnakeView::draw_score() { auto style = *ui::Theme::getInstance()->fg_blue; painter.draw_string({5, 5}, style, "Score: " + std::to_string(score)); } -void draw_borders() { +void SnakeView::draw_borders() { rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER); rect(0, GAME_AREA_TOP, SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_BORDER); } -void show_menu() { +void SnakeView::show_menu() { cls(); background(COLOR_BACKGROUND); auto style_yellow = *ui::Theme::getInstance()->fg_yellow; @@ -223,7 +196,7 @@ void show_menu() { painter.draw_string({15, 240}, style_green, "** PRESS SELECT TO START **"); } -void show_game_over() { +void SnakeView::show_game_over() { cls(); background(COLOR_BACKGROUND); auto style_red = *ui::Theme::getInstance()->fg_red; @@ -238,7 +211,7 @@ void show_game_over() { SnakeView::SnakeView(NavigationView& nav) : nav_{nav} { add_children({&dummy}); - game_timer.attach(&game_timer_check, 1.0 / 5.0); + attach(1.0 / 5.0); } void SnakeView::on_show() { diff --git a/firmware/application/external/snake/ui_snake.hpp b/firmware/application/external/snake/ui_snake.hpp index 70be2af90..ad2f1cc23 100644 --- a/firmware/application/external/snake/ui_snake.hpp +++ b/firmware/application/external/snake/ui_snake.hpp @@ -32,36 +32,11 @@ enum { Black, }; -extern const Color pp_colors[]; -extern Painter painter; -extern bool but_RIGHT; -extern bool but_LEFT; -extern bool but_SELECT; - -void cls(); -void background(int color); -void fillrect(int x1, int y1, int x2, int y2, int color); -void rect(int x1, int y1, int x2, int y2, int color); - #define wait(x) chThdSleepMilliseconds(x * 1000) -using Callback = void (*)(void); - -class Ticker { - public: - Ticker() = default; - void attach(Callback func, double delay_sec); - void detach(); -}; - -#define SCREEN_WIDTH 240 -#define SCREEN_HEIGHT 320 #define SNAKE_SIZE 10 #define INFO_BAR_HEIGHT 25 #define GAME_AREA_TOP (INFO_BAR_HEIGHT + 1) -#define GAME_AREA_HEIGHT (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2) -#define GRID_WIDTH ((SCREEN_WIDTH - 2) / SNAKE_SIZE) -#define GRID_HEIGHT (GAME_AREA_HEIGHT / SNAKE_SIZE) #define STATE_MENU 0 #define STATE_PLAYING 1 #define STATE_GAME_OVER 2 @@ -71,35 +46,6 @@ class Ticker { #define COLOR_FOOD Red #define COLOR_BORDER White -extern Ticker game_timer; - -extern int snake_x[GRID_WIDTH * GRID_HEIGHT]; -extern int snake_y[GRID_WIDTH * GRID_HEIGHT]; -extern int snake_length; -extern int snake_dx; -extern int snake_dy; -extern int food_x; -extern int food_y; -extern int score; -extern int game_state; -extern bool initialized; - -void game_timer_check(); -void init_game(); -void update_game(); -void draw_screen(); -void draw_snake(); -void draw_full_snake(); -void erase_tail(int x, int y); -void draw_food(); -void erase_food(); -void draw_score(); -void draw_borders(); -void spawn_food(); -bool check_collision(); -void show_menu(); -void show_game_over(); - class SnakeView : public View { public: SnakeView(NavigationView& nav); @@ -112,12 +58,67 @@ class SnakeView : public View { void frame_sync(); bool on_key(KeyEvent key) override; + void cls(); + void background(int color); + void fillrect(int x1, int y1, int x2, int y2, int color); + void rect(int x1, int y1, int x2, int y2, int color); + void game_timer_check(); + void init_game(); + void update_game(); + void draw_screen(); + void draw_snake(); + void draw_full_snake(); + void erase_tail(int x, int y); + void draw_food(); + void erase_food(); + void draw_score(); + void draw_borders(); + void spawn_food(); + bool check_collision(); + void show_menu(); + void show_game_over(); + void check_game_timer(); + + void attach(double delay_sec); + void detach(); + private: - bool initialized = false; + const Color pp_colors[9] = { + Color::white(), + Color::blue(), + Color::yellow(), + Color::purple(), + Color::green(), + Color::red(), + Color::magenta(), + Color::orange(), + Color::black(), + }; NavigationView& nav_; + Painter painter{}; + + std::vector snake_x{}; //[GRID_WIDTH * GRID_HEIGHT]; + std::vector snake_y{}; //[GRID_WIDTH * GRID_HEIGHT]; + int snake_length = 1; + int snake_dx = 1; + int snake_dy = 0; + int food_x = 0, food_y = 0; + int score = 0; + int game_state = STATE_MENU; + bool initialized = false; + + int SCREEN_WIDTH = 0; + int SCREEN_HEIGHT = 0; + int GAME_AREA_HEIGHT = 0; //(SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2); + int GRID_WIDTH = 0; // ((SCREEN_WIDTH - 2) / SNAKE_SIZE); + int GRID_HEIGHT = 0; //(GAME_AREA_HEIGHT / SNAKE_SIZE); + + bool game_update_callback = false; + double game_update_timeout = 0; + uint32_t game_update_counter = 0; Button dummy{ - {240, 0, 0, 0}, + {screen_width, 0, 0, 0}, ""}; MessageHandlerRegistration message_handler_frame_sync{ diff --git a/firmware/application/external/spainter/ui_spectrum_painter.cpp b/firmware/application/external/spainter/ui_spectrum_painter.cpp index 31cb4ce67..90b13c7da 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter.cpp +++ b/firmware/application/external/spainter/ui_spectrum_painter.cpp @@ -55,7 +55,7 @@ SpectrumPainterView::SpectrumPainterView( &field_pause, }); - Rect view_rect = {0, 3 * 8, 240, 80}; + Rect view_rect = {0, 3 * 8, screen_width, 80}; input_image.set_parent_rect(view_rect); input_text.set_parent_rect(view_rect); diff --git a/firmware/application/external/spainter/ui_spectrum_painter.hpp b/firmware/application/external/spainter/ui_spectrum_painter.hpp index 63e7e9c9b..72ee260e4 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter.hpp +++ b/firmware/application/external/spainter/ui_spectrum_painter.hpp @@ -89,7 +89,7 @@ class SpectrumPainterView : public View { static constexpr int32_t footer_location = 15 * 16 + 8; ProgressBar progressbar{ - {4, footer_location - 16, 240 - 8, 16}}; + {4, footer_location - 16, screen_width - 8, 16}}; Labels labels{ {{10 * 8, footer_location + 1 * 16}, "GAIN A:", Theme::getInstance()->fg_light->foreground}, diff --git a/firmware/application/external/spainter/ui_spectrum_painter_image.cpp b/firmware/application/external/spainter/ui_spectrum_painter_image.cpp index fd2e8cb18..c47c522ab 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter_image.cpp +++ b/firmware/application/external/spainter/ui_spectrum_painter_image.cpp @@ -244,12 +244,12 @@ std::vector SpectrumInputImageView::get_line(uint16_t y) { void SpectrumInputImageView::paint(Painter& painter) { painter.fill_rectangle( - {{0, 40}, {240, 204}}, + {{0, 40}, {screen_width, 204}}, style().background); if (!painted) { // This is very slow for big pictures. Do only once. - this->drawBMP_scaled({{0, 40}, {240, 160}}, this->file); + this->drawBMP_scaled({{0, 40}, {screen_width, 160}}, this->file); painted = true; } } diff --git a/firmware/application/external/spainter/ui_spectrum_painter_text.cpp b/firmware/application/external/spainter/ui_spectrum_painter_text.cpp index 46966ac18..a9cef177e 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter_text.cpp +++ b/firmware/application/external/spainter/ui_spectrum_painter_text.cpp @@ -73,7 +73,7 @@ void SpectrumInputTextView::paint(Painter& painter) { } painter.fill_rectangle( - {{0, 40}, {240, 204}}, + {{0, 40}, {screen_width, 204}}, style().background); } diff --git a/firmware/application/external/stopwatch/ui_stopwatch.hpp b/firmware/application/external/stopwatch/ui_stopwatch.hpp index c30856afc..fa44b24c7 100644 --- a/firmware/application/external/stopwatch/ui_stopwatch.hpp +++ b/firmware/application/external/stopwatch/ui_stopwatch.hpp @@ -75,11 +75,11 @@ class StopwatchView : public View { "START"}; Button button_reset_lap{ - {72, 240, 96, 24}, + {72, screen_height - 80, 96, 24}, "RESET"}; Button button_done{ - {72, 270, 96, 24}, + {72, screen_height - 50, 96, 24}, "EXIT"}; MessageHandlerRegistration message_handler_frame_sync{ diff --git a/firmware/application/external/tetris/ui_tetris.cpp b/firmware/application/external/tetris/ui_tetris.cpp index 0df9a9d6f..ce8da529e 100644 --- a/firmware/application/external/tetris/ui_tetris.cpp +++ b/firmware/application/external/tetris/ui_tetris.cpp @@ -209,9 +209,9 @@ void StartGame() { cls(); background(Black); foreground(White); - fillrect(0, 0, 162, 320, Black); - rect(162, 0, 164, 320, White); - fillrect(164, 0, 240, 320, Black); + fillrect(0, 0, 162, screen_height, Black); + rect(162, 0, 164, screen_height, White); + fillrect(164, 0, screen_width, screen_height, Black); ShowScore(); ShowNextFigure(); } @@ -483,7 +483,7 @@ void UpdateBoard() { board[i - numberOfLines][j] = 0; } } - fillrect(0, 0, 162, 320, Black); + fillrect(0, 0, 162, screen_height, Black); for (int i = 0; i < 20; i++) { for (int j = 0; j < 10; j++) { if (board[i][j] != 0) { diff --git a/firmware/application/external/tetris/ui_tetris.hpp b/firmware/application/external/tetris/ui_tetris.hpp index c917b8b7b..f1f8738b0 100644 --- a/firmware/application/external/tetris/ui_tetris.hpp +++ b/firmware/application/external/tetris/ui_tetris.hpp @@ -148,7 +148,7 @@ class TetrisView : public View { NavigationView& nav_; Button dummy{ - {240, 0, 0, 0}, + {screen_width, 0, 0, 0}, ""}; MessageHandlerRegistration message_handler_frame_sync{ diff --git a/firmware/application/external/tuner/ui_tuner.hpp b/firmware/application/external/tuner/ui_tuner.hpp index 7b76d0404..ad5f03949 100644 --- a/firmware/application/external/tuner/ui_tuner.hpp +++ b/firmware/application/external/tuner/ui_tuner.hpp @@ -76,12 +76,12 @@ class TunerView : public View { {{0 * 8, 5 * 16}, "Volume:", Theme::getInstance()->fg_light->foreground}}; Text text_note_frequency{ - {(sizeof("Note Frequency:") + 1) * 8, 3 * 16, screen_width - (sizeof("Note Frequency:") + 1) * 8, 16}, + {(sizeof("Note Frequency:") + 1) * 8, 3 * 16, (int)screen_width - (int)(sizeof("Note Frequency:") + 1) * 8, 16}, "", }; Text text_note_octave_shift{ - {(sizeof("Note Octave Shift:") + 1) * 8, 4 * 16, screen_width - (sizeof("Note Octave Shift:") + 1) * 8, 16}, + {(sizeof("Note Octave Shift:") + 1) * 8, 4 * 16, (int)screen_width - (int)(sizeof("Note Octave Shift:") + 1) * 8, 16}, "", }; diff --git a/firmware/application/external/wardrivemap/ui_wardrivemap.hpp b/firmware/application/external/wardrivemap/ui_wardrivemap.hpp index 759cd0110..636a273d2 100644 --- a/firmware/application/external/wardrivemap/ui_wardrivemap.hpp +++ b/firmware/application/external/wardrivemap/ui_wardrivemap.hpp @@ -54,7 +54,7 @@ class WardriveMapView : public View { {0, 20}, GeoPos::alt_unit::METERS, GeoPos::spd_unit::HIDDEN}; - GeoMap geomap{{0, 75, 240, 320 - 75}}; + 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}, "->"}; diff --git a/firmware/application/external/wav_view/ui_view_wav.hpp b/firmware/application/external/wav_view/ui_view_wav.hpp index 688b0163b..7a81ba7fb 100644 --- a/firmware/application/external/wav_view/ui_view_wav.hpp +++ b/firmware/application/external/wav_view/ui_view_wav.hpp @@ -121,7 +121,7 @@ class ViewWavView : public View { {28 * 8, 18 * 16}}; Waveform waveform{ - {0, 5 * 16, 240, 64}, + {0, 5 * 16, screen_width, 64}, waveform_buffer, 240, 0, diff --git a/firmware/application/external/wefax_rx/ui_wefax_rx.cpp b/firmware/application/external/wefax_rx/ui_wefax_rx.cpp index e405d7296..344be5849 100644 --- a/firmware/application/external/wefax_rx/ui_wefax_rx.cpp +++ b/firmware/application/external/wefax_rx/ui_wefax_rx.cpp @@ -130,7 +130,7 @@ void WeFaxRxView::on_status(WeFaxRxStatusDataMessage msg) { // this stores and displays the image. keep it as simple as you can. a bit more complexity will kill the sync void WeFaxRxView::on_image(WeFaxRxImageDataMessage msg) { - if ((line_num) >= 320 - 4 * 16) line_num = 0; // for draw reset + if ((line_num) >= screen_height - 4 * 16) line_num = 0; // for draw reset for (uint16_t i = 0; i < msg.cnt; i += 1) { Color pxl = {msg.image[i], msg.image[i], msg.image[i]}; diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp index 06a2cc164..de5114c94 100644 --- a/firmware/application/ui/ui_btngrid.cpp +++ b/firmware/application/ui/ui_btngrid.cpp @@ -76,10 +76,30 @@ int BtnGridView::rows() { void BtnGridView::set_parent_rect(const Rect new_parent_rect) { View::set_parent_rect(new_parent_rect); + button_h = 48; // btn_h_min; + /* + // DISABLED FOR NOW. TODO fix next, prev button pos + int min_remainder = parent_rect().size().height(); + uint8_t max_button_count = 0; + + for (int h = btn_h_min; h <= btn_h_max; ++h) { + int count = parent_rect().size().height() / h; + int remainder = parent_rect().size().height() % h; + + // Prefer smaller remainder, then more buttons, then larger height + if (remainder < min_remainder || + (remainder == min_remainder && count > max_button_count) || + (remainder == min_remainder && count == max_button_count && h > button_h)) { + button_h = h; + min_remainder = remainder; + max_button_count = count; + } + } + */ displayed_max = (parent_rect().size().height() / button_h); - button_pgup.set_parent_rect({0, (Coord)(displayed_max * button_h), 120, 16}); - button_pgdown.set_parent_rect({120, (Coord)(displayed_max * button_h), 120, 16}); + button_pgup.set_parent_rect({0, (Coord)(displayed_max * button_h), screen_width / 2, 16}); + button_pgdown.set_parent_rect({screen_width / 2, (Coord)(displayed_max * button_h), screen_width / 2, 16}); displayed_max *= rows_; diff --git a/firmware/application/ui/ui_btngrid.hpp b/firmware/application/ui/ui_btngrid.hpp index 0729b5dff..a10115991 100644 --- a/firmware/application/ui/ui_btngrid.hpp +++ b/firmware/application/ui/ui_btngrid.hpp @@ -55,7 +55,7 @@ void load_blacklist(); class BtnGridView : public View { public: - BtnGridView(Rect new_parent_rect = {0, 0, 240, 304}, bool keep_highlight = false); + BtnGridView(Rect new_parent_rect = {0, 0, screen_width, screen_height - 16}, bool keep_highlight = false); ~BtnGridView(); @@ -89,27 +89,33 @@ class BtnGridView : public View { bool blacklisted_app(GridItem new_item); void update_items(); + void set_btn_min_max_height(uint8_t min, uint8_t max) { + btn_h_min = min; + btn_h_max = max; + } protected: virtual void on_populate() = 0; private: int rows_{3}; + uint8_t btn_h_min{40}; + uint8_t btn_h_max{60}; bool keep_highlight{false}; std::vector menu_items{}; std::vector> menu_item_views{}; Button button_pgup{ - {0, 324, 120, 16}, + {0, 1324, 120, 16}, " "}; Button button_pgdown{ - {121, 324, 119, 16}, + {121, 1324, 119, 16}, " "}; - int button_w = 240 / rows_; - static constexpr int button_h = 48; + int button_w = screen_width / rows_; + int button_h = 48; size_t displayed_max{0}; size_t highlighted_item{0}; size_t offset{0}; diff --git a/firmware/application/ui/ui_receiver.hpp b/firmware/application/ui/ui_receiver.hpp index 45440840d..ef7801b97 100644 --- a/firmware/application/ui/ui_receiver.hpp +++ b/firmware/application/ui/ui_receiver.hpp @@ -226,7 +226,7 @@ class FrequencyKeypadView : public View { static constexpr int text_digits = mhz_digits + 1 + submhz_digits; Text text_value{ - {0, 4, 240, 16}}; + {0, 4, screen_width, 16}}; std::array buttons{}; diff --git a/firmware/application/ui/ui_tabview.cpp b/firmware/application/ui/ui_tabview.cpp index f6cde66a7..f2348035f 100644 --- a/firmware/application/ui/ui_tabview.cpp +++ b/firmware/application/ui/ui_tabview.cpp @@ -135,7 +135,7 @@ TabView::TabView(std::initializer_list tab_definitions) { if (n_tabs > MAX_TABS) n_tabs = MAX_TABS; - size_t tab_width = 240 / n_tabs; + size_t tab_width = screen_width / n_tabs; set_parent_rect({0, 0, 30 * 8, 3 * 8}); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index cef21714e..b9fafb212 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -501,7 +501,7 @@ void SystemStatusView::on_camera() { return; for (int i = 0; i < screen_height; i++) { - std::array row; + std::vector row(ui::screen_width); portapack::display.read_pixels({0, i, screen_width, 1}, row); png.write_scanline(row); } @@ -949,8 +949,8 @@ SystemView::SystemView( add_child(&info_view); info_view.set_parent_rect( - {{0, 19 * 16}, - {parent_rect.width(), info_view_height}}); + {{0, screen_height - 16}, + {screen_width, info_view_height}}); navigation_view.on_view_changed = [this](const View& new_view) { if (!this->navigation_view.is_top()) { @@ -1055,7 +1055,7 @@ SplashScreenView::SplashScreenView(NavigationView& nav) void SplashScreenView::paint(Painter&) { if (!portapack::display.draw_bmp_from_sdcard_file({0, 0}, splash_dot_bmp)) // ^ try draw bmp file from sdcard at (0,0), and the (0,0) already bypassed the status bar, so actual pos is (0, STATUS_BAR_HEIGHT) - portapack::display.draw_bitmap({screen_width / 2 - 120, + portapack::display.draw_bitmap({0, screen_height / 2}, bitmap_titlebar_image.size, bitmap_titlebar_image.data, diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 75df0bed1..9a2b878e5 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -332,7 +332,7 @@ class InformationView : public View { NavigationView& nav_; Rectangle backdrop{ - {0, 0 * 16, 240, 16}, + {0, 0, screen_width, 16}, Theme::getInstance()->bg_darker->background}; Text version{ @@ -340,7 +340,7 @@ class InformationView : public View { VERSION_STRING}; LiveDateTime ltime{ - {86, 0, 19 * 8, 16}}; + {screen_width - 19 * 8, 0, 19 * 8, 16}}; }; class SplashScreenView : public View { @@ -355,7 +355,7 @@ class SplashScreenView : public View { private: NavigationView& nav_; Button button_done{ - {240, 0, 1, 1}, + {screen_width, 0, 1, 1}, ""}; }; diff --git a/firmware/application/ui_sd_card_debug.hpp b/firmware/application/ui_sd_card_debug.hpp index cf2b60b66..4b744a894 100644 --- a/firmware/application/ui_sd_card_debug.hpp +++ b/firmware/application/ui_sd_card_debug.hpp @@ -60,62 +60,62 @@ class SDCardDebugView : public View { }; Text text_format{ - {240 - ((sizeof("Undefined: 255") + 1) * 8), 1 * 16, (sizeof("Undefined: 255") + 1) * 8, 16}, + {screen_width - (int)((sizeof("Undefined: 255") + 1) * 8), 1 * 16, (sizeof("Undefined: 255") + 1) * 8, 16}, "Unknown", }; Text text_csd_value_3{ - {240 - ((8 + 1 + 8) * 8), 3 * 16, (8 * 8), 16}, + {screen_width - ((8 + 1 + 8) * 8), 3 * 16, (8 * 8), 16}, "", }; Text text_csd_value_2{ - {240 - (8 * 8), 3 * 16, (8 * 8), 16}, + {screen_width - (8 * 8), 3 * 16, (8 * 8), 16}, "", }; Text text_csd_value_1{ - {240 - ((8 + 1 + 8) * 8), 4 * 16, (8 * 8), 16}, + {screen_width - ((8 + 1 + 8) * 8), 4 * 16, (8 * 8), 16}, "", }; Text text_csd_value_0{ - {240 - (8 * 8), 4 * 16, (8 * 8), 16}, + {screen_width - (8 * 8), 4 * 16, (8 * 8), 16}, "", }; static constexpr size_t bus_width_characters = 1; Text text_bus_width_value{ - {240 - (bus_width_characters * 8), 5 * 16, (bus_width_characters * 8), 16}, + {screen_width - (int)(bus_width_characters * 8), 5 * 16, (bus_width_characters * 8), 16}, "", }; static constexpr size_t card_type_characters = 13; Text text_card_type_value{ - {240 - (card_type_characters * 8), 6 * 16, (card_type_characters * 8), 16}, + {screen_width - (int)(card_type_characters * 8), 6 * 16, (card_type_characters * 8), 16}, "", }; static constexpr size_t block_size_characters = 5; Text text_block_size_value{ - {240 - (block_size_characters * 8), 8 * 16, (block_size_characters * 8), 16}, + {screen_width - (int)(block_size_characters * 8), 8 * 16, (block_size_characters * 8), 16}, "", }; static constexpr size_t block_count_characters = 9; Text text_block_count_value{ - {240 - (block_count_characters * 8), 9 * 16, (block_count_characters * 8), 16}, + {screen_width - (int)(block_count_characters * 8), 9 * 16, (block_count_characters * 8), 16}, "", }; static constexpr size_t capacity_characters = 10; Text text_capacity_value{ - {240 - (capacity_characters * 8), 10 * 16, (capacity_characters * 8), 16}, + {screen_width - (int)(capacity_characters * 8), 10 * 16, (capacity_characters * 8), 16}, "", }; @@ -129,7 +129,7 @@ class SDCardDebugView : public View { }; Text text_test_write_time_value{ - {240 - (test_write_time_characters * 8), 12 * 16, (test_write_time_characters * 8), 16}, + {screen_width - (int)(test_write_time_characters * 8), 12 * 16, (test_write_time_characters * 8), 16}, "", }; @@ -141,7 +141,7 @@ class SDCardDebugView : public View { }; Text text_test_write_rate_value{ - {240 - (test_write_rate_characters * 8), 13 * 16, (test_write_rate_characters * 8), 16}, + {screen_width - (int)(test_write_rate_characters * 8), 13 * 16, (test_write_rate_characters * 8), 16}, "", }; @@ -155,7 +155,7 @@ class SDCardDebugView : public View { }; Text text_test_read_time_value{ - {240 - (test_read_time_characters * 8), 14 * 16, (test_read_time_characters * 8), 16}, + {screen_width - (int)(test_read_time_characters * 8), 14 * 16, (test_read_time_characters * 8), 16}, "", }; @@ -167,7 +167,7 @@ class SDCardDebugView : public View { }; Text text_test_read_rate_value{ - {240 - (test_read_rate_characters * 8), 15 * 16, (test_read_rate_characters * 8), 16}, + {screen_width - (int)(test_read_rate_characters * 8), 15 * 16, (test_read_rate_characters * 8), 16}, "", }; @@ -178,7 +178,7 @@ class SDCardDebugView : public View { "Test"}; Button button_ok{ - {240 - 96 - 16, 17 * 16, 96, 24}, + {screen_width - 96 - 16, 17 * 16, 96, 24}, "OK"}; }; diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 31fb67034..ecb17ef66 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -182,7 +182,7 @@ static void cmd_screenshot(BaseSequentialStream* chp, int argc, char* argv[]) { return; for (int i = 0; i < ui::screen_height; i++) { - std::array row; + std::vector row(ui::screen_width); portapack::display.read_pixels({0, i, ui::screen_width, 1}, row); png.write_scanline(row); } @@ -199,7 +199,7 @@ static void cmd_screenframe(BaseSequentialStream* chp, int argc, char* argv[]) { evtd->enter_shell_working_mode(); for (int i = 0; i < ui::screen_height; i++) { - std::array row; + std::vector row(ui::screen_width); portapack::display.read_pixels({0, i, ui::screen_width, 1}, row); for (int px = 0; px < ui::screen_width; px += 5) { char buffer[5 * 3 * 2 + 1]; @@ -242,9 +242,9 @@ static void cmd_screenframeshort(BaseSequentialStream* chp, int argc, char* argv char buffer[USBSERIAL_BUFFERS_SIZE]; size_t wp = 0; for (int y = 0; y < ui::screen_height; y++) { - std::array row; + std::vector row(ui::screen_width); portapack::display.read_pixels({0, y, ui::screen_width, 1}, row); - for (int i = 0; i < 240; ++i) { + for (int i = 0; i < ui::screen_width; ++i) { screenbuffer_helper_add(chp, buffer, wp, getChrFromRgb(row[i].r, row[i].g, row[i].b)); } screenbuffer_helper_add(chp, buffer, wp, '\r'); diff --git a/firmware/common/lcd_ili9341.hpp b/firmware/common/lcd_ili9341.hpp index e299b1db7..2637b68b0 100644 --- a/firmware/common/lcd_ili9341.hpp +++ b/firmware/common/lcd_ili9341.hpp @@ -34,7 +34,7 @@ namespace lcd { class ILI9341 { public: - constexpr ILI9341() + ILI9341() : scroll_state{0, 0, height(), 0} { } @@ -72,12 +72,23 @@ class ILI9341 { draw_pixels(r, colors.data(), colors.size()); } + void draw_pixels( + const ui::Rect r, + const std::vector& colors) { + draw_pixels(r, colors.data(), colors.size()); + } + template void read_pixels( const ui::Rect r, std::array& colors) { read_pixels(r, colors.data(), colors.size()); } + void read_pixels( + const ui::Rect r, + std::vector& colors) { + read_pixels(r, colors.data(), colors.size()); + } void draw_bitmap( const ui::Point p, @@ -138,9 +149,9 @@ class ILI9341 { */ ui::Coord scroll_area_y(const ui::Coord y) const; - constexpr ui::Dim width() const { return ui::screen_width; } - constexpr ui::Dim height() const { return ui::screen_height; } - constexpr ui::Rect screen_rect() const { return {0, 0, width(), height()}; } + ui::Dim width() { return ui::screen_width; } + ui::Dim height() { return ui::screen_height; } + ui::Rect screen_rect() { return {0, 0, width(), height()}; } void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count); void read_pixels(const ui::Rect r, ui::ColorRGB888* const colors, const size_t count); diff --git a/firmware/common/png_writer.cpp b/firmware/common/png_writer.cpp index bc5aeb64c..3251bad4b 100644 --- a/firmware/common/png_writer.cpp +++ b/firmware/common/png_writer.cpp @@ -63,7 +63,32 @@ Optional PNGWriter::create( } file.write(png_file_header); - file.write(png_ihdr_screen_capture); + // ihdr dynamic + std::array png_ihdr_dyn; + for (uint8_t i = 0; i < 25; i++) { + png_ihdr_dyn[i] = png_ihdr_screen_capture[i]; + } + // Write width (4 bytes big-endian) + png_ihdr_dyn[8] = (width >> 24) & 0xFF; + png_ihdr_dyn[9] = (width >> 16) & 0xFF; + png_ihdr_dyn[10] = (width >> 8) & 0xFF; + png_ihdr_dyn[11] = width & 0xFF; + + // Write height (4 bytes big-endian) + png_ihdr_dyn[12] = (height >> 24) & 0xFF; + png_ihdr_dyn[13] = (height >> 16) & 0xFF; + png_ihdr_dyn[14] = (height >> 8) & 0xFF; + png_ihdr_dyn[15] = height & 0xFF; + crc.reset(); + crc.process_bytes(png_ihdr_dyn.data(), 25); + uint32_t crci = crc.checksum(); + + png_ihdr_dyn[21] = (crci >> 24) & 0xFF; + png_ihdr_dyn[22] = (crci >> 16) & 0xFF; + png_ihdr_dyn[23] = (crci >> 8) & 0xFF; + png_ihdr_dyn[24] = crci & 0xFF; + + file.write(png_ihdr_dyn); write_chunk_header( 2 + height * (5 + 1 + width * 3) + 4, @@ -108,6 +133,35 @@ void PNGWriter::write_scanline(const std::array& scanline) scanline_count++; } +void PNGWriter::write_scanline(const std::vector& scanline) { + constexpr uint8_t scanline_filter_type = 0; + + // Total block length = 1 filter byte + scanline byte length + const uint32_t deflate_block_length = 1 + static_cast(scanline.size() * sizeof(ui::ColorRGB888)); + + const std::array deflate_and_scanline_header{ + static_cast((scanline_count == (height - 1)) ? 0x01 : 0x00), // Final block? + static_cast(deflate_block_length & 0xff), // Length LSB + static_cast((deflate_block_length >> 8) & 0xff), // Length MSB + static_cast((deflate_block_length & 0xff) ^ 0xff), // ~Length LSB + static_cast(((deflate_block_length >> 8) & 0xff) ^ 0xff), // ~Length MSB + scanline_filter_type}; + write_chunk_content(deflate_and_scanline_header); + + adler_32.feed(scanline_filter_type); + adler_32.feed(scanline); + + // Chunked writing to avoid large single writes + constexpr size_t CHUNK_SIZE = 80; // Tune for your hardware/filesystem + + for (size_t i = 0; i < scanline.size(); i += CHUNK_SIZE) { + size_t chunk_len = std::min(CHUNK_SIZE, scanline.size() - i); + write_chunk_content(&scanline[i], chunk_len * sizeof(ui::ColorRGB888)); + } + + scanline_count++; +} + void PNGWriter::write_chunk_header( const size_t length, const std::array& type) { diff --git a/firmware/common/png_writer.hpp b/firmware/common/png_writer.hpp index 348784f9f..688cd517e 100644 --- a/firmware/common/png_writer.hpp +++ b/firmware/common/png_writer.hpp @@ -38,11 +38,12 @@ class PNGWriter { Optional create(const std::filesystem::path& filename); void write_scanline(const std::array& scanline); + void write_scanline(const std::vector& scanline); private: // TODO: These constants are baked in a few places, do not change blithely. - static constexpr int width{240}; - static constexpr int height{320}; + int width{ui::screen_width}; + int height{ui::screen_height}; File file{}; int scanline_count{0}; diff --git a/firmware/common/ui.cpp b/firmware/common/ui.cpp index 58a838f68..8ceb344e7 100644 --- a/firmware/common/ui.cpp +++ b/firmware/common/ui.cpp @@ -28,6 +28,9 @@ namespace ui { +uint16_t screen_width = 240; +uint16_t screen_height = 320; + // CGA palette // Index into this table should match STR_COLOR_ escape string in ui.hpp Color term_colors[16] = { diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index 36a7b837a..4a029cbda 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -50,8 +50,8 @@ namespace ui { using Coord = int16_t; using Dim = int16_t; -constexpr uint16_t screen_width = 240; -constexpr uint16_t screen_height = 320; +extern uint16_t screen_width; +extern uint16_t screen_height; /* Dimensions for the default font character. */ constexpr uint16_t char_width = 8;