PageRenderTime 80ms CodeModel.GetById 29ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 1ms

/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
  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
 27//#include "llviewerprecompiledheaders.h"
 28#include "linden_common.h"
 29
 30#include "llconsole.h"
 31
 32// linden library includes
 33#include "llmath.h"
 34//#include "llviewercontrol.h"
 35#include "llcriticaldamp.h"
 36#include "llfontgl.h"
 37#include "llgl.h"
 38#include "llui.h"
 39#include "lluiimage.h"
 40//#include "llviewerimage.h"
 41//#include "llviewerimagelist.h"
 42//#include "llviewerwindow.h"
 43#include "llsd.h"
 44#include "llfontgl.h"
 45#include "llmath.h"
 46
 47//#include "llstartup.h"
 48
 49// Used for LCD display
 50extern void AddNewDebugConsoleToLCD(const LLWString &newLine);
 51
 52LLConsole* gConsole = NULL;  // Created and destroyed in LLViewerWindow.
 53
 54const F32 FADE_DURATION = 2.f;
 55const S32 MIN_CONSOLE_WIDTH = 200;
 56 
 57static LLDefaultChildRegistry::Register<LLConsole> r("console");
 58
 59LLConsole::LLConsole(const LLConsole::Params& p) 
 60:	LLUICtrl(p),
 61	LLFixedBuffer(p.max_lines),
 62	mLinePersistTime(p.persist_time), // seconds
 63	mFont(p.font),
 64	mConsoleWidth(0),
 65	mConsoleHeight(0)
 66{
 67	if (p.font_size_index.isProvided())
 68	{
 69		setFontSize(p.font_size_index);
 70	}
 71	mFadeTime = mLinePersistTime - FADE_DURATION;
 72	setMaxLines(LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines"));
 73}
 74
 75void LLConsole::setLinePersistTime(F32 seconds)
 76{
 77	mLinePersistTime = seconds;
 78	mFadeTime = mLinePersistTime - FADE_DURATION;
 79}
 80
 81void LLConsole::reshape(S32 width, S32 height, BOOL called_from_parent)
 82{
 83	S32 new_width = llmax(50, llmin(getRect().getWidth(), width));
 84	S32 new_height = llmax(llfloor(mFont->getLineHeight()) + 15, llmin(getRect().getHeight(), height));
 85
 86	if (   mConsoleWidth == new_width
 87		&& mConsoleHeight == new_height )
 88	{
 89		return;
 90	}
 91	
 92	mConsoleWidth = new_width;
 93	mConsoleHeight= new_height;
 94	
 95	LLUICtrl::reshape(new_width, new_height, called_from_parent);
 96	
 97	for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
 98	{
 99		(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
100	}
101}
102
103void LLConsole::setFontSize(S32 size_index)
104{
105	if (-1 == size_index)
106	{
107		mFont = LLFontGL::getFontMonospace();
108	}
109	else if (0 == size_index)
110	{
111		mFont = LLFontGL::getFontSansSerif();
112	}
113	else if (1 == size_index)
114	{
115		mFont = LLFontGL::getFontSansSerifBig();
116	}
117	else
118	{
119		mFont = LLFontGL::getFontSansSerifHuge();
120	}
121	// Make sure the font exists
122	if (mFont == NULL)
123	{
124		mFont = LLFontGL::getFontDefault();
125	}
126	
127	for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
128	{
129		(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
130	}
131}
132
133void LLConsole::draw()
134{
135	// Units in pixels
136	static const F32 padding_horizontal = 10;
137	static const F32 padding_vertical = 3;
138	LLGLSUIDefault gls_ui;
139
140	// skip lines added more than mLinePersistTime ago
141	F32 cur_time = mTimer.getElapsedTimeF32();
142	
143	F32 skip_time = cur_time - mLinePersistTime;
144	F32 fade_time = cur_time - mFadeTime;
145
146	if (mParagraphs.empty()) 	//No text to draw.
147	{
148		return;
149	}
150
151	U32 num_lines=0;
152
153	paragraph_t::reverse_iterator paragraph_it;
154	paragraph_it = mParagraphs.rbegin();
155	U32 paragraph_num=mParagraphs.size();
156	
157	while (!mParagraphs.empty() && paragraph_it != mParagraphs.rend())
158	{
159		num_lines += (*paragraph_it).mLines.size();
160		if(num_lines > mMaxLines 
161			|| ( (mLinePersistTime > (F32)0.f) && ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime) <= (F32)0.f)) 
162		{							//All lines above here are done.  Lose them.
163			for (U32 i=0;i<paragraph_num;i++)
164			{
165				if (!mParagraphs.empty())
166					mParagraphs.pop_front();
167			}
168			break;
169		}
170		paragraph_num--;
171		paragraph_it++;
172	}
173
174	if (mParagraphs.empty())
175	{
176		return;
177	}
178	
179	// draw remaining lines
180	F32 y_pos = 0.f;
181
182	LLUIImagePtr imagep = LLUI::getUIImage("transparent");
183
184	F32 console_opacity = llclamp(LLUI::sSettingGroups["config"]->getF32("ConsoleBackgroundOpacity"), 0.f, 1.f);
185	LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground");
186	color.mV[VALPHA] *= console_opacity;
187
188	F32 line_height = mFont->getLineHeight();
189
190	for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++)
191	{
192		S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + padding_vertical);
193		S32 target_width =  llfloor( (*paragraph_it).mMaxWidth + padding_horizontal);
194
195		y_pos += ((*paragraph_it).mLines.size()) * line_height;
196		imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color);
197
198		F32 y_off=0;
199
200		F32 alpha;
201
202		if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time))
203		{
204			alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime);
205		}
206		else
207		{
208			alpha = 1.0f;
209		}
210
211		if( alpha > 0.f )
212		{
213			for (lines_t::iterator line_it=(*paragraph_it).mLines.begin(); 
214					line_it != (*paragraph_it).mLines.end();
215					line_it ++)
216			{
217				for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin();
218						seg_it != (*line_it).mLineColorSegments.end();
219						seg_it++)
220				{
221					mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos -  y_off,
222						LLColor4(
223							(*seg_it).mColor.mV[VRED], 
224							(*seg_it).mColor.mV[VGREEN], 
225							(*seg_it).mColor.mV[VBLUE], 
226							(*seg_it).mColor.mV[VALPHA]*alpha),
227						LLFontGL::LEFT, 
228						LLFontGL::BASELINE,
229						LLFontGL::NORMAL,
230						LLFontGL::DROP_SHADOW,
231						S32_MAX,
232						target_width
233						);
234				}
235				y_off += line_height;
236			}
237		}
238		y_pos  += padding_vertical;
239	}
240}
241
242//Generate highlight color segments for this paragraph.  Pass in default color of paragraph.
243void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color) 
244{
245	LLSD paragraph_color_segments;
246	LLColor4 lcolor=color;
247	
248	paragraph_color_segments[0]["text"] =wstring_to_utf8str(mParagraphText);
249	LLSD color_sd = color.getValue();
250	paragraph_color_segments[0]["color"]=color_sd;
251
252	for(LLSD::array_const_iterator color_segment_it = paragraph_color_segments.beginArray();
253		color_segment_it != paragraph_color_segments.endArray();
254		++color_segment_it)
255	{			
256		LLSD color_llsd = (*color_segment_it)["color"];
257		std::string color_str  = (*color_segment_it)["text"].asString();
258
259		ParagraphColorSegment color_segment;
260		
261		color_segment.mColor.setValue(color_llsd);
262		color_segment.mNumChars = color_str.length();
263		
264		mParagraphColorSegments.push_back(color_segment);
265	}
266}
267
268//Called when a paragraph is added to the console or window is resized.
269void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, bool force_resize)
270{
271	if ( !force_resize )
272	{
273		if ( mMaxWidth >= 0.0f 
274		 &&  mMaxWidth < screen_width )
275		{
276			return;					//No resize required.
277		}
278	}
279	
280	screen_width = screen_width - 30;	//Margin for small windows.
281	
282	if (	mParagraphText.empty() 
283		|| mParagraphColorSegments.empty()
284		|| font == NULL)
285	{
286		return;					//Not enough info to complete.
287	}
288	
289	mLines.clear();				//Chuck everything.
290	mMaxWidth = 0.0f;
291	
292	paragraph_color_segments_t::iterator current_color = mParagraphColorSegments.begin();
293	U32 current_color_length = (*current_color).mNumChars;	
294	
295	S32 paragraph_offset = 0;			//Offset into the paragraph text.
296
297	// Wrap lines that are longer than the view is wide.
298	while( paragraph_offset < (S32)mParagraphText.length() &&
299		   mParagraphText[paragraph_offset] != 0)
300	{
301		S32 skip_chars; // skip '\n'
302		// Figure out if a word-wrapped line fits here.
303		LLWString::size_type line_end = mParagraphText.find_first_of(llwchar('\n'), paragraph_offset);
304		if (line_end != LLWString::npos)
305		{
306			skip_chars = 1; // skip '\n'
307		}
308		else
309		{
310			line_end = mParagraphText.size();
311			skip_chars = 0;
312		}
313
314		U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, line_end - paragraph_offset, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
315
316		if (drawable != 0)
317		{
318			F32 x_position = 0;						//Screen X position of text.
319			
320			mMaxWidth = llmax( mMaxWidth, (F32)font->getWidth( mParagraphText.substr( paragraph_offset, drawable ).c_str() ) );
321			Line line;
322			
323			U32 left_to_draw = drawable;
324			U32 drawn = 0;
325			
326			while (left_to_draw >= current_color_length 
327				&& current_color != mParagraphColorSegments.end() )
328			{
329				LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, current_color_length );
330				line.mLineColorSegments.push_back( LineColorSegment( color_text,			//Append segment to line.
331												(*current_color).mColor, 
332												x_position ) );
333												
334				x_position += font->getWidth( color_text.c_str() );	//Set up next screen position.
335				
336				drawn += current_color_length;
337				left_to_draw -= current_color_length;
338				
339				current_color++;							//Goto next paragraph color record.
340				
341				if (current_color != mParagraphColorSegments.end())
342				{
343					current_color_length = (*current_color).mNumChars;
344				}
345			}
346			
347			if (left_to_draw > 0 && current_color != mParagraphColorSegments.end() )
348			{
349					LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, left_to_draw );
350					
351					line.mLineColorSegments.push_back( LineColorSegment( color_text,		//Append segment to line.
352													(*current_color).mColor, 
353													x_position ) );
354																		
355					current_color_length -= left_to_draw;
356			}
357			mLines.push_back(line);								//Append line to paragraph line list.
358		}
359		paragraph_offset += (drawable + skip_chars);
360	}
361}
362
363//Pass in the string and the default color for this block of text.
364LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width) 
365:	mParagraphText(str), mAddTime(add_time), mMaxWidth(-1)
366{
367	makeParagraphColorSegments(color);
368	updateLines( screen_width, font );
369}
370	
371// called once per frame regardless of console visibility
372// static
373void LLConsole::updateClass()
374{	
375	for (instance_iter it = beginInstances(); it != endInstances(); ++it)
376	{
377		it->update();
378	} 
379}
380
381void LLConsole::update()
382{
383	{
384		LLMutexLock lock(&mMutex);
385
386		while (!mLines.empty())
387		{
388			mParagraphs.push_back(
389				Paragraph(	mLines.front(), 
390							LLColor4::white, 
391							mTimer.getElapsedTimeF32(), 
392							mFont, 
393							(F32)getRect().getWidth()));
394			mLines.pop_front();
395		}
396	}
397
398	// 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)
399	while ((S32)mParagraphs.size() > llmax((S32)0, (S32)(mMaxLines)))
400	{
401			mParagraphs.pop_front();
402	}
403}
404