MyGUI
3.2.0
|
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