PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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