PageRenderTime 780ms CodeModel.GetById 81ms app.highlight 576ms RepoModel.GetById 108ms app.codeStats 1ms

/indra/newview/lltexturectrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1421 lines | 1066 code | 210 blank | 145 comment | 164 complexity | 187a7887b643e650e53380d3f34aa596 MD5 | raw file
   1/** 
   2 * @file lltexturectrl.cpp
   3 * @author Richard Nelson, James Cook
   4 * @brief LLTextureCtrl class implementation including related functions
   5 *
   6 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
   7 * Second Life Viewer Source Code
   8 * Copyright (C) 2010, Linden Research, Inc.
   9 * 
  10 * This library is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU Lesser General Public
  12 * License as published by the Free Software Foundation;
  13 * version 2.1 of the License only.
  14 * 
  15 * This library is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * Lesser General Public License for more details.
  19 * 
  20 * You should have received a copy of the GNU Lesser General Public
  21 * License along with this library; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23 * 
  24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25 * $/LicenseInfo$
  26 */
  27
  28#include "llviewerprecompiledheaders.h"
  29
  30#include "lltexturectrl.h"
  31
  32#include "llrender.h"
  33#include "llagent.h"
  34#include "llviewertexturelist.h"
  35#include "llcheckboxctrl.h"
  36#include "llcombobox.h"
  37#include "llbutton.h"
  38#include "lldraghandle.h"
  39#include "llfocusmgr.h"
  40#include "llviewertexture.h"
  41#include "llfolderview.h"
  42#include "llfoldervieweventlistener.h"
  43#include "llinventory.h"
  44#include "llinventoryfunctions.h"
  45#include "llinventorymodelbackgroundfetch.h"
  46#include "llinventoryobserver.h"
  47#include "llinventorypanel.h"
  48#include "llfloaterinventory.h"
  49#include "lllineeditor.h"
  50#include "llui.h"
  51#include "llviewerinventory.h"
  52#include "llpermissions.h"
  53#include "llsaleinfo.h"
  54#include "llassetstorage.h"
  55#include "lltextbox.h"
  56#include "llresizehandle.h"
  57#include "llscrollcontainer.h"
  58#include "lltoolmgr.h"
  59#include "lltoolpipette.h"
  60#include "llfiltereditor.h"
  61
  62#include "lltool.h"
  63#include "llviewerwindow.h"
  64#include "llviewerobject.h"
  65#include "llviewercontrol.h"
  66#include "llglheaders.h"
  67#include "lluictrlfactory.h"
  68#include "lltrans.h"
  69
  70
  71static const S32 HPAD = 4;
  72static const S32 VPAD = 4;
  73static const S32 LINE = 16;
  74static const S32 FOOTER_HEIGHT = 100;
  75static const S32 BORDER_PAD = HPAD;
  76static const S32 TEXTURE_INVENTORY_PADDING = 30;
  77static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
  78static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
  79static const F32 CONTEXT_FADE_TIME = 0.08f;
  80
  81//static const char CURRENT_IMAGE_NAME[] = "Current Texture";
  82//static const char WHITE_IMAGE_NAME[] = "Blank Texture";
  83//static const char NO_IMAGE_NAME[] = "None";
  84
  85//////////////////////////////////////////////////////////////////////////////////////////
  86// LLFloaterTexturePicker
  87
  88class LLFloaterTexturePicker : public LLFloater
  89{
  90public:
  91	LLFloaterTexturePicker(
  92		LLTextureCtrl* owner,
  93		const std::string& label,
  94		PermissionMask immediate_filter_perm_mask,
  95		PermissionMask non_immediate_filter_perm_mask,
  96		BOOL can_apply_immediately,
  97		LLUIImagePtr fallback_image_name);
  98
  99	virtual ~LLFloaterTexturePicker();
 100
 101	// LLView overrides
 102	/*virtual*/ BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask,
 103						BOOL drop, EDragAndDropType cargo_type, void *cargo_data, 
 104						EAcceptance *accept,
 105						std::string& tooltip_msg);
 106	/*virtual*/ void	draw();
 107	/*virtual*/ BOOL	handleKeyHere(KEY key, MASK mask);
 108
 109	// LLFloater overrides
 110	/*virtual*/ BOOL    postBuild();
 111	/*virtual*/ void	onClose(bool app_settings);
 112	
 113	// New functions
 114	void setImageID( const LLUUID& image_asset_id);
 115	void updateImageStats();
 116	const LLUUID& getAssetID() { return mImageAssetID; }
 117	const LLUUID& findItemID(const LLUUID& asset_id, BOOL copyable_only);
 118	void			setCanApplyImmediately(BOOL b);
 119
 120	void			setActive( BOOL active );
 121
 122	LLTextureCtrl*	getOwner() const { return mOwner; }
 123	void			setOwner(LLTextureCtrl* owner) { mOwner = owner; }
 124	
 125	void			stopUsingPipette();
 126	PermissionMask 	getFilterPermMask();
 127	void updateFilterPermMask();
 128	void commitIfImmediateSet();
 129	
 130	void onFilterEdit(const std::string& search_string );
 131	
 132	static void		onBtnSetToDefault( void* userdata );
 133	static void		onBtnSelect( void* userdata );
 134	static void		onBtnCancel( void* userdata );
 135		   void		onBtnPipette( );
 136	//static void		onBtnRevert( void* userdata );
 137	static void		onBtnWhite( void* userdata );
 138	static void		onBtnNone( void* userdata );
 139	static void		onBtnClear( void* userdata );
 140		   void		onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
 141	static void		onShowFolders(LLUICtrl* ctrl, void* userdata);
 142	static void		onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata);
 143		   void		onTextureSelect( const LLTextureEntry& te );
 144
 145protected:
 146	LLPointer<LLViewerTexture> mTexturep;
 147	LLTextureCtrl*		mOwner;
 148
 149	LLUUID				mImageAssetID; // Currently selected texture
 150	LLUIImagePtr		mFallbackImage; // What to show if currently selected texture is null.
 151
 152	LLUUID				mWhiteImageAssetID;
 153	LLUUID				mSpecialCurrentImageAssetID;  // Used when the asset id has no corresponding texture in the user's inventory.
 154	LLUUID				mOriginalImageAssetID;
 155
 156	std::string			mLabel;
 157
 158	LLTextBox*			mTentativeLabel;
 159	LLTextBox*			mResolutionLabel;
 160
 161	std::string			mPendingName;
 162	BOOL				mActive;
 163
 164	LLFilterEditor*		mFilterEdit;
 165	LLInventoryPanel*	mInventoryPanel;
 166	PermissionMask		mImmediateFilterPermMask;
 167	PermissionMask		mNonImmediateFilterPermMask;
 168	BOOL				mCanApplyImmediately;
 169	BOOL				mNoCopyTextureSelected;
 170	F32					mContextConeOpacity;
 171	LLSaveFolderState	mSavedFolderState;
 172
 173	BOOL				mSelectedItemPinned;
 174};
 175
 176LLFloaterTexturePicker::LLFloaterTexturePicker(	
 177	LLTextureCtrl* owner,
 178	const std::string& label,
 179	PermissionMask immediate_filter_perm_mask,
 180	PermissionMask non_immediate_filter_perm_mask,
 181	BOOL can_apply_immediately,
 182	LLUIImagePtr fallback_image)
 183:	LLFloater(LLSD()),
 184	mOwner( owner ),
 185	mImageAssetID( owner->getImageAssetID() ),
 186	mFallbackImage( fallback_image ),
 187	mWhiteImageAssetID( gSavedSettings.getString( "UIImgWhiteUUID" ) ),
 188	mOriginalImageAssetID(owner->getImageAssetID()),
 189	mLabel(label),
 190	mTentativeLabel(NULL),
 191	mResolutionLabel(NULL),
 192	mActive( TRUE ),
 193	mFilterEdit(NULL),
 194	mImmediateFilterPermMask(immediate_filter_perm_mask),
 195	mNonImmediateFilterPermMask(non_immediate_filter_perm_mask),
 196	mContextConeOpacity(0.f),
 197	mSelectedItemPinned( FALSE )
 198{
 199	buildFromFile("floater_texture_ctrl.xml");
 200	mCanApplyImmediately = can_apply_immediately;
 201	setCanMinimize(FALSE);
 202}
 203
 204LLFloaterTexturePicker::~LLFloaterTexturePicker()
 205{
 206}
 207
 208void LLFloaterTexturePicker::setImageID(const LLUUID& image_id)
 209{
 210	if( mImageAssetID != image_id && mActive)
 211	{
 212		mNoCopyTextureSelected = FALSE;
 213		mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
 214		mImageAssetID = image_id; 
 215		LLUUID item_id = findItemID(mImageAssetID, FALSE);
 216		if (item_id.isNull())
 217		{
 218			mInventoryPanel->clearSelection();
 219		}
 220		else
 221		{
 222			LLInventoryItem* itemp = gInventory.getItem(image_id);
 223			if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID()))
 224			{
 225				// no copy texture
 226				getChild<LLUICtrl>("apply_immediate_check")->setValue(FALSE);
 227				mNoCopyTextureSelected = TRUE;
 228			}
 229			mInventoryPanel->setSelection(item_id, TAKE_FOCUS_NO);
 230		}
 231	}
 232}
 233
 234void LLFloaterTexturePicker::setActive( BOOL active )					
 235{
 236	if (!active && getChild<LLUICtrl>("Pipette")->getValue().asBoolean())
 237	{
 238		stopUsingPipette();
 239	}
 240	mActive = active; 
 241}
 242
 243void LLFloaterTexturePicker::setCanApplyImmediately(BOOL b)
 244{
 245	mCanApplyImmediately = b;
 246	if (!mCanApplyImmediately)
 247	{
 248		getChild<LLUICtrl>("apply_immediate_check")->setValue(FALSE);
 249	}
 250	updateFilterPermMask();
 251}
 252
 253void LLFloaterTexturePicker::stopUsingPipette()
 254{
 255	if (LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance())
 256	{
 257		LLToolMgr::getInstance()->clearTransientTool();
 258	}
 259}
 260
 261void LLFloaterTexturePicker::updateImageStats()
 262{
 263	if (mTexturep.notNull())
 264	{
 265		//RN: have we received header data for this image?
 266		if (mTexturep->getFullWidth() > 0 && mTexturep->getFullHeight() > 0)
 267		{
 268			std::string formatted_dims = llformat("%d x %d", mTexturep->getFullWidth(),mTexturep->getFullHeight());
 269			mResolutionLabel->setTextArg("[DIMENSIONS]", formatted_dims);
 270		}
 271		else
 272		{
 273			mResolutionLabel->setTextArg("[DIMENSIONS]", std::string("[? x ?]"));
 274		}
 275	}
 276	else
 277	{
 278		mResolutionLabel->setTextArg("[DIMENSIONS]", std::string(""));
 279	}
 280}
 281
 282// virtual
 283BOOL LLFloaterTexturePicker::handleDragAndDrop( 
 284		S32 x, S32 y, MASK mask,
 285		BOOL drop,
 286		EDragAndDropType cargo_type, void *cargo_data, 
 287		EAcceptance *accept,
 288		std::string& tooltip_msg)
 289{
 290	BOOL handled = FALSE;
 291
 292	bool is_mesh = cargo_type == DAD_MESH;
 293
 294	if ((cargo_type == DAD_TEXTURE) || is_mesh)
 295	{
 296		LLInventoryItem *item = (LLInventoryItem *)cargo_data;
 297
 298		BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
 299		BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
 300		BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
 301															gAgent.getID());
 302
 303		PermissionMask item_perm_mask = 0;
 304		if (copy) item_perm_mask |= PERM_COPY;
 305		if (mod)  item_perm_mask |= PERM_MODIFY;
 306		if (xfer) item_perm_mask |= PERM_TRANSFER;
 307		
 308		//PermissionMask filter_perm_mask = getFilterPermMask();  Commented out due to no-copy texture loss.
 309		PermissionMask filter_perm_mask = mImmediateFilterPermMask;
 310		if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask )
 311		{
 312			if (drop)
 313			{
 314				setImageID( item->getAssetUUID() );
 315				commitIfImmediateSet();
 316			}
 317
 318			*accept = ACCEPT_YES_SINGLE;
 319		}
 320		else
 321		{
 322			*accept = ACCEPT_NO;
 323		}
 324	}
 325	else
 326	{
 327		*accept = ACCEPT_NO;
 328	}
 329
 330	handled = TRUE;
 331	lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFloaterTexturePicker " << getName() << llendl;
 332
 333	return handled;
 334}
 335
 336BOOL LLFloaterTexturePicker::handleKeyHere(KEY key, MASK mask)
 337{
 338	LLFolderView* root_folder = mInventoryPanel->getRootFolder();
 339
 340	if (root_folder && mFilterEdit)
 341	{
 342		if (mFilterEdit->hasFocus() 
 343			&& (key == KEY_RETURN || key == KEY_DOWN) 
 344			&& mask == MASK_NONE)
 345		{
 346			if (!root_folder->getCurSelectedItem())
 347			{
 348				LLFolderViewItem* itemp = root_folder->getItemByID(gInventory.getRootFolderID());
 349				if (itemp)
 350				{
 351					root_folder->setSelection(itemp, FALSE, FALSE);
 352				}
 353			}
 354			root_folder->scrollToShowSelection();
 355			
 356			// move focus to inventory proper
 357			mInventoryPanel->setFocus(TRUE);
 358			
 359			// treat this as a user selection of the first filtered result
 360			commitIfImmediateSet();
 361			
 362			return TRUE;
 363		}
 364		
 365		if (mInventoryPanel->hasFocus() && key == KEY_UP)
 366		{
 367			mFilterEdit->focusFirstItem(TRUE);
 368		}
 369	}
 370
 371	return LLFloater::handleKeyHere(key, mask);
 372}
 373
 374void LLFloaterTexturePicker::onClose(bool app_quitting)
 375{
 376	if (mOwner)
 377	{
 378		mOwner->onFloaterClose();
 379	}
 380	stopUsingPipette();
 381}
 382
 383// virtual
 384BOOL LLFloaterTexturePicker::postBuild()
 385{
 386	LLFloater::postBuild();
 387
 388	if (!mLabel.empty())
 389	{
 390		std::string pick = getString("pick title");
 391	
 392		setTitle(pick + mLabel);
 393	}
 394	mTentativeLabel = getChild<LLTextBox>("Multiple");
 395
 396	mResolutionLabel = getChild<LLTextBox>("unknown");
 397
 398
 399	childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this);
 400	childSetAction("None", LLFloaterTexturePicker::onBtnNone,this);
 401	childSetAction("Blank", LLFloaterTexturePicker::onBtnWhite,this);
 402
 403
 404	childSetCommitCallback("show_folders_check", onShowFolders, this);
 405	getChildView("show_folders_check")->setVisible( FALSE);
 406
 407	mFilterEdit = getChild<LLFilterEditor>("inventory search editor");
 408	mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2));
 409
 410	mInventoryPanel = getChild<LLInventoryPanel>("inventory panel");
 411
 412	if(mInventoryPanel)
 413	{
 414		U32 filter_types = 0x0;
 415		filter_types |= 0x1 << LLInventoryType::IT_TEXTURE;
 416		filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT;
 417
 418		mInventoryPanel->setFilterTypes(filter_types);
 419		//mInventoryPanel->setFilterPermMask(getFilterPermMask());  //Commented out due to no-copy texture loss.
 420		mInventoryPanel->setFilterPermMask(mImmediateFilterPermMask);
 421		mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterTexturePicker::onSelectionChange, this, _1, _2));
 422		mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
 423
 424		// Disable auto selecting first filtered item because it takes away
 425		// selection from the item set by LLTextureCtrl owning this floater.
 426		mInventoryPanel->getRootFolder()->setAutoSelectOverride(TRUE);
 427
 428		// Commented out to scroll to currently selected texture. See EXT-5403.
 429		// // store this filter as the default one
 430		// mInventoryPanel->getRootFolder()->getFilter()->markDefault();
 431
 432		// Commented out to stop opening all folders with textures
 433		// mInventoryPanel->openDefaultFolderForType(LLFolderType::FT_TEXTURE);
 434
 435		// don't put keyboard focus on selected item, because the selection callback
 436		// will assume that this was user input
 437		mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO);
 438	}
 439
 440
 441	mNoCopyTextureSelected = FALSE;
 442
 443	getChild<LLUICtrl>("apply_immediate_check")->setValue(gSavedSettings.getBOOL("ApplyTextureImmediately"));
 444	childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this);
 445
 446	if (!mCanApplyImmediately)
 447	{
 448		getChildView("show_folders_check")->setEnabled(FALSE);
 449	}
 450
 451	getChild<LLUICtrl>("Pipette")->setCommitCallback( boost::bind(&LLFloaterTexturePicker::onBtnPipette, this));
 452	childSetAction("Cancel", LLFloaterTexturePicker::onBtnCancel,this);
 453	childSetAction("Select", LLFloaterTexturePicker::onBtnSelect,this);
 454
 455	// update permission filter once UI is fully initialized
 456	updateFilterPermMask();
 457	mSavedFolderState.setApply(FALSE);
 458
 459	LLToolPipette::getInstance()->setToolSelectCallback(boost::bind(&LLFloaterTexturePicker::onTextureSelect, this, _1));
 460	
 461	return TRUE;
 462}
 463
 464// virtual
 465void LLFloaterTexturePicker::draw()
 466{
 467	S32 floater_header_size = getHeaderHeight();
 468	if (mOwner)
 469	{
 470		// draw cone of context pointing back to texture swatch	
 471		LLRect owner_rect;
 472		mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this);
 473		LLRect local_rect = getLocalRect();
 474		if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f)
 475		{
 476			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 477			LLGLEnable(GL_CULL_FACE);
 478			gGL.begin(LLRender::QUADS);
 479			{
 480				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 481				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
 482				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
 483				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 484				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
 485				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
 486
 487				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 488				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
 489				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
 490				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 491				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
 492				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
 493
 494				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 495				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
 496				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
 497				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 498				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
 499				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
 500
 501
 502				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
 503				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
 504				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
 505				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
 506				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
 507				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
 508			}
 509			gGL.end();
 510		}
 511	}
 512
 513	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
 514	{
 515		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 516	}
 517	else
 518	{
 519		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 520	}
 521
 522	updateImageStats();
 523
 524	// if we're inactive, gray out "apply immediate" checkbox
 525	getChildView("show_folders_check")->setEnabled(mActive && mCanApplyImmediately && !mNoCopyTextureSelected);
 526	getChildView("Select")->setEnabled(mActive);
 527	getChildView("Pipette")->setEnabled(mActive);
 528	getChild<LLUICtrl>("Pipette")->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 529
 530	//BOOL allow_copy = FALSE;
 531	if( mOwner ) 
 532	{
 533		mTexturep = NULL;
 534		if(mImageAssetID.notNull())
 535		{
 536			mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, MIPMAP_YES);
 537			mTexturep->setBoostLevel(LLViewerTexture::BOOST_PREVIEW);
 538		}
 539
 540		if (mTentativeLabel)
 541		{
 542			mTentativeLabel->setVisible( FALSE  );
 543		}
 544
 545		getChildView("Default")->setEnabled(mImageAssetID != mOwner->getDefaultImageAssetID());
 546		getChildView("Blank")->setEnabled(mImageAssetID != mWhiteImageAssetID );
 547		getChildView("None")->setEnabled(mOwner->getAllowNoTexture() && !mImageAssetID.isNull() );
 548
 549		LLFloater::draw();
 550
 551		if( isMinimized() )
 552		{
 553			return;
 554		}
 555
 556		// Border
 557		LLRect border( BORDER_PAD, 
 558					   getRect().getHeight() - floater_header_size - BORDER_PAD, 
 559					   ((getMinWidth() / 2) - TEXTURE_INVENTORY_PADDING - HPAD) - BORDER_PAD,
 560					   BORDER_PAD + FOOTER_HEIGHT + (getRect().getHeight() - getMinHeight()));
 561		gl_rect_2d( border, LLColor4::black, FALSE );
 562
 563
 564		// Interior
 565		LLRect interior = border;
 566		interior.stretch( -1 ); 
 567
 568		// If the floater is focused, don't apply its alpha to the texture (STORM-677).
 569		const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
 570		if( mTexturep )
 571		{
 572			if( mTexturep->getComponents() == 4 )
 573			{
 574				gl_rect_2d_checkerboard( interior, alpha );
 575			}
 576
 577			gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha );
 578
 579			// Pump the priority
 580			mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
 581		}
 582		else if (!mFallbackImage.isNull())
 583		{
 584			mFallbackImage->draw(interior, UI_VERTEX_COLOR % alpha);
 585		}
 586		else
 587		{
 588			gl_rect_2d( interior, LLColor4::grey % alpha, TRUE );
 589
 590			// Draw X
 591			gl_draw_x(interior, LLColor4::black );
 592		}
 593
 594		// Draw Tentative Label over the image
 595		if( mOwner->getTentative() && !mViewModel->isDirty() )
 596		{
 597			mTentativeLabel->setVisible( TRUE );
 598			drawChild(mTentativeLabel);
 599		}
 600
 601		if (mSelectedItemPinned) return;
 602
 603		LLFolderView* folder_view = mInventoryPanel->getRootFolder();
 604		if (!folder_view) return;
 605
 606		LLInventoryFilter* filter = folder_view->getFilter();
 607		if (!filter) return;
 608
 609		bool is_filter_active = folder_view->getCompletedFilterGeneration() < filter->getCurrentGeneration() &&
 610				filter->isNotDefault();
 611
 612		// After inventory panel filter is applied we have to update
 613		// constraint rect for the selected item because of folder view
 614		// AutoSelectOverride set to TRUE. We force PinningSelectedItem
 615		// flag to FALSE state and setting filter "dirty" to update
 616		// scroll container to show selected item (see LLFolderView::doIdle()).
 617		if (!is_filter_active && !mSelectedItemPinned)
 618		{
 619			folder_view->setPinningSelectedItem(mSelectedItemPinned);
 620			folder_view->dirtyFilter();
 621			folder_view->arrangeFromRoot();
 622
 623			mSelectedItemPinned = TRUE;
 624		}
 625	}
 626}
 627
 628// static
 629/*
 630void LLFloaterTexturePicker::onSaveAnotherCopyDialog( S32 option, void* userdata )
 631{
 632	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 633	if( 0 == option )
 634	{
 635		self->copyToInventoryFinal();
 636	}
 637}
 638*/
 639
 640const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, BOOL copyable_only)
 641{
 642	LLViewerInventoryCategory::cat_array_t cats;
 643	LLViewerInventoryItem::item_array_t items;
 644	LLAssetIDMatches asset_id_matches(asset_id);
 645	gInventory.collectDescendentsIf(LLUUID::null,
 646							cats,
 647							items,
 648							LLInventoryModel::INCLUDE_TRASH,
 649							asset_id_matches);
 650
 651	if (items.count())
 652	{
 653		// search for copyable version first
 654		for (S32 i = 0; i < items.count(); i++)
 655		{
 656			LLInventoryItem* itemp = items[i];
 657			LLPermissions item_permissions = itemp->getPermissions();
 658			if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
 659			{
 660				return itemp->getUUID();
 661			}
 662		}
 663		// otherwise just return first instance, unless copyable requested
 664		if (copyable_only)
 665		{
 666			return LLUUID::null;
 667		}
 668		else
 669		{
 670			return items[0]->getUUID();
 671		}
 672	}
 673
 674	return LLUUID::null;
 675}
 676
 677PermissionMask LLFloaterTexturePicker::getFilterPermMask()
 678{
 679	bool apply_immediate = getChild<LLUICtrl>("apply_immediate_check")->getValue().asBoolean();
 680	return apply_immediate ? mImmediateFilterPermMask : mNonImmediateFilterPermMask;
 681}
 682
 683void LLFloaterTexturePicker::commitIfImmediateSet()
 684{
 685	bool apply_immediate = getChild<LLUICtrl>("apply_immediate_check")->getValue().asBoolean();
 686	if (!mNoCopyTextureSelected && apply_immediate && mOwner)
 687	{
 688		mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE);
 689	}
 690}
 691
 692// static
 693void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
 694{
 695	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 696	if (self->mOwner)
 697	{
 698		self->setImageID( self->mOwner->getDefaultImageAssetID() );
 699	}
 700	self->commitIfImmediateSet();
 701}
 702
 703// static
 704void LLFloaterTexturePicker::onBtnWhite(void* userdata)
 705{
 706	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 707	self->setImageID( self->mWhiteImageAssetID );
 708	self->commitIfImmediateSet();
 709}
 710
 711
 712// static
 713void LLFloaterTexturePicker::onBtnNone(void* userdata)
 714{
 715	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 716	self->setImageID( LLUUID::null );
 717	self->commitIfImmediateSet();
 718}
 719
 720/*
 721// static
 722void LLFloaterTexturePicker::onBtnRevert(void* userdata)
 723{
 724	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 725	self->setImageID( self->mOriginalImageAssetID );
 726	// TODO: Change this to tell the owner to cancel.  It needs to be
 727	// smart enough to restore multi-texture selections.
 728	self->mOwner->onFloaterCommit();
 729	self->mViewModel->resetDirty();
 730}*/
 731
 732// static
 733void LLFloaterTexturePicker::onBtnCancel(void* userdata)
 734{
 735	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 736	self->setImageID( self->mOriginalImageAssetID );
 737	if (self->mOwner)
 738	{
 739		self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CANCEL);
 740	}
 741	self->mViewModel->resetDirty();
 742	self->closeFloater();
 743}
 744
 745// static
 746void LLFloaterTexturePicker::onBtnSelect(void* userdata)
 747{
 748	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 749	if (self->mOwner)
 750	{
 751		self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT);
 752	}
 753	self->closeFloater();
 754}
 755
 756void LLFloaterTexturePicker::onBtnPipette()
 757{
 758	BOOL pipette_active = getChild<LLUICtrl>("Pipette")->getValue().asBoolean();
 759	pipette_active = !pipette_active;
 760	if (pipette_active)
 761	{
 762		LLToolMgr::getInstance()->setTransientTool(LLToolPipette::getInstance());
 763	}
 764	else
 765	{
 766		LLToolMgr::getInstance()->clearTransientTool();
 767	}
 768}
 769
 770void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
 771{
 772	if (items.size())
 773	{
 774		LLFolderViewItem* first_item = items.front();
 775		LLInventoryItem* itemp = gInventory.getItem(first_item->getListener()->getUUID());
 776		mNoCopyTextureSelected = FALSE;
 777		if (itemp)
 778		{
 779			if (!itemp->getPermissions().allowCopyBy(gAgent.getID()))
 780			{
 781				mNoCopyTextureSelected = TRUE;
 782			}
 783			mImageAssetID = itemp->getAssetUUID();
 784			mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
 785			if (user_action)
 786			{
 787				// only commit intentional selections, not implicit ones
 788				commitIfImmediateSet();
 789			}
 790		}
 791	}
 792}
 793
 794// static
 795void LLFloaterTexturePicker::onShowFolders(LLUICtrl* ctrl, void *user_data)
 796{
 797	LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
 798	LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data;
 799
 800	if (check_box->get())
 801	{
 802		picker->mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
 803	}
 804	else
 805	{
 806		picker->mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NO_FOLDERS);
 807	}
 808}
 809
 810// static
 811void LLFloaterTexturePicker::onApplyImmediateCheck(LLUICtrl* ctrl, void *user_data)
 812{
 813	LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data;
 814
 815	LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
 816	gSavedSettings.setBOOL("ApplyTextureImmediately", check_box->get());
 817
 818	picker->updateFilterPermMask();
 819	picker->commitIfImmediateSet();
 820}
 821
 822void LLFloaterTexturePicker::updateFilterPermMask()
 823{
 824	//mInventoryPanel->setFilterPermMask( getFilterPermMask() );  Commented out due to no-copy texture loss.
 825}
 826
 827void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string )
 828{
 829	std::string upper_case_search_string = search_string;
 830	LLStringUtil::toUpper(upper_case_search_string);
 831
 832	if (upper_case_search_string.empty())
 833	{
 834		if (mInventoryPanel->getFilterSubString().empty())
 835		{
 836			// current filter and new filter empty, do nothing
 837			return;
 838		}
 839
 840		mSavedFolderState.setApply(TRUE);
 841		mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState);
 842		// add folder with current item to list of previously opened folders
 843		LLOpenFoldersWithSelection opener;
 844		mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener);
 845		mInventoryPanel->getRootFolder()->scrollToShowSelection();
 846
 847	}
 848	else if (mInventoryPanel->getFilterSubString().empty())
 849	{
 850		// first letter in search term, save existing folder open state
 851		if (!mInventoryPanel->getRootFolder()->isFilterModified())
 852		{
 853			mSavedFolderState.setApply(FALSE);
 854			mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState);
 855		}
 856	}
 857
 858	mInventoryPanel->setFilterSubString(search_string);
 859}
 860
 861void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te )
 862{
 863	LLUUID inventory_item_id = findItemID(te.getID(), TRUE);
 864	if (inventory_item_id.notNull())
 865	{
 866		LLToolPipette::getInstance()->setResult(TRUE, "");
 867		setImageID(te.getID());
 868
 869		mNoCopyTextureSelected = FALSE;
 870		LLInventoryItem* itemp = gInventory.getItem(inventory_item_id);
 871
 872		if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID()))
 873		{
 874			// no copy texture
 875			mNoCopyTextureSelected = TRUE;
 876		}
 877		
 878		commitIfImmediateSet();
 879	}
 880	else
 881	{
 882		LLToolPipette::getInstance()->setResult(FALSE, LLTrans::getString("InventoryNoTexture"));
 883	}
 884}
 885
 886///////////////////////////////////////////////////////////////////////
 887// LLTextureCtrl
 888
 889static LLDefaultChildRegistry::Register<LLTextureCtrl> r("texture_picker");
 890
 891LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
 892:	LLUICtrl(p),
 893	mDragCallback(NULL),
 894	mDropCallback(NULL),
 895	mOnCancelCallback(NULL),
 896	mOnSelectCallback(NULL),
 897	mBorderColor( p.border_color() ),
 898	mAllowNoTexture( FALSE ),
 899	mImmediateFilterPermMask( PERM_NONE ),
 900	mNonImmediateFilterPermMask( PERM_NONE ),
 901	mCanApplyImmediately( FALSE ),
 902	mNeedsRawImageData( FALSE ),
 903	mValid( TRUE ),
 904	mShowLoadingPlaceholder( TRUE ),
 905	mImageAssetID(p.image_id),
 906	mDefaultImageAssetID(p.default_image_id),
 907	mDefaultImageName(p.default_image_name),
 908	mFallbackImage(p.fallback_image)
 909{
 910	setAllowNoTexture(p.allow_no_texture);
 911	setCanApplyImmediately(p.can_apply_immediately);
 912	mCommitOnSelection = !p.no_commit_on_selection;
 913
 914	LLTextBox::Params params(p.caption_text);
 915	params.name(p.label);
 916	params.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ));
 917	params.initial_value(p.label());
 918	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
 919	mCaption = LLUICtrlFactory::create<LLTextBox> (params);
 920	addChild( mCaption );
 921
 922	S32 image_top = getRect().getHeight();
 923	S32 image_bottom = BTN_HEIGHT_SMALL;
 924	S32 image_middle = (image_top + image_bottom) / 2;
 925	S32 line_height = llround(LLFontGL::getFontSansSerifSmall()->getLineHeight());
 926
 927	LLTextBox::Params tentative_label_p(p.multiselect_text);
 928	tentative_label_p.name("Multiple");
 929	tentative_label_p.rect(LLRect (0, image_middle + line_height / 2, getRect().getWidth(), image_middle - line_height / 2 ));
 930	tentative_label_p.follows.flags(FOLLOWS_ALL);
 931	mTentativeLabel = LLUICtrlFactory::create<LLTextBox> (tentative_label_p);
 932	addChild( mTentativeLabel );
 933
 934	LLRect border_rect = getLocalRect();
 935	border_rect.mBottom += BTN_HEIGHT_SMALL;
 936	LLViewBorder::Params vbparams(p.border);
 937	vbparams.name("border");
 938	vbparams.rect(border_rect);
 939	mBorder = LLUICtrlFactory::create<LLViewBorder> (vbparams);
 940	addChild(mBorder);
 941
 942	mLoadingPlaceholderString = LLTrans::getString("texture_loading");
 943}
 944
 945LLTextureCtrl::~LLTextureCtrl()
 946{
 947	closeDependentFloater();
 948}
 949
 950void LLTextureCtrl::setShowLoadingPlaceholder(BOOL showLoadingPlaceholder)
 951{
 952	mShowLoadingPlaceholder = showLoadingPlaceholder;
 953}
 954
 955void LLTextureCtrl::setCaption(const std::string& caption)
 956{
 957	mCaption->setText( caption );
 958}
 959
 960void LLTextureCtrl::setCanApplyImmediately(BOOL b)
 961{
 962	mCanApplyImmediately = b; 
 963	LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
 964	if( floaterp )
 965	{
 966		floaterp->setCanApplyImmediately(b);
 967	}
 968}
 969
 970void LLTextureCtrl::setVisible( BOOL visible ) 
 971{
 972	if( !visible )
 973	{
 974		closeDependentFloater();
 975	}
 976	LLUICtrl::setVisible( visible );
 977}
 978
 979void LLTextureCtrl::setEnabled( BOOL enabled )
 980{
 981	LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
 982	if( enabled )
 983	{
 984		std::string tooltip;
 985		if (floaterp) tooltip = floaterp->getString("choose_picture");
 986		setToolTip( tooltip );
 987	}
 988	else
 989	{
 990		setToolTip( std::string() );
 991		// *TODO: would be better to keep floater open and show
 992		// disabled state.
 993		closeDependentFloater();
 994	}
 995
 996	if( floaterp )
 997	{
 998		floaterp->setActive(enabled);
 999	}
1000
1001	mCaption->setEnabled( enabled );
1002
1003	LLView::setEnabled( enabled );
1004}
1005
1006void LLTextureCtrl::setValid(BOOL valid )
1007{
1008	mValid = valid;
1009	if (!valid)
1010	{
1011		LLFloaterTexturePicker* pickerp = (LLFloaterTexturePicker*)mFloaterHandle.get();
1012		if (pickerp)
1013		{
1014			pickerp->setActive(FALSE);
1015		}
1016	}
1017}
1018
1019
1020// virtual
1021void LLTextureCtrl::clear()
1022{
1023	setImageAssetID(LLUUID::null);
1024}
1025
1026void LLTextureCtrl::setLabel(const std::string& label)
1027{
1028	mLabel = label;
1029	mCaption->setText(label);
1030}
1031
1032void LLTextureCtrl::showPicker(BOOL take_focus)
1033{
1034	// show hourglass cursor when loading inventory window
1035	// because inventory construction is slooow
1036	getWindow()->setCursor(UI_CURSOR_WAIT);
1037	LLFloater* floaterp = mFloaterHandle.get();
1038
1039	// Show the dialog
1040	if( floaterp )
1041	{
1042		floaterp->openFloater();
1043	}
1044	else
1045	{
1046		floaterp = new LLFloaterTexturePicker(
1047			this,
1048			mLabel,
1049			mImmediateFilterPermMask,
1050			mNonImmediateFilterPermMask,
1051			mCanApplyImmediately,
1052			mFallbackImage);
1053
1054		mFloaterHandle = floaterp->getHandle();
1055
1056		LLFloater* root_floater = gFloaterView->getParentFloater(this);
1057		if (root_floater)
1058			root_floater->addDependentFloater(floaterp);
1059		floaterp->openFloater();
1060	}
1061
1062	if (take_focus)
1063	{
1064		floaterp->setFocus(TRUE);
1065	}
1066}
1067
1068
1069void LLTextureCtrl::closeDependentFloater()
1070{
1071	LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
1072	if( floaterp )
1073	{
1074		floaterp->setOwner(NULL);
1075		floaterp->closeFloater();
1076	}
1077}
1078
1079// Allow us to download textures quickly when floater is shown
1080class LLTextureFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
1081{
1082public:
1083	virtual void done()
1084	{
1085		// We need to find textures in all folders, so get the main
1086		// background download going.
1087		LLInventoryModelBackgroundFetch::instance().start();
1088		gInventory.removeObserver(this);
1089		delete this;
1090	}
1091};
1092
1093BOOL LLTextureCtrl::handleHover(S32 x, S32 y, MASK mask)
1094{
1095	getWindow()->setCursor(mBorder->parentPointInView(x,y) ? UI_CURSOR_HAND : UI_CURSOR_ARROW);
1096	return TRUE;
1097}
1098
1099
1100BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
1101{
1102	BOOL handled = LLUICtrl::handleMouseDown( x, y , mask );
1103
1104	if (!handled && mBorder->parentPointInView(x, y))
1105	{
1106		showPicker(FALSE);
1107		//grab textures first...
1108		LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE));
1109		//...then start full inventory fetch.
1110		LLInventoryModelBackgroundFetch::instance().start();
1111		handled = TRUE;
1112	}
1113
1114	return handled;
1115}
1116
1117void LLTextureCtrl::onFloaterClose()
1118{
1119	LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
1120
1121	if (floaterp)
1122	{
1123		floaterp->setOwner(NULL);
1124	}
1125
1126	mFloaterHandle.markDead();
1127}
1128
1129void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
1130{
1131	LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
1132
1133	if( floaterp && getEnabled())
1134	{
1135		if (op == TEXTURE_CANCEL)
1136			mViewModel->resetDirty();
1137		// If the "no_commit_on_selection" parameter is set
1138		// we get dirty only when user presses OK in the picker
1139		// (i.e. op == TEXTURE_SELECT) or texture changes via DnD.
1140		else if (mCommitOnSelection || op == TEXTURE_SELECT)
1141			mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
1142			
1143		if( floaterp->isDirty() )
1144		{
1145			setTentative( FALSE );
1146			mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
1147			lldebugs << "mImageItemID: " << mImageItemID << llendl;
1148			mImageAssetID = floaterp->getAssetID();
1149			lldebugs << "mImageAssetID: " << mImageAssetID << llendl;
1150			if (op == TEXTURE_SELECT && mOnSelectCallback)
1151			{
1152				mOnSelectCallback( this, LLSD() );
1153			}
1154			else if (op == TEXTURE_CANCEL && mOnCancelCallback)
1155			{
1156				mOnCancelCallback( this, LLSD() );
1157			}
1158			else
1159			{
1160				// If the "no_commit_on_selection" parameter is set
1161				// we commit only when user presses OK in the picker
1162				// (i.e. op == TEXTURE_SELECT) or texture changes via DnD.
1163				if (mCommitOnSelection || op == TEXTURE_SELECT)
1164					onCommit();
1165			}
1166		}
1167	}
1168}
1169
1170void	LLTextureCtrl::setImageAssetName(const std::string& name)
1171{
1172	LLPointer<LLUIImage> imagep = LLUI::getUIImage(name);
1173	if(imagep)
1174	{
1175		LLViewerFetchedTexture* pTexture = dynamic_cast<LLViewerFetchedTexture*>(imagep->getImage().get());
1176		if(pTexture)
1177		{
1178			LLUUID id = pTexture->getID();
1179			setImageAssetID(id);
1180		}
1181	}
1182}
1183
1184void LLTextureCtrl::setImageAssetID( const LLUUID& asset_id )
1185{
1186	if( mImageAssetID != asset_id )
1187	{
1188		mImageItemID.setNull();
1189		mImageAssetID = asset_id;
1190		LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
1191		if( floaterp && getEnabled() )
1192		{
1193			floaterp->setImageID( asset_id );
1194			floaterp->resetDirty();
1195		}
1196	}
1197}
1198
1199BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
1200					  BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
1201					  EAcceptance *accept,
1202					  std::string& tooltip_msg)
1203{
1204	BOOL handled = FALSE;
1205
1206	// this downcast may be invalid - but if the second test below
1207	// returns true, then the cast was valid, and we can perform
1208	// the third test without problems.
1209	LLInventoryItem* item = (LLInventoryItem*)cargo_data; 
1210	bool is_mesh = cargo_type == DAD_MESH;
1211
1212	if (getEnabled() &&
1213		((cargo_type == DAD_TEXTURE) || is_mesh) &&
1214		 allowDrop(item))
1215	{
1216		if (drop)
1217		{
1218			if(doDrop(item))
1219			{
1220				if (!mCommitOnSelection)
1221					mViewModel->setDirty();
1222
1223				// This removes the 'Multiple' overlay, since
1224				// there is now only one texture selected.
1225				setTentative( FALSE ); 
1226				onCommit();
1227			}
1228		}
1229
1230		*accept = ACCEPT_YES_SINGLE;
1231	}
1232	else
1233	{
1234		*accept = ACCEPT_NO;
1235	}
1236
1237	handled = TRUE;
1238	lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLTextureCtrl " << getName() << llendl;
1239
1240	return handled;
1241}
1242
1243void LLTextureCtrl::draw()
1244{
1245	mBorder->setKeyboardFocusHighlight(hasFocus());
1246
1247	if (!mValid)
1248	{
1249		mTexturep = NULL;
1250	}
1251	else if (!mImageAssetID.isNull())
1252	{
1253		LLPointer<LLViewerFetchedTexture> texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID, MIPMAP_YES,LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
1254		
1255		texture->setBoostLevel(LLViewerTexture::BOOST_PREVIEW);
1256		texture->forceToSaveRawImage(0) ;
1257
1258		mTexturep = texture;
1259	}
1260	else//mImageAssetID == LLUUID::null
1261	{
1262		mTexturep = NULL;
1263	}
1264	
1265	// Border
1266	LLRect border( 0, getRect().getHeight(), getRect().getWidth(), BTN_HEIGHT_SMALL );
1267	gl_rect_2d( border, mBorderColor.get(), FALSE );
1268
1269	// Interior
1270	LLRect interior = border;
1271	interior.stretch( -1 ); 
1272
1273	// If we're in a focused floater, don't apply the floater's alpha to the texture (STORM-677).
1274	const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
1275	if( mTexturep )
1276	{
1277		if( mTexturep->getComponents() == 4 )
1278		{
1279			gl_rect_2d_checkerboard( interior, alpha );
1280		}
1281		
1282		gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
1283		mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
1284	}
1285	else if (!mFallbackImage.isNull())
1286	{
1287		mFallbackImage->draw(interior, UI_VERTEX_COLOR % alpha);
1288	}
1289	else
1290	{
1291		gl_rect_2d( interior, LLColor4::grey % alpha, TRUE );
1292
1293		// Draw X
1294		gl_draw_x( interior, LLColor4::black );
1295	}
1296
1297	mTentativeLabel->setVisible( !mTexturep.isNull() && getTentative() );
1298	
1299	// Show "Loading..." string on the top left corner while this texture is loading.
1300	// Using the discard level, do not show the string if the texture is almost but not 
1301	// fully loaded.
1302	if (mTexturep.notNull() &&
1303		(!mTexturep->isFullyLoaded()) &&
1304		(mShowLoadingPlaceholder == TRUE))
1305	{
1306		U32 v_offset = 25;
1307		LLFontGL* font = LLFontGL::getFontSansSerif();
1308
1309		// Don't show as loaded if the texture is almost fully loaded (i.e. discard1) unless god
1310		if ((mTexturep->getDiscardLevel() > 1) || gAgent.isGodlike())
1311		{
1312			font->renderUTF8(
1313				mLoadingPlaceholderString, 
1314				0,
1315				llfloor(interior.mLeft+3), 
1316				llfloor(interior.mTop-v_offset),
1317				LLColor4::white,
1318				LLFontGL::LEFT,
1319				LLFontGL::BASELINE,
1320				LLFontGL::DROP_SHADOW);
1321		}
1322
1323		// Optionally show more detailed information.
1324		if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
1325		{
1326			LLFontGL* font = LLFontGL::getFontSansSerif();
1327			std::string tdesc;
1328			// Show what % the texture has loaded (0 to 100%, 100 is highest), and what level of detail (5 to 0, 0 is best).
1329
1330			v_offset += 12;
1331			tdesc = llformat("  PK  : %d%%", U32(mTexturep->getDownloadProgress()*100.0));
1332			font->renderUTF8(tdesc, 0, llfloor(interior.mLeft+3), llfloor(interior.mTop-v_offset),
1333							 LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
1334
1335			v_offset += 12;
1336			tdesc = llformat("  LVL: %d", mTexturep->getDiscardLevel());
1337			font->renderUTF8(tdesc, 0, llfloor(interior.mLeft+3), llfloor(interior.mTop-v_offset),
1338							 LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
1339
1340			v_offset += 12;
1341			tdesc = llformat("  ID  : %s...", (mImageAssetID.asString().substr(0,7)).c_str());
1342			font->renderUTF8(tdesc, 0, llfloor(interior.mLeft+3), llfloor(interior.mTop-v_offset),
1343							 LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
1344		}
1345	}
1346
1347	LLUICtrl::draw();
1348}
1349
1350BOOL LLTextureCtrl::allowDrop(LLInventoryItem* item)
1351{
1352	BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
1353	BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
1354	BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
1355														gAgent.getID());
1356
1357	PermissionMask item_perm_mask = 0;
1358	if (copy) item_perm_mask |= PERM_COPY;
1359	if (mod)  item_perm_mask |= PERM_MODIFY;
1360	if (xfer) item_perm_mask |= PERM_TRANSFER;
1361	
1362//	PermissionMask filter_perm_mask = mCanApplyImmediately ?			commented out due to no-copy texture loss.
1363//			mImmediateFilterPermMask : mNonImmediateFilterPermMask;
1364	PermissionMask filter_perm_mask = mImmediateFilterPermMask;
1365	if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask )
1366	{
1367		if(mDragCallback)
1368		{
1369			return mDragCallback(this, item);
1370		}
1371		else
1372		{
1373			return TRUE;
1374		}
1375	}
1376	else
1377	{
1378		return FALSE;
1379	}
1380}
1381
1382BOOL LLTextureCtrl::doDrop(LLInventoryItem* item)
1383{
1384	// call the callback if it exists.
1385	if(mDropCallback)
1386	{
1387		// if it returns TRUE, we return TRUE, and therefore the
1388		// commit is called above.
1389		return mDropCallback(this, item);
1390	}
1391
1392	// no callback installed, so just set the image ids and carry on.
1393	setImageAssetID( item->getAssetUUID() );
1394	mImageItemID = item->getUUID();
1395	return TRUE;
1396}
1397
1398BOOL LLTextureCtrl::handleUnicodeCharHere(llwchar uni_char)
1399{
1400	if( ' ' == uni_char )
1401	{
1402		showPicker(TRUE);
1403		return TRUE;
1404	}
1405	return LLUICtrl::handleUnicodeCharHere(uni_char);
1406}
1407
1408void LLTextureCtrl::setValue( const LLSD& value )
1409{
1410	setImageAssetID(value.asUUID());
1411}
1412
1413LLSD LLTextureCtrl::getValue() const
1414{
1415	return LLSD(getImageAssetID());
1416}
1417
1418
1419
1420
1421