Logo
  • Main Page
  • Related Pages
  • Modules
  • Classes
  • Files

mmstextboxwidget.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2007 Stefan Schwarzer, Jens Schneider,             *
00003  *                           Matthias Hardt, Guido Madaus                  *
00004  *                                                                         *
00005  *   Copyright (C) 2007-2008 BerLinux Solutions GbR                        *
00006  *                           Stefan Schwarzer & Guido Madaus               *
00007  *                                                                         *
00008  *   Copyright (C) 2009-2013 BerLinux Solutions GmbH                       *
00009  *                                                                         *
00010  *   Authors:                                                              *
00011  *      Stefan Schwarzer   <stefan.schwarzer@diskohq.org>,                 *
00012  *      Matthias Hardt     <matthias.hardt@diskohq.org>,                   *
00013  *      Jens Schneider     <jens.schneider@diskohq.org>,                   *
00014  *      Guido Madaus       <guido.madaus@diskohq.org>,                     *
00015  *      Patrick Helterhoff <patrick.helterhoff@diskohq.org>,               *
00016  *      René Bählkow       <rene.baehlkow@diskohq.org>                     *
00017  *                                                                         *
00018  *   This library is free software; you can redistribute it and/or         *
00019  *   modify it under the terms of the GNU Lesser General Public            *
00020  *   License version 2.1 as published by the Free Software Foundation.     *
00021  *                                                                         *
00022  *   This library is distributed in the hope that it will be useful,       *
00023  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00024  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00025  *   Lesser General Public License for more details.                       *
00026  *                                                                         *
00027  *   You should have received a copy of the GNU Lesser General Public      *
00028  *   License along with this library; if not, write to the                 *
00029  *   Free Software Foundation, Inc.,                                       *
00030  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
00031  **************************************************************************/
00032 #include "mmsgui/mmstextboxwidget.h"
00033 #include "mmsgui/mmstextbase.h"
00034 #include <cstdlib>
00035 #include <vector>
00036 
00037 MMSTextBoxWidget::MMSTextBoxWidget(MMSWindow *root, string className, MMSTheme *theme) : MMSWidget() {
00038     create(root, className, theme);
00039 }
00040 
00041 MMSTextBoxWidget::~MMSTextBoxWidget() {
00042     for(vector<TEXTBOX_WORDGEOM *>::iterator it(wordgeom.begin()); it != wordgeom.end(); ++it) {
00043         delete(*it);
00044     }
00045     if (this->file) {
00046         delete this->file;
00047     }
00048 }
00049 
00050 bool MMSTextBoxWidget::create(MMSWindow *root, string className, MMSTheme *theme) {
00051     this->type = MMSWIDGETTYPE_TEXTBOX;
00052     this->className = className;
00053 
00054     // init attributes for drawable widgets
00055     this->da = new MMSWIDGET_DRAWABLE_ATTRIBUTES;
00056     if (theme) this->da->theme = theme; else this->da->theme = globalTheme;
00057     this->textBoxWidgetClass = this->da->theme->getTextBoxWidgetClass(className);
00058     this->da->baseWidgetClass = &(this->da->theme->textBoxWidgetClass.widgetClass);
00059     if (this->textBoxWidgetClass) this->da->widgetClass = &(this->textBoxWidgetClass->widgetClass); else this->da->widgetClass = NULL;
00060 
00061     // clear
00062     initLanguage();
00063     this->fontpath = "";
00064     this->fontname = "";
00065     this->fontsize = 0;
00066     this->font = NULL;
00067     this->load_font = true;
00068     this->lasttext = "";
00069     this->surfaceChanged = true;
00070     this->translated = false;
00071     this->swap_left_right = false;
00072     this->file = NULL;
00073     this->current_fgset = false;
00074 
00075     return MMSWidget::create(root, true, false, true, true, false, false, true);
00076 }
00077 
00078 MMSWidget *MMSTextBoxWidget::copyWidget() {
00079     // create widget
00080     MMSTextBoxWidget *newWidget = new MMSTextBoxWidget(this->rootwindow, className);
00081 
00082     newWidget->className = this->className;
00083     newWidget->textBoxWidgetClass = this->textBoxWidgetClass;
00084     newWidget->myTextBoxWidgetClass = this->myTextBoxWidgetClass;
00085 
00086     newWidget->lang = this->lang;
00087     newWidget->wordgeom = this->wordgeom;
00088     newWidget->lasttext = this->lasttext;
00089     newWidget->surfaceChanged = this->surfaceChanged;
00090     newWidget->translated_text = this->translated_text;
00091     newWidget->current_fgset = this->current_fgset;
00092     newWidget->current_fgcolor = this->current_fgcolor;
00093 
00094     // copy base widget
00095     MMSWidget::copyWidget((MMSWidget*)newWidget);
00096 
00097     // reload my font
00098     initLanguage(newWidget);
00099     newWidget->fontpath = "";
00100     newWidget->fontname = "";
00101     newWidget->fontsize = 0;
00102     newWidget->font = NULL;
00103     newWidget->load_font = true;
00104     if (this->rootwindow) {
00105         // load font
00106         loadFont(newWidget);
00107     }
00108 
00109     newWidget->translated = false;
00110     newWidget->swap_left_right = false;
00111 
00112     // reload my file
00113     newWidget->file = NULL;
00114     newWidget->loadFile(false);
00115 
00116     return newWidget;
00117 }
00118 
00119 
00120 void MMSTextBoxWidget::initLanguage(MMSTextBoxWidget *widget) {
00121     if (!widget) widget = this;
00122 
00123     widget->lang = (!this->rootwindow)?MMSLANG_NONE:this->rootwindow->windowmanager->getTranslator()->getTargetLang();
00124 }
00125 
00126 void MMSTextBoxWidget::loadFont(MMSTextBoxWidget *widget) {
00127     if (!this->load_font) return;
00128     if (!widget) widget = this;
00129 
00130     if (this->rootwindow) {
00131         // get font parameter
00132         widget->lang = this->rootwindow->windowmanager->getTranslator()->getTargetLang();
00133         if (widget->font) this->rootwindow->fm->releaseFont(widget->font);
00134         widget->fontpath = widget->getFontPath();
00135         widget->fontname = widget->getFontName(widget->lang);
00136         widget->fontsize = widget->getFontSize();
00137         widget->font = this->rootwindow->fm->getFont(widget->fontpath, widget->fontname, widget->fontsize);
00138         if (widget->font) widget->load_font = false;
00139 
00140         // reset last displayed text, so calcWordGeom() can do recalculation
00141         widget->lasttext = "";
00142     }
00143 }
00144 
00145 
00146 bool MMSTextBoxWidget::setSurfaceGeometry(unsigned int width, unsigned int height) {
00147     if (MMSWidget::setSurfaceGeometry(width, height)) {
00148         this->surfaceChanged = true;
00149 
00150         this->surface->lock();
00151         // set font for new surface
00152         this->surface->setFont(this->font);
00153         this->surface->unlock();
00154 
00155         return true;
00156     }
00157     return false;
00158 }
00159 
00160 
00161 bool MMSTextBoxWidget::calcWordGeom(string &text, unsigned int startWidth, unsigned int startHeight,
00162                               unsigned int *realWidth, unsigned int *realHeight,
00163                               unsigned int *scrollDX, unsigned int *scrollDY, unsigned int *lines, unsigned int *paragraphs,
00164                               bool wrap, bool splitwords, MMSALIGNMENT alignment,
00165                               unsigned int *minWidth, unsigned int *minHeight, bool force_recalc) {
00166     int fontHeight, blankWidth;
00167     unsigned int x = 0, y = 0;
00168 
00169     // init
00170     *realWidth = startWidth;
00171     *realHeight = startHeight;
00172     *lines = 0;
00173     *paragraphs = 0;
00174 
00175     // get font height
00176     this->font->getHeight(&fontHeight);
00177     *scrollDX = fontHeight;
00178     *scrollDY = fontHeight;
00179 
00180     if (minWidth)  *minWidth = 0;
00181     if (minHeight) *minHeight = 0;
00182 
00183     // has text or surface changed?
00184     if ((!force_recalc) && (text == this->lasttext) && (!this->surfaceChanged)) return false;
00185     this->lasttext = text;
00186     this->surfaceChanged = false;
00187 
00188     // clear wordgeom
00189     for (int i = (int)(this->wordgeom.size())-1; i >= 0; i--) {
00190         delete this->wordgeom.at(i);
00191         this->wordgeom.erase(this->wordgeom.end()-1);
00192     }
00193 
00194     // is text set?
00195     if (text=="")
00196         // no text, all is done
00197         return true;
00198 
00199     // get width of a blank character
00200     this->font->getStringWidth(" ", -1, &blankWidth);
00201 
00202     // through the text and extract single words
00203     int text_pos = 0;
00204     do {
00205         // index relative to text_pos where the next line feed is found
00206         size_t lfindex;
00207 
00208         // index relative to text_pos where the next blank is found
00209         size_t index;
00210 
00211         // searching for next line feed
00212         if ((lfindex = text.find('\n', text_pos)) != string::npos) lfindex-= text_pos;
00213 
00214         if (wrap) {
00215             // wrap mode, find next blank
00216             if ((index = text.find(' ', text_pos)) != string::npos) index-= text_pos;
00217         }
00218         else {
00219             // no wrap mode, no need to find blanks
00220             index = string::npos;
00221         }
00222 
00223         if (lfindex == string::npos) {
00224             // no line feed found
00225             if (index == string::npos) {
00226                 // no blank found, so we have found the very last word in the text string
00227                 index = text.size() - text_pos;
00228             }
00229             else
00230             if (index == 0) {
00231                 // another blank found instead of a word
00232                 // so we use all the blanks up to the next word as "empty word"
00233                 if ((index = text.find_first_not_of(' ', text_pos)) != string::npos) index-= text_pos;
00234                 index--;
00235                 if (index == string::npos) {
00236                     // the end of the string consists of blanks only
00237                     index = text.size() - text_pos;
00238                 }
00239             }
00240         }
00241         else {
00242             // line feed found
00243             if ((index == string::npos)||(index > lfindex)) {
00244                 // no blank before line feed, so we have found the last word in the line
00245                 // the length of the word is equal to the lfindex
00246                 index = lfindex;
00247             }
00248             else {
00249                 // blank found before next line feed
00250                 if (index == 0) {
00251                     // another blank found instead of a word
00252                     // so we use all the blanks up to the next word as "empty word"
00253                     if ((index = text.find_first_not_of(' ', text_pos)) != string::npos) index-= text_pos;
00254                     index--;
00255                 }
00256                 lfindex = string::npos;
00257             }
00258         }
00259 
00260         if (*lines == 0) {
00261             // first word
00262             *lines = 1;
00263             x = 0;
00264             y = 0;
00265         }
00266 
00267         // new word
00268         TEXTBOX_WORDGEOM *mywordgeom = new TEXTBOX_WORDGEOM;
00269         mywordgeom->geom.h = fontHeight;
00270         mywordgeom->word   = text.substr(text_pos, index);
00271 
00272         // get the width of the string
00273         this->font->getStringWidth(mywordgeom->word, -1, &mywordgeom->geom.w);
00274 
00275         if (x > 0)
00276             x += blankWidth;
00277 
00278         unsigned int endpos = x + mywordgeom->geom.w;
00279 
00280         bool gotonext = true;
00281 
00282         if ((wrap)&&(splitwords)) {
00283             // split words in wrap mode
00284             if ((index != string::npos)&&(mywordgeom->geom.w > (int)*realWidth)) {
00285                 // recalculate index
00286                 while ((index > 1)&&(mywordgeom->geom.w > (int)*realWidth)) {
00287                     index--;
00288                     mywordgeom->word = text.substr(text_pos, index);
00289                     this->font->getStringWidth(mywordgeom->word, -1, &mywordgeom->geom.w);
00290                     endpos = x + mywordgeom->geom.w;
00291                 }
00292 
00293                 // move the pos ahead
00294                 text_pos+= index;
00295                 gotonext = false;
00296             }
00297         }
00298 
00299         if ((x==0)||(endpos <= *realWidth)||(wrap==false)) {
00300             if (endpos > *realWidth) {
00301                 if (wrap==false)
00302                     *realWidth = endpos;
00303                 else {
00304                     mywordgeom->geom.w-= endpos - *realWidth;
00305                     endpos = *realWidth;
00306                 }
00307             }
00308 
00309             mywordgeom->geom.x = x;
00310             mywordgeom->geom.y = y;
00311 
00312             x = endpos;
00313 
00314             mywordgeom->line = *lines;
00315             mywordgeom->paragraph = *paragraphs;
00316         }
00317         else
00318         {
00319             x = 0;
00320             y+= fontHeight;
00321             (*lines)++;
00322 
00323             mywordgeom->geom.x = x;
00324             mywordgeom->geom.y = y;
00325 
00326             x += mywordgeom->geom.w;
00327 
00328             mywordgeom->line = *lines;
00329             mywordgeom->paragraph = *paragraphs;
00330         }
00331 
00332         if ((lfindex != string::npos)||(gotonext==false)) {
00333             x = 0;
00334             y+= fontHeight;
00335             (*lines)++;
00336             if (lfindex != string::npos) (*paragraphs)++;
00337         }
00338 
00339         if (minWidth) {
00340             if (*minWidth < (unsigned int)(mywordgeom->geom.x + mywordgeom->geom.w))
00341                 *minWidth = mywordgeom->geom.x + mywordgeom->geom.w;
00342         }
00343 
00344         if (minHeight) {
00345             if (*minHeight < (unsigned int)(mywordgeom->geom.y + mywordgeom->geom.h))
00346                 *minHeight = mywordgeom->geom.y + mywordgeom->geom.h;
00347         }
00348 
00349         // add to list
00350         wordgeom.push_back(mywordgeom);
00351 
00352         if (gotonext) {
00353             if (index + 1 < text.size() - text_pos) {
00354                 // move the pos ahead
00355                 text_pos+= index + 1;
00356             }
00357             else {
00358                 // the end reached
00359                 text_pos = (int)text.size();
00360             }
00361         }
00362     } while ((int)text.size() - text_pos > 0);
00363 
00364     // go through the list and calculate horizontal text alignment
00365     unsigned int oldline = 1;
00366     unsigned int oldpos = 0;
00367     for (unsigned int i = 0; i < wordgeom.size(); i++) {
00368         if (wordgeom.at(i)->line != oldline) {
00369             if   ((alignment == MMSALIGNMENT_CENTER)||(alignment == MMSALIGNMENT_TOP_CENTER)||(alignment == MMSALIGNMENT_BOTTOM_CENTER)) {
00370                 // horizontal centered
00371                 unsigned int diff = (*realWidth - wordgeom.at(i-1)->geom.x - wordgeom.at(i-1)->geom.w) / 2;
00372                 for (unsigned int j = oldpos; j < i; j++)
00373                     wordgeom.at(j)->geom.x += diff;
00374             }
00375             else
00376             if   ((alignment == MMSALIGNMENT_RIGHT)||(alignment == MMSALIGNMENT_TOP_RIGHT)
00377                 ||(alignment == MMSALIGNMENT_BOTTOM_RIGHT)) {
00378                 // right aligned
00379                 unsigned int diff = *realWidth - wordgeom.at(i-1)->geom.x - wordgeom.at(i-1)->geom.w;
00380                 for (unsigned int j = oldpos; j < i; j++)
00381                     wordgeom.at(j)->geom.x += diff;
00382             }
00383             else
00384             if  (((alignment == MMSALIGNMENT_JUSTIFY)||(alignment == MMSALIGNMENT_TOP_JUSTIFY)
00385                 ||(alignment == MMSALIGNMENT_BOTTOM_JUSTIFY))&&(wordgeom.at(i)->paragraph == wordgeom.at(i-1)->paragraph)) {
00386                 // justified
00387                 if (oldpos < i-1) {
00388                     unsigned int diff = ((*realWidth - wordgeom.at(i-1)->geom.x - wordgeom.at(i-1)->geom.w)*10) / (i-1-oldpos);
00389                     for (unsigned int j = oldpos + 1; j < i-1; j++) {
00390                         wordgeom.at(j)->geom.x += ((j - oldpos) * diff) / 10;
00391                     }
00392                     if (oldpos < i-1) {
00393                         // at least two words in the line, set the last word exactly to the right side
00394                         wordgeom.at(i-1)->geom.x = *realWidth - wordgeom.at(i-1)->geom.w;
00395                     }
00396                 }
00397             }
00398             oldpos = i;
00399             oldline = wordgeom.at(i)->line;
00400         }
00401     }
00402     if   ((alignment == MMSALIGNMENT_CENTER)||(alignment == MMSALIGNMENT_TOP_CENTER)||(alignment == MMSALIGNMENT_BOTTOM_CENTER)) {
00403         // horizontal centered
00404         unsigned int diff = (*realWidth - wordgeom.at(wordgeom.size()-1)->geom.x - wordgeom.at(wordgeom.size()-1)->geom.w) / 2;
00405         for (unsigned int j = oldpos; j < wordgeom.size(); j++)
00406             wordgeom.at(j)->geom.x += diff;
00407     }
00408     else
00409     if   ((alignment == MMSALIGNMENT_RIGHT)||(alignment == MMSALIGNMENT_TOP_RIGHT)
00410         ||(alignment == MMSALIGNMENT_BOTTOM_RIGHT)) {
00411         // right aligned
00412         unsigned int diff = *realWidth - wordgeom.at(wordgeom.size()-1)->geom.x - wordgeom.at(wordgeom.size()-1)->geom.w;
00413         for (unsigned int j = oldpos; j < wordgeom.size(); j++)
00414             wordgeom.at(j)->geom.x += diff;
00415     }
00416 
00417     // go through the list and calculate vertical text alignment
00418     if (fontHeight * (*lines) > *realHeight) {
00419         *realHeight = fontHeight * (*lines);
00420     } else if (fontHeight * (*lines) < *realHeight) {
00421         if   ((alignment == MMSALIGNMENT_CENTER)||(alignment == MMSALIGNMENT_LEFT)
00422             ||(alignment == MMSALIGNMENT_RIGHT)||(alignment == MMSALIGNMENT_JUSTIFY)) {
00423             // vertical centered
00424             unsigned int diff = (*realHeight - fontHeight * (*lines)) / 2;
00425             if (diff > 0) {
00426                     for (unsigned int i = 0; i < wordgeom.size(); i++)
00427                         wordgeom.at(i)->geom.y += diff;
00428             }
00429         }
00430         else
00431         if   ((alignment == MMSALIGNMENT_BOTTOM_CENTER)||(alignment == MMSALIGNMENT_BOTTOM_LEFT)
00432             ||(alignment == MMSALIGNMENT_BOTTOM_RIGHT)||(alignment == MMSALIGNMENT_BOTTOM_JUSTIFY)) {
00433             // bottom aligned
00434             unsigned int diff = (*realHeight - fontHeight * (*lines));
00435             if (diff > 0)
00436                 for (unsigned int i = 0; i < wordgeom.size(); i++)
00437                     wordgeom.at(i)->geom.y += diff;
00438         }
00439     }
00440     if(this->swap_left_right) {
00441         /* quick fix line ordering... that is not yet the real deal!!!! */
00442         std::vector<int> mylines;
00443         int linepos = (*wordgeom.begin())->geom.y;
00444         mylines.push_back(linepos);
00445         for (unsigned int i = 0; i < wordgeom.size(); i++) {
00446             if(linepos != wordgeom.at(i)->geom.y) {
00447                 linepos = wordgeom.at(i)->geom.y;
00448                 mylines.push_back(linepos);
00449             }
00450         }
00451         for(vector<int>::iterator it = mylines.begin(); it != mylines.end(); it++) {
00452             printf("%d\n", *it);
00453         }
00454 
00455         linepos = (*wordgeom.begin())->geom.y;
00456         vector<int>::reverse_iterator it = mylines.rbegin();
00457         for (unsigned int i = 0; i < wordgeom.size(); i++) {
00458             if(linepos != wordgeom.at(i)->geom.y) {
00459                 linepos = wordgeom.at(i)->geom.y;
00460                 it++;
00461             }
00462             wordgeom.at(i)->geom.y = *it;
00463         }
00464 
00465     }
00466 
00467 
00468 
00469     return true;
00470 }
00471 
00472 
00473 bool MMSTextBoxWidget::init() {
00474     // init widget basics
00475     if (!MMSWidget::init())
00476         return false;
00477 
00478     // init language
00479     initLanguage();
00480 
00481     // load font
00482     loadFont();
00483 
00484     // load file
00485     this->loadFile(false);
00486 
00487     return true;
00488 }
00489 
00490 bool MMSTextBoxWidget::release() {
00491     // release widget basics
00492     if (!MMSWidget::release())
00493         return false;
00494 
00495     // release my font
00496     this->rootwindow->fm->releaseFont(this->font);
00497     this->fontpath = "";
00498     this->fontname = "";
00499     this->fontsize = 0;
00500     this->font = NULL;
00501     this->load_font = true;
00502 
00503     return true;
00504 }
00505 
00506 
00507 bool MMSTextBoxWidget::prepareText(int *width, int *height, bool recalc) {
00508     // check if we have to (re)load the font
00509     this->surface->lock();
00510     loadFont();
00511 
00512     if (!this->font) {
00513         this->surface->unlock();
00514         return false;
00515     }
00516 
00517     // font available, use it for this surface
00518     this->surface->setFont(this->font);
00519     this->surface->unlock();
00520 
00521     if (!this->translated) {
00522         // text changed and have to be translated
00523         if ((this->rootwindow)&&(this->rootwindow->windowmanager)&&(getTranslate())) {
00524             // translate text
00525             string source;
00526             getText(source);
00527             this->rootwindow->windowmanager->getTranslator()->translate(source, this->translated_text);
00528         }
00529         else {
00530             // text can not or should not translated
00531             getText(this->translated_text);
00532         }
00533 
00534         // reset swap flag
00535         this->swap_left_right = false;
00536 
00537         // language specific conversions
00538         MMSLanguage targetlang = this->rootwindow->windowmanager->getTranslator()->getTargetLang();
00539         if (((targetlang == MMSLANG_IL) || (targetlang == MMSLANG_AR)) && getTranslate()) {
00540             if (convBidiString(this->translated_text, this->translated_text, (targetlang == MMSLANG_AR) ? true : false)) {
00541                 // bidirectional conversion successful, swap alignment horizontal
00542                 this->swap_left_right = true;
00543             }
00544         }
00545 
00546         // mark as translated
00547         this->translated = true;
00548     }
00549 
00550     if (!this->minmax_set) {
00551         // calculate text and surface size
00552         unsigned int realWidth, realHeight, scrollDX, scrollDY, lines, paragraphs;
00553         if (calcWordGeom(this->translated_text, getInnerGeometry().w, getInnerGeometry().h, &realWidth, &realHeight, &scrollDX, &scrollDY,
00554                          &lines, &paragraphs, getWrap(), getSplitWords(),
00555                          (!this->swap_left_right) ? getAlignment() : swapAlignmentHorizontal(getAlignment()))) {
00556             // text has changed, reset something
00557             setScrollSize(scrollDX, scrollDY);
00558             setSurfaceGeometry(realWidth, realHeight);
00559         }
00560     }
00561     else {
00562         // get maximum width and height of the textbox
00563         int maxWidth = getMaxWidthPix();
00564         if (maxWidth <= 0) maxWidth = getInnerGeometry().w;
00565         int maxHeight = getMaxHeightPix();
00566         if (maxHeight <= 0) maxHeight = getInnerGeometry().h;
00567 
00568         // calculate dynamic textbox size
00569         if (recalc) {
00570             unsigned int realWidth, realHeight, scrollDX, scrollDY, lines, paragraphs, minWidth, minHeight;
00571             if (calcWordGeom(this->translated_text,
00572                                 maxWidth, maxHeight,
00573                                 &realWidth, &realHeight, &scrollDX, &scrollDY,
00574                                 &lines, &paragraphs, getWrap(), getSplitWords(),
00575                                 (!this->swap_left_right) ? getAlignment() : swapAlignmentHorizontal(getAlignment()),
00576                                 &minWidth, &minHeight, true)) {
00577                 // text has changed, reset something
00578 //              setScrollSize(scrollDX, scrollDY);
00579 //              setSurfaceGeometry(realWidth, realHeight);
00580 
00581 
00582                 if ((int)minWidth < getMinWidthPix())
00583                     minWidth = getMinWidthPix();
00584                 if ((int)minHeight < getMinHeightPix())
00585                     minHeight = getMinHeightPix();
00586 
00587                 if ((int)minWidth < maxWidth || (int)minHeight < maxHeight) {
00588                     calcWordGeom(this->translated_text,
00589                                     ((int)minWidth < maxWidth) ? minWidth : maxWidth,
00590                                     ((int)minHeight < maxHeight) ? minHeight : maxHeight,
00591                                     &realWidth, &realHeight, &scrollDX, &scrollDY,
00592                                     &lines, &paragraphs, getWrap(), getSplitWords(),
00593                                     (!this->swap_left_right) ? getAlignment() : swapAlignmentHorizontal(getAlignment()),
00594                                     &minWidth, &minHeight, true);
00595                 }
00596 
00597 
00598                 if (width) {
00599                     if (realWidth < minWidth)
00600                         *width = minWidth;
00601                     else
00602                     if ((int)realWidth > maxWidth)
00603                         *width = maxWidth;
00604                     else
00605                         *width = realWidth;
00606 
00607                     if (*width <= 0) *width = 1;
00608                 }
00609 
00610                 if (height) {
00611                     if (realHeight < minHeight)
00612                         *height = minHeight;
00613                     else
00614                     if ((int)realHeight > maxHeight)
00615                         *height = maxHeight;
00616                     else
00617                         *height = realHeight;
00618 
00619                     if (*height <= 0) *height = 1;
00620                 }
00621             }
00622         }
00623         else {
00624             unsigned int realWidth, realHeight, scrollDX, scrollDY, lines, paragraphs;
00625             if (calcWordGeom(this->translated_text, getInnerGeometry().w, getInnerGeometry().h, &realWidth, &realHeight, &scrollDX, &scrollDY,
00626                              &lines, &paragraphs, getWrap(), getSplitWords(),
00627                              (!this->swap_left_right) ? getAlignment() : swapAlignmentHorizontal(getAlignment()))) {
00628                 // text has changed, reset something
00629                 setScrollSize(scrollDX, scrollDY);
00630                 setSurfaceGeometry(realWidth, realHeight);
00631             }
00632         }
00633 
00634 
00635     }
00636 
00637     return true;
00638 }
00639 
00640 
00641 void MMSTextBoxWidget::calcContentSize() {
00642     int width, height;
00643 
00644     if (prepareText(&width, &height, true)) {
00645         // text is translated and font is set
00646         setContentSize(width, height);
00647     }
00648 }
00649 
00650 
00651 void MMSTextBoxWidget::getForeground(MMSFBColor *color) {
00652     color->a = 0;
00653 
00654     if (isActivated()) {
00655         if (isSelected()) {
00656             *color = getSelColor();
00657         }
00658         else {
00659             *color = getColor();
00660         }
00661         if (isPressed()) {
00662             MMSFBColor mycol;
00663             if (isSelected()) {
00664                 mycol = getSelColor_p();
00665                 if (mycol.a>0) *color=mycol;
00666             }
00667             else {
00668                 mycol = getColor_p();
00669                 if (mycol.a>0) *color=mycol;
00670             }
00671         }
00672     }
00673     else {
00674         if (isSelected()) {
00675             *color = getSelColor_i();
00676         }
00677         else {
00678             *color = getColor_i();
00679         }
00680     }
00681 }
00682 
00683 bool MMSTextBoxWidget::enableRefresh(bool enable) {
00684     if (!MMSWidget::enableRefresh(enable)) return false;
00685 
00686     // mark foreground as not set
00687     this->current_fgset = false;
00688 
00689     return true;
00690 }
00691 
00692 bool MMSTextBoxWidget::checkRefreshStatus() {
00693     if (MMSWidget::checkRefreshStatus()) return true;
00694 
00695     if (this->current_fgset) {
00696         // current foreground initialized
00697         MMSFBColor color;
00698         getForeground(&color);
00699 
00700         if (color == this->current_fgcolor) {
00701             // foreground color not changed, so we do not enable refreshing
00702             return false;
00703         }
00704     }
00705 
00706     // (re-)enable refreshing
00707     enableRefresh();
00708 
00709     return true;
00710 }
00711 
00712 
00713 bool MMSTextBoxWidget::draw(bool *backgroundFilled) {
00714     bool myBackgroundFilled = false;
00715 
00716     if (!this->initialized) {
00717         // init widget (e.g. load images, fonts, ...)
00718         init();
00719         this->initialized = true;
00720     }
00721 
00722     if(!surface)
00723         return false;
00724 
00725     if (backgroundFilled) {
00726         if (this->has_own_surface)
00727             *backgroundFilled = false;
00728     }
00729     else
00730         backgroundFilled = &myBackgroundFilled;
00731 
00732     // lock
00733     this->surface->lock();
00734 
00735     // draw widget basics
00736     if (MMSWidget::draw(backgroundFilled)) {
00737 
00738         // draw my things
00739         if (prepareText(NULL, NULL)) {
00740             // text is translated and font is set
00741             MMSFBRectangle surfaceGeom = getSurfaceGeometry();
00742 
00743             // get color
00744             MMSFBColor color;
00745             getForeground(&color);
00746             this->current_fgcolor   = color;
00747             this->current_fgset     = true;
00748 
00749             if (color.a) {
00750                 // prepare for drawing
00751                 this->surface->setDrawingColorAndFlagsByBrightnessAndOpacity(
00752                                     color,
00753                                     (isSelected())?getSelShadowColor(MMSPOSITION_TOP):getShadowColor(MMSPOSITION_TOP),
00754                                     (isSelected())?getSelShadowColor(MMSPOSITION_BOTTOM):getShadowColor(MMSPOSITION_BOTTOM),
00755                                     (isSelected())?getSelShadowColor(MMSPOSITION_LEFT):getShadowColor(MMSPOSITION_LEFT),
00756                                     (isSelected())?getSelShadowColor(MMSPOSITION_RIGHT):getShadowColor(MMSPOSITION_RIGHT),
00757                                     (isSelected())?getSelShadowColor(MMSPOSITION_TOP_LEFT):getShadowColor(MMSPOSITION_TOP_LEFT),
00758                                     (isSelected())?getSelShadowColor(MMSPOSITION_TOP_RIGHT):getShadowColor(MMSPOSITION_TOP_RIGHT),
00759                                     (isSelected())?getSelShadowColor(MMSPOSITION_BOTTOM_LEFT):getShadowColor(MMSPOSITION_BOTTOM_LEFT),
00760                                     (isSelected())?getSelShadowColor(MMSPOSITION_BOTTOM_RIGHT):getShadowColor(MMSPOSITION_BOTTOM_RIGHT),
00761                                     getBrightness(), getOpacity());
00762 
00763                 // draw single words into surface
00764                 for (unsigned int i = 0; i < this->wordgeom.size(); i++) {
00765                     if (this->has_own_surface) {
00766                         this->surface->drawString(this->wordgeom.at(i)->word, -1,
00767                                                   surfaceGeom.x + this->wordgeom.at(i)->geom.x,
00768                                                   surfaceGeom.y + this->wordgeom.at(i)->geom.y);
00769                     }
00770                     else {
00771                         this->surface->drawString(this->wordgeom.at(i)->word, -1,
00772                                                   surfaceGeom.x + this->wordgeom.at(i)->geom.x - this->da->scrollPosX,
00773                                                   surfaceGeom.y + this->wordgeom.at(i)->geom.y - this->da->scrollPosY);
00774                     }
00775                 }
00776             }
00777         }
00778 
00779         // update window surface with an area of surface
00780         updateWindowSurfaceWithSurface(!*backgroundFilled);
00781     }
00782 
00783     // unlock
00784     this->surface->unlock();
00785 
00786     // draw widgets debug frame
00787     return MMSWidget::drawDebug();
00788 }
00789 
00790 void MMSTextBoxWidget::targetLangChanged(MMSLanguage lang) {
00791     this->translated = false;
00792     this->load_font = true;
00793     loadFont();
00794 
00795     // recalculate content size for dynamic widgets, because new language can result in new widget size
00796     // note: DO NOT REFRESH at this point
00797     recalcContentSize(false);
00798 }
00799 
00800 bool MMSTextBoxWidget::loadFile(bool refresh) {
00801     if (this->file) {
00802         // free the "old" file
00803         delete this->file;
00804         this->file = NULL;
00805     }
00806 
00807     // create new file instance
00808     this->file = new MMSFile(getFilePath() + "/" + getFileName());
00809     if (!this->file)
00810         return false;
00811     if (this->file->getLastError())
00812         return false;
00813 
00814     // read the file
00815     void *ptr;
00816     size_t ritems;
00817     if (!this->file->readBufferEx(&ptr, &ritems)) {
00818         delete this->file;
00819         this->file = NULL;
00820         return false;
00821     }
00822 
00823     // free old text to save memory
00824     setText("", false);
00825 
00826     // fill the text
00827     string text;
00828     text.insert(0, (const char *)ptr, ritems);
00829     setText(&text, refresh);
00830 
00831     // free buffer
00832     free(ptr);
00833 
00834     return true;
00835 }
00836 
00837 bool MMSTextBoxWidget::reloadFile() {
00838     return loadFile(true);
00839 }
00840 
00841 
00842 /***********************************************/
00843 /* begin of theme access methods (get methods) */
00844 /***********************************************/
00845 
00846 #define GETTEXTBOX(x) \
00847     if (this->myTextBoxWidgetClass.is##x()) return myTextBoxWidgetClass.get##x(); \
00848     else if ((textBoxWidgetClass)&&(textBoxWidgetClass->is##x())) return textBoxWidgetClass->get##x(); \
00849     else return this->da->theme->textBoxWidgetClass.get##x();
00850 
00851 #define GETTEXTBOX2(x, y) \
00852     if (this->myTextBoxWidgetClass.is##x()) y=myTextBoxWidgetClass.get##x(); \
00853     else if ((textBoxWidgetClass)&&(textBoxWidgetClass->is##x())) y=textBoxWidgetClass->get##x(); \
00854     else y=this->da->theme->textBoxWidgetClass.get##x();
00855 
00856 #define GETTEXTBOXFONT(lang) \
00857     if (this->myTextBoxWidgetClass.isFontName(lang)) return myTextBoxWidgetClass.getFontName(lang); \
00858     else if (this->myTextBoxWidgetClass.isFontName(MMSLANG_NONE)) return myTextBoxWidgetClass.getFontName(MMSLANG_NONE); \
00859     else if ((textBoxWidgetClass)&&(textBoxWidgetClass->isFontName(lang))) return textBoxWidgetClass->getFontName(lang); \
00860     else if ((textBoxWidgetClass)&&(textBoxWidgetClass->isFontName(MMSLANG_NONE))) return textBoxWidgetClass->getFontName(MMSLANG_NONE); \
00861     else return this->da->theme->textBoxWidgetClass.getFontName();
00862 
00863 #define GETTEXTBOXSHADOW(x) \
00864     if (this->myTextBoxWidgetClass.isShadowColor(x)) return myTextBoxWidgetClass.getShadowColor(x); \
00865     else if ((textBoxWidgetClass)&&(textBoxWidgetClass->isShadowColor(x))) return textBoxWidgetClass->getShadowColor(x); \
00866     else return this->da->theme->textBoxWidgetClass.getShadowColor(x);
00867 
00868 #define GETTEXTBOXSHADOWSEL(x) \
00869     if (this->myTextBoxWidgetClass.isSelShadowColor(x)) return myTextBoxWidgetClass.getSelShadowColor(x); \
00870     else if ((textBoxWidgetClass)&&(textBoxWidgetClass->isSelShadowColor(x))) return textBoxWidgetClass->getSelShadowColor(x); \
00871     else return this->da->theme->textBoxWidgetClass.getSelShadowColor(x);
00872 
00873 string MMSTextBoxWidget::getFontPath() {
00874     GETTEXTBOX(FontPath);
00875 }
00876 
00877 string MMSTextBoxWidget::getFontName(MMSLanguage lang) {
00878     GETTEXTBOXFONT(lang);
00879 }
00880 
00881 unsigned int MMSTextBoxWidget::getFontSize() {
00882     GETTEXTBOX(FontSize);
00883 }
00884 
00885 MMSALIGNMENT MMSTextBoxWidget::getAlignment() {
00886     GETTEXTBOX(Alignment);
00887 }
00888 
00889 bool MMSTextBoxWidget::getWrap() {
00890     GETTEXTBOX(Wrap);
00891 }
00892 
00893 bool MMSTextBoxWidget::getSplitWords() {
00894     GETTEXTBOX(SplitWords);
00895 }
00896 
00897 MMSFBColor MMSTextBoxWidget::getColor() {
00898     GETTEXTBOX(Color);
00899 }
00900 
00901 MMSFBColor MMSTextBoxWidget::getSelColor() {
00902     GETTEXTBOX(SelColor);
00903 }
00904 
00905 MMSFBColor MMSTextBoxWidget::getColor_p() {
00906     GETTEXTBOX(Color_p);
00907 }
00908 
00909 MMSFBColor MMSTextBoxWidget::getSelColor_p() {
00910     GETTEXTBOX(SelColor_p);
00911 }
00912 
00913 MMSFBColor MMSTextBoxWidget::getColor_i() {
00914     GETTEXTBOX(Color_i);
00915 }
00916 
00917 MMSFBColor MMSTextBoxWidget::getSelColor_i() {
00918     GETTEXTBOX(SelColor_i);
00919 }
00920 
00921 string MMSTextBoxWidget::getText() {
00922     GETTEXTBOX(Text);
00923 }
00924 
00925 void MMSTextBoxWidget::getText(string &text) {
00926     GETTEXTBOX2(Text, text);
00927 }
00928 
00929 bool MMSTextBoxWidget::getTranslate() {
00930     GETTEXTBOX(Translate);
00931 }
00932 
00933 string MMSTextBoxWidget::getFilePath() {
00934     GETTEXTBOX(FilePath);
00935 }
00936 
00937 string MMSTextBoxWidget::getFileName() {
00938     GETTEXTBOX(FileName);
00939 }
00940 
00941 MMSFBColor MMSTextBoxWidget::getShadowColor(MMSPOSITION position) {
00942     GETTEXTBOXSHADOW(position);
00943 }
00944 
00945 MMSFBColor MMSTextBoxWidget::getSelShadowColor(MMSPOSITION position) {
00946     GETTEXTBOXSHADOWSEL(position);
00947 }
00948 
00949 /***********************************************/
00950 /* begin of theme access methods (set methods) */
00951 /***********************************************/
00952 
00953 void MMSTextBoxWidget::setFontPath(string fontpath, bool load, bool refresh) {
00954     myTextBoxWidgetClass.setFontPath(fontpath);
00955     if (load) {
00956         this->load_font = true;
00957         loadFont();
00958     }
00959 
00960     // refresh is required
00961     enableRefresh();
00962 
00963     this->refresh(refresh);
00964 }
00965 
00966 void MMSTextBoxWidget::setFontName(MMSLanguage lang, string fontname, bool load, bool refresh) {
00967     myTextBoxWidgetClass.setFontName(fontname, lang);
00968     if (load) {
00969         this->load_font = true;
00970         loadFont();
00971     }
00972 
00973     // refresh is required
00974     enableRefresh();
00975 
00976     this->refresh(refresh);
00977 }
00978 
00979 void MMSTextBoxWidget::setFontName(string fontname, bool load, bool refresh) {
00980     setFontName(MMSLANG_NONE, fontname, load, refresh);
00981 }
00982 
00983 void MMSTextBoxWidget::setFontSize(unsigned int fontsize, bool load, bool refresh) {
00984     myTextBoxWidgetClass.setFontSize(fontsize);
00985     if (load) {
00986         this->load_font = true;
00987         loadFont();
00988     }
00989 
00990     // refresh is required
00991     enableRefresh();
00992 
00993     this->refresh(refresh);
00994 }
00995 
00996 void MMSTextBoxWidget::setFont(MMSLanguage lang, string fontpath, string fontname, unsigned int fontsize, bool load, bool refresh) {
00997     myTextBoxWidgetClass.setFontPath(fontpath);
00998     myTextBoxWidgetClass.setFontName(fontname, lang);
00999     myTextBoxWidgetClass.setFontSize(fontsize);
01000     if (load) {
01001         this->load_font = true;
01002         loadFont();
01003     }
01004 
01005     // refresh is required
01006     enableRefresh();
01007 
01008     this->refresh(refresh);
01009 }
01010 
01011 void MMSTextBoxWidget::setFont(string fontpath, string fontname, unsigned int fontsize, bool load, bool refresh) {
01012     setFont(MMSLANG_NONE, fontpath, fontname, fontsize, load, refresh);
01013 }
01014 
01015 void MMSTextBoxWidget::setAlignment(MMSALIGNMENT alignment, bool refresh) {
01016     myTextBoxWidgetClass.setAlignment(alignment);
01017 
01018     // refresh is required
01019     enableRefresh();
01020 
01021     this->refresh(refresh);
01022 }
01023 
01024 void MMSTextBoxWidget::setWrap(bool wrap, bool refresh) {
01025     myTextBoxWidgetClass.setWrap(wrap);
01026 
01027     // refresh is required
01028     enableRefresh();
01029 
01030     this->refresh(refresh);
01031 }
01032 
01033 void MMSTextBoxWidget::setSplitWords(bool splitwords, bool refresh) {
01034     myTextBoxWidgetClass.setSplitWords(splitwords);
01035 
01036     // refresh is required
01037     enableRefresh();
01038 
01039     this->refresh(refresh);
01040 }
01041 
01042 void MMSTextBoxWidget::setColor(MMSFBColor color, bool refresh) {
01043     myTextBoxWidgetClass.setColor(color);
01044 
01045     // refresh required?
01046     enableRefresh((color != this->current_fgcolor));
01047 
01048     this->refresh(refresh);
01049 }
01050 
01051 void MMSTextBoxWidget::setSelColor(MMSFBColor selcolor, bool refresh) {
01052     myTextBoxWidgetClass.setSelColor(selcolor);
01053 
01054     // refresh required?
01055     enableRefresh((selcolor != this->current_fgcolor));
01056 
01057     this->refresh(refresh);
01058 }
01059 
01060 void MMSTextBoxWidget::setColor_p(MMSFBColor color_p, bool refresh) {
01061     myTextBoxWidgetClass.setColor_p(color_p);
01062 
01063     // refresh required?
01064     enableRefresh((color_p != this->current_fgcolor));
01065 
01066     this->refresh(refresh);
01067 }
01068 
01069 void MMSTextBoxWidget::setSelColor_p(MMSFBColor selcolor_p, bool refresh) {
01070     myTextBoxWidgetClass.setSelColor_p(selcolor_p);
01071 
01072     // refresh required?
01073     enableRefresh((selcolor_p != this->current_fgcolor));
01074 
01075     this->refresh(refresh);
01076 }
01077 
01078 void MMSTextBoxWidget::setColor_i(MMSFBColor color_i, bool refresh) {
01079     myTextBoxWidgetClass.setColor_i(color_i);
01080 
01081     // refresh required?
01082     enableRefresh((color_i != this->current_fgcolor));
01083 
01084     this->refresh(refresh);
01085 }
01086 
01087 void MMSTextBoxWidget::setSelColor_i(MMSFBColor selcolor_i, bool refresh) {
01088     myTextBoxWidgetClass.setSelColor_i(selcolor_i);
01089 
01090     // refresh required?
01091     enableRefresh((selcolor_i != this->current_fgcolor));
01092 
01093     this->refresh(refresh);
01094 }
01095 
01096 
01097 void MMSTextBoxWidget::setText(string *text, bool refresh) {
01098     myTextBoxWidgetClass.setText(text);
01099     this->translated = false;
01100     this->da->scrollPosX=0;
01101     this->da->scrollPosY=0;
01102 
01103     // refresh is required
01104     enableRefresh();
01105 
01106     this->refresh(refresh);
01107 }
01108 
01109 void MMSTextBoxWidget::setText(string text, bool refresh) {
01110     setText(&text, refresh);
01111 }
01112 
01113 void MMSTextBoxWidget::setTranslate(bool translate, bool refresh) {
01114     myTextBoxWidgetClass.setTranslate(translate);
01115     this->translated = false;
01116 
01117     // refresh is required
01118     enableRefresh();
01119 
01120     this->refresh(refresh);
01121 }
01122 
01123 void MMSTextBoxWidget::setFilePath(string filepath, bool load, bool refresh) {
01124     myTextBoxWidgetClass.setFilePath(filepath);
01125     if (load)
01126         loadFile(false);
01127 
01128     // refresh is required
01129     enableRefresh();
01130 
01131     this->refresh(refresh);
01132 }
01133 
01134 void MMSTextBoxWidget::setFileName(string filename, bool load, bool refresh) {
01135     myTextBoxWidgetClass.setFileName(filename);
01136     if (load)
01137         loadFile(false);
01138 
01139     // refresh is required
01140     enableRefresh();
01141 
01142     this->refresh(refresh);
01143 }
01144 
01145 void MMSTextBoxWidget::setShadowColor(MMSPOSITION position, MMSFBColor color, bool refresh) {
01146     myTextBoxWidgetClass.setShadowColor(position, color);
01147 
01148     // refresh is required
01149     enableRefresh();
01150 
01151     this->refresh(refresh);
01152 }
01153 
01154 void MMSTextBoxWidget::setSelShadowColor(MMSPOSITION position, MMSFBColor selcolor, bool refresh) {
01155     myTextBoxWidgetClass.setSelShadowColor(position, selcolor);
01156 
01157     // refresh is required
01158     enableRefresh();
01159 
01160     this->refresh(refresh);
01161 }
01162 
01163 
01164 void MMSTextBoxWidget::updateFromThemeClass(MMSTextBoxWidgetClass *themeClass) {
01165 
01166     // update widget-specific settings
01167     if (themeClass->isWrap())
01168         setWrap(themeClass->getWrap());
01169     if (themeClass->isSplitWords())
01170         setSplitWords(themeClass->getSplitWords());
01171     if (themeClass->isTranslate())
01172         setTranslate(themeClass->getTranslate());
01173     if (themeClass->isFilePath())
01174         setFilePath(themeClass->getFilePath());
01175     if (themeClass->isFileName())
01176         setFileName(themeClass->getFileName());
01177 
01178     // update base text-specific settings
01179     MMSTEXTBASE_UPDATE_FROM_THEME_CLASS(this, themeClass);
01180 
01181     // update general widget settings
01182     MMSWidget::updateFromThemeClass(&(themeClass->widgetClass));
01183 }
01184 
01185 /***********************************************/
01186 /* end of theme access methods                 */
01187 /***********************************************/

Generated by doxygen