PageRenderTime 112ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/llconsole.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 404 lines | 293 code | 66 blank | 45 comment | 64 complexity | 9c4def3d4dfef1820d8428e041e32242 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llconsole.cpp
  3. * @brief a scrolling console output device
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. //#include "llviewerprecompiledheaders.h"
  27. #include "linden_common.h"
  28. #include "llconsole.h"
  29. // linden library includes
  30. #include "llmath.h"
  31. //#include "llviewercontrol.h"
  32. #include "llcriticaldamp.h"
  33. #include "llfontgl.h"
  34. #include "llgl.h"
  35. #include "llui.h"
  36. #include "lluiimage.h"
  37. //#include "llviewerimage.h"
  38. //#include "llviewerimagelist.h"
  39. //#include "llviewerwindow.h"
  40. #include "llsd.h"
  41. #include "llfontgl.h"
  42. #include "llmath.h"
  43. //#include "llstartup.h"
  44. // Used for LCD display
  45. extern void AddNewDebugConsoleToLCD(const LLWString &newLine);
  46. LLConsole* gConsole = NULL; // Created and destroyed in LLViewerWindow.
  47. const F32 FADE_DURATION = 2.f;
  48. const S32 MIN_CONSOLE_WIDTH = 200;
  49. static LLDefaultChildRegistry::Register<LLConsole> r("console");
  50. LLConsole::LLConsole(const LLConsole::Params& p)
  51. : LLUICtrl(p),
  52. LLFixedBuffer(p.max_lines),
  53. mLinePersistTime(p.persist_time), // seconds
  54. mFont(p.font),
  55. mConsoleWidth(0),
  56. mConsoleHeight(0)
  57. {
  58. if (p.font_size_index.isProvided())
  59. {
  60. setFontSize(p.font_size_index);
  61. }
  62. mFadeTime = mLinePersistTime - FADE_DURATION;
  63. setMaxLines(LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines"));
  64. }
  65. void LLConsole::setLinePersistTime(F32 seconds)
  66. {
  67. mLinePersistTime = seconds;
  68. mFadeTime = mLinePersistTime - FADE_DURATION;
  69. }
  70. void LLConsole::reshape(S32 width, S32 height, BOOL called_from_parent)
  71. {
  72. S32 new_width = llmax(50, llmin(getRect().getWidth(), width));
  73. S32 new_height = llmax(llfloor(mFont->getLineHeight()) + 15, llmin(getRect().getHeight(), height));
  74. if ( mConsoleWidth == new_width
  75. && mConsoleHeight == new_height )
  76. {
  77. return;
  78. }
  79. mConsoleWidth = new_width;
  80. mConsoleHeight= new_height;
  81. LLUICtrl::reshape(new_width, new_height, called_from_parent);
  82. for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
  83. {
  84. (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
  85. }
  86. }
  87. void LLConsole::setFontSize(S32 size_index)
  88. {
  89. if (-1 == size_index)
  90. {
  91. mFont = LLFontGL::getFontMonospace();
  92. }
  93. else if (0 == size_index)
  94. {
  95. mFont = LLFontGL::getFontSansSerif();
  96. }
  97. else if (1 == size_index)
  98. {
  99. mFont = LLFontGL::getFontSansSerifBig();
  100. }
  101. else
  102. {
  103. mFont = LLFontGL::getFontSansSerifHuge();
  104. }
  105. // Make sure the font exists
  106. if (mFont == NULL)
  107. {
  108. mFont = LLFontGL::getFontDefault();
  109. }
  110. for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
  111. {
  112. (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
  113. }
  114. }
  115. void LLConsole::draw()
  116. {
  117. // Units in pixels
  118. static const F32 padding_horizontal = 10;
  119. static const F32 padding_vertical = 3;
  120. LLGLSUIDefault gls_ui;
  121. // skip lines added more than mLinePersistTime ago
  122. F32 cur_time = mTimer.getElapsedTimeF32();
  123. F32 skip_time = cur_time - mLinePersistTime;
  124. F32 fade_time = cur_time - mFadeTime;
  125. if (mParagraphs.empty()) //No text to draw.
  126. {
  127. return;
  128. }
  129. U32 num_lines=0;
  130. paragraph_t::reverse_iterator paragraph_it;
  131. paragraph_it = mParagraphs.rbegin();
  132. U32 paragraph_num=mParagraphs.size();
  133. while (!mParagraphs.empty() && paragraph_it != mParagraphs.rend())
  134. {
  135. num_lines += (*paragraph_it).mLines.size();
  136. if(num_lines > mMaxLines
  137. || ( (mLinePersistTime > (F32)0.f) && ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime) <= (F32)0.f))
  138. { //All lines above here are done. Lose them.
  139. for (U32 i=0;i<paragraph_num;i++)
  140. {
  141. if (!mParagraphs.empty())
  142. mParagraphs.pop_front();
  143. }
  144. break;
  145. }
  146. paragraph_num--;
  147. paragraph_it++;
  148. }
  149. if (mParagraphs.empty())
  150. {
  151. return;
  152. }
  153. // draw remaining lines
  154. F32 y_pos = 0.f;
  155. LLUIImagePtr imagep = LLUI::getUIImage("transparent");
  156. F32 console_opacity = llclamp(LLUI::sSettingGroups["config"]->getF32("ConsoleBackgroundOpacity"), 0.f, 1.f);
  157. LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground");
  158. color.mV[VALPHA] *= console_opacity;
  159. F32 line_height = mFont->getLineHeight();
  160. for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++)
  161. {
  162. S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + padding_vertical);
  163. S32 target_width = llfloor( (*paragraph_it).mMaxWidth + padding_horizontal);
  164. y_pos += ((*paragraph_it).mLines.size()) * line_height;
  165. imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color);
  166. F32 y_off=0;
  167. F32 alpha;
  168. if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time))
  169. {
  170. alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime);
  171. }
  172. else
  173. {
  174. alpha = 1.0f;
  175. }
  176. if( alpha > 0.f )
  177. {
  178. for (lines_t::iterator line_it=(*paragraph_it).mLines.begin();
  179. line_it != (*paragraph_it).mLines.end();
  180. line_it ++)
  181. {
  182. for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin();
  183. seg_it != (*line_it).mLineColorSegments.end();
  184. seg_it++)
  185. {
  186. mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos - y_off,
  187. LLColor4(
  188. (*seg_it).mColor.mV[VRED],
  189. (*seg_it).mColor.mV[VGREEN],
  190. (*seg_it).mColor.mV[VBLUE],
  191. (*seg_it).mColor.mV[VALPHA]*alpha),
  192. LLFontGL::LEFT,
  193. LLFontGL::BASELINE,
  194. LLFontGL::NORMAL,
  195. LLFontGL::DROP_SHADOW,
  196. S32_MAX,
  197. target_width
  198. );
  199. }
  200. y_off += line_height;
  201. }
  202. }
  203. y_pos += padding_vertical;
  204. }
  205. }
  206. //Generate highlight color segments for this paragraph. Pass in default color of paragraph.
  207. void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color)
  208. {
  209. LLSD paragraph_color_segments;
  210. LLColor4 lcolor=color;
  211. paragraph_color_segments[0]["text"] =wstring_to_utf8str(mParagraphText);
  212. LLSD color_sd = color.getValue();
  213. paragraph_color_segments[0]["color"]=color_sd;
  214. for(LLSD::array_const_iterator color_segment_it = paragraph_color_segments.beginArray();
  215. color_segment_it != paragraph_color_segments.endArray();
  216. ++color_segment_it)
  217. {
  218. LLSD color_llsd = (*color_segment_it)["color"];
  219. std::string color_str = (*color_segment_it)["text"].asString();
  220. ParagraphColorSegment color_segment;
  221. color_segment.mColor.setValue(color_llsd);
  222. color_segment.mNumChars = color_str.length();
  223. mParagraphColorSegments.push_back(color_segment);
  224. }
  225. }
  226. //Called when a paragraph is added to the console or window is resized.
  227. void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, bool force_resize)
  228. {
  229. if ( !force_resize )
  230. {
  231. if ( mMaxWidth >= 0.0f
  232. && mMaxWidth < screen_width )
  233. {
  234. return; //No resize required.
  235. }
  236. }
  237. screen_width = screen_width - 30; //Margin for small windows.
  238. if ( mParagraphText.empty()
  239. || mParagraphColorSegments.empty()
  240. || font == NULL)
  241. {
  242. return; //Not enough info to complete.
  243. }
  244. mLines.clear(); //Chuck everything.
  245. mMaxWidth = 0.0f;
  246. paragraph_color_segments_t::iterator current_color = mParagraphColorSegments.begin();
  247. U32 current_color_length = (*current_color).mNumChars;
  248. S32 paragraph_offset = 0; //Offset into the paragraph text.
  249. // Wrap lines that are longer than the view is wide.
  250. while( paragraph_offset < (S32)mParagraphText.length() &&
  251. mParagraphText[paragraph_offset] != 0)
  252. {
  253. S32 skip_chars; // skip '\n'
  254. // Figure out if a word-wrapped line fits here.
  255. LLWString::size_type line_end = mParagraphText.find_first_of(llwchar('\n'), paragraph_offset);
  256. if (line_end != LLWString::npos)
  257. {
  258. skip_chars = 1; // skip '\n'
  259. }
  260. else
  261. {
  262. line_end = mParagraphText.size();
  263. skip_chars = 0;
  264. }
  265. U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, line_end - paragraph_offset, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
  266. if (drawable != 0)
  267. {
  268. F32 x_position = 0; //Screen X position of text.
  269. mMaxWidth = llmax( mMaxWidth, (F32)font->getWidth( mParagraphText.substr( paragraph_offset, drawable ).c_str() ) );
  270. Line line;
  271. U32 left_to_draw = drawable;
  272. U32 drawn = 0;
  273. while (left_to_draw >= current_color_length
  274. && current_color != mParagraphColorSegments.end() )
  275. {
  276. LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, current_color_length );
  277. line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line.
  278. (*current_color).mColor,
  279. x_position ) );
  280. x_position += font->getWidth( color_text.c_str() ); //Set up next screen position.
  281. drawn += current_color_length;
  282. left_to_draw -= current_color_length;
  283. current_color++; //Goto next paragraph color record.
  284. if (current_color != mParagraphColorSegments.end())
  285. {
  286. current_color_length = (*current_color).mNumChars;
  287. }
  288. }
  289. if (left_to_draw > 0 && current_color != mParagraphColorSegments.end() )
  290. {
  291. LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, left_to_draw );
  292. line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line.
  293. (*current_color).mColor,
  294. x_position ) );
  295. current_color_length -= left_to_draw;
  296. }
  297. mLines.push_back(line); //Append line to paragraph line list.
  298. }
  299. paragraph_offset += (drawable + skip_chars);
  300. }
  301. }
  302. //Pass in the string and the default color for this block of text.
  303. LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width)
  304. : mParagraphText(str), mAddTime(add_time), mMaxWidth(-1)
  305. {
  306. makeParagraphColorSegments(color);
  307. updateLines( screen_width, font );
  308. }
  309. // called once per frame regardless of console visibility
  310. // static
  311. void LLConsole::updateClass()
  312. {
  313. for (instance_iter it = beginInstances(); it != endInstances(); ++it)
  314. {
  315. it->update();
  316. }
  317. }
  318. void LLConsole::update()
  319. {
  320. {
  321. LLMutexLock lock(&mMutex);
  322. while (!mLines.empty())
  323. {
  324. mParagraphs.push_back(
  325. Paragraph( mLines.front(),
  326. LLColor4::white,
  327. mTimer.getElapsedTimeF32(),
  328. mFont,
  329. (F32)getRect().getWidth()));
  330. mLines.pop_front();
  331. }
  332. }
  333. // remove old paragraphs which can't possibly be visible any more. ::draw() will do something similar but more conservative - we do this here because ::draw() isn't guaranteed to ever be called! (i.e. the console isn't visible)
  334. while ((S32)mParagraphs.size() > llmax((S32)0, (S32)(mMaxLines)))
  335. {
  336. mParagraphs.pop_front();
  337. }
  338. }