New Morse TX app (#2948)

* morse tx
* global button repeat function improvement
This commit is contained in:
Pezsma
2026-01-30 17:18:13 +01:00
committed by GitHub
parent 106d9b1207
commit e2b642ae25
25 changed files with 1684 additions and 11 deletions
+131
View File
@@ -2338,6 +2338,137 @@ bool NumberField::on_touch(const TouchEvent event) {
return true;
}
/* FloatField ***********************************************************/
FloatField::FloatField(
Point parent_pos,
int length,
range_t range,
float step,
char fill_char,
bool can_loop,
uint8_t precision_)
: Widget{{parent_pos, {8 * length, 16}}},
range{range},
step{step},
length_{length},
fill_char{fill_char},
can_loop{can_loop},
precision{precision_} {
set_focusable(true);
}
float FloatField::value() const {
return value_;
}
void FloatField::getAccessibilityText(std::string& result) {
result = to_string_decimal(value_, precision);
}
void FloatField::getWidgetName(std::string& result) {
result = "FloatField";
}
void FloatField::set_value(float new_value, bool trigger_change) {
const float lo = range.first;
const float hi = range.second;
if (can_loop) {
if (new_value > hi)
new_value = lo;
else if (new_value < lo)
new_value = hi;
}
new_value = clip(new_value, lo, hi);
// set final value if needed
if (new_value != value_) {
value_ = new_value;
if (on_change && trigger_change) on_change(value_);
set_dirty();
}
}
void FloatField::set_range(const float min, const float max) {
range.first = min;
range.second = max;
set_value(value_, false);
}
void FloatField::set_step(const float new_step) {
step = new_step;
}
void FloatField::paint(Painter& painter) {
auto text = to_string_decimal(value_, precision);
const auto paint_style = has_focus() ? style().invert() : style();
// clip to widget size
const auto r = screen_rect();
auto label_r = style().font.size_of(text);
size_t max_chars = (r.width()) / style().font.char_width();
if (label_r.width() > r.width()) {
text = text.substr(0, max_chars);
}
size_t padneeded = max_chars - text.length();
if (padneeded > 0 && fill_char) {
std::string filler(fill_char, padneeded);
text = filler + text;
}
painter.fill_rectangle(r, style().background);
painter.draw_string(
screen_pos(),
paint_style,
text);
}
bool FloatField::on_key(const KeyEvent key) {
if (key == KeyEvent::Select) {
if (on_select) {
on_select(*this);
return true;
} else {
return on_encoder(1);
}
}
return false;
}
bool FloatField::on_encoder(const EncoderEvent delta) {
float old_value = value();
set_value(old_value + ((float)delta * step));
if (on_wrap) {
if ((delta > 0) && (value_ < old_value))
on_wrap(1);
else if ((delta < 0) && (value_ > old_value))
on_wrap(-1);
}
return true;
}
bool FloatField::on_keyboard(const KeyboardEvent key) {
if (key == 10) {
if (on_select) {
on_select(*this);
return true;
}
}
if (key == '+' || key == ' ') {
return on_encoder(1);
}
if (key == '-' || key == 8) {
return on_encoder(-1);
}
return false;
}
bool FloatField::on_touch(const TouchEvent event) {
if (event.type == TouchEvent::Type::Start) {
focus();
}
return true;
}
/* SymField **************************************************************/
SymField::SymField(
@@ -885,6 +885,53 @@ class NumberField : public Widget {
bool can_loop{};
};
class FloatField : public Widget {
public:
std::function<void(FloatField&)> on_select{};
std::function<void(float)> on_change{};
std::function<void(int32_t)> on_wrap{};
using range_t = std::pair<float, float>;
FloatField(Point parent_pos, int length, range_t range, float step, char fill_char, bool can_loop, uint8_t precision_ = 1);
FloatField(Point parent_pos, int length, range_t range, float step, char fill_char)
: FloatField{parent_pos, length, range, step, fill_char, true, 1} {
}
FloatField()
: FloatField{{0, 0}, 1, {0, 1}, 1, ' ', true, 1} {
}
FloatField(const FloatField&) = delete;
FloatField(FloatField&&) = delete;
float value() const;
void set_value(float new_value, bool trigger_change = true);
void set_range(const float min, const float max);
void set_step(const float new_step);
void set_precision(uint8_t precision);
void paint(Painter& painter) override;
bool on_key(const KeyEvent key) override;
bool on_encoder(const EncoderEvent delta) override;
bool on_touch(const TouchEvent event) override;
bool on_keyboard(const KeyboardEvent event) override;
void getAccessibilityText(std::string& result) override;
void getWidgetName(std::string& result) override;
private:
range_t range;
float step;
const int length_;
const char fill_char;
float value_{0};
bool can_loop{};
uint8_t precision = 1;
};
/* A widget that allows for character-by-character editing of its value. */
class SymField : public Widget {
public:
+5 -3
View File
@@ -126,9 +126,11 @@ struct is_flags_type {
template <typename TEnum>
constexpr bool is_flags_type_v = is_flags_type<TEnum>::value;
#define ENABLE_FLAGS_OPERATORS(type) \
template <> \
struct is_flags_type<type> { static constexpr bool value = true; };
#define ENABLE_FLAGS_OPERATORS(type) \
template <> \
struct is_flags_type<type> { \
static constexpr bool value = true; \
};
template <typename TEnum>
constexpr std::enable_if_t<is_flags_type_v<TEnum>, TEnum> operator|(TEnum a, TEnum b) {