mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-24 06:49:24 -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_alphanum.cpp
|
||||||
ui/ui_audio.cpp
|
ui/ui_audio.cpp
|
||||||
ui/ui_channel.cpp
|
ui/ui_channel.cpp
|
||||||
|
ui/ui_font_fixed_5x8.cpp
|
||||||
ui/ui_font_fixed_8x16.cpp
|
ui/ui_font_fixed_8x16.cpp
|
||||||
ui/ui_geomap.cpp
|
ui/ui_geomap.cpp
|
||||||
ui/ui_qrcode.cpp
|
ui/ui_qrcode.cpp
|
||||||
@ -259,6 +260,7 @@ set(CPPSRC
|
|||||||
apps/ui_sonde.cpp
|
apps/ui_sonde.cpp
|
||||||
apps/ui_sstvtx.cpp
|
apps/ui_sstvtx.cpp
|
||||||
# apps/ui_test.cpp
|
# apps/ui_test.cpp
|
||||||
|
apps/ui_text_editor.cpp
|
||||||
apps/ui_tone_search.cpp
|
apps/ui_tone_search.cpp
|
||||||
apps/ui_touch_calibration.cpp
|
apps/ui_touch_calibration.cpp
|
||||||
apps/ui_touchtunes.cpp
|
apps/ui_touchtunes.cpp
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
{"1750k", 1750000}, \
|
{"1750k", 1750000}, \
|
||||||
{"2000k", 2000000}, \
|
{"2000k", 2000000}, \
|
||||||
{"2500k", 2500000}, \
|
{"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 {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -76,9 +76,7 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ADSBLogger::log_str(std::string& logline) {
|
void ADSBLogger::log_str(std::string& logline) {
|
||||||
rtc::RTC datetime;
|
log_file.write_entry(logline);
|
||||||
rtcGetTime(&RTCD1, &datetime);
|
|
||||||
log_file.write_entry(datetime, logline);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aircraft Details
|
// Aircraft Details
|
||||||
|
@ -34,10 +34,7 @@ using namespace portapack;
|
|||||||
using namespace modems;
|
using namespace modems;
|
||||||
|
|
||||||
void AFSKLogger::log_raw_data(const std::string& data) {
|
void AFSKLogger::log_raw_data(const std::string& data) {
|
||||||
rtc::RTC datetime;
|
log_file.write_entry(data);
|
||||||
rtcGetTime(&RTCD1, &datetime);
|
|
||||||
|
|
||||||
log_file.write_entry(datetime, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
@ -31,10 +31,7 @@
|
|||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
void APRSLogger::log_raw_data(const std::string& data) {
|
void APRSLogger::log_raw_data(const std::string& data) {
|
||||||
rtc::RTC datetime;
|
log_file.write_entry(data);
|
||||||
rtcGetTime(&RTCD1, &datetime);
|
|
||||||
|
|
||||||
log_file.write_entry(datetime, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
@ -45,22 +45,6 @@ std::string truncate(const fs::path& path, size_t max_length) {
|
|||||||
return ::truncate(path.string(), 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.
|
// Case insensitive path equality on underlying "native" string.
|
||||||
bool iequal(
|
bool iequal(
|
||||||
const fs::path& lhs,
|
const fs::path& lhs,
|
||||||
@ -272,25 +256,27 @@ void FileManBaseView::refresh_list() {
|
|||||||
auto entry_name = truncate(entry.path, 20);
|
auto entry_name = truncate(entry.path, 20);
|
||||||
|
|
||||||
if (entry.is_directory) {
|
if (entry.is_directory) {
|
||||||
menu_view.add_item({entry_name,
|
menu_view.add_item(
|
||||||
ui::Color::yellow(),
|
{entry_name,
|
||||||
&bitmap_icon_dir,
|
ui::Color::yellow(),
|
||||||
[this](KeyEvent key) {
|
&bitmap_icon_dir,
|
||||||
if (on_select_entry)
|
[this](KeyEvent key) {
|
||||||
on_select_entry(key);
|
if (on_select_entry)
|
||||||
}});
|
on_select_entry(key);
|
||||||
|
}});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const auto& assoc = get_assoc(entry.path.extension());
|
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,
|
menu_view.add_item(
|
||||||
assoc.color,
|
{entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||||
assoc.icon,
|
assoc.color,
|
||||||
[this](KeyEvent key) {
|
assoc.icon,
|
||||||
if (on_select_entry)
|
[this](KeyEvent key) {
|
||||||
on_select_entry(key);
|
if (on_select_entry)
|
||||||
}});
|
on_select_entry(key);
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: Should page menu items instead of limiting the number.
|
// HACK: Should page menu items instead of limiting the number.
|
||||||
|
@ -118,7 +118,7 @@ bool MorseView::start_tx() {
|
|||||||
update_tx_duration();
|
update_tx_duration();
|
||||||
|
|
||||||
if (!symbol_count) {
|
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;
|
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");
|
auto open_view = nav.push<FileLoadView>(".WAV");
|
||||||
open_view->on_changed = [this](std::filesystem::path file_path) {
|
open_view->on_changed = [this](std::filesystem::path file_path) {
|
||||||
if (!wav_reader->open(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;
|
return;
|
||||||
}
|
}
|
||||||
if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
load_wav(file_path);
|
load_wav(file_path);
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#include "ui_widget.hpp"
|
#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_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
|
// 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
|
#define FREQMAN_MAX_PER_FILE_STR "115" // STRING OF FREQMAN_MAX_PER_FILE
|
||||||
|
|
||||||
|
@ -20,9 +20,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "log_file.hpp"
|
#include "log_file.hpp"
|
||||||
|
|
||||||
#include "string_format.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) {
|
Optional<File::Error> LogFile::write_entry(const rtc::RTC& datetime, const std::string& entry) {
|
||||||
std::string timestamp = to_string_timestamp(datetime);
|
std::string timestamp = to_string_timestamp(datetime);
|
||||||
return write_line(timestamp + " " + entry);
|
return write_line(timestamp + " " + entry);
|
||||||
|
@ -25,10 +25,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
|
#include "rtc_time.hpp"
|
||||||
#include "lpc43xx_cpp.hpp"
|
|
||||||
|
|
||||||
using namespace lpc43xx;
|
|
||||||
|
|
||||||
#define LOG_ROOT_DIR "LOGS"
|
#define LOG_ROOT_DIR "LOGS"
|
||||||
|
|
||||||
@ -42,6 +39,7 @@ class LogFile {
|
|||||||
return file.append(filename);
|
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);
|
Optional<File::Error> write_entry(const rtc::RTC& datetime, const std::string& entry);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -29,4 +29,15 @@ void on_tick_second() {
|
|||||||
signal_tick_second.emit();
|
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 */
|
} /* namespace rtc_time */
|
||||||
|
@ -24,12 +24,21 @@
|
|||||||
|
|
||||||
#include "signal.hpp"
|
#include "signal.hpp"
|
||||||
|
|
||||||
|
#include "lpc43xx_cpp.hpp"
|
||||||
|
using namespace lpc43xx;
|
||||||
|
|
||||||
namespace rtc_time {
|
namespace rtc_time {
|
||||||
|
|
||||||
extern Signal<> signal_tick_second;
|
extern Signal<> signal_tick_second;
|
||||||
|
|
||||||
void on_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 */
|
} /* namespace rtc_time */
|
||||||
|
|
||||||
#endif /*__RTC_TIME_H__*/
|
#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');
|
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) {
|
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};
|
const uint32_t powers_of_ten[5] = {1, 10, 100, 1000, 10000};
|
||||||
std::string string{""};
|
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_timestamp(const rtc::RTC& value);
|
||||||
std::string to_string_FAT_timestamp(const FATTimestamp& timestamp);
|
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);
|
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
|
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_sonde.hpp"
|
||||||
#include "ui_sstvtx.hpp"
|
#include "ui_sstvtx.hpp"
|
||||||
//#include "ui_test.hpp"
|
//#include "ui_test.hpp"
|
||||||
|
#include "ui_text_editor.hpp"
|
||||||
#include "ui_tone_search.hpp"
|
#include "ui_tone_search.hpp"
|
||||||
#include "ui_touchtunes.hpp"
|
#include "ui_touchtunes.hpp"
|
||||||
#include "ui_playlist.hpp"
|
#include "ui_playlist.hpp"
|
||||||
@ -578,7 +579,7 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
|
|||||||
//{ "Test app", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<TestView>(); } },
|
//{ "Test app", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<TestView>(); } },
|
||||||
{"Freq. manager", ui::Color::green(), &bitmap_icon_freqman, [&nav]() { nav.push<FrequencyManagerView>(); }},
|
{"Freq. manager", ui::Color::green(), &bitmap_icon_freqman, [&nav]() { nav.push<FrequencyManagerView>(); }},
|
||||||
{"File manager", ui::Color::yellow(), &bitmap_icon_dir, [&nav]() { nav.push<FileManagerView>(); }},
|
{"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>(); }},
|
{"Signal gen", ui::Color::green(), &bitmap_icon_cwgen, [&nav]() { nav.push<SigGenView>(); }},
|
||||||
//{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<ToneSearchView>(); } },
|
//{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<ToneSearchView>(); } },
|
||||||
{"Wav viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav]() { nav.push<ViewWavView>(); }},
|
{"Wav viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav]() { nav.push<ViewWavView>(); }},
|
||||||
@ -783,8 +784,11 @@ ModalMessageView::ModalMessageView(
|
|||||||
if (type == INFO) {
|
if (type == INFO) {
|
||||||
add_child(&button_ok);
|
add_child(&button_ok);
|
||||||
|
|
||||||
button_ok.on_select = [&nav](Button&) {
|
button_ok.on_select = [this, &nav](Button&) {
|
||||||
nav.pop();
|
if (on_choice_)
|
||||||
|
on_choice_(true); // Assumes handler will pop.
|
||||||
|
else
|
||||||
|
nav.pop();
|
||||||
};
|
};
|
||||||
} else if (type == YESNO) {
|
} else if (type == YESNO) {
|
||||||
add_children({&button_yes,
|
add_children({&button_yes,
|
||||||
|
@ -35,7 +35,7 @@ class Optional {
|
|||||||
: value_{std::move(value)}, valid_{true} {};
|
: value_{std::move(value)}, valid_{true} {};
|
||||||
|
|
||||||
bool is_valid() const { return valid_; };
|
bool is_valid() const { return valid_; };
|
||||||
T value() const { return value_; };
|
const T& value() const { return value_; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T value_;
|
T value_;
|
||||||
|
Loading…
Reference in New Issue
Block a user