diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/lltexturectrl.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/lltexturectrl.cpp')
-rw-r--r-- | linden/indra/newview/lltexturectrl.cpp | 1387 |
1 files changed, 1387 insertions, 0 deletions
diff --git a/linden/indra/newview/lltexturectrl.cpp b/linden/indra/newview/lltexturectrl.cpp new file mode 100644 index 0000000..9edd0ad --- /dev/null +++ b/linden/indra/newview/lltexturectrl.cpp | |||
@@ -0,0 +1,1387 @@ | |||
1 | /** | ||
2 | * @file lltexturectrl.cpp | ||
3 | * @author Richard Nelson, James Cook | ||
4 | * @brief LLTextureCtrl class implementation including related functions | ||
5 | * | ||
6 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #include "llviewerprecompiledheaders.h" | ||
30 | |||
31 | #include "lltexturectrl.h" | ||
32 | |||
33 | #include "llagent.h" | ||
34 | #include "llviewerimagelist.h" | ||
35 | #include "llcheckboxctrl.h" | ||
36 | #include "llcombobox.h" | ||
37 | #include "llbutton.h" | ||
38 | #include "lldraghandle.h" | ||
39 | #include "llfocusmgr.h" | ||
40 | #include "llviewerimage.h" | ||
41 | #include "llfolderview.h" | ||
42 | #include "llinventory.h" | ||
43 | #include "llinventorymodel.h" | ||
44 | #include "llinventoryview.h" | ||
45 | #include "lllineeditor.h" | ||
46 | #include "llui.h" | ||
47 | #include "llviewerinventory.h" | ||
48 | #include "llpermissions.h" | ||
49 | #include "llsaleinfo.h" | ||
50 | #include "llassetstorage.h" | ||
51 | #include "lltextbox.h" | ||
52 | #include "llresizehandle.h" | ||
53 | #include "llscrollcontainer.h" | ||
54 | #include "lltoolmgr.h" | ||
55 | #include "lltoolpipette.h" | ||
56 | |||
57 | #include "lltool.h" | ||
58 | #include "llviewerwindow.h" | ||
59 | #include "llviewerobject.h" | ||
60 | #include "llviewercontrol.h" | ||
61 | #include "llglheaders.h" | ||
62 | #include "llvieweruictrlfactory.h" | ||
63 | |||
64 | |||
65 | static const S32 CLOSE_BTN_WIDTH = 100; | ||
66 | const S32 PIPETTE_BTN_WIDTH = 32; | ||
67 | static const S32 HPAD = 4; | ||
68 | static const S32 VPAD = 4; | ||
69 | static const S32 LINE = 16; | ||
70 | static const S32 SMALL_BTN_WIDTH = 64; | ||
71 | static const S32 TEX_PICKER_MIN_WIDTH = | ||
72 | (HPAD + | ||
73 | CLOSE_BTN_WIDTH + | ||
74 | HPAD + | ||
75 | CLOSE_BTN_WIDTH + | ||
76 | HPAD + | ||
77 | SMALL_BTN_WIDTH + | ||
78 | HPAD + | ||
79 | SMALL_BTN_WIDTH + | ||
80 | HPAD + | ||
81 | 30 + | ||
82 | RESIZE_HANDLE_WIDTH * 2); | ||
83 | static const S32 CLEAR_BTN_WIDTH = 50; | ||
84 | static const S32 TEX_PICKER_MIN_HEIGHT = 290; | ||
85 | static const S32 FOOTER_HEIGHT = 100; | ||
86 | static const S32 BORDER_PAD = HPAD; | ||
87 | static const S32 TEXTURE_INVENTORY_PADDING = 30; | ||
88 | static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f; | ||
89 | static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; | ||
90 | static const F32 CONTEXT_FADE_TIME = 0.08f; | ||
91 | |||
92 | //static const char CURRENT_IMAGE_NAME[] = "Current Texture"; | ||
93 | //static const char WHITE_IMAGE_NAME[] = "Blank Texture"; | ||
94 | //static const char NO_IMAGE_NAME[] = "None"; | ||
95 | |||
96 | ////////////////////////////////////////////////////////////////////////////////////////// | ||
97 | // LLFloaterTexturePicker | ||
98 | |||
99 | class LLFloaterTexturePicker : public LLFloater | ||
100 | { | ||
101 | public: | ||
102 | LLFloaterTexturePicker( | ||
103 | LLTextureCtrl* owner, | ||
104 | const LLRect& rect, | ||
105 | const std::string& label, | ||
106 | PermissionMask immediate_filter_perm_mask, | ||
107 | PermissionMask non_immediate_filter_perm_mask, | ||
108 | BOOL can_apply_immediately); | ||
109 | virtual ~LLFloaterTexturePicker(); | ||
110 | |||
111 | // LLView overrides | ||
112 | virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, | ||
113 | BOOL drop, EDragAndDropType cargo_type, void *cargo_data, | ||
114 | EAcceptance *accept, | ||
115 | LLString& tooltip_msg); | ||
116 | virtual void draw(); | ||
117 | |||
118 | // LLFloater overrides | ||
119 | virtual void onClose(bool app_quitting); | ||
120 | |||
121 | // New functions | ||
122 | void setImageID( const LLUUID& image_asset_id); | ||
123 | void updateImageStats(); | ||
124 | const LLUUID& getAssetID() { return mImageAssetID; } | ||
125 | const LLUUID& findItemID(const LLUUID& asset_id, BOOL copyable_only); | ||
126 | void setCanApplyImmediately(BOOL b); | ||
127 | |||
128 | void setDirty( BOOL b ) { mIsDirty = b; } | ||
129 | BOOL isDirty() { return mIsDirty; } | ||
130 | void setActive( BOOL active ); | ||
131 | |||
132 | LLTextureCtrl* getOwner() const { return mOwner; } | ||
133 | void setOwner(LLTextureCtrl* owner) { mOwner = owner; } | ||
134 | |||
135 | void stopUsingPipette(); | ||
136 | PermissionMask getFilterPermMask(); | ||
137 | void updateFilterPermMask(); | ||
138 | void commitIfImmediateSet(); | ||
139 | |||
140 | static void onBtnSetToDefault( void* userdata ); | ||
141 | static void onBtnSelect( void* userdata ); | ||
142 | static void onBtnCancel( void* userdata ); | ||
143 | static void onBtnPipette( void* userdata ); | ||
144 | //static void onBtnRevert( void* userdata ); | ||
145 | static void onBtnWhite( void* userdata ); | ||
146 | static void onBtnNone( void* userdata ); | ||
147 | static void onBtnClear( void* userdata ); | ||
148 | static void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action, void* data); | ||
149 | static void onShowFolders(LLUICtrl* ctrl, void* userdata); | ||
150 | static void onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata); | ||
151 | static void onSearchEdit(const LLString& search_string, void* user_data ); | ||
152 | static void onTextureSelect( const LLTextureEntry& te, void *data ); | ||
153 | |||
154 | protected: | ||
155 | LLPointer<LLViewerImage> mTexturep; | ||
156 | LLTextureCtrl* mOwner; | ||
157 | |||
158 | LLUUID mImageAssetID; // Currently selected texture | ||
159 | |||
160 | LLUUID mWhiteImageAssetID; | ||
161 | LLUUID mSpecialCurrentImageAssetID; // Used when the asset id has no corresponding texture in the user's inventory. | ||
162 | LLUUID mOriginalImageAssetID; | ||
163 | |||
164 | LLTextBox* mTentativeLabel; | ||
165 | LLTextBox* mResolutionLabel; | ||
166 | |||
167 | LLString mPendingName; | ||
168 | BOOL mIsDirty; | ||
169 | BOOL mActive; | ||
170 | |||
171 | LLSearchEditor* mSearchEdit; | ||
172 | LLInventoryPanel* mInventoryPanel; | ||
173 | PermissionMask mImmediateFilterPermMask; | ||
174 | PermissionMask mNonImmediateFilterPermMask; | ||
175 | BOOL mCanApplyImmediately; | ||
176 | BOOL mNoCopyTextureSelected; | ||
177 | F32 mContextConeOpacity; | ||
178 | }; | ||
179 | |||
180 | LLFloaterTexturePicker::LLFloaterTexturePicker( | ||
181 | LLTextureCtrl* owner, | ||
182 | const LLRect& rect, | ||
183 | const std::string& label, | ||
184 | PermissionMask immediate_filter_perm_mask, | ||
185 | PermissionMask non_immediate_filter_perm_mask, | ||
186 | BOOL can_apply_immediately) | ||
187 | : | ||
188 | LLFloater( "texture picker", | ||
189 | rect, | ||
190 | LLString( "Pick: " ) + label, | ||
191 | TRUE, | ||
192 | TEX_PICKER_MIN_WIDTH, TEX_PICKER_MIN_HEIGHT ), | ||
193 | mOwner( owner ), | ||
194 | mImageAssetID( owner->getImageAssetID() ), | ||
195 | mWhiteImageAssetID( gSavedSettings.getString( "UIImgWhiteUUID" ) ), | ||
196 | mOriginalImageAssetID(owner->getImageAssetID()), | ||
197 | mTentativeLabel(NULL), | ||
198 | mResolutionLabel(NULL), | ||
199 | mIsDirty( FALSE ), | ||
200 | mActive( TRUE ), | ||
201 | mSearchEdit(NULL), | ||
202 | mImmediateFilterPermMask(immediate_filter_perm_mask), | ||
203 | mNonImmediateFilterPermMask(non_immediate_filter_perm_mask), | ||
204 | mContextConeOpacity(0.f) | ||
205 | { | ||
206 | gUICtrlFactory->buildFloater(this,"floater_texture_ctrl.xml"); | ||
207 | |||
208 | mTentativeLabel = LLUICtrlFactory::getTextBoxByName(this,"Multiple"); | ||
209 | |||
210 | mResolutionLabel = LLUICtrlFactory::getTextBoxByName(this,"unknown"); | ||
211 | |||
212 | |||
213 | childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this); | ||
214 | childSetAction("None", LLFloaterTexturePicker::onBtnNone,this); | ||
215 | childSetAction("Blank", LLFloaterTexturePicker::onBtnWhite,this); | ||
216 | |||
217 | |||
218 | childSetCommitCallback("show_folders_check", onShowFolders, this); | ||
219 | childSetVisible("show_folders_check", FALSE); | ||
220 | |||
221 | mSearchEdit = (LLSearchEditor*)getCtrlByNameAndType("inventory search editor", WIDGET_TYPE_SEARCH_EDITOR); | ||
222 | mSearchEdit->setSearchCallback(onSearchEdit, this); | ||
223 | |||
224 | mInventoryPanel = (LLInventoryPanel*)this->getCtrlByNameAndType("inventory panel", WIDGET_TYPE_INVENTORY_PANEL); | ||
225 | |||
226 | if(mInventoryPanel) | ||
227 | { | ||
228 | U32 filter_types = 0x0; | ||
229 | filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; | ||
230 | filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; | ||
231 | |||
232 | mInventoryPanel->setAutoSelectOverride(true); | ||
233 | mInventoryPanel->setFilterTypes(filter_types); | ||
234 | mInventoryPanel->setFilterPermMask(getFilterPermMask()); | ||
235 | mInventoryPanel->setSelectCallback(onSelectionChange, this); | ||
236 | mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); | ||
237 | mInventoryPanel->setAllowMultiSelect(FALSE); | ||
238 | // Commented out to stop opening all folders with textures | ||
239 | // mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_TEXTURE); | ||
240 | |||
241 | // don't put keyboard focus on selected item, because the selection callback | ||
242 | // will assume that this was user input | ||
243 | mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO); | ||
244 | } | ||
245 | |||
246 | mCanApplyImmediately = can_apply_immediately; | ||
247 | mNoCopyTextureSelected = FALSE; | ||
248 | |||
249 | childSetValue("apply_immediate_check", gSavedSettings.getBOOL("ApplyTextureImmediately")); | ||
250 | childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this); | ||
251 | |||
252 | if (!can_apply_immediately) | ||
253 | { | ||
254 | childSetEnabled("show_folders_check", FALSE); | ||
255 | } | ||
256 | |||
257 | childSetAction("Pipette", LLFloaterTexturePicker::onBtnPipette,this); | ||
258 | childSetAction("Cancel", LLFloaterTexturePicker::onBtnCancel,this); | ||
259 | childSetAction("Select", LLFloaterTexturePicker::onBtnSelect,this); | ||
260 | |||
261 | // update permission filter once UI is fully initialized | ||
262 | updateFilterPermMask(); | ||
263 | |||
264 | setCanMinimize(FALSE); | ||
265 | } | ||
266 | |||
267 | LLFloaterTexturePicker::~LLFloaterTexturePicker() | ||
268 | { | ||
269 | } | ||
270 | |||
271 | void LLFloaterTexturePicker::setImageID(const LLUUID& image_id) | ||
272 | { | ||
273 | if( mImageAssetID != image_id && mActive) | ||
274 | { | ||
275 | mNoCopyTextureSelected = FALSE; | ||
276 | mIsDirty = TRUE; | ||
277 | mImageAssetID = image_id; | ||
278 | LLUUID item_id = findItemID(mImageAssetID, FALSE); | ||
279 | if (item_id.isNull()) | ||
280 | { | ||
281 | mInventoryPanel->clearSelection(); | ||
282 | } | ||
283 | else | ||
284 | { | ||
285 | LLInventoryItem* itemp = gInventory.getItem(image_id); | ||
286 | if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) | ||
287 | { | ||
288 | // no copy texture | ||
289 | childSetValue("apply_immediate_check", FALSE); | ||
290 | mNoCopyTextureSelected = TRUE; | ||
291 | } | ||
292 | mInventoryPanel->setSelection(item_id, TAKE_FOCUS_NO); | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | void LLFloaterTexturePicker::setActive( BOOL active ) | ||
298 | { | ||
299 | if (!active && childGetValue("Pipette").asBoolean()) | ||
300 | { | ||
301 | stopUsingPipette(); | ||
302 | } | ||
303 | mActive = active; | ||
304 | } | ||
305 | |||
306 | void LLFloaterTexturePicker::setCanApplyImmediately(BOOL b) | ||
307 | { | ||
308 | mCanApplyImmediately = b; | ||
309 | if (!mCanApplyImmediately) | ||
310 | { | ||
311 | childSetValue("apply_immediate_check", FALSE); | ||
312 | } | ||
313 | updateFilterPermMask(); | ||
314 | } | ||
315 | |||
316 | void LLFloaterTexturePicker::stopUsingPipette() | ||
317 | { | ||
318 | if (gToolMgr && gToolMgr->getCurrentTool(gKeyboard->currentMask(TRUE)) == gToolPipette) | ||
319 | { | ||
320 | gToolMgr->clearTransientTool(); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | void LLFloaterTexturePicker::updateImageStats() | ||
325 | { | ||
326 | if (mTexturep.notNull()) | ||
327 | { | ||
328 | //RN: have we received header data for this image? | ||
329 | if (mTexturep->getWidth(0) > 0 && mTexturep->getHeight(0) > 0) | ||
330 | { | ||
331 | std::ostringstream formatted_dims; | ||
332 | formatted_dims << llformat("Dimensions: %d x %d", mTexturep->getWidth(0),mTexturep->getHeight(0)); | ||
333 | mResolutionLabel->setText(formatted_dims.str()); | ||
334 | } | ||
335 | else | ||
336 | { | ||
337 | mResolutionLabel->setText("Dimensions: unknown"); | ||
338 | } | ||
339 | if (gAgent.isGodlike()) | ||
340 | { | ||
341 | LLString tstring = "Pick: " + mTexturep->getID().getString(); | ||
342 | setTitle(tstring); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | // virtual | ||
348 | BOOL LLFloaterTexturePicker::handleDragAndDrop( | ||
349 | S32 x, S32 y, MASK mask, | ||
350 | BOOL drop, | ||
351 | EDragAndDropType cargo_type, void *cargo_data, | ||
352 | EAcceptance *accept, | ||
353 | LLString& tooltip_msg) | ||
354 | { | ||
355 | BOOL handled = FALSE; | ||
356 | |||
357 | if (cargo_type == DAD_TEXTURE) | ||
358 | { | ||
359 | LLInventoryItem *item = (LLInventoryItem *)cargo_data; | ||
360 | |||
361 | BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); | ||
362 | BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); | ||
363 | BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, | ||
364 | gAgent.getID()); | ||
365 | |||
366 | PermissionMask item_perm_mask = 0; | ||
367 | if (copy) item_perm_mask |= PERM_COPY; | ||
368 | if (mod) item_perm_mask |= PERM_MODIFY; | ||
369 | if (xfer) item_perm_mask |= PERM_TRANSFER; | ||
370 | |||
371 | PermissionMask filter_perm_mask = getFilterPermMask(); | ||
372 | if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask ) | ||
373 | { | ||
374 | if (drop) | ||
375 | { | ||
376 | setImageID( item->getAssetUUID() ); | ||
377 | commitIfImmediateSet(); | ||
378 | } | ||
379 | |||
380 | *accept = ACCEPT_YES_SINGLE; | ||
381 | } | ||
382 | else | ||
383 | { | ||
384 | *accept = ACCEPT_NO; | ||
385 | } | ||
386 | } | ||
387 | else | ||
388 | { | ||
389 | *accept = ACCEPT_NO; | ||
390 | } | ||
391 | |||
392 | handled = TRUE; | ||
393 | lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFloaterTexturePicker " << getName() << llendl; | ||
394 | |||
395 | return handled; | ||
396 | } | ||
397 | |||
398 | // virtual | ||
399 | void LLFloaterTexturePicker::onClose(bool app_quitting) | ||
400 | { | ||
401 | if (mOwner) | ||
402 | { | ||
403 | mOwner->onFloaterClose(); | ||
404 | } | ||
405 | stopUsingPipette(); | ||
406 | destroy(); | ||
407 | } | ||
408 | |||
409 | // virtual | ||
410 | void LLFloaterTexturePicker::draw() | ||
411 | { | ||
412 | if (mOwner) | ||
413 | { | ||
414 | // draw cone of context pointing back to texture swatch | ||
415 | LLRect owner_rect; | ||
416 | mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this); | ||
417 | LLRect local_rect = getLocalRect(); | ||
418 | if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f) | ||
419 | { | ||
420 | LLGLSNoTexture no_texture; | ||
421 | LLGLEnable(GL_CULL_FACE); | ||
422 | glBegin(GL_QUADS); | ||
423 | { | ||
424 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); | ||
425 | glVertex2i(owner_rect.mLeft, owner_rect.mTop); | ||
426 | glVertex2i(owner_rect.mRight, owner_rect.mTop); | ||
427 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); | ||
428 | glVertex2i(local_rect.mRight, local_rect.mTop); | ||
429 | glVertex2i(local_rect.mLeft, local_rect.mTop); | ||
430 | |||
431 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); | ||
432 | glVertex2i(local_rect.mLeft, local_rect.mTop); | ||
433 | glVertex2i(local_rect.mLeft, local_rect.mBottom); | ||
434 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); | ||
435 | glVertex2i(owner_rect.mLeft, owner_rect.mBottom); | ||
436 | glVertex2i(owner_rect.mLeft, owner_rect.mTop); | ||
437 | |||
438 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); | ||
439 | glVertex2i(local_rect.mRight, local_rect.mBottom); | ||
440 | glVertex2i(local_rect.mRight, local_rect.mTop); | ||
441 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); | ||
442 | glVertex2i(owner_rect.mRight, owner_rect.mTop); | ||
443 | glVertex2i(owner_rect.mRight, owner_rect.mBottom); | ||
444 | |||
445 | |||
446 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); | ||
447 | glVertex2i(local_rect.mLeft, local_rect.mBottom); | ||
448 | glVertex2i(local_rect.mRight, local_rect.mBottom); | ||
449 | glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); | ||
450 | glVertex2i(owner_rect.mRight, owner_rect.mBottom); | ||
451 | glVertex2i(owner_rect.mLeft, owner_rect.mBottom); | ||
452 | } | ||
453 | glEnd(); | ||
454 | } | ||
455 | } | ||
456 | |||
457 | if (gFocusMgr.childHasMouseCapture(mDragHandle)) | ||
458 | { | ||
459 | mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME)); | ||
460 | } | ||
461 | else | ||
462 | { | ||
463 | mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME)); | ||
464 | } | ||
465 | |||
466 | updateImageStats(); | ||
467 | |||
468 | // if we're inactive, gray out "apply immediate" checkbox | ||
469 | childSetEnabled("show_folders_check", mActive && mCanApplyImmediately && !mNoCopyTextureSelected); | ||
470 | childSetEnabled("Select", mActive); | ||
471 | childSetEnabled("Pipette", gToolMgr != NULL && mActive); | ||
472 | childSetValue("Pipette", gToolMgr && gToolMgr->getCurrentTool(gKeyboard->currentMask(TRUE)) == gToolPipette); | ||
473 | |||
474 | //RN: reset search bar to reflect actual search query (all caps, for example) | ||
475 | mSearchEdit->setText(mInventoryPanel->getFilterSubString()); | ||
476 | |||
477 | //BOOL allow_copy = FALSE; | ||
478 | if( getVisible() && mOwner) | ||
479 | { | ||
480 | mTexturep = NULL; | ||
481 | if(mImageAssetID.notNull()) | ||
482 | { | ||
483 | mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); | ||
484 | mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); | ||
485 | } | ||
486 | |||
487 | if (mTentativeLabel) | ||
488 | { | ||
489 | mTentativeLabel->setVisible( FALSE ); | ||
490 | } | ||
491 | |||
492 | childSetEnabled("Default", mImageAssetID != mOwner->getDefaultImageAssetID()); | ||
493 | childSetEnabled("Blank", mImageAssetID != mWhiteImageAssetID ); | ||
494 | childSetEnabled("None", mOwner->getAllowNoTexture() && !mImageAssetID.isNull() ); | ||
495 | |||
496 | LLFloater::draw(); | ||
497 | |||
498 | if( isMinimized() ) | ||
499 | { | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | // Border | ||
504 | LLRect border( BORDER_PAD, | ||
505 | mRect.getHeight() - LLFLOATER_HEADER_SIZE - BORDER_PAD, | ||
506 | ((TEX_PICKER_MIN_WIDTH / 2) - TEXTURE_INVENTORY_PADDING - HPAD) - BORDER_PAD, | ||
507 | BORDER_PAD + FOOTER_HEIGHT + (mRect.getHeight() - TEX_PICKER_MIN_HEIGHT)); | ||
508 | gl_rect_2d( border, LLColor4::black, FALSE ); | ||
509 | |||
510 | |||
511 | // Interior | ||
512 | LLRect interior = border; | ||
513 | interior.stretch( -1 ); | ||
514 | |||
515 | if( mTexturep ) | ||
516 | { | ||
517 | if( mTexturep->getComponents() == 4 ) | ||
518 | { | ||
519 | gl_rect_2d_checkerboard( interior ); | ||
520 | } | ||
521 | |||
522 | gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep ); | ||
523 | |||
524 | // Pump the priority | ||
525 | mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); | ||
526 | |||
527 | // Draw Tentative Label over the image | ||
528 | if( mOwner->getTentative() && !mIsDirty ) | ||
529 | { | ||
530 | mTentativeLabel->setVisible( TRUE ); | ||
531 | drawChild(mTentativeLabel); | ||
532 | } | ||
533 | } | ||
534 | else | ||
535 | { | ||
536 | gl_rect_2d( interior, LLColor4::grey, TRUE ); | ||
537 | |||
538 | // Draw X | ||
539 | gl_draw_x(interior, LLColor4::black ); | ||
540 | } | ||
541 | } | ||
542 | } | ||
543 | |||
544 | // static | ||
545 | /* | ||
546 | void LLFloaterTexturePicker::onSaveAnotherCopyDialog( S32 option, void* userdata ) | ||
547 | { | ||
548 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
549 | if( 0 == option ) | ||
550 | { | ||
551 | self->copyToInventoryFinal(); | ||
552 | } | ||
553 | } | ||
554 | */ | ||
555 | |||
556 | const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, BOOL copyable_only) | ||
557 | { | ||
558 | LLViewerInventoryCategory::cat_array_t cats; | ||
559 | LLViewerInventoryItem::item_array_t items; | ||
560 | LLAssetIDMatches asset_id_matches(asset_id); | ||
561 | gInventory.collectDescendentsIf(LLUUID::null, | ||
562 | cats, | ||
563 | items, | ||
564 | LLInventoryModel::INCLUDE_TRASH, | ||
565 | asset_id_matches); | ||
566 | |||
567 | if (items.count()) | ||
568 | { | ||
569 | // search for copyable version first | ||
570 | for (S32 i = 0; i < items.count(); i++) | ||
571 | { | ||
572 | LLInventoryItem* itemp = items[i]; | ||
573 | LLPermissions item_permissions = itemp->getPermissions(); | ||
574 | if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) | ||
575 | { | ||
576 | return itemp->getUUID(); | ||
577 | } | ||
578 | } | ||
579 | // otherwise just return first instance, unless copyable requested | ||
580 | if (copyable_only) | ||
581 | { | ||
582 | return LLUUID::null; | ||
583 | } | ||
584 | else | ||
585 | { | ||
586 | return items[0]->getUUID(); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | return LLUUID::null; | ||
591 | } | ||
592 | |||
593 | PermissionMask LLFloaterTexturePicker::getFilterPermMask() | ||
594 | { | ||
595 | bool apply_immediate = childGetValue("apply_immediate_check").asBoolean(); | ||
596 | return apply_immediate ? mImmediateFilterPermMask : mNonImmediateFilterPermMask; | ||
597 | } | ||
598 | |||
599 | void LLFloaterTexturePicker::commitIfImmediateSet() | ||
600 | { | ||
601 | bool apply_immediate = childGetValue("apply_immediate_check").asBoolean(); | ||
602 | if (!mNoCopyTextureSelected && apply_immediate && mOwner) | ||
603 | { | ||
604 | mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | // static | ||
609 | void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata) | ||
610 | { | ||
611 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
612 | if (self->mOwner) | ||
613 | { | ||
614 | self->setImageID( self->mOwner->getDefaultImageAssetID() ); | ||
615 | } | ||
616 | self->commitIfImmediateSet(); | ||
617 | } | ||
618 | |||
619 | // static | ||
620 | void LLFloaterTexturePicker::onBtnWhite(void* userdata) | ||
621 | { | ||
622 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
623 | self->setImageID( self->mWhiteImageAssetID ); | ||
624 | self->commitIfImmediateSet(); | ||
625 | } | ||
626 | |||
627 | |||
628 | // static | ||
629 | void LLFloaterTexturePicker::onBtnNone(void* userdata) | ||
630 | { | ||
631 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
632 | self->setImageID( LLUUID::null ); | ||
633 | self->commitIfImmediateSet(); | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | // static | ||
638 | void LLFloaterTexturePicker::onBtnRevert(void* userdata) | ||
639 | { | ||
640 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
641 | self->setImageID( self->mOriginalImageAssetID ); | ||
642 | // TODO: Change this to tell the owner to cancel. It needs to be | ||
643 | // smart enough to restore multi-texture selections. | ||
644 | self->mOwner->onFloaterCommit(); | ||
645 | self->mIsDirty = FALSE; | ||
646 | }*/ | ||
647 | |||
648 | // static | ||
649 | void LLFloaterTexturePicker::onBtnCancel(void* userdata) | ||
650 | { | ||
651 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
652 | self->setImageID( self->mOriginalImageAssetID ); | ||
653 | if (self->mOwner) | ||
654 | { | ||
655 | self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CANCEL); | ||
656 | } | ||
657 | self->mIsDirty = FALSE; | ||
658 | self->close(); | ||
659 | } | ||
660 | |||
661 | // static | ||
662 | void LLFloaterTexturePicker::onBtnSelect(void* userdata) | ||
663 | { | ||
664 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
665 | if (self->mOwner) | ||
666 | { | ||
667 | self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT); | ||
668 | } | ||
669 | self->close(); | ||
670 | } | ||
671 | |||
672 | // static | ||
673 | void LLFloaterTexturePicker::onBtnPipette( void* userdata ) | ||
674 | { | ||
675 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; | ||
676 | |||
677 | if ( self && gToolMgr) | ||
678 | { | ||
679 | BOOL pipette_active = self->childGetValue("Pipette").asBoolean(); | ||
680 | pipette_active = !pipette_active; | ||
681 | if (pipette_active) | ||
682 | { | ||
683 | gToolPipette->setSelectCallback(onTextureSelect, self); | ||
684 | gToolMgr->setTransientTool(gToolPipette); | ||
685 | } | ||
686 | else | ||
687 | { | ||
688 | gToolMgr->clearTransientTool(); | ||
689 | } | ||
690 | } | ||
691 | |||
692 | } | ||
693 | |||
694 | // static | ||
695 | void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action, void* data) | ||
696 | { | ||
697 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)data; | ||
698 | if (items.size()) | ||
699 | { | ||
700 | LLFolderViewItem* first_item = items.front(); | ||
701 | LLInventoryItem* itemp = gInventory.getItem(first_item->getListener()->getUUID()); | ||
702 | self->mNoCopyTextureSelected = FALSE; | ||
703 | if (itemp) | ||
704 | { | ||
705 | if (!itemp->getPermissions().allowCopyBy(gAgent.getID())) | ||
706 | { | ||
707 | self->mNoCopyTextureSelected = TRUE; | ||
708 | } | ||
709 | self->mImageAssetID = itemp->getAssetUUID(); | ||
710 | self->mIsDirty = TRUE; | ||
711 | if (user_action) | ||
712 | { | ||
713 | // only commit intentional selections, not implicit ones | ||
714 | self->commitIfImmediateSet(); | ||
715 | } | ||
716 | } | ||
717 | } | ||
718 | } | ||
719 | |||
720 | // static | ||
721 | void LLFloaterTexturePicker::onShowFolders(LLUICtrl* ctrl, void *user_data) | ||
722 | { | ||
723 | LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl; | ||
724 | LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data; | ||
725 | |||
726 | if (check_box->get()) | ||
727 | { | ||
728 | picker->mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); | ||
729 | } | ||
730 | else | ||
731 | { | ||
732 | picker->mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NO_FOLDERS); | ||
733 | } | ||
734 | } | ||
735 | |||
736 | // static | ||
737 | void LLFloaterTexturePicker::onApplyImmediateCheck(LLUICtrl* ctrl, void *user_data) | ||
738 | { | ||
739 | LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data; | ||
740 | |||
741 | LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl; | ||
742 | gSavedSettings.setBOOL("ApplyTextureImmediately", check_box->get()); | ||
743 | |||
744 | picker->updateFilterPermMask(); | ||
745 | picker->commitIfImmediateSet(); | ||
746 | } | ||
747 | |||
748 | void LLFloaterTexturePicker::updateFilterPermMask() | ||
749 | { | ||
750 | mInventoryPanel->setFilterPermMask( getFilterPermMask() ); | ||
751 | } | ||
752 | |||
753 | void LLFloaterTexturePicker::onSearchEdit(const LLString& search_string, void* user_data ) | ||
754 | { | ||
755 | LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data; | ||
756 | |||
757 | std::string filter_text = search_string; | ||
758 | |||
759 | if (filter_text.empty()&& picker->mInventoryPanel->getFilterSubString().empty()) | ||
760 | { | ||
761 | // current filter and new filter empty, do nothing | ||
762 | return; | ||
763 | } | ||
764 | std::string upper_case_search_string = filter_text; | ||
765 | LLString::toUpper(upper_case_search_string); | ||
766 | |||
767 | picker->mInventoryPanel->setFilterSubString(upper_case_search_string); | ||
768 | |||
769 | LLFolderView* root_folder = picker->mInventoryPanel->getRootFolder(); | ||
770 | |||
771 | //if (search_string.size()) | ||
772 | //{ | ||
773 | // LLSelectFirstFilteredItem filter; | ||
774 | // root_folder->applyFunctorRecursively(filter); | ||
775 | // //...and scroll to show it | ||
776 | // root_folder->scrollToShowSelection(); | ||
777 | //} | ||
778 | |||
779 | KEY key = gKeyboard->currentKey(); | ||
780 | |||
781 | if ((key == KEY_RETURN || key == KEY_DOWN) && gKeyboard->currentMask(FALSE) == MASK_NONE) | ||
782 | { | ||
783 | if (search_string.size()) | ||
784 | { | ||
785 | LLSelectFirstFilteredItem filter; | ||
786 | root_folder->applyFunctorRecursively(filter); | ||
787 | //...and scroll to show it | ||
788 | root_folder->scrollToShowSelection(); | ||
789 | } | ||
790 | |||
791 | if (!root_folder->getCurSelectedItem()) | ||
792 | { | ||
793 | LLFolderViewItem* itemp = root_folder->getItemByID(gAgent.getInventoryRootID()); | ||
794 | if (itemp) | ||
795 | { | ||
796 | root_folder->setSelection(itemp, FALSE, FALSE); | ||
797 | } | ||
798 | } | ||
799 | |||
800 | // move focus to inventory proper | ||
801 | root_folder->setFocus(TRUE); | ||
802 | root_folder->scrollToShowSelection(); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | //static | ||
807 | void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te, void *data ) | ||
808 | { | ||
809 | LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)data; | ||
810 | |||
811 | LLUUID inventory_item_id = self->findItemID(te.getID(), TRUE); | ||
812 | if (self && inventory_item_id.notNull()) | ||
813 | { | ||
814 | gToolPipette->setResult(TRUE, ""); | ||
815 | self->setImageID(te.getID()); | ||
816 | |||
817 | self->mNoCopyTextureSelected = FALSE; | ||
818 | LLInventoryItem* itemp = gInventory.getItem(inventory_item_id); | ||
819 | |||
820 | if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) | ||
821 | { | ||
822 | // no copy texture | ||
823 | self->mNoCopyTextureSelected = TRUE; | ||
824 | } | ||
825 | |||
826 | self->commitIfImmediateSet(); | ||
827 | } | ||
828 | else | ||
829 | { | ||
830 | gToolPipette->setResult(FALSE, "You do not have a copy this \nof texture in your inventory"); | ||
831 | } | ||
832 | } | ||
833 | |||
834 | /////////////////////////////////////////////////////////////////////// | ||
835 | // LLTextureCtrl | ||
836 | |||
837 | LLTextureCtrl::LLTextureCtrl( | ||
838 | const std::string& name, | ||
839 | const LLRect &rect, | ||
840 | const std::string& label, | ||
841 | const LLUUID &image_id, | ||
842 | const LLUUID &default_image_id, | ||
843 | const std::string& default_image_name ) | ||
844 | : | ||
845 | LLUICtrl(name, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP), | ||
846 | mDragCallback(NULL), | ||
847 | mDropCallback(NULL), | ||
848 | mOnCancelCallback(NULL), | ||
849 | mOnSelectCallback(NULL), | ||
850 | mBorderColor( gColors.getColor("DefaultHighlightLight") ), | ||
851 | mImageAssetID( image_id ), | ||
852 | mDefaultImageAssetID( default_image_id ), | ||
853 | mDefaultImageName( default_image_name ), | ||
854 | mLabel( label ), | ||
855 | mAllowNoTexture( FALSE ), | ||
856 | mImmediateFilterPermMask( PERM_NONE ), | ||
857 | mNonImmediateFilterPermMask( PERM_NONE ), | ||
858 | mCanApplyImmediately( FALSE ), | ||
859 | mNeedsRawImageData( FALSE ), | ||
860 | mValid( TRUE ) | ||
861 | { | ||
862 | mCaption = new LLTextBox( label, | ||
863 | LLRect( 0, BTN_HEIGHT_SMALL, mRect.getWidth(), 0 ), | ||
864 | NULL, | ||
865 | LLFontGL::sSansSerifSmall ); | ||
866 | mCaption->setFollows( FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); | ||
867 | addChild( mCaption ); | ||
868 | |||
869 | S32 image_top = mRect.getHeight(); | ||
870 | S32 image_bottom = BTN_HEIGHT_SMALL; | ||
871 | S32 image_middle = (image_top + image_bottom) / 2; | ||
872 | S32 line_height = llround(LLFontGL::sSansSerifSmall->getLineHeight()); | ||
873 | |||
874 | mTentativeLabel = new LLTextBox( "Multiple", | ||
875 | LLRect( | ||
876 | 0, image_middle + line_height / 2, | ||
877 | mRect.getWidth(), image_middle - line_height / 2 ), | ||
878 | NULL, | ||
879 | LLFontGL::sSansSerifSmall ); | ||
880 | mTentativeLabel->setHAlign( LLFontGL::HCENTER ); | ||
881 | mTentativeLabel->setFollowsAll(); | ||
882 | addChild( mTentativeLabel ); | ||
883 | |||
884 | LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0); | ||
885 | border_rect.mBottom += BTN_HEIGHT_SMALL; | ||
886 | mBorder = new LLViewBorder("border", border_rect, LLViewBorder::BEVEL_IN); | ||
887 | addChild(mBorder); | ||
888 | |||
889 | setEnabled(TRUE); // for the tooltip | ||
890 | } | ||
891 | |||
892 | |||
893 | LLTextureCtrl::~LLTextureCtrl() | ||
894 | { | ||
895 | closeFloater(); | ||
896 | } | ||
897 | |||
898 | // virtual | ||
899 | LLXMLNodePtr LLTextureCtrl::getXML(bool save_children) const | ||
900 | { | ||
901 | LLXMLNodePtr node = LLUICtrl::getXML(); | ||
902 | |||
903 | node->createChild("label", TRUE)->setStringValue(getLabel()); | ||
904 | |||
905 | node->createChild("default_image_name", TRUE)->setStringValue(getDefaultImageName()); | ||
906 | |||
907 | node->createChild("allow_no_texture", TRUE)->setBoolValue(mAllowNoTexture); | ||
908 | |||
909 | node->createChild("can_apply_immediately", TRUE)->setBoolValue(mCanApplyImmediately ); | ||
910 | |||
911 | return node; | ||
912 | } | ||
913 | |||
914 | LLView* LLTextureCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) | ||
915 | { | ||
916 | LLString name("texture_picker"); | ||
917 | node->getAttributeString("name", name); | ||
918 | |||
919 | LLRect rect; | ||
920 | createRect(node, rect, parent); | ||
921 | |||
922 | LLString label; | ||
923 | node->getAttributeString("label", label); | ||
924 | |||
925 | LLString image_id(""); | ||
926 | node->getAttributeString("image", image_id); | ||
927 | |||
928 | LLString default_image_id(""); | ||
929 | node->getAttributeString("default_image", default_image_id); | ||
930 | |||
931 | LLString default_image_name("Default"); | ||
932 | node->getAttributeString("default_image_name", default_image_name); | ||
933 | |||
934 | BOOL allow_no_texture = FALSE; | ||
935 | node->getAttributeBOOL("allow_no_texture", allow_no_texture); | ||
936 | |||
937 | BOOL can_apply_immediately = FALSE; | ||
938 | node->getAttributeBOOL("can_apply_immediately", can_apply_immediately); | ||
939 | |||
940 | if (label.empty()) | ||
941 | { | ||
942 | label.assign(node->getValue()); | ||
943 | } | ||
944 | |||
945 | LLTextureCtrl* texture_picker = new LLTextureCtrl( | ||
946 | name, | ||
947 | rect, | ||
948 | label, | ||
949 | LLUUID(image_id), | ||
950 | LLUUID(default_image_id), | ||
951 | default_image_name ); | ||
952 | texture_picker->setAllowNoTexture(allow_no_texture); | ||
953 | texture_picker->setCanApplyImmediately(can_apply_immediately); | ||
954 | |||
955 | texture_picker->initFromXML(node, parent); | ||
956 | |||
957 | return texture_picker; | ||
958 | } | ||
959 | |||
960 | void LLTextureCtrl::setCaption(const LLString& caption) | ||
961 | { | ||
962 | mCaption->setText( caption ); | ||
963 | } | ||
964 | |||
965 | void LLTextureCtrl::setCanApplyImmediately(BOOL b) | ||
966 | { | ||
967 | mCanApplyImmediately = b; | ||
968 | LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle); | ||
969 | if( floaterp ) | ||
970 | { | ||
971 | floaterp->setCanApplyImmediately(b); | ||
972 | } | ||
973 | } | ||
974 | |||
975 | void LLTextureCtrl::setVisible( BOOL visible ) | ||
976 | { | ||
977 | if( !visible ) | ||
978 | { | ||
979 | closeFloater(); | ||
980 | } | ||
981 | LLUICtrl::setVisible( visible ); | ||
982 | } | ||
983 | |||
984 | void LLTextureCtrl::setEnabled( BOOL enabled ) | ||
985 | { | ||
986 | if( enabled ) | ||
987 | { | ||
988 | setToolTip( "Click to choose a picture" ); | ||
989 | } | ||
990 | else | ||
991 | { | ||
992 | setToolTip( "" ); | ||
993 | // *TODO: would be better to keep floater open and show | ||
994 | // disabled state. | ||
995 | closeFloater(); | ||
996 | } | ||
997 | |||
998 | LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle); | ||
999 | if( floaterp ) | ||
1000 | { | ||
1001 | floaterp->setActive(enabled); | ||
1002 | } | ||
1003 | |||
1004 | mCaption->setEnabled( enabled ); | ||
1005 | |||
1006 | LLUICtrl::setEnabled( enabled ); | ||
1007 | } | ||
1008 | |||
1009 | void LLTextureCtrl::setValid(BOOL valid ) | ||
1010 | { | ||
1011 | mValid = valid; | ||
1012 | if (!valid) | ||
1013 | { | ||
1014 | LLFloaterTexturePicker* pickerp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle); | ||
1015 | if (pickerp) | ||
1016 | { | ||
1017 | pickerp->setActive(FALSE); | ||
1018 | } | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | // virtual | ||
1024 | void LLTextureCtrl::clear() | ||
1025 | { | ||
1026 | setImageAssetID(LLUUID::null); | ||
1027 | } | ||
1028 | |||
1029 | void LLTextureCtrl::setLabel(const LLString& label) | ||
1030 | { | ||
1031 | mLabel = label; | ||
1032 | mCaption->setText(label); | ||
1033 | } | ||
1034 | |||
1035 | void LLTextureCtrl::showPicker(BOOL take_focus) | ||
1036 | { | ||
1037 | LLFloater* floaterp = LLFloater::getFloaterByHandle(mFloaterHandle); | ||
1038 | |||
1039 | // Show the dialog | ||
1040 | if( floaterp ) | ||
1041 | { | ||
1042 | floaterp->open( ); | ||
1043 | } | ||
1044 | else | ||
1045 | { | ||
1046 | if( !mLastFloaterLeftTop.mX && !mLastFloaterLeftTop.mY ) | ||
1047 | { | ||
1048 | gFloaterView->getNewFloaterPosition(&mLastFloaterLeftTop.mX, &mLastFloaterLeftTop.mY); | ||
1049 | } | ||
1050 | LLRect rect = gSavedSettings.getRect("TexturePickerRect"); | ||
1051 | rect.translate( mLastFloaterLeftTop.mX - rect.mLeft, mLastFloaterLeftTop.mY - rect.mTop ); | ||
1052 | |||
1053 | floaterp = new LLFloaterTexturePicker( | ||
1054 | this, | ||
1055 | rect, | ||
1056 | mLabel, | ||
1057 | mImmediateFilterPermMask, | ||
1058 | mNonImmediateFilterPermMask, | ||
1059 | mCanApplyImmediately); | ||
1060 | mFloaterHandle = floaterp->getHandle(); | ||
1061 | |||
1062 | gFloaterView->getParentFloater(this)->addDependentFloater(floaterp); | ||
1063 | floaterp->open(); | ||
1064 | } | ||
1065 | |||
1066 | if (take_focus) | ||
1067 | { | ||
1068 | floaterp->setFocus(TRUE); | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | void LLTextureCtrl::closeFloater() | ||
1074 | { | ||
1075 | LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle); | ||
1076 | if( floaterp ) | ||
1077 | { | ||
1078 | floaterp->setOwner(NULL); | ||
1079 | floaterp->close(); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | // Allow us to download textures quickly when floater is shown | ||
1084 | class LLTextureFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver | ||
1085 | { | ||
1086 | public: | ||
1087 | virtual void done() | ||
1088 | { | ||
1089 | // We need to find textures in all folders, so get the main | ||
1090 | // background download going. | ||
1091 | gInventory.startBackgroundFetch(); | ||
1092 | gInventory.removeObserver(this); | ||
1093 | delete this; | ||
1094 | } | ||
1095 | }; | ||
1096 | |||
1097 | BOOL LLTextureCtrl::handleHover(S32 x, S32 y, MASK mask) | ||
1098 | { | ||
1099 | getWindow()->setCursor(UI_CURSOR_HAND); | ||
1100 | return TRUE; | ||
1101 | } | ||
1102 | |||
1103 | |||
1104 | BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) | ||
1105 | { | ||
1106 | BOOL handled = LLUICtrl::handleMouseDown( x, y , mask ); | ||
1107 | if( handled ) | ||
1108 | { | ||
1109 | showPicker(FALSE); | ||
1110 | |||
1111 | //grab textures first... | ||
1112 | gInventory.startBackgroundFetch(gInventory.findCategoryUUIDForType(LLAssetType::AT_TEXTURE)); | ||
1113 | //...then start full inventory fetch. | ||
1114 | gInventory.startBackgroundFetch(); | ||
1115 | } | ||
1116 | return handled; | ||
1117 | } | ||
1118 | |||
1119 | void LLTextureCtrl::onFloaterClose() | ||
1120 | { | ||
1121 | LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle); | ||
1122 | |||
1123 | if (floaterp) | ||
1124 | { | ||
1125 | floaterp->setOwner(NULL); | ||
1126 | mLastFloaterLeftTop.set( floaterp->getRect().mLeft, floaterp->getRect().mTop ); | ||
1127 | } | ||
1128 | |||
1129 | mFloaterHandle.markDead(); | ||
1130 | } | ||
1131 | |||
1132 | void LLTextureCtrl::onFloaterCommit(ETexturePickOp op) | ||
1133 | { | ||
1134 | LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle); | ||
1135 | |||
1136 | if( floaterp && mEnabled) | ||
1137 | { | ||
1138 | if( floaterp->isDirty() ) | ||
1139 | { | ||
1140 | setTentative( FALSE ); | ||
1141 | mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE); | ||
1142 | lldebugs << "mImageItemID: " << mImageItemID << llendl; | ||
1143 | mImageAssetID = floaterp->getAssetID(); | ||
1144 | lldebugs << "mImageAssetID: " << mImageAssetID << llendl; | ||
1145 | if (op == TEXTURE_SELECT && mOnSelectCallback) | ||
1146 | { | ||
1147 | mOnSelectCallback(this, mCallbackUserData); | ||
1148 | } | ||
1149 | else if (op == TEXTURE_CANCEL && mOnCancelCallback) | ||
1150 | { | ||
1151 | mOnCancelCallback(this, mCallbackUserData); | ||
1152 | } | ||
1153 | else | ||
1154 | { | ||
1155 | onCommit(); | ||
1156 | } | ||
1157 | } | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | void LLTextureCtrl::setImageAssetID( const LLUUID& asset_id ) | ||
1162 | { | ||
1163 | if( mImageAssetID != asset_id ) | ||
1164 | { | ||
1165 | mImageItemID.setNull(); | ||
1166 | mImageAssetID = asset_id; | ||
1167 | LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle); | ||
1168 | if( floaterp && getEnabled() ) | ||
1169 | { | ||
1170 | floaterp->setImageID( asset_id ); | ||
1171 | floaterp->setDirty( FALSE ); | ||
1172 | } | ||
1173 | } | ||
1174 | } | ||
1175 | |||
1176 | BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, | ||
1177 | BOOL drop, EDragAndDropType cargo_type, void *cargo_data, | ||
1178 | EAcceptance *accept, | ||
1179 | LLString& tooltip_msg) | ||
1180 | { | ||
1181 | BOOL handled = FALSE; | ||
1182 | |||
1183 | // this downcast may be invalid - but if the second test below | ||
1184 | // returns true, then the cast was valid, and we can perform | ||
1185 | // the third test without problems. | ||
1186 | LLInventoryItem* item = (LLInventoryItem*)cargo_data; | ||
1187 | if (mEnabled && (cargo_type == DAD_TEXTURE) && allowDrop(item)) | ||
1188 | { | ||
1189 | if (drop) | ||
1190 | { | ||
1191 | if(doDrop(item)) | ||
1192 | { | ||
1193 | // This removes the 'Multiple' overlay, since | ||
1194 | // there is now only one texture selected. | ||
1195 | setTentative( FALSE ); | ||
1196 | onCommit(); | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | *accept = ACCEPT_YES_SINGLE; | ||
1201 | } | ||
1202 | else | ||
1203 | { | ||
1204 | *accept = ACCEPT_NO; | ||
1205 | } | ||
1206 | |||
1207 | handled = TRUE; | ||
1208 | lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLTextureCtrl " << getName() << llendl; | ||
1209 | |||
1210 | return handled; | ||
1211 | } | ||
1212 | |||
1213 | void LLTextureCtrl::draw() | ||
1214 | { | ||
1215 | if( getVisible() ) | ||
1216 | { | ||
1217 | mBorder->setKeyboardFocusHighlight(hasFocus()); | ||
1218 | |||
1219 | if (mImageAssetID.isNull() || !mValid) | ||
1220 | { | ||
1221 | mTexturep = NULL; | ||
1222 | } | ||
1223 | else | ||
1224 | { | ||
1225 | mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); | ||
1226 | mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); | ||
1227 | } | ||
1228 | |||
1229 | // Border | ||
1230 | LLRect border( 0, mRect.getHeight(), mRect.getWidth(), BTN_HEIGHT_SMALL ); | ||
1231 | gl_rect_2d( border, mBorderColor, FALSE ); | ||
1232 | |||
1233 | // Interior | ||
1234 | LLRect interior = border; | ||
1235 | interior.stretch( -1 ); | ||
1236 | |||
1237 | if( mTexturep ) | ||
1238 | { | ||
1239 | if( mTexturep->getComponents() == 4 ) | ||
1240 | { | ||
1241 | gl_rect_2d_checkerboard( interior ); | ||
1242 | } | ||
1243 | |||
1244 | gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep); | ||
1245 | mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); | ||
1246 | } | ||
1247 | else | ||
1248 | { | ||
1249 | gl_rect_2d( interior, LLColor4::grey, TRUE ); | ||
1250 | |||
1251 | // Draw X | ||
1252 | gl_draw_x( interior, LLColor4::black ); | ||
1253 | } | ||
1254 | |||
1255 | mTentativeLabel->setVisible( !mTexturep.isNull() && mTentative ); | ||
1256 | |||
1257 | LLUICtrl::draw(); | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | BOOL LLTextureCtrl::allowDrop(LLInventoryItem* item) | ||
1262 | { | ||
1263 | BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); | ||
1264 | BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); | ||
1265 | BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, | ||
1266 | gAgent.getID()); | ||
1267 | |||
1268 | PermissionMask item_perm_mask = 0; | ||
1269 | if (copy) item_perm_mask |= PERM_COPY; | ||
1270 | if (mod) item_perm_mask |= PERM_MODIFY; | ||
1271 | if (xfer) item_perm_mask |= PERM_TRANSFER; | ||
1272 | |||
1273 | PermissionMask filter_perm_mask = mCanApplyImmediately ? | ||
1274 | mImmediateFilterPermMask : mNonImmediateFilterPermMask; | ||
1275 | if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask ) | ||
1276 | { | ||
1277 | if(mDragCallback) | ||
1278 | { | ||
1279 | return mDragCallback(this, item, mCallbackUserData); | ||
1280 | } | ||
1281 | else | ||
1282 | { | ||
1283 | return TRUE; | ||
1284 | } | ||
1285 | } | ||
1286 | else | ||
1287 | { | ||
1288 | return FALSE; | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | BOOL LLTextureCtrl::doDrop(LLInventoryItem* item) | ||
1293 | { | ||
1294 | // call the callback if it exists. | ||
1295 | if(mDropCallback) | ||
1296 | { | ||
1297 | // if it returns TRUE, we return TRUE, and therefore the | ||
1298 | // commit is called above. | ||
1299 | return mDropCallback(this, item, mCallbackUserData); | ||
1300 | } | ||
1301 | |||
1302 | // no callback installed, so just set the image ids and carry on. | ||
1303 | setImageAssetID( item->getAssetUUID() ); | ||
1304 | mImageItemID = item->getUUID(); | ||
1305 | return TRUE; | ||
1306 | } | ||
1307 | |||
1308 | BOOL LLTextureCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent) | ||
1309 | { | ||
1310 | if( getVisible() && mEnabled && !called_from_parent && ' ' == uni_char ) | ||
1311 | { | ||
1312 | showPicker(TRUE); | ||
1313 | return TRUE; | ||
1314 | } | ||
1315 | return LLUICtrl::handleUnicodeCharHere(uni_char, called_from_parent); | ||
1316 | } | ||
1317 | |||
1318 | void LLTextureCtrl::setValue( LLSD value ) | ||
1319 | { | ||
1320 | setImageAssetID(value.asUUID()); | ||
1321 | } | ||
1322 | |||
1323 | LLSD LLTextureCtrl::getValue() const | ||
1324 | { | ||
1325 | return LLSD(getImageAssetID()); | ||
1326 | } | ||
1327 | |||
1328 | |||
1329 | ///////////////////////////////////////////////////////////////////////////////// | ||
1330 | // LLToolTexEyedropper | ||
1331 | |||
1332 | class LLToolTexEyedropper : public LLTool | ||
1333 | { | ||
1334 | public: | ||
1335 | LLToolTexEyedropper( void (*callback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ), void* userdata ); | ||
1336 | virtual ~LLToolTexEyedropper(); | ||
1337 | virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); | ||
1338 | virtual BOOL handleHover(S32 x, S32 y, MASK mask); | ||
1339 | |||
1340 | protected: | ||
1341 | void (*mCallback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ); | ||
1342 | void* mCallbackUserData; | ||
1343 | }; | ||
1344 | |||
1345 | |||
1346 | LLToolTexEyedropper::LLToolTexEyedropper( | ||
1347 | void (*callback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ), | ||
1348 | void* userdata ) | ||
1349 | : LLTool("texeyedropper"), | ||
1350 | mCallback( callback ), | ||
1351 | mCallbackUserData( userdata ) | ||
1352 | { | ||
1353 | } | ||
1354 | |||
1355 | LLToolTexEyedropper::~LLToolTexEyedropper() | ||
1356 | { | ||
1357 | } | ||
1358 | |||
1359 | |||
1360 | BOOL LLToolTexEyedropper::handleMouseDown(S32 x, S32 y, MASK mask) | ||
1361 | { | ||
1362 | LLViewerObject* hit_obj = gViewerWindow->lastObjectHit(); | ||
1363 | if (hit_obj && | ||
1364 | !hit_obj->isAvatar()) | ||
1365 | { | ||
1366 | if( (0 <= gLastHitObjectFace) && (gLastHitObjectFace < hit_obj->getNumTEs()) ) | ||
1367 | { | ||
1368 | LLViewerImage* image = hit_obj->getTEImage( gLastHitObjectFace ); | ||
1369 | if( image ) | ||
1370 | { | ||
1371 | if( mCallback ) | ||
1372 | { | ||
1373 | mCallback( hit_obj->getID(), image->getID(), mCallbackUserData ); | ||
1374 | } | ||
1375 | } | ||
1376 | } | ||
1377 | } | ||
1378 | return TRUE; | ||
1379 | } | ||
1380 | |||
1381 | BOOL LLToolTexEyedropper::handleHover(S32 x, S32 y, MASK mask) | ||
1382 | { | ||
1383 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolTexEyedropper" << llendl; | ||
1384 | gViewerWindow->getWindow()->setCursor(UI_CURSOR_CROSS); // TODO: better cursor | ||
1385 | return TRUE; | ||
1386 | } | ||
1387 | |||