diff options
| author | Richard Nelson <richard@lindenlab.com> | 2007-04-05 00:59:55 +0000 | 
|---|---|---|
| committer | Richard Nelson <richard@lindenlab.com> | 2007-04-05 00:59:55 +0000 | 
| commit | 2ce0fc5f185f22be79b9be5406b76c97ed91ee01 (patch) | |
| tree | d70ea9faf02e4e1e7aeb14aa524644c23c703d55 | |
| parent | fd5608a3e79397d4ebc8819dc9de75863f6fb9b3 (diff) | |
svn merge -r 59234:60086 svn+ssh://svn/svn/linden/branches/live_lsl_help2 -> release
| -rw-r--r-- | indra/llmath/v3color.cpp | 49 | ||||
| -rw-r--r-- | indra/llmath/v3color.h | 2 | ||||
| -rw-r--r-- | indra/llmath/v4color.cpp | 49 | ||||
| -rw-r--r-- | indra/llmath/v4color.h | 2 | ||||
| -rw-r--r-- | indra/llrender/llfontgl.cpp | 181 | ||||
| -rw-r--r-- | indra/llrender/llfontgl.h | 3 | ||||
| -rw-r--r-- | indra/llui/llcombobox.cpp | 5 | ||||
| -rw-r--r-- | indra/llui/llfloater.cpp | 37 | ||||
| -rw-r--r-- | indra/llui/llscrolllistctrl.cpp | 17 | ||||
| -rw-r--r-- | indra/llui/llscrolllistctrl.h | 15 | ||||
| -rw-r--r-- | indra/llui/lltexteditor.cpp | 25 | ||||
| -rw-r--r-- | indra/llui/lltexteditor.h | 4 | ||||
| -rw-r--r-- | indra/newview/llfloatercolorpicker.cpp | 60 | ||||
| -rw-r--r-- | indra/newview/llfloatercolorpicker.h | 1 | ||||
| -rw-r--r-- | indra/newview/llpreviewscript.cpp | 249 | ||||
| -rw-r--r-- | indra/newview/llpreviewscript.h | 14 | 
16 files changed, 563 insertions, 150 deletions
diff --git a/indra/llmath/v3color.cpp b/indra/llmath/v3color.cpp index 2dbc368d98..d85006fa9c 100644 --- a/indra/llmath/v3color.cpp +++ b/indra/llmath/v3color.cpp @@ -42,3 +42,52 @@ std::ostream& operator<<(std::ostream& s, const LLColor3 &a)  	s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << " }";  	return s;  } + +void LLColor3::calcHSL(F32* hue, F32* saturation, F32* luminance) const +{ +	F32 var_R = mV[VRED]; +	F32 var_G = mV[VGREEN]; +	F32 var_B = mV[VBLUE]; + +	F32 var_Min = ( var_R < ( var_G < var_B ? var_G : var_B ) ? var_R : ( var_G < var_B ? var_G : var_B ) ); +	F32 var_Max = ( var_R > ( var_G > var_B ? var_G : var_B ) ? var_R : ( var_G > var_B ? var_G : var_B ) ); + +	F32 del_Max = var_Max - var_Min; + +	F32 L = ( var_Max + var_Min ) / 2.0f; +	F32 H = 0.0f; +	F32 S = 0.0f; + +	if ( del_Max == 0.0f ) +	{ +	   H = 0.0f; +	   S = 0.0f; +	} +	else +	{ +		if ( L < 0.5 ) +			S = del_Max / ( var_Max + var_Min ); +		else +			S = del_Max / ( 2.0f - var_Max - var_Min ); + +		F32 del_R = ( ( ( var_Max - var_R ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; +		F32 del_G = ( ( ( var_Max - var_G ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; +		F32 del_B = ( ( ( var_Max - var_B ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; + +		if ( var_R >= var_Max ) +			H = del_B - del_G; +		else +		if ( var_G >= var_Max ) +			H = ( 1.0f / 3.0f ) + del_R - del_B; +		else +		if ( var_B >= var_Max ) +			H = ( 2.0f / 3.0f ) + del_G - del_R; + +		if ( H < 0.0f ) H += 1.0f; +		if ( H > 1.0f ) H -= 1.0f; +	} + +	if (hue) *hue = H; +	if (saturation) *saturation = S; +	if (luminance) *luminance = L; +}
\ No newline at end of file diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 956cca614d..779fda436e 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -52,6 +52,8 @@ public:  		mV[1] = (F32) sd[1].asReal();;  		mV[2] = (F32) sd[2].asReal();;  	} + +	void calcHSL(F32* hue, F32* saturation, F32* luminance) const;  	const LLColor3&	setToBlack();					// Clears LLColor3 to (0, 0, 0)  	const LLColor3&	setToWhite();					// Zero LLColor3 to (0, 0, 0) diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp index 83870941df..4e2287eee2 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -205,6 +205,55 @@ LLColor4	vec3to4(const LLColor3 &vec)  	return temp;  } +void LLColor4::calcHSL(F32* hue, F32* saturation, F32* luminance) const +{ +	F32 var_R = mV[VRED]; +	F32 var_G = mV[VGREEN]; +	F32 var_B = mV[VBLUE]; + +	F32 var_Min = ( var_R < ( var_G < var_B ? var_G : var_B ) ? var_R : ( var_G < var_B ? var_G : var_B ) ); +	F32 var_Max = ( var_R > ( var_G > var_B ? var_G : var_B ) ? var_R : ( var_G > var_B ? var_G : var_B ) ); + +	F32 del_Max = var_Max - var_Min; + +	F32 L = ( var_Max + var_Min ) / 2.0f; +	F32 H = 0.0f; +	F32 S = 0.0f; + +	if ( del_Max == 0.0f ) +	{ +	   H = 0.0f; +	   S = 0.0f; +	} +	else +	{ +		if ( L < 0.5 ) +			S = del_Max / ( var_Max + var_Min ); +		else +			S = del_Max / ( 2.0f - var_Max - var_Min ); + +		F32 del_R = ( ( ( var_Max - var_R ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; +		F32 del_G = ( ( ( var_Max - var_G ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; +		F32 del_B = ( ( ( var_Max - var_B ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; + +		if ( var_R >= var_Max ) +			H = del_B - del_G; +		else +		if ( var_G >= var_Max ) +			H = ( 1.0f / 3.0f ) + del_R - del_B; +		else +		if ( var_B >= var_Max ) +			H = ( 2.0f / 3.0f ) + del_G - del_R; + +		if ( H < 0.0f ) H += 1.0f; +		if ( H > 1.0f ) H -= 1.0f; +	} + +	if (hue) *hue = H; +	if (saturation) *saturation = S; +	if (luminance) *luminance = L; +} +  // static  BOOL LLColor4::parseColor(const char* buf, LLColor4* color)  { diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index 8fe5846e26..ef9c5d4769 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -54,6 +54,8 @@ class LLColor4  			mV[3] = (F32) sd[3].asReal();  		} +		void calcHSL(F32* hue, F32* saturation, F32* luminance) const; +  		const LLColor4&	setToBlack();						// zero LLColor4 to (0, 0, 0, 1)  		const LLColor4&	setToWhite();						// zero LLColor4 to (0, 0, 0, 1) diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index b85a0b65e6..94a8eb822d 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -50,6 +50,7 @@ const F32 PIXEL_BORDER_THRESHOLD = 0.0001f;  const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;  const F32 PAD_AMT = 0.5f; +const F32 DROP_SHADOW_STRENGTH = 0.3f;  F32 llfont_round_x(F32 x)  { @@ -114,7 +115,8 @@ void LLFontGL::init()  		mImageGLp = new LLImageGL(FALSE);  		//RN: use nearest mipmap filtering to obviate the need to do pixel-accurate positioning  		mImageGLp->bind(); -		mImageGLp->setMipFilterNearest(TRUE, TRUE); +		// we allow bilinear filtering to get sub-pixel positioning for drop shadows +		//mImageGLp->setMipFilterNearest(TRUE, TRUE);  	}  	if (mRawImageGLp.isNull())  	{ @@ -530,28 +532,8 @@ S32 LLFontGL::render(const LLWString &wstr,  		return 0;  	}  -	if (style & DROP_SHADOW) -	{ -		LLColor4 shadow_color = sShadowColor; -		shadow_color[3] = color[3]; -		render(wstr, begin_offset, -				x + 1.f / sScaleX,  -				y - 1.f / sScaleY, -				shadow_color, -				halign,  -				valign, -				style & (~DROP_SHADOW), -				max_chars, -				max_pixels, -			   	right_x, -			   	use_embedded, -				use_ellipses); -	} -  	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX); -	BOOL render_bold = FALSE; -  	// HACK for better bolding  	if (style & BOLD)  	{ @@ -566,9 +548,17 @@ S32 LLFontGL::render(const LLWString &wstr,  				max_chars, max_pixels,  				right_x, use_embedded);  		} -		else +	} + +	F32 drop_shadow_strength = 0.f; +	if (style & DROP_SHADOW) +	{ +		F32 luminance; +		color.calcHSL(NULL, NULL, &luminance); +		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, DROP_SHADOW_STRENGTH); +		if (luminance < 0.35f)  		{ -			render_bold = TRUE; +			style = style & ~DROP_SHADOW;  		}  	} @@ -612,9 +602,6 @@ S32 LLFontGL::render(const LLWString &wstr,  	}  	F32 cur_x, cur_y, cur_render_x, cur_render_y; -	F32 slant_offset; - -	slant_offset = ((style & ITALIC) ? ( -mAscender * 0.25f) : 0.f);  	// Bind the font texture @@ -718,34 +705,13 @@ S32 LLFontGL::render(const LLWString &wstr,  			glEnd(); -			glColor3f(1.f, 1.f, 1.f); -  			ext_image->bind();  			const F32 ext_x = cur_render_x + (EXT_X_BEARING * sScaleX);  			const F32 ext_y = cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight); -			glBegin(GL_QUADS); -			{ -				S32 num_passes = render_bold ? 2 : 1; -				for (S32 pass = 0; pass < num_passes; pass++) -				{ -					glTexCoord2f(1.f, 1.f); -					glVertex2f(llfont_round_x(ext_x + ext_width  + (F32)(pass * BOLD_OFFSET)),  -								llfont_round_y(ext_y + ext_height)); - -					glTexCoord2f(0.f, 1.f); -					glVertex2f(llfont_round_x(ext_x + (F32)(pass * BOLD_OFFSET)),  -								llfont_round_y(ext_y + ext_height)); - -					glTexCoord2f(0.f, 0.f); -					glVertex2f(llfont_round_x(ext_x + (F32)(pass * BOLD_OFFSET)), llfont_round_y(ext_y)); - -					glTexCoord2f(1.f, 0.f); -					glVertex2f(llfont_round_x(ext_x + ext_width + (F32)(pass * BOLD_OFFSET)),  -								llfont_round_y(ext_y)); -				} -			} -			glEnd(); +			LLRectf uv_rect(0.f, 1.f, 1.f, 0.f); +			LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y); +			drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);  			if (!label.empty())  			{ @@ -798,31 +764,21 @@ S32 LLFontGL::render(const LLWString &wstr,  			// Draw the text at the appropriate location  			//Specify vertices and texture coordinates -			S32 num_passes = render_bold ? 2 : 1; -			for (S32 pass = 0; pass < num_passes; pass++) -			{ -				glTexCoord2f((fgi->mXBitmapOffset - PAD_AMT) * inv_width, -					(fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height); -				glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + (F32)(pass * BOLD_OFFSET) - PAD_AMT), -					llfont_round_y(cur_render_y + (F32)fgi->mYBearing + PAD_AMT)); -				glTexCoord2f((fgi->mXBitmapOffset - PAD_AMT) * inv_width, -					(fgi->mYBitmapOffset - PAD_AMT) * inv_height); -				glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + slant_offset + (F32)(pass * BOLD_OFFSET) - PAD_AMT), -					llfont_round_y(cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT)); -				glTexCoord2f((fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width, -					(fgi->mYBitmapOffset - PAD_AMT) * inv_height); -				glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + slant_offset + (F32)fgi->mWidth + (F32)(pass * BOLD_OFFSET) + PAD_AMT), -					llfont_round_y(cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT)); -				glTexCoord2f((fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width, -					(fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height); -				glVertex2f(llfont_round_x(cur_render_x + (F32)fgi->mXBearing + (F32)fgi->mWidth + (F32)(pass * BOLD_OFFSET) + PAD_AMT), -					llfont_round_y(cur_render_y + (F32)fgi->mYBearing + PAD_AMT)); -			} +			LLRectf uv_rect((fgi->mXBitmapOffset - PAD_AMT) * inv_width, +							(fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height, +							(fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width, +							(fgi->mYBitmapOffset - PAD_AMT) * inv_height); +			LLRectf screen_rect(cur_render_x + (F32)fgi->mXBearing - PAD_AMT, +								cur_render_y + (F32)fgi->mYBearing + PAD_AMT, +								cur_render_x + (F32)fgi->mXBearing + (F32)fgi->mWidth + PAD_AMT, +								cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT); -			chars_drawn++; +			drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength); +			chars_drawn++;  			cur_x += fgi->mXAdvance;  			cur_y += fgi->mYAdvance; +  			llwchar next_char = wstr[i+1];  			if (next_char && (next_char < LAST_CHARACTER))  			{ @@ -1328,6 +1284,89 @@ void LLFontGL::removeEmbeddedChar( llwchar wc )  	}  } + +void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const +{ +	glTexCoord2f(uv_rect.mRight, uv_rect.mTop); +	glVertex2f(llfont_round_x(screen_rect.mRight),  +				llfont_round_y(screen_rect.mTop)); + +	glTexCoord2f(uv_rect.mLeft, uv_rect.mTop); +	glVertex2f(llfont_round_x(screen_rect.mLeft),  +				llfont_round_y(screen_rect.mTop)); + +	glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom); +	glVertex2f(llfont_round_x(screen_rect.mLeft + slant_amt),  +				llfont_round_y(screen_rect.mBottom)); + +	glTexCoord2f(uv_rect.mRight, uv_rect.mBottom); +	glVertex2f(llfont_round_x(screen_rect.mRight + slant_amt),  +				llfont_round_y(screen_rect.mBottom)); +} + +void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_strength) const +{ +	F32 slant_offset; +	slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f); + +	glBegin(GL_QUADS); +	{ +		//FIXME: bold and drop shadow are mutually exclusive only for convenience +		//Allow both when we need them. +		if (style & BOLD) +		{ +			glColor4fv(color.mV); +			for (S32 pass = 0; pass < 2; pass++) +			{ +				LLRectf screen_rect_offset = screen_rect; + +				screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); +				renderQuad(screen_rect_offset, uv_rect, slant_offset); +			} +		} +		else if (style & DROP_SHADOW) +		{ +			LLColor4 shadow_color = LLFontGL::sShadowColor; +			shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength; +			glColor4fv(shadow_color.mV); +			for (S32 pass = 0; pass < 5; pass++) +			{ +				LLRectf screen_rect_offset = screen_rect; + +				switch(pass) +				{ +				case 0: +					screen_rect_offset.translate(-1.f, -1.f); +					break; +				case 1: +					screen_rect_offset.translate(1.f, -1.f); +					break; +				case 2: +					screen_rect_offset.translate(1.f, 1.f); +					break; +				case 3: +					screen_rect_offset.translate(-1.f, 1.f); +					break; +				case 4: +					screen_rect_offset.translate(0, -2.f); +					break; +				} +			 +				renderQuad(screen_rect_offset, uv_rect, slant_offset); +			} +			glColor4fv(color.mV); +			renderQuad(screen_rect, uv_rect, slant_offset); +		} +		else // normal rendering +		{ +			glColor4fv(color.mV); +			renderQuad(screen_rect, uv_rect, slant_offset); +		} + +	} +	glEnd(); +} +  // static  LLString LLFontGL::nameFromFont(const LLFontGL* fontp)  { diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 789879a5ca..75e12f0475 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -14,6 +14,7 @@  #include "llimagegl.h"  #include "v2math.h"  #include "llcoord.h" +#include "llrect.h"  class LLColor4; @@ -187,6 +188,8 @@ protected:  	const embedded_data_t* getEmbeddedCharData(const llwchar wch) const;  	F32 getEmbeddedCharAdvance(const embedded_data_t* ext_data) const;  	void clearEmbeddedChars(); +	void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const; +	void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_fade) const;  public:  	static F32 sVertDPI; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index e439cd0acc..f13e0d54b9 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -782,6 +782,7 @@ void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative  			mTextEntry->setCommitOnFocusLost(FALSE);  			mTextEntry->setText(cur_label);  			mTextEntry->setIgnoreTab(TRUE); +			mTextEntry->setFollowsAll();  			addChild(mTextEntry);  			mMaxChars = max_chars;  		} @@ -789,6 +790,8 @@ void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative  		{  			mTextEntry->setVisible(TRUE);  		} + +		mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);  	}  	else if (!allow && mAllowTextEntry)  	{ @@ -799,6 +802,7 @@ void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative  		{  			mTextEntry->setVisible(FALSE);  		} +		mButton->setFollowsAll();  	}  	mAllowTextEntry = allow;  	mTextEntryTentative = set_tentative;	 @@ -834,6 +838,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)  		else  		{  			line_editor->setTentative(self->mTextEntryTentative); +			self->mList->deselectAllItems();  		}  		return;  	} diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 1f71de1c87..c3364a7a35 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -38,6 +38,8 @@ extern BOOL gNoRender;  const S32 MINIMIZED_WIDTH = 160;  const S32 CLOSE_BOX_FROM_TOP = 1; +// use this to control "jumping" behavior when Ctrl-Tabbing +const S32 TABBED_FLOATER_OFFSET = 0;  LLString	LLFloater::sButtonActiveImageNames[BUTTON_COUNT] =   { @@ -2169,32 +2171,27 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out  void LLFloaterView::draw()  { -	if( getVisible() ) -	{ -		refresh(); - -		// hide focused floater if in cycle mode, so that it can be drawn on top -		LLFloater* focused_floater = getFocusedFloater(); -		BOOL floater_visible = FALSE; -		if (mFocusCycleMode && focused_floater) -		{ -			floater_visible = focused_floater->getVisible(); -			focused_floater->setVisible(FALSE); -		} +	refresh(); -		// And actually do the draw -		LLView::draw(); +	// hide focused floater if in cycle mode, so that it can be drawn on top +	LLFloater* focused_floater = getFocusedFloater(); -		// manually draw focused floater on top when in cycle mode -		if (mFocusCycleMode && focused_floater) +	if (mFocusCycleMode && focused_floater) +	{ +		child_list_const_iter_t child_it = getChildList()->begin(); +		for (;child_it != getChildList()->end(); ++child_it)  		{ -			// draw focused item on top for better feedback -			focused_floater->setVisible(floater_visible); -			if (floater_visible) +			if ((*child_it) != focused_floater)  			{ -				drawChild(focused_floater); +				drawChild(*child_it);  			}  		} + +		drawChild(focused_floater, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET); +	} +	else +	{ +		LLView::draw();  	}  } diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 98dddfb542..f442855aca 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -136,6 +136,19 @@ BOOL LLScrollListCheck::handleClick()  }  // +// LLScrollListSeparator +// +LLScrollListSeparator::LLScrollListSeparator(S32 width) : mWidth(width) +{ +} + +void LLScrollListSeparator::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const +{ +	//*FIXME: use dynamic item heights and make separators narrow, and inactive +	gl_line_2d(5, 8, llmax(5, width - 5), 8, color); +} + +//  // LLScrollListText  //  U32 LLScrollListText::sCount = 0; @@ -2750,6 +2763,10 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p  														LLRect(0, 0, width, width), "label");  			new_item->setColumn(index, new LLScrollListCheck(ctrl,width));  		} +		else if (type == "separator") +		{ +			new_item->setColumn(index, new LLScrollListSeparator(width)); +		}  		else  		{  			new_item->setColumn(index, new LLScrollListText(value.asString(), font, width, font_style, font_alignment)); diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 99218ab3c4..7a0a32c87e 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -48,6 +48,21 @@ public:  	virtual	void	setEnabled(BOOL enable) { }  }; +class LLScrollListSeparator : public LLScrollListCell +{ +public: +	LLScrollListSeparator(S32 width); +	virtual ~LLScrollListSeparator() {}; +	virtual void			drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const;		// truncate to given width, if possible +	virtual S32				getWidth() const {return mWidth;} +	virtual S32				getHeight() const { return 5; }; +	virtual void			setWidth(S32 width) {mWidth = width; } +	virtual BOOL			isText() { return FALSE; } + +protected: +	S32 mWidth; +}; +  class LLScrollListText : public LLScrollListCell  {  public: diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 366b1956c4..651a421742 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -793,6 +793,31 @@ LLWString LLTextEditor::getWSubString(S32 pos, S32 len)  	return mWText.substr(pos, len);  } +LLTextSegment*	LLTextEditor::getCurrentSegment() +{ +	return getSegmentAtOffset(mCursorPos); +} + +LLTextSegment*	LLTextEditor::getPreviousSegment() +{ +	// find segment index at character to left of cursor (or rightmost edge of selection) +	S32 idx = llmax(0, getSegmentIdxAtOffset(mCursorPos) - 1); +	return idx >= 0 ? mSegments[idx] : NULL; +} + +void LLTextEditor::getSelectedSegments(std::vector<LLTextSegment*>& segments) +{ +	S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; +	S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; +	S32 first_idx = llmax(0, getSegmentIdxAtOffset(left)); +	S32 last_idx = llmax(0, first_idx, getSegmentIdxAtOffset(right)); + +	for (S32 idx = first_idx; idx <= last_idx; ++idx) +	{ +		segments.push_back(mSegments[idx]); +	} +} +  S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round )  {  		// If round is true, if the position is on the right half of a character, the cursor diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 21db32b33f..d95230f0dc 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -221,6 +221,10 @@ public:  	llwchar			getWChar(S32 pos);  	LLWString		getWSubString(S32 pos, S32 len); +	LLTextSegment*	getCurrentSegment(); +	LLTextSegment*  getPreviousSegment(); +	void getSelectedSegments(std::vector<LLTextSegment*>& segments); +  protected:   	S32				getLength() const;  	void			getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ); diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index 8af0dd410f..c3962bffb8 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -275,59 +275,6 @@ destroyUI ()  	}  } -////////////////////////////////////////////////////////////////////////////// -// -void -LLFloaterColorPicker:: -rgbToHsl ( F32 rValIn, F32 gValIn, F32 bValIn, F32& hValOut, F32& sValOut, F32& lValOut ) -{ -	F32 var_R = ( rValIn ); -	F32 var_G = ( gValIn ); -	F32 var_B = ( bValIn ); - -	F32 var_Min = ( var_R < ( var_G < var_B ? var_G : var_B ) ? var_R : ( var_G < var_B ? var_G : var_B ) ); -	F32 var_Max = ( var_R > ( var_G > var_B ? var_G : var_B ) ? var_R : ( var_G > var_B ? var_G : var_B ) ); - -	F32 del_Max = var_Max - var_Min; - -	F32 L = ( var_Max + var_Min ) / 2.0f; -	F32 H = 0.0f; -	F32 S = 0.0f; - -	if ( del_Max == 0.0f ) -	{ -	   H = 0.0f; -	   S = 0.0f; -	} -	else -	{ -		if ( L < 0.5 ) -			S = del_Max / ( var_Max + var_Min ); -		else -			S = del_Max / ( 2.0f - var_Max - var_Min ); - -		F32 del_R = ( ( ( var_Max - var_R ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; -		F32 del_G = ( ( ( var_Max - var_G ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; -		F32 del_B = ( ( ( var_Max - var_B ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; - -		if ( var_R >= var_Max ) -			H = del_B - del_G; -		else -		if ( var_G >= var_Max ) -			H = ( 1.0f / 3.0f ) + del_R - del_B; -		else -		if ( var_B >= var_Max ) -			H = ( 2.0f / 3.0f ) + del_G - del_R; - -		if ( H < 0.0f ) H += 1.0f; -		if ( H > 1.0f ) H -= 1.0f; -	} - -	// scale to meet calculation requirements -	hValOut = H * 360.0f / 360.0f; -	sValOut = S * 100.0f / 100.0f; -	lValOut = L * 100.0f / 100.0f; -}  //////////////////////////////////////////////////////////////////////////////  // @@ -407,7 +354,7 @@ setCurRgb ( F32 curRIn, F32 curGIn, F32 curBIn )  	curB = curBIn;  	// update corresponding HSL values and -	rgbToHsl ( curR, curG, curB, curH, curS, curL ); +	LLColor3(curRIn, curGIn, curBIn).calcHSL(&curH, &curS, &curL);  	// color changed so update text fields (fixes SL-16968)      // HACK: turn off the call back wilst we update the text or we recurse ourselves into oblivion @@ -706,7 +653,10 @@ getComplimentaryColor ( LLColor4& backgroundColor )  {  	// going to base calculation on luminance  	F32 hVal, sVal, lVal; -	rgbToHsl ( backgroundColor [ 0 ], backgroundColor [ 1 ], backgroundColor [ 2 ], hVal, sVal, lVal ); +	backgroundColor.calcHSL(&hVal, &sVal, &lVal); +	hVal *= 360.f; +	sVal *= 100.f; +	lVal *= 100.f;  	// fairly simple heuristic for now...!  	if ( lVal < 0.5f ) diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h index 7660aa8c2d..2a93c26501 100644 --- a/indra/newview/llfloatercolorpicker.h +++ b/indra/newview/llfloatercolorpicker.h @@ -91,7 +91,6 @@ class LLFloaterColorPicker  		// convert RGB to HSL and vice-versa  		void hslToRgb ( F32 hValIn, F32 sValIn, F32 lValIn, F32& rValOut, F32& gValOut, F32& bValOut ); -		void rgbToHsl ( F32 rValIn, F32 gValIn, F32 bValIn, F32& hValOut, F32& sValOut, F32& lValOut );  		F32	 hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn );  		void setActive(BOOL active); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 97b4a982d2..6a9965dbfb 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -57,6 +57,7 @@  #include "llviewertexteditor.h"  #include "llviewerwindow.h"  #include "llvieweruictrlfactory.h" +#include "llwebbrowserctrl.h"  #include "lluictrlfactory.h"  #include "viewer.h" @@ -115,6 +116,9 @@ const S32 SCRIPT_SEARCH_HEIGHT = 120;  const S32 SCRIPT_SEARCH_LABEL_WIDTH = 50;  const S32 SCRIPT_SEARCH_BUTTON_WIDTH = 80;  const S32 TEXT_EDIT_COLUMN_HEIGHT = 16; +const S32 MAX_HISTORY_COUNT = 10; +const F32 LIVE_HELP_REFRESH_TIME = 1.f; +  /// ---------------------------------------------------------------------------  /// LLFloaterScriptSearch  /// --------------------------------------------------------------------------- @@ -254,6 +258,7 @@ void LLFloaterScriptSearch::open()		/*Flawfinder: ignore*/  	LLFloater::open();		/*Flawfinder: ignore*/  	childSetFocus("search_text", TRUE);   } +  /// ---------------------------------------------------------------------------  /// LLScriptEdCore  /// --------------------------------------------------------------------------- @@ -276,7 +281,9 @@ LLScriptEdCore::LLScriptEdCore(  	mLoadCallback( load_callback ),  	mSaveCallback( save_callback ),  	mUserdata( userdata ), -	mForceClose( FALSE ) +	mForceClose( FALSE ), +	mLastHelpToken(NULL), +	mLiveHelpHistorySize(0)  {  	setFollowsAll();  	setBorderVisible(FALSE); @@ -336,14 +343,13 @@ LLScriptEdCore::LLScriptEdCore(  	initMenu(); -	  	// Do the work that addTabPanel() normally does.  	//LLRect tab_panel_rect( 0, mRect.getHeight(), mRect.getWidth(), 0 );  	//tab_panel_rect.stretch( -LLPANEL_BORDER_WIDTH );  	//mCodePanel->setFollowsAll();  	//mCodePanel->translate( tab_panel_rect.mLeft - mCodePanel->getRect().mLeft, tab_panel_rect.mBottom - mCodePanel->getRect().mBottom);  	//mCodePanel->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE ); -		 +	  }  LLScriptEdCore::~LLScriptEdCore() @@ -402,6 +408,9 @@ void LLScriptEdCore::initMenu()  	menuItem->setMenuCallback(onBtnHelp, this);  	menuItem->setEnabledCallback(NULL); +	menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "LSL Wiki Help..."); +	menuItem->setMenuCallback(onBtnDynamicHelp, this); +	menuItem->setEnabledCallback(NULL);  }  BOOL LLScriptEdCore::hasChanged(void* userdata) @@ -431,9 +440,135 @@ void LLScriptEdCore::draw()  		childSetText("line_col", "");  	} +	updateDynamicHelp(); +  	LLPanel::draw();  } +void LLScriptEdCore::updateDynamicHelp(BOOL immediate) +{ +	LLFloater* help_floater = LLFloater::getFloaterByHandle(mLiveHelpHandle); +	if (!help_floater) return; + +	// update back and forward buttons +	LLButton* fwd_button = LLUICtrlFactory::getButtonByName(help_floater, "fwd_btn"); +	LLButton* back_button = LLUICtrlFactory::getButtonByName(help_floater, "back_btn"); +	LLWebBrowserCtrl* browser = LLUICtrlFactory::getWebBrowserCtrlByName(help_floater, "lsl_guide_html"); +	back_button->setEnabled(browser->canNavigateBack()); +	fwd_button->setEnabled(browser->canNavigateForward()); + +	if (!immediate && !gSavedSettings.getBOOL("ScriptHelpFollowsCursor")) +	{ +		return; +	} + +	LLTextSegment* segment = NULL; +	std::vector<LLTextSegment*> selected_segments; +	mEditor->getSelectedSegments(selected_segments); + +	// try segments in selection range first +	std::vector<LLTextSegment*>::iterator segment_iter; +	for (segment_iter = selected_segments.begin(); segment_iter != selected_segments.end(); ++segment_iter) +	{ +		if((*segment_iter)->getToken() && (*segment_iter)->getToken()->getType() == LLKeywordToken::WORD) +		{ +			segment = *segment_iter; +			break; +		} +	} + +	// then try previous segment in case we just typed it +	if (!segment) +	{ +		LLTextSegment* test_segment = mEditor->getPreviousSegment(); +		if(test_segment->getToken() && test_segment->getToken()->getType() == LLKeywordToken::WORD) +		{ +			segment = test_segment; +		} +	} + +	if (segment) +	{ +		if (segment->getToken() != mLastHelpToken) +		{ +			mLastHelpToken = segment->getToken(); +			mLiveHelpTimer.start(); +		} +		if (immediate || (mLiveHelpTimer.getStarted() && mLiveHelpTimer.getElapsedTimeF32() > LIVE_HELP_REFRESH_TIME)) +		{ +			LLString help_string = mEditor->getText().substr(segment->getStart(), segment->getEnd() - segment->getStart()); +			setHelpPage(help_string); +			mLiveHelpTimer.stop(); +		} +	} +	else +	{ +		setHelpPage(""); +	} +} + +void LLScriptEdCore::setHelpPage(const LLString& help_string) +{ +	LLFloater* help_floater = LLFloater::getFloaterByHandle(mLiveHelpHandle); +	if (!help_floater) return; +	 +	LLWebBrowserCtrl* web_browser = gUICtrlFactory->getWebBrowserCtrlByName(help_floater, "lsl_guide_html"); +	if (!web_browser) return; + +	LLComboBox* history_combo = gUICtrlFactory->getComboBoxByName(help_floater, "history_combo"); +	if (!history_combo) return; + +	LLUIString url_string = gSavedSettings.getString("LSLHelpURL"); +	url_string.setArg("[APP_DIRECTORY]", gDirUtilp->getWorkingDir()); +	url_string.setArg("[LSL_STRING]", help_string); + +	addHelpItemToHistory(help_string); +	web_browser->navigateTo(url_string); +} + +void LLScriptEdCore::addHelpItemToHistory(const LLString& help_string) +{ +	if (help_string.empty()) return; + +	LLFloater* help_floater = LLFloater::getFloaterByHandle(mLiveHelpHandle); +	if (!help_floater) return; + +	LLComboBox* history_combo = gUICtrlFactory->getComboBoxByName(help_floater, "history_combo"); +	if (!history_combo) return; + +	// separate history items from full item list +	if (mLiveHelpHistorySize == 0) +	{ +		LLSD row; +		row["columns"][0]["type"] = "separator"; +		history_combo->addElement(row, ADD_TOP); +	} +	// delete all history items over history limit +	while(mLiveHelpHistorySize > MAX_HISTORY_COUNT - 1) +	{ +		history_combo->remove(mLiveHelpHistorySize - 1); +		mLiveHelpHistorySize--; +	} + +	history_combo->setSimple(help_string); +	S32 index = history_combo->getCurrentIndex(); + +	// if help string exists in the combo box +	if (index >= 0) +	{ +		S32 cur_index = history_combo->getCurrentIndex(); +		if (cur_index < mLiveHelpHistorySize) +		{ +			// item found in history, bubble up to top +			history_combo->remove(history_combo->getCurrentIndex()); +			mLiveHelpHistorySize--; +		} +	} +	history_combo->add(help_string, LLSD(help_string), ADD_TOP); +	history_combo->selectFirstItem(); +	mLiveHelpHistorySize++; +} +  BOOL LLScriptEdCore::canClose()  {  	if(mForceClose || mEditor->isPristine()) @@ -498,6 +633,92 @@ void LLScriptEdCore::onBtnHelp(void* userdata)  }  // static  +void LLScriptEdCore::onBtnDynamicHelp(void* userdata) +{ +	LLScriptEdCore* corep = (LLScriptEdCore*)userdata; + +	LLFloater* live_help_floater = LLFloater::getFloaterByHandle(corep->mLiveHelpHandle); +	if (live_help_floater) +	{ +		live_help_floater->setFocus(TRUE); +		corep->updateDynamicHelp(TRUE); + +		return; +	} + +	live_help_floater = new LLFloater("lsl_help"); +	gUICtrlFactory->buildFloater(live_help_floater, "floater_lsl_guide.xml"); +	((LLFloater*)corep->getParent())->addDependentFloater(live_help_floater, TRUE); +	live_help_floater->childSetCommitCallback("lock_check", onCheckLock, userdata); +	live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor")); +	live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, userdata); +	live_help_floater->childSetAction("back_btn", onClickBack, userdata); +	live_help_floater->childSetAction("fwd_btn", onClickForward, userdata); + +	LLWebBrowserCtrl* browser = LLUICtrlFactory::getWebBrowserCtrlByName(live_help_floater, "lsl_guide_html"); +	browser->setAlwaysRefresh(TRUE); + +	LLComboBox* help_combo = LLUICtrlFactory::getComboBoxByName(live_help_floater, "history_combo"); +	LLKeywordToken *token; +	LLKeywords::word_token_map_t::iterator token_it; +	for (token_it = corep->mEditor->mKeywords.mWordTokenMap.begin();  +		token_it != corep->mEditor->mKeywords.mWordTokenMap.end();  +		++token_it) +	{ +		token = token_it->second; +		help_combo->add(wstring_to_utf8str(token->mToken)); +	} +	help_combo->sortByName(); + +	// re-initialize help variables +	corep->mLastHelpToken = NULL; +	corep->mLiveHelpHandle = live_help_floater->getHandle(); +	corep->mLiveHelpHistorySize = 0; +	corep->updateDynamicHelp(TRUE); +} + +//static  +void LLScriptEdCore::onClickBack(void* userdata) +{ +	LLScriptEdCore* corep = (LLScriptEdCore*)userdata; +	LLFloater* live_help_floater = LLFloater::getFloaterByHandle(corep->mLiveHelpHandle); +	if (live_help_floater) +	{ +		LLWebBrowserCtrl* browserp = LLUICtrlFactory::getWebBrowserCtrlByName(live_help_floater, "lsl_guide_html"); +		if (browserp) +		{ +			browserp->navigateBack(); +		} +	} +} + +//static  +void LLScriptEdCore::onClickForward(void* userdata) +{ +	LLScriptEdCore* corep = (LLScriptEdCore*)userdata; +	LLFloater* live_help_floater = LLFloater::getFloaterByHandle(corep->mLiveHelpHandle); +	if (live_help_floater) +	{ +		LLWebBrowserCtrl* browserp = LLUICtrlFactory::getWebBrowserCtrlByName(live_help_floater, "lsl_guide_html"); +		if (browserp) +		{ +			browserp->navigateForward(); +		} +	} +} + +// static +void LLScriptEdCore::onCheckLock(LLUICtrl* ctrl, void* userdata) +{ +	LLScriptEdCore* corep = (LLScriptEdCore*)userdata; + +	// clear out token any time we lock the frame, so we will refresh web page immediately when unlocked +	gSavedSettings.setBOOL("ScriptHelpFollowsCursor", ctrl->getValue().asBoolean()); + +	corep->mLastHelpToken = NULL; +} + +// static   void LLScriptEdCore::onBtnInsertSample(void* userdata)  {  	LLScriptEdCore* self = (LLScriptEdCore*) userdata; @@ -509,6 +730,27 @@ void LLScriptEdCore::onBtnInsertSample(void* userdata)  }  // static  +void LLScriptEdCore::onHelpComboCommit(LLUICtrl* ctrl, void* userdata) +{ +	LLScriptEdCore* corep = (LLScriptEdCore*)userdata; + +	LLFloater* live_help_floater = LLFloater::getFloaterByHandle(corep->mLiveHelpHandle); +	if (live_help_floater) +	{ +		LLWebBrowserCtrl* web_browser = gUICtrlFactory->getWebBrowserCtrlByName(live_help_floater, "lsl_guide_html"); + +		LLString help_string = ctrl->getValue().asString(); + +		corep->addHelpItemToHistory(help_string); + +		LLUIString url_string = gSavedSettings.getString("LSLHelpURL"); +		url_string.setArg("[APP_DIRECTORY]", gDirUtilp->getWorkingDir()); +		url_string.setArg("[LSL_STRING]", help_string); +		web_browser->navigateTo(url_string); +	} +} + +// static   void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata)  {  	LLScriptEdCore* self = (LLScriptEdCore*) userdata; @@ -519,6 +761,7 @@ void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata)  		self->mEditor->insertText(self->mFunctions->getSimple());  	}  	self->mEditor->setFocus(TRUE); +	self->setHelpPage(self->mFunctions->getSimple());  }  // static  diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 5b15fda222..54b27316f7 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -15,6 +15,7 @@  #include "llinventory.h"  #include "llcombobox.h"  #include "lliconctrl.h" +#include "llframetimer.h"  class LLMessageSystem; @@ -26,6 +27,7 @@ class LLViewerObject;  struct 	LLEntryAndEdCore;  class LLMenuBarGL;  class LLFloaterScriptSearch; +class LLKeywordToken;  // Inner, implementation class.  LLPreviewScript and LLLiveScriptEditor each own one of these.  class LLScriptEdCore : public LLPanel @@ -60,6 +62,11 @@ public:  	static void		onHelpWebDialog(S32 option, void* userdata);  	static void		onBtnHelp(void* userdata); +	static void		onBtnDynamicHelp(void* userdata); +	static void		onCheckLock(LLUICtrl*, void*); +	static void		onHelpComboCommit(LLUICtrl* ctrl, void* userdata); +	static void		onClickBack(void* userdata); +	static void		onClickForward(void* userdata);  	static void		onBtnInsertSample(void*);  	static void		onBtnInsertFunction(LLUICtrl*, void*);  	static void		doSave( void* userdata, BOOL close_after_save ); @@ -91,6 +98,9 @@ public:  protected:  	void deleteBridges(); +	void setHelpPage(const LLString& help_string); +	void updateDynamicHelp(BOOL immediate = FALSE); +	void addHelpItemToHistory(const LLString& help_string);  	static void onErrorList(LLUICtrl*, void* user_data); @@ -107,6 +117,10 @@ private:  	LLPanel*		mCodePanel;  	LLScrollListCtrl* mErrorList;  	LLDynamicArray<LLEntryAndEdCore*> mBridges; +	LLViewHandle	mLiveHelpHandle; +	LLKeywordToken* mLastHelpToken; +	LLFrameTimer	mLiveHelpTimer; +	S32				mLiveHelpHistorySize;  };  | 
