mayhem-firmware/firmware/application/apps/ui_text_editor.hpp
Kyle Reed 02811b9967
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>
2023-05-20 08:39:35 +12:00

170 lines
4.3 KiB
C++

/*
* 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__