diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index ca6d2662..d70e724f 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -45,7 +45,7 @@ void MicTXView::focus() { field_rxfrequency.focus(); break; default: - field_frequency.focus(); + field_va.focus(); break; } } @@ -126,7 +126,7 @@ void MicTXView::do_timing() { } else { // Check for PTT release const auto switches_state = get_switches_state(); - if (!switches_state[0] && transmitting) // Right button + if (!switches_state[4] && transmitting && !button_touch) // Select button set_tx(false); } } @@ -175,9 +175,7 @@ void MicTXView::on_headphone_volume_changed(int32_t v) { } void MicTXView::set_ptt_visibility(bool v) { - text_ptt_1.hidden(!v); - text_ptt_2.hidden(!v); - text_ptt_3.hidden(!v); + tx_button.hidden(!v); } MicTXView::MicTXView( @@ -210,9 +208,7 @@ MicTXView::MicTXView( &field_rxlna, &field_rxvga, &field_rxamp, - &text_ptt_1, - &text_ptt_2, - &text_ptt_3 + &tx_button }); tone_keys_populate(options_tone_key); @@ -236,10 +232,10 @@ MicTXView::MicTXView( transmitter_model.set_tuning_frequency(f); }; field_frequency.on_edit = [this, &nav]() { + focused_ui = 0; // TODO: Provide separate modal method/scheme? auto new_view = nav.push(tx_frequency); new_view->on_changed = [this](rf::Frequency f) { - focused_ui = 0; tx_frequency = f; if(!rx_enabled) transmitter_model.set_tuning_frequency(f); @@ -350,10 +346,10 @@ MicTXView::MicTXView( receiver_model.set_tuning_frequency(f); }; field_rxfrequency.on_edit = [this, &nav]() { + focused_ui = 1; // TODO: Provide separate modal method/scheme? auto new_view = nav.push(rx_frequency); new_view->on_changed = [this](rf::Frequency f) { - focused_ui = 1; rx_frequency = f; if(rx_enabled) receiver_model.set_tuning_frequency(f); @@ -384,6 +380,26 @@ MicTXView::MicTXView( }; field_rxamp.set_value(rx_amp); + tx_button.on_select = [this](TxButton&) { + if(ptt_enabled && !transmitting) { + button_touch = true; + set_tx(true); + } + }; + + tx_button.on_release = [this](TxButton&) { + if(button_touch) { + button_touch = false; + set_tx(false); + } + }; + + tx_button.on_buttonpress = [this](TxButton&) { + if(ptt_enabled && !transmitting) { + set_tx(true); + } + }; + transmitter_model.set_sampling_rate(sampling_rate); transmitter_model.set_baseband_bandwidth(1750000); diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 0b0c6d6e..cb735503 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -47,6 +47,8 @@ public: void focus() override; // PTT: Enable through KeyEvent (only works with presses), disable by polling :( + // This is the old "RIGHT BUTTON" method. + /* bool on_key(const KeyEvent key) { if ((key == KeyEvent::Right) && (!va_enabled) && ptt_enabled) { set_tx(true); @@ -54,7 +56,8 @@ public: } else return false; }; - + */ + std::string title() const override { return "Mic TX RX"; }; private: @@ -93,26 +96,27 @@ private: bool rx_amp { false }; rf::Frequency tx_frequency { 0 }; rf::Frequency rx_frequency { 0 }; - int32_t focused_ui { 0 }; + int32_t focused_ui { 2 }; + bool button_touch { true }; Labels labels { { { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() }, - { { 3 * 8, 3 * 8 }, "FREQUENCY:", Color::light_grey() }, - { { 3 * 8, 5 * 8 }, "BANDWIDTH: kHz", Color::light_grey() }, - { { 3 * 8, 7 * 8 }, "RFGAIN:", Color::light_grey() }, - { {13 * 8, 7 * 8 }, "Amp:", Color::light_grey() }, - { { 3 * 8, 10 * 8 }, "TX Activation:", Color::light_grey() }, - { { 7 * 8, 12 * 8 }, "LEVEL: /255", Color::light_grey() }, - { { 6 * 8, 14 * 8 }, "ATTACK: ms", Color::light_grey() }, - { { 7 * 8, 16 * 8 }, "DECAY: ms", Color::light_grey() }, - { { 4 * 8, ( 19 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() }, - { { 9 * 8, 30 * 8 }, "VOL:", Color::light_grey() }, - { { 5 * 8, 32 * 8 }, "SQUELCH:", Color::light_grey() }, - { { 5 * 8, 34 * 8 }, "FREQUENCY:", Color::light_grey() }, - { { 5 * 8, 36 * 8 }, "LNA:", Color::light_grey()}, - { {12 * 8, 36 * 8 }, "VGA:", Color::light_grey()}, - { {19 * 8, 36 * 8 }, "AMP:", Color::light_grey()} + { { 3 * 8, 3 * 8 }, "F:", Color::light_grey() }, + { { 15 * 8, 3 * 8 }, "BW: kHz", Color::light_grey() }, + { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, + { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, + { { 3 * 8, 8 * 8 }, "TX Activation:", Color::light_grey() }, + { { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() }, + { {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() }, + { {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() }, + { { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() }, + { { 9 * 8, 23 * 8 }, "VOL:", Color::light_grey() }, + { {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() }, + { { 5 * 8, 25 * 8 }, "F:", Color::light_grey() }, + { { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()}, + { {12 * 8, 27 * 8 }, "VGA:", Color::light_grey()}, + { {19 * 8, 27 * 8 }, "AMP:", Color::light_grey()} }; VuMeter vumeter { @@ -120,6 +124,7 @@ private: 12, true }; + OptionsField options_gain { { 13 * 8, 1 * 8 }, @@ -133,10 +138,10 @@ private: }; FrequencyField field_frequency { - { 13 * 8, 3 * 8 }, + { 5 * 8, 3 * 8 }, }; NumberField field_bw { - { 13 * 8, 5 * 8 }, + { 18 * 8, 3 * 8 }, 3, { 0, 150 }, 1, @@ -144,14 +149,14 @@ private: }; NumberField field_rfgain { - { 10 * 8, 7 * 8 }, + { 8 * 8, 5 * 8 }, 2, { 0, 47 }, 1, ' ' }; NumberField field_rfamp { - { 17 * 8, 7 * 8 }, + { 15 * 8, 5 * 8 }, 2, { 0, 14 }, 14, @@ -167,7 +172,7 @@ private: */ OptionsField field_va { - { 17 * 8, 10 * 8 }, + { 17 * 8, 8 * 8 }, 3, { {" OFF", 0}, @@ -177,21 +182,21 @@ private: }; NumberField field_va_level { - { 13 * 8, 12 * 8 }, + { 8 * 8, 10 * 8 }, 3, { 0, 255 }, 2, ' ' }; NumberField field_va_attack { - { 13 * 8, 14 * 8 }, + { 16 * 8, 10 * 8 }, 3, { 0, 999 }, 20, ' ' }; NumberField field_va_decay { - { 13 * 8, 16 * 8 }, + { 24 * 8, 10 * 8 }, 4, { 0, 9999 }, 100, @@ -199,27 +204,27 @@ private: }; OptionsField options_tone_key { - { 10 * 8, ( 21 * 8 ) - 2 }, + { 10 * 8, ( 15 * 8 ) - 2 }, 23, { } }; Checkbox check_rogerbeep { - { 3 * 8, 23 * 8 }, + { 3 * 8, ( 16 * 8 ) + 4 }, 10, "Roger beep", false }; Checkbox check_rxactive { - { 3 * 8, (27 * 8) + 4 }, + { 3 * 8, ( 21 * 8 ) - 4 }, 8, "RX audio listening", false }; NumberField field_volume { - { 13 * 8, 30 * 8 }, + { 13 * 8, 23 * 8 }, 2, { 0, 99 }, 1, @@ -227,7 +232,7 @@ private: }; NumberField field_squelch { - { 13 * 8, 32 * 8 }, + { 20 * 8, 25 * 8 }, 2, { 0, 99 }, 1, @@ -235,11 +240,11 @@ private: }; FrequencyField field_rxfrequency { - { 15 * 8, 34 * 8 }, + { 7 * 8, 25 * 8 }, }; NumberField field_rxlna { - { 9 * 8, 36 * 8 }, + { 9 * 8, 27 * 8 }, 2, { 0, 40 }, 8, @@ -247,7 +252,7 @@ private: }; NumberField field_rxvga { - { 16 * 8, 36 * 8 }, + { 16 * 8, 27 * 8 }, 2, { 0, 62 }, 2, @@ -255,24 +260,16 @@ private: }; NumberField field_rxamp { - { 23 * 8, 36 * 8 }, + { 23 * 8, 27 * 8 }, 1, { 0, 1 }, 1, ' ', }; - Text text_ptt_1 { - { 22 * 8, 13 * 8, 7 * 8, 8 }, - "PTT: " - }; - Text text_ptt_2 { - { 22 * 8, 15 * 8, 7 * 8, 8 }, - "RIGHT " - }; - Text text_ptt_3 { - { 22 * 8, 17 * 8, 7 * 8, 8 }, - "BUTTON" + TxButton tx_button { + { 10 * 8, 30 * 8, 10 * 8, 5 * 8 }, + "TX" }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index a9333eae..af20b152 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -946,6 +946,101 @@ bool Button::on_touch(const TouchEvent event) { #endif } +/* TxButton ****************************************************************/ + +TxButton::TxButton( + Rect parent_rect, + std::string text +) : Widget { parent_rect }, + text_ { text } +{ + set_focusable(true); +} + +void TxButton::set_text(const std::string value) { + text_ = value; + set_dirty(); +} + +std::string TxButton::text() const { + return text_; +} + +void TxButton::paint(Painter& painter) { + Color bg, fg; + const auto r = screen_rect(); + + if (has_focus() || highlighted()) { + bg = style().foreground; + fg = Color::black(); + } else { + bg = Color::grey(); + fg = style().foreground; + } + + const Style paint_style = { style().font, bg, fg }; + + painter.draw_rectangle({r.location(), {r.size().width(), 1}}, Color::light_grey()); + painter.draw_rectangle({r.location().x(), r.location().y() + r.size().height() - 1, r.size().width(), 1}, Color::dark_grey()); + painter.draw_rectangle({r.location().x() + r.size().width() - 1, r.location().y(), 1, r.size().height()}, Color::dark_grey()); + + painter.fill_rectangle( + { r.location().x(), r.location().y() + 1, r.size().width() - 1, r.size().height() - 2 }, + paint_style.background + ); + + const auto label_r = paint_style.font.size_of(text_); + painter.draw_string( + { r.location().x() + (r.size().width() - label_r.width()) / 2, r.location().y() + (r.size().height() - label_r.height()) / 2 }, + paint_style, + text_ + ); +} + +void TxButton::on_focus() { + if( on_highlight ) + on_highlight(*this); +} + +bool TxButton::on_key(const KeyEvent key) { + if( key == KeyEvent::Select ) { + if( on_buttonpress ) { + on_buttonpress(*this); + return true; + } + } else { + if( on_dir ) { + return on_dir(*this, key); + } + } + + return false; +} + +bool TxButton::on_touch(const TouchEvent event) { + switch(event.type) { + case TouchEvent::Type::Start: + set_highlighted(true); + set_dirty(); + if( on_select ) { + on_select(*this); + } + return true; + + + case TouchEvent::Type::End: + set_highlighted(false); + set_dirty(); + if( on_release ) { + on_release(*this); + } + return true; + + default: + return false; + } +} + /* NewButton ****************************************************************/ NewButton::NewButton( diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 51de4277..6bca547f 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -401,6 +401,34 @@ private: std::string text_; }; +class TxButton : public Widget { +public: + std::function on_select { }; // Touch only. + std::function on_release { }; // Touch only. There's no way (or complicated) for detecting a button's release :( + std::function on_buttonpress { }; + std::function on_dir { }; + std::function on_highlight { }; + + TxButton(Rect parent_rect, std::string text); + + TxButton( + ) : TxButton { { }, { } } + { + } + + void set_text(const std::string value); + std::string text() const; + + void paint(Painter& painter) override; + + void on_focus() override; + bool on_key(const KeyEvent key) override; + bool on_touch(const TouchEvent event) override; + +private: + std::string text_; +}; + class NewButton : public Widget { public: std::function on_select { };