Prepare for display orientation part 1 (#2661)

This commit is contained in:
Totoo 2025-05-22 17:24:53 +02:00 committed by GitHub
parent 6f6d863a14
commit a1d7cf2b86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
85 changed files with 405 additions and 334 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -6,6 +6,10 @@
#include <cstdint>
/*
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",
};

View file

@ -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<ADSBRxDetailsView>(entry);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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<int>(title.size()) * 8) / 2, 16,
text_title.set_parent_rect({(screen_width - static_cast<int>(title.size()) * 8) / 2, 16,
static_cast<int>(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({&registers_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));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -34,6 +34,7 @@ namespace ui {
IQTrimView::IQTrimView(NavigationView& nav)
: nav_{nav} {
power_buckets_.resize(screen_width);
add_children({
&labels,
&field_path,

View file

@ -96,7 +96,7 @@ class IQTrimView : public View {
std::filesystem::path path_{};
Optional<iq::CaptureInfo> info_{};
std::array<iq::PowerBuckets::Bucket, screen_width> power_buckets_{};
std::vector<iq::PowerBuckets::Bucket> power_buckets_{};
TrimProgressUI progress_ui{};
Labels labels{

View file

@ -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<int> y_max_range{0, 320 - (108 + 16)};
const range_t<int> 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,7 +304,7 @@ 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({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
@ -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

View file

@ -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<Color, SCREEN_W> spectrum_row{};
std::array<uint8_t, SCREEN_W> spectrum_data{};
std::vector<Color> spectrum_row{};
std::vector<uint8_t> 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{

View file

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

View file

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

View file

@ -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 {
"<REMOVE>"};
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},

View file

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

View file

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

View file

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

View file

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

View file

@ -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<Color, screen_width> pixel_data;
std::vector<Color> pixel_data(screen_width);
// Seek past all the headers.
file.seek(43);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -53,7 +53,7 @@ class CVSSpamView : public View {
std::vector<std::filesystem::path> 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,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,19 +46,22 @@ class Ticker {
#define COLOR_FOOD Red
#define COLOR_BORDER White
extern Ticker game_timer;
class SnakeView : public View {
public:
SnakeView(NavigationView& nav);
void on_show() override;
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;
std::string title() const override { return "Snake"; }
void focus() override { dummy.focus(); }
void paint(Painter& painter) override;
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();
@ -99,25 +77,48 @@ void spawn_food();
bool check_collision();
void show_menu();
void show_game_over();
void check_game_timer();
class SnakeView : public View {
public:
SnakeView(NavigationView& nav);
void on_show() override;
std::string title() const override { return "Snake"; }
void focus() override { dummy.focus(); }
void paint(Painter& painter) override;
void frame_sync();
bool on_key(KeyEvent key) override;
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<int> snake_x{}; //[GRID_WIDTH * GRID_HEIGHT];
std::vector<int> 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{

View file

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

View file

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

View file

@ -244,12 +244,12 @@ std::vector<uint8_t> 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;
}
}

View file

@ -73,7 +73,7 @@ void SpectrumInputTextView::paint(Painter& painter) {
}
painter.fill_rectangle(
{{0, 40}, {240, 204}},
{{0, 40}, {screen_width, 204}},
style().background);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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<GridItem> menu_items{};
std::vector<std::unique_ptr<NewButton>> 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};

View file

@ -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<Button, 12> buttons{};

View file

@ -135,7 +135,7 @@ TabView::TabView(std::initializer_list<TabDef> 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});

View file

@ -501,7 +501,7 @@ void SystemStatusView::on_camera() {
return;
for (int i = 0; i < screen_height; i++) {
std::array<ColorRGB888, screen_width> row;
std::vector<ColorRGB888> 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,

View file

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

View file

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

View file

@ -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<ui::ColorRGB888, ui::screen_width> row;
std::vector<ui::ColorRGB888> 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<ui::ColorRGB888, ui::screen_width> row;
std::vector<ui::ColorRGB888> 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<ui::ColorRGB888, ui::screen_width> row;
std::vector<ui::ColorRGB888> 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');

View file

@ -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<ui::Color>& colors) {
draw_pixels(r, colors.data(), colors.size());
}
template <size_t N>
void read_pixels(
const ui::Rect r,
std::array<ui::ColorRGB888, N>& colors) {
read_pixels(r, colors.data(), colors.size());
}
void read_pixels(
const ui::Rect r,
std::vector<ui::ColorRGB888>& 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);

View file

@ -63,7 +63,32 @@ Optional<File::Error> PNGWriter::create(
}
file.write(png_file_header);
file.write(png_ihdr_screen_capture);
// ihdr dynamic
std::array<uint8_t, 25> 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<ui::ColorRGB888, 240>& scanline)
scanline_count++;
}
void PNGWriter::write_scanline(const std::vector<ui::ColorRGB888>& 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<uint32_t>(scanline.size() * sizeof(ui::ColorRGB888));
const std::array<uint8_t, 6> deflate_and_scanline_header{
static_cast<uint8_t>((scanline_count == (height - 1)) ? 0x01 : 0x00), // Final block?
static_cast<uint8_t>(deflate_block_length & 0xff), // Length LSB
static_cast<uint8_t>((deflate_block_length >> 8) & 0xff), // Length MSB
static_cast<uint8_t>((deflate_block_length & 0xff) ^ 0xff), // ~Length LSB
static_cast<uint8_t>(((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<uint8_t, 4>& type) {

View file

@ -38,11 +38,12 @@ class PNGWriter {
Optional<File::Error> create(const std::filesystem::path& filename);
void write_scanline(const std::array<ui::ColorRGB888, 240>& scanline);
void write_scanline(const std::vector<ui::ColorRGB888>& 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};

View file

@ -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] = {

View file

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