Digit Mode for frequency field (#1298)

* Remove 'auto' step mode

* Support per-digit edits on the freq field.

* Swizzle instead of raw accessor

* Fix debug ui after swizzle
This commit is contained in:
Kyle Reed
2023-07-24 09:09:22 -07:00
committed by GitHub
parent e2bca9aebb
commit 3514a9a608
11 changed files with 230 additions and 95 deletions

View File

@@ -20,16 +20,15 @@
* Boston, MA 02110-1301, USA.
*/
#include "irq_controls.hpp"
#include "max283x.hpp"
#include "portapack.hpp"
#include "string_format.hpp"
#include "ui_receiver.hpp"
#include "ui_freqman.hpp"
#include "portapack.hpp"
using namespace portapack;
#include "string_format.hpp"
#include "max283x.hpp"
namespace ui {
/* FrequencyField ********************************************************/
@@ -38,10 +37,15 @@ FrequencyField::FrequencyField(
const Point parent_pos)
: Widget{{parent_pos, {8 * 10, 16}}},
length_{11},
range(rf::tuning_range) {
range_{rf::tuning_range} {
initial_switch_config_ = get_switches_long_press_config();
set_focusable(true);
}
FrequencyField::~FrequencyField() {
set_switches_long_press_config(initial_switch_config_);
}
rf::Frequency FrequencyField::value() const {
return value_;
}
@@ -59,48 +63,75 @@ void FrequencyField::set_value(rf::Frequency new_value) {
}
void FrequencyField::set_step(rf::Frequency new_value) {
step = new_value;
// TODO: Quantize current frequency to a step of the new size?
step_ = new_value;
}
void FrequencyField::paint(Painter& painter) {
const std::string str_value = to_string_short_freq(value_);
const auto str_value = to_string_short_freq(value_);
const auto paint_style = has_focus() ? style().invert() : style();
painter.draw_string(
screen_pos(),
paint_style,
str_value);
// Highlight current digit in digit_mode.
if (digit_mode_) {
auto p = screen_pos();
p += {digit_ * char_width, 0};
painter.draw_char(p, Styles::bg_blue, str_value[digit_]);
}
}
bool FrequencyField::on_key(const ui::KeyEvent event) {
if (event == ui::KeyEvent::Select) {
bool FrequencyField::on_key(KeyEvent event) {
if (event == KeyEvent::Select) {
// Toggle 'digit' mode with long-press.
if (digit_mode_ || key_is_long_pressed(event)) {
digit_mode_ = !digit_mode_;
set_dirty();
return true;
}
if (on_edit) {
on_edit();
return true;
}
}
if (digit_mode_) {
switch (event) {
case KeyEvent::Up:
set_value(value_ + digit_step());
break;
case KeyEvent::Down:
set_value(value_ - digit_step());
break;
case KeyEvent::Left:
digit_--;
break;
case KeyEvent::Right:
digit_++;
break;
default:
return false;
}
// Clip value to the bounds of 'to_string_short_freq' result.
digit_ = clip<uint8_t>(digit_, 0, 8);
set_dirty();
return true;
}
return false;
}
bool FrequencyField::on_encoder(const EncoderEvent delta) {
if (step == 0) { // 'Auto' mode.'
auto ms = RTT2MS(halGetCounterValue());
auto delta_ms = last_ms_ <= ms ? ms - last_ms_ : ms;
last_ms_ = ms;
if (digit_mode_)
set_value(value_ + (delta * digit_step()));
else
set_value(value_ + (delta * step_));
// The goal is to map 'scale' to a range of about 10 to 10M.
// The faster the encoder is rotated, the larger the step.
// Linear doesn't feel right. Hyperbolic felt better.
// To get these magic numbers, I graphed the function until the
// curve shape seemed about right then tested on device.
delta_ms = std::min(145ull, delta_ms) + 5; // Prevent DIV/0
int64_t scale = 200'000'000 / (0.001'55 * std::pow(delta_ms, 5.45)) + 8;
set_value(value() + (delta * scale));
} else {
set_value(value() + (delta * step));
}
return true;
}
@@ -115,10 +146,35 @@ void FrequencyField::on_focus() {
if (on_show_options) {
on_show_options();
}
// Enable long press on "Select".
SwitchesState config;
config[toUType(Switch::Sel)] = true;
set_switches_long_press_config(config);
}
void FrequencyField::on_blur() {
set_switches_long_press_config(initial_switch_config_);
}
rf::Frequency FrequencyField::digit_step() const {
constexpr rf::Frequency steps[] = {
1'000'000'000,
100'000'000,
10'000'000,
1'000'000,
0, // Decimal point position.
100'000,
10'000,
1'000,
100,
};
return digit_ < std::size(steps) ? steps[digit_] : 0;
}
rf::Frequency FrequencyField::clamp_value(rf::Frequency value) {
return range.clip(value);
return range_.clip(value);
}
/* FrequencyKeypadView ***************************************************/

View File

@@ -27,6 +27,7 @@
#include "ui_painter.hpp"
#include "ui_widget.hpp"
#include "irq_controls.hpp"
#include "rf_path.hpp"
#include <cstddef>
@@ -45,6 +46,7 @@ class FrequencyField : public Widget {
using range_t = rf::FrequencyRange;
FrequencyField(Point parent_pos);
~FrequencyField();
rf::Frequency value() const;
@@ -53,18 +55,26 @@ class FrequencyField : public Widget {
void paint(Painter& painter) override;
bool on_key(ui::KeyEvent event) override;
bool on_key(KeyEvent event) override;
bool on_encoder(EncoderEvent delta) override;
bool on_touch(TouchEvent event) override;
void on_focus() override;
void on_blur() override;
private:
const size_t length_;
const range_t range;
const range_t range_;
rf::Frequency value_{0};
rf::Frequency step{25000};
rf::Frequency step_{25000};
uint64_t last_ms_{0};
uint8_t digit_{3};
bool digit_mode_{false};
SwitchesState initial_switch_config_{};
/* Gets the step value for the given digit when in digit_mode. */
rf::Frequency digit_step() const;
rf::Frequency clamp_value(rf::Frequency value);
};
@@ -242,7 +252,6 @@ class FrequencyStepView : public OptionsField {
parent_pos,
5,
{
{" Auto", 0}, /* Faster == larger step. */
{" 10", 10}, /* Fine tuning SSB voice pitch,in HF and QO-100 sat #669 */
{" 50", 50}, /* added 50Hz/10Hz,but we do not increase GUI digit decimal */
{" 100", 100},