Implement View Text (#406)

* View text and code cleanup

* Typo fix

* Fixed case generation

* check list fixed

* Horizontal clipping fixed

* Lost letter fixed.

* Cleanup

* Unified implementation (Rotory button support)

* Fixed USB menu issue and RTN button.

* Rotary encoder acceleration implemented

* Do not close file on every line read

* Sliding window implemented. File size limitations practically removed.

* scrollbar implemented

* Cleanup & scroll bar adjustment

* Cleanup

* Smoother scrolling for long lines.

* Minor cleanup
This commit is contained in:
eshifri
2021-07-14 10:46:42 +10:00
committed by GitHub
parent 38a99bca23
commit 64f277152c
8 changed files with 659 additions and 54 deletions
+1
View File
@@ -62,6 +62,7 @@ set(GUI_SRC
view_channels.cpp
view_logical_switches.cpp
view_statistics.cpp
view_text.cpp
menu_screen.cpp
screen_setup.cpp
switch_warn_dialog.cpp
+38 -9
View File
@@ -21,10 +21,38 @@
#include "static.h"
MessageDialog::MessageDialog(Window* parent, const char* title,
const char* message, const char* info,
const int lineHeight,
const WindowFlags windowFlags,
const LcdFlags textFlags) :
const char* message, const char* info) :
Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146})
{
messageWidget = new StaticText(
this,
{0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT},
message, 0, CENTERED);
infoWidget = new StaticText(this,
{0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2,
width(), PAGE_LINE_HEIGHT},
info, 0, CENTERED);
setCloseWhenClickOutside(true);
setFocus();
}
#if defined(HARDWARE_KEYS)
void MessageDialog::onEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(),
event);
if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) {
deleteLater();
}
}
#endif
DynamicMessageDialog::DynamicMessageDialog(
Window* parent, const char* title, std::function<std::string()> textHandler,
const char* message, const int lineHeight,
const LcdFlags textFlags) :
Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146})
{
setWindowFlags(windowFlags);
@@ -34,21 +62,22 @@ MessageDialog::MessageDialog(Window* parent, const char* title,
{0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT},
message, 0, CENTERED);
infoWidget = new StaticText(
infoWidget = new DynamicText(
this,
{0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), lineHeight},
info, 0, textFlags);
textHandler, textFlags);
setCloseWhenClickOutside(true);
setFocus();
}
#if defined(HARDWARE_KEYS)
void MessageDialog::onEvent(event_t event)
void DynamicMessageDialog::onEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(),
event);
if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) {
deleteLater();
}
}
#endif
#endif
+33 -9
View File
@@ -23,23 +23,46 @@
#include "dialog.h"
#include "static.h"
class MessageDialog : public Dialog
class MessageDialog: public Dialog {
public:
MessageDialog(Window * parent, const char * title, const char * message, const char * info = "");
void setInfoText(std::string text)
{
infoWidget->setText(std::move(text));
}
protected:
StaticText * messageWidget;
StaticText * infoWidget;
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "MessageDialog";
}
#endif
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override;
#endif
};
class DynamicMessageDialog : public Dialog
{
public:
MessageDialog(Window* parent, const char* title, const char* message,
const char* info = "", const int lineHeight = PAGE_LINE_HEIGHT,
const WindowFlags windowFlags = 0,
DynamicMessageDialog(Window* parent, const char* title,
std::function<std::string()> textHandler, const char* message = "", const int lineHeight = PAGE_LINE_HEIGHT,
const LcdFlags textFlags = CENTERED);
// Attn.: FONT(XXL) is not supported by MessageDialog
// Attn.: FONT(XXL) is not supported by DynamicMessageDialog
void setInfoText(std::string text) { infoWidget->setText(std::move(text)); }
protected:
StaticText* messageWidget;
StaticText* infoWidget;
LcdFlags textFlags;
DynamicText* infoWidget;
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "MessageDialog"; }
std::string getName() const override { return "DynamicMessageDialog"; }
#endif
#if defined(HARDWARE_KEYS)
@@ -47,4 +70,5 @@ class MessageDialog : public Dialog
#endif
};
#endif // _MESSAGE_DIALOG_H_
+8 -22
View File
@@ -41,26 +41,6 @@ std::string switchWarninglabel(swsrc_t index)
1);
}
class RssiDialog : public MessageDialog
{
public:
RssiDialog(Window* parent, const char* title, const char* message,
const char* info = "", const int lineHeight = PAGE_LINE_HEIGHT,
const WindowFlags windowFlags = 0,
const LcdFlags textFlags = CENTERED) :
MessageDialog(parent, title, message, info, lineHeight, windowFlags,
textFlags)
{
}
virtual void checkEvents()
{
char buf[10];
sprintf(buf, "%d", (int)TELEMETRY_RSSI());
setInfoText(buf);
MessageDialog::checkEvents();
}
};
class ChannelFailsafeBargraph: public Window {
public:
@@ -871,8 +851,14 @@ class ModuleWindow : public FormGroup {
}
else {
moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK;
auto rssiDialog = new RssiDialog(
this, "Range Test", "RSSI:", "", 50, REFRESH_ALWAYS,
auto rssiDialog = new DynamicMessageDialog(
this, "Range Test",
[=]() {
char buf[16];
sprintf(buf, "%d db", (int)TELEMETRY_RSSI());
return std::string(buf);
},
"RSSI:", 50,
DEFAULT_COLOR | CENTERED | FONT(BOLD) | FONT(XL));
rssiDialog->setCloseHandler([this]() {
rangeButton->check(false);
+17 -10
View File
@@ -26,6 +26,7 @@
#include "io/bootloader_flash.h"
#include "standalone_lua.h"
#include "sdcard.h"
#include "view_text.h"
class FileNameEditWindow : public Page
{
@@ -232,15 +233,15 @@ void RadioSdManagerPage::build(FormWindow * window)
if (res != FR_OK || fno.fname[0] == 0)
break; // Break on error or end of dir
if (strlen(fno.fname) > SD_SCREEN_FILE_LENGTH)
if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH)
continue;
if (fno.fname[0] == '.' && fno.fname[1] != '.')
continue; // Ignore hidden files under UNIX, but not ..
if (fno.fattrib & AM_DIR) {
directories.push_back(fno.fname);
directories.push_back((char*)fno.fname);
} else {
files.push_back(fno.fname);
files.push_back((char*)fno.fname);
}
}
@@ -251,7 +252,7 @@ void RadioSdManagerPage::build(FormWindow * window)
for (auto name: directories) {
auto b = new TextButton(window, grid.getLabelSlot(), name, [=]() -> uint8_t {
std::string fullpath = currentPath + "/" + name;
f_chdir(fullpath.c_str());
f_chdir((TCHAR*)fullpath.c_str());
window->clear();
build(window);
return 0;
@@ -303,11 +304,18 @@ void RadioSdManagerPage::build(FormWindow * window)
// else if (isExtensionMatching(ext, BITMAPS_EXT)) {
// // TODO
// }
// else if (!strcasecmp(ext, TEXT_EXT)) {
// menu->addLine(STR_VIEW_TEXT, [=]() {
// // TODO
// });
// }
else if (!strcasecmp(ext, TEXT_EXT)) {
menu->addLine(STR_VIEW_TEXT, [=]() {
static char lfn[FF_MAX_LFN + 1]; // TODO optimize that!
f_getcwd((TCHAR *)lfn, FF_MAX_LFN);
auto textView = new ViewTextWindow(lfn, name);
textView->setCloseHandler([=]() {
//window->clear();
rebuild(window);
});
});
}
if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) {
if (isBootloader(name.data())) {
menu->addLine(STR_FLASH_BOOTLOADER, [=]() {
@@ -378,7 +386,6 @@ void RadioSdManagerPage::build(FormWindow * window)
//window->clear();
rebuild(window);
});
// rebuild(window); });
});
menu->addLine(STR_DELETE_FILE, [=]() {
f_unlink((const TCHAR*)getFullPath(name));
+435
View File
@@ -0,0 +1,435 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#include "view_text.h"
#include "gridlayout.h"
#include "menu.h"
#include "opentx.h"
#include "sdcard.h"
#define CASE_EVT_KEY_NEXT_LINE \
case EVT_ROTARY_RIGHT: \
case EVT_KEY_BREAK(KEY_PGDN)
// case EVT_KEY_BREAK(KEY_DOWN)
#define CASE_EVT_KEY_PREVIOUS_LINE \
case EVT_ROTARY_LEFT: \
case EVT_KEY_BREAK(KEY_PGUP): \
case EVT_KEY_BREAK(KEY_UP)
#define CASE_EVT_START \
case EVT_ENTRY: \
case EVT_KEY_BREAK(KEY_ENTER): \
case EVT_KEY_BREAK(KEY_TELEM)
void ViewTextWindow::extractNameSansExt()
{
uint8_t nameLength;
uint8_t extLength;
const char *ext =
getFileExtension(name.data(), 0, 0, &nameLength, &extLength);
extension = std::string(ext);
if (nameLength > TEXT_FILENAME_MAXLEN) nameLength = TEXT_FILENAME_MAXLEN;
nameLength -= extLength;
name.substr(nameLength);
}
#if READ_FILE_BY_LINE
void ViewTextWindow::buildBody(Window *window)
{
GridLayout grid(window);
grid.spacer();
int i;
// assume average characte is 10 pixels wide, round the string length to tens.
// Font is not fixed width, so this is for the worst case...
const int maxLineLength = int(floor(window->width() / 10 / 10)) * 10 - 2;
window->setFocus();
FIL file;
if (FR_OK !=
f_open(&file, (TCHAR *)fullPath.c_str(), FA_OPEN_EXISTING | FA_READ)) {
return;
}
readCount = 0;
longestLine = 0;
lastLine = false;
for (i = 0; i < TEXT_FILE_MAXSIZE && !lastLine; i++) {
lastLine =
sdReadTextLine(&file, reusableBuffer.viewText.lines[0], maxLineLength);
new StaticText(window, grid.getSlot(), reusableBuffer.viewText.lines[0]);
grid.nextLine();
}
f_close(&file);
window->setInnerWidth((longestLine + 4) * 10);
window->setInnerHeight(grid.getWindowHeight());
}
void ViewTextWindow::checkEvents()
{
if (&body == Window::focusWindow) {
const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING;
coord_t currentPos = body.getScrollPositionY();
coord_t deltaY;
event_t event = getWindowEvent();
if (event == EVT_ROTARY_LEFT || event == EVT_ROTARY_RIGHT) {
deltaY = ROTARY_ENCODER_SPEED() * step;
} else {
deltaY = step;
}
switch (event) {
CASE_EVT_KEY_NEXT_LINE:
currentPos += deltaY;
break;
CASE_EVT_KEY_PREVIOUS_LINE:
currentPos -= deltaY;
break;
default:
Page::onEvent(event);
return;
}
body.setScrollPositionY(currentPos);
}
Page::checkEvents();
}
bool ViewTextWindow::sdReadTextLine(FIL *file, char line[],
const uint8_t maxLineLength)
{
char c;
unsigned int sz;
uint8_t line_length = 0;
uint8_t escape = 0;
char escape_chars[4] = {0};
int current_line = 0;
memclear(line, maxLineLength + 1);
line[line_length++] = 0x20;
for (uint8_t i = 0; i < maxLineLength && readCount < (int)TEXT_FILE_MAXSIZE;
++i) {
if ((f_read(file, &c, 1, &sz) != FR_OK || !sz) &&
line_length < maxLineLength) {
return true;
}
readCount++;
if (c == '\n') {
++current_line;
escape = 0;
return false;
} else if (c != '\r') {
if (c == '\\' && escape == 0) {
escape = 1;
continue;
} else if (c != '\\' && escape > 0 && escape < sizeof(escape_chars)) {
escape_chars[escape - 1] = c;
if (escape == 2 && !strncmp(escape_chars, "up", 2)) {
c = CHAR_UP;
} else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) {
c = CHAR_DOWN;
} else if (escape == 3) {
int val = atoi(escape_chars);
if (val >= 200 && val < 225) {
c = '\200' + val - 200;
}
} else {
escape++;
continue;
}
} else if (c == '~') {
c = 'z' + 1;
} else if (c == '\t') {
c = 0x1D; // tab
}
escape = 0;
line[line_length++] = c;
if (longestLine < line_length) longestLine = line_length;
}
}
if (c != '\n') {
current_line += 1;
return false;
}
return false;
}
#else
void ViewTextWindow::buildBody(Window *window)
{
GridLayout grid(window);
grid.spacer();
int i;
// assume average characte is 10 pixels wide, round the string length to tens.
// Font is not fixed width, so this is for the worst case...
maxLineLength = int(floor(window->width() / 10 / 10)) * 10 - 2;
maxScreenLines = window->height() / (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING);
window->setFocus();
readLinesCount = 0;
lastLoadedLine = 0;
lines = new char*[maxScreenLines];
for(i = 0 ; i < maxScreenLines; i++)
{
lines[i] = new char[maxLineLength + 1];
memclear(lines[i], maxLineLength + 1);
}
longestLine = 0;
loadFirstScreen();
if(isInSetup == true)
{
textBottom = false;
while(!textBottom)
{
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
textVerticalOffset += 10;
}
maxPos = (maxLines - maxScreenLines) * (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING);
if(maxPos < body.getRect().h) maxPos = body.getRect().h;
}
isInSetup = false;
loadFirstScreen();
for (i = 0; i < maxScreenLines; i++) {
new DynamicText(window, grid.getSlot(), [=]() {
std::string str = (lines[i][0]) ? std::string(lines[i]) : std::string(" ");
return std::string(str);
});
grid.nextLine();
}
}
#if defined(HARDWARE_TOUCH)
bool ViewTextWindow::onTouchSlide(coord_t x, coord_t y, coord_t startX,
coord_t startY, coord_t slideX,
coord_t slideY)
{
if (&body == Window::focusWindow) {
const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING;
int deltaY = -slideY;
int lineStep = deltaY / step;
textVerticalOffset += lineStep;
if (textVerticalOffset < 0) textVerticalOffset = 0;
// if (textBottom && lineStep > 0) textVerticalOffset -= lineStep;
if(textVerticalOffset > maxLines) textVerticalOffset = maxLines;
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
}
return Page::onTouchSlide(x, y, startX, startY, slideX, slideY);
}
#endif
void ViewTextWindow::checkEvents()
{
if (&body == Window::focusWindow) {
const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING;
coord_t deltaY;
event_t event = getWindowEvent();
if (event == EVT_ROTARY_LEFT || event == EVT_ROTARY_RIGHT) {
deltaY = ROTARY_ENCODER_SPEED() * step;
} else {
deltaY = step;
}
int lineStep = deltaY / step;
if(lineStep > (maxScreenLines >> 1)) lineStep = maxScreenLines >> 1;
/*
if(event) {
sprintf(lines[0], "Received event %d", event);
if(!readLinesCount)
readLinesCount = 1;
Page::onEvent(event);
return;
}
*/
switch (event) {
CASE_EVT_START:
textVerticalOffset = 0;
readLinesCount = 0;
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
break;
CASE_EVT_KEY_NEXT_LINE:
if(textBottom && textVerticalOffset) //(textVerticalOffset + maxScreenLines - 1 >= readLinesCount)
break;
else {
textVerticalOffset += lineStep;
if(textVerticalOffset > maxLines) textVerticalOffset = maxLines;
}
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
break;
CASE_EVT_KEY_PREVIOUS_LINE:
if (textVerticalOffset == 0)
break;
else {
textVerticalOffset -= lineStep;
if(textVerticalOffset < 0) textVerticalOffset = 0;
}
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
break;
default:
Page::onEvent(event);
break;
}
}
Page::checkEvents();
}
void ViewTextWindow::loadFirstScreen()
{
textVerticalOffset = 0;
readLinesCount = 0;
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
}
void ViewTextWindow::sdReadTextFileBlock(const char *filename, int &lines_count)
{
FIL file;
int result;
char c;
unsigned int sz = 0;
int line_length = 1;
uint8_t escape = 0;
char escape_chars[4] = {0};
int current_line = 0;
textBottom = false;
for(int i = 0; i < maxScreenLines; i++) {
memclear(lines[i], maxLineLength + 1);
lines[i][0] = ' ';
}
result = f_open(&file, (TCHAR *)filename, FA_OPEN_EXISTING | FA_READ);
if (result == FR_OK) {
for (int i = 0; i < TEXT_FILE_MAXSIZE &&
f_read(&file, &c, 1, &sz) == FR_OK && sz == 1 &&
(lines_count == 0 ||
current_line - textVerticalOffset < maxScreenLines);
i++) {
if (c == '\n' || line_length >= maxLineLength) {
++current_line;
line_length = 1;
escape = 0;
}
if (c != '\r' && c != '\n' && current_line >= textVerticalOffset &&
current_line - textVerticalOffset < maxScreenLines &&
line_length < maxLineLength) {
if (c == '\\' && escape == 0) {
escape = 1;
continue;
} else if (c != '\\' && escape > 0 && escape < sizeof(escape_chars)) {
escape_chars[escape - 1] = c;
if (escape == 2 && !strncmp(escape_chars, "up", 2)) {
c = CHAR_UP;
} else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) {
c = CHAR_DOWN;
} else if (escape == 3) {
int val = atoi(escape_chars);
if (val >= 200 && val < 225) {
c = '\200' + val - 200;
}
} else {
escape++;
continue;
}
}
else if (c == '~') {
c = 'z' + 1;
} else if (c == '\t') {
c = 0x1D; // tab
}
escape = 0;
lines[current_line - textVerticalOffset][line_length++] = c;
if (longestLine < line_length) longestLine = line_length;
} else if(current_line < textVerticalOffset) {
++line_length;
}
}
if (c != '\n') {
++current_line;
}
if (f_eof(&file)) {
textBottom = true;
if (isInSetup) maxLines = current_line;
}
f_close(&file);
}
if(lastLoadedLine < textVerticalOffset)
lastLoadedLine = textVerticalOffset;
if (lines_count == 0) {
lines_count = current_line;
}
}
void ViewTextWindow::drawVerticalScrollbar(BitmapBuffer *dc)
{
int readPos = textVerticalOffset * (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING);
if(readPos < header.getRect().h << 1) readPos = header.getRect().h << 1;
coord_t yofs = divRoundClosest(body.getRect().h * readPos, maxPos);
coord_t yhgt = divRoundClosest(body.getRect().h * body.getRect().h, maxPos);
if (yhgt < 15) yhgt = 15;
if (yhgt + yofs > maxPos) yhgt = maxPos - yofs;
dc->drawSolidFilledRect(body.getRect().w - SCROLLBAR_WIDTH, yofs,
SCROLLBAR_WIDTH, yhgt, SCROLLBAR_COLOR);
}
#endif
#include "datastructs.h"
void readModelNotes()
{
LED_ERROR_BEGIN();
std::string modelNotesName(g_model.header.name);
modelNotesName.append(TEXT_EXT);
const char buf[] = {MODELS_PATH};
f_chdir((TCHAR*)buf);
new ViewTextWindow(std::string(buf), modelNotesName, ICON_MODEL);
LED_ERROR_END();
}
+126
View File
@@ -0,0 +1,126 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#pragma once
#include "page.h"
#include "static.h"
#include "lcd.h"
#include "menus.h"
#include "ff.h"
#define READ_FILE_BY_LINE 0
constexpr uint16_t TEXT_FILE_MAXSIZE = 20480;
class ViewTextWindow : public Page
{
public:
ViewTextWindow(const std::string iPath, const std::string iName, unsigned int icon = ICON_RADIO_SD_MANAGER) :
Page(icon),
path(std::move(iPath)),
name(std::move(iName)),
icon(icon)
{
fullPath = path + std::string("/") + name;
extractNameSansExt();
lines = nullptr;
lastLoadedLine = 0;
maxPos = 0;
maxLines = 0;
isInSetup = true;
//body.setWindowFlags(FORWARD_SCROLL);
header.setWindowFlags(NO_SCROLLBAR);
buildHeader(&header);
buildBody(&body);
};
#if READ_FILE_BY_LINE
bool sdReadTextLine(FIL* file, char lines[],
const uint8_t lineLength = LCD_COLS);
#else
void sdReadTextFileBlock(const char * filename, int& lines_count);
void loadFirstScreen(void);
#if defined(HARDWARE_TOUCH)
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override;
#endif
void drawVerticalScrollbar(BitmapBuffer * dc);
~ViewTextWindow()
{
if(lines != nullptr) {
for(int i = 0; i < maxScreenLines; i++)
{
delete[] lines[i];
}
delete[] lines;
}
}
void paint(BitmapBuffer* dc)
{
Page::paint(dc);
drawVerticalScrollbar(dc);
}
#endif
virtual void checkEvents();
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "ViewTextWindow"; };
#endif
protected:
std::string path;
std::string name;
std::string fullPath;
std::string extension;
unsigned int icon;
bool lastLine;
uint16_t readCount;
int longestLine;
#if !READ_FILE_BY_LINE
char** lines = nullptr;
//char lines[15][80];
int maxScreenLines;
int maxLineLength;
int textVerticalOffset;
int readLinesCount;
int lastLoadedLine;
int maxPos;
int maxLines;
bool textBottom;
bool isInSetup;
#endif
void extractNameSansExt(void);
void buildBody(Window *window);
void buildHeader(Window *window)
{
new StaticText(window,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + 10,
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
name, 0, MENU_HIGHLIGHT_COLOR);
};
};
void readModelNotes();
+1 -4
View File
@@ -26,6 +26,7 @@
// #include "shutdown_animation.h"
#include "radio_calibration.h"
#include "view_main.h"
#include "view_text.h"
#endif
#if defined(PCBSKY9X)
@@ -745,13 +746,9 @@ void checkAll()
disableVBatBridge();
#endif
#if defined(COLORLCD)
#warning "Model notes missing"
#else
if (g_model.displayChecklist && modelHasNotes()) {
readModelNotes();
}
#endif
#if defined(MULTIMODULE)
checkMultiLowPower();