diff options
-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; }; |