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