[reader] Fixed bug when a word is too big

This commit is contained in:
Laury
2022-04-08 19:03:13 +02:00
parent 22ba190542
commit 2bf6de5044
17 changed files with 218 additions and 75 deletions

View File

@@ -1,6 +1,6 @@
# LaTeX Parser
In the reader app, you can read a txt file. You can also read a txt file with LaTeX expression inside of it.
In the reader app, you can read a txt file. You can also read a .urt file with LaTeX expression inside of it.
All the symbols you can use are listed here :

View File

@@ -1,3 +1,5 @@
ReaderApp = "Leser"
ReaderAppCapital = "LESER"
NoFileToDisplay = "Keine Dateien zum Anzeigen"
NoFileToDisplay = "Keine Dateien zum Anzeigen"
FileError1 = "Fehler beim Lesen der Datei"
FileError2 = "Bitte überprüfen Sie die Syntax"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Reader"
ReaderAppCapital = "READER"
NoFileToDisplay = "No file to display"
NoFileToDisplay = "No file to display"
FileError1 = "Error while reading file"
FileError2 = "Please check its syntax"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Lector"
ReaderAppCapital = "LECTOR"
NoFileToDisplay ="No hay archivos para mostrar"
NoFileToDisplay ="No hay archivos para mostrar"
FileError1 = "Error al leer el archivo"
FileError2 = "Por favor revise su sintaxis"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Liseuse"
ReaderAppCapital = "LISEUSE"
NoFileToDisplay = "Aucun fichier à afficher"
NoFileToDisplay = "Aucun fichier à afficher"
FileError1 = "Erreur durant la lecture du fichier"
FileError2 = "Veuillez vérifier sa syntaxe"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Olvasó"
ReaderAppCapital = "OLVASÓ"
NoFileToDisplay = "Nincs megjeleníthető fájl"
NoFileToDisplay = "Nincs megjeleníthető fájl"
FileError1 = "Hiba a fájl olvasása közben"
FileError2 = "Kérjük, ellenőrizze a szintaxisát"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Lettore"
ReaderAppCapital = "LETTORE"
NoFileToDisplay = "essun file da visualizzare"
NoFileToDisplay = "essun file da visualizzare"
FileError1 = "Errore durante la lettura del file"
FileError2 = "Si prega di controllare la sua sintassi"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Lezer"
ReaderAppCapital = "LEZER"
NoFileToDisplay = "Geen bestanden om weer te geven"
NoFileToDisplay = "Geen bestanden om weer te geven"
FileError1 = "Fout tijdens het lezen van bestand"
FileError2 = "Controleer de syntaxis ervan"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Leitor"
ReaderAppCapital = "LEITOR"
NoFileToDisplay = "Nenhum arquivo para exibir"
NoFileToDisplay = "Nenhum arquivo para exibir"
FileError1 = "Erro ao ler o arquivo"
FileError2 = "Verifique sua sintaxe"

View File

@@ -1,10 +1,12 @@
#include "read_book_controller.h"
#include <apps/apps_container.h>
namespace Reader
namespace Reader
{
ReadBookController::ReadBookController(Responder * parentResponder) :
ViewController(parentResponder)
ViewController(parentResponder),
m_readerView(this)
{
}
@@ -18,7 +20,7 @@ void ReadBookController::setBook(const External::Archive::File& file, bool isRic
m_readerView.setText(reinterpret_cast<const char*>(file.data), file.dataLength, isRichTextFile);
}
bool ReadBookController::handleEvent(Ion::Events::Event event) {
bool ReadBookController::handleEvent(Ion::Events::Event event) {
if(event == Ion::Events::Down) {
m_readerView.nextPage();
return true;
@@ -34,6 +36,13 @@ void ReadBookController::viewDidDisappear() {
savePosition();
}
void ReadBookController::throwError() {
static_cast<StackViewController *>(parentResponder())->pop();
Container::activeApp()->displayWarning(I18n::Message::SyntaxError);
// As the error is thrown when we are drawing, me must redraw the whole screen
AppsContainer::sharedAppsContainer()->redrawWindow();
}
void ReadBookController::savePosition() const {
BookSave save = m_readerView.getBookSave();

View File

@@ -16,6 +16,7 @@ public:
void viewDidDisappear() override;
void savePosition() const;
void loadPosition();
void throwError();
private:
WordWrapTextView m_readerView;
const External::Archive::File* m_file;
@@ -23,4 +24,4 @@ private:
}
#endif
#endif

View File

@@ -129,6 +129,13 @@ const char * StartOfPrintableWord(const char * word, const char * start) {
if (word == start) {
return word;
}
// Go to start of code point with some code points dark magic
if (!(*word & 0x80 == 0)) {
word--;
while (!(*word & 0x80 && *word & 0x40)) {
word--;
}
}
UTF8Decoder decoder(start, word);
CodePoint codePoint = decoder.previousCodePoint();
const char * result = word;

View File

@@ -5,17 +5,19 @@
#include <poincare/expression.h>
#include "../shared/poincare_helpers.h"
#include <poincare/undefined.h>
#include "read_book_controller.h"
namespace Reader
{
WordWrapTextView::WordWrapTextView() :
WordWrapTextView::WordWrapTextView(ReadBookController * readBookController) :
PointerTextView(GlobalPreferences::sharedGlobalPreferences()->font()),
m_pageOffset(0),
m_nextPageOffset(0),
m_length(0),
m_isRichTextFile(false), // Value isn't important, it will change when the file is loaded
m_lastPagesOffsetsIndex(0)
m_lastPagesOffsetsIndex(0),
m_readBookController(readBookController)
{
for (int i = 0; i < k_lastOffsetsBufferSize; i++) {
m_lastPagesOffsets[i] = -1; // -1 Means : no informations
@@ -96,7 +98,8 @@ void WordWrapTextView::richTextPreviousPage() {
endOfWord = startOfWord - 1; // Update next endOfWord
continue;
} else {
// TODO: print error
m_readBookController->throwError();
return;
}
}
@@ -110,7 +113,7 @@ void WordWrapTextView::richTextPreviousPage() {
if (expressionStart < text()) {
break; // File isn't rightly formated
}
expressionStart ++;
expressionStart --;
}
TexParser parser = TexParser(expressionStart, endOfWord);
@@ -175,13 +178,16 @@ void WordWrapTextView::plainTextPreviousPage() {
KDPoint textEndPosition(m_frame.width() - k_margin, m_frame.height() - k_margin);
while(startOfWord>=text()) {
startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
endOfWord = UTF8Helper::EndOfWord(startOfWord);
while(endOfWord>text()) {
KDSize textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
KDPoint textStartPosition = KDPoint(textEndPosition.x()-textSize.width(), textEndPosition.y());
if (textStartPosition.x() < k_margin) {
// We check if the word is too long to be displayed entirely on just one line
if(textSize.width() > m_frame.width() - 2 * k_margin) {
startOfWord = endOfWord - (textEndPosition.x() - k_margin) / charWidth;
continue;
}
textEndPosition = KDPoint(m_frame.width() - k_margin, textEndPosition.y() - charHeight);
textStartPosition = KDPoint(textEndPosition.x() - textSize.width(), textEndPosition.y());
}
@@ -203,16 +209,23 @@ void WordWrapTextView::plainTextPreviousPage() {
break;
}
if (textStartPosition.y() != textEndPosition.y()) { // If line changed, x is at start of line
if (textStartPosition.y() != textEndPosition.y()) { // If line changed, x is at start of line
textStartPosition = KDPoint(m_frame.width() - k_margin, textStartPosition.y());
}
if (textStartPosition.x() < k_margin) { // Go to line if left overflow
if (textStartPosition.x() <= k_margin) { // Go to line if left overflow
textStartPosition = KDPoint(m_frame.width() - k_margin, textStartPosition.y() - charHeight);
}
textEndPosition = textStartPosition;
endOfWord = startOfWord + 1;
startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
}
while (endOfWord < text() + m_length && (*endOfWord == ' ' || *endOfWord == '\n')) {
endOfWord++;
}
m_pageOffset = endOfWord - text();
}
void WordWrapTextView::drawRect(KDContext * ctx, KDRect rect) const {
@@ -242,11 +255,12 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
const int wordMaxLength = (m_frame.width() - 2*k_margin ) / charWidth;
char word[wordMaxLength];
Layout layout;
Layout tooBigLayout = EmptyLayout::Builder(); // To store layouts that are too big to be displayed entirely on one line
KDCoordinate tooBigLayoutAlreadyWroteWidth = 0; // We store here the part of the layout that has already been written
KDPoint textPosition = KDPoint(k_margin, k_margin);
while (!endOfPage && startOfWord < endOfFile) {
while (!endOfPage && (startOfWord < endOfFile || !tooBigLayout.isEmpty())) {
// We process line by line
const char * firstReadIndex = startOfWord;
@@ -256,8 +270,19 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
KDCoordinate baseline = charHeight / 2;
while (firstReadIndex < endOfFile) {
// 1.0. We check if we are drawing a too big layout
if (!tooBigLayout.isEmpty()) {
lineSize = tooBigLayout.layoutSize();
baseline = tooBigLayout.baseline();
if (tooBigLayout.layoutSize().width() - tooBigLayoutAlreadyWroteWidth > m_frame.width() - 2 * k_margin) {
// Remaining part of the layout don't fit on the line
break;
}
}
KDSize textSize = KDSizeZero;
KDCoordinate updatedBaseline = 0; // 0 if it's not a layout
// 1.1. And we check if we are at the end of the line
if(*firstReadIndex == '\n') {
@@ -265,12 +290,20 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
}
// 1.2. Check if we are in a color change
if (*firstReadIndex == '%') { // We assume each '%' non-escaped is announcing a color change // TODO : check file is rightly formated
if (*firstReadIndex == '%') { // We assume each '%' non-escaped is announcing a color change
// We go to the end of the color change + 1
const char * startIndex = firstReadIndex;
do {
firstReadIndex ++;
} while (*firstReadIndex != '%');
} while (*firstReadIndex != '%' && firstReadIndex < endOfFile && startIndex - firstReadIndex < 5);
firstReadIndex ++;
if (firstReadIndex - startIndex > 5) {
m_readBookController->throwError();
return;
}
continue;
}
@@ -286,16 +319,17 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
}
TexParser parser = TexParser(expressionStart, firstReadIndex);
Layout layout = parser.getLayout();
Layout firstReadLayout = parser.getLayout();
KDCoordinate layoutBaseline = layout.baseline();
// We check if we must change baseline
KDCoordinate layoutBaseline = firstReadLayout.baseline();
updatedBaseline = baseline; // We really update baseline after, if the layout fit on the line
if (layoutBaseline > baseline) {
baseline = layoutBaseline;
updatedBaseline = layoutBaseline;
}
KDSize layoutSize = layout.layoutSize();
textSize = KDSize(layoutSize.width(), layoutSize.height() + baseline - layoutBaseline);
KDSize layoutSize = firstReadLayout.layoutSize();
textSize = KDSize(layoutSize.width(), layoutSize.height() + updatedBaseline - layoutBaseline);
firstReadIndex ++;
}
@@ -315,11 +349,16 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
// 1.5. We update size
int newWidth = lineSize.width() + textSize.width();
// We check if the new text fit on the line
if (newWidth > m_frame.width() - 2 * k_margin) {
// We check if the new text fit on the line.
// If not, we look if only the word cannot fit on one line. If so, we do not go to the line
if (newWidth > m_frame.width() - 2 * k_margin && !(textSize.width() > m_frame.width() - 2 * k_margin)) {
break;
}
if (updatedBaseline) { // Now we update baseline
baseline = updatedBaseline;
}
int newHeight;
if (lineSize.height() > textSize.height()) {
newHeight = lineSize.height();
@@ -345,7 +384,30 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
}
// 2. And now... we read the line again to draw it !
while (startOfWord < endOfFile) {
while (startOfWord < endOfFile || !tooBigLayout.isEmpty()) {
// 2.0 Before all, we check if we were drawing a layout that was too big to fit on one line.
// In this case, we do all the routine here.
if (!tooBigLayout.isEmpty()) {
KDPoint position = KDPoint(textPosition.x() - tooBigLayoutAlreadyWroteWidth, textPosition.y());
tooBigLayout.draw(ctx, position, m_textColor, m_backgroundColor);
// We fill the left margin
ctx->fillRect(KDRect(0, textPosition.y(), k_margin, tooBigLayout.layoutSize().height()), m_backgroundColor);
KDCoordinate drawnWidth = tooBigLayout.layoutSize().width() - tooBigLayoutAlreadyWroteWidth;
tooBigLayoutAlreadyWroteWidth += drawnWidth;
if (drawnWidth > m_frame.width() - 2 * k_margin) {
// We have to fill the margin with the background color
ctx->fillRect(KDRect(textPosition.x() + drawnWidth, textPosition.y(), k_margin, lineSize.height()), m_backgroundColor);
textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
break;
} else {
tooBigLayout = EmptyLayout::Builder(); // We have finished drawing the tooBigLayout
}
continue;
}
Layout layout;
//2.1. We check if we are at the end of the line
if (*startOfWord == '\n') {
@@ -355,7 +417,6 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
// We aren't supposed to be at the end of the page, else the loop on top would have stopped drawing
}
const char * endOfWord;
// 2.2. Check if we are in a color change
@@ -369,7 +430,8 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
continue;
}
else {
// TODO: Print exception
m_readBookController->throwError();
return;
}
}
@@ -412,14 +474,34 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
// 2.4.1. Check if we need to go to the next line
if(endTextPosition.x() > m_frame.width() - k_margin) {
textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
break;
// We check if the word is too long to be displayed entirely on just one line
if(textSize.width() > m_frame.width() - 2 * k_margin) {
if (toDraw == ToDraw::Text) {
startOfWord = endOfWord - (endTextPosition.x() - k_margin) / charWidth;
continue;
} else {
assert(toDraw == ToDraw::Expression);
tooBigLayout = layout;
tooBigLayoutAlreadyWroteWidth += m_frame.width() - k_margin - textPosition.x();
endTextPosition = KDPoint(k_margin, textPosition.y() + lineSize.height()); // We jump line now, because this will be the next value of textPosition
}
} else {
textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
// endTextPosition will be updated later
break;
}
}
// 2.5. Now we draw !
if (toDraw == ToDraw::Expression) {
KDPoint position = KDPoint(textPosition.x(), textPosition.y() + baseline - layout.baseline());
layout.draw(ctx, position, m_textColor, m_backgroundColor);
if (!tooBigLayout.isEmpty()) {
// We fill the margin
ctx->fillRect(KDRect(m_frame.width() - k_margin, textPosition.y(), k_margin, lineSize.height()), m_backgroundColor);
}
}
else {
KDPoint position = KDPoint(textPosition.x(), textPosition.y() + baseline - charHeight / 2);
@@ -435,6 +517,11 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
textPosition = KDPoint(textPosition.x() + charWidth, textPosition.y());
}
startOfWord = endOfWord;
// 2.8. We exit now if we are in the "too big layout" case
if (!tooBigLayout.isEmpty()) {
break;
}
}
}
m_nextPageOffset = startOfWord - text();
@@ -446,7 +533,7 @@ void WordWrapTextView::plainTextDrawRect(KDContext * ctx, KDRect rect) const {
const char * endOfFile = text() + m_length;
const char * startOfWord = text() + m_pageOffset;
const char * endOfWord = UTF8Helper::EndOfWord(startOfWord);
const char * endOfWord = UTF8Helper::EndOfWord(startOfWord, endOfFile);
KDPoint textPosition(k_margin, k_margin);
const int wordMaxLength = 128;
@@ -458,8 +545,13 @@ void WordWrapTextView::plainTextDrawRect(KDContext * ctx, KDRect rect) const {
while(startOfWord < endOfFile) {
KDSize textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
KDPoint nextTextPosition = KDPoint(textPosition.x()+textSize.width(), textPosition.y());
if(nextTextPosition.x() > m_frame.width() - k_margin) { // Right overflow
// We check if the word is too long to be displayed entirely on just one line
if(textSize.width() > m_frame.width() - 2 * k_margin) {
endOfWord = startOfWord + (m_frame.width() - k_margin - textPosition.x()) / charWidth;
continue;
}
textPosition = KDPoint(k_margin, textPosition.y() + textSize.height());
nextTextPosition = KDPoint(k_margin + textSize.width(), textPosition.y());
}
@@ -488,15 +580,15 @@ void WordWrapTextView::plainTextDrawRect(KDContext * ctx, KDRect rect) const {
if(nextTextPosition.y() + textSize.height() > m_frame.height() - k_margin) { // If out of page, quit
break;
}
if(nextTextPosition.y() != textPosition.y()) { // If line changed, x is at start of line
if(nextTextPosition.y() != textPosition.y()) { // If line changed, x is at start of line
nextTextPosition = KDPoint(k_margin, nextTextPosition.y());
}
if(nextTextPosition.x() > m_frame.width() - k_margin) { // Go to line if right overflow
if(nextTextPosition.x() >= m_frame.width() - k_margin) { // Go to line if right overflow
nextTextPosition = KDPoint(k_margin, nextTextPosition.y() + textSize.height());
}
textPosition = nextTextPosition;
endOfWord = UTF8Helper::EndOfWord(startOfWord);
endOfWord = UTF8Helper::EndOfWord(startOfWord, endOfFile);
}
m_nextPageOffset = startOfWord - text();
@@ -523,7 +615,7 @@ bool WordWrapTextView::updateTextColorForward(const char * colorStart) const {
int keySize = 1;
KDColor lastColor = m_textColor;
switch (*(colorStart+1))
{
case 'r':
@@ -666,6 +758,6 @@ bool WordWrapTextView::updateTextColorBackward(const char * colorStart) const {
}
return true;
}
}
}

View File

@@ -12,9 +12,11 @@ struct BookSave {
KDColor color;
};
class ReadBookController;
class WordWrapTextView : public PointerTextView {
public:
WordWrapTextView();
WordWrapTextView(ReadBookController * readBookController);
void drawRect(KDContext * ctx, KDRect rect) const override;
void setText(const char*, int length, bool isRichTextFile);
void nextPage();
@@ -42,6 +44,7 @@ private:
*/
int m_lastPagesOffsets[k_lastOffsetsBufferSize];
int m_lastPagesOffsetsIndex;
ReadBookController * m_readBookController;
};
}