mirror of
git://projects.qi-hardware.com/gmenu2x.git
synced 2024-11-26 04:01:53 +02:00
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.
This commit is contained in:
parent
0c860e8b90
commit
d0de870180
@ -409,8 +409,7 @@ void GMenu2X::initMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GMenu2X::about() {
|
void GMenu2X::about() {
|
||||||
vector<string> text;
|
string str, line;
|
||||||
string line;
|
|
||||||
string fn(GMENU2X_SYSTEM_DIR);
|
string fn(GMENU2X_SYSTEM_DIR);
|
||||||
string build_date("Build date: ");
|
string build_date("Build date: ");
|
||||||
fn.append("/about.txt");
|
fn.append("/about.txt");
|
||||||
@ -418,11 +417,12 @@ void GMenu2X::about() {
|
|||||||
|
|
||||||
ifstream inf(fn.c_str(), ios_base::in);
|
ifstream inf(fn.c_str(), ios_base::in);
|
||||||
|
|
||||||
while(getline(inf, line, '\n'))
|
while(getline(inf, line, '\n')) {
|
||||||
text.push_back(line);
|
str.append(line).append("\n");
|
||||||
|
}
|
||||||
inf.close();
|
inf.close();
|
||||||
|
|
||||||
TextDialog td(this, "GMenu2X", build_date, "icons/about.png", &text);
|
TextDialog td(this, "GMenu2X", build_date, "icons/about.png", str);
|
||||||
td.exec();
|
td.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,14 +431,13 @@ void GMenu2X::viewLog() {
|
|||||||
if (fileExists(logfile)) {
|
if (fileExists(logfile)) {
|
||||||
ifstream inf(logfile.c_str(), ios_base::in);
|
ifstream inf(logfile.c_str(), ios_base::in);
|
||||||
if (inf.is_open()) {
|
if (inf.is_open()) {
|
||||||
vector<string> log;
|
string str, line;
|
||||||
|
while (getline(inf, line, '\n')) {
|
||||||
string line;
|
str.append(line).append("\n");
|
||||||
while (getline(inf, line, '\n'))
|
}
|
||||||
log.push_back(line);
|
|
||||||
inf.close();
|
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();
|
td.exec();
|
||||||
|
|
||||||
MessageBox mb(this, tr["Do you want to delete the log file?"], "icons/ebook.png");
|
MessageBox mb(this, tr["Do you want to delete the log file?"], "icons/ebook.png");
|
||||||
|
@ -375,7 +375,7 @@ void LinkApp::showManual() {
|
|||||||
#ifdef HAVE_LIBOPK
|
#ifdef HAVE_LIBOPK
|
||||||
if (isOPK) {
|
if (isOPK) {
|
||||||
vector<string> readme;
|
vector<string> readme;
|
||||||
char *token, *ptr;
|
char *ptr;
|
||||||
struct OPK *opk;
|
struct OPK *opk;
|
||||||
int err;
|
int err;
|
||||||
void *buf;
|
void *buf;
|
||||||
@ -395,24 +395,14 @@ void LinkApp::showManual() {
|
|||||||
opk_close(opk);
|
opk_close(opk);
|
||||||
|
|
||||||
ptr = (char *) buf;
|
ptr = (char *) buf;
|
||||||
while((token = strchr(ptr, '\n'))) {
|
string str(ptr, len);
|
||||||
*token = '\0';
|
|
||||||
|
|
||||||
string str(ptr);
|
|
||||||
readme.push_back(str);
|
|
||||||
ptr = token + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the last line */
|
|
||||||
string str(ptr);
|
|
||||||
readme.push_back(str);
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
if (manual.substr(manual.size()-8,8)==".man.txt") {
|
if (manual.substr(manual.size()-8,8)==".man.txt") {
|
||||||
TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), &readme);
|
TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), str);
|
||||||
tmd.exec();
|
tmd.exec();
|
||||||
} else {
|
} else {
|
||||||
TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme);
|
TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), str);
|
||||||
td.exec();
|
td.exec();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -501,15 +491,15 @@ void LinkApp::showManual() {
|
|||||||
|
|
||||||
// Txt manuals
|
// Txt manuals
|
||||||
if (manual.substr(manual.size()-8,8)==".man.txt") {
|
if (manual.substr(manual.size()-8,8)==".man.txt") {
|
||||||
vector<string> txtman;
|
string str, line;
|
||||||
|
|
||||||
string line;
|
|
||||||
ifstream infile(manual.c_str(), ios_base::in);
|
ifstream infile(manual.c_str(), ios_base::in);
|
||||||
if (infile.is_open()) {
|
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();
|
infile.close();
|
||||||
|
|
||||||
TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), &txtman);
|
TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), str);
|
||||||
tmd.exec();
|
tmd.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,15 +507,15 @@ void LinkApp::showManual() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Readmes
|
//Readmes
|
||||||
vector<string> readme;
|
string str, line;
|
||||||
|
|
||||||
string line;
|
|
||||||
ifstream infile(manual.c_str(), ios_base::in);
|
ifstream infile(manual.c_str(), ios_base::in);
|
||||||
if (infile.is_open()) {
|
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();
|
infile.close();
|
||||||
|
|
||||||
TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme);
|
TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), str);
|
||||||
td.exec();
|
td.exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,102 +25,22 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
TextDialog::TextDialog(GMenu2X *gmenu2x, const string &title, const string &description, const string &icon, vector<string> *text)
|
TextDialog::TextDialog(GMenu2X *gmenu2x, const string &title, const string &description, const string &icon, const string &text)
|
||||||
: Dialog(gmenu2x)
|
: Dialog(gmenu2x)
|
||||||
{
|
{
|
||||||
this->text = text;
|
split(this->text, gmenu2x->font->wordWrap(text, (int) gmenu2x->resX - 15), "\n");
|
||||||
this->title = title;
|
this->title = title;
|
||||||
this->description = description;
|
this->description = description;
|
||||||
this->icon = icon;
|
this->icon = icon;
|
||||||
preProcess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDialog::preProcess() {
|
void TextDialog::drawText(const vector<string> &text, unsigned int y,
|
||||||
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<string> *text, unsigned int y,
|
|
||||||
unsigned int firstRow, unsigned int rowsPerPage)
|
unsigned int firstRow, unsigned int rowsPerPage)
|
||||||
{
|
{
|
||||||
const int fontHeight = gmenu2x->font->getLineSpacing();
|
const int fontHeight = gmenu2x->font->getLineSpacing();
|
||||||
|
|
||||||
for (unsigned i = firstRow; i < firstRow + rowsPerPage && i < text->size(); i++) {
|
for (unsigned i = firstRow; i < firstRow + rowsPerPage && i < text.size(); i++) {
|
||||||
const string &line = text->at(i);
|
const string &line = text.at(i);
|
||||||
int rowY = y + (i - firstRow) * fontHeight;
|
int rowY = y + (i - firstRow) * fontHeight;
|
||||||
if (line == "----") { // horizontal ruler
|
if (line == "----") { // horizontal ruler
|
||||||
rowY += fontHeight / 2;
|
rowY += fontHeight / 2;
|
||||||
@ -131,7 +51,7 @@ void TextDialog::drawText(vector<string> *text, unsigned int y,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gmenu2x->drawScrollBar(rowsPerPage, text->size(), firstRow);
|
gmenu2x->drawScrollBar(rowsPerPage, text.size(), firstRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDialog::exec() {
|
void TextDialog::exec() {
|
||||||
@ -171,18 +91,18 @@ void TextDialog::exec() {
|
|||||||
if (firstRow > 0) firstRow--;
|
if (firstRow > 0) firstRow--;
|
||||||
break;
|
break;
|
||||||
case InputManager::DOWN:
|
case InputManager::DOWN:
|
||||||
if (firstRow + rowsPerPage < text->size()) firstRow++;
|
if (firstRow + rowsPerPage < text.size()) firstRow++;
|
||||||
break;
|
break;
|
||||||
case InputManager::ALTLEFT:
|
case InputManager::ALTLEFT:
|
||||||
if (firstRow >= rowsPerPage-1) firstRow -= rowsPerPage-1;
|
if (firstRow >= rowsPerPage-1) firstRow -= rowsPerPage-1;
|
||||||
else firstRow = 0;
|
else firstRow = 0;
|
||||||
break;
|
break;
|
||||||
case InputManager::ALTRIGHT:
|
case InputManager::ALTRIGHT:
|
||||||
if (firstRow + rowsPerPage*2 -1 < text->size()) {
|
if (firstRow + rowsPerPage*2 -1 < text.size()) {
|
||||||
firstRow += rowsPerPage-1;
|
firstRow += rowsPerPage-1;
|
||||||
} else {
|
} else {
|
||||||
firstRow = text->size() < rowsPerPage ?
|
firstRow = text.size() < rowsPerPage ?
|
||||||
0 : text->size() - rowsPerPage;
|
0 : text.size() - rowsPerPage;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InputManager::SETTINGS:
|
case InputManager::SETTINGS:
|
||||||
|
@ -28,17 +28,16 @@
|
|||||||
|
|
||||||
class TextDialog : protected Dialog {
|
class TextDialog : protected Dialog {
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::string> *text;
|
std::vector<std::string> text;
|
||||||
std::string title, description, icon;
|
std::string title, description, icon;
|
||||||
|
|
||||||
void preProcess();
|
void drawText(const std::vector<std::string> &text, unsigned int y,
|
||||||
void drawText(std::vector<std::string> *text, unsigned int y,
|
|
||||||
unsigned int firstRow, unsigned int rowsPerPage);
|
unsigned int firstRow, unsigned int rowsPerPage);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TextDialog(GMenu2X *gmenu2x, const std::string &title,
|
TextDialog(GMenu2X *gmenu2x, const std::string &title,
|
||||||
const std::string &description, const std::string &icon,
|
const std::string &description, const std::string &icon,
|
||||||
std::vector<std::string> *text);
|
const std::string &text);
|
||||||
void exec();
|
void exec();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,12 +29,12 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
TextManualDialog::TextManualDialog(GMenu2X *gmenu2x, const string &title, const string &icon, vector<string> *text)
|
TextManualDialog::TextManualDialog(GMenu2X *gmenu2x, const string &title, const string &icon, const string &text)
|
||||||
: TextDialog(gmenu2x,title,"",icon,text) {
|
: TextDialog(gmenu2x,title,"",icon,text) {
|
||||||
|
|
||||||
//split the text in multiple pages
|
//split the text in multiple pages
|
||||||
for (uint i=0; i<text->size(); i++) {
|
for (uint i=0; i<this->text.size(); i++) {
|
||||||
string line = trim(text->at(i));
|
string line = trim(this->text.at(i));
|
||||||
if (line[0]=='[' && line[line.length()-1]==']') {
|
if (line[0]=='[' && line[line.length()-1]==']') {
|
||||||
ManualPage mp;
|
ManualPage mp;
|
||||||
mp.title = line.substr(1,line.length()-2);
|
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"];
|
mp.title = gmenu2x->tr["Untitled"];
|
||||||
pages.push_back(mp);
|
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) {
|
if (pages.size()==0) {
|
||||||
@ -99,7 +99,7 @@ void TextManualDialog::exec() {
|
|||||||
while (!close) {
|
while (!close) {
|
||||||
bg.blit(gmenu2x->s,0,0);
|
bg.blit(gmenu2x->s,0,0);
|
||||||
writeSubTitle(pages[page].title);
|
writeSubTitle(pages[page].title);
|
||||||
drawText(&pages[page].text, 42 /* TODO */, firstRow, rowsPerPage);
|
drawText(pages[page].text, 42 /* TODO */, firstRow, rowsPerPage);
|
||||||
|
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss << page+1;
|
ss << page+1;
|
||||||
|
@ -37,7 +37,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
TextManualDialog(GMenu2X *gmenu2x, const std::string &title,
|
TextManualDialog(GMenu2X *gmenu2x, const std::string &title,
|
||||||
const std::string &icon, std::vector<std::string> *text);
|
const std::string &icon, const std::string &text);
|
||||||
void exec();
|
void exec();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user