mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-07-26 10:38:52 +00:00
Aprs tx gps added, and save config added, path added (#2937)
This commit is contained in:
@@ -68,6 +68,9 @@ void BoundSetting::parse(std::string_view value) {
|
||||
as<bool>() = (parsed != 0);
|
||||
break;
|
||||
}
|
||||
case SettingType::Float:
|
||||
as<float>() = atof(value.data());
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,6 +104,11 @@ void BoundSetting::write(File& file) const {
|
||||
case SettingType::Bool:
|
||||
file.write(as<bool>() ? "1" : "0", 1);
|
||||
break;
|
||||
|
||||
case SettingType::Float: {
|
||||
auto float_str = to_string_decimal(as<float>(), 6);
|
||||
file.write(float_str.c_str(), float_str.length());
|
||||
}
|
||||
}
|
||||
|
||||
file.write("\r\n", 2);
|
||||
|
||||
@@ -52,6 +52,7 @@ class BoundSetting {
|
||||
U8,
|
||||
String,
|
||||
Bool,
|
||||
Float
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -73,6 +74,9 @@ class BoundSetting {
|
||||
BoundSetting(std::string_view name, bool* target)
|
||||
: name_{name}, target_{target}, type_{SettingType::Bool} {}
|
||||
|
||||
BoundSetting(std::string_view name, float* target)
|
||||
: name_{name}, target_{target}, type_{SettingType::Float} {}
|
||||
|
||||
std::string_view name() const { return name_; }
|
||||
void parse(std::string_view value);
|
||||
void write(File& file) const;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "ui_geomap.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
@@ -49,10 +50,24 @@ APRSTXView::~APRSTXView() {
|
||||
|
||||
void APRSTXView::start_tx() {
|
||||
// TODO: Clean up this API to take string_views to avoid allocations.
|
||||
std::string new_payload = payload;
|
||||
|
||||
std::string gps = text_gps_coord.get();
|
||||
std::string token = "?GPS?";
|
||||
size_t pos = 0;
|
||||
while ((pos = new_payload.find(token, pos)) != std::string::npos) {
|
||||
new_payload.replace(pos, token.size(), gps);
|
||||
pos += gps.size();
|
||||
}
|
||||
|
||||
text_payload.set(new_payload);
|
||||
|
||||
std::string path = text_path.get();
|
||||
|
||||
make_aprs_frame(
|
||||
sym_source.to_string().c_str(), num_ssid_source.value(),
|
||||
sym_dest.to_string().c_str(), num_ssid_dest.value(),
|
||||
payload);
|
||||
new_payload, path);
|
||||
|
||||
// uint8_t * bb_data_ptr = shared_memory.bb_data.data;
|
||||
// text_payload.set(to_string_hex_array(bb_data_ptr + 56, 15));
|
||||
@@ -77,6 +92,61 @@ void APRSTXView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
}
|
||||
}
|
||||
|
||||
void APRSTXView::process_coordinates(float lat_, float lon_) {
|
||||
std::string s;
|
||||
|
||||
char ns = lat_ >= 0 ? 'N' : 'S';
|
||||
float lat = (lat_ >= 0) ? lat_ : -lat_;
|
||||
uint32_t lat_d = (uint32_t)lat;
|
||||
uint32_t lat_m = (uint32_t)((lat - lat_d) * 6000.0f + 0.5f);
|
||||
|
||||
if (lat_m >= 6000) {
|
||||
lat_m = 0;
|
||||
lat_d++;
|
||||
}
|
||||
|
||||
s += to_string_dec_uint(lat_d, 2, '0');
|
||||
s += to_string_dec_uint(lat_m / 100, 2, '0');
|
||||
s += ".";
|
||||
s += to_string_dec_uint(lat_m % 100, 2, '0');
|
||||
s += ns;
|
||||
|
||||
s += "/";
|
||||
|
||||
char ew = lon_ >= 0 ? 'E' : 'W';
|
||||
float lon = (lon_ >= 0) ? lon_ : -lon_;
|
||||
uint32_t lon_d = (uint32_t)lon;
|
||||
uint32_t lon_m = (uint32_t)((lon - lon_d) * 6000.0f + 0.5f);
|
||||
|
||||
if (lon_m >= 6000) {
|
||||
lon_m = 0;
|
||||
lon_d++;
|
||||
}
|
||||
|
||||
s += to_string_dec_uint(lon_d, 3, '0');
|
||||
s += to_string_dec_uint(lon_m / 100, 2, '0');
|
||||
s += ".";
|
||||
s += to_string_dec_uint(lon_m % 100, 2, '0');
|
||||
s += ew;
|
||||
text_gps_coord.set(s);
|
||||
}
|
||||
|
||||
void APRSTXView::on_gps(const GPSPosDataMessage* message) {
|
||||
if (manual_gps_mode) {
|
||||
return; // no more update once set manually
|
||||
}
|
||||
if (message->lat < -90.0 || message->lat > 90.0 ||
|
||||
message->lon < -180.0 || message->lon > 180.0) {
|
||||
return;
|
||||
}
|
||||
if (message->lat == 0.0f && message->lon == 0.0f) {
|
||||
return;
|
||||
}
|
||||
last_lat = message->lat;
|
||||
last_lon = message->lon;
|
||||
process_coordinates(message->lat, message->lon);
|
||||
}
|
||||
|
||||
APRSTXView::APRSTXView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_afsk);
|
||||
|
||||
@@ -87,8 +157,33 @@ APRSTXView::APRSTXView(NavigationView& nav) {
|
||||
&num_ssid_dest,
|
||||
&text_payload,
|
||||
&button_set,
|
||||
&text_gps_coord,
|
||||
&button_mangps,
|
||||
&gps_is_manual,
|
||||
&text_path,
|
||||
&button_setpath,
|
||||
&tx_view});
|
||||
|
||||
sym_source.set_value(symsrc);
|
||||
num_ssid_source.set_value(ssidsrc);
|
||||
sym_dest.set_value(symdst);
|
||||
num_ssid_dest.set_value(ssiddst);
|
||||
text_payload.set(payload);
|
||||
text_path.set(path_cache);
|
||||
|
||||
sym_source.on_change = [this](SymField&) {
|
||||
symsrc = sym_source.to_string();
|
||||
};
|
||||
num_ssid_source.on_change = [this](int32_t v) {
|
||||
ssidsrc = v;
|
||||
};
|
||||
sym_dest.on_change = [this](SymField&) {
|
||||
symdst = sym_dest.to_string();
|
||||
};
|
||||
num_ssid_dest.on_change = [this](int32_t v) {
|
||||
ssiddst = v;
|
||||
};
|
||||
|
||||
button_set.on_select = [this, &nav](Button&) {
|
||||
text_prompt(
|
||||
nav,
|
||||
@@ -99,6 +194,17 @@ APRSTXView::APRSTXView(NavigationView& nav) {
|
||||
text_payload.set(s);
|
||||
});
|
||||
};
|
||||
button_setpath.on_select = [this, &nav](Button&) {
|
||||
text_prompt(
|
||||
nav,
|
||||
path_cache,
|
||||
60,
|
||||
ENTER_KEYBOARD_MODE_ALPHA,
|
||||
[this](std::string& s) {
|
||||
text_path.set(s);
|
||||
path_cache = s;
|
||||
});
|
||||
};
|
||||
|
||||
tx_view.on_edit_frequency = [this, &nav]() {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
|
||||
@@ -116,6 +222,23 @@ APRSTXView::APRSTXView(NavigationView& nav) {
|
||||
tx_view.set_transmitting(false);
|
||||
transmitter_model.disable();
|
||||
};
|
||||
|
||||
button_mangps.on_select = [this, &nav](Button&) {
|
||||
nav.push<GeoMapView>(
|
||||
0,
|
||||
GeoPos::alt_unit::METERS,
|
||||
GeoPos::spd_unit::HIDDEN,
|
||||
last_lat,
|
||||
last_lon,
|
||||
[this](int32_t, float lat, float lon, int32_t) {
|
||||
last_lat = lat;
|
||||
last_lon = lon;
|
||||
manual_gps_mode = true;
|
||||
gps_is_manual.set("MANUAL");
|
||||
process_coordinates(lat, lon);
|
||||
});
|
||||
};
|
||||
// process_coordinates(last_lat, last_lon); //don't load last, so won't confuse users
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -50,59 +50,109 @@ class APRSTXView : public View {
|
||||
1750000 /* bandwidth */,
|
||||
AFSK_TX_SAMPLERATE /* sampling rate */
|
||||
};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_aprs", app_settings::Mode::TX};
|
||||
|
||||
std::string symsrc = "";
|
||||
std::string symdst = "";
|
||||
std::string payload{""};
|
||||
std::string path_cache = "";
|
||||
int32_t ssidsrc = 0;
|
||||
int32_t ssiddst = 0;
|
||||
|
||||
bool manual_gps_mode = false;
|
||||
float last_lat = 0.0f;
|
||||
float last_lon = 0.0f;
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_aprs",
|
||||
app_settings::Mode::TX,
|
||||
{{"symsrc"sv, &symsrc},
|
||||
{"symdst"sv, &symdst},
|
||||
{"ssidsrc"sv, &ssidsrc},
|
||||
{"ssiddst"sv, &ssiddst},
|
||||
{"payload"sv, &payload},
|
||||
{"last_lat"sv, &last_lat},
|
||||
{"last_lon"sv, &last_lon},
|
||||
{"path"sv, &path_cache}}};
|
||||
|
||||
void start_tx();
|
||||
void generate_frame();
|
||||
void generate_frame_pos();
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
void on_gps(const GPSPosDataMessage* message);
|
||||
void process_coordinates(float lat, float lon);
|
||||
|
||||
Labels labels{
|
||||
{{UI_POS_X(0), 1 * 16}, "Source: SSID:", Theme::getInstance()->fg_light->foreground}, // 6 alphanum + SSID
|
||||
{{UI_POS_X(0), 2 * 16}, " Dest.: SSID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), 4 * 16}, "Info field:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "Source: SSID:", Theme::getInstance()->fg_light->foreground}, // 6 alphanum + SSID
|
||||
{{UI_POS_X(0), UI_POS_Y(1)}, " Dest.: SSID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(2)}, "Path: (ex.: WIDE1-1,WIDE2-1)", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(6)}, "Info field:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X(0), UI_POS_Y(10)}, "GPS:", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(22), UI_POS_Y(14)}, "Use ?GPS? in the info", Theme::getInstance()->fg_light->foreground},
|
||||
{{UI_POS_X_CENTER(17), UI_POS_Y(15)}, "as a placeholder.", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Text text_path{
|
||||
{UI_POS_X(0), UI_POS_Y(3), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)},
|
||||
"WIDE1-1",
|
||||
};
|
||||
Text gps_is_manual{
|
||||
{UI_POS_X(6), UI_POS_Y(10), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)},
|
||||
"",
|
||||
};
|
||||
|
||||
SymField sym_source{
|
||||
{7 * 8, 1 * 16},
|
||||
{UI_POS_X(7), UI_POS_Y(0)},
|
||||
6,
|
||||
SymField::Type::Alpha};
|
||||
|
||||
NumberField num_ssid_source{
|
||||
{19 * 8, 1 * 16},
|
||||
{UI_POS_X(19), UI_POS_Y(0)},
|
||||
2,
|
||||
{0, 15},
|
||||
1,
|
||||
' '};
|
||||
|
||||
SymField sym_dest{
|
||||
{7 * 8, 2 * 16},
|
||||
{UI_POS_X(7), UI_POS_Y(1)},
|
||||
6,
|
||||
SymField::Type::Alpha};
|
||||
|
||||
NumberField num_ssid_dest{
|
||||
{19 * 8, 2 * 16},
|
||||
{UI_POS_X(19), UI_POS_Y(1)},
|
||||
2,
|
||||
{0, 15},
|
||||
1,
|
||||
' '};
|
||||
|
||||
Text text_payload{
|
||||
{UI_POS_X(0), 5 * 16, screen_width, 16},
|
||||
"-"};
|
||||
{UI_POS_X(0), UI_POS_Y(7), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)},
|
||||
""};
|
||||
Button button_set{
|
||||
{UI_POS_X(0), 6 * 16, 80, 32},
|
||||
{UI_POS_X(0), UI_POS_Y(8), UI_POS_WIDTH(10), UI_POS_HEIGHT(2)},
|
||||
"Set"};
|
||||
|
||||
Text text_gps_coord{
|
||||
{UI_POS_X(0), UI_POS_Y(11), UI_POS_WIDTH(20), UI_POS_HEIGHT(1)},
|
||||
"-"};
|
||||
|
||||
Button button_mangps{
|
||||
{UI_POS_X(0), UI_POS_Y(12), UI_POS_WIDTH(14), UI_POS_HEIGHT(2)},
|
||||
"Manual GPS"};
|
||||
Button button_setpath{
|
||||
{UI_POS_X(0), UI_POS_Y(4), UI_POS_WIDTH(14), UI_POS_HEIGHT(2)},
|
||||
"Set Path"};
|
||||
TransmitterView tx_view{
|
||||
(int16_t)UI_POS_Y_BOTTOM(4),
|
||||
5000,
|
||||
0 // disable setting bandwith, since APRS used fixed 10k bandwidth
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_gps{
|
||||
Message::ID::GPSPosData,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const GPSPosDataMessage*>(p);
|
||||
this->on_gps(message);
|
||||
}};
|
||||
MessageHandlerRegistration message_handler_tx_progress{
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
|
||||
@@ -31,20 +31,67 @@ using namespace ax25;
|
||||
|
||||
namespace aprs {
|
||||
|
||||
void make_aprs_frame(const char* src_address, const uint32_t src_ssid, const char* dest_address, const uint32_t dest_ssid, const std::string& payload) {
|
||||
void make_aprs_frame(const char* src_address, const uint32_t src_ssid, const char* dest_address, const uint32_t dest_ssid, const std::string& payload, const std::string& path) {
|
||||
AX25Frame frame;
|
||||
|
||||
char address[14] = {0};
|
||||
memset(address, ' ', 14);
|
||||
|
||||
memcpy(&address[0], dest_address, 6);
|
||||
memcpy(&address[7], src_address, 6);
|
||||
size_t dest_len = strlen(dest_address);
|
||||
if (dest_len > 6) dest_len = 6;
|
||||
memcpy(&address[0], dest_address, dest_len);
|
||||
size_t src_len = strlen(src_address);
|
||||
if (src_len > 6) src_len = 6;
|
||||
memcpy(&address[7], src_address, src_len);
|
||||
// euquiq: According to ax.25 doc section 2.2.13.x.x and 2.4.1.2
|
||||
// SSID need bits 5.6 set, so later when shifted it will end up being 011xxxx0 (xxxx = SSID number)
|
||||
// Notice that if need to signal usage of AX.25 V2.0, (dest_ssid | 112); (MSb will need to be set at the end)
|
||||
address[6] = (dest_ssid | 48);
|
||||
address[13] = (src_ssid | 48);
|
||||
// SSID need bits 5.6 set, so later when shifted it will end up being 011xxxx0 (xxxx = SSID number)
|
||||
// Notice that if need to signal usage of AX.25 V2.0, (dest_ssid | 112); (MSb will need to be set at the end)
|
||||
address[6] = (dest_ssid | 0x30);
|
||||
address[13] = (src_ssid | 0x30);
|
||||
|
||||
frame.make_ui_frame(address, 0x03, protocol_id_t::NO_LAYER3, payload);
|
||||
// fix path ssid bits. the result will be the same as above
|
||||
std::string fixed_path = "";
|
||||
|
||||
const char* p = path.c_str();
|
||||
|
||||
while (*p) {
|
||||
while (*p == ' ') p++;
|
||||
if (!*p) break;
|
||||
|
||||
char call[6] = {' ', ' ', ' ', ' ', ' ', ' '};
|
||||
int idx = 0;
|
||||
|
||||
while (*p && *p != '-' && *p != ',') {
|
||||
if (*p != ' ') {
|
||||
if (idx < 6) {
|
||||
char c = *p;
|
||||
if (c >= 'a' && c <= 'z') c -= 32;
|
||||
call[idx++] = c;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
int ssid = 0;
|
||||
if (*p == '-') {
|
||||
p++;
|
||||
while (*p == ' ') p++;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
ssid = ssid * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssid >= 0 && ssid <= 15) {
|
||||
for (int i = 0; i < 6; i++) fixed_path += call[i];
|
||||
fixed_path += (char)(ssid | 0x30);
|
||||
}
|
||||
|
||||
while (*p && *p != ',') p++;
|
||||
if (*p == ',') p++;
|
||||
}
|
||||
|
||||
frame.make_ui_frame(address, 0x03, protocol_id_t::NO_LAYER3, payload, fixed_path);
|
||||
}
|
||||
|
||||
} /* namespace aprs */
|
||||
|
||||
@@ -33,7 +33,8 @@ void make_aprs_frame(
|
||||
const uint32_t src_ssid,
|
||||
const char* dest_address,
|
||||
const uint32_t dest_ssid,
|
||||
const std::string& payload);
|
||||
const std::string& payload,
|
||||
const std::string& path = "");
|
||||
|
||||
} /* namespace aprs */
|
||||
|
||||
|
||||
@@ -26,13 +26,16 @@
|
||||
|
||||
namespace ax25 {
|
||||
|
||||
void AX25Frame::make_extended_field(char* const data, size_t length) {
|
||||
void AX25Frame::make_extended_field(char* const data, size_t length, bool is_last) {
|
||||
size_t i = 0;
|
||||
|
||||
for (i = 0; i < length - 1; i++)
|
||||
add_data(data[i] << 1);
|
||||
|
||||
add_data((data[i] << 1) | 1);
|
||||
if (is_last)
|
||||
add_data((data[i] << 1) | 1);
|
||||
else
|
||||
add_data((data[i] << 1));
|
||||
}
|
||||
|
||||
void AX25Frame::NRZI_add_bit(const uint32_t bit) {
|
||||
@@ -92,7 +95,7 @@ void AX25Frame::add_checksum() {
|
||||
add_byte(checksum >> 8, false, false);
|
||||
}
|
||||
|
||||
void AX25Frame::make_ui_frame(char* const address, const uint8_t control, const uint8_t protocol, const std::string& info) {
|
||||
void AX25Frame::make_ui_frame(char* const address, const uint8_t control, const uint8_t protocol, const std::string& info, const std::string& path) {
|
||||
size_t i;
|
||||
|
||||
bb_data_ptr = (uint16_t*)shared_memory.bb_data.data;
|
||||
@@ -103,22 +106,27 @@ void AX25Frame::make_ui_frame(char* const address, const uint8_t control, const
|
||||
ones_counter = 0;
|
||||
crc_ccitt.reset();
|
||||
|
||||
add_flag();
|
||||
add_flag();
|
||||
add_flag();
|
||||
add_flag();
|
||||
add_flag(); // 0x73
|
||||
add_flag(); // 0x73
|
||||
add_flag(); // 0x73
|
||||
add_flag(); // 0x73
|
||||
|
||||
make_extended_field(address, 14);
|
||||
add_data(control);
|
||||
add_data(protocol);
|
||||
// path must not contain the - character! just the callsign and SSID next to each other
|
||||
bool has_path = (path.size() > 0 && path.size() <= 63 && path.size() % 7 == 0);
|
||||
make_extended_field(address, 14, !has_path);
|
||||
if (has_path) {
|
||||
make_extended_field(const_cast<char*>(path.data()), path.size(), true);
|
||||
}
|
||||
add_data(control); // 0x03
|
||||
add_data(protocol); // 0xf0
|
||||
|
||||
for (i = 0; i < info.size(); i++)
|
||||
add_data(info[i]);
|
||||
|
||||
add_checksum();
|
||||
add_checksum(); // fcs
|
||||
|
||||
add_flag();
|
||||
add_flag();
|
||||
add_flag(); // 0x73
|
||||
add_flag(); // 0x73
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
@@ -43,11 +43,11 @@ enum protocol_id_t {
|
||||
|
||||
class AX25Frame {
|
||||
public:
|
||||
void make_ui_frame(char* const address, const uint8_t control, const uint8_t protocol, const std::string& info);
|
||||
void make_ui_frame(char* const address, const uint8_t control, const uint8_t protocol, const std::string& info, const std::string& path = "");
|
||||
|
||||
private:
|
||||
void NRZI_add_bit(const uint32_t bit);
|
||||
void make_extended_field(char* const data, size_t length);
|
||||
void make_extended_field(char* const data, size_t length, bool is_last = false);
|
||||
void add_byte(uint8_t byte, bool is_flag, bool is_data);
|
||||
void add_data(uint8_t byte);
|
||||
void add_checksum();
|
||||
|
||||
@@ -103,8 +103,10 @@ class APRSPacket {
|
||||
std::string get_digipeaters_formatted() {
|
||||
uint8_t position = DIGIPEATER_START;
|
||||
bool has_more = parse_address(SOURCE_START, REPEATER);
|
||||
|
||||
std::string repeaters = "";
|
||||
if (!has_more) {
|
||||
return "";
|
||||
}
|
||||
std::string repeaters = ",";
|
||||
while (has_more) {
|
||||
has_more = parse_address(position, REPEATER);
|
||||
repeaters += std::string(address_buffer);
|
||||
@@ -112,7 +114,7 @@ class APRSPacket {
|
||||
position += ADDRESS_SIZE;
|
||||
|
||||
if (has_more) {
|
||||
repeaters += ">";
|
||||
repeaters += ",";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +148,8 @@ class APRSPacket {
|
||||
}
|
||||
|
||||
std::string get_stream_text() {
|
||||
std::string stream = get_source_formatted() + ">" + get_destination_formatted() + ";" + get_digipeaters_formatted() + ";" + get_information_text_formatted();
|
||||
|
||||
// get_digipeaters_formatted will add the "," to the beginning if there are digipeaters
|
||||
std::string stream = get_source_formatted() + ">" + get_destination_formatted() + get_digipeaters_formatted() + ":" + get_information_text_formatted();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
@@ -384,6 +384,10 @@ void Text::set(std::string_view value) {
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
std::string Text::get() {
|
||||
return text;
|
||||
}
|
||||
|
||||
void Text::getAccessibilityText(std::string& result) {
|
||||
result = text;
|
||||
}
|
||||
|
||||
@@ -217,6 +217,7 @@ class Text : public Widget {
|
||||
Text(Rect parent_rect);
|
||||
|
||||
void set(std::string_view value);
|
||||
std::string get();
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void getAccessibilityText(std::string& result) override;
|
||||
|
||||
Reference in New Issue
Block a user