mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[reader] Fixed bug when a word is too big
This commit is contained in:
@@ -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 :
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
import re
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
from typing import Dict, List
|
||||
# Deep translator import
|
||||
try:
|
||||
from deep_translator import GoogleTranslator
|
||||
@@ -64,14 +64,14 @@ def translate(text: str, output_language: str, input_language: str = 'auto')\
|
||||
return translator.translate(text)
|
||||
|
||||
|
||||
def get_all_files_in_directory(directory: str) -> list[str]:
|
||||
def get_all_files_in_directory(directory: str) -> List[str]:
|
||||
"""Get all files in the given directory recursively.
|
||||
|
||||
Args:
|
||||
directory (str): The directory
|
||||
|
||||
Returns:
|
||||
List[str]: The list of files in the directory
|
||||
Liststr]: The list of files in the directory
|
||||
|
||||
"""
|
||||
# Initialize the list of files
|
||||
@@ -92,7 +92,7 @@ def get_all_files_in_directory(directory: str) -> list[str]:
|
||||
return files
|
||||
|
||||
|
||||
def get_i18n_files(directory: str = '.') -> dict[str, list[str]]:
|
||||
def get_i18n_files(directory: str = '.') -> Dict[str, List[str]]:
|
||||
"""Get the list of i18n files in the given directory.
|
||||
|
||||
Args:
|
||||
@@ -100,13 +100,13 @@ def get_i18n_files(directory: str = '.') -> dict[str, list[str]]:
|
||||
Defaults to '.'.
|
||||
|
||||
Returns:
|
||||
dict[list[str]]: The list of i18n files in a dictionary of languages.
|
||||
Dict[List[str]]: The list of i18n files in a dictionary of languages.
|
||||
|
||||
"""
|
||||
# Get all files in the directory recursively
|
||||
files = get_all_files_in_directory(directory)
|
||||
# Initialize the dictionary
|
||||
i18n_files_language: dict[str, list[str]] = {}
|
||||
i18n_files_language: Dict[str, List[str]] = {}
|
||||
# Iterate over all files in the directory
|
||||
for i in files:
|
||||
# If the file is an i18n file
|
||||
@@ -125,21 +125,21 @@ def get_i18n_files(directory: str = '.') -> dict[str, list[str]]:
|
||||
return i18n_files_language
|
||||
|
||||
|
||||
def need_to_be_translated(keys: dict[str, list[list[str]]])\
|
||||
-> dict[str, list[list[str]]]:
|
||||
def need_to_be_translated(keys: Dict[str, List[List[str]]])\
|
||||
-> Dict[str, List[List[str]]]:
|
||||
"""Return the key that needs to be translated by locale.
|
||||
|
||||
Args:
|
||||
keys (dict[str, list[str]]): The keys of the i18n files
|
||||
keys (Dict[str, List[str]]): The keys of the i18n files
|
||||
|
||||
Returns:
|
||||
dict[str, list[str]]: The keys that needs to be translated,
|
||||
Dict[str, List[str]]: The keys that needs to be translated,
|
||||
sorted by locale
|
||||
|
||||
"""
|
||||
# Initialize the list of keys
|
||||
keys_list: list[list[str]] = []
|
||||
keys_to_translate: dict[str, list[list[str]]] = {}
|
||||
keys_list: List[List[str]] = []
|
||||
keys_to_translate: Dict[str, List[List[str]]] = {}
|
||||
# Iterate over all locales
|
||||
for value_ in keys.values():
|
||||
# Iterate on keys of the locale
|
||||
@@ -151,14 +151,14 @@ def need_to_be_translated(keys: dict[str, list[list[str]]])\
|
||||
keys_list.append(key)
|
||||
for locale, value in keys.items():
|
||||
# Initialize the list of keys in the locale
|
||||
keys_in_locale: list[str] = [i[0] for i in value]
|
||||
keys_in_locale: List[str] = [i[0] for i in value]
|
||||
# Get the keys of keys that need to be translated
|
||||
keys_to_translate_in_locale: list[list[str]] = [
|
||||
keys_to_translate_in_locale: List[List[str]] = [
|
||||
key for key in keys_list if key[0] not in keys_in_locale
|
||||
]
|
||||
# Remove duplicates from the list
|
||||
# Initialize the deduplicated list
|
||||
keys_to_translate_in_locale_deduplicated: list[list[str]] = []
|
||||
keys_to_translate_in_locale_deduplicated: List[List[str]] = []
|
||||
# Iterate over the duplicated list
|
||||
for item in keys_to_translate_in_locale:
|
||||
# If the key is not in the deduplicated list, add it
|
||||
@@ -170,14 +170,14 @@ def need_to_be_translated(keys: dict[str, list[list[str]]])\
|
||||
return keys_to_translate
|
||||
|
||||
|
||||
def get_keys_in_file(filename: str) -> list[list[str]]:
|
||||
def get_keys_in_file(filename: str) -> List[List[str]]:
|
||||
"""Return a list of keys in the file.
|
||||
|
||||
Args:
|
||||
filename (str): The name of the file to read
|
||||
|
||||
Returns:
|
||||
list[str]: The keys in the file
|
||||
List[str]: The keys in the file
|
||||
|
||||
"""
|
||||
# Initialize the list of keys in the file
|
||||
@@ -211,19 +211,19 @@ def get_keys_in_file(filename: str) -> list[list[str]]:
|
||||
return keys
|
||||
|
||||
|
||||
def list_keys(i18n_files: dict[str, list[str]]) -> dict[str, list[list[str]]]:
|
||||
def list_keys(i18n_files: Dict[str, List[str]]) -> Dict[str, List[List[str]]]:
|
||||
"""List all keys in the i18n files.
|
||||
|
||||
Args:
|
||||
i18n_files (dict[str, list[str]]): I18n files list
|
||||
i18n_files (Dict[str, List[str]]): I18n files list
|
||||
|
||||
Returns:
|
||||
dict[str, list[str]]: The dictionnary of keys in the i18n files by
|
||||
Dict[str, List[str]]: The dictionnary of keys in the i18n files by
|
||||
locale.
|
||||
|
||||
"""
|
||||
# Initialize the list of keys in the i18n files
|
||||
keys_dict: dict[str, list[list[str]]] = {}
|
||||
keys_dict: Dict[str, List[List[str]]] = {}
|
||||
# Iterate on the locales
|
||||
for locale in i18n_files:
|
||||
# Initialize the dictionary for the locale
|
||||
@@ -294,22 +294,22 @@ def get_value_from_key(key_to_find: str, filename_generic: str, locale: str)\
|
||||
return ""
|
||||
|
||||
|
||||
def translate_missing_keys(keys_to_translate: dict[str, list[list[str]]],
|
||||
input_language: str) -> dict[str, list[list[str]]]:
|
||||
def translate_missing_keys(keys_to_translate: Dict[str, List[List[str]]],
|
||||
input_language: str) -> Dict[str, List[List[str]]]:
|
||||
"""Get a dictionary of file with the keys and translations to add.
|
||||
|
||||
Args:
|
||||
keys_to_translate (dict[str, list[list[str]]]): The list of keys to
|
||||
keys_to_translate (Dict[str, List[List[str]]]): The list of keys to
|
||||
translate
|
||||
input_language (str): The language to get the text that will be
|
||||
translated
|
||||
|
||||
Returns:
|
||||
dict[str, list[str]]: The dictionary of files with translations
|
||||
Dict[str, List[str]]: The dictionary of files with translations
|
||||
|
||||
"""
|
||||
# Initialize the dictionary of translations
|
||||
output: dict[str, list[list[str]]] = {}
|
||||
output: Dict[str, List[List[str]]] = {}
|
||||
# Initialize the variable to store the number of translated keys
|
||||
keys_translated: int = 0
|
||||
# Iterate over the locales of the dictionary of untranslated keys
|
||||
@@ -373,11 +373,11 @@ def translate_missing_keys(keys_to_translate: dict[str, list[list[str]]],
|
||||
return output
|
||||
|
||||
|
||||
def save_translations(missing_keys_translation: dict[str, list[list[str]]]):
|
||||
def save_translations(missing_keys_translation: Dict[str, List[List[str]]]):
|
||||
"""Save the translations.
|
||||
|
||||
Args:
|
||||
missing_keys_translation (dict[str, list[list[str]]]): The dictionary
|
||||
missing_keys_translation (Dict[str, List[List[str]]]): The dictionary
|
||||
of translations
|
||||
|
||||
"""
|
||||
|
||||
@@ -120,6 +120,7 @@ size_t StringGlyphLength(const char * s, int maxSize = -1);
|
||||
const char * BeginningOfWord(const char * text, const char * word);
|
||||
// Returns the position of the first following char ' ', '\n' or 0
|
||||
const char * EndOfWord(const char * word);
|
||||
const char * EndOfWord(const char * word, const char * end);
|
||||
|
||||
// On a line, count number of glyphs before and after locations
|
||||
void countGlyphsInLine(const char * text, int * before, int * after, const char * beforeLocation, const char *afterLocation = nullptr);
|
||||
|
||||
@@ -475,6 +475,20 @@ const char * EndOfWord(const char * word) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const char * EndOfWord(const char * word, const char * end) {
|
||||
UTF8Decoder decoder(word);
|
||||
CodePoint codePoint = decoder.nextCodePoint();
|
||||
const char * result = word;
|
||||
while (!CodePointIsEndOfWord(codePoint)) {
|
||||
result = decoder.stringPosition();
|
||||
if (result >= end) {
|
||||
break;
|
||||
}
|
||||
codePoint = decoder.nextCodePoint();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void countGlyphsInLine(const char * text, int * before, int * after, const char * beforeLocation, const char *afterLocation) {
|
||||
UTF8Helper::CodePointAction countGlyph = [](int, void * glyphCount, int, int) {
|
||||
int * castedCount = (int *) glyphCount;
|
||||
|
||||
Reference in New Issue
Block a user