diff --git a/firmware/application/external/gfxeq/ui_gfxeq.cpp b/firmware/application/external/gfxeq/ui_gfxeq.cpp index 7e2a23f9f..c74044601 100644 --- a/firmware/application/external/gfxeq/ui_gfxeq.cpp +++ b/firmware/application/external/gfxeq/ui_gfxeq.cpp @@ -13,18 +13,18 @@ namespace ui::external_app::gfxeq { gfxEQView::gfxEQView(NavigationView& nav) : nav_{nav}, bar_heights(NUM_BARS, 0), prev_bar_heights(NUM_BARS, 0) { baseband::run_image(spi_flash::image_tag_wfm_audio); - add_children({&rssi, &channel, &audio, &field_frequency, &field_lna, &field_vga, - &options_modulation, &field_volume, &text_ctcss, &record_view, &dummy}); + add_children({&field_frequency, &field_lna, &field_vga, &options_modulation, + &field_volume, &text_ctcss, &record_view, &button_mood, &dummy}); field_lna.on_show_options = [this]() { this->on_show_options_rf_gain(); }; field_vga.on_show_options = [this]() { this->on_show_options_rf_gain(); }; receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio); receiver_model.set_sampling_rate(3072000); - receiver_model.set_baseband_bandwidth(40000); receiver_model.set_target_frequency(93100000); receiver_model.set_rf_amp(true); receiver_model.enable(); + receiver_model.set_baseband_bandwidth(40000); field_lna.set_value(40); field_vga.set_value(62); @@ -44,6 +44,8 @@ gfxEQView::gfxEQView(NavigationView& nav) record_view.set_sampling_rate(48000); audio::output::start(); + + button_mood.on_select = [this](Button&) { this->cycle_theme(); }; } gfxEQView::~gfxEQView() { @@ -86,6 +88,7 @@ void gfxEQView::update_audio_spectrum(const AudioSpectrum& spectrum) { void gfxEQView::render_equalizer(Painter& painter) { const int num_bars = SCREEN_WIDTH / (BAR_WIDTH + BAR_SPACING); const int num_segments = RENDER_HEIGHT / SEGMENT_HEIGHT; + const ColorTheme& theme = themes[current_theme]; for (int bar = 0; bar < num_bars; bar++) { int x = bar * (BAR_WIDTH + BAR_SPACING); @@ -101,7 +104,7 @@ void gfxEQView::render_equalizer(Painter& painter) { int y = SCREEN_HEIGHT - (seg + 1) * SEGMENT_HEIGHT; if (y < header_height) break; - Color segment_color = (seg >= active_segments - 2 && seg < active_segments) ? Color(255, 255, 255) : Color(255, 0, 255); + Color segment_color = (seg >= active_segments - 2 && seg < active_segments) ? theme.peak_color : theme.base_color; painter.fill_rectangle({x, y, BAR_WIDTH, SEGMENT_HEIGHT - 1}, segment_color); } @@ -246,4 +249,9 @@ void gfxEQView::handle_coded_squelch(uint32_t value) { text_ctcss.set(tonekey::tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8)); } +void gfxEQView::cycle_theme() { + current_theme = (current_theme + 1) % themes.size(); + set_dirty(); +} + } // namespace ui::external_app::gfxeq \ No newline at end of file diff --git a/firmware/application/external/gfxeq/ui_gfxeq.hpp b/firmware/application/external/gfxeq/ui_gfxeq.hpp index 415245531..5c9ab396b 100644 --- a/firmware/application/external/gfxeq/ui_gfxeq.hpp +++ b/firmware/application/external/gfxeq/ui_gfxeq.hpp @@ -36,15 +36,40 @@ private: static constexpr int BAR_SPACING = 2; static constexpr int SEGMENT_HEIGHT = 10; + struct ColorTheme { + Color base_color; + Color peak_color; + }; + NavigationView& nav_; bool initialized{false}; std::vector bar_heights; std::vector prev_bar_heights; bool running{false}; + size_t current_theme{0}; + const std::array themes{ + ColorTheme{Color(255, 0, 255), Color(255, 255, 255)}, // Neon Fury + ColorTheme{Color(0, 255, 0), Color(255, 0, 0)}, // Toxic Blaze + ColorTheme{Color(0, 0, 255), Color(255, 255, 0)}, // Midnight Venom + ColorTheme{Color(255, 128, 0), Color(255, 0, 128)}, // Inferno Pulse + ColorTheme{Color(128, 0, 255), Color(0, 255, 255)}, // Cyber Vortex + ColorTheme{Color(255, 255, 0), Color(0, 255, 128)}, // Solar Flare + ColorTheme{Color(255, 0, 0), Color(0, 128, 255)}, // Blood Eclipse + ColorTheme{Color(0, 255, 128), Color(255, 128, 255)}, // Acid Horizon + ColorTheme{Color(128, 128, 128), Color(255, 255, 255)},// Steel Phantom + ColorTheme{Color(255, 64, 0), Color(0, 255, 64)}, // Ember Storm + ColorTheme{Color(0, 128, 128), Color(255, 192, 0)}, // Teal Abyss + ColorTheme{Color(0, 255, 0), Color(0, 128, 0)}, // Matrix Rain + ColorTheme{Color(32, 64, 32), Color(0, 255, 0)}, // Hacker Terminal + ColorTheme{Color(64, 0, 128), Color(255, 0, 255)}, // BBS Neon + ColorTheme{Color(0, 64, 0), Color(0, 255, 128)}, // CRT Glow + ColorTheme{Color(255, 255, 255), Color(0, 0, 255)}, // Digital Grid + ColorTheme{Color(128, 0, 0), Color(255, 128, 0)}, // Redline Hack + ColorTheme{Color(0, 128, 255), Color(255, 255, 128)}, // Cybernet Blue + ColorTheme{Color(64, 64, 64), Color(255, 0, 0)}, // Shadow Net + ColorTheme{Color(255, 192, 0), Color(0, 64, 128)} // Amber Code + }; - RSSI rssi{{21 * 8, 0, 6 * 8, 4}}; - Channel channel{{21 * 8, 5, 6 * 8, 4}}; - Audio audio{{21 * 8, 10, 6 * 8, 4}}; RxFrequencyField field_frequency{{5 * 8, 0 * 16}, nav_}; LNAGainField field_lna{Point{15 * 8, 0 * 16}}; VGAGainField field_vga{Point{18 * 8, 0 * 16}}; @@ -70,6 +95,7 @@ private: }; const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16}; std::unique_ptr options_widget{}; + Button button_mood{{21 * 8, 0, 6 * 8, 16}, "MOOD"}; Button dummy{{240, 0, 0, 0}, ""}; void start(); @@ -85,6 +111,7 @@ private: void set_options_widget(std::unique_ptr new_widget); void update_modulation(ReceiverModel::Mode modulation); void handle_coded_squelch(uint32_t value); + void cycle_theme(); MessageHandlerRegistration message_handler_frame_sync{ Message::ID::DisplayFrameSync,