382 lines
9.9 KiB
C++
382 lines
9.9 KiB
C++
/**
|
|
* @file llcolorswatch.cpp
|
|
* @brief LLColorSwatch class implementation
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (c) 2001-2009, Linden Research, Inc.
|
|
*
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
// File include
|
|
#include "llcolorswatch.h"
|
|
|
|
// Linden library includes
|
|
#include "v4color.h"
|
|
#include "llwindow.h" // setCursor()
|
|
|
|
// Project includes
|
|
#include "llui.h"
|
|
#include "llrender.h"
|
|
#include "lluiconstants.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llbutton.h"
|
|
#include "lltextbox.h"
|
|
#include "llfloatercolorpicker.h"
|
|
#include "llviewborder.h"
|
|
#include "llviewertexturelist.h"
|
|
#include "llfocusmgr.h"
|
|
|
|
static LLRegisterWidget<LLColorSwatchCtrl> r("color_swatch");
|
|
|
|
LLColorSwatchCtrl::LLColorSwatchCtrl(const std::string& name, const LLRect& rect, const std::string& label, const LLColor4& color)
|
|
: LLUICtrl(name, rect, TRUE, NULL, FOLLOWS_LEFT | FOLLOWS_TOP),
|
|
mValid( TRUE ),
|
|
mColor( color ),
|
|
mBorderColor( gColors.getColor("DefaultHighlightLight") ),
|
|
mCanApplyImmediately(FALSE),
|
|
mOnCancelCallback(NULL),
|
|
mOnSelectCallback(NULL)
|
|
{
|
|
mCaption = new LLTextBox( label,
|
|
LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ),
|
|
label,
|
|
LLFontGL::getFontSansSerifSmall() );
|
|
mCaption->setFollows( FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM );
|
|
addChild( mCaption );
|
|
|
|
// Scalable UI made this off-by-one, I don't know why. JC
|
|
LLRect border_rect(0, getRect().getHeight()-1, getRect().getWidth()-1, 0);
|
|
border_rect.mBottom += BTN_HEIGHT_SMALL;
|
|
mBorder = new LLViewBorder(std::string("border"), border_rect, LLViewBorder::BEVEL_IN);
|
|
addChild(mBorder);
|
|
|
|
mAlphaGradientImage = LLUI::getUIImage("color_swatch_alpha.tga");
|
|
}
|
|
|
|
LLColorSwatchCtrl::~LLColorSwatchCtrl ()
|
|
{
|
|
// parent dialog is destroyed so we are too and we need to cancel selection
|
|
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get();
|
|
if (pickerp)
|
|
{
|
|
pickerp->cancelSelection();
|
|
pickerp->close();
|
|
}
|
|
mAlphaGradientImage = NULL;
|
|
}
|
|
|
|
BOOL LLColorSwatchCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
|
|
{
|
|
return handleMouseDown(x, y, mask);
|
|
}
|
|
|
|
BOOL LLColorSwatchCtrl::handleHover(S32 x, S32 y, MASK mask)
|
|
{
|
|
getWindow()->setCursor(UI_CURSOR_HAND);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLColorSwatchCtrl::handleUnicodeCharHere(llwchar uni_char)
|
|
{
|
|
if( ' ' == uni_char )
|
|
{
|
|
showPicker(TRUE);
|
|
}
|
|
return LLUICtrl::handleUnicodeCharHere(uni_char);
|
|
}
|
|
|
|
// forces color of this swatch and any associated floater to the input value, if currently invalid
|
|
void LLColorSwatchCtrl::setOriginal(const LLColor4& color)
|
|
{
|
|
mColor = color;
|
|
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get();
|
|
if (pickerp)
|
|
{
|
|
pickerp->setOrigRgb(mColor.mV[VRED], mColor.mV[VGREEN], mColor.mV[VBLUE]);
|
|
}
|
|
}
|
|
|
|
void LLColorSwatchCtrl::set(const LLColor4& color, BOOL update_picker, BOOL from_event)
|
|
{
|
|
mColor = color;
|
|
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get();
|
|
if (pickerp && update_picker)
|
|
{
|
|
pickerp->setCurRgb(mColor.mV[VRED], mColor.mV[VGREEN], mColor.mV[VBLUE]);
|
|
}
|
|
if (!from_event)
|
|
{
|
|
setControlValue(mColor.getValue());
|
|
}
|
|
}
|
|
|
|
void LLColorSwatchCtrl::setLabel(const std::string& label)
|
|
{
|
|
mCaption->setText(label);
|
|
}
|
|
|
|
BOOL LLColorSwatchCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
|
|
{
|
|
// Route future Mouse messages here preemptively. (Release on mouse up.)
|
|
// No handler is needed for capture lost since this object has no state that depends on it.
|
|
gFocusMgr.setMouseCapture( this );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL LLColorSwatchCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
|
|
{
|
|
// We only handle the click if the click both started and ended within us
|
|
if( hasMouseCapture() )
|
|
{
|
|
// Release the mouse
|
|
gFocusMgr.setMouseCapture( NULL );
|
|
|
|
// If mouseup in the widget, it's been clicked
|
|
if ( pointInView(x, y) )
|
|
{
|
|
llassert(getEnabled());
|
|
llassert(getVisible());
|
|
|
|
// Focus the widget now in order to return the focus
|
|
// after the color picker is closed.
|
|
setFocus(TRUE);
|
|
showPicker(FALSE);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// assumes GL state is set for 2D
|
|
void LLColorSwatchCtrl::draw()
|
|
{
|
|
mBorder->setKeyboardFocusHighlight(hasFocus());
|
|
// Draw border
|
|
LLRect border( 0, getRect().getHeight(), getRect().getWidth(), BTN_HEIGHT_SMALL );
|
|
gl_rect_2d( border, mBorderColor, FALSE );
|
|
|
|
LLRect interior = border;
|
|
interior.stretch( -1 );
|
|
|
|
// Check state
|
|
if ( mValid )
|
|
{
|
|
if (!mColor.isOpaque())
|
|
{
|
|
gl_rect_2d_checkerboard( calcScreenRect(), interior );
|
|
// Draw the color swatch
|
|
}
|
|
|
|
gl_rect_2d(interior, mColor, TRUE);
|
|
if (!mColor.isOpaque())
|
|
{
|
|
LLColor4 opaque_color = mColor;
|
|
opaque_color.mV[VALPHA] = 1.f;
|
|
gGL.color4fv(opaque_color.mV);
|
|
if (mAlphaGradientImage.notNull())
|
|
{
|
|
gGL.pushMatrix();
|
|
{
|
|
mAlphaGradientImage->draw(interior, mColor);
|
|
}
|
|
gGL.popMatrix();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!mFallbackImageName.empty())
|
|
{
|
|
LLPointer<LLViewerFetchedTexture> fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE,
|
|
LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
|
if( fallback_image->getComponents() == 4 )
|
|
{
|
|
gl_rect_2d_checkerboard( calcScreenRect(), interior );
|
|
}
|
|
gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), fallback_image);
|
|
fallback_image->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
|
|
}
|
|
else
|
|
{
|
|
// Draw grey and an X
|
|
gl_rect_2d(interior, LLColor4::grey, TRUE);
|
|
|
|
gl_draw_x(interior, LLColor4::black);
|
|
}
|
|
}
|
|
|
|
LLUICtrl::draw();
|
|
}
|
|
|
|
void LLColorSwatchCtrl::setEnabled( BOOL enabled )
|
|
{
|
|
mCaption->setEnabled( enabled );
|
|
LLView::setEnabled( enabled );
|
|
|
|
if (!enabled)
|
|
{
|
|
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get();
|
|
if (pickerp)
|
|
{
|
|
pickerp->cancelSelection();
|
|
pickerp->close();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void LLColorSwatchCtrl::setValue(const LLSD& value)
|
|
{
|
|
set(LLColor4(value), TRUE, TRUE);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// called (infrequently) when the color changes so the subject of the swatch can be updated.
|
|
void LLColorSwatchCtrl::onColorChanged ( void* data, EColorPickOp pick_op )
|
|
{
|
|
LLColorSwatchCtrl* subject = ( LLColorSwatchCtrl* )data;
|
|
if ( subject )
|
|
{
|
|
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)subject->mPickerHandle.get();
|
|
if (pickerp)
|
|
{
|
|
// move color across from selector to internal widget storage
|
|
LLColor4 updatedColor ( pickerp->getCurR (),
|
|
pickerp->getCurG (),
|
|
pickerp->getCurB (),
|
|
subject->mColor.mV[VALPHA] ); // keep current alpha
|
|
subject->mColor = updatedColor;
|
|
subject->setControlValue(updatedColor.getValue());
|
|
|
|
if (pick_op == COLOR_CANCEL && subject->mOnCancelCallback)
|
|
{
|
|
subject->mOnCancelCallback(subject, LLSD());
|
|
}
|
|
else if (pick_op == COLOR_SELECT && subject->mOnSelectCallback)
|
|
{
|
|
subject->mOnSelectCallback(subject, LLSD());
|
|
}
|
|
else
|
|
{
|
|
// just commit change
|
|
subject->onCommit ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLColorSwatchCtrl::setValid(BOOL valid )
|
|
{
|
|
mValid = valid;
|
|
|
|
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get();
|
|
if (pickerp)
|
|
{
|
|
pickerp->setActive(valid);
|
|
}
|
|
}
|
|
|
|
void LLColorSwatchCtrl::showPicker(BOOL take_focus)
|
|
{
|
|
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get();
|
|
if (!pickerp)
|
|
{
|
|
pickerp = new LLFloaterColorPicker(this, mCanApplyImmediately);
|
|
LLFloater* parent = gFloaterView->getParentFloater(this);
|
|
if (parent)
|
|
{
|
|
parent->addDependentFloater(pickerp);
|
|
}
|
|
mPickerHandle = pickerp->getHandle();
|
|
}
|
|
|
|
// initialize picker with current color
|
|
pickerp->initUI ( mColor.mV [ VRED ], mColor.mV [ VGREEN ], mColor.mV [ VBLUE ] );
|
|
|
|
// display it
|
|
pickerp->showUI ();
|
|
|
|
if (take_focus)
|
|
{
|
|
pickerp->setFocus(TRUE);
|
|
}
|
|
}
|
|
|
|
// virtual
|
|
LLXMLNodePtr LLColorSwatchCtrl::getXML(bool save_children) const
|
|
{
|
|
LLXMLNodePtr node = LLUICtrl::getXML();
|
|
|
|
node->setName(LL_COLOR_SWATCH_CTRL_TAG);
|
|
|
|
node->createChild("color", TRUE)->setFloatValue(4, mColor.mV);
|
|
|
|
node->createChild("border_color", TRUE)->setFloatValue(4, mBorderColor.mV);
|
|
|
|
if (mCaption)
|
|
{
|
|
node->createChild("label", TRUE)->setStringValue(mCaption->getText());
|
|
}
|
|
|
|
node->createChild("can_apply_immediately", TRUE)->setBoolValue(mCanApplyImmediately);
|
|
|
|
return node;
|
|
}
|
|
|
|
LLView* LLColorSwatchCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
|
|
{
|
|
std::string label;
|
|
node->getAttributeString("label", label);
|
|
|
|
LLColor4 color(1.f, 1.f, 1.f, 1.f);
|
|
node->getAttributeColor("initial_color", color);
|
|
|
|
LLRect rect;
|
|
createRect(node, rect, parent, LLRect());
|
|
|
|
BOOL can_apply_immediately = FALSE;
|
|
node->getAttributeBOOL("can_apply_immediately", can_apply_immediately);
|
|
|
|
if (label.empty())
|
|
{
|
|
label.assign(node->getValue());
|
|
}
|
|
|
|
LLColorSwatchCtrl* color_swatch = new LLColorSwatchCtrl(
|
|
"colorswatch",
|
|
rect,
|
|
label,
|
|
color );
|
|
|
|
color_swatch->setCanApplyImmediately(can_apply_immediately);
|
|
color_swatch->initFromXML(node, parent);
|
|
|
|
return color_swatch;
|
|
}
|