PageRenderTime 1062ms CodeModel.GetById 232ms app.highlight 609ms RepoModel.GetById 140ms app.codeStats 1ms

/indra/newview/llfloatercolorpicker.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1115 lines | 767 code | 164 blank | 184 comment | 100 complexity | c1ddea8c613e61db32521aa369bd8575 MD5 | raw file
   1/** 
   2 * @file llfloatercolorpicker.cpp
   3 * @brief Generic system color picker
   4 *
   5 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llfloatercolorpicker.h"
  30
  31// Viewer project includes
  32#include "lltoolmgr.h"
  33#include "lltoolpipette.h"
  34#include "llviewercontrol.h"
  35#include "llworld.h"
  36
  37// Linden library includes
  38#include "llfontgl.h"
  39#include "llsys.h"
  40#include "llgl.h"
  41#include "llrender.h"
  42#include "v3dmath.h"
  43#include "lldir.h"
  44#include "llui.h"
  45#include "lllineeditor.h"
  46#include "v4coloru.h"
  47#include "llbutton.h"
  48#include "lluictrlfactory.h"
  49#include "llgl.h"
  50#include "llpointer.h"
  51#include "llimage.h"
  52#include "llmousehandler.h"
  53#include "llglheaders.h"
  54#include "llcheckboxctrl.h"
  55#include "lltextbox.h"
  56#include "lluiconstants.h"
  57#include "llfocusmgr.h"
  58#include "lldraghandle.h"
  59#include "llwindow.h"
  60
  61// System includes
  62#include <sstream>
  63#include <iomanip>
  64
  65const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
  66const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
  67const F32 CONTEXT_FADE_TIME = 0.08f;
  68
  69//////////////////////////////////////////////////////////////////////////////
  70//
  71// Class LLFloaterColorPicker
  72//
  73//////////////////////////////////////////////////////////////////////////////
  74
  75LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate )
  76	: LLFloater(LLSD()),
  77	  mComponents			( 3 ),
  78	  mMouseDownInLumRegion	( FALSE ),
  79	  mMouseDownInHueRegion	( FALSE ),
  80	  mMouseDownInSwatch	( FALSE ),
  81	  // *TODO: Specify this in XML
  82	  mRGBViewerImageLeft	( 140 ),
  83	  mRGBViewerImageTop	( 356 ),
  84	  mRGBViewerImageWidth	( 256 ),
  85	  mRGBViewerImageHeight ( 256 ),
  86	  mLumRegionLeft		( mRGBViewerImageLeft + mRGBViewerImageWidth + 16 ),
  87	  mLumRegionTop			( mRGBViewerImageTop ),
  88	  mLumRegionWidth		( 16 ),
  89	  mLumRegionHeight		( mRGBViewerImageHeight ),
  90	  mLumMarkerSize		( 6 ),
  91	  // *TODO: Specify this in XML
  92	  mSwatchRegionLeft		( 12 ),
  93	  mSwatchRegionTop		( 190 ),
  94	  mSwatchRegionWidth	( 116 ),
  95	  mSwatchRegionHeight	( 60 ),
  96	  mSwatchView			( NULL ),
  97	  // *TODO: Specify this in XML
  98	  numPaletteColumns		( 16 ),
  99	  numPaletteRows		( 2 ),
 100	  highlightEntry		( -1 ),
 101	  mPaletteRegionLeft	( 11 ),
 102	  mPaletteRegionTop		( 100 - 8 ),
 103	  mPaletteRegionWidth	( mLumRegionLeft + mLumRegionWidth - 10 ),
 104	  mPaletteRegionHeight	( 40 ),
 105	  mSwatch				( swatch ),
 106	  mActive				( TRUE ),
 107	  mCanApplyImmediately	( show_apply_immediate ),
 108	  mContextConeOpacity	( 0.f )
 109{
 110	buildFromFile ( "floater_color_picker.xml");
 111
 112	// create user interface for this picker
 113	createUI ();
 114
 115	if (!mCanApplyImmediately)
 116	{
 117		mApplyImmediateCheck->setEnabled(FALSE);
 118		mApplyImmediateCheck->set(FALSE);
 119	}
 120}
 121
 122LLFloaterColorPicker::~LLFloaterColorPicker()
 123{
 124	// destroy the UI we created
 125	destroyUI ();
 126}
 127
 128//////////////////////////////////////////////////////////////////////////////
 129//
 130void LLFloaterColorPicker::createUI ()
 131{
 132	// create RGB type area (not really RGB but it's got R,G & B in it.,..
 133
 134	LLPointer<LLImageRaw> raw = new LLImageRaw ( mRGBViewerImageWidth, mRGBViewerImageHeight, mComponents );
 135	U8* bits = raw->getData();
 136	S32 linesize = mRGBViewerImageWidth * mComponents;
 137	for ( S32 y = 0; y < mRGBViewerImageHeight; ++y )
 138	{
 139		for ( S32 x = 0; x < linesize; x += mComponents )
 140		{
 141			F32 rVal, gVal, bVal;
 142
 143			hslToRgb ( (F32)x / (F32) ( linesize - 1 ),
 144					   (F32)y / (F32) ( mRGBViewerImageHeight - 1 ),
 145					   0.5f,
 146					   rVal,
 147					   gVal,
 148					   bVal );
 149
 150			* ( bits + x + y * linesize + 0 ) = ( U8 )( rVal * 255.0f );
 151			* ( bits + x + y * linesize + 1 ) = ( U8 )( gVal * 255.0f );
 152			* ( bits + x + y * linesize + 2 ) = ( U8 )( bVal * 255.0f );
 153		}
 154	}
 155	mRGBImage = LLViewerTextureManager::getLocalTexture( (LLImageRaw*)raw, FALSE );
 156	gGL.getTexUnit(0)->bind(mRGBImage);
 157	mRGBImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 158	
 159	// create palette
 160	for ( S32 each = 0; each < numPaletteColumns * numPaletteRows; ++each )
 161	{
 162		std::ostringstream codec;
 163		codec << "ColorPaletteEntry" << std::setfill ( '0' ) << std::setw ( 2 ) << each + 1;
 164
 165		// argh!
 166		const std::string s ( codec.str () );
 167		mPalette.push_back ( new LLColor4 ( LLUIColorTable::instance().getColor ( s )  ) );
 168	}
 169}
 170
 171//////////////////////////////////////////////////////////////////////////////
 172//
 173void LLFloaterColorPicker::showUI ()
 174{
 175	setVisible ( TRUE );
 176	setFocus ( TRUE );
 177	openFloater(getKey());
 178
 179	// HACK: if system color picker is required - close the SL one we made and use default system dialog
 180	if ( gSavedSettings.getBOOL ( "UseDefaultColorPicker" ) )
 181	{
 182		LLColorSwatchCtrl* swatch = getSwatch ();
 183
 184		setVisible ( FALSE );
 185
 186		// code that will get switched in for default system color picker
 187		if ( swatch )
 188		{
 189			LLColor4 curCol = swatch->get ();
 190			send_agent_pause();
 191			getWindow()->dialogColorPicker( &curCol [ 0 ], &curCol [ 1 ], &curCol [ 2 ] );
 192			send_agent_resume();
 193
 194			setOrigRgb ( curCol [ 0 ], curCol [ 1 ], curCol [ 2 ] );
 195			setCurRgb( curCol [ 0 ], curCol [ 1 ], curCol [ 2 ] );
 196
 197			LLColorSwatchCtrl::onColorChanged ( swatch, LLColorSwatchCtrl::COLOR_CHANGE );
 198		}
 199
 200		closeFloater();
 201	}
 202}
 203
 204//////////////////////////////////////////////////////////////////////////////
 205// called after the dialog is rendered
 206BOOL LLFloaterColorPicker::postBuild()
 207{
 208	mCancelBtn = getChild<LLButton>( "cancel_btn" );
 209    mCancelBtn->setClickedCallback ( onClickCancel, this );
 210
 211	mSelectBtn = getChild<LLButton>( "select_btn");
 212    mSelectBtn->setClickedCallback ( onClickSelect, this );
 213	mSelectBtn->setFocus ( TRUE );
 214
 215	mPipetteBtn = getChild<LLButton>("color_pipette" );
 216
 217	mPipetteBtn->setImages(std::string("eye_button_inactive.tga"), std::string("eye_button_active.tga"));
 218
 219	mPipetteBtn->setCommitCallback( boost::bind(&LLFloaterColorPicker::onClickPipette, this ));
 220
 221	mApplyImmediateCheck = getChild<LLCheckBoxCtrl>("apply_immediate");
 222	mApplyImmediateCheck->set(gSavedSettings.getBOOL("ApplyColorImmediately"));
 223	mApplyImmediateCheck->setCommitCallback(onImmediateCheck, this);
 224
 225	childSetCommitCallback("rspin", onTextCommit, (void*)this );
 226	childSetCommitCallback("gspin", onTextCommit, (void*)this );
 227	childSetCommitCallback("bspin", onTextCommit, (void*)this );
 228	childSetCommitCallback("hspin", onTextCommit, (void*)this );
 229	childSetCommitCallback("sspin", onTextCommit, (void*)this );
 230	childSetCommitCallback("lspin", onTextCommit, (void*)this );
 231
 232	LLToolPipette::getInstance()->setToolSelectCallback(boost::bind(&LLFloaterColorPicker::onColorSelect, this, _1));
 233
 234    return TRUE;
 235}
 236
 237//////////////////////////////////////////////////////////////////////////////
 238//
 239void LLFloaterColorPicker::initUI ( F32 rValIn, F32 gValIn, F32 bValIn )
 240{
 241	// under some circumstances, we get rogue values that can be calmed by clamping...
 242	rValIn = llclamp ( rValIn, 0.0f, 1.0f );
 243	gValIn = llclamp ( gValIn, 0.0f, 1.0f );
 244	bValIn = llclamp ( bValIn, 0.0f, 1.0f );
 245
 246	// store initial value in case cancel or revert is selected
 247	setOrigRgb ( rValIn, gValIn, bValIn );
 248
 249	// starting point for current value to
 250	setCurRgb ( rValIn, gValIn, bValIn );
 251
 252	// unpdate text entry fields
 253	updateTextEntry ();
 254}
 255
 256//////////////////////////////////////////////////////////////////////////////
 257//
 258void LLFloaterColorPicker::destroyUI ()
 259{
 260	// shut down pipette tool if active
 261	stopUsingPipette();
 262
 263	// delete palette we created
 264	std::vector < LLColor4* >::iterator iter = mPalette.begin ();
 265	while ( iter != mPalette.end () )
 266	{
 267		delete ( *iter );
 268		++iter;
 269	}
 270
 271	if ( mSwatchView )
 272	{
 273		this->removeChild ( mSwatchView );
 274		mSwatchView->die();;
 275		mSwatchView = NULL;
 276	}
 277}
 278
 279
 280//////////////////////////////////////////////////////////////////////////////
 281//
 282F32 LLFloaterColorPicker::hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn )
 283{
 284	if ( valHUeIn < 0.0f ) valHUeIn += 1.0f;
 285	if ( valHUeIn > 1.0f ) valHUeIn -= 1.0f;
 286	if ( ( 6.0f * valHUeIn ) < 1.0f ) return ( val1In + ( val2In - val1In ) * 6.0f * valHUeIn );
 287	if ( ( 2.0f * valHUeIn ) < 1.0f ) return ( val2In );
 288	if ( ( 3.0f * valHUeIn ) < 2.0f ) return ( val1In + ( val2In - val1In ) * ( ( 2.0f / 3.0f ) - valHUeIn ) * 6.0f );
 289	return ( val1In );
 290}
 291
 292//////////////////////////////////////////////////////////////////////////////
 293//
 294void LLFloaterColorPicker::hslToRgb ( F32 hValIn, F32 sValIn, F32 lValIn, F32& rValOut, F32& gValOut, F32& bValOut )
 295{
 296	if ( sValIn < 0.00001f )
 297	{
 298		rValOut = lValIn;
 299		gValOut = lValIn;
 300		bValOut = lValIn;
 301	}
 302	else
 303	{
 304		F32 interVal1;
 305		F32 interVal2;
 306
 307		if ( lValIn < 0.5f )
 308			interVal2 = lValIn * ( 1.0f + sValIn );
 309		else
 310			interVal2 = ( lValIn + sValIn ) - ( sValIn * lValIn );
 311
 312		interVal1 = 2.0f * lValIn - interVal2;
 313
 314		rValOut = hueToRgb ( interVal1, interVal2, hValIn + ( 1.f / 3.f ) );
 315		gValOut = hueToRgb ( interVal1, interVal2, hValIn );
 316		bValOut = hueToRgb ( interVal1, interVal2, hValIn - ( 1.f / 3.f ) );
 317	}
 318}
 319
 320//////////////////////////////////////////////////////////////////////////////
 321// mutator for original RGB value
 322void LLFloaterColorPicker::setOrigRgb ( F32 origRIn, F32 origGIn, F32 origBIn )
 323{
 324	origR = origRIn;
 325	origG = origGIn;
 326	origB = origBIn;
 327}
 328
 329//////////////////////////////////////////////////////////////////////////////
 330// accessor for original RGB value
 331void LLFloaterColorPicker::getOrigRgb ( F32& origROut, F32& origGOut, F32& origBOut )
 332{
 333	origROut = origR;
 334	origGOut = origG;
 335	origBOut = origB;
 336}
 337
 338//////////////////////////////////////////////////////////////////////////////
 339// mutator for current RGB value
 340void LLFloaterColorPicker::setCurRgb ( F32 curRIn, F32 curGIn, F32 curBIn )
 341{
 342	// save current RGB
 343	curR = curRIn;
 344	curG = curGIn;
 345	curB = curBIn;
 346
 347	// update corresponding HSL values and
 348	LLColor3(curRIn, curGIn, curBIn).calcHSL(&curH, &curS, &curL);
 349
 350	// color changed so update text fields
 351    updateTextEntry();
 352}
 353
 354//////////////////////////////////////////////////////////////////////////////
 355// accessor for current RGB value
 356void LLFloaterColorPicker::getCurRgb ( F32& curROut, F32& curGOut, F32& curBOut )
 357{
 358	curROut = curR;
 359	curGOut = curG;
 360	curBOut = curB;
 361}
 362
 363//////////////////////////////////////////////////////////////////////////////
 364// mutator for current HSL value
 365void LLFloaterColorPicker::setCurHsl ( F32 curHIn, F32 curSIn, F32 curLIn )
 366{
 367	// save current HSL
 368	curH = curHIn;
 369	curS = curSIn;
 370	curL = curLIn;
 371
 372	// update corresponding RGB values and
 373	hslToRgb ( curH, curS, curL, curR, curG, curB );
 374}
 375
 376//////////////////////////////////////////////////////////////////////////////
 377// accessor for current HSL value
 378void LLFloaterColorPicker::getCurHsl ( F32& curHOut, F32& curSOut, F32& curLOut )
 379{
 380	curHOut = curH;
 381	curSOut = curS;
 382	curLOut = curL;
 383}
 384
 385//////////////////////////////////////////////////////////////////////////////
 386// called when 'cancel' clicked
 387void LLFloaterColorPicker::onClickCancel ( void* data )
 388{
 389	if (data)
 390	{
 391		LLFloaterColorPicker* self = ( LLFloaterColorPicker* )data;
 392
 393		if ( self )
 394		{
 395			self->cancelSelection ();
 396			self->closeFloater();
 397		}
 398	}
 399}
 400
 401//////////////////////////////////////////////////////////////////////////////
 402// called when 'select' clicked
 403void LLFloaterColorPicker::onClickSelect ( void* data )
 404{
 405	if (data)
 406	{
 407		LLFloaterColorPicker* self = ( LLFloaterColorPicker* )data;
 408
 409		if ( self )
 410		{
 411			// apply to selection
 412			LLColorSwatchCtrl::onColorChanged ( self->getSwatch (), LLColorSwatchCtrl::COLOR_SELECT );
 413			self->closeFloater();
 414		}
 415	}
 416}
 417
 418void LLFloaterColorPicker::onClickPipette( )
 419{
 420	BOOL pipette_active = mPipetteBtn->getToggleState();
 421	pipette_active = !pipette_active;
 422	if (pipette_active)
 423	{
 424		LLToolMgr::getInstance()->setTransientTool(LLToolPipette::getInstance());
 425	}
 426	else
 427	{
 428		LLToolMgr::getInstance()->clearTransientTool();
 429	}
 430}
 431
 432//////////////////////////////////////////////////////////////////////////////
 433// called when 'text is committed' - i,e. focus moves from a text field
 434void LLFloaterColorPicker::onTextCommit ( LLUICtrl* ctrl, void* data )
 435{
 436	if ( data )
 437	{
 438		LLFloaterColorPicker* self = ( LLFloaterColorPicker* )data;
 439		if ( self )
 440		{
 441			self->onTextEntryChanged ( ctrl );
 442		}
 443	}
 444}
 445
 446void LLFloaterColorPicker::onImmediateCheck( LLUICtrl* ctrl, void* data)
 447{
 448	LLFloaterColorPicker* self = ( LLFloaterColorPicker* )data;
 449	if (self)
 450	{
 451		gSavedSettings.setBOOL("ApplyColorImmediately", self->mApplyImmediateCheck->get());
 452
 453		if (self->mApplyImmediateCheck->get())
 454		{
 455			LLColorSwatchCtrl::onColorChanged ( self->getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE );
 456		}
 457	}
 458}
 459
 460void LLFloaterColorPicker::onColorSelect( const LLTextureEntry& te )
 461{
 462	setCurRgb(te.getColor().mV[VRED], te.getColor().mV[VGREEN], te.getColor().mV[VBLUE]);
 463	if (mApplyImmediateCheck->get())
 464	{
 465		LLColorSwatchCtrl::onColorChanged ( getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE );
 466	}
 467}
 468
 469void LLFloaterColorPicker::onMouseCaptureLost()
 470{
 471	setMouseDownInHueRegion(FALSE);
 472	setMouseDownInLumRegion(FALSE);
 473}
 474
 475F32 LLFloaterColorPicker::getSwatchTransparency()
 476{
 477	// If the floater is focused, don't apply its alpha to the color swatch (STORM-676).
 478	return getTransparencyType() == TT_ACTIVE ? 1.f : LLFloater::getCurrentTransparency();
 479}
 480
 481//////////////////////////////////////////////////////////////////////////////
 482//
 483void LLFloaterColorPicker::draw()
 484{
 485	LLRect swatch_rect;
 486	mSwatch->localRectToOtherView(mSwatch->getLocalRect(), &swatch_rect, this);
 487	// draw context cone connecting color picker with color swatch in parent floater
 488	LLRect local_rect = getLocalRect();
 489	if (gFocusMgr.childHasKeyboardFocus(this) && mSwatch->isInVisibleChain() && mContextConeOpacity > 0.001f)
 490	{
 491		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 492		LLGLEnable(GL_CULL_FACE);
 493		gGL.begin(LLRender::QUADS);
 494		{
 495			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 496			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
 497			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
 498			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 499			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
 500			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
 501
 502			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 503			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
 504			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
 505			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 506			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
 507			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
 508
 509			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 510			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
 511			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
 512			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 513			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
 514			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
 515
 516			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 517			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
 518			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
 519			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 520			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
 521			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
 522		}
 523		gGL.end();
 524	}
 525
 526	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
 527	{
 528		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 529	}
 530	else
 531	{
 532		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 533	}
 534
 535	mPipetteBtn->setToggleState(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 536	mApplyImmediateCheck->setEnabled(mActive && mCanApplyImmediately);
 537	mSelectBtn->setEnabled(mActive);
 538
 539	// base floater stuff
 540	LLFloater::draw ();
 541
 542	const F32 alpha = getSwatchTransparency();
 543
 544	// draw image for RGB area (not really RGB but you'll see what I mean...
 545	gl_draw_image ( mRGBViewerImageLeft, mRGBViewerImageTop - mRGBViewerImageHeight, mRGBImage, LLColor4::white % alpha);
 546
 547	// update 'cursor' into RGB Section
 548	S32 xPos = ( S32 ) ( ( F32 )mRGBViewerImageWidth * getCurH () ) - 8;
 549	S32 yPos = ( S32 ) ( ( F32 )mRGBViewerImageHeight * getCurS () ) - 8;
 550	gl_line_2d ( mRGBViewerImageLeft + xPos,
 551				 mRGBViewerImageTop - mRGBViewerImageHeight + yPos + 8,
 552				 mRGBViewerImageLeft + xPos + 16,
 553				 mRGBViewerImageTop - mRGBViewerImageHeight + yPos + 8,
 554				 LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ) );
 555
 556	gl_line_2d ( mRGBViewerImageLeft + xPos + 8,
 557				 mRGBViewerImageTop - mRGBViewerImageHeight + yPos,
 558				 mRGBViewerImageLeft + xPos + 8,
 559				 mRGBViewerImageTop - mRGBViewerImageHeight + yPos + 16,
 560				 LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ) );
 561
 562	// create rgb area outline
 563	gl_rect_2d ( mRGBViewerImageLeft,
 564				 mRGBViewerImageTop - mRGBViewerImageHeight,
 565				 mRGBViewerImageLeft + mRGBViewerImageWidth + 1,
 566				 mRGBViewerImageTop,
 567				 LLColor4 ( 0.0f, 0.0f, 0.0f, alpha ),
 568				 FALSE );
 569
 570	// draw luminance slider
 571	for ( S32 y = 0; y < mLumRegionHeight; ++y )
 572	{
 573		F32 rValSlider, gValSlider, bValSlider;
 574		hslToRgb ( getCurH (), getCurS (), ( F32 )y / ( F32 )mLumRegionHeight, rValSlider, gValSlider, bValSlider );
 575
 576		gl_rect_2d( mLumRegionLeft, 
 577			mLumRegionTop - mLumRegionHeight + y, 
 578				mLumRegionLeft + mLumRegionWidth, 
 579					mLumRegionTop - mLumRegionHeight + y - 1, 
 580						LLColor4 ( rValSlider, gValSlider, bValSlider, alpha ) );
 581	}
 582
 583
 584	// draw luninance marker
 585	S32 startX = mLumRegionLeft + mLumRegionWidth;
 586	S32 startY = mLumRegionTop - mLumRegionHeight + ( S32 ) ( mLumRegionHeight * getCurL () );
 587	gl_triangle_2d ( startX, startY,
 588			startX + mLumMarkerSize, startY - mLumMarkerSize,
 589				startX + mLumMarkerSize, startY + mLumMarkerSize,
 590					LLColor4 ( 0.75f, 0.75f, 0.75f, 1.0f ), TRUE );
 591
 592	// draw luminance slider outline
 593	gl_rect_2d ( mLumRegionLeft,
 594				 mLumRegionTop - mLumRegionHeight,
 595				 mLumRegionLeft + mLumRegionWidth + 1,
 596				 mLumRegionTop,
 597				 LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ),
 598				 FALSE );
 599
 600	// draw selected color swatch
 601	gl_rect_2d ( mSwatchRegionLeft,
 602				 mSwatchRegionTop - mSwatchRegionHeight,
 603				 mSwatchRegionLeft + mSwatchRegionWidth,
 604				 mSwatchRegionTop,
 605				 LLColor4 ( getCurR (), getCurG (), getCurB (), alpha ),
 606				 TRUE );
 607
 608	// draw selected color swatch outline
 609	gl_rect_2d ( mSwatchRegionLeft,
 610				 mSwatchRegionTop - mSwatchRegionHeight,
 611				 mSwatchRegionLeft + mSwatchRegionWidth + 1,
 612				 mSwatchRegionTop,
 613				 LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ),
 614				 FALSE );
 615
 616	// color palette code is a little more involved so break it out into its' own method
 617	drawPalette ();
 618}
 619
 620//////////////////////////////////////////////////////////////////////////////
 621// find a complimentary color to the one passed in that can be used to highlight
 622const LLColor4& LLFloaterColorPicker::getComplimentaryColor ( const LLColor4& backgroundColor )
 623{
 624	// going to base calculation on luminance
 625	F32 hVal, sVal, lVal;
 626	backgroundColor.calcHSL(&hVal, &sVal, &lVal);
 627	hVal *= 360.f;
 628	sVal *= 100.f;
 629	lVal *= 100.f;
 630
 631	// fairly simple heuristic for now...!
 632	if ( lVal < 0.5f )
 633	{
 634		return LLColor4::white;
 635	}
 636
 637	return LLColor4::black;
 638}
 639
 640//////////////////////////////////////////////////////////////////////////////
 641// draw color palette
 642void LLFloaterColorPicker::drawPalette ()
 643{
 644	S32 curEntry = 0;
 645	const F32 alpha = getSwatchTransparency();
 646
 647	for ( S32 y = 0; y < numPaletteRows; ++y )
 648	{
 649		for ( S32 x = 0; x < numPaletteColumns; ++x )
 650		{
 651			// calculate position
 652			S32 x1 = mPaletteRegionLeft + ( mPaletteRegionWidth * x ) / numPaletteColumns;
 653			S32 y1 = mPaletteRegionTop - ( mPaletteRegionHeight * y ) / numPaletteRows;
 654			S32 x2 = ( mPaletteRegionLeft + ( mPaletteRegionWidth * ( x + 1 ) ) / numPaletteColumns );
 655			S32 y2 = ( mPaletteRegionTop - ( mPaletteRegionHeight * ( y + 1 ) ) / numPaletteRows );
 656
 657			// draw palette entry color
 658			if ( mPalette [ curEntry ] )
 659			{
 660				gl_rect_2d ( x1 + 2, y1 - 2, x2 - 2, y2 + 2, *mPalette [ curEntry++ ] % alpha, TRUE );
 661				gl_rect_2d ( x1 + 1, y1 - 1, x2 - 1, y2 + 1, LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ), FALSE );
 662			}
 663		}
 664	}
 665
 666	// if there is something to highlight (mouse down in swatch & hovering over palette)
 667	if ( highlightEntry >= 0 )
 668	{
 669		// extract row/column from palette index
 670		S32 entryColumn = highlightEntry % numPaletteColumns;
 671		S32 entryRow = highlightEntry / numPaletteColumns;
 672
 673		// calculate position of this entry
 674		S32 x1 = mPaletteRegionLeft + ( mPaletteRegionWidth * entryColumn ) / numPaletteColumns;
 675		S32 y1 = mPaletteRegionTop - ( mPaletteRegionHeight * entryRow ) / numPaletteRows;
 676		S32 x2 = ( mPaletteRegionLeft + ( mPaletteRegionWidth * ( entryColumn + 1 ) ) / numPaletteColumns );
 677		S32 y2 = ( mPaletteRegionTop - ( mPaletteRegionHeight * ( entryRow + 1 ) ) / numPaletteRows );
 678
 679		// center position of entry
 680		S32 xCenter = x1 + ( x2 - x1 ) / 2;
 681		S32 yCenter = y1 - ( y1 - y2 ) / 2;
 682
 683		// find a color that works well as a highlight color
 684		LLColor4 hlColor ( getComplimentaryColor ( *mPalette [ highlightEntry ] ) );
 685
 686		// mark a cross for entry that is being hovered
 687		gl_line_2d ( xCenter - 4, yCenter - 4, xCenter + 4, yCenter + 4, hlColor );
 688		gl_line_2d ( xCenter + 4, yCenter - 4, xCenter - 4, yCenter + 4, hlColor );
 689	}
 690}
 691
 692//////////////////////////////////////////////////////////////////////////////
 693// update text entry values for RGB/HSL (can't be done in ::draw () since this overwrites input
 694void LLFloaterColorPicker::updateTextEntry ()
 695{
 696	// set values in spinners
 697	getChild<LLUICtrl>("rspin")->setValue(( getCurR () * 255.0f ) );
 698	getChild<LLUICtrl>("gspin")->setValue(( getCurG () * 255.0f ) );
 699	getChild<LLUICtrl>("bspin")->setValue(( getCurB () * 255.0f ) );
 700	getChild<LLUICtrl>("hspin")->setValue(( getCurH () * 360.0f ) );
 701	getChild<LLUICtrl>("sspin")->setValue(( getCurS () * 100.0f ) );
 702	getChild<LLUICtrl>("lspin")->setValue(( getCurL () * 100.0f ) );
 703}
 704
 705//////////////////////////////////////////////////////////////////////////////
 706//
 707void LLFloaterColorPicker::onTextEntryChanged ( LLUICtrl* ctrl )
 708{
 709	// value in RGB boxes changed
 710	std::string name = ctrl->getName();
 711	if ( ( name == "rspin" ) || ( name == "gspin" ) || ( name == "bspin" ) )
 712	{
 713		// get current RGB
 714		F32 rVal, gVal, bVal;
 715		getCurRgb ( rVal, gVal, bVal );
 716
 717		// update component value with new value from text
 718		if ( name == "rspin" )
 719		{
 720			rVal = (F32)ctrl->getValue().asReal() / 255.0f;
 721		}
 722		else
 723		if ( name == "gspin" )
 724		{
 725			gVal = (F32)ctrl->getValue().asReal() / 255.0f;
 726		}
 727		else
 728		if ( name == "bspin" )
 729		{
 730			bVal = (F32)ctrl->getValue().asReal() / 255.0f;
 731		}
 732
 733		// update current RGB (and implicitly HSL)
 734		setCurRgb ( rVal, gVal, bVal );
 735
 736		updateTextEntry ();
 737	}
 738	else
 739	// value in HSL boxes changed
 740	if ( ( name == "hspin" ) || ( name == "sspin" ) || ( name == "lspin" ) )
 741	{
 742		// get current HSL
 743		F32 hVal, sVal, lVal;
 744		getCurHsl ( hVal, sVal, lVal );
 745
 746		// update component value with new value from text
 747		if ( name == "hspin" )
 748			hVal = (F32)ctrl->getValue().asReal() / 360.0f;
 749		else
 750		if ( name == "sspin" )
 751			sVal = (F32)ctrl->getValue().asReal() / 100.0f;
 752		else
 753		if ( name == "lspin" )
 754			lVal = (F32)ctrl->getValue().asReal() / 100.0f;
 755
 756		// update current HSL (and implicitly RGB)
 757		setCurHsl ( hVal, sVal, lVal );
 758
 759		updateTextEntry ();
 760	}
 761
 762	if (mApplyImmediateCheck->get())
 763	{
 764		LLColorSwatchCtrl::onColorChanged ( getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE );
 765	}
 766}
 767
 768//////////////////////////////////////////////////////////////////////////////
 769//
 770BOOL LLFloaterColorPicker::updateRgbHslFromPoint ( S32 xPosIn, S32 yPosIn )
 771{
 772	if ( xPosIn >= mRGBViewerImageLeft &&
 773		 xPosIn <= mRGBViewerImageLeft + mRGBViewerImageWidth &&
 774		 yPosIn <= mRGBViewerImageTop &&
 775		 yPosIn >= mRGBViewerImageTop - mRGBViewerImageHeight )
 776	{
 777		// update HSL (and therefore RGB) based on new H & S and current L
 778		setCurHsl ( ( ( F32 )xPosIn - ( F32 )mRGBViewerImageLeft ) / ( F32 )mRGBViewerImageWidth,
 779					( ( F32 )yPosIn - ( ( F32 )mRGBViewerImageTop - ( F32 )mRGBViewerImageHeight ) ) / ( F32 )mRGBViewerImageHeight,
 780					getCurL () );
 781
 782		// indicate a value changed
 783		return TRUE;
 784	}
 785	else
 786	if ( xPosIn >= mLumRegionLeft &&
 787		 xPosIn <= mLumRegionLeft + mLumRegionWidth &&
 788		 yPosIn <= mLumRegionTop &&
 789		 yPosIn >= mLumRegionTop - mLumRegionHeight )
 790	{
 791
 792		// update HSL (and therefore RGB) based on current HS and new L
 793		 setCurHsl ( getCurH (),
 794					 getCurS (),
 795					( ( F32 )yPosIn - ( ( F32 )mRGBViewerImageTop - ( F32 )mRGBViewerImageHeight ) ) / ( F32 )mRGBViewerImageHeight );
 796
 797		// indicate a value changed
 798		return TRUE;
 799	}
 800
 801	return FALSE;
 802}
 803
 804//////////////////////////////////////////////////////////////////////////////
 805//
 806BOOL LLFloaterColorPicker::handleMouseDown ( S32 x, S32 y, MASK mask )
 807{
 808	// make it the frontmost
 809	gFloaterView->bringToFront(this);
 810
 811	// rect containing RGB area
 812	LLRect rgbAreaRect ( mRGBViewerImageLeft,
 813						 mRGBViewerImageTop,
 814						 mRGBViewerImageLeft + mRGBViewerImageWidth,
 815						 mRGBViewerImageTop - mRGBViewerImageHeight );
 816
 817	if ( rgbAreaRect.pointInRect ( x, y ) )
 818	{
 819		gFocusMgr.setMouseCapture(this);
 820		// mouse button down
 821		setMouseDownInHueRegion ( TRUE );
 822
 823		// update all values based on initial click
 824		updateRgbHslFromPoint ( x, y );
 825
 826		// required by base class
 827		return TRUE;
 828	}
 829
 830	// rect containing RGB area
 831	LLRect lumAreaRect ( mLumRegionLeft,
 832						 mLumRegionTop,
 833						 mLumRegionLeft + mLumRegionWidth + mLumMarkerSize,
 834						 mLumRegionTop - mLumRegionHeight );
 835
 836	if ( lumAreaRect.pointInRect ( x, y ) )
 837	{
 838		gFocusMgr.setMouseCapture(this);
 839		// mouse button down
 840		setMouseDownInLumRegion ( TRUE );
 841
 842		// required by base class
 843		return TRUE;
 844	}
 845
 846	// rect containing swatch area
 847	LLRect swatchRect ( mSwatchRegionLeft,
 848						mSwatchRegionTop,
 849						mSwatchRegionLeft + mSwatchRegionWidth,
 850						mSwatchRegionTop - mSwatchRegionHeight );
 851
 852	setMouseDownInSwatch( FALSE );
 853	if ( swatchRect.pointInRect ( x, y ) )
 854	{
 855		setMouseDownInSwatch( TRUE );
 856
 857		// required - dont drag windows here.
 858		return TRUE;
 859	}
 860
 861	// rect containing palette area
 862	LLRect paletteRect ( mPaletteRegionLeft,
 863						 mPaletteRegionTop,
 864						 mPaletteRegionLeft + mPaletteRegionWidth,
 865						 mPaletteRegionTop - mPaletteRegionHeight );
 866
 867	if ( paletteRect.pointInRect ( x, y ) )
 868	{
 869		// release keyboard focus so we can change text values
 870		if (gFocusMgr.childHasKeyboardFocus(this))
 871		{
 872			mSelectBtn->setFocus(TRUE);
 873		}
 874
 875		// calculate which palette index we selected
 876		S32 c = ( ( x - mPaletteRegionLeft ) * numPaletteColumns ) / mPaletteRegionWidth;
 877		S32 r = ( ( y - ( mPaletteRegionTop - mPaletteRegionHeight ) ) * numPaletteRows ) / mPaletteRegionHeight;
 878
 879		U32 index = ( numPaletteRows - r - 1 ) * numPaletteColumns + c;
 880
 881		if ( index <= mPalette.size () )
 882		{
 883			LLColor4 selected = *mPalette [ index ];
 884
 885			setCurRgb ( selected [ 0 ], selected [ 1 ], selected [ 2 ] );
 886
 887			if (mApplyImmediateCheck->get())
 888			{
 889				LLColorSwatchCtrl::onColorChanged ( getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE );
 890			}
 891
 892			updateTextEntry ();
 893		}
 894
 895		return TRUE;
 896	}
 897
 898	// dispatch to base class for the rest of things
 899	
 900	return LLFloater::handleMouseDown ( x, y, mask );
 901}
 902
 903//////////////////////////////////////////////////////////////////////////////
 904//
 905BOOL LLFloaterColorPicker::handleHover ( S32 x, S32 y, MASK mask )
 906{
 907	// if we're the front most window
 908	if ( isFrontmost () )
 909	{
 910		// mouse was pressed within region
 911		if ( getMouseDownInHueRegion() || getMouseDownInLumRegion())
 912		{
 913			S32 clamped_x, clamped_y;
 914			if (getMouseDownInHueRegion())
 915			{
 916				clamped_x = llclamp(x, mRGBViewerImageLeft, mRGBViewerImageLeft + mRGBViewerImageWidth);
 917				clamped_y = llclamp(y, mRGBViewerImageTop - mRGBViewerImageHeight, mRGBViewerImageTop);
 918			}
 919			else
 920			{
 921				clamped_x = llclamp(x, mLumRegionLeft, mLumRegionLeft + mLumRegionWidth);
 922				clamped_y = llclamp(y, mLumRegionTop - mLumRegionHeight, mLumRegionTop);
 923			}
 924
 925			// update the stored RGB/HSL values using the mouse position - returns TRUE if RGB was updated
 926			if ( updateRgbHslFromPoint ( clamped_x, clamped_y ) )
 927			{
 928				// update text entry fields
 929				updateTextEntry ();
 930
 931				// RN: apparently changing color when dragging generates too much traffic and results in sporadic updates
 932				//// commit changed color to swatch subject
 933				//// REVIEW: this gets sent each time a color changes - is this okay ?
 934				//if (mApplyImmediateCheck->get())
 935				//{
 936				//	LLColorSwatchCtrl::onColorChanged ( getSwatch () );
 937				//}
 938			}
 939		}
 940
 941		highlightEntry = -1;
 942
 943		if ( mMouseDownInSwatch )
 944		{
 945			getWindow()->setCursor ( UI_CURSOR_ARROWDRAG );
 946
 947			// if cursor if over a palette entry
 948			LLRect paletteRect ( mPaletteRegionLeft,
 949								mPaletteRegionTop,
 950								mPaletteRegionLeft + mPaletteRegionWidth,
 951								mPaletteRegionTop - mPaletteRegionHeight );
 952
 953			if ( paletteRect.pointInRect ( x, y ) )
 954			{
 955				// find row/column in palette
 956				S32 xOffset = ( ( x - mPaletteRegionLeft ) * numPaletteColumns ) / mPaletteRegionWidth;
 957				S32 yOffset = ( ( mPaletteRegionTop - y - 1 ) * numPaletteRows ) / mPaletteRegionHeight;
 958
 959				// calculate the entry 0..n-1 to highlight and set variable to next draw() picks it up
 960				highlightEntry = xOffset + yOffset * numPaletteColumns;
 961			}
 962
 963			return TRUE;
 964		}
 965	}
 966
 967	// dispatch to base class for the rest of things
 968	return LLFloater::handleHover ( x, y, mask );
 969}
 970
 971//////////////////////////////////////////////////////////////////////////////
 972// reverts state once mouse button is released
 973BOOL LLFloaterColorPicker::handleMouseUp ( S32 x, S32 y, MASK mask )
 974{
 975	getWindow()->setCursor ( UI_CURSOR_ARROW );
 976
 977	if (getMouseDownInHueRegion() || getMouseDownInLumRegion())
 978	{
 979		if (mApplyImmediateCheck->get())
 980		{
 981			LLColorSwatchCtrl::onColorChanged ( getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE );
 982		}
 983	}
 984
 985	// rect containing palette area
 986	LLRect paletteRect ( mPaletteRegionLeft,
 987							mPaletteRegionTop,
 988							mPaletteRegionLeft + mPaletteRegionWidth,
 989							mPaletteRegionTop - mPaletteRegionHeight );
 990
 991	if ( paletteRect.pointInRect ( x, y ) )
 992	{
 993		if ( mMouseDownInSwatch )
 994		{
 995			S32 curEntry = 0;
 996			for ( S32 row = 0; row < numPaletteRows; ++row )
 997			{
 998				for ( S32 column = 0; column < numPaletteColumns; ++column )
 999				{
1000					S32 left = mPaletteRegionLeft + ( mPaletteRegionWidth * column ) / numPaletteColumns;
1001					S32 top = mPaletteRegionTop - ( mPaletteRegionHeight * row ) / numPaletteRows;
1002					S32 right = ( mPaletteRegionLeft + ( mPaletteRegionWidth * ( column + 1 ) ) / numPaletteColumns );
1003					S32 bottom = ( mPaletteRegionTop - ( mPaletteRegionHeight * ( row + 1 ) ) / numPaletteRows );
1004
1005					// rect is flipped vertically when testing here
1006					LLRect dropRect ( left, top, right, bottom );
1007
1008					if ( dropRect.pointInRect ( x, y ) )
1009					{
1010						if ( mPalette [ curEntry ] )
1011						{
1012							delete mPalette [ curEntry ];
1013
1014							mPalette [ curEntry ] = new LLColor4 ( getCurR (), getCurG (), getCurB (), 1.0f );
1015
1016							// save off color
1017							std::ostringstream codec;
1018							codec << "ColorPaletteEntry" << std::setfill ( '0' ) << std::setw ( 2 ) << curEntry + 1;
1019							const std::string s ( codec.str () );
1020							LLUIColorTable::instance().setColor(s, *mPalette [ curEntry ] );
1021						}
1022					}
1023
1024					++curEntry;
1025				}
1026			}
1027		}
1028	}
1029
1030	// mouse button not down anymore
1031	setMouseDownInHueRegion ( FALSE );
1032	setMouseDownInLumRegion ( FALSE );
1033
1034	// mouse button not down in color swatch anymore
1035	mMouseDownInSwatch = false;
1036
1037	if (hasMouseCapture())
1038	{
1039		gFocusMgr.setMouseCapture(NULL);
1040	}
1041
1042	// dispatch to base class for the rest of things
1043	return LLFloater::handleMouseUp ( x, y, mask );
1044}
1045
1046//////////////////////////////////////////////////////////////////////////////
1047// cancel current color selection, revert to original and close picker
1048void LLFloaterColorPicker::cancelSelection ()
1049{
1050	// restore the previous color selection
1051	setCurRgb ( getOrigR (), getOrigG (), getOrigB () );
1052
1053	// update in world item with original color via current swatch
1054	LLColorSwatchCtrl::onColorChanged( getSwatch(), LLColorSwatchCtrl::COLOR_CANCEL );
1055
1056	// hide picker dialog
1057	this->setVisible ( FALSE );
1058}
1059
1060void LLFloaterColorPicker::setMouseDownInHueRegion ( BOOL mouse_down_in_region )
1061{
1062	mMouseDownInHueRegion = mouse_down_in_region;
1063	if (mouse_down_in_region)
1064	{
1065		if (gFocusMgr.childHasKeyboardFocus(this))
1066		{
1067			// get focus out of spinners so that they can update freely
1068			mSelectBtn->setFocus(TRUE);
1069		}
1070	}
1071}
1072
1073void LLFloaterColorPicker::setMouseDownInLumRegion ( BOOL mouse_down_in_region )
1074{
1075	mMouseDownInLumRegion = mouse_down_in_region;
1076	if (mouse_down_in_region)
1077	{
1078		if (gFocusMgr.childHasKeyboardFocus(this))
1079		{
1080			// get focus out of spinners so that they can update freely
1081			mSelectBtn->setFocus(TRUE);
1082		}
1083	}
1084}
1085
1086void LLFloaterColorPicker::setMouseDownInSwatch (BOOL mouse_down_in_swatch)
1087{
1088	mMouseDownInSwatch = mouse_down_in_swatch;
1089	if (mouse_down_in_swatch)
1090	{
1091		if (gFocusMgr.childHasKeyboardFocus(this))
1092		{
1093			// get focus out of spinners so that they can update freely
1094			mSelectBtn->setFocus(TRUE);
1095		}
1096	}
1097}
1098
1099void LLFloaterColorPicker::setActive(BOOL active) 
1100{ 
1101	// shut down pipette tool if active
1102	if (!active && mPipetteBtn->getToggleState())
1103	{
1104		stopUsingPipette();
1105	}
1106	mActive = active; 
1107}
1108
1109void LLFloaterColorPicker::stopUsingPipette()
1110{
1111	if (LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance())
1112	{
1113		LLToolMgr::getInstance()->clearTransientTool();
1114	}
1115}