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

Generated by doxygen