From d0de870180081cc97b4b9a2f77e168e837e37917 Mon Sep 17 00:00:00 2001 From: Nebuleon Fumika Date: Thu, 24 Jul 2014 01:36:01 +0000 Subject: [PATCH] Use Font::wordWrap in TextDialog and TextManualDialog The constructors of those classes now accept a string to be wrapped, instead of a vector to be modified with split lines inserted into its middle. Along with this conversion, manuals for applications stored in OPK packages are now transferred into a string without garbage at the end. --- src/gmenu2x.cpp | 21 ++++---- src/linkapp.cpp | 38 ++++++--------- src/textdialog.cpp | 100 ++++----------------------------------- src/textdialog.h | 7 ++- src/textmanualdialog.cpp | 10 ++-- src/textmanualdialog.h | 2 +- 6 files changed, 43 insertions(+), 135 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 878508a..08ff48e 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -409,8 +409,7 @@ void GMenu2X::initMenu() { } void GMenu2X::about() { - vector text; - string line; + string str, line; string fn(GMENU2X_SYSTEM_DIR); string build_date("Build date: "); fn.append("/about.txt"); @@ -418,11 +417,12 @@ void GMenu2X::about() { ifstream inf(fn.c_str(), ios_base::in); - while(getline(inf, line, '\n')) - text.push_back(line); + while(getline(inf, line, '\n')) { + str.append(line).append("\n"); + } inf.close(); - TextDialog td(this, "GMenu2X", build_date, "icons/about.png", &text); + TextDialog td(this, "GMenu2X", build_date, "icons/about.png", str); td.exec(); } @@ -431,14 +431,13 @@ void GMenu2X::viewLog() { if (fileExists(logfile)) { ifstream inf(logfile.c_str(), ios_base::in); if (inf.is_open()) { - vector log; - - string line; - while (getline(inf, line, '\n')) - log.push_back(line); + string str, line; + while (getline(inf, line, '\n')) { + str.append(line).append("\n"); + } inf.close(); - TextDialog td(this, tr["Log Viewer"], tr["Displays last launched program's output"], "icons/ebook.png", &log); + TextDialog td(this, tr["Log Viewer"], tr["Displays last launched program's output"], "icons/ebook.png", str); td.exec(); MessageBox mb(this, tr["Do you want to delete the log file?"], "icons/ebook.png"); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 5248ba0..3ab9aae 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -375,7 +375,7 @@ void LinkApp::showManual() { #ifdef HAVE_LIBOPK if (isOPK) { vector readme; - char *token, *ptr; + char *ptr; struct OPK *opk; int err; void *buf; @@ -395,24 +395,14 @@ void LinkApp::showManual() { opk_close(opk); ptr = (char *) buf; - while((token = strchr(ptr, '\n'))) { - *token = '\0'; - - string str(ptr); - readme.push_back(str); - ptr = token + 1; - } - - /* Add the last line */ - string str(ptr); - readme.push_back(str); + string str(ptr, len); free(buf); if (manual.substr(manual.size()-8,8)==".man.txt") { - TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), &readme); + TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), str); tmd.exec(); } else { - TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme); + TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), str); td.exec(); } return; @@ -501,15 +491,15 @@ void LinkApp::showManual() { // Txt manuals if (manual.substr(manual.size()-8,8)==".man.txt") { - vector txtman; - - string line; + string str, line; ifstream infile(manual.c_str(), ios_base::in); if (infile.is_open()) { - while (getline(infile, line, '\n')) txtman.push_back(line); + while (getline(infile, line, '\n')) { + str.append(line).append("\n"); + } infile.close(); - TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), &txtman); + TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), str); tmd.exec(); } @@ -517,15 +507,15 @@ void LinkApp::showManual() { } //Readmes - vector readme; - - string line; + string str, line; ifstream infile(manual.c_str(), ios_base::in); if (infile.is_open()) { - while (getline(infile, line, '\n')) readme.push_back(line); + while (getline(infile, line, '\n')) { + str.append(line).append("\n"); + } infile.close(); - TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme); + TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), str); td.exec(); } } diff --git a/src/textdialog.cpp b/src/textdialog.cpp index 35ab96a..5b3231e 100644 --- a/src/textdialog.cpp +++ b/src/textdialog.cpp @@ -25,102 +25,22 @@ using namespace std; -TextDialog::TextDialog(GMenu2X *gmenu2x, const string &title, const string &description, const string &icon, vector *text) +TextDialog::TextDialog(GMenu2X *gmenu2x, const string &title, const string &description, const string &icon, const string &text) : Dialog(gmenu2x) { - this->text = text; + split(this->text, gmenu2x->font->wordWrap(text, (int) gmenu2x->resX - 15), "\n"); this->title = title; this->description = description; this->icon = icon; - preProcess(); } -void TextDialog::preProcess() { - unsigned i = 0; - - while (i < text->size()) { - /* Clean the end of the string, allowing lines that are indented at - * the start to stay as such. */ - string line = rtrim(text->at(i)); - - if (gmenu2x->font->getTextWidth(line) > (int) gmenu2x->resX - 15) { - /* At least one full character must fit, in order to advance. */ - size_t fits = 1; - while (fits < line.length() && !isUTF8Starter(line[fits])) { - fits++; - } - size_t doesntFit = fits; - - /* This preprocessing finds an upper bound on the number of - * bytes of full characters that fit on the screen, 2^n, in - * n steps. */ - do { - fits = doesntFit; /* what didn't fit has been determined to fit by a previous iteration */ - doesntFit = min(2 * fits, line.length()); - while (doesntFit < line.length() && !isUTF8Starter(line[doesntFit])) { - doesntFit++; - } - } while (doesntFit <= line.length() - && gmenu2x->font->getTextWidth(line.substr(0, doesntFit)) <= (int) gmenu2x->resX - 15); - - /* End this loop when N characters fit but N + 1 don't. */ - while (fits + 1 < doesntFit) { - size_t guess = fits + (doesntFit - fits) / 2; - if (!isUTF8Starter(line[guess])) - { - size_t oldGuess = guess; - /* Adjust the guess to the nearest UTF-8 starter that is - * not 'fits' or 'doesntFit'. */ - for (size_t offset = 1; offset < (doesntFit - fits) / 2 - 1; offset++) { - if (isUTF8Starter(line[guess - offset])) { - guess -= offset; - break; - } else if (isUTF8Starter(line[guess + offset])) { - guess += offset; - break; - } - } - /* If there's no such character, exit early. */ - if (guess == oldGuess) { - break; - } - } - if (gmenu2x->font->getTextWidth(line.substr(0, guess)) <= (int) gmenu2x->resX - 15) { - fits = guess; - } else { - doesntFit = guess; - } - } - - /* The line shall be split at the last space-separated word that - * fully fits, or otherwise at the last character that fits. */ - size_t lastSpace = line.find_last_of(" \t\r", fits); - if (lastSpace != string::npos) { - fits = lastSpace; - } - - /* Insert the rest in a new slot after this line. - * TODO (Nebuleon) Don't use a vector for this, because all later - * elements are moved, which is inefficient. */ - text->insert(text->begin() + i + 1, ltrim(line.substr(fits))); - line = rtrim(line.substr(0, fits)); - } - - /* Put the trimmed whole line or the smaller split of the split line - * back into the same slot */ - text->at(i) = line; - - i++; - } -} - -void TextDialog::drawText(vector *text, unsigned int y, +void TextDialog::drawText(const vector &text, unsigned int y, unsigned int firstRow, unsigned int rowsPerPage) { const int fontHeight = gmenu2x->font->getLineSpacing(); - for (unsigned i = firstRow; i < firstRow + rowsPerPage && i < text->size(); i++) { - const string &line = text->at(i); + for (unsigned i = firstRow; i < firstRow + rowsPerPage && i < text.size(); i++) { + const string &line = text.at(i); int rowY = y + (i - firstRow) * fontHeight; if (line == "----") { // horizontal ruler rowY += fontHeight / 2; @@ -131,7 +51,7 @@ void TextDialog::drawText(vector *text, unsigned int y, } } - gmenu2x->drawScrollBar(rowsPerPage, text->size(), firstRow); + gmenu2x->drawScrollBar(rowsPerPage, text.size(), firstRow); } void TextDialog::exec() { @@ -171,18 +91,18 @@ void TextDialog::exec() { if (firstRow > 0) firstRow--; break; case InputManager::DOWN: - if (firstRow + rowsPerPage < text->size()) firstRow++; + if (firstRow + rowsPerPage < text.size()) firstRow++; break; case InputManager::ALTLEFT: if (firstRow >= rowsPerPage-1) firstRow -= rowsPerPage-1; else firstRow = 0; break; case InputManager::ALTRIGHT: - if (firstRow + rowsPerPage*2 -1 < text->size()) { + if (firstRow + rowsPerPage*2 -1 < text.size()) { firstRow += rowsPerPage-1; } else { - firstRow = text->size() < rowsPerPage ? - 0 : text->size() - rowsPerPage; + firstRow = text.size() < rowsPerPage ? + 0 : text.size() - rowsPerPage; } break; case InputManager::SETTINGS: diff --git a/src/textdialog.h b/src/textdialog.h index 4ede7b2..de2177a 100644 --- a/src/textdialog.h +++ b/src/textdialog.h @@ -28,17 +28,16 @@ class TextDialog : protected Dialog { protected: - std::vector *text; + std::vector text; std::string title, description, icon; - void preProcess(); - void drawText(std::vector *text, unsigned int y, + void drawText(const std::vector &text, unsigned int y, unsigned int firstRow, unsigned int rowsPerPage); public: TextDialog(GMenu2X *gmenu2x, const std::string &title, const std::string &description, const std::string &icon, - std::vector *text); + const std::string &text); void exec(); }; diff --git a/src/textmanualdialog.cpp b/src/textmanualdialog.cpp index 2921329..25736cd 100644 --- a/src/textmanualdialog.cpp +++ b/src/textmanualdialog.cpp @@ -29,12 +29,12 @@ using namespace std; -TextManualDialog::TextManualDialog(GMenu2X *gmenu2x, const string &title, const string &icon, vector *text) +TextManualDialog::TextManualDialog(GMenu2X *gmenu2x, const string &title, const string &icon, const string &text) : TextDialog(gmenu2x,title,"",icon,text) { //split the text in multiple pages - for (uint i=0; isize(); i++) { - string line = trim(text->at(i)); + for (uint i=0; itext.size(); i++) { + string line = trim(this->text.at(i)); if (line[0]=='[' && line[line.length()-1]==']') { ManualPage mp; mp.title = line.substr(1,line.length()-2); @@ -45,7 +45,7 @@ TextManualDialog::TextManualDialog(GMenu2X *gmenu2x, const string &title, const mp.title = gmenu2x->tr["Untitled"]; pages.push_back(mp); } - pages[pages.size()-1].text.push_back(text->at(i)); + pages[pages.size()-1].text.push_back(this->text.at(i)); } } if (pages.size()==0) { @@ -99,7 +99,7 @@ void TextManualDialog::exec() { while (!close) { bg.blit(gmenu2x->s,0,0); writeSubTitle(pages[page].title); - drawText(&pages[page].text, 42 /* TODO */, firstRow, rowsPerPage); + drawText(pages[page].text, 42 /* TODO */, firstRow, rowsPerPage); ss.clear(); ss << page+1; diff --git a/src/textmanualdialog.h b/src/textmanualdialog.h index 5669d65..ac21e18 100644 --- a/src/textmanualdialog.h +++ b/src/textmanualdialog.h @@ -37,7 +37,7 @@ private: public: TextManualDialog(GMenu2X *gmenu2x, const std::string &title, - const std::string &icon, std::vector *text); + const std::string &icon, const std::string &text); void exec(); };