summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llmath/v3color.cpp49
-rw-r--r--indra/llmath/v3color.h2
-rw-r--r--indra/llmath/v4color.cpp49
-rw-r--r--indra/llmath/v4color.h2
-rw-r--r--indra/llrender/llfontgl.cpp181
-rw-r--r--indra/llrender/llfontgl.h3
-rw-r--r--indra/llui/llcombobox.cpp5
-rw-r--r--indra/llui/llfloater.cpp37
-rw-r--r--indra/llui/llscrolllistctrl.cpp17
-rw-r--r--indra/llui/llscrolllistctrl.h15
-rw-r--r--indra/llui/lltexteditor.cpp25
-rw-r--r--indra/llui/lltexteditor.h4
-rw-r--r--indra/newview/llfloatercolorpicker.cpp60
-rw-r--r--indra/newview/llfloatercolorpicker.h1
-rw-r--r--indra/newview/llpreviewscript.cpp249
-rw-r--r--indra/newview/llpreviewscript.h14
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;
};