mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-23 14:29:23 -05:00
Add Notepad app (#1010)
* easier 'now', start adding text editor * Adding scrolling to notepad * Better scrolling * Better scrolling, off-by-1 bugs * MVP fit and finish * Add tiny font and use in Notepad * Font tweaking, tiny font cursor * Fix warning * Format changed files --------- Co-authored-by: kallanreed <kallanreed@outlook.com>
This commit is contained in:
parent
693d7864e4
commit
02811b9967
@ -210,6 +210,7 @@ set(CPPSRC
|
||||
ui/ui_alphanum.cpp
|
||||
ui/ui_audio.cpp
|
||||
ui/ui_channel.cpp
|
||||
ui/ui_font_fixed_5x8.cpp
|
||||
ui/ui_font_fixed_8x16.cpp
|
||||
ui/ui_geomap.cpp
|
||||
ui/ui_qrcode.cpp
|
||||
@ -259,6 +260,7 @@ set(CPPSRC
|
||||
apps/ui_sonde.cpp
|
||||
apps/ui_sstvtx.cpp
|
||||
# apps/ui_test.cpp
|
||||
apps/ui_text_editor.cpp
|
||||
apps/ui_tone_search.cpp
|
||||
apps/ui_touch_calibration.cpp
|
||||
apps/ui_touchtunes.cpp
|
||||
|
@ -44,7 +44,7 @@
|
||||
{"1750k", 1750000}, \
|
||||
{"2000k", 2000000}, \
|
||||
{"2500k", 2500000}, \
|
||||
{ "2750k", 2750000 } // That is our max Capture option , to keep using later / 8 decimation (22Mhz sampling ADC)
|
||||
{"2750k", 2750000}, // That is our max Capture option , to keep using later / 8 decimation (22Mhz sampling ADC)
|
||||
|
||||
namespace ui {
|
||||
|
||||
|
@ -76,9 +76,7 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
||||
}
|
||||
|
||||
void ADSBLogger::log_str(std::string& logline) {
|
||||
rtc::RTC datetime;
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
log_file.write_entry(datetime, logline);
|
||||
log_file.write_entry(logline);
|
||||
}
|
||||
|
||||
// Aircraft Details
|
||||
|
@ -34,10 +34,7 @@ using namespace portapack;
|
||||
using namespace modems;
|
||||
|
||||
void AFSKLogger::log_raw_data(const std::string& data) {
|
||||
rtc::RTC datetime;
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
|
||||
log_file.write_entry(datetime, data);
|
||||
log_file.write_entry(data);
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
|
@ -31,10 +31,7 @@
|
||||
using namespace portapack;
|
||||
|
||||
void APRSLogger::log_raw_data(const std::string& data) {
|
||||
rtc::RTC datetime;
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
|
||||
log_file.write_entry(datetime, data);
|
||||
log_file.write_entry(data);
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
|
@ -45,22 +45,6 @@ std::string truncate(const fs::path& path, size_t max_length) {
|
||||
return ::truncate(path.string(), max_length);
|
||||
}
|
||||
|
||||
// Gets a human readable file size string.
|
||||
std::string get_pretty_size(uint32_t file_size) {
|
||||
static const std::string suffix[5] = {"B", "kB", "MB", "GB", "??"};
|
||||
size_t suffix_index = 0;
|
||||
|
||||
while (file_size >= 1024) {
|
||||
file_size /= 1024;
|
||||
suffix_index++;
|
||||
}
|
||||
|
||||
if (suffix_index > 4)
|
||||
suffix_index = 4;
|
||||
|
||||
return to_string_dec_uint(file_size) + suffix[suffix_index];
|
||||
}
|
||||
|
||||
// Case insensitive path equality on underlying "native" string.
|
||||
bool iequal(
|
||||
const fs::path& lhs,
|
||||
@ -272,25 +256,27 @@ void FileManBaseView::refresh_list() {
|
||||
auto entry_name = truncate(entry.path, 20);
|
||||
|
||||
if (entry.is_directory) {
|
||||
menu_view.add_item({entry_name,
|
||||
ui::Color::yellow(),
|
||||
&bitmap_icon_dir,
|
||||
[this](KeyEvent key) {
|
||||
if (on_select_entry)
|
||||
on_select_entry(key);
|
||||
}});
|
||||
menu_view.add_item(
|
||||
{entry_name,
|
||||
ui::Color::yellow(),
|
||||
&bitmap_icon_dir,
|
||||
[this](KeyEvent key) {
|
||||
if (on_select_entry)
|
||||
on_select_entry(key);
|
||||
}});
|
||||
|
||||
} else {
|
||||
const auto& assoc = get_assoc(entry.path.extension());
|
||||
auto size_str = get_pretty_size(entry.size);
|
||||
auto size_str = to_string_file_size(entry.size);
|
||||
|
||||
menu_view.add_item({entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
assoc.color,
|
||||
assoc.icon,
|
||||
[this](KeyEvent key) {
|
||||
if (on_select_entry)
|
||||
on_select_entry(key);
|
||||
}});
|
||||
menu_view.add_item(
|
||||
{entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
assoc.color,
|
||||
assoc.icon,
|
||||
[this](KeyEvent key) {
|
||||
if (on_select_entry)
|
||||
on_select_entry(key);
|
||||
}});
|
||||
}
|
||||
|
||||
// HACK: Should page menu items instead of limiting the number.
|
||||
|
@ -118,7 +118,7 @@ bool MorseView::start_tx() {
|
||||
update_tx_duration();
|
||||
|
||||
if (!symbol_count) {
|
||||
nav_.display_modal("Error", "Message too long,\nmust be < 256 symbols.", INFO, nullptr);
|
||||
nav_.display_modal("Error", "Message too long,\nmust be < 256 symbols.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
322
firmware/application/apps/ui_text_editor.cpp
Normal file
322
firmware/application/apps/ui_text_editor.cpp
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_fileman.hpp"
|
||||
#include "ui_text_editor.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
T mid(const T& val1, const T& val2, const T& val3) {
|
||||
return std::max(val1, std::min(val2, val3));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace ui {
|
||||
|
||||
TextEditorView::TextEditorView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
add_children(
|
||||
{&button_open,
|
||||
&text_position});
|
||||
set_focusable(true);
|
||||
|
||||
// log_.append("LOGS/NOTEPAD.TXT");
|
||||
|
||||
button_open.on_select = [this](Button&) {
|
||||
auto open_view = nav_.push<FileLoadView>(".TXT");
|
||||
open_view->on_changed = [this](std::filesystem::path path) {
|
||||
open_file(path);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
void TextEditorView::on_focus() {
|
||||
refresh_ui();
|
||||
}
|
||||
|
||||
void TextEditorView::paint(Painter& painter) {
|
||||
auto first_line = paint_state_.first_line;
|
||||
auto first_col = paint_state_.first_col;
|
||||
|
||||
if (!paint_state_.has_file)
|
||||
return;
|
||||
|
||||
if (cursor_.line < first_line)
|
||||
first_line = cursor_.line;
|
||||
else if (cursor_.line >= first_line + max_line)
|
||||
first_line = cursor_.line - max_line + 1;
|
||||
|
||||
if (cursor_.col < first_col)
|
||||
first_col = cursor_.col;
|
||||
if (cursor_.col >= first_col + max_col)
|
||||
first_col = cursor_.col - max_col + 1;
|
||||
|
||||
if (first_line != paint_state_.first_line ||
|
||||
first_col != paint_state_.first_col) {
|
||||
paint_state_.first_line = first_line;
|
||||
paint_state_.first_col = first_col;
|
||||
paint_state_.redraw_text = true;
|
||||
}
|
||||
|
||||
if (paint_state_.redraw_text) {
|
||||
paint_text(painter, first_line, first_col);
|
||||
paint_state_.redraw_text = false;
|
||||
}
|
||||
|
||||
paint_cursor(painter);
|
||||
}
|
||||
|
||||
bool TextEditorView::on_key(const KeyEvent key) {
|
||||
int16_t delta_col = 0;
|
||||
int16_t delta_line = 0;
|
||||
|
||||
if (key == KeyEvent::Left)
|
||||
delta_col = -1;
|
||||
else if (key == KeyEvent::Right)
|
||||
delta_col = 1;
|
||||
else if (key == KeyEvent::Up)
|
||||
delta_line = -1;
|
||||
else if (key == KeyEvent::Down)
|
||||
delta_line = 1;
|
||||
/* else if (key == KeyEvent::Select)
|
||||
; // TODO: Edit/Menu */
|
||||
|
||||
// Always allow cursor direction to be updated.
|
||||
cursor_.dir = delta_col != 0 ? ScrollDirection::Horizontal : ScrollDirection::Vertical;
|
||||
auto updated = apply_scrolling_constraints(delta_line, delta_col);
|
||||
|
||||
if (updated)
|
||||
refresh_ui();
|
||||
return updated;
|
||||
}
|
||||
|
||||
bool TextEditorView::on_encoder(EncoderEvent delta) {
|
||||
bool updated = false;
|
||||
|
||||
if (cursor_.dir == ScrollDirection::Horizontal)
|
||||
updated = apply_scrolling_constraints(0, delta);
|
||||
else
|
||||
updated = apply_scrolling_constraints(delta, 0);
|
||||
|
||||
if (updated)
|
||||
refresh_ui();
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
bool TextEditorView::apply_scrolling_constraints(int16_t delta_line, int16_t delta_col) {
|
||||
int32_t new_line = cursor_.line + delta_line;
|
||||
int32_t new_col = cursor_.col + delta_col;
|
||||
|
||||
auto new_line_length = info_.line_length(new_line);
|
||||
|
||||
if (new_col < 0)
|
||||
--new_line;
|
||||
else if (new_col > new_line_length && delta_line == 0) {
|
||||
// Only want to wrap if moving horizontally.
|
||||
new_col = 0;
|
||||
++new_line;
|
||||
}
|
||||
|
||||
if (new_line < 0 || (uint32_t)new_line >= info_.line_count())
|
||||
return false;
|
||||
|
||||
new_line_length = info_.line_length(new_line);
|
||||
|
||||
// TODO: don't wrap with encoder?
|
||||
// Wrap or clamp column.
|
||||
if (new_line_length == 0)
|
||||
new_col = 0;
|
||||
else if (new_col > new_line_length || new_col < 0)
|
||||
new_col = new_line_length;
|
||||
|
||||
cursor_.line = new_line;
|
||||
cursor_.col = new_col;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextEditorView::refresh_ui() {
|
||||
if (paint_state_.has_file) {
|
||||
text_position.set(
|
||||
to_string_dec_uint(cursor_.col + 1) + ":" +
|
||||
to_string_dec_uint(cursor_.line + 1) + "/" +
|
||||
to_string_dec_uint(info_.line_count()) +
|
||||
(info_.truncated ? "*" : "") +
|
||||
" Size: " +
|
||||
to_string_file_size(info_.size));
|
||||
focus();
|
||||
} else {
|
||||
button_open.focus();
|
||||
}
|
||||
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void TextEditorView::refresh_file_info() {
|
||||
constexpr size_t buffer_size = 128;
|
||||
char buffer[buffer_size];
|
||||
uint32_t base_offset = 0;
|
||||
|
||||
file_.seek(0);
|
||||
info_.newlines.clear();
|
||||
info_.line_ending = LineEnding::LF;
|
||||
info_.size = file_.size();
|
||||
info_.truncated = false;
|
||||
|
||||
while (true) {
|
||||
auto result = file_.read(buffer, buffer_size);
|
||||
if (result.is_error())
|
||||
break; // TODO: report error?
|
||||
|
||||
// TODO: CRLF state machine for cross block.
|
||||
for (uint32_t i = 0; i < result.value(); ++i) {
|
||||
switch (buffer[i]) {
|
||||
case '\n':
|
||||
info_.newlines.push_back(base_offset + i);
|
||||
}
|
||||
}
|
||||
|
||||
base_offset += result.value();
|
||||
|
||||
// Fake a newline at the end for consistency.
|
||||
// Could check if there already is a trailing newline, but it doesn't hurt.
|
||||
if (result.value() < buffer_size) {
|
||||
info_.newlines.push_back(base_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
// HACK HACK: only show first 1000 lines for now.
|
||||
if (info_.newlines.size() >= 1000) {
|
||||
info_.truncated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
refresh_ui();
|
||||
}
|
||||
|
||||
void TextEditorView::open_file(const fs::path& path) {
|
||||
// TODO: need a temp backing file for edits.
|
||||
|
||||
auto result = file_.open(path);
|
||||
paint_state_.has_file = !result.is_valid(); /* Has an error. */
|
||||
|
||||
if (paint_state_.has_file) {
|
||||
refresh_file_info();
|
||||
paint_state_.first_line = 0;
|
||||
paint_state_.first_col = 0;
|
||||
cursor_.line = 0;
|
||||
cursor_.col = 0;
|
||||
} else {
|
||||
nav_.display_modal("Read Error", "Cannot open file:\n" + result.value().what());
|
||||
paint_state_.has_file = false;
|
||||
}
|
||||
|
||||
paint_state_.redraw_text = true;
|
||||
refresh_ui();
|
||||
}
|
||||
|
||||
std::string TextEditorView::read(uint32_t offset, uint32_t length) {
|
||||
if (offset >= info_.size)
|
||||
return {"[BAD OFFSET]"};
|
||||
|
||||
std::string buffer(length + 1, '\0');
|
||||
file_.seek(offset);
|
||||
|
||||
auto result = file_.read(&buffer[0], length);
|
||||
if (result.is_ok())
|
||||
/* resize? */;
|
||||
else
|
||||
return result.error().what();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void TextEditorView::paint_text(Painter& painter, uint32_t line, uint16_t col) {
|
||||
// TODO: A line cache would use more memory but save a lot of IO.
|
||||
// Only the new lines/characters would need to be refetched.
|
||||
|
||||
auto r = screen_rect();
|
||||
auto& lines = info_.newlines;
|
||||
auto line_start = info_.line_start(line);
|
||||
|
||||
// Draw the lines from the file
|
||||
for (uint32_t i = 0; i < max_line && i < lines.size(); ++i) {
|
||||
auto line_end = lines[line + i];
|
||||
int32_t read_length = max_col;
|
||||
|
||||
// Don't read past end of the line.
|
||||
if (line_start + col + (uint32_t)read_length > line_end)
|
||||
read_length = line_end - col - line_start;
|
||||
|
||||
if (read_length > 0)
|
||||
painter.draw_string(
|
||||
{0, r.location().y() + (int)i * char_height},
|
||||
style_default, read(line_start + col, read_length));
|
||||
|
||||
// Erase empty line sectons.
|
||||
if (read_length >= 0) {
|
||||
int32_t clear_width = max_col - read_length;
|
||||
if (clear_width > 0)
|
||||
painter.fill_rectangle(
|
||||
{(max_col - clear_width) * char_width,
|
||||
r.location().y() + (int)i * char_height,
|
||||
clear_width * char_width, char_height},
|
||||
style_default.background);
|
||||
}
|
||||
|
||||
line_start = lines[line + i] + 1 /* newline */;
|
||||
}
|
||||
}
|
||||
|
||||
void TextEditorView::paint_cursor(Painter& painter) {
|
||||
auto draw_cursor = [this, &painter](uint32_t line, uint16_t col, Color c) {
|
||||
auto r = screen_rect();
|
||||
line = line - paint_state_.first_line;
|
||||
col = col - paint_state_.first_col;
|
||||
|
||||
painter.draw_rectangle(
|
||||
{(int)col * char_width - 1,
|
||||
r.location().y() + (int)line * char_height,
|
||||
char_width + 1, char_height},
|
||||
c);
|
||||
};
|
||||
|
||||
// TOOD: bug where cursor doesn't clear at EOF.
|
||||
// TODO: XOR cursor?
|
||||
|
||||
// Clear old cursor.
|
||||
draw_cursor(paint_state_.line, paint_state_.col, style_default.background);
|
||||
draw_cursor(cursor_.line, cursor_.col, style_default.foreground);
|
||||
paint_state_.line = cursor_.line;
|
||||
paint_state_.col = cursor_.col;
|
||||
}
|
||||
|
||||
uint16_t TextEditorView::line_length() const {
|
||||
return info_.line_length(cursor_.line);
|
||||
}
|
||||
|
||||
} // namespace ui
|
170
firmware/application/apps/ui_text_editor.hpp
Normal file
170
firmware/application/apps/ui_text_editor.hpp
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_TEXT_EDITOR_H__
|
||||
#define __UI_TEXT_EDITOR_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_font_fixed_5x8.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
//#include "ui_textentry.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "log_file.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ui {
|
||||
|
||||
enum class LineEnding : uint8_t {
|
||||
LF,
|
||||
CRLF
|
||||
};
|
||||
|
||||
enum class ScrollDirection : uint8_t {
|
||||
Vertical,
|
||||
Horizontal
|
||||
};
|
||||
|
||||
// TODO: RAM is _very_ limited. Need to
|
||||
// rework this to not store every line.
|
||||
// Should be able to get away with only
|
||||
// abount one screen of lines so long as
|
||||
// you can't scroll more than one screen
|
||||
// at a time.
|
||||
struct FileInfo {
|
||||
/* Offsets of newlines. */
|
||||
std::vector<uint32_t> newlines;
|
||||
LineEnding line_ending;
|
||||
File::Size size;
|
||||
bool truncated;
|
||||
|
||||
uint32_t line_count() const {
|
||||
return newlines.size();
|
||||
}
|
||||
|
||||
uint32_t line_start(uint32_t line) const {
|
||||
return line == 0 ? 0 : (newlines[line - 1] + 1);
|
||||
}
|
||||
|
||||
uint16_t line_length(uint32_t line) const {
|
||||
if (line >= line_count())
|
||||
return 0;
|
||||
|
||||
auto start = line_start(line);
|
||||
auto end = newlines[line];
|
||||
return end - start;
|
||||
}
|
||||
};
|
||||
|
||||
/*class TextViewer : public Widget {
|
||||
};*/
|
||||
|
||||
class TextEditorView : public View {
|
||||
public:
|
||||
TextEditorView(NavigationView& nav);
|
||||
// TextEditorView(NavigationView& nav, const std::filesystem::path& path);
|
||||
|
||||
std::string title() const override {
|
||||
return "Notepad";
|
||||
};
|
||||
|
||||
void on_focus() override;
|
||||
void paint(Painter& painter) override;
|
||||
bool on_key(KeyEvent delta) override;
|
||||
bool on_encoder(EncoderEvent delta) override;
|
||||
|
||||
private:
|
||||
static constexpr uint8_t max_line = 32;
|
||||
static constexpr uint8_t max_col = 48;
|
||||
static constexpr int8_t char_width = 5;
|
||||
static constexpr int8_t char_height = 8;
|
||||
|
||||
// TODO: should these be common somewhere?
|
||||
static constexpr Style style_default{
|
||||
.font = font::fixed_5x8,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::white(),
|
||||
};
|
||||
|
||||
/* Returns true if the cursor was updated. */
|
||||
bool apply_scrolling_constraints(
|
||||
int16_t delta_line,
|
||||
int16_t delta_col);
|
||||
|
||||
void refresh_ui();
|
||||
void refresh_file_info();
|
||||
void open_file(const std::filesystem::path& path);
|
||||
std::string read(uint32_t offset, uint32_t length = 30);
|
||||
|
||||
void paint_text(Painter& painter, uint32_t line, uint16_t col);
|
||||
void paint_cursor(Painter& painter);
|
||||
|
||||
// Gets the length of the current line.
|
||||
uint16_t line_length() const;
|
||||
|
||||
NavigationView& nav_;
|
||||
|
||||
File file_{};
|
||||
FileInfo info_{};
|
||||
// LogFile log_{ };
|
||||
|
||||
struct {
|
||||
// Previous cursor state.
|
||||
uint32_t line{};
|
||||
uint16_t col{};
|
||||
|
||||
// Previous draw state.
|
||||
uint32_t first_line{};
|
||||
uint16_t first_col{};
|
||||
bool redraw_text{true};
|
||||
bool has_file{false};
|
||||
} paint_state_{};
|
||||
|
||||
struct {
|
||||
uint32_t line{};
|
||||
uint16_t col{};
|
||||
ScrollDirection dir{ScrollDirection::Vertical};
|
||||
} cursor_{};
|
||||
|
||||
/* 8px grid is 30 wide, 38 tall. */
|
||||
/* 16px font height or 19 rows. */
|
||||
/* Titlebar is 16px tall, so 18 rows left. */
|
||||
/* 240 x 320, (304 with titlebar) */
|
||||
|
||||
// TODO: The scrollable view should be its own widget
|
||||
// otherwise control navigation doesn't work.
|
||||
|
||||
Button button_open{
|
||||
{24 * 8, 34 * 8, 6 * 8, 4 * 8},
|
||||
"Open"};
|
||||
|
||||
Text text_position{
|
||||
{0 * 8, 36 * 8, 24 * 8, 2 * 8},
|
||||
""};
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // __UI_TEXT_EDITOR_H__
|
@ -140,11 +140,11 @@ ViewWavView::ViewWavView(
|
||||
auto open_view = nav.push<FileLoadView>(".WAV");
|
||||
open_view->on_changed = [this](std::filesystem::path file_path) {
|
||||
if (!wav_reader->open(file_path)) {
|
||||
nav_.display_modal("Error", "Couldn't open file.", INFO, nullptr);
|
||||
nav_.display_modal("Error", "Couldn't open file.");
|
||||
return;
|
||||
}
|
||||
if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
|
||||
nav_.display_modal("Error", "Wrong format.\nWav viewer only accepts\n16-bit mono files.", INFO, nullptr);
|
||||
nav_.display_modal("Error", "Wrong format.\nWav viewer only accepts\n16-bit mono files.");
|
||||
return;
|
||||
}
|
||||
load_wav(file_path);
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "ui_widget.hpp"
|
||||
|
||||
#define FREQMAN_DESC_MAX_LEN 24 // This is the number of characters that can be drawn in front of "R: TEXT..." before taking a full screen line
|
||||
#define FREQMAN_MAX_PER_FILE 115 // Maximum of entries we can read. This is a hardware limit \
|
||||
#define FREQMAN_MAX_PER_FILE 115 // Maximum of entries we can read. This is a hardware limit
|
||||
// It was tested and lowered to leave a bit of space to the caller
|
||||
#define FREQMAN_MAX_PER_FILE_STR "115" // STRING OF FREQMAN_MAX_PER_FILE
|
||||
|
||||
|
@ -20,9 +20,12 @@
|
||||
*/
|
||||
|
||||
#include "log_file.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
|
||||
Optional<File::Error> LogFile::write_entry(const std::string& entry) {
|
||||
return write_entry(rtc_time::now(), entry);
|
||||
}
|
||||
|
||||
Optional<File::Error> LogFile::write_entry(const rtc::RTC& datetime, const std::string& entry) {
|
||||
std::string timestamp = to_string_timestamp(datetime);
|
||||
return write_line(timestamp + " " + entry);
|
||||
|
@ -25,10 +25,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "file.hpp"
|
||||
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
|
||||
using namespace lpc43xx;
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
#define LOG_ROOT_DIR "LOGS"
|
||||
|
||||
@ -42,6 +39,7 @@ class LogFile {
|
||||
return file.append(filename);
|
||||
}
|
||||
|
||||
Optional<File::Error> write_entry(const std::string& entry);
|
||||
Optional<File::Error> write_entry(const rtc::RTC& datetime, const std::string& entry);
|
||||
|
||||
private:
|
||||
|
@ -29,4 +29,15 @@ void on_tick_second() {
|
||||
signal_tick_second.emit();
|
||||
}
|
||||
|
||||
rtc::RTC now() {
|
||||
rtc::RTC datetime;
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
return datetime;
|
||||
}
|
||||
|
||||
rtc::RTC now(rtc::RTC& out_datetime) {
|
||||
rtcGetTime(&RTCD1, &out_datetime);
|
||||
return out_datetime;
|
||||
}
|
||||
|
||||
} /* namespace rtc_time */
|
||||
|
@ -24,12 +24,21 @@
|
||||
|
||||
#include "signal.hpp"
|
||||
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
using namespace lpc43xx;
|
||||
|
||||
namespace rtc_time {
|
||||
|
||||
extern Signal<> signal_tick_second;
|
||||
|
||||
void on_tick_second();
|
||||
|
||||
/* Returns the current RTCTime from the RTC. */
|
||||
rtc::RTC now();
|
||||
|
||||
/* Returns the current RTCTime from the RTC. */
|
||||
rtc::RTC now(rtc::RTC& out_datetime);
|
||||
|
||||
} /* namespace rtc_time */
|
||||
|
||||
#endif /*__RTC_TIME_H__*/
|
||||
|
@ -213,6 +213,21 @@ std::string to_string_FAT_timestamp(const FATTimestamp& timestamp) {
|
||||
to_string_dec_uint((timestamp.FAT_time >> 5) & 0x3F, 2, '0');
|
||||
}
|
||||
|
||||
std::string to_string_file_size(uint32_t file_size) {
|
||||
static const std::string suffix[5] = {"B", "kB", "MB", "GB", "??"};
|
||||
size_t suffix_index = 0;
|
||||
|
||||
while (file_size >= 1024) {
|
||||
file_size /= 1024;
|
||||
suffix_index++;
|
||||
}
|
||||
|
||||
if (suffix_index > 4)
|
||||
suffix_index = 4;
|
||||
|
||||
return to_string_dec_uint(file_size) + suffix[suffix_index];
|
||||
}
|
||||
|
||||
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision) {
|
||||
const uint32_t powers_of_ten[5] = {1, 10, 100, 1000, 10000};
|
||||
std::string string{""};
|
||||
|
@ -56,6 +56,9 @@ std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format =
|
||||
std::string to_string_timestamp(const rtc::RTC& value);
|
||||
std::string to_string_FAT_timestamp(const FATTimestamp& timestamp);
|
||||
|
||||
// Gets a human readable file size string.
|
||||
std::string to_string_file_size(uint32_t file_size);
|
||||
|
||||
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision);
|
||||
double get_decimals(double num, int16_t mult, bool round = false); // euquiq added
|
||||
|
||||
|
710
firmware/application/ui/ui_font_fixed_5x8.cpp
Normal file
710
firmware/application/ui/ui_font_fixed_5x8.cpp
Normal file
@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_font_fixed_5x8.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
namespace font {
|
||||
|
||||
namespace {
|
||||
|
||||
const uint8_t fixed_5x8_glyph_data[] = {
|
||||
|
||||
// Index: 0 (0x00) Char: 0x0020 (' ')
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
// Index: 1 (0x01) Char: 0x0021 ('!')
|
||||
0x80,
|
||||
0x10,
|
||||
0x42,
|
||||
0x00,
|
||||
0x01,
|
||||
|
||||
// Index: 2 (0x02) Char: 0x0022 ('"')
|
||||
0x40,
|
||||
0x29,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
// Index: 3 (0x03) Char: 0x0023 ('#')
|
||||
0x00,
|
||||
0xA8,
|
||||
0xA7,
|
||||
0x9E,
|
||||
0x02,
|
||||
|
||||
// Index: 4 (0x04) Char: 0x0024 ('$')
|
||||
0x80,
|
||||
0x38,
|
||||
0x83,
|
||||
0x1C,
|
||||
0x01,
|
||||
|
||||
// Index: 5 (0x05) Char: 0x0025 ('%')
|
||||
0x00,
|
||||
0x80,
|
||||
0x44,
|
||||
0x44,
|
||||
0x02,
|
||||
|
||||
// Index: 6 (0x06) Char: 0x0026 ('&')
|
||||
0x40,
|
||||
0x94,
|
||||
0xA1,
|
||||
0xCA,
|
||||
0x02,
|
||||
|
||||
// Index: 7 (0x07) Char: 0x0027 (''')
|
||||
0x80,
|
||||
0x10,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
// Index: 8 (0x08) Char: 0x0028 ('(')
|
||||
0x80,
|
||||
0x08,
|
||||
0x21,
|
||||
0x04,
|
||||
0x01,
|
||||
|
||||
// Index: 9 (0x09) Char: 0x0029 (')')
|
||||
0x40,
|
||||
0x10,
|
||||
0x42,
|
||||
0x88,
|
||||
0x00,
|
||||
|
||||
// Index: 10 (0x0A) Char: 0x002A ('*')
|
||||
0x00,
|
||||
0x28,
|
||||
0xE2,
|
||||
0x88,
|
||||
0x02,
|
||||
|
||||
// Index: 11 (0x0B) Char: 0x002B ('+')
|
||||
0x00,
|
||||
0x00,
|
||||
0xE2,
|
||||
0x08,
|
||||
0x00,
|
||||
|
||||
// Index: 12 (0x0C) Char: 0x002C (',')
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x88,
|
||||
0x00,
|
||||
|
||||
// Index: 13 (0x0D) Char: 0x002D ('-')
|
||||
0x00,
|
||||
0x00,
|
||||
0xE0,
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
// Index: 14 (0x0E) Char: 0x002E ('.')
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x80,
|
||||
0x00,
|
||||
|
||||
// Index: 15 (0x0F) Char: 0x002F ('/')
|
||||
0x00,
|
||||
0x21,
|
||||
0x42,
|
||||
0x84,
|
||||
0x00,
|
||||
|
||||
// Index: 16 (0x10) Char: 0x0030 ('0')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0xB6,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 17 (0x11) Char: 0x0031 ('1')
|
||||
0x80,
|
||||
0x18,
|
||||
0x42,
|
||||
0x88,
|
||||
0x03,
|
||||
|
||||
// Index: 18 (0x12) Char: 0x0032 ('2')
|
||||
0xC0,
|
||||
0x24,
|
||||
0x64,
|
||||
0xC2,
|
||||
0x03,
|
||||
|
||||
// Index: 19 (0x13) Char: 0x0033 ('3')
|
||||
0xC0,
|
||||
0x24,
|
||||
0x82,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 20 (0x14) Char: 0x0034 ('4')
|
||||
0x00,
|
||||
0x31,
|
||||
0x95,
|
||||
0x1E,
|
||||
0x02,
|
||||
|
||||
// Index: 21 (0x15) Char: 0x0035 ('5')
|
||||
0xE0,
|
||||
0x85,
|
||||
0x83,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 22 (0x16) Char: 0x0036 ('6')
|
||||
0xC0,
|
||||
0x84,
|
||||
0x93,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 23 (0x17) Char: 0x0037 ('7')
|
||||
0xE0,
|
||||
0x21,
|
||||
0x44,
|
||||
0x84,
|
||||
0x00,
|
||||
|
||||
// Index: 24 (0x18) Char: 0x0038 ('8')
|
||||
0xC0,
|
||||
0x24,
|
||||
0x93,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 25 (0x19) Char: 0x0039 ('9')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0xE4,
|
||||
0x90,
|
||||
0x01,
|
||||
|
||||
// Index: 26 (0x1A) Char: 0x003A (':')
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x04,
|
||||
0x00,
|
||||
|
||||
// Index: 27 (0x1B) Char: 0x003B (';')
|
||||
0x00,
|
||||
0x00,
|
||||
0x02,
|
||||
0x88,
|
||||
0x00,
|
||||
|
||||
// Index: 28 (0x1C) Char: 0x003C ('<')
|
||||
0x00,
|
||||
0x10,
|
||||
0x11,
|
||||
0x04,
|
||||
0x01,
|
||||
|
||||
// Index: 29 (0x1D) Char: 0x003D ('=')
|
||||
0x00,
|
||||
0x00,
|
||||
0x07,
|
||||
0x1C,
|
||||
0x00,
|
||||
|
||||
// Index: 30 (0x1E) Char: 0x003E ('>')
|
||||
0x00,
|
||||
0x08,
|
||||
0x82,
|
||||
0x88,
|
||||
0x00,
|
||||
|
||||
// Index: 31 (0x1F) Char: 0x003F ('?')
|
||||
0x80,
|
||||
0x28,
|
||||
0x44,
|
||||
0x00,
|
||||
0x01,
|
||||
|
||||
// Index: 32 (0x20) Char: 0x0040 ('@')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0xD6,
|
||||
0x82,
|
||||
0x01,
|
||||
|
||||
// Index: 33 (0x21) Char: 0x0041 ('A')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0xF4,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 34 (0x22) Char: 0x0042 ('B')
|
||||
0xE0,
|
||||
0xA4,
|
||||
0x93,
|
||||
0xD2,
|
||||
0x01,
|
||||
|
||||
// Index: 35 (0x23) Char: 0x0043 ('C')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0x10,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 36 (0x24) Char: 0x0044 ('D')
|
||||
0xE0,
|
||||
0xA4,
|
||||
0x94,
|
||||
0xD2,
|
||||
0x01,
|
||||
|
||||
// Index: 37 (0x25) Char: 0x0045 ('E')
|
||||
0xE0,
|
||||
0x85,
|
||||
0x13,
|
||||
0xC2,
|
||||
0x03,
|
||||
|
||||
// Index: 38 (0x26) Char: 0x0046 ('F')
|
||||
0xE0,
|
||||
0x85,
|
||||
0x13,
|
||||
0x42,
|
||||
0x00,
|
||||
|
||||
// Index: 39 (0x27) Char: 0x0047 ('G')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0xD0,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 40 (0x28) Char: 0x0048 ('H')
|
||||
0x20,
|
||||
0xA5,
|
||||
0x97,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 41 (0x29) Char: 0x0049 ('I')
|
||||
0xC0,
|
||||
0x11,
|
||||
0x42,
|
||||
0x88,
|
||||
0x03,
|
||||
|
||||
// Index: 42 (0x2A) Char: 0x004A ('J')
|
||||
0xC0,
|
||||
0x21,
|
||||
0x84,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 43 (0x2B) Char: 0x004B ('K')
|
||||
0x20,
|
||||
0x95,
|
||||
0x51,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 44 (0x2C) Char: 0x004C ('L')
|
||||
0x20,
|
||||
0x84,
|
||||
0x10,
|
||||
0xC2,
|
||||
0x01,
|
||||
|
||||
// Index: 45 (0x2D) Char: 0x004D ('M')
|
||||
0xA0,
|
||||
0xBD,
|
||||
0x95,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 46 (0x2E) Char: 0x004E ('N')
|
||||
0x20,
|
||||
0xA5,
|
||||
0xD5,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 47 (0x2F) Char: 0x004F ('O')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0x94,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 48 (0x30) Char: 0x0050 ('P')
|
||||
0xE0,
|
||||
0xA4,
|
||||
0x74,
|
||||
0x42,
|
||||
0x00,
|
||||
|
||||
// Index: 49 (0x31) Char: 0x0051 ('Q')
|
||||
0xC0,
|
||||
0xA4,
|
||||
0x94,
|
||||
0x8A,
|
||||
0x02,
|
||||
|
||||
// Index: 50 (0x32) Char: 0x0052 ('R')
|
||||
0xE0,
|
||||
0xA4,
|
||||
0x74,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 51 (0x33) Char: 0x0053 ('S')
|
||||
0xC0,
|
||||
0x24,
|
||||
0x41,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 52 (0x34) Char: 0x0054 ('T')
|
||||
0xC0,
|
||||
0x11,
|
||||
0x42,
|
||||
0x08,
|
||||
0x01,
|
||||
|
||||
// Index: 53 (0x35) Char: 0x0055 ('U')
|
||||
0x20,
|
||||
0xA5,
|
||||
0x94,
|
||||
0x92,
|
||||
0x03,
|
||||
|
||||
// Index: 54 (0x36) Char: 0x0056 ('V')
|
||||
0x20,
|
||||
0xA5,
|
||||
0x94,
|
||||
0x8A,
|
||||
0x00,
|
||||
|
||||
// Index: 55 (0x37) Char: 0x0057 ('W')
|
||||
0x20,
|
||||
0xA5,
|
||||
0xB4,
|
||||
0x5E,
|
||||
0x01,
|
||||
|
||||
// Index: 56 (0x38) Char: 0x0058 ('X')
|
||||
0x20,
|
||||
0x25,
|
||||
0x63,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 57 (0x39) Char: 0x0059 ('Y')
|
||||
0x20,
|
||||
0xA5,
|
||||
0x64,
|
||||
0x08,
|
||||
0x01,
|
||||
|
||||
// Index: 58 (0x3A) Char: 0x005A ('Z')
|
||||
0xE0,
|
||||
0x21,
|
||||
0x22,
|
||||
0xC2,
|
||||
0x03,
|
||||
|
||||
// Index: 59 (0x3B) Char: 0x005B ('[')
|
||||
0xC0,
|
||||
0x08,
|
||||
0x21,
|
||||
0x84,
|
||||
0x01,
|
||||
|
||||
// Index: 60 (0x3C) Char: 0x005C ('\')
|
||||
0x40,
|
||||
0x08,
|
||||
0x42,
|
||||
0x10,
|
||||
0x02,
|
||||
|
||||
// Index: 61 (0x3D) Char: 0x005D (']')
|
||||
0xC0,
|
||||
0x10,
|
||||
0x42,
|
||||
0x88,
|
||||
0x01,
|
||||
|
||||
// Index: 62 (0x3E) Char: 0x005E ('^')
|
||||
0x00,
|
||||
0x10,
|
||||
0x05,
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
// Index: 63 (0x3F) Char: 0x005F ('_')
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xC0,
|
||||
0x03,
|
||||
|
||||
// Index: 64 (0x40) Char: 0x0060 ('`')
|
||||
0x40,
|
||||
0x10,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
// Index: 65 (0x41) Char: 0x0061 ('a')
|
||||
0x00,
|
||||
0x00,
|
||||
0x83,
|
||||
0x9E,
|
||||
0x03,
|
||||
|
||||
// Index: 66 (0x42) Char: 0x0062 ('b')
|
||||
0x20,
|
||||
0x84,
|
||||
0x93,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 67 (0x43) Char: 0x0063 ('c')
|
||||
0x00,
|
||||
0x00,
|
||||
0x17,
|
||||
0x82,
|
||||
0x03,
|
||||
|
||||
// Index: 68 (0x44) Char: 0x0064 ('d')
|
||||
0x00,
|
||||
0x21,
|
||||
0x97,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 69 (0x45) Char: 0x0065 ('e')
|
||||
0x00,
|
||||
0x00,
|
||||
0xF3,
|
||||
0x82,
|
||||
0x01,
|
||||
|
||||
// Index: 70 (0x46) Char: 0x0066 ('f')
|
||||
0x80,
|
||||
0x89,
|
||||
0x23,
|
||||
0x84,
|
||||
0x00,
|
||||
|
||||
// Index: 71 (0x47) Char: 0x0067 ('g')
|
||||
0x00,
|
||||
0x98,
|
||||
0xE4,
|
||||
0x90,
|
||||
0x01,
|
||||
|
||||
// Index: 72 (0x48) Char: 0x0068 ('h')
|
||||
0x20,
|
||||
0x84,
|
||||
0x93,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 73 (0x49) Char: 0x0069 ('i')
|
||||
0x80,
|
||||
0x00,
|
||||
0x43,
|
||||
0x08,
|
||||
0x02,
|
||||
|
||||
// Index: 74 (0x4A) Char: 0x006A ('j')
|
||||
0x00,
|
||||
0x01,
|
||||
0x86,
|
||||
0x90,
|
||||
0x01,
|
||||
|
||||
// Index: 75 (0x4B) Char: 0x006B ('k')
|
||||
0x40,
|
||||
0x08,
|
||||
0x65,
|
||||
0x94,
|
||||
0x02,
|
||||
|
||||
// Index: 76 (0x4C) Char: 0x006C ('l')
|
||||
0xC0,
|
||||
0x10,
|
||||
0x42,
|
||||
0x08,
|
||||
0x02,
|
||||
|
||||
// Index: 77 (0x4D) Char: 0x006D ('m')
|
||||
0x00,
|
||||
0x80,
|
||||
0xF6,
|
||||
0x56,
|
||||
0x02,
|
||||
|
||||
// Index: 78 (0x4E) Char: 0x006E ('n')
|
||||
0x00,
|
||||
0x80,
|
||||
0x93,
|
||||
0x52,
|
||||
0x02,
|
||||
|
||||
// Index: 79 (0x4F) Char: 0x006F ('o')
|
||||
0x00,
|
||||
0x00,
|
||||
0x93,
|
||||
0x92,
|
||||
0x01,
|
||||
|
||||
// Index: 80 (0x50) Char: 0x0070 ('p')
|
||||
0x00,
|
||||
0x98,
|
||||
0x74,
|
||||
0x42,
|
||||
0x00,
|
||||
|
||||
// Index: 81 (0x51) Char: 0x0071 ('q')
|
||||
0x00,
|
||||
0x98,
|
||||
0xE4,
|
||||
0x10,
|
||||
0x02,
|
||||
|
||||
// Index: 82 (0x52) Char: 0x0072 ('r')
|
||||
0x00,
|
||||
0x00,
|
||||
0x65,
|
||||
0x84,
|
||||
0x00,
|
||||
|
||||
// Index: 83 (0x53) Char: 0x0073 ('s')
|
||||
0x00,
|
||||
0x00,
|
||||
0x66,
|
||||
0x90,
|
||||
0x03,
|
||||
|
||||
// Index: 84 (0x54) Char: 0x0074 ('t')
|
||||
0x80,
|
||||
0x10,
|
||||
0x47,
|
||||
0x08,
|
||||
0x02,
|
||||
|
||||
// Index: 85 (0x55) Char: 0x0075 ('u')
|
||||
0x00,
|
||||
0x80,
|
||||
0x94,
|
||||
0x92,
|
||||
0x03,
|
||||
|
||||
// Index: 86 (0x56) Char: 0x0076 ('v')
|
||||
0x00,
|
||||
0x80,
|
||||
0x94,
|
||||
0x8A,
|
||||
0x00,
|
||||
|
||||
// Index: 87 (0x57) Char: 0x0077 ('w')
|
||||
0x00,
|
||||
0x80,
|
||||
0xB4,
|
||||
0x5E,
|
||||
0x01,
|
||||
|
||||
// Index: 88 (0x58) Char: 0x0078 ('x')
|
||||
0x00,
|
||||
0x00,
|
||||
0x45,
|
||||
0x88,
|
||||
0x02,
|
||||
|
||||
// Index: 89 (0x59) Char: 0x0079 ('y')
|
||||
0x00,
|
||||
0x00,
|
||||
0xE5,
|
||||
0x90,
|
||||
0x01,
|
||||
|
||||
// Index: 90 (0x5A) Char: 0x007A ('z')
|
||||
0x00,
|
||||
0x00,
|
||||
0xC7,
|
||||
0x84,
|
||||
0x03,
|
||||
|
||||
// Index: 91 (0x5B) Char: 0x007B ('{')
|
||||
0x80,
|
||||
0x11,
|
||||
0x41,
|
||||
0x08,
|
||||
0x03,
|
||||
|
||||
// Index: 92 (0x5C) Char: 0x007C ('|')
|
||||
0x80,
|
||||
0x10,
|
||||
0x42,
|
||||
0x08,
|
||||
0x01,
|
||||
|
||||
// Index: 93 (0x5D) Char: 0x007D ('}')
|
||||
0xC0,
|
||||
0x10,
|
||||
0x44,
|
||||
0x88,
|
||||
0x01,
|
||||
|
||||
// Index: 94 (0x5E) Char: 0x007E ('~')
|
||||
0x00,
|
||||
0x00,
|
||||
0x55,
|
||||
0x00,
|
||||
0x00,
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const ui::Font fixed_5x8{
|
||||
5,
|
||||
8,
|
||||
fixed_5x8_glyph_data,
|
||||
0x20,
|
||||
95,
|
||||
};
|
||||
|
||||
} /* namespace font */
|
||||
} /* namespace ui */
|
35
firmware/application/ui/ui_font_fixed_5x8.hpp
Normal file
35
firmware/application/ui/ui_font_fixed_5x8.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_FONT_FIXED_5X8_H__
|
||||
#define __UI_FONT_FIXED_5X8_H__
|
||||
|
||||
#include "ui_text.hpp"
|
||||
|
||||
namespace ui {
|
||||
namespace font {
|
||||
|
||||
extern const ui::Font fixed_5x8;
|
||||
|
||||
} // namespace font
|
||||
} // namespace ui
|
||||
|
||||
#endif /*__UI_FONT_FIXED_5X8_H__*/
|
@ -66,6 +66,7 @@
|
||||
#include "ui_sonde.hpp"
|
||||
#include "ui_sstvtx.hpp"
|
||||
//#include "ui_test.hpp"
|
||||
#include "ui_text_editor.hpp"
|
||||
#include "ui_tone_search.hpp"
|
||||
#include "ui_touchtunes.hpp"
|
||||
#include "ui_playlist.hpp"
|
||||
@ -578,7 +579,7 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
|
||||
//{ "Test app", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<TestView>(); } },
|
||||
{"Freq. manager", ui::Color::green(), &bitmap_icon_freqman, [&nav]() { nav.push<FrequencyManagerView>(); }},
|
||||
{"File manager", ui::Color::yellow(), &bitmap_icon_dir, [&nav]() { nav.push<FileManagerView>(); }},
|
||||
//{ "Notepad", ui::Color::dark_grey(), &bitmap_icon_notepad, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{"Notepad", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<TextEditorView>(); }},
|
||||
{"Signal gen", ui::Color::green(), &bitmap_icon_cwgen, [&nav]() { nav.push<SigGenView>(); }},
|
||||
//{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<ToneSearchView>(); } },
|
||||
{"Wav viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav]() { nav.push<ViewWavView>(); }},
|
||||
@ -783,8 +784,11 @@ ModalMessageView::ModalMessageView(
|
||||
if (type == INFO) {
|
||||
add_child(&button_ok);
|
||||
|
||||
button_ok.on_select = [&nav](Button&) {
|
||||
nav.pop();
|
||||
button_ok.on_select = [this, &nav](Button&) {
|
||||
if (on_choice_)
|
||||
on_choice_(true); // Assumes handler will pop.
|
||||
else
|
||||
nav.pop();
|
||||
};
|
||||
} else if (type == YESNO) {
|
||||
add_children({&button_yes,
|
||||
|
@ -35,7 +35,7 @@ class Optional {
|
||||
: value_{std::move(value)}, valid_{true} {};
|
||||
|
||||
bool is_valid() const { return valid_; };
|
||||
T value() const { return value_; };
|
||||
const T& value() const { return value_; };
|
||||
|
||||
private:
|
||||
T value_;
|
||||
|
Loading…
Reference in New Issue
Block a user