MyGUI  3.2.0
MyGUI_TextView.cpp
Go to the documentation of this file.
00001 
00006 /*
00007     This file is part of MyGUI.
00008 
00009     MyGUI is free software: you can redistribute it and/or modify
00010     it under the terms of the GNU Lesser General Public License as published by
00011     the Free Software Foundation, either version 3 of the License, or
00012     (at your option) any later version.
00013 
00014     MyGUI is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00021 */
00022 #include "MyGUI_Precompiled.h"
00023 #include "MyGUI_TextView.h"
00024 
00025 namespace MyGUI
00026 {
00027 
00028     class RollBackPoint
00029     {
00030     public:
00031         RollBackPoint() :
00032             position(0),
00033             count(0),
00034             lenght(0),
00035             rollback(false)
00036         {
00037         }
00038 
00039         void set(size_t _position, UString::const_iterator& _space_point, size_t _count, int _length)
00040         {
00041             position = _position;
00042             space_point = _space_point;
00043             count = _count;
00044             lenght = _length;
00045             rollback = true;
00046         }
00047 
00048         void clear()
00049         {
00050             rollback = false;
00051         }
00052 
00053         bool empty() const
00054         {
00055             return !rollback;
00056         }
00057 
00058         int getLenght() const
00059         {
00060             MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
00061             return lenght;
00062         }
00063 
00064         size_t getCount() const
00065         {
00066             MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
00067             return count;
00068         }
00069 
00070         size_t getPosition() const
00071         {
00072             MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
00073             return position;
00074         }
00075 
00076         UString::const_iterator getTextIter() const
00077         {
00078             MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
00079             return space_point;
00080         }
00081 
00082     private:
00083         size_t position;
00084         UString::const_iterator space_point;
00085         size_t count;
00086         int lenght;
00087         bool rollback;
00088     };
00089 
00090     TextView::TextView() :
00091         mLength(0),
00092         mFontHeight(0)
00093     {
00094     }
00095 
00096     void TextView::update(const UString& _text, IFont* _font, int _height, Align _align, VertexColourType _format, int _maxheight)
00097     {
00098         mFontHeight = _height;
00099 
00100         // массив для быстрой конвертации цветов
00101         static const char convert_colour[64] =
00102         {
00103             0,  1,  2,  3,  4,  5,  6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
00104             0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00105             0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00106             0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0
00107         };
00108 
00109         mViewSize.clear();
00110 
00111         RollBackPoint roll_back;
00112         IntSize result;
00113         int width = 0;
00114         size_t count = 0;
00115         mLength = 0;
00116         mLineInfo.clear();
00117         LineInfo line_info;
00118         int font_height = _font->getDefaultHeight();
00119 
00120         UString::const_iterator end = _text.end();
00121         UString::const_iterator index = _text.begin();
00122 
00123         /*if (index == end)
00124             return;*/
00125 
00126         result.height += _height;
00127 
00128         for (; index != end; ++index)
00129         {
00130             Char character = *index;
00131 
00132             // новая строка
00133             if (character == FontCodeType::CR
00134                 || character == FontCodeType::NEL
00135                 || character == FontCodeType::LF)
00136             {
00137                 if (character == FontCodeType::CR)
00138                 {
00139                     UString::const_iterator peeki = index;
00140                     ++peeki;
00141                     if ((peeki != end) && (*peeki == FontCodeType::LF))
00142                         index = peeki; // skip both as one newline
00143                 }
00144 
00145                 line_info.width = width;
00146                 line_info.count = count;
00147                 mLength += line_info.count + 1;
00148 
00149                 result.height += _height;
00150                 if (result.width < width)
00151                     result.width = width;
00152                 width = 0;
00153                 count = 0;
00154 
00155                 mLineInfo.push_back(line_info);
00156                 line_info.clear();
00157 
00158                 // отменяем откат
00159                 roll_back.clear();
00160 
00161                 continue;
00162             }
00163             // тег
00164             else if (character == L'#')
00165             {
00166                 // берем следующий символ
00167                 ++ index;
00168                 if (index == end)
00169                 {
00170                     --index;    // это защита
00171                     continue;
00172                 }
00173 
00174                 character = *index;
00175                 // если два подряд, то рисуем один шарп, если нет то меняем цвет
00176                 if (character != L'#')
00177                 {
00178                     // парсим первый символ
00179                     uint32 colour = convert_colour[(character-48) & 0x3F];
00180 
00181                     // и еще пять символов после шарпа
00182                     for (char i = 0; i < 5; i++)
00183                     {
00184                         ++ index;
00185                         if (index == end)
00186                         {
00187                             --index;    // это защита
00188                             continue;
00189                         }
00190                         colour <<= 4;
00191                         colour += convert_colour[ ((*index) - 48) & 0x3F ];
00192                     }
00193 
00194                     // если нужно, то меняем красный и синий компоненты
00195                     texture_utility::convertColour(colour, _format);
00196 
00197                     line_info.simbols.push_back( CharInfo(colour) );
00198 
00199                     continue;
00200                 }
00201             }
00202 
00203             GlyphInfo* info = _font->getGlyphInfo(character);
00204             if (FontCodeType::Space == character)
00205             {
00206                 roll_back.set(line_info.simbols.size(), index, count, width);
00207             }
00208             else if (FontCodeType::Tab == character)
00209             {
00210                 roll_back.set(line_info.simbols.size(), index, count, width);
00211             }
00212 
00213             int char_width = info->width;
00214             if (font_height != _height)
00215             {
00216                 char_width = char_width * _height / font_height;
00217                 if (!char_width) char_width = 1;
00218             }
00219 
00220             // перенос слов
00221             if (_maxheight != -1
00222                 && (width + char_width) > _maxheight
00223                 && !roll_back.empty())
00224             {
00225                 // откатываем до последнего пробела
00226                 width = roll_back.getLenght();
00227                 count = roll_back.getCount();
00228                 index = roll_back.getTextIter();
00229                 line_info.simbols.erase(line_info.simbols.begin() + roll_back.getPosition(), line_info.simbols.end());
00230 
00231                 // запоминаем место отката, как полную строку
00232                 line_info.width = width;
00233                 line_info.count = count;
00234                 mLength += line_info.count + 1;
00235 
00236                 result.height += _height;
00237                 if (result.width < width)
00238                     result.width = width;
00239                 width = 0;
00240                 count = 0;
00241 
00242                 mLineInfo.push_back(line_info);
00243                 line_info.clear();
00244 
00245                 // отменяем откат
00246                 roll_back.clear();
00247 
00248                 continue;
00249             }
00250 
00251             line_info.simbols.push_back(CharInfo(info->uvRect, char_width));
00252             width += char_width;
00253             count ++;
00254         }
00255 
00256         line_info.width = width;
00257         line_info.count = count;
00258         mLength += line_info.count;
00259 
00260         mLineInfo.push_back(line_info);
00261 
00262         if (result.width < width)
00263             result.width = width;
00264 
00265         // теперь выравниванием строки
00266         for (VectorLineInfo::iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
00267         {
00268             if (_align.isRight())
00269                 line->offset = result.width - line->width;
00270             else if (_align.isHCenter())
00271                 line->offset = (result.width - line->width) / 2;
00272         }
00273 
00274         mViewSize = result;
00275     }
00276 
00277     size_t TextView::getCursorPosition(const IntPoint& _value)
00278     {
00279         const int height = mFontHeight;
00280         size_t result = 0;
00281         int top = 0;
00282 
00283         for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
00284         {
00285             // это последняя строка
00286             bool lastline = !(line + 1 != mLineInfo.end());
00287 
00288             // наша строчка
00289             if (top + height > _value.top || lastline)
00290             {
00291                 top += height;
00292                 int left = line->offset;
00293                 int count = 0;
00294 
00295                 // ищем символ
00296                 for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
00297                 {
00298                     if (sim->isColour())
00299                         continue;
00300 
00301                     if ((left + (sim->getWidth() / 2)) > _value.left)
00302                     {
00303                         break;
00304                     }
00305                     left += sim->getWidth();
00306                     count ++;
00307                 }
00308 
00309                 result += count;
00310                 break;
00311             }
00312 
00313             if (!lastline)
00314             {
00315                 top += height;
00316                 result += line->count + 1;
00317             }
00318         }
00319 
00320         return result;
00321     }
00322 
00323     IntPoint TextView::getCursorPoint(size_t _position)
00324     {
00325         if (_position >= mLength + 1)
00326             _position = mLength;
00327 
00328         size_t position = 0;
00329         int top = 0;
00330         int left = 0;
00331         for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
00332         {
00333             left = line->offset;
00334             if (position + line->count >= _position)
00335             {
00336                 for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
00337                 {
00338                     if (sim->isColour())
00339                         continue;
00340 
00341                     if (position == _position)
00342                         break;
00343 
00344                     position ++;
00345                     left += sim->getWidth();
00346                 }
00347                 break;
00348             }
00349             position += line->count + 1;
00350             top += mFontHeight;
00351         }
00352 
00353         return IntPoint(left, top);
00354     }
00355 
00356     const IntSize& TextView::getViewSize() const
00357     {
00358         return mViewSize;
00359     }
00360 
00361     size_t TextView::getTextLength() const
00362     {
00363         return mLength;
00364     }
00365 
00366     const VectorLineInfo& TextView::getData() const
00367     {
00368         return mLineInfo;
00369     }
00370 
00371 } // namespace MyGUI