From a90d7bbb464e9a60005b80652e11f39505e3d6b5 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 16 Feb 2012 12:00:38 -0600 Subject: [PATCH 01/32] Innitial commit. Pulled minor changes out of bulk of changes comming for multi-wearables. --- indra/llcharacter/llgesture.cpp | 36 +- indra/llcharacter/llgesture.h | 36 +- indra/llcharacter/llmultigesture.cpp | 36 +- indra/llcharacter/llmultigesture.h | 4 + indra/llcharacter/llvisualparam.cpp | 36 +- indra/llcharacter/llvisualparam.h | 36 +- indra/llprimitive/llprimitive.cpp | 2 +- indra/llprimitive/llprimitive.h | 2 +- indra/llui/llmenugl.cpp | 74 +-- indra/llui/llmenugl.h | 2 + indra/llui/llview.h | 2 +- indra/newview/CMakeLists.txt | 4 +- indra/newview/ascentprefsvan.cpp | 6 +- indra/newview/floaterao.cpp | 2 +- indra/newview/floaterlocalassetbrowse.cpp | 6 +- indra/newview/llagent.cpp | 6 - indra/newview/llagentwearables.cpp | 6 +- indra/newview/llagentwearables.h | 2 +- indra/newview/llappviewer.cpp | 10 +- indra/newview/llappviewer.h | 5 + indra/newview/llassetuploadresponders.cpp | 449 +++++++++++------- indra/newview/llassetuploadresponders.h | 43 +- indra/newview/llavatarpropertiesprocessor.cpp | 9 - indra/newview/llcallbacklist.cpp | 6 + indra/newview/lldriverparam.cpp | 40 +- indra/newview/lldriverparam.h | 38 +- indra/newview/llfloateravatarlist.cpp | 85 +--- indra/newview/llfloateravatarlist.h | 8 +- indra/newview/llfloatercustomize.cpp | 46 +- indra/newview/llfloatercustomize.h | 10 +- indra/newview/llfloateropenobject.cpp | 11 +- indra/newview/llfloateropenobject.h | 4 +- indra/newview/llfloatertools.cpp | 4 +- indra/newview/llfolderviewitem.cpp | 15 +- indra/newview/llfolderviewitem.h | 13 +- indra/newview/llinventoryactions.cpp | 8 +- indra/newview/llinventorybridge.cpp | 58 +-- indra/newview/llinventoryclipboard.cpp | 36 +- indra/newview/llinventoryclipboard.h | 36 +- indra/newview/llinventorymodel.cpp | 42 +- indra/newview/llinventorymodel.h | 4 + indra/newview/llinventorypanel.cpp | 8 + indra/newview/llinventorypanel.h | 2 + indra/newview/llnetmap.cpp | 2 +- indra/newview/llpanelcontents.cpp | 2 +- indra/newview/llpanelcontents.h | 4 +- indra/newview/llpanelmaininventory.cpp | 2 +- indra/newview/llpanelobject.cpp | 2 +- indra/newview/llpanelobject.h | 2 +- ...ventory.cpp => llpanelobjectinventory.cpp} | 442 ++++++----------- ...elinventory.h => llpanelobjectinventory.h} | 117 ++--- indra/newview/llpanelvolume.cpp | 2 +- indra/newview/llpanelvolume.h | 2 +- indra/newview/llpolymesh.cpp | 54 +-- indra/newview/llpolymesh.h | 37 +- indra/newview/llpolymorph.cpp | 37 +- indra/newview/llpolymorph.h | 1 + indra/newview/llpreview.cpp | 3 +- indra/newview/llpreviewgesture.cpp | 24 +- indra/newview/llpreviewgesture.h | 1 + indra/newview/llpreviewscript.cpp | 2 +- indra/newview/llstartup.cpp | 8 +- indra/newview/lltexlayerparams.cpp | 37 +- indra/newview/llviewerdisplay.cpp | 2 + indra/newview/llviewergesture.cpp | 1 + indra/newview/llviewerjoint.cpp | 36 +- indra/newview/llviewerjoint.h | 36 +- indra/newview/llviewerjointattachment.cpp | 40 +- indra/newview/llviewerjointmesh.h | 36 +- indra/newview/llviewermenu.cpp | 19 +- indra/newview/llviewermessage.cpp | 93 ++-- indra/newview/llviewermessage.h | 10 +- indra/newview/llviewertexteditor.cpp | 3 +- indra/newview/llviewervisualparam.cpp | 12 +- indra/newview/llviewervisualparam.h | 38 +- indra/newview/rlvhandler.cpp | 39 +- indra/newview/rlvhandler.h | 2 + indra/newview/rlvhelper.cpp | 6 +- indra/newview/rlvlocks.cpp | 12 +- 79 files changed, 1162 insertions(+), 1292 deletions(-) rename indra/newview/{llpanelinventory.cpp => llpanelobjectinventory.cpp} (85%) rename indra/newview/{llpanelinventory.h => llpanelobjectinventory.h} (50%) diff --git a/indra/llcharacter/llgesture.cpp b/indra/llcharacter/llgesture.cpp index 83e4e35b0..c23694639 100644 --- a/indra/llcharacter/llgesture.cpp +++ b/indra/llcharacter/llgesture.cpp @@ -1,31 +1,25 @@ /** * @file llgesture.cpp * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcharacter/llgesture.h b/indra/llcharacter/llgesture.h index d394ab763..66b618c47 100644 --- a/indra/llcharacter/llgesture.h +++ b/indra/llcharacter/llgesture.h @@ -3,31 +3,25 @@ * @brief A gesture is a combination of a triggering chat phrase or * key, a sound, an animation, and a chat string. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcharacter/llmultigesture.cpp b/indra/llcharacter/llmultigesture.cpp index 7fe21dbc9..b43554409 100644 --- a/indra/llcharacter/llmultigesture.cpp +++ b/indra/llcharacter/llmultigesture.cpp @@ -2,31 +2,25 @@ * @file llmultigesture.cpp * @brief Gestures that are asset-based and can have multiple steps. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcharacter/llmultigesture.h b/indra/llcharacter/llmultigesture.h index eb15f600c..0d1c652f9 100644 --- a/indra/llcharacter/llmultigesture.h +++ b/indra/llcharacter/llmultigesture.h @@ -70,6 +70,10 @@ public: KEY mKey; MASK mMask; + // This name can be empty if the inventory item is not around and + // the gesture manager has not yet set the name + std::string mName; + // String, like "/foo" or "hello" that makes it play std::string mTrigger; diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp index 122406e20..809b312ab 100644 --- a/indra/llcharacter/llvisualparam.cpp +++ b/indra/llcharacter/llvisualparam.cpp @@ -2,31 +2,25 @@ * @file llvisualparam.cpp * @brief Implementation of LLPolyMesh class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index 63b9d6893..a70efa9dd 100644 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -2,31 +2,25 @@ * @file llvisualparam.h * @brief Implementation of LLPolyMesh class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 298308ae8..f6ecbc953 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -223,7 +223,7 @@ void LLPrimitive::setPCode(const U8 p_code) } //=============================================================== -const LLTextureEntry* LLPrimitive::getTE(const U8 index) const +LLTextureEntry* LLPrimitive::getTE(const U8 index) const { return mTextureList.getTexture(index); } diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 126d96f91..7fe47fb01 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -334,7 +334,7 @@ public: // Modify texture entry properties inline BOOL validTE(const U8 te_num) const; - const LLTextureEntry *getTE(const U8 te_num) const; + LLTextureEntry *getTE(const U8 te_num) const; virtual void setNumTEs(const U8 num_tes); virtual void setAllTETextures(const LLUUID &tex_id); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 9b60fbaaa..cd0c2f0c0 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -661,7 +661,7 @@ void LLMenuItemTearOffGL::doIt() getMenu()->highlightNextItem(this); } - getMenu()->arrange(); + getMenu()->needsArrange(); LLFloater* parent_floater = mParentHandle.get(); LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu()); @@ -1325,55 +1325,58 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask ) void LLMenuItemBranchGL::openMenu() { - if(!getBranch()) return; + LLMenuGL* branch = getBranch(); + if (!branch) + return; - if (getBranch()->getTornOff()) + if (branch->getTornOff()) { - gFloaterView->bringToFront((LLFloater*)getBranch()->getParent()); + gFloaterView->bringToFront((LLFloater*)branch->getParent()); // this might not be necessary, as torn off branches don't get focus and hence no highligth - getBranch()->highlightNextItem(NULL); + branch->highlightNextItem(NULL); } - else if( !getBranch()->getVisible() ) + else if( !branch->getVisible() ) { // get valid rectangle for menus const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); - getBranch()->arrange(); + branch->arrange(); - LLRect rect = getBranch()->getRect(); + LLRect branch_rect = branch->getRect(); // calculate root-view relative position for branch menu S32 left = getRect().mRight; S32 top = getRect().mTop - getRect().mBottom; - localPointToOtherView(left, top, &left, &top, getBranch()->getParent()); + localPointToOtherView(left, top, &left, &top, branch->getParent()); - rect.setLeftTopAndSize( left, top, - rect.getWidth(), rect.getHeight() ); + branch_rect.setLeftTopAndSize( left, top, + branch_rect.getWidth(), branch_rect.getHeight() ); - if (getBranch()->getCanTearOff()) + if (branch->getCanTearOff()) { - rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS); + branch_rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS); } - getBranch()->setRect( rect ); + branch->setRect( branch_rect ); S32 x = 0; S32 y = 0; - getBranch()->localPointToOtherView( 0, 0, &x, &y, getBranch()->getParent() ); S32 delta_x = 0; S32 delta_y = 0; + branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() ); if( y < menu_region_rect.mBottom ) { delta_y = menu_region_rect.mBottom - y; } S32 menu_region_width = menu_region_rect.getWidth(); - if( x - menu_region_rect.mLeft > menu_region_width - rect.getWidth() ) + if( x - menu_region_rect.mLeft > menu_region_width - branch_rect.getWidth() ) { // move sub-menu over to left side - delta_x = llmax(-x, (-1 * (rect.getWidth() + getRect().getWidth()))); + delta_x = llmax(-x, ( -(branch_rect.getWidth() + getRect().getWidth()))); } - getBranch()->translate( delta_x, delta_y ); - getBranch()->setVisible( TRUE ); - getBranch()->getParent()->sendChildToFront(getBranch()); + branch->translate( delta_x, delta_y ); + + branch->setVisible( TRUE ); + branch->getParent()->sendChildToFront(branch); } } @@ -1705,7 +1708,8 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle< mSpilloverBranch(NULL), mSpilloverMenu(NULL), mParentFloaterHandle(parent_floater_handle), - mJumpKey(KEY_NONE) + mJumpKey(KEY_NONE), + mNeedsArrange(FALSE) { mFadeTimer.stop(); setCanTearOff(TRUE, parent_floater_handle); @@ -1753,7 +1757,7 @@ void LLMenuGL::setCanTearOff(BOOL tear_off, LLHandle parent_floater_h mTearOffItem = new LLMenuItemTearOffGL(parent_floater_handle); mItems.insert(mItems.begin(), mTearOffItem); addChildAtEnd(mTearOffItem); - arrange(); + needsArrange(); } else if (!tear_off && mTearOffItem != NULL) { @@ -1761,7 +1765,7 @@ void LLMenuGL::setCanTearOff(BOOL tear_off, LLHandle parent_floater_h removeChild(mTearOffItem); delete mTearOffItem; mTearOffItem = NULL; - arrange(); + needsArrange(); } } @@ -2502,7 +2506,7 @@ void LLMenuGL::empty( void ) void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom) { setRect(LLRect(left, getRect().mTop, getRect().mRight, bottom)); - arrange(); + needsArrange(); } BOOL LLMenuGL::handleJumpKey(KEY key) @@ -2539,7 +2543,7 @@ BOOL LLMenuGL::append( LLMenuItemGL* item ) mItems.push_back( item ); addChild( item ); - arrange(); + needsArrange(); return TRUE; } @@ -2610,7 +2614,7 @@ BOOL LLMenuGL::remove( LLMenuItemGL* item ) // Note that getMenu() will still not work since its parent isn't a menu. sMenuContainer->addChild( item ); - arrange(); + needsArrange(); return TRUE; } @@ -2648,6 +2652,7 @@ void LLMenuGL::setItemVisible( const std::string& name, BOOL visible ) if( (*item_iter)->getName() == name ) { (*item_iter)->setVisible( visible ); + needsArrange(); break; } } @@ -2978,17 +2983,20 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask ) void LLMenuGL::draw( void ) { + if (mNeedsArrange) + { + arrange(); + mNeedsArrange = FALSE; + } if (mDropShadowed && !mTornOff) { - static LLColor4 color_drop_shadow = LLUI::sColorsGroup->getColor("ColorDropShadow"); static S32 drop_shadow_floater = LLUI::sConfigGroup->getS32("DropShadowFloater"); + static LLColor4 color_drop_shadow = LLUI::sColorsGroup->getColor("ColorDropShadow"); + gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, - color_drop_shadow, - drop_shadow_floater ); + color_drop_shadow, drop_shadow_floater ); } - LLColor4 bg_color = mBackgroundColor; - if( mBgVisible ) { gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor ); @@ -4464,7 +4472,7 @@ LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : // flag menu as being torn off menup->setTornOff(TRUE); // update menu layout as torn off menu (no spillover menus) - menup->arrange(); + menup->needsArrange(); LLRect rect; menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView); @@ -4491,7 +4499,7 @@ LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : void LLTearOffMenu::draw() { mMenu->setBackgroundVisible(isBackgroundOpaque()); - mMenu->arrange(); + mMenu->needsArrange(); if (getRect().getHeight() != mTargetHeight) { diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 2150d5584..9f843a3e9 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -477,6 +477,7 @@ public: virtual BOOL isOpen(); + void needsArrange() { mNeedsArrange = TRUE; } // Shape this menu to fit the current state of the children, and // adjust the child rects to fit. This is called automatically // when you add items. *FIX: We may need to deal with visibility @@ -541,6 +542,7 @@ protected: S32 mMouseVelY; BOOL mHorizontalLayout; BOOL mKeepFixedSize; + BOOL mNeedsArrange; private: static LLColor4 sDefaultBackgroundColor; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index d69360515..524dba010 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -84,7 +84,7 @@ virtual void removeCtrl( LLUICtrl* ctrl); virtual BOOL canFocusChildren() const { return TRUE; } LLFolderView virtual void deleteAllChildren(); - LLFolderView, LLPanelInventory + LLFolderView, LLPanelObjectInventory virtual void setTentative(BOOL b) {} LLUICtrl, LLSliderCtrl, LLSpinCtrl virtual BOOL getTentative() const { return FALSE; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7ad78bc0f..8fcbe7054 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -356,7 +356,7 @@ set(viewer_SOURCE_FILES llpanelgrouproles.cpp llpanelgroupvoting.cpp llpanelinput.cpp - llpanelinventory.cpp + llpanelobjectinventory.cpp llpanelland.cpp llpanellandaudio.cpp llpanellandmedia.cpp @@ -842,7 +842,7 @@ set(viewer_HEADER_FILES llpanelgrouproles.h llpanelgroupvoting.h llpanelinput.h - llpanelinventory.h + llpanelobjectinventory.h llpanelland.h llpanellandaudio.h llpanellandmedia.h diff --git a/indra/newview/ascentprefsvan.cpp b/indra/newview/ascentprefsvan.cpp index 4b73e2e1f..245a33af2 100644 --- a/indra/newview/ascentprefsvan.cpp +++ b/indra/newview/ascentprefsvan.cpp @@ -98,13 +98,11 @@ void LLPrefsAscentVan::onCommitClientTag(LLUICtrl* ctrl, void* userdata) gSavedSettings.setString("AscentReportClientUUID", client_uuid); gSavedSettings.setU32("AscentReportClientIndex", client_index); - LLVOAvatar* avatar = gAgentAvatarp; - - if (avatar) + if (gAgentAvatarp) { // Slam pending upload count to "unstick" things bool slam_for_debug = true; - avatar->forceBakeAllTextures(slam_for_debug); + gAgentAvatarp->forceBakeAllTextures(slam_for_debug); } } } diff --git a/indra/newview/floaterao.cpp b/indra/newview/floaterao.cpp index cff0dbe23..afc0fcb75 100644 --- a/indra/newview/floaterao.cpp +++ b/indra/newview/floaterao.cpp @@ -30,7 +30,7 @@ #include "roles_constants.h" #include "llviewerregion.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llinventorybridge.h" #include "llboost.h" diff --git a/indra/newview/floaterlocalassetbrowse.cpp b/indra/newview/floaterlocalassetbrowse.cpp index 5c67eea15..eeb1ebfd4 100644 --- a/indra/newview/floaterlocalassetbrowse.cpp +++ b/indra/newview/floaterlocalassetbrowse.cpp @@ -670,8 +670,10 @@ void LocalAssetBrowser::PerformTimedActions(void) // one of the layer bitmaps has been updated, we need to rebake. if ( mLayerUpdated ) { - LLVOAvatar* avatar = gAgentAvatarp; - if (avatar) { avatar->forceBakeAllTextures(SLAM_FOR_DEBUG); } + if (isAgentAvatarValid()) + { + gAgentAvatarp->forceBakeAllTextures(SLAM_FOR_DEBUG); + } mLayerUpdated = false; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 103a5e594..8471710f0 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3695,12 +3695,6 @@ void LLAgent::setTeleportState(ETeleportState state) default: break; } -// [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Version: 1.23.4 | Checked: 2009-07-07 (RLVa-1.0.0d) | Added: RLVa-0.2.0b - if ( (rlv_handler_t::isEnabled()) && (TELEPORT_NONE == mTeleportState) ) - { - gRlvHandler.setCanCancelTp(true); - } -// [/RLVa:KB] } void LLAgent::stopCurrentAnimations() diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index a583d771a..a8afd7f71 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1903,15 +1903,15 @@ void LLAgentWearables::userRemoveAllClothes() // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty. if (gAgentCamera.cameraCustomizeAvatar()) { - gFloaterCustomize->askToSaveIfDirty( LLAgentWearables::userRemoveAllClothesStep2, NULL ); + gFloaterCustomize->askToSaveIfDirty( boost::bind(LLAgentWearables::userRemoveAllClothesStep2,_1) ); } else { - userRemoveAllClothesStep2( TRUE, NULL ); + userRemoveAllClothesStep2( TRUE ); } } -void LLAgentWearables::userRemoveAllClothesStep2( BOOL proceed, void* userdata ) +void LLAgentWearables::userRemoveAllClothesStep2( BOOL proceed ) { if( proceed ) { diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 630d57525..6e753d441 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -185,7 +185,7 @@ private: void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); - static void userRemoveAllClothesStep2(BOOL proceed, void* userdata ); // userdata is NULL + static void userRemoveAllClothesStep2(BOOL proceed); // userdata is NULL //-------------------------------------------------------------------- // Server Communication diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b42ead885..e8281457f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4639,13 +4639,9 @@ void LLAppViewer::handleLoginComplete() { gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); } - writeDebugInfo(); -// [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b - if (rlv_handler_t::isEnabled()) - { - gRlvHandler.onLoginComplete(); - } -// [/RLVa:KB] + mOnLoginCompleted(); + + writeDebugInfo(); } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index f268324d7..1b0e5614f 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -160,6 +160,11 @@ public: void handleLoginComplete(); LLAllocator & getAllocator() { return mAlloc; } + // On LoginCompleted callback + typedef boost::signals2::signal login_completed_signal_t; + login_completed_signal_t mOnLoginCompleted; + boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb ) { return mOnLoginCompleted.connect(cb); } + void addOnIdleCallback(const boost::function& cb); // add a callback to fire (once) when idle void purgeCache(); // Clear the local cache. diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 757252286..a9ff6e3f7 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -34,19 +34,12 @@ #include "llassetuploadresponders.h" -// library includes -#include "lleconomy.h" -#include "llfocusmgr.h" -#include "llnotifications.h" -#include "llscrolllistctrl.h" -#include "llsdserialize.h" - // viewer includes #include "llagent.h" #include "llcompilequeue.h" #include "llfloaterbuycurrency.h" -#include "llnotify.h" -#include "llinventorymodel.h" +#include "llinventorydefines.h" +#include "llinventoryobserver.h" #include "llinventorypanel.h" #include "llpanelmaininventory.h" #include "llpermissionsflags.h" @@ -63,6 +56,18 @@ #include "llviewermenufile.h" #include "llviewerwindow.h" #include "lltexlayer.h" +#include "lltrans.h" + +// library includes +#include "lldir.h" +#include "lleconomy.h" +#include "llfocusmgr.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "llsdserialize.h" +#include "llsdutil.h" +#include "llvfs.h" + #include "statemachine/aifilepicker.h" // When uploading multiple files, don't display any of them when uploading more than this number. @@ -70,14 +75,15 @@ static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; void dialog_refresh_all(); -void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - const std::string inventory_type_string, - const LLUUID& item_folder_id, - const std::string& item_name, - const std::string& item_description, - const LLSD& server_response, - S32 upload_price) +void on_new_single_inventory_upload_complete( + LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + const std::string inventory_type_string, + const LLUUID& item_folder_id, + const std::string& item_name, + const std::string& item_description, + const LLSD& server_response, + S32 upload_price) { if (upload_price > 0) { @@ -87,7 +93,7 @@ void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, LLSD args; args["AMOUNT"] = llformat("%d", upload_price); - LLNotifications::instance().add("UploadPayment", args); + LLNotificationsUtil::add("UploadPayment", args); } if (item_folder_id.notNull()) @@ -115,9 +121,18 @@ void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, } LLPermissions new_perms; - new_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); - new_perms.initMasks(PERM_ALL, PERM_ALL, everyone_perms, group_perms, - next_owner_perms); + new_perms.init( + gAgent.getID(), + gAgent.getID(), + LLUUID::null, + LLUUID::null); + + new_perms.initMasks( + PERM_ALL, + PERM_ALL, + everyone_perms, + group_perms, + next_owner_perms); U32 inventory_item_flags = 0; if (server_response.has("inventory_flags")) @@ -147,17 +162,18 @@ void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, // Show the preview panel for textures and sounds to let // user know that the image (or snapshot) arrived intact. - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if (view) + LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); + if ( panel ) { LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); - view->getPanel()->setSelection(server_response["new_inventory_item"].asUUID(), - TAKE_FOCUS_NO); + panel->setSelection( + server_response["new_inventory_item"].asUUID(), + TAKE_FOCUS_NO); if ((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) /* FIXME: && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD */) { - view->getPanel()->openSelected(); + panel->openSelected(); } // restore keyboard focus @@ -190,7 +206,8 @@ LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, } } -LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, +LLAssetUploadResponder::LLAssetUploadResponder( + const LLSD &post_data, const std::string& file_name, LLAssetType::EType asset_type) : LLHTTPClient::Responder(), @@ -221,14 +238,14 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); args["REASON"] = "Error in upload request. Please visit " "http://secondlife.com/support for help fixing this problem."; - LLNotifications::instance().add("CannotUploadReason", args); + LLNotificationsUtil::add("CannotUploadReason", args); break; case 500: default: args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); args["REASON"] = "The server is experiencing unexpected " "difficulties."; - LLNotifications::instance().add("CannotUploadReason", args); + LLNotificationsUtil::add("CannotUploadReason", args); break; } LLUploadDialog::modalUploadFinished(); @@ -291,7 +308,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content) LLSD args; args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); args["REASON"] = content["message"].asString(); - LLNotifications::instance().add("CannotUploadReason", args); + LLNotificationsUtil::add("CannotUploadReason", args); } } @@ -299,17 +316,19 @@ void LLAssetUploadResponder::uploadComplete(const LLSD& content) { } -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, vfile_id, asset_type) +LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) { } -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type) +LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, file_name, asset_type) { } @@ -347,17 +366,21 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) asset_type == LLAssetType::AT_ANIMATION || asset_type == LLAssetType::AT_MESH) { - expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + expected_upload_cost = + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); } llinfos << "Adding " << content["new_inventory_item"].asUUID() << " " << content["new_asset"].asUUID() << " to inventory." << llendl; - on_new_single_inventory_upload_complete(asset_type, inventory_type, - mPostData["asset_type"].asString(), - mPostData["folder_id"].asUUID(), - mPostData["name"], - mPostData["description"], - content, expected_upload_cost); + on_new_single_inventory_upload_complete( + asset_type, + inventory_type, + mPostData["asset_type"].asString(), + mPostData["folder_id"].asUUID(), + mPostData["name"], + mPostData["description"], + content, + expected_upload_cost); // continue uploading for bulk uploads @@ -378,42 +401,54 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // and use them for each next file to be uploaded. Note the requested // perms are not the same as the granted ones found in the given // "content" structure but can still be found in mPostData. -MG - U32 everyone_perms = mPostData.has("everyone_mask") ? - mPostData.get("everyone_mask").asInteger() : - PERM_NONE; + U32 everyone_perms = + mPostData.has("everyone_mask") ? + mPostData.get("everyone_mask").asInteger() : + PERM_NONE; - U32 group_perms = mPostData.has("group_mask") ? - mPostData.get("group_mask").asInteger() : - PERM_NONE; + U32 group_perms = + mPostData.has("group_mask") ? + mPostData.get("group_mask").asInteger() : + PERM_NONE; - U32 next_owner_perms = mPostData.has("next_owner_mask") ? - mPostData.get("next_owner_mask").asInteger() : - PERM_NONE; + U32 next_owner_perms = + mPostData.has("next_owner_mask") ? + mPostData.get("next_owner_mask").asInteger() : + PERM_NONE; std::string display_name = LLStringUtil::null; LLAssetStorage::LLStoreAssetCallback callback = NULL; void *userdata = NULL; - upload_new_resource(next_file, asset_name, asset_name, 0, - LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - next_owner_perms, group_perms, everyone_perms, - display_name, callback, expected_upload_cost, - userdata); + + upload_new_resource( + next_file, + asset_name, + asset_name, + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + next_owner_perms, + group_perms, + everyone_perms, + display_name, + callback, + expected_upload_cost, + userdata); } } LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type, - LLBakedUploadData * baked_upload_data) -: LLAssetUploadResponder(post_data, vfile_id, asset_type), + LLBakedUploadData * baked_upload_data) : + LLAssetUploadResponder(post_data, vfile_id, asset_type), mBakedUploadData(baked_upload_data) { } LLSendTexLayerResponder::~LLSendTexLayerResponder() { - // mBakedUploadData is normally deleted by calls to - // LLTexLayerSetBuffer::onTextureUploadComplete() below + // mBakedUploadData is normally deleted by calls to LLTexLayerSetBuffer::onTextureUploadComplete() below if (mBakedUploadData) { // ...but delete it in the case where uploadComplete() is never called delete mBakedUploadData; @@ -430,19 +465,16 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content) std::string result = content["state"]; LLUUID new_id = content["new_asset"]; - llinfos << "LLSendTexLayerResponder::result from capabilities: " << result << llendl; - if (result == "complete" && mBakedUploadData != NULL) + llinfos << "result: " << result << " new_id: " << new_id << llendl; + if (result == "complete" + && mBakedUploadData != NULL) { // Invoke - LLTexLayerSetBuffer::onTextureUploadComplete(new_id, - (void*)mBakedUploadData, - 0, LL_EXSTAT_NONE); + LLTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE); mBakedUploadData = NULL; // deleted in onTextureUploadComplete() } else { // Invoke the original callback with an error result - LLTexLayerSetBuffer::onTextureUploadComplete(new_id, - (void*)mBakedUploadData, - -1, LL_EXSTAT_NONE); + LLTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); mBakedUploadData = NULL; // deleted in onTextureUploadComplete() } } @@ -452,23 +484,23 @@ void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason) llinfos << "status: " << statusNum << " reason: " << reason << llendl; // Invoke the original callback with an error result - LLTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), - (void*)mBakedUploadData, - -1, LL_EXSTAT_NONE); + LLTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); mBakedUploadData = NULL; // deleted in onTextureUploadComplete() } -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, vfile_id, asset_type) +LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) { } -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type) +LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, file_name, asset_type) { } @@ -501,8 +533,7 @@ void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) case LLInventoryType::IT_NOTECARD: { // Update the UI with the new asset. - LLPreviewNotecard* nc; - nc = (LLPreviewNotecard*)LLPreview::find(new_item->getUUID()); + LLPreviewNotecard* nc = (LLPreviewNotecard*)LLPreview::find(new_item->getUUID()); if (nc) { // *HACK: we have to delete the asset in the VFS so @@ -511,10 +542,9 @@ void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) // the uploader, so this can be optimized away in some // cases. A better design is to have a new uuid if the // script actually changed the asset. - if (nc->hasEmbeddedInventory()) + if(nc->hasEmbeddedInventory()) { - gVFS->removeFile(content["new_asset"].asUUID(), - LLAssetType::AT_NOTECARD); + gVFS->removeFile(content["new_asset"].asUUID(), LLAssetType::AT_NOTECARD); } nc->refreshFromInventory(); } @@ -538,15 +568,16 @@ void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) } break; } + case LLInventoryType::IT_GESTURE: { // If this gesture is active, then we need to update the in-memory - // active map with the new pointer. - if (LLGestureMgr::getInstance()->isGestureActive(item_id)) - { - LLUUID asset_id = new_item->getAssetUUID(); - LLGestureMgr::getInstance()->replaceGesture(item_id, asset_id); - gInventory.notifyObservers(); + // active map with the new pointer. + if (LLGestureMgr::instance().isGestureActive(item_id)) + { + LLUUID asset_id = new_item->getAssetUUID(); + LLGestureMgr::instance().replaceGesture(item_id, asset_id); + gInventory.notifyObservers(); } //gesture will have a new asset_id @@ -639,9 +670,7 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) // Bytecode save completed if (content["compiled"]) { - preview->callbackLSLCompileSucceeded(task_id, - item_id, - mPostData["is_script_running"]); + preview->callbackLSLCompileSucceeded(task_id, item_id, mPostData["is_script_running"]); } else { @@ -662,27 +691,30 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) class LLNewAgentInventoryVariablePriceResponder::Impl { public: - Impl(const LLUUID& vfile_id, - LLAssetType::EType asset_type, - const LLSD& inventory_data) - : mVFileID(vfile_id), + Impl( + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + const LLSD& inventory_data) : + mVFileID(vfile_id), mAssetType(asset_type), mInventoryData(inventory_data), mFileName("") { if (!gVFS->getExists(vfile_id, asset_type)) { - llwarns << "LLAssetUploadResponder called with nonexistant " - << "vfile_id " << vfile_id << llendl; + llwarns + << "LLAssetUploadResponder called with nonexistant " + << "vfile_id " << vfile_id << llendl; mVFileID.setNull(); mAssetType = LLAssetType::AT_NONE; } } - Impl(const std::string& file_name, - LLAssetType::EType asset_type, - const LLSD& inventory_data) - : mFileName(file_name), + Impl( + const std::string& file_name, + LLAssetType::EType asset_type, + const LLSD& inventory_data) : + mFileName(file_name), mAssetType(asset_type), mInventoryData(inventory_data) { @@ -741,7 +773,8 @@ public: args["FILE"] = getFilenameOrIDString(); args["REASON"] = reason; - LLNotifications::instance().add("CannotUploadReason", args); + + LLNotificationsUtil::add("CannotUploadReason", args); LLUploadDialog::modalUploadFinished(); } @@ -776,45 +809,55 @@ public: else if (_MISSING_REQUIRED_PARAMETER == error_identifier) { // Missing parameters - if (error.has(_MISSING_PARAMETER)) + if (error.has(_MISSING_PARAMETER) ) { - std::string message = "Upload request was missing required parameter '[P]'"; - LLStringUtil::replaceString(message, "[P]", - error[_MISSING_PARAMETER].asString()); + std::string message = + "Upload request was missing required parameter '[P]'"; + LLStringUtil::replaceString( + message, + "[P]", + error[_MISSING_PARAMETER].asString()); displayCannotUploadReason(message); } else { - std::string message = "Upload request was missing a required parameter"; + std::string message = + "Upload request was missing a required parameter"; displayCannotUploadReason(message); } } - else if (_INVALID_REQUEST_BODY == error_identifier) + else if ( _INVALID_REQUEST_BODY == error_identifier ) { // Invalid request body, check to see if // a particular parameter was invalid - if (error.has(_INVALID_PARAMETER)) + if ( error.has(_INVALID_PARAMETER) ) { std::string message = "Upload parameter '[P]' is invalid."; - LLStringUtil::replaceString(message, "[P]", - error[_INVALID_PARAMETER].asString()); + LLStringUtil::replaceString( + message, + "[P]", + error[_INVALID_PARAMETER].asString()); // See if the server also responds with what resource // is missing. - if (error.has(_MISSING_RESOURCE)) + if ( error.has(_MISSING_RESOURCE) ) { message += "\nMissing resource '[R]'."; - LLStringUtil::replaceString(message, "[R]", - error[_MISSING_RESOURCE].asString()); + LLStringUtil::replaceString( + message, + "[R]", + error[_MISSING_RESOURCE].asString()); } - else if (error.has(_INVALID_RESOURCE)) + else if ( error.has(_INVALID_RESOURCE) ) { message += "\nInvalid resource '[R]'."; - LLStringUtil::replaceString(message, "[R]", - error[_INVALID_RESOURCE].asString()); + LLStringUtil::replaceString( + message, + "[R]", + error[_INVALID_RESOURCE].asString()); } displayCannotUploadReason(message); @@ -837,7 +880,8 @@ public: void onTransportError() { - displayCannotUploadReason("The server is experiencing unexpected difficulties."); + displayCannotUploadReason( + "The server is experiencing unexpected difficulties."); } void onTransportError(const LLSD& error) @@ -852,47 +896,72 @@ public: // TODO*: Pull the user visible strings from an xml file // to be localized - if (_SERVER_ERROR_AFTER_CHARGE == error_identifier) + if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier ) { - displayCannotUploadReason("The server is experiencing unexpected difficulties. You may have been charged for the upload."); + displayCannotUploadReason( + "The server is experiencing unexpected difficulties. You may have been charged for the upload."); } else { - displayCannotUploadReason("The server is experiencing unexpected difficulties."); + displayCannotUploadReason( + "The server is experiencing unexpected difficulties."); } } - bool uploadConfirmationCallback(const LLSD& notification, - const LLSD& response, - boost::intrusive_ptr responder) + bool uploadConfirmationCallback( + const LLSD& notification, + const LLSD& response, + boost::intrusive_ptr responder) { - S32 option = LLNotification::getSelectedOption(notification, response); - std::string confirmation_url = notification["payload"]["confirmation_url"].asString(); + S32 option; + std::string confirmation_url; + + option = LLNotificationsUtil::getSelectedOption( + notification, + response); + + confirmation_url = + notification["payload"]["confirmation_url"].asString(); // Yay! We are confirming or cancelling our upload - if (option == 0) + switch(option) { - confirmUpload(confirmation_url, responder); + case 0: + { + confirmUpload(confirmation_url, responder); + } + break; + case 1: + default: + break; } return false; } - void confirmUpload(const std::string& confirmation_url, - boost::intrusive_ptr responder) + void confirmUpload( + const std::string& confirmation_url, + boost::intrusive_ptr responder) { - if (getFilename().empty()) + if ( getFilename().empty() ) { // we have no filename, use virtual file ID instead - LLHTTPClient::postFile(confirmation_url, getVFileID(), - getAssetType(), responder); + LLHTTPClient::postFile( + confirmation_url, + getVFileID(), + getAssetType(), + responder); } else { - LLHTTPClient::postFile(confirmation_url, getFilename(), responder); + LLHTTPClient::postFile( + confirmation_url, + getFilename(), + responder); } } + private: std::string mFileName; @@ -904,18 +973,26 @@ private: /////////////////////////////////////////////// // LLNewAgentInventoryVariablePriceResponder // /////////////////////////////////////////////// -LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(const LLUUID& vfile_id, - LLAssetType::EType asset_type, - const LLSD& inventory_info) +LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + const LLSD& inventory_info) { - mImpl = new Impl(vfile_id, asset_type, inventory_info); + mImpl = new Impl( + vfile_id, + asset_type, + inventory_info); } -LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(const std::string& file_name, - LLAssetType::EType asset_type, - const LLSD& inventory_info) +LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( + const std::string& file_name, + LLAssetType::EType asset_type, + const LLSD& inventory_info) { - mImpl = new Impl(file_name, asset_type, inventory_info); + mImpl = new Impl( + file_name, + asset_type, + inventory_info); } LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder() @@ -923,16 +1000,19 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp delete mImpl; } -void LLNewAgentInventoryVariablePriceResponder::errorWithContent(U32 statusNum, - const std::string& reason, - const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::errorWithContent( + U32 statusNum, + const std::string& reason, + const LLSD& content) { - LL_DEBUGS("Upload") << "LLNewAgentInventoryVariablePrice::error " - << statusNum << " reason: " << reason << LL_ENDL; + lldebugs + << "LLNewAgentInventoryVariablePrice::error " << statusNum + << " reason: " << reason << llendl; - if (content.has("error")) + if ( content.has("error") ) { static const std::string _ERROR = "error"; + mImpl->onTransportError(content[_ERROR]); } else @@ -972,27 +1052,32 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) { // rename the file in the VFS to the actual asset id // llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl; - gVFS->renameFile(mImpl->getVFileID(), asset_type, - content["new_asset"].asUUID(), asset_type); + gVFS->renameFile( + mImpl->getVFileID(), + asset_type, + content["new_asset"].asUUID(), + asset_type); } - on_new_single_inventory_upload_complete(asset_type, - mImpl->getInventoryType(), - mImpl->getInventoryTypeString(), - mImpl->getFolderID(), - mImpl->getItemName(), - mImpl->getItemDescription(), - content, - content[_UPLOAD_PRICE].asInteger()); + on_new_single_inventory_upload_complete( + asset_type, + mImpl->getInventoryType(), + mImpl->getInventoryTypeString(), + mImpl->getFolderID(), + mImpl->getItemName(), + mImpl->getItemDescription(), + content, + content[_UPLOAD_PRICE].asInteger()); // TODO* Add bulk (serial) uploading or add // a super class of this that does so } - else if (_CONFIRM_UPLOAD == state) + else if ( _CONFIRM_UPLOAD == state ) { - showConfirmationDialog(content[_UPLOAD_PRICE].asInteger(), - content[_RESOURCE_COST].asInteger(), - content[_RSVP].asString()); + showConfirmationDialog( + content[_UPLOAD_PRICE].asInteger(), + content[_RESOURCE_COST].asInteger(), + content[_RSVP].asString()); } else { @@ -1000,14 +1085,16 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) } } -void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError(const LLSD& error) +void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError( + const LLSD& error) { mImpl->onApplicationLevelError(error); } -void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(S32 upload_price, - S32 resource_cost, - const std::string& confirmation_url) +void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( + S32 upload_price, + S32 resource_cost, + const std::string& confirmation_url) { if (0 == upload_price) { @@ -1027,8 +1114,9 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(S32 uploa // when using plain ol' 'this', that this object // would be deleted before the callback is triggered // and cause sadness. - mImpl->confirmUpload(confirmation_url, - boost::intrusive_ptr(this)); + mImpl->confirmUpload( + confirmation_url, + boost::intrusive_ptr(this)); } else { @@ -1052,10 +1140,15 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(S32 uploa // when using plain ol' 'this', that this object // would be deleted before the callback is triggered // and cause sadness. - LLNotifications::instance().add("UploadCostConfirmation", - substitutions, payload, - boost::bind(&LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback, - mImpl, _1, _2, - boost::intrusive_ptr(this))); + LLNotificationsUtil::add( + "UploadCostConfirmation", + substitutions, + payload, + boost::bind( + &LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback, + mImpl, + _1, + _2, + boost::intrusive_ptr(this))); } } diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 2643bc52a..1b8da5748 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -73,12 +73,14 @@ protected: class LLNewAgentInventoryResponder : public LLAssetUploadResponder { public: - LLNewAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type); - LLNewAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type); + LLNewAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type); + LLNewAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type); virtual void error(U32 statusNum, const std::string& reason); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); @@ -92,23 +94,28 @@ class LLNewAgentInventoryVariablePriceResponder : public LLHTTPClient::Responder { public: - LLNewAgentInventoryVariablePriceResponder(const LLUUID& vfile_id, - LLAssetType::EType asset_type, - const LLSD& inventory_info); + LLNewAgentInventoryVariablePriceResponder( + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + const LLSD& inventory_info); - LLNewAgentInventoryVariablePriceResponder(const std::string& file_name, - LLAssetType::EType asset_type, - const LLSD& inventory_info); + LLNewAgentInventoryVariablePriceResponder( + const std::string& file_name, + LLAssetType::EType asset_type, + const LLSD& inventory_info); virtual ~LLNewAgentInventoryVariablePriceResponder(); - void errorWithContent(U32 statusNum, - const std::string& reason, - const LLSD& content); + void errorWithContent( + U32 statusNum, + const std::string& reason, + const LLSD& content); void result(const LLSD& content); - virtual void onApplicationLevelError(const LLSD& error); - virtual void showConfirmationDialog(S32 upload_price, - S32 resource_cost, + virtual void onApplicationLevelError( + const LLSD& error); + virtual void showConfirmationDialog( + S32 upload_price, + S32 resource_cost, const std::string& confirmation_url); private: diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 4d3ce23a4..aa7d391a1 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -131,9 +131,6 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avat void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id) { - std::string name; - gCacheName->getFullName(avatar_id, name); - llinfos << "Sending avatarpicksrequest for " << avatar_id << " ("<getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.agent_id); msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id); - std::string name; - gCacheName->getFullName(avatar_picks.target_id, name); - - llinfos << "Got reply for " << avatar_picks.target_id << ": (" << name << ")" << llendl; S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data); for (int block = 0; block < block_count; ++block) { @@ -411,14 +404,12 @@ void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_id, block); msg->getString(_PREHASH_Data, _PREHASH_PickName, pick_name, block); - llinfos << "\t" << pick_id << ": " << pick_name << llendl; avatar_picks.picks_list.push_back(std::make_pair(pick_id,pick_name)); } LLAvatarPropertiesProcessor* self = getInstance(); // Request processed, no longer pending self->removePendingRequest(avatar_picks.target_id, APT_PICKS); self->notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS); - //LLPanelAvatar } void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**) diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp index d59394083..1bfd2cb9b 100644 --- a/indra/newview/llcallbacklist.cpp +++ b/indra/newview/llcallbacklist.cpp @@ -180,6 +180,12 @@ private: bool_func_t mCallable; }; +void doOnIdleRepeating(bool_func_t callable) +{ + OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); +} + #ifdef _DEBUG void test1(void *data) diff --git a/indra/newview/lldriverparam.cpp b/indra/newview/lldriverparam.cpp index fb220d24a..eaca5d3a5 100644 --- a/indra/newview/lldriverparam.cpp +++ b/indra/newview/lldriverparam.cpp @@ -2,31 +2,25 @@ * @file lldriverparam.cpp * @brief A visual parameter that drives (controls) other visual parameters. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,6 +30,10 @@ #include "llfasttimer.h" #include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llagent.h" +#include "llwearable.h" +#include "llagentwearables.h" //----------------------------------------------------------------------------- // LLDriverParamInfo diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h index f881e445e..ba627925e 100644 --- a/indra/newview/lldriverparam.h +++ b/indra/newview/lldriverparam.h @@ -2,31 +2,25 @@ * @file lldriverparam.h * @brief A visual parameter that drives (controls) other visual parameters. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,9 +28,11 @@ #define LL_LLDRIVERPARAM_H #include "llviewervisualparam.h" +#include "llwearabletype.h" class LLPhysicsMotion; class LLVOAvatar; +class LLWearable; //----------------------------------------------------------------------------- diff --git a/indra/newview/llfloateravatarlist.cpp b/indra/newview/llfloateravatarlist.cpp index 398b4a846..7b6d1225f 100644 --- a/indra/newview/llfloateravatarlist.cpp +++ b/indra/newview/llfloateravatarlist.cpp @@ -215,54 +215,31 @@ BOOL LLAvatarListEntry::isDead() return getEntryAgeSeconds() > DEAD_KEEP_TIME; } -LLFloaterAvatarList* LLFloaterAvatarList::sInstance = NULL; - LLFloaterAvatarList::LLFloaterAvatarList() : LLFloater(std::string("radar")) { - llassert_always(sInstance == NULL); - sInstance = this; + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_radar.xml"); mUpdateRate = gSavedSettings.getU32("RadarUpdateRate") * 3 + 3; } LLFloaterAvatarList::~LLFloaterAvatarList() { gIdleCallbacks.deleteFunction(LLFloaterAvatarList::callbackIdle); - sInstance = NULL; -} -//static -void LLFloaterAvatarList::createInstance(bool visible) -{ - sInstance = new LLFloaterAvatarList(); - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_radar.xml"); - if(!visible) - { - sInstance->setVisible(FALSE); - gSavedSettings.setBOOL("ShowRadar", FALSE); - } } //static void LLFloaterAvatarList::toggle(void*) { - if (sInstance) - { - if (sInstance->getVisible() // [RLVa:KB] - || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) -// [/RLVa:KB] - ) - - { - sInstance->close(false); - } - else - { - sInstance->open(); - } + if(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + if(instanceExists()) + getInstance()->close(); } else - { +// [/RLVa:KB] + if(!instanceExists() || !getInstance()->getVisible()) showInstance(); - } + else + getInstance()->close(); } //static @@ -272,17 +249,7 @@ void LLFloaterAvatarList::showInstance() if(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) return; // [/RLVa:KB] - if (sInstance) - { - if (!sInstance->getVisible()) - { - sInstance->open(); - } - } - else - { - createInstance(true); - } + getInstance()->open(); } void LLFloaterAvatarList::draw() @@ -293,12 +260,11 @@ void LLFloaterAvatarList::draw() void LLFloaterAvatarList::onOpen() { gSavedSettings.setBOOL("ShowRadar", TRUE); - sInstance->setVisible(TRUE); } void LLFloaterAvatarList::onClose(bool app_quitting) { - sInstance->setVisible(FALSE); + setVisible(FALSE); if (!app_quitting) { gSavedSettings.setBOOL("ShowRadar", FALSE); @@ -361,8 +327,6 @@ BOOL LLFloaterAvatarList::postBuild() void LLFloaterAvatarList::updateAvatarList() { - if (sInstance != this) return; - //llinfos << "radar refresh: updating map" << llendl; // Check whether updates are enabled @@ -602,7 +566,7 @@ void LLFloaterAvatarList::expireAvatarList() void LLFloaterAvatarList::refreshAvatarList() { // Don't update list when interface is hidden - if (!sInstance->getVisible()) return; + if (!getVisible()) return; // We rebuild the list fully each time it's refreshed // The assumption is that it's faster to refill it and sort than @@ -1441,15 +1405,13 @@ void LLFloaterAvatarList::callbackFreeze(const LLSD& notification, const LLSD& r { S32 option = LLNotification::getSelectedOption(notification, response); - LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance; - if (option == 0) { - self->doCommand(cmd_freeze); + getInstance()->doCommand( cmd_freeze ); } else if (option == 1) { - self->doCommand(cmd_unfreeze); + getInstance()->doCommand( cmd_unfreeze ); } } @@ -1458,15 +1420,13 @@ void LLFloaterAvatarList::callbackEject(const LLSD& notification, const LLSD& re { S32 option = LLNotification::getSelectedOption(notification, response); - LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance; - if (option == 0) { - self->doCommand(cmd_eject); + getInstance()->doCommand( cmd_eject ); } else if (option == 1) { - self->doCommand(cmd_ban); + getInstance()->doCommand( cmd_ban ); } } @@ -1475,22 +1435,21 @@ void LLFloaterAvatarList::callbackEjectFromEstate(const LLSD& notification, cons { S32 option = LLNotification::getSelectedOption(notification, response); - LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance; - if (option == 0) { - self->doCommand(cmd_estate_eject); + getInstance()->doCommand( cmd_estate_eject ); } } //static -void LLFloaterAvatarList::callbackIdle(void *userdata) { - if (LLFloaterAvatarList::sInstance != NULL) +void LLFloaterAvatarList::callbackIdle(void *userdata) +{ + if (instanceExists()) { // Do not update at every frame: this would be insane ! - if (gFrameCount % LLFloaterAvatarList::sInstance->mUpdateRate == 0) + if (gFrameCount % getInstance()->mUpdateRate == 0) { - LLFloaterAvatarList::sInstance->updateAvatarList(); + getInstance()->updateAvatarList(); } } } diff --git a/indra/newview/llfloateravatarlist.h b/indra/newview/llfloateravatarlist.h index 3afd6929d..872f2159c 100644 --- a/indra/newview/llfloateravatarlist.h +++ b/indra/newview/llfloateravatarlist.h @@ -135,12 +135,13 @@ private: * Since I'm very new to C++ any suggestions on coding, style, etc are very * welcome. */ -class LLFloaterAvatarList : public LLFloater +class LLFloaterAvatarList : public LLFloater, public LLSingleton { /** * @brief Creates and initializes the LLFloaterAvatarList * Here the interface is created, and callbacks are initialized. */ + friend class LLSingleton; private: LLFloaterAvatarList(); public: @@ -187,11 +188,6 @@ public: static void sound_trigger_hook(LLMessageSystem* msg,void **); static void sendKeys(); -private: - static LLFloaterAvatarList* sInstance; - -public: - static LLFloaterAvatarList* getInstance() { return sInstance; } private: // when a line editor loses keyboard focus, it is committed. // commit callbacks are named onCommitWidgetName by convention. diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index fc72e7e17..afbefb3e5 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -32,6 +32,7 @@ #include "llviewerprecompiledheaders.h" +#include "llappearancemgr.h" #include "llimagejpeg.h" #include "llfloatercustomize.h" #include "llfontgl.h" @@ -814,23 +815,22 @@ void LLPanelEditWearable::onColorCommit( LLUICtrl* ctrl, void* userdata ) LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; LLColorSwatchCtrl* color_ctrl = (LLColorSwatchCtrl*) ctrl; - LLVOAvatar* avatar = gAgentAvatarp; - if( self && color_ctrl && avatar ) + if( self && color_ctrl && gAgentAvatarp ) { std::map::const_iterator cl_itr = self->mColorList.find(ctrl->getName()); if(cl_itr != self->mColorList.end()) { ETextureIndex te = (ETextureIndex)cl_itr->second; - LLColor4 old_color = avatar->getClothesColor( te ); + LLColor4 old_color = gAgentAvatarp->getClothesColor( te ); const LLColor4& new_color = color_ctrl->get(); if( old_color != new_color ) { // Set the new version - avatar->setClothesColor( te, new_color, TRUE ); + gAgentAvatarp->setClothesColor( te, new_color, TRUE ); LLVisualParamHint::requestHintUpdates(); - avatar->wearableUpdated(self->mType, FALSE); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); } } } @@ -1736,9 +1736,7 @@ struct WearablePanelData LLFloaterCustomize::LLFloaterCustomize() : LLFloater(std::string("customize")), mScrollingPanelList( NULL ), - mInventoryObserver(NULL), - mNextStepAfterSaveCallback( NULL ), - mNextStepAfterSaveUserdata( NULL ) + mInventoryObserver(NULL) { memset(&mWearablePanelList[0],0,sizeof(char*)*LLWearableType::WT_COUNT); //Initialize to 0 @@ -1990,12 +1988,11 @@ void LLFloaterCustomize::onBtnOk( void* userdata ) LLFloaterCustomize* floater = (LLFloaterCustomize*) userdata; gAgentWearables.saveAllWearables(); - LLVOAvatar* avatar = gAgentAvatarp; - if ( avatar ) + if ( gAgentAvatarp ) { - avatar->invalidateAll(); + gAgentAvatarp->invalidateAll(); - avatar->requestLayerSetUploads(); + gAgentAvatarp->requestLayerSetUploads(); gAgent.sendAgentSetAppearance(); } @@ -2602,11 +2599,11 @@ void LLFloaterCustomize::onTabPrecommit( void* userdata, bool from_click ) LLWearableType::EType type = (LLWearableType::EType)(intptr_t) userdata; if (type != LLWearableType::WT_INVALID && gFloaterCustomize && gFloaterCustomize->getCurrentWearableType() != type) { - gFloaterCustomize->askToSaveIfDirty(onCommitChangeTab, userdata); + gFloaterCustomize->askToSaveIfDirty(boost::bind(&onCommitChangeTab, _1)); } else { - onCommitChangeTab(TRUE, NULL); + onCommitChangeTab(true); } } @@ -2629,7 +2626,7 @@ void LLFloaterCustomize::onClose(bool app_quitting) } // static -void LLFloaterCustomize::onCommitChangeTab(BOOL proceed, void* userdata) +void LLFloaterCustomize::onCommitChangeTab(BOOL proceed) { if (!proceed || !gFloaterCustomize) { @@ -2716,24 +2713,20 @@ void LLFloaterCustomize::updateScrollingPanelList(BOOL allow_modify) } -void LLFloaterCustomize::askToSaveIfDirty( void(*next_step_callback)(BOOL proceed, void* userdata), void* userdata ) +void LLFloaterCustomize::askToSaveIfDirty( boost::function cb ) { if( isDirty()) { // Ask if user wants to save, then continue to next step afterwards - mNextStepAfterSaveCallback = next_step_callback; - mNextStepAfterSaveUserdata = userdata; + mNextStepAfterSaveCallback.connect(cb); // Bring up view-modal dialog: Save changes? Yes, No, Cancel LLNotificationsUtil::add("SaveClothingBodyChanges", LLSD(), LLSD(), boost::bind(&LLFloaterCustomize::onSaveDialog, this, _1, _2)); - return; } - - // Try to move to the next step - if( next_step_callback ) + else { - next_step_callback( TRUE, userdata ); + cb(TRUE); //just clal it immediately. } } @@ -2767,10 +2760,9 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp break; } - if( mNextStepAfterSaveCallback ) - { - mNextStepAfterSaveCallback( proceed, mNextStepAfterSaveUserdata ); - } + mNextStepAfterSaveCallback(proceed); + mNextStepAfterSaveCallback.disconnect_all_slots(); //Should this be done? + return false; } diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index 4bf4ef708..c19a570ad 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -99,7 +99,7 @@ public: virtual BOOL isDirty() const; - void askToSaveIfDirty( void(*next_step_callback)(BOOL proceed, void* userdata), void* userdata ); + void askToSaveIfDirty( boost::function cb ); void switchToDefaultSubpart(); @@ -118,7 +118,7 @@ public: static void onTabChanged( void* userdata, bool from_click ); static void onTabPrecommit( void* userdata, bool from_click ); bool onSaveDialog(const LLSD& notification, const LLSD& response); - static void onCommitChangeTab(BOOL proceed, void* userdata); + static void onCommitChangeTab(BOOL proceed); void fetchInventory(); void updateInventoryUI(); @@ -135,10 +135,8 @@ protected: LLInventoryObserver* mInventoryObserver; - void (*mNextStepAfterSaveCallback)(BOOL proceed, void* userdata); - void* mNextStepAfterSaveUserdata; - - + boost::signals2::signal mNextStepAfterSaveCallback; + protected: static void* createWearablePanel(void* userdata); diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 102856d6e..ae60a6a9b 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -50,7 +50,7 @@ #include "llinventorybridge.h" #include "llinventorymodel.h" #include "llinventorypanel.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llselectmgr.h" #include "lluiconstants.h" #include "llviewerobject.h" @@ -211,11 +211,10 @@ void LLFloaterOpenObject::callbackMoveInventory(S32 result, void* data) if (result == 0) { - LLInventoryView::showAgentInventory(); - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if (view) + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) { - view->getPanel()->setSelection(cat->mCatID, TAKE_FOCUS_NO); + active_panel->setSelection(cat->mCatID, TAKE_FOCUS_NO); } } @@ -243,6 +242,6 @@ void LLFloaterOpenObject::onClickMoveAndWear(void* data) void* LLFloaterOpenObject::createPanelInventory(void* data) { LLFloaterOpenObject* floater = (LLFloaterOpenObject*)data; - floater->mPanelInventory = new LLPanelInventory(std::string("Object Contents"), LLRect()); + floater->mPanelInventory = new LLPanelObjectInventory(std::string("Object Contents"), LLRect()); return floater->mPanelInventory; } diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index 8c00cc7f7..7639fd9f8 100644 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -41,7 +41,7 @@ #include "llfloater.h" class LLObjectSelection; -class LLPanelInventory; +class LLPanelObjectInventory; class LLFloaterOpenObject : public LLFloater @@ -84,7 +84,7 @@ protected: protected: static LLFloaterOpenObject* sInstance; - LLPanelInventory* mPanelInventory; + LLPanelObjectInventory* mPanelInventory; LLSafeHandle mObjectSelection; BOOL mDirty; }; diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 385a45306..821cd03fb 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -51,7 +51,7 @@ #include "llpanelcontents.h" #include "llpanelface.h" #include "llpanelland.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llpanelobject.h" #include "llpanelvolume.h" #include "llpanelpermissions.h" @@ -168,7 +168,7 @@ void* LLFloaterTools::createPanelContents(void* data) void* LLFloaterTools::createPanelContentsInventory(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelContents->mPanelInventory = new LLPanelInventory(std::string("ContentsInventory"), LLRect()); + floater->mPanelContents->mPanelInventory = new LLPanelObjectInventory(std::string("ContentsInventory"), LLRect()); return floater->mPanelContents->mPanelInventory; } diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 044529577..3f5deb093 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -93,25 +93,28 @@ LLFolderViewItem::LLFolderViewItem( const std::string& name, LLUIImagePtr icon, LLFolderView* root, LLFolderViewEventListener* listener ) : LLUICtrl( name, LLRect(0, 0, 0, 0), TRUE, NULL, NULL, FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_RIGHT), - mLabel( name ), mLabelWidth(0), - mCreationDate(creation_date), + mParentFolder( NULL ), - mListener( listener ), mIsSelected( FALSE ), mIsCurSelection( FALSE ), mSelectPending(FALSE), mLabelStyle( LLFontGL::NORMAL ), - mIcon(icon), + mHasVisibleChildren(FALSE), mIndentation(0), mPassedFilter(FALSE), mLastFilterGeneration(-1), mStringMatchOffset(std::string::npos), mControlLabelRotation(0.f), - mRoot( root ), + mDragAndDropTarget(FALSE), - mIsLoading(FALSE) + mIsLoading(FALSE), + mLabel( name ), + mRoot( root ), + mCreationDate(creation_date), + mIcon(icon), + mListener(listener) { sFolderViewItems.insert(this); refresh(); // possible opt: only call refreshFromListener() diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index ae19b4082..587348efd 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -335,7 +335,7 @@ protected: LLFolderViewEventListener* listener ); friend class LLBuildNewViewsScheduler; - friend class LLPanelInventory; + friend class LLPanelObjectInventory; friend class LLInventoryPanel; public: @@ -495,8 +495,9 @@ public: void applyFunctorRecursively(LLFolderViewFunctor& functor); virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor); + virtual void openItem( void ); - virtual BOOL addItem(LLFolderViewItem* item); + virtual BOOL addItem(LLFolderViewItem* item); virtual BOOL addFolder( LLFolderViewFolder* folder); // LLView functionality @@ -505,10 +506,10 @@ public: virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); virtual void draw(); time_t getCreationDate() const; diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 5c081054d..1be9d7550 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -35,7 +35,7 @@ #include // for std::pair<> #include "llinventorypanel.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llinventorybridge.h" #include "message.h" @@ -103,7 +103,7 @@ const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) -typedef LLMemberListener object_inventory_listener_t; +typedef LLMemberListener object_inventory_listener_t; typedef LLMemberListener inventory_listener_t; typedef LLMemberListener inventory_panel_listener_t; @@ -190,7 +190,7 @@ class LLDoToSelectedPanel : public object_inventory_listener_t bool handleEvent(LLPointer event, const LLSD& userdata) { std::string action = userdata.asString(); - LLPanelInventory *panel = mPtr; + LLPanelObjectInventory *panel = mPtr; LLFolderView* folder = panel->getRootFolder(); if(!folder) return true; @@ -707,7 +707,7 @@ class LL : public listener_t }; */ -void init_object_inventory_panel_actions(LLPanelInventory *panel) +void init_object_inventory_panel_actions(LLPanelObjectInventory *panel) { (new LLDoToSelectedPanel())->registerListener(panel, "Inventory.DoToSelected"); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ecdd0bc73..e2fefc4d0 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -156,9 +156,17 @@ void dec_busy_count() } // Function declarations + +struct LLWearInfo +{ + LLUUID mCategoryID; + BOOL mAppend; + BOOL mReplace; +}; + struct LLWearableHoldingPattern; void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append, BOOL replace = FALSE); -void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata); +void wear_inventory_category_on_avatar_step2( BOOL proceed, const LLWearInfo wear_info); void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append); void remove_inventory_category_from_avatar(LLInventoryCategory* category); @@ -180,12 +188,6 @@ void gotAssetForSaveItemAs(LLVFS *vfs, void* user_data, S32 status, LLExtStat ext_status); // -struct LLWearInfo -{ - LLUUID mCategoryID; - BOOL mAppend; - BOOL mReplace; -}; // [RLVa:KB] - Made this part of LLWearableHoldingPattern //BOOL gAddToOutfit = FALSE; @@ -4688,31 +4690,27 @@ void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL appen lldebugs << "wear_inventory_category_on_avatar( " << category->getName() << " )" << llendl; - LLWearInfo* userdata = new LLWearInfo; - userdata->mAppend = append; - userdata->mReplace = replace; - userdata->mCategoryID = category->getUUID(); + LLWearInfo wear_info; + wear_info.mAppend = append; + wear_info.mReplace = replace; + wear_info.mCategoryID = category->getUUID(); if( gFloaterCustomize ) { gFloaterCustomize->askToSaveIfDirty( - wear_inventory_category_on_avatar_step2, - userdata); + boost::bind(wear_inventory_category_on_avatar_step2,_1,wear_info)); } else { wear_inventory_category_on_avatar_step2( TRUE, - userdata ); + wear_info ); } } -void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) +void wear_inventory_category_on_avatar_step2( BOOL proceed, const LLWearInfo wear_info ) { - LLWearInfo* wear_info = (LLWearInfo*)userdata; - if (!wear_info) return; - // Find all the wearables that are in the category's subtree. lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl; if(proceed) @@ -4720,7 +4718,7 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; LLFindWearables is_wearable; - gInventory.collectDescendentsIf(wear_info->mCategoryID, + gInventory.collectDescendentsIf(wear_info.mCategoryID, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -4729,14 +4727,14 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) S32 wearable_count = item_array.count(); LLInventoryModel::item_array_t obj_items_new; - LLCOFMgr::getDescendentsOfAssetType(wear_info->mCategoryID, obj_items_new, LLAssetType::AT_OBJECT, false); + LLCOFMgr::getDescendentsOfAssetType(wear_info.mCategoryID, obj_items_new, LLAssetType::AT_OBJECT, false); S32 obj_count = obj_items_new.count(); // Find all gestures in this folder LLInventoryModel::cat_array_t gest_cat_array; LLInventoryModel::item_array_t gest_item_array; LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(wear_info->mCategoryID, + gInventory.collectDescendentsIf(wear_info.mCategoryID, gest_cat_array, gest_item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -4746,7 +4744,6 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) if( !wearable_count && !obj_count && !gest_count) { LLNotificationsUtil::add("CouldNotPutOnOutfit"); - delete wear_info; return; } @@ -4765,7 +4762,7 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) // Update the inventory item labels to reflect the fact // they are active. - LLViewerInventoryCategory* catp = gInventory.getCategory(wear_info->mCategoryID); + LLViewerInventoryCategory* catp = gInventory.getCategory(wear_info.mCategoryID); if (catp) { gInventory.updateCategory(catp); @@ -4781,7 +4778,7 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) // before the final getNextData(). // LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; // [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i - LLWearableHoldingPattern* holder = new LLWearableHoldingPattern(wear_info->mAppend); + LLWearableHoldingPattern* holder = new LLWearableHoldingPattern(wear_info.mAppend); // [/RLVa:KB] LLFoundData* found; LLDynamicArray found_container; @@ -4814,10 +4811,10 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) // // - Attachments: include COF contents only if appending. // - if (!wear_info->mReplace) + if (!wear_info.mReplace) { LLInventoryModel::item_array_t obj_items; - if (wear_info->mAppend) + if (wear_info.mAppend) LLCOFMgr::getDescendentsOfAssetType(idCOF, obj_items, LLAssetType::AT_OBJECT, false); // [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b else if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) @@ -4855,11 +4852,9 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) } } - if (!wear_info->mAppend) - LLCOFMgr::instance().addBOFLink(wear_info->mCategoryID); + if (!wear_info.mAppend) + LLCOFMgr::instance().addBOFLink(wear_info.mCategoryID); } - delete wear_info; - wear_info = NULL; } void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void* data) @@ -4967,8 +4962,7 @@ void remove_inventory_category_from_avatar( LLInventoryCategory* category ) if( gFloaterCustomize ) { gFloaterCustomize->askToSaveIfDirty( - remove_inventory_category_from_avatar_step2, - uuid); + boost::bind(remove_inventory_category_from_avatar_step2,_1,uuid)); } else { diff --git a/indra/newview/llinventoryclipboard.cpp b/indra/newview/llinventoryclipboard.cpp index 94ffcbd45..5c2eb9f7c 100644 --- a/indra/newview/llinventoryclipboard.cpp +++ b/indra/newview/llinventoryclipboard.cpp @@ -2,31 +2,25 @@ * @file llinventoryclipboard.cpp * @brief LLInventoryClipboard class implementation * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/llinventoryclipboard.h b/indra/newview/llinventoryclipboard.h index 7a2cf15d6..e9b069eeb 100644 --- a/indra/newview/llinventoryclipboard.h +++ b/indra/newview/llinventoryclipboard.h @@ -2,31 +2,25 @@ * @file llinventoryclipboard.h * @brief LLInventoryClipboard class header file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c85b6fa75..2bcac85a1 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -31,44 +31,26 @@ */ #include "llviewerprecompiledheaders.h" - #include "llinventorymodel.h" -#include "llassetstorage.h" -#include "llcrc.h" -#include "lldir.h" -#include "llsys.h" -#include "llxfermanager.h" +#include "llagent.h" +#include "llinventorypanel.h" +#include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventoryobserver.h" -#include "message.h" - -#include "llagent.h" -#include "llfloater.h" -#include "llfloaterinventory.h" -#include "llfocusmgr.h" #include "llinventorypanel.h" -#include "llviewerinventory.h" +#include "llnotificationsutil.h" +#include "llwindow.h" +#include "llviewercontrol.h" +#include "llpreview.h" #include "llviewermessage.h" -#include "llfoldertype.h" #include "llviewerfoldertype.h" #include "llviewerwindow.h" -#include "llviewerregion.h" #include "llappviewer.h" -#include "lldbstrings.h" -#include "llviewerstats.h" -#include "llmutelist.h" -#include "llnotificationsutil.h" +#include "llviewerregion.h" #include "llcallbacklist.h" -#include "llpreview.h" -#include "llviewercontrol.h" -#include "llvoavatar.h" -#include "llsdutil.h" +#include "llvoavatarself.h" #include "statemachine/aievent.h" -// -#include "llappviewer.h" // gLostItemsRoot -// -#include // [RLVa:KB] #include "rlvhandler.h" @@ -2614,10 +2596,10 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, gInventory.notifyObservers(); // *HACK: Do the 'show' logic for a new item in the inventory. - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if(view) + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) { - view->getPanel()->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO); + active_panel->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO); } } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index ae4e9451c..e788baba9 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -168,6 +168,10 @@ private: //-------------------------------------------------------------------- // Login //-------------------------------------------------------------------- +public: + static BOOL getIsFirstTimeInViewer2(); +private: + static BOOL sFirstTimeInViewer2; const static S32 sCurrentInvCacheVersion; // expected inventory cache version /** Initialization/Setup diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index bc264cc1e..76e0f3770 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -48,6 +48,7 @@ #include "llvoavatarself.h" #include "llscrollcontainer.h" #include "llviewerassettype.h" +#include "llpanelmaininventory.h" #include "llsdserialize.h" @@ -292,6 +293,13 @@ U32 LLInventoryPanel::getSortOrder() const return mFolderRoot->getSortOrder(); } +// static +LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel() +{ + LLInventoryView *view = LLInventoryView::getActiveInventory(); + return view ? view->getPanel() : NULL; +} + void LLInventoryPanel::setSinceLogoff(BOOL sl) { getFilter()->setDateRangeLastLogoff(sl); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 3a26926e4..d18097f73 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -165,6 +165,8 @@ public: void setSortOrder(U32 order); U32 getSortOrder() const; + + static LLInventoryPanel *getActiveInventoryPanel(); private: const std::string mSortOrderSetting; LLUUID mSelectThisID; // if non null, select this item diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 716dc1b8b..d4b2d10fb 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -662,7 +662,7 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rec LLVector3d mypos = gAgent.getPositionGlobal(); LLVector3d position = mClosestAgentPosition; - if ( LLFloaterAvatarList::getInstance() ) + if ( LLFloaterAvatarList::instanceExists() ) { LLAvatarListEntry *ent = LLFloaterAvatarList::getInstance()->getAvatarEntry(mClosestAgentToCursor); if ( NULL != ent ) diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index a049c58ac..e5219fd99 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -68,7 +68,7 @@ #include "lltool.h" #include "lltoolmgr.h" #include "lltoolcomp.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" // [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) #include "rlvhandler.h" // [/RLVa:KB] diff --git a/indra/newview/llpanelcontents.h b/indra/newview/llpanelcontents.h index ea0670749..b7b103d5b 100644 --- a/indra/newview/llpanelcontents.h +++ b/indra/newview/llpanelcontents.h @@ -37,7 +37,7 @@ #include "llpanel.h" class LLButton; -class LLPanelInventory; +class LLPanelObjectInventory; class LLViewerObject; class LLCheckBoxCtrl; class LLSpinCtrl; @@ -58,7 +58,7 @@ protected: void getState(LLViewerObject *object); public: - LLPanelInventory* mPanelInventory; + LLPanelObjectInventory* mPanelInventory; }; #endif diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index a844f8a78..200cc1c4b 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -42,7 +42,7 @@ #include "lltooldraganddrop.h" #include "llviewermenu.h" #include "llviewertexturelist.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llappviewer.h" #include "rlvhandler.h" diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 935d0af1b..bee2b1bd2 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -55,7 +55,7 @@ #include "llinventoryfunctions.h" #include "llmanipscale.h" #include "llnotificationsutil.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 05d339d3a..504e3d94f 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -45,7 +45,7 @@ class LLUICtrl; class LLButton; class LLViewerObject; class LLComboBox; -class LLPanelInventory; +class LLPanelObjectInventory; class LLColorSwatchCtrl; class LLTextureCtrl; class LLInventoryItem; diff --git a/indra/newview/llpanelinventory.cpp b/indra/newview/llpanelobjectinventory.cpp similarity index 85% rename from indra/newview/llpanelinventory.cpp rename to indra/newview/llpanelobjectinventory.cpp index 3c318a700..7744b52b6 100644 --- a/indra/newview/llpanelinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1,36 +1,30 @@ /** - * @file llpanelinventory.cpp - * @brief LLPanelInventory class implementation + * @file llsidepanelinventory.cpp + * @brief LLPanelObjectInventory class implementation * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -// ***************************************************************************** +//***************************************************************************** // // Implementation of the panel inventory - used to view and control a // task's inventory. @@ -39,66 +33,43 @@ #include "llviewerprecompiledheaders.h" -#include // for std::ostringstream -#include // for std::pair<> +#include "llpanelobjectinventory.h" -#include "stdenums.h" -#include "llpanelinventory.h" - -#include "message.h" -#include "lldarray.h" -#include "llfontgl.h" -#include "llassetstorage.h" -#include "llfoldervieweventlistener.h" -#include "llinventory.h" -#include "llinventorybridge.h" -#include "llinventorydefines.h" -#include "llinventoryicon.h" +#include "llmenugl.h" #include "llnotificationsutil.h" +#include "roles_constants.h" #include "llagent.h" #include "llcallbacklist.h" -#include "llfocusmgr.h" +#include "llfloaterbuycontents.h" #include "llfloaterbuycurrency.h" -#include "llfloaterproperties.h" #include "llfolderview.h" -#include "llgl.h" -#include "llinventorymodel.h" -#include "llinventoryicon.h" #include "llinventorybridge.h" +#include "llinventorydefines.h" #include "llinventoryfilter.h" -#include "llmenugl.h" +#include "llinventoryfunctions.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" #include "llpreviewnotecard.h" #include "llpreviewscript.h" #include "llpreviewsound.h" #include "llpreviewtexture.h" -#include "roles_constants.h" #include "llscrollcontainer.h" #include "llselectmgr.h" #include "llstatusbar.h" #include "lltooldraganddrop.h" -#include "llviewercontrol.h" -#include "llviewerregion.h" -#include "llviewertexturelist.h" -#include "llviewerinventory.h" -#include "llviewermessage.h" -#include "llviewerobject.h" -#include "llviewerobjectlist.h" -#include "llviewerwindow.h" -#include "llwearable.h" +#include "lltrans.h" #include "llviewerassettype.h" +#include "llviewerinventory.h" +#include "llviewerregion.h" +#include "llviewerobjectlist.h" +#include "llviewermessage.h" // [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) #include "rlvhandler.h" // [/RLVa:KB] #include "hippogridmanager.h" -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - ///---------------------------------------------------------------------------- /// Class LLTaskInvFVBridge @@ -110,23 +81,22 @@ protected: LLUUID mUUID; std::string mName; mutable std::string mDisplayName; - LLPanelInventory* mPanel; + LLPanelObjectInventory* mPanel; U32 mFlags; LLInventoryItem* findItem() const; public: - LLTaskInvFVBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name, + LLTaskInvFVBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, U32 flags=0); - virtual ~LLTaskInvFVBridge( void ) {} + virtual ~LLTaskInvFVBridge( ) {} virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; } virtual std::string getLabelSuffix() const { return LLStringUtil::null; } - static LLTaskInvFVBridge* createObjectBridge(LLPanelInventory* panel, + static LLTaskInvFVBridge* createObjectBridge(LLPanelObjectInventory* panel, LLInventoryObject* object); void showProperties(); void buyItem(); @@ -161,6 +131,7 @@ public: virtual BOOL isUpToDate() const { return TRUE; } virtual BOOL hasChildren() const { return FALSE; } virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; } + // LLDragAndDropBridge functionality virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, @@ -171,7 +142,7 @@ public: }; LLTaskInvFVBridge::LLTaskInvFVBridge( - LLPanelInventory* panel, + LLPanelObjectInventory* panel, const LLUUID& uuid, const std::string& name, U32 flags): @@ -275,7 +246,7 @@ void LLTaskInvFVBridge::buyItem() payload["task_id"] = inv->mTaskID; payload["item_id"] = inv->mItemID; payload["type"] = inv->mType; - LLNotifications::instance().add(alertdesc, args, payload, LLTaskInvFVBridge::commitBuyItem); + LLNotificationsUtil::add(alertdesc, args, payload, LLTaskInvFVBridge::commitBuyItem); } } @@ -295,7 +266,7 @@ S32 LLTaskInvFVBridge::getPrice() // static bool LLTaskInvFVBridge::commitBuyItem(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if(0 == option) { LLViewerObject* object = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); @@ -311,6 +282,7 @@ bool LLTaskInvFVBridge::commitBuyItem(const LLSD& notification, const LLSD& resp msg->addUUIDFast(_PREHASH_ObjectID, notification["payload"]["task_id"].asUUID()); msg->addUUIDFast(_PREHASH_ItemID, notification["payload"]["item_id"].asUUID()); msg->addUUIDFast(_PREHASH_FolderID, + //"type" should be LLAssetType::AssetType, not LLFolderType::EType gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType((LLAssetType::EType)notification["payload"]["type"].asInteger()))); msg->sendReliable(object->getRegion()->getHost()); } @@ -359,11 +331,7 @@ time_t LLTaskInvFVBridge::getCreationDate() const LLUIImagePtr LLTaskInvFVBridge::getIcon() const { - BOOL item_is_multi = FALSE; - if ( mFlags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) - { - item_is_multi = TRUE; - } + const BOOL item_is_multi = (mFlags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS); return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi ); } @@ -393,8 +361,7 @@ BOOL LLTaskInvFVBridge::isItemRenameable() const // LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { - LLInventoryItem* item; - item = (LLInventoryItem*)(object->getInventoryObject(mUUID)); + LLInventoryItem* item = (LLInventoryItem*)(object->getInventoryObject(mUUID)); if(item && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE, GOD_LIKE)) { @@ -491,13 +458,9 @@ BOOL LLTaskInvFVBridge::isItemRemovable() return FALSE; } -// helper for remove -typedef std::pair > two_uuids_list_t; -typedef std::pair remove_data_t; - -bool remove_task_inventory_callback(const LLSD& notification, const LLSD& response, LLPanelInventory* panel) +bool remove_task_inventory_callback(const LLSD& notification, const LLSD& response, LLPanelObjectInventory* panel) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLViewerObject* object = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); if(option == 0 && object) { @@ -516,6 +479,10 @@ bool remove_task_inventory_callback(const LLSD& notification, const LLSD& respon return false; } +// helper for remove +// ! REFACTOR ! two_uuids_list_t is also defined in llinventorybridge.h, but differently. +typedef std::pair > panel_two_uuids_list_t; +typedef std::pair remove_data_t; BOOL LLTaskInvFVBridge::removeItem() { if(isItemRemovable() && mPanel) @@ -531,10 +498,6 @@ BOOL LLTaskInvFVBridge::removeItem() } else { - remove_data_t* data = new remove_data_t; - data->first = mPanel; - data->second.first = mPanel->getTaskUUID(); - data->second.second.push_back(mUUID); LLSD payload; payload["task_id"] = mPanel->getTaskUUID(); payload["inventory_ids"].append(mUUID); @@ -812,7 +775,7 @@ class LLTaskCategoryBridge : public LLTaskInvFVBridge { public: LLTaskCategoryBridge( - LLPanelInventory* panel, + LLPanelObjectInventory* panel, const LLUUID& uuid, const std::string& name); @@ -830,7 +793,7 @@ public: }; LLTaskCategoryBridge::LLTaskCategoryBridge( - LLPanelInventory* panel, + LLPanelObjectInventory* panel, const LLUUID& uuid, const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) @@ -915,9 +878,8 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_BODYPART: case DAD_ANIMATION: case DAD_GESTURE: - // case DAD_CALLINGCARD: - // + case DAD_MESH: // *HACK: In order to resolve SL-22177, we need to block // drags from notecards and objects onto other // objects. uncomment the simpler version when we have @@ -965,9 +927,6 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, LLToolDragAndDrop::getInstance()->getSourceID()); } break; - // - //case DAD_CALLINGCARD: - // default: break; } @@ -982,11 +941,11 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, class LLTaskTextureBridge : public LLTaskInvFVBridge { public: - LLTaskTextureBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLInventoryType::EType it); + LLTaskTextureBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + LLInventoryType::EType it, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name), mInventoryType(it){} virtual LLUIImagePtr getIcon() const; virtual void openItem(); @@ -994,16 +953,6 @@ protected: LLInventoryType::EType mInventoryType; }; -LLTaskTextureBridge::LLTaskTextureBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLInventoryType::EType it) : - LLTaskInvFVBridge(panel, uuid, name), - mInventoryType(it) -{ -} - LLUIImagePtr LLTaskTextureBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInventoryType, 0, FALSE); @@ -1044,10 +993,10 @@ void LLTaskTextureBridge::openItem() class LLTaskSoundBridge : public LLTaskInvFVBridge { public: - LLTaskSoundBridge( - LLPanelInventory* panel, + LLTaskSoundBridge(LLPanelObjectInventory* panel, const LLUUID& uuid, - const std::string& name); + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} virtual LLUIImagePtr getIcon() const; virtual void openItem(); @@ -1056,19 +1005,11 @@ public: static void openSoundPreview(void* data); }; -LLTaskSoundBridge::LLTaskSoundBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} LLUIImagePtr LLTaskSoundBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); } - void LLTaskSoundBridge::openItem() { openSoundPreview((void*)this); @@ -1077,7 +1018,8 @@ void LLTaskSoundBridge::openItem() void LLTaskSoundBridge::openSoundPreview(void* data) { LLTaskSoundBridge* self = (LLTaskSoundBridge*)data; - if(!self) return; + if(!self) + return; if(!LLPreview::show(self->mUUID)) { // There isn't one, so make a new preview @@ -1182,28 +1124,18 @@ void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) class LLTaskLandmarkBridge : public LLTaskInvFVBridge { public: - LLTaskLandmarkBridge( - LLPanelInventory* panel, + LLTaskLandmarkBridge(LLPanelObjectInventory* panel, const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} + virtual LLUIImagePtr getIcon() const; }; -LLTaskLandmarkBridge::LLTaskLandmarkBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - LLUIImagePtr LLTaskLandmarkBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, 0, FALSE); } - ///---------------------------------------------------------------------------- /// Class LLTaskCallingCardBridge ///---------------------------------------------------------------------------- @@ -1211,24 +1143,15 @@ LLUIImagePtr LLTaskLandmarkBridge::getIcon() const class LLTaskCallingCardBridge : public LLTaskInvFVBridge { public: - LLTaskCallingCardBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name); + LLTaskCallingCardBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} virtual LLUIImagePtr getIcon() const; virtual BOOL isItemRenameable() const; virtual BOOL renameItem(const std::string& new_name); }; - -LLTaskCallingCardBridge::LLTaskCallingCardBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - LLUIImagePtr LLTaskCallingCardBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, 0, FALSE); @@ -1252,36 +1175,28 @@ BOOL LLTaskCallingCardBridge::renameItem(const std::string& new_name) class LLTaskScriptBridge : public LLTaskInvFVBridge { public: - LLTaskScriptBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name); + LLTaskScriptBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} virtual LLUIImagePtr getIcon() const; //static BOOL enableIfCopyable( void* userdata ); }; -LLTaskScriptBridge::LLTaskScriptBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} LLUIImagePtr LLTaskScriptBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); } - class LLTaskLSLBridge : public LLTaskScriptBridge { public: - LLTaskLSLBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name); + LLTaskLSLBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskScriptBridge(panel, uuid, name) {} virtual void openItem(); virtual BOOL removeItem(); @@ -1290,14 +1205,6 @@ public: //static void copyToInventory(void* userdata); }; -LLTaskLSLBridge::LLTaskLSLBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskScriptBridge(panel, uuid, name) -{ -} - void LLTaskLSLBridge::openItem() { llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl; @@ -1361,21 +1268,15 @@ BOOL LLTaskLSLBridge::removeItem() class LLTaskObjectBridge : public LLTaskInvFVBridge { public: - LLTaskObjectBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name); + LLTaskObjectBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + U32 flags = 0) : + LLTaskInvFVBridge(panel, uuid, name, flags) {} virtual LLUIImagePtr getIcon() const; }; -LLTaskObjectBridge::LLTaskObjectBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} LLUIImagePtr LLTaskObjectBridge::getIcon() const { @@ -1395,24 +1296,16 @@ LLUIImagePtr LLTaskObjectBridge::getIcon() const class LLTaskNotecardBridge : public LLTaskInvFVBridge { public: - LLTaskNotecardBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name); + LLTaskNotecardBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} virtual LLUIImagePtr getIcon() const; virtual void openItem(); virtual BOOL removeItem(); }; -LLTaskNotecardBridge::LLTaskNotecardBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - LLUIImagePtr LLTaskNotecardBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); @@ -1469,24 +1362,16 @@ BOOL LLTaskNotecardBridge::removeItem() class LLTaskGestureBridge : public LLTaskInvFVBridge { public: - LLTaskGestureBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name); + LLTaskGestureBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} virtual LLUIImagePtr getIcon() const; virtual void openItem(); virtual BOOL removeItem(); }; -LLTaskGestureBridge::LLTaskGestureBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - LLUIImagePtr LLTaskGestureBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); @@ -1529,24 +1414,16 @@ BOOL LLTaskGestureBridge::removeItem() class LLTaskAnimationBridge : public LLTaskInvFVBridge { public: - LLTaskAnimationBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name); + LLTaskAnimationBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} virtual LLUIImagePtr getIcon() const; virtual void openItem(); virtual BOOL removeItem(); }; -LLTaskAnimationBridge::LLTaskAnimationBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - LLUIImagePtr LLTaskAnimationBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); @@ -1607,12 +1484,12 @@ BOOL LLTaskAnimationBridge::removeItem() class LLTaskWearableBridge : public LLTaskInvFVBridge { public: - LLTaskWearableBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLAssetType::EType asset_type, - U32 flags); + LLTaskWearableBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + LLAssetType::EType asset_type, + U32 flags) : + LLTaskInvFVBridge(panel, uuid, name, flags), mAssetType(asset_type) {} virtual LLUIImagePtr getIcon() const; @@ -1620,102 +1497,93 @@ protected: LLAssetType::EType mAssetType; }; -LLTaskWearableBridge::LLTaskWearableBridge( - LLPanelInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLAssetType::EType asset_type, - U32 flags) : - LLTaskInvFVBridge(panel, uuid, name, flags), - mAssetType( asset_type ) -{ -} - LLUIImagePtr LLTaskWearableBridge::getIcon() const { return LLInventoryIcon::getIcon(mAssetType, LLInventoryType::IT_WEARABLE, mFlags, FALSE ); } - ///---------------------------------------------------------------------------- /// LLTaskInvFVBridge impl //---------------------------------------------------------------------------- -LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelInventory* panel, +LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* panel, LLInventoryObject* object) { LLTaskInvFVBridge* new_bridge = NULL; - LLAssetType::EType type = object->getType(); - LLInventoryItem* item = NULL; + const LLInventoryItem* item = dynamic_cast(object); + const U32 itemflags = ( NULL == item ? 0 : item->getFlags() ); + LLAssetType::EType type = object ? object->getType() : LLAssetType::AT_CATEGORY; + LLUUID object_id = object ? object->getUUID() : LLUUID::null; + std::string object_name = object ? object->getName() : std::string(); + switch(type) { case LLAssetType::AT_TEXTURE: - item = (LLInventoryItem*)object; new_bridge = new LLTaskTextureBridge(panel, - object->getUUID(), - object->getName(), - item->getInventoryType()); + object_id, + item->getInventoryType(), + object_name); break; case LLAssetType::AT_SOUND: new_bridge = new LLTaskSoundBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_LANDMARK: new_bridge = new LLTaskLandmarkBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_CALLINGCARD: new_bridge = new LLTaskCallingCardBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_SCRIPT: // OLD SCRIPTS DEPRECATED - JC llwarns << "Old script" << llendl; //new_bridge = new LLTaskOldScriptBridge(panel, - // object->getUUID(), - // object->getName()); + // object_id, + // object_name); break; case LLAssetType::AT_OBJECT: new_bridge = new LLTaskObjectBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_NOTECARD: new_bridge = new LLTaskNotecardBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_ANIMATION: new_bridge = new LLTaskAnimationBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_GESTURE: new_bridge = new LLTaskGestureBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_CLOTHING: case LLAssetType::AT_BODYPART: - item = (LLInventoryItem*)object; new_bridge = new LLTaskWearableBridge(panel, - object->getUUID(), - object->getName(), - type, - item->getFlags()); + object_id, + object_name, + type, + itemflags); break; case LLAssetType::AT_CATEGORY: new_bridge = new LLTaskCategoryBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); break; case LLAssetType::AT_LSL_TEXT: new_bridge = new LLTaskLSLBridge(panel, - object->getUUID(), - object->getName()); + object_id, + object_name); + break; break; default: llinfos << "Unhandled inventory type (llassetstorage.h): " @@ -1727,11 +1595,11 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelInventory* panel ///---------------------------------------------------------------------------- -/// Class LLPanelInventory +/// Class LLPanelObjectInventory ///---------------------------------------------------------------------------- // Default constructor -LLPanelInventory::LLPanelInventory(const std::string& name, const LLRect& rect) : +LLPanelObjectInventory::LLPanelObjectInventory(const std::string& name, const LLRect& rect) : LLPanel(name, rect), mScroller(NULL), mFolders(NULL), @@ -1746,16 +1614,16 @@ LLPanelInventory::LLPanelInventory(const std::string& name, const LLRect& rect) } // Destroys the object -LLPanelInventory::~LLPanelInventory() +LLPanelObjectInventory::~LLPanelObjectInventory() { if (!gIdleCallbacks.deleteFunction(idle, this)) { - llwarns << "LLPanelInventory::~LLPanelInventory() failed to delete callback" << llendl; + llwarns << "LLPanelObjectInventory::~LLPanelObjectInventory() failed to delete callback" << llendl; } } -void LLPanelInventory::clearContents() +void LLPanelObjectInventory::clearContents() { mHaveInventory = FALSE; mIsInventoryEmpty = TRUE; @@ -1775,7 +1643,7 @@ void LLPanelInventory::clearContents() } -void LLPanelInventory::reset() +void LLPanelObjectInventory::reset() { clearContents(); @@ -1794,7 +1662,7 @@ void LLPanelInventory::reset() mFolders->setScrollContainer( mScroller ); } -void LLPanelInventory::inventoryChanged(LLViewerObject* object, +void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object, LLInventoryObject::object_list_t* inventory, S32 serial_num, void* data) @@ -1837,7 +1705,7 @@ void LLPanelInventory::inventoryChanged(LLViewerObject* object, } } -void LLPanelInventory::updateInventory() +void LLPanelObjectInventory::updateInventory() { //llinfos << "inventory arrived: \n" // << " panel UUID: " << panel->mTaskUUID << "\n" @@ -1910,7 +1778,7 @@ void LLPanelInventory::updateInventory() // leads to an N^2 based on the category count. This could be greatly // speeded with an efficient multimap implementation, but we don't // have that in our current arsenal. -void LLPanelInventory::createFolderViews(LLInventoryObject* inventory_root, LLInventoryObject::object_list_t& contents) +void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root, LLInventoryObject::object_list_t& contents) { if (!inventory_root) { @@ -1935,7 +1803,7 @@ void LLPanelInventory::createFolderViews(LLInventoryObject* inventory_root, LLIn typedef std::pair obj_folder_pair; -void LLPanelInventory::createViewsForCategory(LLInventoryObject::object_list_t* inventory, +void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_list_t* inventory, LLInventoryObject* parent, LLFolderViewFolder* folder) { @@ -1987,9 +1855,9 @@ void LLPanelInventory::createViewsForCategory(LLInventoryObject::object_list_t* } } -void LLPanelInventory::refresh() +void LLPanelObjectInventory::refresh() { - //llinfos << "LLPanelInventory::refresh()" << llendl; + //llinfos << "LLPanelObjectInventory::refresh()" << llendl; BOOL has_inventory = FALSE; const BOOL non_root_ok = TRUE; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(NULL, non_root_ok); @@ -2042,10 +1910,10 @@ void LLPanelInventory::refresh() removeVOInventoryListener(); clearContents(); } - //llinfos << "LLPanelInventory::refresh() " << mTaskUUID << llendl; + //llinfos << "LLPanelObjectInventory::refresh() " << mTaskUUID << llendl; } -void LLPanelInventory::removeSelectedItem() +void LLPanelObjectInventory::removeSelectedItem() { if(mFolders) { @@ -2053,7 +1921,7 @@ void LLPanelInventory::removeSelectedItem() } } -void LLPanelInventory::startRenamingSelectedItem() +void LLPanelObjectInventory::startRenamingSelectedItem() { if(mFolders) { @@ -2061,7 +1929,7 @@ void LLPanelInventory::startRenamingSelectedItem() } } -void LLPanelInventory::draw() +void LLPanelObjectInventory::draw() { LLPanel::draw(); @@ -2089,14 +1957,14 @@ void LLPanelInventory::draw() } } -void LLPanelInventory::deleteAllChildren() +void LLPanelObjectInventory::deleteAllChildren() { mScroller = NULL; mFolders = NULL; LLView::deleteAllChildren(); } -BOOL LLPanelInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg) +BOOL LLPanelObjectInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg) { if (mFolders && mHaveInventory) { @@ -2126,9 +1994,9 @@ BOOL LLPanelInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDr } //static -void LLPanelInventory::idle(void* user_data) +void LLPanelObjectInventory::idle(void* user_data) { - LLPanelInventory* self = (LLPanelInventory*)user_data; + LLPanelObjectInventory* self = (LLPanelObjectInventory*)user_data; if (self->mInventoryNeedsUpdate) diff --git a/indra/newview/llpanelinventory.h b/indra/newview/llpanelobjectinventory.h similarity index 50% rename from indra/newview/llpanelinventory.h rename to indra/newview/llpanelobjectinventory.h index d06d716aa..fb50d65ce 100644 --- a/indra/newview/llpanelinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -1,62 +1,41 @@ /** - * @file llpanelinventory.h - * @brief LLPanelInventory class definition + * @file llpanelobjectinventory.h + * @brief LLPanelObjectInventory class definition * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -// ***************************************************************************** -// -// This class represents the panel used to view and control a -// particular task's inventory. -// -// ***************************************************************************** +#ifndef LL_LLPANELOBJECTINVENTORY_H +#define LL_LLPANELOBJECTINVENTORY_H -#ifndef LL_LLPANELINVENTORY_H -#define LL_LLPANELINVENTORY_H - -#include "llinventory.h" -#include "lluuid.h" -#include "llmap.h" -#include "llviewerobject.h" #include "llvoinventorylistener.h" #include "llpanel.h" -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLPanelInventory -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#include "llinventory.h" class LLScrollableContainerView; class LLFolderView; class LLFolderViewFolder; class LLViewerObject; -class LLFolderViewEventListener; -//class LLVOInventoryListener; // Utility function to hide all entries except those in the list class LLMenuGL; @@ -64,16 +43,32 @@ void hide_context_entries(LLMenuGL& menu, const std::vector &entries_to_show, const std::vector &disabled_entries); -class LLPanelInventory : public LLPanel, public LLVOInventoryListener +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLPanelObjectInventory +// +// This class represents the panel used to view and control a +// particular task's inventory. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener { -protected: - LLScrollableContainerView* mScroller; - LLFolderView* mFolders; +public: + LLPanelObjectInventory(const std::string& name, const LLRect& rect); + virtual ~LLPanelObjectInventory(); + + void refresh(); + const LLUUID& getTaskUUID() { return mTaskUUID;} + void removeSelectedItem(); + void startRenamingSelectedItem(); - LLUUID mTaskUUID; - BOOL mHaveInventory; - BOOL mIsInventoryEmpty; - BOOL mInventoryNeedsUpdate; + LLFolderView* getRootFolder() const { return mFolders; } + + virtual void draw(); + virtual void deleteAllChildren(); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); + + + static void idle(void* user_data); protected: void reset(); @@ -89,24 +84,16 @@ protected: void clearContents(); -public: - LLPanelInventory(const std::string& name, const LLRect& rect); - virtual ~LLPanelInventory(); - - void refresh(); - const LLUUID& getTaskUUID() { return mTaskUUID;} - void removeSelectedItem(); - void startRenamingSelectedItem(); - - LLFolderView* getRootFolder() const { return mFolders; } - - virtual void draw(); - virtual void deleteAllChildren(); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); +private: + LLScrollableContainerView* mScroller; + LLFolderView* mFolders; - static void idle(void* user_data); + LLUUID mTaskUUID; + BOOL mHaveInventory; + BOOL mIsInventoryEmpty; + BOOL mInventoryNeedsUpdate; }; -void init_object_inventory_panel_actions(LLPanelInventory *panel); +void init_object_inventory_panel_actions(LLPanelObjectInventory *panel); #endif // LL_LLPANELINVENTORY_H diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 52f0a6e88..17f6ff4a9 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -58,7 +58,7 @@ #include "llfirstuse.h" #include "llfocusmgr.h" #include "llmanipscale.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 412f22669..abf460dd0 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -45,7 +45,7 @@ class LLUICtrl; class LLButton; class LLViewerObject; class LLComboBox; -class LLPanelInventory; +class LLPanelObjectInventory; class LLColorSwatchCtrl; class LLPanelVolume : public LLPanel diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index 180c3dd2e..2e6664071 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -2,31 +2,25 @@ * @file llpolymesh.cpp * @brief Implementation of LLPolyMesh class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,16 +29,18 @@ //----------------------------------------------------------------------------- #include "llviewerprecompiledheaders.h" -#include "llpolymesh.h" +#include "llfasttimer.h" +#include "llmemory.h" #include "llviewercontrol.h" #include "llxmltree.h" #include "llvoavatar.h" +#include "llwearable.h" #include "lldir.h" #include "llvolume.h" #include "llendianswizzle.h" -#include "llfasttimer.h" +#include "llpolymesh.h" #define HEADER_ASCII "Linden Mesh 1.0" #define HEADER_BINARY "Linden Binary Mesh 1.0" @@ -1881,9 +1877,9 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl; } mJointOffsets[joint] = bone_info->mPositionDeformation; - } - } - return TRUE; + } + } + return TRUE; } //----------------------------------------------------------------------------- @@ -1891,10 +1887,10 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) //----------------------------------------------------------------------------- void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { - F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); + F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); - LLJoint* joint; - joint_vec_map_t::iterator iter; + LLJoint* joint; + joint_vec_map_t::iterator iter; for (iter = mJointScales.begin(); iter != mJointScales.end(); diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h index a91d88c71..bed0f2cd1 100644 --- a/indra/newview/llpolymesh.h +++ b/indra/newview/llpolymesh.h @@ -2,31 +2,25 @@ * @file llpolymesh.h * @brief Implementation of LLPolyMesh class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,6 +40,7 @@ class LLSkinJoint; class LLVOAvatar; +class LLWearable; //#define USE_STRIPS // Use tri-strips for rendering. diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index 9b2a7b4a5..e595a3f67 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -2,31 +2,25 @@ * @file llpolymorph.cpp * @brief Implementation of LLPolyMesh class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,6 +31,7 @@ #include "llpolymorph.h" #include "llvoavatar.h" +#include "llwearable.h" #include "llxmltree.h" #include "llendianswizzle.h" diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h index 5137fc1fc..749ac6d97 100644 --- a/indra/newview/llpolymorph.h +++ b/indra/newview/llpolymorph.h @@ -42,6 +42,7 @@ class LLPolyMeshSharedData; class LLVOAvatar; class LLVector2; class LLViewerJointCollisionVolume; +class LLWearable; //----------------------------------------------------------------------------- // LLPolyMorphData() diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 1ba07c364..5019814e0 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -459,7 +459,8 @@ void LLPreview::onBtnCopyToInv(void* userdata) if (self->mNotecardInventoryID.notNull()) { copy_inventory_from_notecard(self->mObjectID, - self->mNotecardInventoryID, item); + self->mNotecardInventoryID, + item); } else { diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index b6dfcc185..d1d813a06 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -95,12 +95,9 @@ protected: void LLInventoryGestureAvailable::done() { - LLPreview* preview = NULL; - uuid_vec_t::iterator it = mComplete.begin(); - uuid_vec_t::iterator end = mComplete.end(); - for(; it < end; ++it) + for(uuid_vec_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it) { - preview = LLPreview::find((*it)); + LLPreview *preview = LLPreview::find((*it)); if(preview) { preview->refresh(); @@ -166,7 +163,7 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& // this will call refresh when we have everything. LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); - if(item && !item->isComplete()) + if (item && !item->isFinished()) { LLInventoryGestureAvailable* observer; observer = new LLInventoryGestureAvailable(); @@ -188,6 +185,11 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& return self; } +void LLPreviewGesture::draw() +{ + // Skip LLPreview::draw() to avoid description update + LLFloater::draw(); +} // virtual BOOL LLPreviewGesture::handleKeyHere(KEY key, MASK mask) @@ -888,7 +890,13 @@ void LLPreviewGesture::initDefaultGesture() void LLPreviewGesture::loadAsset() { const LLInventoryItem* item = getItem(); - if (!item) return; + if (!item) + { + // Don't set asset status here; we may not have set the item id yet + // (e.g. when this gets called initially) + //mAssetStatus = PREVIEW_ASSET_ERROR; + return; + } LLUUID asset_id = item->getAssetUUID(); if (asset_id.isNull()) @@ -897,6 +905,7 @@ void LLPreviewGesture::loadAsset() // Blank gesture will be fine. initDefaultGesture(); refresh(); + mAssetStatus = PREVIEW_ASSET_LOADED; return; } @@ -952,6 +961,7 @@ void LLPreviewGesture::onLoadComplete(LLVFS *vfs, self->mDirty = FALSE; self->refresh(); + self->refreshFromItem(self->getItem()); // to update description and title } else { diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index c245c0e8d..e2cc50bb3 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -55,6 +55,7 @@ public: static LLPreviewGesture* show(const std::string& title, const LLUUID& item_id, const LLUUID& object_id, BOOL take_focus = TRUE); // LLView + virtual void draw(); virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 6682a6e8c..424f2a902 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -91,7 +91,7 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "llappviewer.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) #include "rlvhandler.h" // [/RLVa:KB] diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 36b25a27c..f995787b0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -204,6 +204,8 @@ #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llagentlanguage.h" +#include "llwearable.h" +#include "llinventorybridge.h" #include "llsocks5.h" #include "jcfloaterareasearch.h" @@ -234,8 +236,6 @@ // exported globals // bool gAgentMovementCompleted = false; -std::string gInitialOutfit; -std::string gInitialOutfitGender; std::string SCREEN_HOME_FILENAME = "screen_home.bmp"; std::string SCREEN_LAST_FILENAME = "screen_last.bmp"; @@ -2092,7 +2092,7 @@ bool idle_startup() // else if (gSavedSettings.getBOOL("RadarKeepOpen")) { - LLFloaterAvatarList::createInstance(false); + LLFloaterAvatarList::getInstance()->close(); } if (gSavedSettings.getBOOL("SHShowMediaTicker")) { @@ -2918,7 +2918,7 @@ bool idle_startup() const F32 wearables_time = wearables_timer.getElapsedTimeF32(); const F32 MAX_WEARABLES_TIME = 10.f; - if (!gAgent.isGenderChosen()) + if (!gAgent.isGenderChosen() && isAgentAvatarValid()) { // No point in waiting for clothing, we don't even // know what gender we are. Pop a dialog to ask and diff --git a/indra/newview/lltexlayerparams.cpp b/indra/newview/lltexlayerparams.cpp index ee6e534d2..8972827ef 100644 --- a/indra/newview/lltexlayerparams.cpp +++ b/indra/newview/lltexlayerparams.cpp @@ -2,33 +2,26 @@ * @file lltexlayerparams.cpp * @brief Texture layer parameters * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ #include "llviewerprecompiledheaders.h" diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index a78f98f2d..bc297bcb0 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -152,6 +152,8 @@ void display_startup() LLGLState::checkStates(); LLGLState::checkTextureChannels(); + gViewerWindow->handlePerFrameHover(); // Fix ui flicker. + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); LLGLSUIDefault gls_ui; gPipeline.disableLights(); diff --git a/indra/newview/llviewergesture.cpp b/indra/newview/llviewergesture.cpp index a8129875a..65cee0e5e 100644 --- a/indra/newview/llviewergesture.cpp +++ b/indra/newview/llviewergesture.cpp @@ -110,6 +110,7 @@ BOOL LLViewerGesture::trigger(const std::string &trigger_string) } } + // private void LLViewerGesture::doTrigger( BOOL send_chat ) { diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp index d2adad2ce..061f9a156 100644 --- a/indra/newview/llviewerjoint.cpp +++ b/indra/newview/llviewerjoint.cpp @@ -2,31 +2,25 @@ * @file llviewerjoint.cpp * @brief Implementation of LLViewerJoint class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h index 67bd7786c..76e3833ac 100644 --- a/indra/newview/llviewerjoint.h +++ b/indra/newview/llviewerjoint.h @@ -2,31 +2,25 @@ * @file llviewerjoint.h * @brief Implementation of LLViewerJoint class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 8e8dcef98..e833845df 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -2,31 +2,25 @@ * @file llviewerjointattachment.cpp * @brief Implementation of LLViewerJointAttachment class * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,12 +29,12 @@ #include "llviewerjointattachment.h" #include "llagentconstants.h" - #include "llviewercontrol.h" #include "lldrawable.h" #include "llgl.h" +#include "llhudtext.h" #include "llrender.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvolume.h" #include "pipeline.h" #include "llspatialpartition.h" diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h index 749f676b6..0191f0cae 100644 --- a/indra/newview/llviewerjointmesh.h +++ b/indra/newview/llviewerjointmesh.h @@ -2,31 +2,25 @@ * @file llviewerjointmesh.h * @brief Implementation of LLViewerJointMesh class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index bf4d71edd..982089f31 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -173,6 +173,7 @@ #include "llinventorydefines.h" #include "llinventoryfunctions.h" #include "llinventorypanel.h" +#include "llinventorybridge.h" #include "llkeyboard.h" #include "llpanellogin.h" #include "llmenucommands.h" @@ -4189,18 +4190,18 @@ void handle_show_newest_map(void*) // // Major mode switching // -void reset_view_final( BOOL proceed, void* ); +void reset_view_final( BOOL proceed ); void handle_reset_view() { if( (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) && gFloaterCustomize ) { // Show dialog box if needed. - gFloaterCustomize->askToSaveIfDirty( reset_view_final, NULL ); + gFloaterCustomize->askToSaveIfDirty( boost::bind(&reset_view_final, _1) ); } else { - reset_view_final( TRUE, NULL ); + reset_view_final( true ); } } @@ -4214,7 +4215,7 @@ class LLViewResetView : public view_listener_t }; // Note: extra parameters allow this function to be called from dialog. -void reset_view_final( BOOL proceed, void* ) +void reset_view_final( BOOL proceed ) { if( !proceed ) { @@ -8298,10 +8299,9 @@ void slow_mo_animations(void*) void handle_dump_avatar_local_textures(void*) { - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar ) + if( isAgentAvatarValid() ) { - avatar->dumpLocalTextures(); + gAgentAvatarp->dumpLocalTextures(); } } @@ -9062,12 +9062,11 @@ void handle_buy_currency_test(void*) void handle_rebake_textures(void*) { - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) return; + if (!isAgentAvatarValid()) return; // Slam pending upload count to "unstick" things bool slam_for_debug = true; - avatar->forceBakeAllTextures(slam_for_debug); + gAgentAvatarp->forceBakeAllTextures(slam_for_debug); } void toggle_visibility(void* user_data) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5fa5bbf40..0e524aaa6 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -38,6 +38,7 @@ #include #include "llimagejpeg.h" +#include "llagentui.h" #include "llanimationstates.h" #include "llaudioengine.h" #include "llavatarnamecache.h" @@ -122,6 +123,7 @@ #include "lluploaddialog.h" #include "llviewercamera.h" #include "llviewerdisplay.h" +#include "llviewerfoldertype.h" #include "llviewergenericmessage.h" #include "llviewerinventory.h" #include "llviewerjoystick.h" @@ -954,8 +956,8 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) void open_offer(const std::vector& items, const std::string& from_name) { - std::vector::const_iterator it = items.begin(); - std::vector::const_iterator end = items.end(); + uuid_vec_t::const_iterator it = items.begin(); + uuid_vec_t::const_iterator end = items.end(); LLInventoryItem* item; for(; it != end; ++it) { @@ -1153,7 +1155,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& { LLChat chat; std::string log_message; - S32 button = LLNotification::getSelectedOption(notification, response); + S32 button = LLNotificationsUtil::getSelectedOption(notification, response); // For muting, we need to add the mute, then decline the offer. // This must be done here because: @@ -1177,7 +1179,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& msg->addUUIDFast(_PREHASH_ID, mTransactionID); msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); msg->addStringFast(_PREHASH_FromAgentName, name); msg->addStringFast(_PREHASH_Message, ""); msg->addU32Fast(_PREHASH_ParentEstateID, 0); @@ -1573,7 +1575,7 @@ bool lure_callback(const LLSD& notification, const LLSD& response) } else { - option = LLNotification::getSelectedOption(notification, response); + option = LLNotificationsUtil::getSelectedOption(notification, response); } LLUUID from_id = notification["payload"]["from_id"].asUUID(); @@ -1604,7 +1606,7 @@ static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lu bool goto_url_callback(const LLSD& notification, const LLSD& response) { std::string url = notification["payload"]["url"].asString(); - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if(1 == option) { LLWeb::loadURL(url); @@ -1665,6 +1667,16 @@ static std::string clean_name_from_im(const std::string& name, EInstantMessage t } } + +void notification_display_name_callback(const LLUUID& id, + const LLAvatarName& av_name, + const std::string& name, + LLSD& substitutions, + const LLSD& payload) +{ + substitutions["NAME"] = av_name.mDisplayName; + LLNotificationsUtil::add(name, substitutions, payload); +} void process_improved_im(LLMessageSystem *msg, void **user_data) { if (gNoRender) @@ -2025,7 +2037,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // if there is not a panel for this conversation (i.e. it is a new IM conversation // initiated by the other party) then... std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); std::string response = gSavedPerAccountSettings.getText("BusyModeResponse"); pack_instant_message( gMessageSystem, @@ -2211,7 +2223,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) if (has_inventory) { - info = new LLOfferInfo; + info = new LLOfferInfo(); info->mIM = IM_GROUP_NOTICE; info->mFromID = from_id; @@ -2812,7 +2824,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) send_generic_message("requestonlinenotification", strings); args["NAME"] = name; - LLNotificationsUtil::add("FriendshipAccepted", args); + LLSD payload; + payload["from_id"] = from_id; + LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, + _1, + _2, + "FriendshipAccepted", + args, + payload)); } break; @@ -2836,7 +2855,7 @@ void busy_message (LLMessageSystem* msg, LLUUID from_id) if (gAgent.getBusy()) { std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); std::string response = gSavedPerAccountSettings.getText("BusyModeResponse"); pack_instant_message( gMessageSystem, @@ -2854,7 +2873,7 @@ void busy_message (LLMessageSystem* msg, LLUUID from_id) bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLUUID fid; LLUUID from_id; LLMessageSystem* msg = gMessageSystem; @@ -3817,6 +3836,9 @@ void process_teleport_finish(LLMessageSystem* msg, void**) M7WindlightInterface::getInstance()->receiveReset(); + // Make sure we're standing + gAgent.standUp(); + // now, use the circuit info to tell simulator about us! LL_INFOS("Messaging") << "process_teleport_finish() Enabling " << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; @@ -3950,7 +3972,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.sendAgentSetAppearance(); // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - if ( (gAgentAvatarp) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) + if ( (isAgentAvatarValid()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) // [/RLVa:KB] // if (avatarp) { @@ -4990,9 +5012,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) BOOL force_mouselook; mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook); - LLVOAvatar* avatar = gAgentAvatarp; - - if (avatar && dist_vec_squared(camera_eye, camera_at) > 0.0001f) + if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > 0.0001f) { gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at); } @@ -5006,7 +5026,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) if (object) { LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); - if (!use_autopilot || (avatar && avatar->isSitting() && avatar->getRoot() == object->getRoot())) + if (!use_autopilot || isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot()) { //we're already sitting on this object, so don't autopilot } @@ -5273,7 +5293,9 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) S32 credit = 0; S32 committed = 0; std::string desc; + LLUUID tid; + msg->getUUID("MoneyData", "TransactionID", tid); msg->getS32("MoneyData", "MoneyBalance", balance); msg->getS32("MoneyData", "SquareMetersCredit", credit); msg->getS32("MoneyData", "SquareMetersCommitted", committed); @@ -5303,9 +5325,6 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) gStatusBar->setLandCredit(credit); gStatusBar->setLandCommitted(committed); } - - LLUUID tid; - msg->getUUID("MoneyData", "TransactionID", tid); static std::deque recent; if(!desc.empty() && gSavedSettings.getBOOL("NotifyMoneyChange") && (std::find(recent.rbegin(), recent.rend(), tid) == recent.rend())) @@ -5337,7 +5356,7 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) bool handle_special_notification_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) { @@ -5358,18 +5377,18 @@ bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) llsdBlock["REGIONMATURITY"] = LLViewerRegion::accessToString(regionAccess); // we're going to throw the LLSD in there in case anyone ever wants to use it - LLNotifications::instance().add(notificationID+"_Notify", llsdBlock); + LLNotificationsUtil::add(notificationID+"_Notify", llsdBlock); if (regionAccess == SIM_ACCESS_MATURE) { if (gAgent.isTeen()) { - LLNotifications::instance().add(notificationID+"_KB", llsdBlock); + LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); return true; } else if (gAgent.prefersPG()) { - LLNotifications::instance().add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); + LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); return true; } } @@ -5377,12 +5396,12 @@ bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) { if (!gAgent.isAdult()) { - LLNotifications::instance().add(notificationID+"_KB", llsdBlock); + LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); return true; } else if (gAgent.prefersPG() || gAgent.prefersMature()) { - LLNotifications::instance().add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); + LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); return true; } } @@ -5442,7 +5461,7 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } } - LLNotifications::instance().add(notificationID, llsdBlock); + LLNotificationsUtil::add(notificationID, llsdBlock); return true; } return false; @@ -5508,14 +5527,14 @@ void process_alert_core(const std::string& message, BOOL modal) // Allow the server to spawn a named alert so that server alerts can be // translated out of English. std::string alert_name(message.substr(ALERT_PREFIX.length())); - LLNotifications::instance().add(alert_name); + LLNotificationsUtil::add(alert_name); } else if (message.find(NOTIFY_PREFIX) == 0) { // Allow the server to spawn a named notification so that server notifications can be // translated out of English. std::string notify_name(message.substr(NOTIFY_PREFIX.length())); - LLNotifications::instance().add(notify_name); + LLNotificationsUtil::add(notify_name); } else if (message[0] == '/') { @@ -5784,7 +5803,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp bool script_question_cb(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLMessageSystem *msg = gMessageSystem; S32 orig = notification["payload"]["questions"].asInteger(); S32 new_questions = orig; @@ -5836,7 +5855,7 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) { return (notification->getPayload()["item_id"].asUUID() == blocked_id); } - return FALSE; + return false; } private: const LLUUID& blocked_id; @@ -5848,7 +5867,7 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) if (response["Details"]) { // respawn notification... - LLNotifications::instance().add(notification["name"], notification["substitutions"], notification["payload"]); + LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); // ...with description on top LLNotificationsUtil::add("DebitPermissionDetails"); @@ -5884,7 +5903,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // so we'll reuse the same namespace for both throttle types. std::string throttle_name = owner_name; std::string self_name; - gAgent.getName( self_name ); + LLAgentUI::buildFullname( self_name ); if( owner_name == self_name ) { throttle_name = taskid.getString(); @@ -5920,7 +5939,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) S32 count = 0; LLSD args; args["OBJECTNAME"] = object_name; - args["NAME"] = owner_name; + args["NAME"] = LLCacheName::cleanFullName(owner_name); // check the received permission flags against each permission for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) @@ -5975,7 +5994,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) //if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) { // display the caution permissions prompt - LLNotifications::instance().add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); + LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); } else { @@ -6254,7 +6273,7 @@ void send_simple_im(const LLUUID& to_id, const LLUUID& id) { std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); send_improved_im(to_id, my_name, message, @@ -6275,7 +6294,7 @@ void send_group_notice(const LLUUID& group_id, // This will mean converting the item to a binary bucket, // and the subject/message into a single field. std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); // Combine subject + message into a single string. std::ostringstream subject_and_message; @@ -6646,7 +6665,7 @@ std::vector gLoadUrlList; bool callback_load_url(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) { diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index fa49ede4d..709e582ad 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -33,20 +33,26 @@ #ifndef LL_LLVIEWERMESSAGE_H #define LL_LLVIEWERMESSAGE_H +#include "llassettype.h" #include "llinstantmessage.h" +#include "llpointer.h" #include "lltransactiontypes.h" #include "lluuid.h" -#include "llchat.h" +#include "message.h" #include "stdenums.h" +#include "llnotifications.h" +#include "llchat.h" // // Forward declarations // class LLColor4; -class LLViewerObject; class LLInventoryObject; class LLInventoryItem; +class LLMeanCollisionData; class LLMessageSystem; +class LLVFS; +class LLViewerObject; class LLViewerRegion; // diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index b7b4dbc27..35b1dba5d 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -1567,7 +1567,8 @@ void LLViewerTextEditor::copyInventory(const LLInventoryItem* item, U32 callback { copy_inventory_from_notecard(mObjectID, mNotecardInventoryID, - item, callback_id); + item, + callback_id); } bool LLViewerTextEditor::hasEmbeddedInventory() diff --git a/indra/newview/llviewervisualparam.cpp b/indra/newview/llviewervisualparam.cpp index 733fd485e..187db674e 100644 --- a/indra/newview/llviewervisualparam.cpp +++ b/indra/newview/llviewervisualparam.cpp @@ -119,12 +119,6 @@ LLViewerVisualParam::LLViewerVisualParam() { } -/* -//============================================================================= -// These virtual functions should always be overridden, -// but are included here for use as templates -//============================================================================= - //----------------------------------------------------------------------------- // setInfo() //----------------------------------------------------------------------------- @@ -140,6 +134,12 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info) return TRUE; } +/* +//============================================================================= +// These virtual functions should always be overridden, +// but are included here for use as templates +//============================================================================= + //----------------------------------------------------------------------------- // parseData() //----------------------------------------------------------------------------- diff --git a/indra/newview/llviewervisualparam.h b/indra/newview/llviewervisualparam.h index 48d28cebf..09052ae56 100644 --- a/indra/newview/llviewervisualparam.h +++ b/indra/newview/llviewervisualparam.h @@ -2,31 +2,25 @@ * @file llviewervisualparam.h * @brief viewer side visual params (with data file parsing) * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,6 +31,8 @@ #include "llstring.h" #include "llvisualparam.h" +class LLWearable; + //----------------------------------------------------------------------------- // LLViewerVisualParamInfo //----------------------------------------------------------------------------- diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 1fd9239ee..db7c27c79 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -16,6 +16,7 @@ #include "llviewerprecompiledheaders.h" #include "llfloateravatarlist.h" +#include "llappviewer.h" #include "llavatarnamecache.h" #include "llcallbacklist.h" #include "llfloaterbeacons.h" @@ -33,6 +34,7 @@ #include "llviewermenu.h" #include "llviewermessage.h" #include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerwindow.h" #include "llagentcamera.h" @@ -589,9 +591,24 @@ void RlvHandler::onLoginComplete() RlvSettings::updateLoginLastLocation(); #endif // RLV_EXTENSION_STARTLOCATION + LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&RlvHandler::onTeleportFailed, this)); + LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&RlvHandler::onTeleportFinished, this, _1)); + processRetainedCommands(); } +// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void RlvHandler::onTeleportFailed() +{ + setCanCancelTp(true); +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void RlvHandler::onTeleportFinished(const LLVector3d& posArrival) +{ + setCanCancelTp(true); +} + // ============================================================================ // String/chat censoring functions // @@ -932,6 +949,9 @@ BOOL RlvHandler::setEnabled(BOOL fEnable) if (fEnable) { + RLV_INFOS << "Enabling Restrained Love API support - " << RlvStrings::getVersion() << RLV_ENDL; + m_fEnabled = TRUE; + // Initialize the command lookup table RlvCommand::initLookupTable(); @@ -941,11 +961,11 @@ BOOL RlvHandler::setEnabled(BOOL fEnable) gRlvHandler.addCommandHandler(new RlvExtGetSet()); - // Fetch shared inventory if we're enabled after logon - if (LLStartUp::getStartupState() >= STATE_CLEANUP) - RlvInventory::instance().fetchSharedInventory(); - - m_fEnabled = TRUE; + // Make sure we get notified when login is successful + if (LLStartUp::getStartupState() < STATE_STARTED) + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&RlvHandler::onLoginComplete, &gRlvHandler)); + else + gRlvHandler.onLoginComplete(); } #ifdef RLV_ADVANCED_MENU @@ -1015,7 +1035,8 @@ ERlvCmdRet RlvHandler::processAddRemCommand(const RlvCommand& rlvCmd) VERIFY_OPTION_REF( (rlvCmdOption.isEmpty()) || (rlvCmdOption.isWearableType()) ); // We need to flush any queued force-wear commands before changing the restrictions - RlvForceWear::instance().done(); + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); ERlvLockMask eLock = (RLV_BHVR_ADDOUTFIT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE; for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) @@ -1419,7 +1440,8 @@ ERlvCmdRet RlvHandler::onAddRemAttach(const RlvCommand& rlvCmd, bool& fRefCount) return RLV_RET_FAILED; // We need to flush any queued force-wear commands before changing the restrictions - RlvForceWear::instance().done(); + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); ERlvLockMask eLock = (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD; for (LLVOAvatar::attachment_map_t::const_iterator itAttach = pAvatar->mAttachmentPoints.begin(); @@ -1445,7 +1467,8 @@ ERlvCmdRet RlvHandler::onAddRemDetach(const RlvCommand& rlvCmd, bool& fRefCount) RLV_ASSERT(RLV_BHVR_DETACH == rlvCmd.getBehaviourType()); // We need to flush any queued force-wear commands before changing the restrictions - RlvForceWear::instance().done(); + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); if (rlvCmd.getOption().empty()) // @detach=n|y - RLV_LOCK_REMOVE locks an attachment *object* { diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h index e0962332b..b22554ff0 100644 --- a/indra/newview/rlvhandler.h +++ b/indra/newview/rlvhandler.h @@ -143,6 +143,8 @@ public: bool onGC(); void onLoginComplete(); void onSitOrStand(bool fSitting); + void onTeleportFailed(); + void onTeleportFinished(const LLVector3d& posArrival); static void onIdleStartup(void* pParam); /* diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 4148e326d..3a485d135 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -15,6 +15,8 @@ */ #include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llagentwearables.h" #include "llattachmentsmgr.h" #include "llfloaterinventory.h" #include "llfloaterwindlight.h" @@ -29,11 +31,11 @@ #include "llvoavatar.h" #include "llwearablelist.h" #include "llwlparammanager.h" -#include "llagentwearables.h" + #include "rlvhelper.h" -#include "rlvinventory.h" #include "rlvhandler.h" +#include "rlvinventory.h" #include diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp index 0cc6822f6..471e48858 100644 --- a/indra/newview/rlvlocks.cpp +++ b/indra/newview/rlvlocks.cpp @@ -184,7 +184,7 @@ void RlvAttachmentLocks::addAttachmentLock(const LLUUID& idAttachObj, const LLUU #endif // RLV_RELEASE m_AttachObjRem.insert(std::pair(idAttachObj, idRlvObj)); - if(LLViewerObject *pObj = gObjectList.findObject(idAttachObj)) //OK + if(LLViewerObject *pObj = gObjectList.findObject(idAttachObj)) //Update labels to (locked) { gInventory.addChangedMask(LLInventoryObserver::LABEL, pObj->getAttachmentItemID()); gInventory.notifyObservers(); @@ -206,7 +206,7 @@ void RlvAttachmentLocks::addAttachmentPointLock(S32 idxAttachPt, const LLUUID& i { m_AttachPtRem.insert(std::pair(idxAttachPt, idRlvObj)); LLVOAvatar* pAvatar = gAgentAvatarp; - if (pAvatar) + if (pAvatar) //Update labels to (locked) { bool need_update = false; LLVOAvatar::attachment_map_t::iterator iter = pAvatar->mAttachmentPoints.find(idxAttachPt); @@ -343,7 +343,7 @@ void RlvAttachmentLocks::removeAttachmentLock(const LLUUID& idAttachObj, const L if (idRlvObj == itAttachObj->second) { m_AttachObjRem.erase(itAttachObj); - if(LLViewerObject *pObj = gObjectList.findObject(idAttachObj)) //OK + if(LLViewerObject *pObj = gObjectList.findObject(idAttachObj)) //Update labels to (locked) { gInventory.addChangedMask(LLInventoryObserver::LABEL, pObj->getAttachmentItemID()); gInventory.notifyObservers(); @@ -378,7 +378,7 @@ void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID break; } } - if(removed_entry) + if(removed_entry) //Update labels to (locked) { if(m_AttachPtRem.find(idxAttachPt) == m_AttachPtRem.end()) { @@ -880,7 +880,7 @@ void RlvWearableLocks::addWearableTypeLock(LLWearableType::EType eType, const LL { m_WearableTypeRem.insert(std::pair(eType, idRlvObj)); LLUUID item_id = gAgentWearables.getWearableItemID(eType, 0); // TODO: MULTI-WEARABLE - if(item_id.notNull()) + if(item_id.notNull()) //Update labels to (locked) { gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); gInventory.notifyObservers(); @@ -971,7 +971,7 @@ void RlvWearableLocks::removeWearableTypeLock(LLWearableType::EType eType, const break; } } - if(removed_entry) + if(removed_entry) //Update labels to (locked) { if(m_WearableTypeRem.find(eType) == m_WearableTypeRem.end()) { From ae7b12f2301a93490935ba92abc361de2915597a Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 16 Feb 2012 19:25:59 -0600 Subject: [PATCH 02/32] Interim commit before diving into reworking the inventory panel. --- indra/newview/CMakeLists.txt | 14 +- indra/newview/app_settings/settings.xml | 92 +- indra/newview/character/avatar_lad.xml | 53 +- indra/newview/cofmgr.cpp | 536 --- indra/newview/cofmgr.h | 90 - indra/newview/llagent.cpp | 20 +- indra/newview/llagentwearables.cpp | 1271 +++---- indra/newview/llagentwearables.h | 148 +- indra/newview/llagentwearablesfetch.cpp | 607 ++++ indra/newview/llagentwearablesfetch.h | 114 + indra/newview/llappearancemgr.cpp | 3138 +++++++++++++++++ indra/newview/llappearancemgr.h | 265 ++ indra/newview/llassetuploadresponders.h | 2 +- indra/newview/llbuildnewviewsscheduler.cpp | 2 + indra/newview/lldriverparam.cpp | 190 +- indra/newview/lldriverparam.h | 12 + indra/newview/llfloateravatarpicker.cpp | 2 +- indra/newview/llfloatercustomize.cpp | 23 +- indra/newview/llfloaterlandmark.cpp | 2 +- indra/newview/llfolderview.cpp | 138 +- indra/newview/llfolderview.h | 28 +- indra/newview/llfoldervieweventlistener.h | 12 +- indra/newview/llfolderviewitem.cpp | 483 ++- indra/newview/llfolderviewitem.h | 19 +- indra/newview/llgesturemgr.cpp | 286 +- indra/newview/llgesturemgr.h | 75 +- indra/newview/llinventoryactions.cpp | 16 +- indra/newview/llinventorybridge.cpp | 3039 ++++++++-------- indra/newview/llinventorybridge.h | 228 +- indra/newview/llinventoryclipboard.cpp | 12 + indra/newview/llinventoryclipboard.h | 3 + indra/newview/llinventoryfunctions.cpp | 117 +- indra/newview/llinventoryfunctions.h | 119 + indra/newview/llinventorymodel.cpp | 230 +- indra/newview/llinventorymodel.h | 88 +- .../llinventorymodelbackgroundfetch.cpp | 3 +- indra/newview/llinventoryobserver.h | 4 +- indra/newview/llinventorypanel.cpp | 139 +- indra/newview/llinventorypanel.h | 18 +- indra/newview/lllocaltextureobject.cpp | 212 ++ indra/newview/lllocaltextureobject.h | 87 + indra/newview/lloutfitobserver.cpp | 153 + indra/newview/lloutfitobserver.h | 96 + indra/newview/llpanelmaininventory.cpp | 318 +- indra/newview/llpanelmaininventory.h | 5 +- indra/newview/llpanelobjectinventory.cpp | 172 +- indra/newview/llpanelobjectinventory.h | 6 - indra/newview/llpolymesh.cpp | 7 + indra/newview/llpolymesh.h | 2 + indra/newview/llpolymorph.cpp | 56 +- indra/newview/llpolymorph.h | 3 +- indra/newview/llpreview.cpp | 7 +- indra/newview/llpreviewnotecard.cpp | 2 +- indra/newview/llstartup.cpp | 94 +- indra/newview/llstartup.h | 5 + indra/newview/lltexglobalcolor.cpp | 152 + indra/newview/lltexglobalcolor.h | 83 + indra/newview/lltexlayer.cpp | 2728 +++++++------- indra/newview/lltexlayer.h | 710 ++-- indra/newview/lltexlayerparams.h | 193 + indra/newview/lltexturectrl.cpp | 2 +- indra/newview/lltooldraganddrop.cpp | 32 +- indra/newview/llviewercontrol.cpp | 2 +- indra/newview/llviewerfoldertype.cpp | 73 +- indra/newview/llviewerfoldertype.h | 1 + indra/newview/llviewerinventory.cpp | 701 +++- indra/newview/llviewerinventory.h | 61 +- indra/newview/llviewerjointattachment.cpp | 2 +- indra/newview/llviewermenu.cpp | 152 +- indra/newview/llviewermessage.cpp | 306 +- indra/newview/llviewermessage.h | 8 + indra/newview/llviewerstats.cpp | 8 +- indra/newview/llviewertexteditor.cpp | 3 +- indra/newview/llviewervisualparam.cpp | 16 + indra/newview/llviewervisualparam.h | 10 +- indra/newview/llvoavatar.cpp | 2368 ++++--------- indra/newview/llvoavatar.h | 259 +- indra/newview/llvoavatarself.cpp | 1952 +++++++++- indra/newview/llvoavatarself.h | 228 ++ indra/newview/llwearable.cpp | 704 +++- indra/newview/llwearable.h | 63 +- indra/newview/llwearablelist.cpp | 19 +- indra/newview/llwearablelist.h | 4 +- indra/newview/llwearabletype.cpp | 7 +- indra/newview/rlvhandler.cpp | 2 +- indra/newview/rlvhelper.cpp | 88 +- indra/newview/rlvinventory.cpp | 10 - indra/newview/rlvinventory.h | 1 - indra/newview/rlvlocks.cpp | 12 +- indra/newview/rlvviewer2.cpp | 102 - indra/newview/rlvviewer2.h | 31 - .../default/xui/en-us/menu_inventory.xml | 6 +- .../skins/default/xui/en-us/notifications.xml | 25 + .../skins/default/xui/en-us/strings.xml | 14 + 94 files changed, 15690 insertions(+), 8311 deletions(-) delete mode 100644 indra/newview/cofmgr.cpp delete mode 100644 indra/newview/cofmgr.h create mode 100644 indra/newview/llagentwearablesfetch.cpp create mode 100644 indra/newview/llagentwearablesfetch.h create mode 100644 indra/newview/llappearancemgr.cpp create mode 100644 indra/newview/llappearancemgr.h create mode 100644 indra/newview/lllocaltextureobject.cpp create mode 100644 indra/newview/lllocaltextureobject.h create mode 100644 indra/newview/lloutfitobserver.cpp create mode 100644 indra/newview/lloutfitobserver.h create mode 100644 indra/newview/lltexglobalcolor.cpp create mode 100644 indra/newview/lltexglobalcolor.h create mode 100644 indra/newview/lltexlayerparams.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8fcbe7054..ea59c495f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -84,7 +84,6 @@ set(viewer_SOURCE_FILES lggdicdownload.cpp floaterao.cpp floatervoicelicense.cpp - cofmgr.cpp lldaycyclemanager.cpp llenvmanager.cpp llwlhandlers.cpp @@ -121,7 +120,9 @@ set(viewer_SOURCE_FILES llagentpilot.cpp llagentui.cpp llagentwearables.cpp + llagentwearablesfetch.cpp llanimstatelabels.cpp + llappearancemgr.cpp llappviewer.cpp llassetconverter.cpp llassetuploadresponders.cpp @@ -307,6 +308,7 @@ set(viewer_SOURCE_FILES llinventorypanel.cpp lljoystickbutton.cpp lllandmarklist.cpp + lllocaltextureobject.cpp lllocalinventory.cpp lllogchat.cpp llloginhandler.cpp @@ -328,6 +330,7 @@ set(viewer_SOURCE_FILES llnamelistctrl.cpp llnetmap.cpp llnotify.cpp + lloutfitobserver.cpp lloverlaybar.cpp llpanelaudioprefs.cpp llpanelaudiovolume.cpp @@ -410,7 +413,9 @@ set(viewer_SOURCE_FILES llstylemap.cpp llsurface.cpp llsurfacepatch.cpp + lltexglobalcolor.cpp lltexlayer.cpp + lltexlayerparams.cpp lltexturecache.cpp lltexturectrl.cpp lltexturefetch.cpp @@ -568,7 +573,6 @@ set(viewer_HEADER_FILES aoremotectrl.h floaterao.h floatervoicelicense.h - cofmgr.h lldaycyclemanager.h llenvmanager.h llwlhandlers.h @@ -605,8 +609,10 @@ set(viewer_HEADER_FILES llagentpilot.h llagentui.h llagentwearables.h + llagentwearablesfetch.h llanimstatelabels.h llappearance.h + llappearancemgr.h llappviewer.h llassetconverter.h llassetuploadresponders.h @@ -793,6 +799,7 @@ set(viewer_HEADER_FILES lljoystickbutton.h lllandmarklist.h lllightconstants.h + lllocaltextureobject.h lllocalinventory.h lllogchat.h llloginhandler.h @@ -814,6 +821,7 @@ set(viewer_HEADER_FILES llnamelistctrl.h llnetmap.h llnotify.h + lloutfitobserver.h lloverlaybar.h llpanelaudioprefs.h llpanelaudiovolume.h @@ -899,7 +907,9 @@ set(viewer_HEADER_FILES llsurface.h llsurfacepatch.h lltable.h + lltexglobalcolor.h lltexlayer.h + lltexlayerparams.h lltexturecache.h lltexturectrl.h lltexturefetch.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0b4e7c630..6468e8ce3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2052,6 +2052,28 @@ Value 2 + AvatarBakedTextureUploadTimeout + + Comment + Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution. + Persist + 1 + Type + U32 + Value + 60 + + AvatarBakedLocalTextureUpdateTimeout + + Comment + Specifes the maximum time in seconds to wait before updating your appearance during appearance mode. + Persist + 1 + Type + U32 + Value + 10 + AvatarPhysics Comment @@ -3948,8 +3970,30 @@ Type String Value - + + DebugAvatarRezTime + + Comment + Display times for avatars to resolve. + Persist + 1 + Type + Boolean + Value + 0 + + DebugAvatarLocalTexLoadedTime + + Comment + Display time for loading avatar local textures. + Persist + 1 + Type + Boolean + Value + 0 + DebugBeaconLineWidth Comment @@ -6773,6 +6817,17 @@ Value 0 + ForceAssetFail + + Comment + Force wearable fetches to fail for this asset type. + Persist + 1 + Type + U32 + Value + 255 + ForceShowGrid Comment @@ -8013,6 +8068,17 @@ Value 128.0 + MaxWearableWaitTime + + Comment + Max seconds to wait for wearable assets to fetch. + Persist + 1 + Type + F32 + Value + 60.0 + MeanCollisionBump Comment @@ -8473,8 +8539,19 @@ Type Boolean Value - 1 + 0 + MyOutfitsAutofill + + Comment + Always autofill My Outfits from library when empty (else happens just once). + Persist + 1 + Type + Boolean + Value + 0 + NearMeRange Comment @@ -14747,6 +14824,17 @@ Value 1 + OutfitOperationsTimeout + + Comment + Timeout for outfit related operations. + Persist + 1 + Type + S32 + Value + 180 + UseHTTPInventory Comment diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 4ad68ee8d..6d659e2d0 100755 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -6387,8 +6387,6 @@ - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/indra/newview/cofmgr.cpp b/indra/newview/cofmgr.cpp deleted file mode 100644 index 2b7da5ddf..000000000 --- a/indra/newview/cofmgr.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/** - * - * Copyright (c) 2010, Kitty Barnett - * - * The source code in this file is provided to you under the terms of the - * GNU General Public License, version 2.0, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. Terms of the GPL can be found in doc/GPL-license.txt - * in this distribution, or online at http://www.gnu.org/licenses/gpl-2.0.txt - * - * By copying, modifying or distributing this software, you acknowledge that - * you have read and understood your obligations described above, and agree to - * abide by those obligations. - * - */ - -#include "llviewerprecompiledheaders.h" -#include "cofmgr.h" -#include "llagent.h" -#include "llagentwearables.h" -#include "llcommonutils.h" -#include "llerror.h" -#include "llinventoryfunctions.h" -#include "llinventoryobserver.h" -#include "llvoavatarself.h" -#include "rlvviewer2.h" - -// ============================================================================ -// Inventory helper classes -// - -class LLCOFLinkTargetFetcher : public LLInventoryFetchItemsObserver -{ -public: - LLCOFLinkTargetFetcher(const uuid_vec_t& idItems) : LLInventoryFetchItemsObserver(idItems) {} - /*virtual*/ ~LLCOFLinkTargetFetcher() {} - - /*virtual*/ void done() - { - // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() - doOnIdleOneTime(boost::bind(&LLCOFLinkTargetFetcher::doneIdle, this)); - gInventory.removeObserver(this); - } - - void doneIdle() - { - LLCOFMgr::instance().checkCOF(); - LLCOFMgr::instance().setLinkAttachments(true); - LLCOFMgr::instance().updateAttachments(); - LLCOFMgr::instance().synchWearables(); - - delete this; - } -}; - -class LLCOFFetcher : public LLInventoryFetchDescendentsObserver -{ -public: - LLCOFFetcher(const LLUUID& cat_id) : LLInventoryFetchDescendentsObserver(cat_id) {} - /*virtual*/ ~LLCOFFetcher() {} - - /*virtual*/ void done() - { - // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() - doOnIdleOneTime(boost::bind(&LLCOFFetcher::doneIdle, this)); - gInventory.removeObserver(this); - } - - void doneIdle() - { - uuid_vec_t idItems; - - // Add the link targets for COF - LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; - gInventory.collectDescendents(LLCOFMgr::getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH); - for (S32 idxItem = 0; idxItem < items.count(); idxItem++) - { - const LLViewerInventoryItem* pItem = items.get(idxItem); - if (!pItem) - continue; - idItems.push_back(pItem->getLinkedUUID()); - } - - // Add all currently worn wearables - for (S32 idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) - { - const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType,0); // TODO: MULTI-WEARABLE - if (idItem.isNull()) - continue; - idItems.push_back(idItem); - } - - // Add all currently worn attachments - const LLVOAvatar* pAvatar = gAgentAvatarp; - if (pAvatar) - { - for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = pAvatar->mAttachmentPoints.begin(); - itAttachPt != pAvatar->mAttachmentPoints.end(); ++itAttachPt) - { - const LLViewerJointAttachment* pAttachPt = itAttachPt->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachment = pAttachPt->mAttachedObjects.begin(); - itAttachment != pAttachPt->mAttachedObjects.end(); ++itAttachment) - { - const LLUUID& idItem = (*itAttachment)->getAttachmentItemID(); - if (idItem.isNull()) - continue; - idItems.push_back(idItem); - } - } - } - - // Fetch it all - LLCOFLinkTargetFetcher* pFetcher = new LLCOFLinkTargetFetcher(idItems); - pFetcher->startFetch(); - if (pFetcher->isFinished()) - { - pFetcher->done(); - } - else - { - gInventory.addObserver(pFetcher); - - // It doesn't look like we *really* need the link targets so we can do a preliminary initialization now already - LLCOFMgr::instance().setLinkAttachments(true); - LLCOFMgr::instance().updateAttachments(); - } - - delete this; - } -}; - -class LLDeferredAddLinkTargetFetcher : public LLInventoryFetchItemsObserver -{ -public: - LLDeferredAddLinkTargetFetcher(const LLUUID& idItem, LLPointer cb) - : LLInventoryFetchItemsObserver(idItem), m_Callback(cb) - {} - LLDeferredAddLinkTargetFetcher(const uuid_vec_t& idItems, LLPointer cb) - : LLInventoryFetchItemsObserver(idItems), m_Callback(cb) - {} - /*virtual*/ ~LLDeferredAddLinkTargetFetcher() {} - - /*virtual*/ void done() - { - // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() - doOnIdleOneTime(boost::bind(&LLDeferredAddLinkTargetFetcher::doneIdle, this)); - gInventory.removeObserver(this); - } - - void doneIdle() - { - for (uuid_vec_t::const_iterator itItemId = mComplete.begin(); itItemId != mComplete.end(); ++itItemId) - { - const LLViewerInventoryItem* pItem = gInventory.getItem(*itItemId); - if (!pItem) - continue; - LLCOFMgr::instance().addCOFItemLink(pItem, m_Callback); - } - delete this; - } -protected: - LLPointer m_Callback; -}; - -class LLLinkAttachmentCallback : public LLInventoryCallback -{ -public: - LLLinkAttachmentCallback() {} - /*virtual*/ ~LLLinkAttachmentCallback() {} - /*virtual*/ void fire(const LLUUID& idItem) { LLCOFMgr::instance().onLinkAttachmentComplete(idItem); } -}; - -class LLLinkWearableCallback : public LLInventoryCallback -{ -public: - LLLinkWearableCallback() {} - /*virtual*/ ~LLLinkWearableCallback() {} - /*virtual*/ void fire(const LLUUID& idItem) { LLCOFMgr::instance().onLinkWearableComplete(idItem); } -}; - -// ============================================================================ -// Helper functions -// - -void LLCOFMgr::checkCOF() -{ - const LLUUID idCOF = getCOF(); - const LLUUID idLAF = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - - // Check COF for non-links and move them to Lost&Found - LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; - gInventory.getDirectDescendentsOf(idCOF, pFolders, pItems); - for (S32 idxFolder = 0, cntFolder = pFolders->count(); idxFolder < cntFolder; idxFolder++) - { - LLViewerInventoryCategory* pFolder = pFolders->get(idxFolder).get(); - if ( (pFolder) && (idLAF.notNull()) ) - change_category_parent(&gInventory, pFolder, idLAF, false); - } - for (S32 idxItem = 0, cntItem = pItems->count(); idxItem < cntItem; idxItem++) - { - LLViewerInventoryItem* pItem = pItems->get(idxItem).get(); - if ( (pItem) && (!pItem->getIsLinkType()) && (idLAF.notNull()) ) - change_item_parent(&gInventory, pItem, idLAF, false); - } -} - -void LLCOFMgr::fetchCOF() -{ - static bool sFetched = false; - if (!sFetched) - { - const LLUUID idCOF = getCOF(); - if (idCOF.isNull()) - { - LL_ERRS("COFMgr") << "Unable to find (or create) COF" << LL_ENDL; - return; - } - - LLCOFFetcher* pFetcher = new LLCOFFetcher(idCOF); - pFetcher->startFetch(); - if (pFetcher->isFinished()) - pFetcher->done(); - else - gInventory.addObserver(pFetcher); - - sFetched = true; - } -} - -void LLCOFMgr::getDescendentsOfAssetType(const LLUUID& idCat, LLInventoryModel::item_array_t& items, - LLAssetType::EType typeAsset, bool fFollowFolderLinks) -{ - LLInventoryModel::cat_array_t folders; - LLIsType f(typeAsset); - gInventory.collectDescendentsIf(idCat, folders, items, LLInventoryModel::EXCLUDE_TRASH, f, fFollowFolderLinks); -} - -void LLCOFMgr::addCOFItemLink(const LLUUID& idItem, LLPointer cb) -{ - const LLViewerInventoryItem *pItem = gInventory.getItem(idItem); - if (!pItem) - { - LLDeferredAddLinkTargetFetcher* pFetcher = new LLDeferredAddLinkTargetFetcher(idItem, cb); - pFetcher->startFetch(); - gInventory.addObserver(pFetcher); - return; - } - addCOFItemLink(pItem, cb); -} - -void LLCOFMgr::addCOFItemLink(const LLInventoryItem* pItem, LLPointer cb) -{ - if ( (!pItem) || (isLinkInCOF(pItem->getLinkedUUID())) ) - { - return; - } - - gInventory.addChangedMask(LLInventoryObserver::LABEL, pItem->getLinkedUUID()); - - const std::string strDescr = (pItem->getIsLinkType()) ? pItem->getDescription() : ""; - link_inventory_item(gAgent.getID(), pItem->getLinkedUUID(), getCOF(), pItem->getName(), strDescr, LLAssetType::AT_LINK, cb); -} - -bool LLCOFMgr::isLinkInCOF(const LLUUID& idItem) const -{ - LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; - LLLinkedItemIDMatches f(gInventory.getLinkedItemID(idItem)); - gInventory.collectDescendentsIf(getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH, f); - return (!items.empty()); -} - -void LLCOFMgr::removeCOFItemLinks(const LLUUID& idItem) -{ - gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); - - LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; - gInventory.collectDescendents(getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH); - - for (S32 idxItem = 0; idxItem < items.count(); idxItem++) - { - const LLInventoryItem* pItem = items.get(idxItem).get(); - if ( (pItem->getIsLinkType()) && (idItem == pItem->getLinkedUUID()) ) - gInventory.purgeObject(pItem->getUUID()); - } -} - -BOOL LLCOFMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const -{ - if (!isLinkInCOF(obj_id)) return FALSE; - - // If a non-link somehow ended up in COF, allow deletion. - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (obj && !obj->getIsLinkType()) - { - return FALSE; - } - - // For now, don't allow direct deletion from the COF. Instead, force users - // to choose "Detach" or "Take Off". - return TRUE; - /* - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (!obj) return FALSE; - - // Can't delete bodyparts, since this would be equivalent to removing the item. - if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; - - // Can't delete the folder link, since this is saved for bookkeeping. - if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; - - return FALSE; - */ -} - -// ============================================================================ -// Attachment functions -// - -void LLCOFMgr::addAttachment(const LLUUID& idItem) -{ - if ( (isLinkInCOF(idItem)) || (std::find(m_PendingAttachLinks.begin(), m_PendingAttachLinks.end(), idItem) != m_PendingAttachLinks.end()) ) - { - return; - } - - gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); - m_PendingAttachLinks.push_back(idItem); - - if (m_fLinkAttachments) - { - LLPointer cb = new LLLinkAttachmentCallback(); - addCOFItemLink(idItem, cb); - } -} - -void LLCOFMgr::removeAttachment(const LLUUID& idItem) -{ - gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); - - // Remove the attachment from the pending list - uuid_vec_t::iterator itPending = std::find(m_PendingAttachLinks.begin(), m_PendingAttachLinks.end(), idItem); - if (itPending != m_PendingAttachLinks.end()) - m_PendingAttachLinks.erase(itPending); - - if (m_fLinkAttachments) - { - removeCOFItemLinks(idItem); - } -} - -void LLCOFMgr::setLinkAttachments(bool fEnable) -{ - m_fLinkAttachments = fEnable; - - if (m_fLinkAttachments) - linkPendingAttachments(); -} - -void LLCOFMgr::linkPendingAttachments() -{ - LLPointer cb = NULL; - for (uuid_vec_t::const_iterator itPending = m_PendingAttachLinks.begin(); itPending != m_PendingAttachLinks.end(); ++itPending) - { - const LLUUID& idAttachItem = *itPending; - if ( (gAgentAvatarp->isWearingAttachment(idAttachItem)) && (!isLinkInCOF(idAttachItem)) ) - { - if (!cb) - cb = new LLLinkAttachmentCallback(); - addCOFItemLink(idAttachItem, cb); - } - } -} - -void LLCOFMgr::onLinkAttachmentComplete(const LLUUID& idItem) -{ - const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); - - // Remove the attachment from the pending list - uuid_vec_t::iterator itPending = std::find(m_PendingAttachLinks.begin(), m_PendingAttachLinks.end(), idItemBase); - if (itPending != m_PendingAttachLinks.end()) - m_PendingAttachLinks.erase(itPending); - - // It may have been detached already in which case we should remove the COF link - if ( (gAgentAvatarp) && (!gAgentAvatarp->isWearingAttachment(idItemBase)) ) - removeCOFItemLinks(idItemBase); -} - -void LLCOFMgr::updateAttachments() -{ - /*const*/ LLVOAvatar* pAvatar = gAgentAvatarp; - if (!pAvatar) - return; - - const LLUUID idCOF = getCOF(); - - // Grab all attachment links currently in COF - LLInventoryModel::item_array_t items; - getDescendentsOfAssetType(idCOF, items, LLAssetType::AT_OBJECT, true); - - // Include attachments which should be in COF but don't have their link created yet - uuid_vec_t::iterator itPendingAttachLink = m_PendingAttachLinks.begin(); - while (itPendingAttachLink != m_PendingAttachLinks.end()) - { - const LLUUID& idItem = *itPendingAttachLink; - if ( (!pAvatar->isWearingAttachment(idItem)) || (isLinkInCOF(idItem)) ) - { - itPendingAttachLink = m_PendingAttachLinks.erase(itPendingAttachLink); - continue; - } - - LLViewerInventoryItem* pItem = gInventory.getItem(idItem); - if (pItem) - items.push_back(pItem); - - ++itPendingAttachLink; - } - - // Don't remove attachments until avatar is fully loaded (should reduce random attaching/detaching/reattaching at log-on) - LLAgentWearables::userUpdateAttachments(items, !pAvatar->isFullyLoaded()); -} - -// ============================================================================ -// Wearable functions -// - -void LLCOFMgr::addWearable(const LLUUID& idItem) -{ - if ( (isLinkInCOF(idItem)) || (std::find(m_PendingWearableLinks.begin(), m_PendingWearableLinks.end(), idItem) != m_PendingWearableLinks.end()) ) - { - return; - } - - gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); - m_PendingWearableLinks.push_back(idItem); - - LLPointer cb = new LLLinkWearableCallback(); - addCOFItemLink(idItem, cb); -} - -void LLCOFMgr::removeWearable(const LLUUID& idItem) -{ - gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); - - // Remove the attachment from the pending list - uuid_vec_t::iterator itPending = std::find(m_PendingWearableLinks.begin(), m_PendingWearableLinks.end(), idItem); - if (itPending != m_PendingWearableLinks.end()) - m_PendingWearableLinks.erase(itPending); - - removeCOFItemLinks(idItem); -} - -void LLCOFMgr::onLinkWearableComplete(const LLUUID& idItem) -{ - const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); - - // Remove the attachment from the pending list - uuid_vec_t::iterator itPending = std::find(m_PendingWearableLinks.begin(), m_PendingWearableLinks.end(), idItemBase); - if (itPending != m_PendingWearableLinks.end()) - m_PendingWearableLinks.erase(itPending); - - // It may have been removed already in which case we should remove the COF link - if (!gAgentWearables.isWearingItem(idItemBase)) - removeCOFItemLinks(idItemBase); -} - -void LLCOFMgr::synchWearables() -{ - const LLUUID idCOF = getCOF(); - - // Grab all wearable links currently in COF - LLInventoryModel::item_array_t items; - getDescendentsOfAssetType(idCOF, items, LLAssetType::AT_BODYPART, true); - getDescendentsOfAssetType(idCOF, items, LLAssetType::AT_CLOTHING, true); - - // Transform collection of link LLViewerInventory pointers into collection of target LLUUIDs - uuid_vec_t curItems; - for (S32 idxItem = 0; idxItem < items.count(); idxItem++) - { - const LLViewerInventoryItem* pItem = items.get(idxItem); - if (!pItem) - continue; - curItems.push_back(pItem->getLinkedUUID()); - } - - // Grab the item UUIDs of all currently worn wearables - uuid_vec_t newItems; - for (S32 idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) - { - const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType, 0); // TODO: MULTI-WEARABLE - if (idItem.isNull()) - continue; - newItems.push_back(idItem); - } - - uuid_vec_t addItems, remItems; - LLCommonUtils::computeDifference(newItems, curItems, addItems, remItems); - - // Add links for worn wearables that aren't linked yet - for (uuid_vec_t::const_iterator itItem = addItems.begin(); itItem != addItems.end(); ++itItem) - addWearable(*itItem); - - // Remove links of wearables that aren't worn anymore - for (uuid_vec_t::const_iterator itItem = remItems.begin(); itItem != remItems.end(); ++itItem) - removeWearable(*itItem); -} - -// ============================================================================ -// Base outfit folder functions -// - -void LLCOFMgr::addBOFLink(const LLUUID &idFolder, LLPointer cb) -{ - purgeBOFLink(); - - const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder); - if ( (pFolder) && (LLFolderType::FT_OUTFIT == pFolder->getPreferredType()) ) - link_inventory_item(gAgent.getID(), idFolder, getCOF(), pFolder->getName(), "", LLAssetType::AT_LINK_FOLDER, cb); -} - -void LLCOFMgr::purgeBOFLink() -{ - LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; - gInventory.getDirectDescendentsOf(getCOF(), pFolders, pItems); - for (S32 idxItem = 0, cntItem = pItems->count(); idxItem < cntItem; idxItem++) - { - const LLViewerInventoryItem* pItem = pItems->get(idxItem).get(); - if ( (!pItem) || (LLAssetType::AT_LINK_FOLDER != pItem->getActualType()) ) - continue; - - const LLViewerInventoryCategory* pLinkFolder = pItem->getLinkedCategory(); - if ( (pLinkFolder) && (LLFolderType::FT_OUTFIT == pLinkFolder->getPreferredType()) ) - gInventory.purgeObject(pItem->getUUID()); - } -} - -// ============================================================================ diff --git a/indra/newview/cofmgr.h b/indra/newview/cofmgr.h deleted file mode 100644 index 50d812c68..000000000 --- a/indra/newview/cofmgr.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * - * Copyright (c) 2010, Kitty Barnett - * - * The source code in this file is provided to you under the terms of the - * GNU General Public License, version 2.0, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. Terms of the GPL can be found in doc/GPL-license.txt - * in this distribution, or online at http://www.gnu.org/licenses/gpl-2.0.txt - * - * By copying, modifying or distributing this software, you acknowledge that - * you have read and understood your obligations described above, and agree to - * abide by those obligations. - * - */ - -#include "llinventorymodel.h" -#include "llmemory.h" -#include "llviewerinventory.h" - -// ============================================================================ - -class LLCOFMgr : public LLSingleton -{ - /* - * Helper functions - */ -public: - void checkCOF(); - void fetchCOF(); - static const LLUUID getCOF() { return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); } - static void getDescendentsOfAssetType(const LLUUID& idCat, LLInventoryModel::item_array_t& items, - LLAssetType::EType typeAsset, bool fFollowFolderLinks); - bool isLinkInCOF(const LLUUID& idItem) const; - BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const; -protected: - void addCOFItemLink(const LLUUID& idItem, LLPointer cb = NULL); - void addCOFItemLink(const LLInventoryItem* pItem, LLPointer cb = NULL); - void removeCOFItemLinks(const LLUUID& idItem); - - /* - * Attachment functions - */ -public: - void addAttachment(const LLUUID& idItem); - void removeAttachment(const LLUUID& idItem); - void synchAttachments(); -protected: - void onLinkAttachmentComplete(const LLUUID& idItem); - void linkPendingAttachments(); - void setLinkAttachments(bool fEnable); - void updateAttachments(); - - /* - * Wearable functions - */ -public: - void addWearable(const LLUUID& idItem); - void removeWearable(const LLUUID& idItem); - void synchWearables(); -protected: - void onLinkWearableComplete(const LLUUID& idItem); - - /* - * Base outfit folder functions - */ -public: - void addBOFLink(const LLUUID& idFolder, LLPointer cb = NULL); - void purgeBOFLink(); - - /* - * Member variables - */ -protected: - bool m_fLinkAttachments; - uuid_vec_t m_PendingAttachLinks; - uuid_vec_t m_PendingWearableLinks; - -protected: - LLCOFMgr() : m_fLinkAttachments(false) {} -private: - friend class LLCOFFetcher; - friend class LLCOFLinkTargetFetcher; - friend class LLDeferredAddLinkTargetFetcher; - friend class LLLinkAttachmentCallback; - friend class LLLinkWearableCallback; - friend class LLSingleton; -}; - -// ============================================================================ diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 8471710f0..f1dac09f8 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3831,12 +3831,11 @@ void LLAgent::sendAgentSetAppearance() { if (!isAgentAvatarValid()) return; - if (gAgentQueryManager.mNumPendingQueries > 0 && (isAgentAvatarValid() && !gAgentCamera.cameraCustomizeAvatar())) + if (gAgentQueryManager.mNumPendingQueries > 0 && (isAgentAvatarValid() && gAgentAvatarp->isUsingBakedTextures())) { return; } - llinfos << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << llendl; //dumpAvatarTEs( "sendAgentSetAppearance()" ); @@ -3866,7 +3865,7 @@ void LLAgent::sendAgentSetAppearance() // is texture data current relative to wearables? // KLW - TAT this will probably need to check the local queue. - BOOL textures_current = !gAgentAvatarp->hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded(); + BOOL textures_current = gAgentAvatarp->areTexturesCurrent(); for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) { @@ -3878,8 +3877,8 @@ void LLAgent::sendAgentSetAppearance() continue; } - // IMG_DEFAULT_AVATAR means not baked - if (!gAgentAvatarp->isTextureDefined(texture_index)) + // IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures + if (!gAgentAvatarp->isTextureDefined(texture_index, 0)) { textures_current = FALSE; break; @@ -3892,12 +3891,17 @@ void LLAgent::sendAgentSetAppearance() llinfos << "TAT: Sending cached texture data" << llendl; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { + BOOL generate_valid_hash = TRUE; + if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLVOAvatarDefines::EBakedTextureIndex)baked_index)) + { + generate_valid_hash = FALSE; + llinfos << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << llendl; + } - const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, true); + const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); if (hash.notNull()) { - const ETextureIndex texture_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - + ETextureIndex texture_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index); msg->nextBlockFast(_PREHASH_WearableData); msg->addUUIDFast(_PREHASH_CacheID, hash); msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index a8afd7f71..9966d07e3 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -36,21 +36,26 @@ #include "llagent.h" #include "llagentcamera.h" +#include "llagentwearablesfetch.h" +#include "llappearancemgr.h" #include "llcallbacklist.h" #include "llfolderview.h" #include "llgesturemgr.h" #include "llinventorybridge.h" -#include "llfloaterinventory.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" #include "llinventorypanel.h" +#include "llpanelmaininventory.h" #include "llmd5.h" #include "llnotificationsutil.h" +#include "lloutfitobserver.h" #include "lltexlayer.h" +#include "lltooldraganddrop.h" #include "llviewerregion.h" #include "llvoavatarself.h" #include "llwearable.h" #include "llwearablelist.h" -#include "cofmgr.h" #include "llfloatercustomize.h" @@ -69,8 +74,110 @@ LLAgentWearables gAgentWearables; BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; using namespace LLVOAvatarDefines; + +/////////////////////////////////////////////////////////////////////////////// + +// Callback to wear and start editing an item that has just been created. +class LLWearAndEditCallback : public LLInventoryCallback +{ + void fire(const LLUUID& inv_item) + { + if (inv_item.isNull()) return; + + // Request editing the item after it gets worn. + gAgentWearables.requestEditingWearable(inv_item); + + // Wear it. + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item); + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +// HACK: For EXT-3923: Pants item shows in inventory with skin icon and messes with "current look" +// Some db items are corrupted, have inventory flags = 0, implying wearable type = shape, even though +// wearable type stored in asset is some other value. +// Calling this function whenever a wearable is added to increase visibility if this problem +// turns up in other inventories. +void checkWearableAgainstInventory(LLWearable *wearable) +{ + if (wearable->getItemID().isNull()) + return; + + // Check for wearable type consistent with inventory item wearable type. + LLViewerInventoryItem *item = gInventory.getItem(wearable->getItemID()); + if (item) + { + if (!item->isWearableType()) + { + llwarns << "wearable associated with non-wearable item" << llendl; + } + if (item->getWearableType() != wearable->getType()) + { + llwarns << "type mismatch: wearable " << wearable->getName() + << " has type " << wearable->getType() + << " but inventory item " << item->getName() + << " has type " << item->getWearableType() << llendl; + } + } + else + { + llwarns << "wearable inventory item not found" << wearable->getName() + << " itemID " << wearable->getItemID().asString() << llendl; + } +} + +void LLAgentWearables::dump() +{ + llinfos << "LLAgentWearablesDump" << llendl; + for (S32 i = 0; i < LLWearableType::WT_COUNT; i++) + { + U32 count = getWearableCount((LLWearableType::EType)i); + llinfos << "Type: " << i << " count " << count << llendl; + for (U32 j=0; jgetName() + << " description " << wearable->getDescription() << llendl; + + } + } + llinfos << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << llendl; + for (std::set::iterator it = mItemsAwaitingWearableUpdate.begin(); + it != mItemsAwaitingWearableUpdate.end(); + ++it) + { + llinfos << (*it).asString() << llendl; + } +} + +struct LLAgentDumper +{ + LLAgentDumper(std::string name): + mName(name) + { + llinfos << llendl; + llinfos << "LLAgentDumper " << mName << llendl; + gAgentWearables.dump(); + } + + ~LLAgentDumper() + { + llinfos << llendl; + llinfos << "~LLAgentDumper " << mName << llendl; + gAgentWearables.dump(); + } + + std::string mName; +}; + LLAgentWearables::LLAgentWearables() : mWearablesLoaded(FALSE) +, mCOFChangeInProgress(false) { } @@ -86,15 +193,20 @@ void LLAgentWearables::cleanup() // static void LLAgentWearables::initClass() { + // this can not be called from constructor because its instance is global and is created too early. + // Subscribe to "COF is Saved" signal to notify observers about this (Loading indicator for ex.). + LLOutfitObserver::instance().addCOFSavedCallback(boost::bind(&LLAgentWearables::notifyLoadingFinished, &gAgentWearables)); } void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) { if (avatar) { + avatar->outputRezTiming("Sending wearables request"); sendAgentWearablesRequest(); } } + // wearables LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() { @@ -125,7 +237,7 @@ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInvento mTodo(todo), mCB(cb) { - llassert_always(index == 0); + //llassert_always(index == 0); llinfos << "constructor" << llendl; } @@ -147,6 +259,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i } if (mTodo & CALL_RECOVERDONE) { + LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); gAgentWearables.recoverMissingWearableDone(); } /* @@ -154,12 +267,17 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i */ if (mTodo & CALL_CREATESTANDARDDONE) { + LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); gAgentWearables.createStandardWearablesDone(mType, mIndex); } if (mTodo & CALL_MAKENEWOUTFITDONE) { gAgentWearables.makeNewOutfitDone(mType, mIndex); } + if (mTodo & CALL_WEARITEM) + { + LLAppearanceMgr::instance().addCOFItemLink(inv_item, true); + } } void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::EType type, @@ -167,7 +285,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy const LLUUID& item_id, LLWearable* wearable) { - llassert_always(index == 0); + //llassert_always(index == 0); llinfos << "type " << type << " index " << index << " item " << item_id.asString() << llendl; @@ -240,9 +358,6 @@ void LLAgentWearables::sendAgentWearablesUpdate() // Then make sure the inventory is in sync with the avatar. gInventory.notifyObservers(); - // This isn't the proper place to be doing this, but it's a good "catch-all" - LLCOFMgr::instance().synchWearables(); - // Send the AgentIsNowWearing gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); @@ -287,19 +402,24 @@ void LLAgentWearables::sendAgentWearablesUpdate() void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, const std::string new_name) { - llassert_always(index == 0); + //llassert_always(index == 0); LLWearable* old_wearable = getWearable(type, index); if(!old_wearable) return; bool name_changed = !new_name.empty() && (new_name != old_wearable->getName()); if (name_changed || old_wearable->isDirty() || old_wearable->isOldVersion()) { LLUUID old_item_id = old_wearable->getItemID(); - LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( old_wearable ); + LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()? setWearable(type,index,new_wearable); + // old_wearable may still be referred to by other inventory items. Revert + // unsaved changes so other inventory items aren't affected by the changes + // that were just saved. + old_wearable->revertValues(); + LLInventoryItem* item = gInventory.getItem(old_item_id); - if( item ) + if (item) { std::string item_name = item->getName(); if (name_changed) @@ -361,7 +481,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, const std::string& new_name, BOOL save_in_lost_and_found) { - llassert_always(index == 0); + //llassert_always(index == 0); if (!isWearableCopyable(type, index)) { llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; @@ -382,7 +502,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, } std::string trunc_name(new_name); LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN); - LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( + LLWearable* new_wearable = LLWearableList::instance().createCopy( old_wearable, trunc_name); LLPointer cb = @@ -391,7 +511,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, type, index, new_wearable, - addWearableToAgentInventoryCallback::CALL_UPDATE); + addWearableToAgentInventoryCallback::CALL_WEARITEM); LLUUID category_id; if (save_in_lost_and_found) { @@ -412,72 +532,28 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, new_name, cb); -/* - LLWearable* old_wearable = getWearable( type ); - if( old_wearable ) - { - std::string old_name = old_wearable->getName(); - old_wearable->setName( new_name ); - LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( old_wearable ); - old_wearable->setName( old_name ); - - LLUUID category_id; - LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID ); - if( item ) - { - new_wearable->setPermissions(item->getPermissions()); - if (save_in_lost_and_found) - { - category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); - } - else - { - // put in same folder as original - category_id = item->getParentUUID(); - } - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if(view) - { - view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO); - } - } - - mWearableEntry[ type ].mWearable = new_wearable; - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type, - addWearableToAgentInventoryCallback::CALL_UPDATE); - addWearableToAgentInventory(cb, new_wearable, category_id); - } -*/ + // old_wearable may still be referred to by other inventory items. Revert + // unsaved changes so other inventory items aren't affected by the changes + // that were just saved. + old_wearable->revertValues(); } -void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) +void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index, bool set_by_user) { - llassert_always(index == 0); + //llassert_always(index == 0); LLWearable* wearable = getWearable(type, index); llassert(wearable); - if( wearable ) + if (wearable) { - wearable->writeToAvatar( TRUE ); + wearable->revertValues(); } gAgent.sendAgentSetAppearance(); } -void LLAgentWearables::revertAllWearables() -{ - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) - { - for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) - revertWearable( (LLWearableType::EType)i, j); - } -} - void LLAgentWearables::saveAllWearables() { - //if(!gInventory.isLoaded()) + //if (!gInventory.isLoaded()) //{ // return; //} @@ -526,7 +602,7 @@ void LLAgentWearables::setWearableName( const LLUUID& item_id, const std::string BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const { - llassert_always(index == 0); + //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type, index); return item_id.notNull() ? isWearableModifiable(item_id) : FALSE; } @@ -548,7 +624,7 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const { - llassert_always(index == 0); + //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type, index); if (!item_id.isNull()) { @@ -562,16 +638,9 @@ BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) return FALSE; } -BOOL LLAgentWearables::areWearablesLoaded() const -{ - static const LLCachedControl rener_unloaded_avatar("RenderUnloadedAvatar"); - if(rener_unloaded_avatar) - return TRUE; - return mWearablesLoaded; -} - -/*U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) const -{ +/* + U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) + { LLUUID item_id = getWearableItemID(type); if(!item_id.isNull()) { @@ -587,7 +656,7 @@ BOOL LLAgentWearables::areWearablesLoaded() const LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index) { - llassert_always(index == 0); + //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type,index); LLInventoryItem* item = NULL; if(item_id.notNull()) @@ -665,7 +734,7 @@ BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type) LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index) { - llassert_always(index == 0); + //llassert_always(index == 0); wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -684,7 +753,7 @@ LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 void LLAgentWearables::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable) { - llassert_always(index == 0); + //llassert_always(index == 0); LLWearable *old_wearable = getWearable(type,index); if (!old_wearable) { @@ -708,6 +777,7 @@ void LLAgentWearables::setWearable(const LLWearableType::EType type, U32 index, wearable_vec[index] = wearable; old_wearable->setLabelUpdated(); wearableUpdated(wearable); + checkWearableAgainstInventory(wearable); } } @@ -723,6 +793,7 @@ U32 LLAgentWearables::pushWearable(const LLWearableType::EType type, LLWearable { mWearableDatas[type].push_back(wearable); wearableUpdated(wearable); + checkWearableAgainstInventory(wearable); return mWearableDatas[type].size()-1; } return MAX_CLOTHING_PER_TYPE; @@ -733,6 +804,22 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable) gAgentAvatarp->wearableUpdated(wearable->getType(), FALSE); wearable->refreshName(); wearable->setLabelUpdated(); + + wearable->pullCrossWearableValues(); + + // Hack pt 2. If the wearable we just loaded has definition version 24, + // then force a re-save of this wearable after slamming the version number to 22. + // This number was incorrectly incremented for internal builds before release, and + // this fix will ensure that the affected wearables are re-saved with the right version number. + // the versions themselves are compatible. This code can be removed before release. + if( wearable->getDefinitionVersion() == 24 ) + { + wearable->setDefinitionVersion(22); + U32 index = getWearableIndex(wearable); + llinfos << "forcing werable type " << wearable->getType() << " to version 22 from 24" << llendl; + saveWearable(wearable->getType(),index,TRUE); + } + } void LLAgentWearables::popWearable(LLWearable *wearable) @@ -754,7 +841,7 @@ void LLAgentWearables::popWearable(LLWearable *wearable) void LLAgentWearables::popWearable(const LLWearableType::EType type, U32 index) { - llassert_always(index == 0); + //llassert_always(index == 0); LLWearable *wearable = getWearable(type, index); if (wearable) { @@ -792,7 +879,7 @@ U32 LLAgentWearables::getWearableIndex(const LLWearable *wearable) const const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index) const { - llassert_always(index == 0); + //llassert_always(index == 0); wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -848,9 +935,19 @@ U32 LLAgentWearables::getWearableCount(const U32 tex_index) const } +BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const +{ + return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end(); +} + +U32 LLAgentWearables::itemUpdatePendingCount() const +{ + return mItemsAwaitingWearableUpdate.size(); +} + const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const { - llassert_always(index == 0); + //llassert_always(index == 0); const LLWearable *wearable = getWearable(type,index); if (wearable) return wearable->getItemID(); @@ -860,7 +957,7 @@ const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const { - llassert_always(index == 0); + //llassert_always(index == 0); const LLWearable *wearable = getWearable(type,index); if (wearable) return wearable->getAssetID(); @@ -868,10 +965,9 @@ const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U3 return LLUUID(); } -BOOL LLAgentWearables::isWearingItem( const LLUUID& item_id ) const +BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const { - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - return (getWearableFromItemID(base_item_id) != NULL); + return getWearableFromItemID(item_id) != NULL; } // MULTI-WEARABLE: DEPRECATED (see backwards compatibility) @@ -885,10 +981,21 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs // that may result from AgentWearablesRequest having been sent more than once. if (mInitialWearablesUpdateReceived) return; + + if (isAgentAvatarValid()) + { + gAgentAvatarp->outputRezTiming("Received initial wearables update"); + } + + // notify subscribers that wearables started loading. See EXT-7777 + // *TODO: find more proper place to not be called from deprecated method. + // Seems such place is found: LLInitialWearablesFetch::processContents() + gAgentWearables.notifyLoadingStarted(); + mInitialWearablesUpdateReceived = true; LLUUID agent_id; - gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); + gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) { @@ -899,19 +1006,27 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs if (num_wearables < NUM_BODY_PARTS) { // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). - // The fact that they don't have any here (only a dummy is sent) implies that this account existed - // before we had wearables, or that the database has gotten messed up. + // The fact that they don't have any here (only a dummy is sent) implies that either: + // 1. This account existed before we had wearables + // 2. The database has gotten messed up + // 3. This is the account's first login (i.e. the wearables haven't been generated yet). return; } + // Get the UUID of the current outfit folder (will be created if it doesn't exist) + const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id); + //lldebugs << "processAgentInitialWearablesUpdate()" << llendl; // Add wearables - std::pair asset_id_array[ LLWearableType::WT_COUNT ]; + // MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future. + gAgentWearables.mItemsAwaitingWearableUpdate.clear(); for (S32 i=0; i < num_wearables; i++) { + // Parse initial wearables data from message system U8 type_u8 = 0; - gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i ); - if( type_u8 >= LLWearableType::WT_COUNT ) + gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i); + if (type_u8 >= LLWearableType::WT_COUNT) { continue; } @@ -929,104 +1044,36 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs else { LLAssetType::EType asset_type = LLWearableType::getAssetType( type ); - if( asset_type == LLAssetType::AT_NONE ) + if (asset_type == LLAssetType::AT_NONE) { continue; } - - asset_id_array[type] = std::pair(asset_id,item_id); + + // MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions + + // Store initial wearables data until we know whether we have the current outfit folder or need to use the data. + LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); + outfit->add(wearable_data); } - - LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel(type) << " " << asset_id << " item id " << gAgentWearables.getWearableItemID(type, 0).asString() << LL_ENDL; + + lldebugs << " " << LLWearableType::getTypeLabel(type) << llendl; } - - LLCOFMgr::instance().fetchCOF(); - - // now that we have the asset ids...request the wearable assets - for(S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + + // Get the complete information on the items in the inventory and set up an observer + // that will trigger when the complete information is fetched. + outfit->startFetch(); + if(outfit->isFinished()) { - LL_DEBUGS("Wearables") << " fetching " << asset_id_array[i].first << LL_ENDL; - const LLUUID item_id = asset_id_array[i].second; - if( !item_id.isNull() ) - { - LLWearableList::instance().getAsset( - asset_id_array[i].first, - LLStringUtil::null, - LLWearableType::getAssetType( (LLWearableType::EType) i ), - LLAgentWearables::onInitialWearableAssetArrived, - //This scary cast is to prevent messing with llwearablelist. Since ItemIDs are now tied to wearables, - // we now need to pass the ids to onInitialWearableAssetArrived so LLWearable::setItemID can be called there. - (void*)(intptr_t)new std::pair((LLWearableType::EType)i,item_id) ); - } + // everything is already here - call done. + outfit->done(); } - - // Not really sure where else to put this - gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL); - } -} - -// A single wearable that the avatar was wearing on start-up has arrived from the database. -// static -void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void* userdata ) -{ - std::pair* wearable_data = (std::pair*)(intptr_t) userdata; - LLWearableType::EType type = wearable_data->first; - LLUUID item_id = wearable_data->second; - delete wearable_data; - - LLVOAvatar* avatar = gAgentAvatarp; - if( !avatar ) - { - return; - } - - if( wearable ) - { - llassert( type == wearable->getType() ); - wearable->setItemID(item_id); - gAgentWearables.setWearable(type,0,wearable); - - // disable composites if initial textures are baked - avatar->setupComposites(); - gAgentWearables.queryWearableCache(); - - wearable->writeToAvatar( FALSE ); - avatar->setCompositeUpdatesEnabled(TRUE); - gInventory.addChangedMask( LLInventoryObserver::LABEL, item_id ); - } - else - { - // Somehow the asset doesn't exist in the database. - gAgentWearables.recoverMissingWearable( type, 0 ); - } - - gInventory.notifyObservers(); - - // Have all the wearables that the avatar was wearing at log-in arrived? - if( !gAgentWearables.mWearablesLoaded ) - { - gAgentWearables.mWearablesLoaded = TRUE; - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + else { - if( !gAgentWearables.getWearableItemID((LLWearableType::EType)i, 0).isNull() && !gAgentWearables.getWearable((LLWearableType::EType)i, 0) ) - { - gAgentWearables.mWearablesLoaded = FALSE; - break; - } - } - } - - if( gAgentWearables.mWearablesLoaded ) - { - // Make sure that the server's idea of the avatar's wearables actually match the wearables. - gAgent.sendAgentSetAppearance(); - - // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time. - // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive. - if( !gAgentCamera.cameraCustomizeAvatar() ) - { - avatar->requestLayerSetUploads(); + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(outfit); } + } } @@ -1035,14 +1082,14 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void // the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.) void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) { - llassert_always(index == 0); + //llassert_always(index == 0); // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); lldebugs << "Wearable " << LLWearableType::getTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type); setWearable(type,index,new_wearable); - new_wearable->writeToAvatar( TRUE ); + //new_wearable->writeToAvatar( TRUE ); // Add a new one in the lost and found folder. // (We used to overwrite the "not found" one, but that could potentially @@ -1074,19 +1121,102 @@ void LLAgentWearables::recoverMissingWearableDone() } } -void LLAgentWearables::createStandardWearables(BOOL female) +void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index) { - llwarns << "Creating Standard " << (female ? "female" : "male" ) - << " Wearables" << llendl; + LLWearable* wearable = getWearable((LLWearableType::EType)wearable_type, wearable_index); + if (!wearable) + { + llerrs << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << llendl; + return; + } + LLLocalTextureObject lto; + wearable->setLocalTextureObject(texture_type, lto); +} + +class OnWearableItemCreatedCB: public LLInventoryCallback +{ +public: + OnWearableItemCreatedCB(): + mWearablesAwaitingItems(LLWearableType::WT_COUNT,NULL) + { + llinfos << "created callback" << llendl; + } + /* virtual */ void fire(const LLUUID& inv_item) + { + llinfos << "One item created " << inv_item.asString() << llendl; + LLViewerInventoryItem *item = gInventory.getItem(inv_item); + mItemsToLink.put(item); + updatePendingWearable(inv_item); + } + ~OnWearableItemCreatedCB() + { + llinfos << "All items created" << llendl; + LLPointer link_waiter = new LLUpdateAppearanceOnDestroy; + LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(), + mItemsToLink, + link_waiter); + } + void addPendingWearable(LLWearable *wearable) + { + if (!wearable) + { + llwarns << "no wearable" << llendl; + return; + } + LLWearableType::EType type = wearable->getType(); + if (typeisWearableType()) + { + llwarns << "non-wearable item found" << llendl; + return; + } + if (item && item->isWearableType()) + { + LLWearableType::EType type = item->getWearableType(); + if (type < LLWearableType::WT_COUNT) + { + LLWearable *wearable = mWearablesAwaitingItems[type]; + if (wearable) + wearable->setItemID(inv_item); + } + else + { + llwarns << "invalid wearable type " << type << llendl; + } + } + } + +private: + LLInventoryModel::item_array_t mItemsToLink; + std::vector mWearablesAwaitingItems; +}; + +void LLAgentWearables::createStandardWearables() +{ + llwarns << "Creating standard wearables" << llendl; if (!isAgentAvatarValid()) return; - gAgentAvatarp->setSex(female ? SEX_FEMALE : SEX_MALE); - const BOOL create[LLWearableType::WT_COUNT] = - { - TRUE, //WT_SHAPE - TRUE, //WT_SKIN + { + TRUE, //LLWearableType::WT_SHAPE + TRUE, //LLWearableType::WT_SKIN TRUE, //WT_HAIR TRUE, //WT_EYES TRUE, //WT_SHIRT @@ -1103,265 +1233,65 @@ void LLAgentWearables::createStandardWearables(BOOL female) FALSE, //WT_PHYSICS }; - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) + LLPointer cb = new OnWearableItemCreatedCB; + for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { - bool once = false; - LLPointer donecb = NULL; - if( create[i] ) + if (create[i]) { - if (!once) - { - once = true; - donecb = new createStandardWearablesAllDoneCallback; - } llassert(getWearableCount((LLWearableType::EType)i) == 0); LLWearable* wearable = LLWearableList::instance().createNewWearable((LLWearableType::EType)i); + ((OnWearableItemCreatedCB*)(&(*cb)))->addPendingWearable(wearable); // no need to update here... - LLPointer cb = - new addWearableToAgentInventoryCallback( - donecb, - (LLWearableType::EType)i, - 0, - wearable, - addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE); - addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE); + LLUUID category_id = LLUUID::null; + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + category_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + wearable->getAssetType(), + LLInventoryType::IT_WEARABLE, + wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); } } } + void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) { - LLWearable* wearable = getWearable((LLWearableType::EType)type, index); + llinfos << "type " << type << " index " << index << llendl; - if (wearable) - { - wearable->writeToAvatar(TRUE); - } + if (!isAgentAvatarValid()) return; + gAgentAvatarp->updateVisualParams(); } void LLAgentWearables::createStandardWearablesAllDone() { // ... because sendAgentWearablesUpdate will notify inventory // observers. + llinfos << "all done?" << llendl; + mWearablesLoaded = TRUE; + checkWearablesLoaded(); + notifyLoadingFinished(); + updateServer(); // Treat this as the first texture entry message, if none received yet gAgentAvatarp->onFirstTEMessageReceived(); } -void LLAgentWearables::makeNewOutfit( - const std::string& new_folder_name, - const LLDynamicArray& wearables_to_include, - const LLDynamicArray& attachments_to_include, - BOOL rename_clothing) -{ - if (!gAgentAvatarp) - { - return; - } - - BOOL fUseLinks = !gSavedSettings.getBOOL("UseInventoryLinks") || - !gHippoGridManager->getConnectedGrid()->supportsInvLinks(); - BOOL fUseOutfits = gSavedSettings.getBOOL("UseOutfitFolders") && - gHippoGridManager->getConnectedGrid()->supportsInvLinks(); - - LLFolderType::EType typeDest = (fUseOutfits) ? LLFolderType::FT_MY_OUTFITS : LLFolderType::FT_CLOTHING; - LLFolderType::EType typeFolder = (fUseOutfits) ? LLFolderType::FT_OUTFIT : LLFolderType::FT_NONE; - - // First, make a folder for the outfit. - LLUUID folder_id = gInventory.createNewCategory(gInventory.findCategoryUUIDForType(typeDest), typeFolder, new_folder_name); - - bool found_first_item = false; - - /////////////////// - // Wearables - - if( wearables_to_include.count() ) - { - // Then, iterate though each of the wearables and save copies of them in the folder. - S32 i; - S32 count = wearables_to_include.count(); - LLPointer cbdone = NULL; - for( i = 0; i < count; ++i ) - { - S32 index = wearables_to_include[i]; - LLWearable* old_wearable = getWearable((LLWearableType::EType)index, 0); - if( old_wearable ) - { - LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((LLWearableType::EType)index, 0)); - llassert(item); - if (!item) - continue; - if (fUseOutfits) - { - std::string strOrdering = llformat("@%d", item->getWearableType() * 100); - - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - folder_id, - item->getName(), - strOrdering, - LLAssetType::AT_LINK, - LLPointer(NULL)); - } - else - { - std::string new_name = item->getName(); - if (rename_clothing) - { - new_name = new_folder_name; - new_name.append(" "); - new_name.append(old_wearable->getTypeLabel()); - LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); - } - - if (fUseLinks || isWearableCopyable((LLWearableType::EType)index, 0)) - { - LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); - if (rename_clothing) - { - new_wearable->setName(new_name); - } - - S32 todo = addWearableToAgentInventoryCallback::CALL_NONE; - if (!found_first_item) - { - found_first_item = true; - /* set the focus to the first item */ - todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE; - /* send the agent wearables update when done */ - cbdone = new sendAgentWearablesUpdateCallback; - } - LLPointer cb = - new addWearableToAgentInventoryCallback( - cbdone, - (LLWearableType::EType)index, - 0, - new_wearable, - todo); - if (isWearableCopyable((LLWearableType::EType)index, 0)) - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getLinkedUUID(), - folder_id, - new_name, - cb); - } - else - { - move_inventory_item( - gAgent.getID(), - gAgent.getSessionID(), - item->getLinkedUUID(), - folder_id, - new_name, - cb); - } - } - else - { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - folder_id, - item->getName(), // Apparently, links cannot have arbitrary names... - item->getDescription(), - LLAssetType::AT_LINK, - LLPointer(NULL)); - } - } - } - } - gInventory.notifyObservers(); - } - - - /////////////////// - // Attachments - - if( attachments_to_include.count() ) - { - for( S32 i = 0; i < attachments_to_include.count(); i++ ) - { - S32 attachment_pt = attachments_to_include[i]; - LLViewerJointAttachment* attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL ); - if(!attachment) continue; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject *attached_object = (*attachment_iter); - if (!attached_object) continue; - const LLUUID& item_id = attached_object->getAttachmentItemID(); - if (item_id.isNull()) continue; - LLInventoryItem* item = gInventory.getItem(item_id); - if (!item) continue; - if (fUseOutfits) - { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - folder_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, - LLPointer(NULL)); - } - else - { - if (fUseLinks || item->getPermissions().allowCopyBy(gAgent.getID())) - { - const LLUUID& old_folder_id = item->getParentUUID(); - - move_inventory_item( - gAgent.getID(), - gAgent.getSessionID(), - item->getLinkedUUID(), - folder_id, - item->getName(), - LLPointer(NULL)); - - if (item->getPermissions().allowCopyBy(gAgent.getID())) - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getLinkedUUID(), - old_folder_id, - item->getName(), - LLPointer(NULL)); - } - } - else - { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - folder_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, - LLPointer(NULL)); - } - } - } - } - } -} - void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) { LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type, index); // Open the inventory and select the first item we added. - if( first_item_id.notNull() ) + if (first_item_id.notNull()) { - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if(view) + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) { - view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO); + active_panel->setSelection(first_item_id, TAKE_FOCUS_NO); } } } @@ -1387,7 +1317,7 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointer& wearables, - BOOL remove ) + BOOL remove) { - lldebugs << "setWearableOutfit() start" << llendl; + llinfos << "setWearableOutfit() start" << llendl; - BOOL wearables_to_remove[LLWearableType::WT_COUNT]; - wearables_to_remove[LLWearableType::WT_SHAPE] = FALSE; - wearables_to_remove[LLWearableType::WT_SKIN] = FALSE; - wearables_to_remove[LLWearableType::WT_HAIR] = FALSE; - wearables_to_remove[LLWearableType::WT_EYES] = FALSE; -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.1.3b) | Added: RLVa-0.2.2a - wearables_to_remove[LLWearableType::WT_SHIRT] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_SHIRT); - wearables_to_remove[LLWearableType::WT_PANTS] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_PANTS); - wearables_to_remove[LLWearableType::WT_SHOES] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_SHOES); - wearables_to_remove[LLWearableType::WT_SOCKS] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_SOCKS); - wearables_to_remove[LLWearableType::WT_JACKET] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_JACKET); - wearables_to_remove[LLWearableType::WT_GLOVES] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_GLOVES); - wearables_to_remove[LLWearableType::WT_UNDERSHIRT] = (!gAgent.isTeen()) && remove && gRlvWearableLocks.canRemove(LLWearableType::WT_UNDERSHIRT); - wearables_to_remove[LLWearableType::WT_UNDERPANTS] = (!gAgent.isTeen()) && remove && gRlvWearableLocks.canRemove(LLWearableType::WT_UNDERPANTS); - wearables_to_remove[LLWearableType::WT_SKIRT] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_SKIRT); - wearables_to_remove[LLWearableType::WT_ALPHA] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_ALPHA); - wearables_to_remove[LLWearableType::WT_TATTOO] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_TATTOO); - wearables_to_remove[LLWearableType::WT_PHYSICS] = remove && gRlvWearableLocks.canRemove(LLWearableType::WT_PHYSICS); -// [/RLVa:KB] + // TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later + if (remove) + { + // note: shirt is the first non-body part wearable item. Update if wearable order changes. + // This loop should remove all clothing, but not any body parts + for (S32 type = 0; type < (S32)LLWearableType::WT_COUNT; type++) + { + if (LLWearableType::getAssetType((LLWearableType::EType)type) == LLAssetType::AT_CLOTHING) + { + removeWearable((LLWearableType::EType)type, true, 0); + } + } + } S32 count = wearables.count(); - llassert( items.count() == count ); + llassert(items.count() == count); S32 i; - for( i = 0; i < count; i++ ) + for (i = 0; i < count; i++) { LLWearable* new_wearable = wearables[i]; LLPointer new_item = items[i]; llassert(new_wearable); - if (new_wearable) { - LLWearableType::EType type = new_wearable->getType(); - wearables_to_remove[type] = FALSE; - - LLWearable* old_wearable = getWearable(type, 0); - if( old_wearable ) - { - const LLUUID& old_item_id = getWearableItemID(type, 0); - if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getLinkedUUID()) ) - { - lldebugs << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << llendl; - continue; - } - - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - - // Assumes existing wearables are not dirty. - if( old_wearable->isDirty() ) - { - llassert(0); - continue; - } - } + const LLWearableType::EType type = new_wearable->getType(); if (isFirstPhysicsWearable(type, new_item, new_wearable)) { @@ -1603,71 +1489,46 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it } new_wearable->setName(new_item->getName()); - new_wearable->setItemID(new_item->getLinkedUUID()); + new_wearable->setItemID(new_item->getUUID()); if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART) { // exactly one wearable per body part setWearable(type,0,new_wearable); } - else if(old_wearable) //Remove when multi-wearables are implemented. - { - setWearable(type,0,new_wearable); - } else { pushWearable(type,new_wearable); } - } - } - - std::vector wearables_being_removed; - - for( i = 0; i < LLWearableType::WT_COUNT; i++ ) - { - if( wearables_to_remove[i] ) - { - LLWearable* wearable = getWearable((LLWearableType::EType)i, 0); - wearables_being_removed.push_back(getWearable((LLWearableType::EType)i, 0)); - popWearable(wearable); - - gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID()); + wearableUpdated(new_wearable); + checkWearableAgainstInventory(new_wearable); } } gInventory.notifyObservers(); - queryWearableCache(); - - std::vector::iterator wearable_iter; - - for( wearable_iter = wearables_being_removed.begin(); - wearable_iter != wearables_being_removed.end(); - ++wearable_iter) + if (isAgentAvatarValid()) { - LLWearable* wearablep = *wearable_iter; - if (wearablep) - { - wearablep->removeFromAvatar( TRUE ); - } - } - - for( i = 0; i < count; i++ ) - { - wearables[i]->writeToAvatar( TRUE ); + gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); + gAgentAvatarp->updateVisualParams(); + gAgentAvatarp->invalidateAll(); } // Start rendering & update the server mWearablesLoaded = TRUE; + checkWearablesLoaded(); + notifyLoadingFinished(); + queryWearableCache(); updateServer(); + gAgentAvatarp->dumpAvatarTEs("setWearableOutfit"); lldebugs << "setWearableOutfit() end" << llendl; } // User has picked "wear on avatar" from a menu. -void LLAgentWearables::setWearableItem( LLInventoryItem* new_item, LLWearable* new_wearable ) +void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append) { //LLAgentDumper dumper("setWearableItem"); if (isWearingItem(new_item->getUUID())) @@ -1675,44 +1536,41 @@ void LLAgentWearables::setWearableItem( LLInventoryItem* new_item, LLWearable* n llwarns << "wearable " << new_item->getUUID() << " is already worn" << llendl; return; } - LLWearableType::EType type = new_wearable->getType(); - - -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.1.4a) - // Block if: we can't wear on that layer; or we're already wearing something there we can't take off - if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canWear(dynamic_cast(new_item))) ) - { - return; - } -// [/RLVa:KB] + + const LLWearableType::EType type = new_wearable->getType(); if (isFirstPhysicsWearable(type, new_item, new_wearable)) { return; } - - LLWearable* old_wearable = getWearable(type,0); - if( old_wearable ) + + if (!do_append) { - const LLUUID& old_item_id = old_wearable->getItemID(); - if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getUUID()) ) + // Remove old wearable, if any + // MULTI_WEARABLE: hardwired to 0 + LLWearable* old_wearable = getWearable(type,0); + if( old_wearable ) { - lldebugs << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << llendl; - return; - } + const LLUUID& old_item_id = old_wearable->getItemID(); + if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && + (old_item_id == new_item->getUUID()) ) + { + lldebugs << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << llendl; + return; + } - if( old_wearable->isDirty() ) - { - // Bring up modal dialog: Save changes? Yes, No, Cancel - LLSD payload; - payload["item_id"] = new_item->getUUID(); - LLNotificationsUtil::add( "WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); - return; + if( old_wearable->isDirty() ) + { + // Bring up modal dialog: Save changes? Yes, No, Cancel + LLSD payload; + payload["item_id"] = new_item->getUUID(); + LLNotificationsUtil::add( "WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); + return; + } } } - setWearableFinal( new_item, new_wearable ); + setWearableFinal(new_item, new_wearable, do_append); } // static @@ -1750,11 +1608,21 @@ bool LLAgentWearables::onSetWearableDialog( const LLSD& notification, const LLSD return false; } -// Called from setWearable() and onSetWearableDialog() to actually set the wearable. -void LLAgentWearables::setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable ) +// Called from setWearableItem() and onSetWearableDialog() to actually set the wearable. +// MULTI_WEARABLE: unify code after null objects are gone. +void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append) { const LLWearableType::EType type = new_wearable->getType(); + if (do_append && getWearableItemID(type,0).notNull()) + { + new_wearable->setItemID(new_item->getUUID()); + mWearableDatas[type].push_back(new_wearable); + llinfos << "Added additional wearable for type " << type + << " size is now " << mWearableDatas[type].size() << llendl; + checkWearableAgainstInventory(new_wearable); + } + else { // Replace the old wearable with a new one. llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); @@ -1765,7 +1633,7 @@ void LLAgentWearables::setWearableFinal( LLInventoryItem* new_item, LLWearable* { old_item_id = old_wearable->getItemID(); } - new_wearable->setItemID(new_item->getLinkedUUID()); + new_wearable->setItemID(new_item->getUUID()); setWearable(type,0,new_wearable); if (old_item_id.notNull()) @@ -1779,7 +1647,7 @@ void LLAgentWearables::setWearableFinal( LLInventoryItem* new_item, LLWearable* //llinfos << "LLVOAvatar::setWearableItem()" << llendl; queryWearableCache(); - new_wearable->writeToAvatar( TRUE ); + //new_wearable->writeToAvatar(TRUE); updateServer(); } @@ -1828,6 +1696,10 @@ void LLAgentWearables::queryWearableCache() //VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout if(gAgent.getRegion()) { + if (isAgentAvatarValid()) + { + gAgentAvatarp->outputRezTiming("Fetching textures from cache"); + } llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl; gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); gAgentQueryManager.mNumPendingQueries++; @@ -1898,44 +1770,9 @@ void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &ty } } -void LLAgentWearables::userRemoveAllClothes() -{ - // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty. - if (gAgentCamera.cameraCustomizeAvatar()) - { - gFloaterCustomize->askToSaveIfDirty( boost::bind(LLAgentWearables::userRemoveAllClothesStep2,_1) ); - } - else - { - userRemoveAllClothesStep2( TRUE ); - } -} - -void LLAgentWearables::userRemoveAllClothesStep2( BOOL proceed ) -{ - if( proceed ) - { - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SHIRT ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_PANTS ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SHOES ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SOCKS ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_JACKET ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_GLOVES ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_UNDERSHIRT ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_UNDERPANTS ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SKIRT ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_ALPHA ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_TATTOO ); - gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_PHYSICS ); - } -} - // Combines userRemoveAllAttachments() and userAttachMultipleAttachments() logic to // get attachments into desired state with minimal number of adds/removes. -//void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array) -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a -void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array, bool fAttachOnly) -// [/SL:KB] +void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array) { // Possible cases: // already wearing but not in request set -> take off. @@ -2002,7 +1839,7 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj // Remove everything in objects_to_remove // userRemoveMultipleAttachments(objects_to_remove); // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a - if (!fAttachOnly) + if (!gAgentAvatarp->isFullyLoaded()) { userRemoveMultipleAttachments(objects_to_remove); } @@ -2016,34 +1853,6 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo { if (!isAgentAvatarValid()) return; -// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.1.3b) | Modified: RLVa-1.2.0a - // RELEASE-RLVa: [SL-2.0.0] Check our callers and verify that erasing elements from the passed vector won't break random things - if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) - { - llvo_vec_t::iterator itObj = objects_to_remove.begin(); - while (itObj != objects_to_remove.end()) - { - const LLViewerObject* pAttachObj = *itObj; - if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) - { - itObj = objects_to_remove.erase(itObj); - - // Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere) - LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; - LLLinkedItemIDMatches f(pAttachObj->getAttachmentItemID()); - gInventory.collectDescendentsIf(LLCOFMgr::instance().getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH, f); - RLV_ASSERT( 0 != items.count() ); - if (0 == items.count()) - LLCOFMgr::instance().addAttachment(pAttachObj->getAttachmentItemID()); - } - else - { - ++itObj; - } - } - } -// [/RLVa:KB] - if (objects_to_remove.empty()) return; @@ -2079,10 +1888,7 @@ void LLAgentWearables::userRemoveAllAttachments() ++attachment_iter) { LLViewerObject *attached_object = (*attachment_iter); -// if (attached_object) -// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b - if ( (attached_object) && ((!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.isLockedAttachment(attached_object))) ) -// [/RLVa:KB] + if (attached_object) { objects_to_remove.push_back(attached_object); } @@ -2159,22 +1965,229 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra } } } + +void LLAgentWearables::checkWearablesLoaded() const +{ +#ifdef SHOW_ASSERT + U32 item_pend_count = itemUpdatePendingCount(); + if (mWearablesLoaded) + { + llassert(item_pend_count==0); + } +#endif +} + +// Returns false if the given wearable is already topmost/bottommost +// (depending on closer_to_body parameter). +bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) +{ + const LLWearable* wearable = getWearableFromItemID(item_id); + if (!wearable) return false; + + LLWearableType::EType wtype = wearable->getType(); + const LLWearable* marginal_wearable = closer_to_body ? getBottomWearable(wtype) : getTopWearable(wtype); + if (!marginal_wearable) return false; + + return wearable != marginal_wearable; +} + +BOOL LLAgentWearables::areWearablesLoaded() const +{ + checkWearablesLoaded(); + return mWearablesLoaded; +} + // MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate void LLAgentWearables::updateWearablesLoaded() { - mWearablesLoaded = TRUE; - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + mWearablesLoaded = (itemUpdatePendingCount()==0); + if (mWearablesLoaded) { - if( !getWearableItemID((LLWearableType::EType)i, 0).isNull() && !getWearable((LLWearableType::EType)i, 0) ) + notifyLoadingFinished(); + } +} + +bool LLAgentWearables::canWearableBeRemoved(const LLWearable* wearable) const +{ + if (!wearable) return false; + + LLWearableType::EType type = wearable->getType(); + // Make sure the user always has at least one shape, skin, eyes, and hair type currently worn. + return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES)) + && (getWearableCount(type) <= 1) ); +} +void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) +{ + for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type ) + { + for (S32 count = 0; count < (S32)getWearableCount((LLWearableType::EType)type); ++count) { - mWearablesLoaded = FALSE; - break; + LLWearable *wearable = getWearable((LLWearableType::EType)type,count); + llassert(wearable); + if (wearable) + { + wearable->animateParams(delta, upload_bake); + } } } - } + +bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool closer_to_body) +{ + if (!item) return false; + if (!item->isWearableType()) return false; + + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(item->getWearableType()); + if (wearable_iter == mWearableDatas.end()) return false; + + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (wearable_vec.empty()) return false; + + const LLUUID& asset_id = item->getAssetUUID(); + + //nowhere to move if the wearable is already on any boundary (closest to the body/furthest from the body) + if (closer_to_body && asset_id == wearable_vec.front()->getAssetID()) return false; + if (!closer_to_body && asset_id == wearable_vec.back()->getAssetID()) return false; + + for (U32 i = 0; i < wearable_vec.size(); ++i) + { + LLWearable* wearable = wearable_vec[i]; + if (!wearable) continue; + if (wearable->getAssetID() != asset_id) continue; + + //swapping wearables + U32 swap_i = closer_to_body ? i-1 : i+1; + wearable_vec[i] = wearable_vec[swap_i]; + wearable_vec[swap_i] = wearable; + return true; + } + + return false; +} + +// static +void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id) +{ + if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return; + + LLWearable* wearable = LLWearableList::instance().createNewWearable(type); + LLAssetType::EType asset_type = wearable->getAssetType(); + LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; + LLPointer cb = wear ? new LLWearAndEditCallback : NULL; + LLUUID folder_id; + + if (parent_id.notNull()) + { + folder_id = parent_id; + } + else + { + LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type); + folder_id = gInventory.findCategoryUUIDForType(folder_type); + } + + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, wearable->getTransactionID(), wearable->getName(), + wearable->getDescription(), asset_type, inv_type, wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); +} + +// static +void LLAgentWearables::editWearable(const LLUUID& item_id) +{ + LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id); + if (!item) + { + llwarns << "Failed to get linked item" << llendl; + return; + } + + LLWearable* wearable = gAgentWearables.getWearableFromItemID(item_id); + if (!wearable) + { + llwarns << "Cannot get wearable" << llendl; + return; + } + + if (!gAgentWearables.isWearableModifiable(item->getUUID())) + { + llwarns << "Cannot modify wearable" << llendl; + return; + } + + //const BOOL disable_camera_switch = LLWearableType::getDisableCameraSwitch(wearable->getType()); + + // Set the tab to the right wearable. + LLFloaterCustomize::setCurrentWearableType( wearable->getType() ); + + if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() ) + { + // Start Avatar Customization + gAgentCamera.changeCameraToCustomizeAvatar(); + } +} + +// Request editing the item after it gets worn. +void LLAgentWearables::requestEditingWearable(const LLUUID& item_id) +{ + mItemToEdit = gInventory.getLinkedItemID(item_id); +} + +// Start editing the item if previously requested. +void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id) +{ + if (mItemToEdit.notNull() && + mItemToEdit == gInventory.getLinkedItemID(item_id)) + { + LLAgentWearables::editWearable(item_id); + mItemToEdit.setNull(); + } +} + void LLAgentWearables::updateServer() { sendAgentWearablesUpdate(); gAgent.sendAgentSetAppearance(); } + +void LLAgentWearables::populateMyOutfitsFolder(void) +{ + llinfos << "starting outfit population" << llendl; + + const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(my_outfits_id); + outfits->mMyOutfitsID = my_outfits_id; + + // Get the complete information on the items in the inventory and + // setup an observer that will wait for that to happen. + gInventory.addObserver(outfits); + outfits->startFetch(); + if (outfits->isFinished()) + { + outfits->done(); + } +} + +boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb) +{ + return mLoadingStartedSignal.connect(cb); +} + +boost::signals2::connection LLAgentWearables::addLoadedCallback(loaded_callback_t cb) +{ + return mLoadedSignal.connect(cb); +} + +void LLAgentWearables::notifyLoadingStarted() +{ + mCOFChangeInProgress = true; + mLoadingStartedSignal(); +} + +void LLAgentWearables::notifyLoadingFinished() +{ + mCOFChangeInProgress = false; + mLoadedSignal(); +} +// EOF diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 6e753d441..c84daa4ec 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -2,33 +2,26 @@ * @file llagentwearables.h * @brief LLAgentWearables class header file * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ #ifndef LL_LLAGENTWEARABLES_H @@ -63,16 +56,16 @@ public: LLAgentWearables(); virtual ~LLAgentWearables(); void setAvatarObject(LLVOAvatarSelf *avatar); - void createStandardWearables(BOOL female); + void createStandardWearables(); void cleanup(); - //void dump(); + void dump(); // LLInitClass interface static void initClass(); protected: void createStandardWearablesDone(S32 type, U32 index/* = 0*/); void createStandardWearablesAllDone(); - + //-------------------------------------------------------------------- // Queries //-------------------------------------------------------------------- @@ -83,18 +76,16 @@ public: BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL areWearablesLoaded() const; + bool isCOFChangeInProgress() const { return mCOFChangeInProgress; } void updateWearablesLoaded(); - //void checkWearablesLoaded() const; - //bool canMoveWearable(const LLUUID& item_id, bool closer_to_body); + void checkWearablesLoaded() const; + bool canMoveWearable(const LLUUID& item_id, bool closer_to_body); // Note: False for shape, skin, eyes, and hair, unless you have MORE than 1. - //bool canWearableBeRemoved(const LLWearable* wearable) const; + bool canWearableBeRemoved(const LLWearable* wearable) const; - //void animateAllWearableParams(F32 delta, BOOL upload_bake); + void animateAllWearableParams(F32 delta, BOOL upload_bake); - BOOL needsReplacement(LLWearableType::EType wearableType, S32 remove); - //U32 getWearablePermMask(LLWearableType::EType type) const; - //-------------------------------------------------------------------- // Accessors //-------------------------------------------------------------------- @@ -109,11 +100,11 @@ public: LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/); const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const; LLWearable* getTopWearable(const LLWearableType::EType type); - LLWearable* getBottomWearable(const LLWearableType::EType type); + LLWearable* getBottomWearable(const LLWearableType::EType type); U32 getWearableCount(const LLWearableType::EType type) const; U32 getWearableCount(const U32 tex_index) const; - static const U32 MAX_CLOTHING_PER_TYPE = 1; + static const U32 MAX_CLOTHING_PER_TYPE = 5; //-------------------------------------------------------------------- @@ -129,31 +120,20 @@ private: void popWearable(const LLWearableType::EType type, U32 index); public: - void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable); + void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable, bool do_append = false); void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove); void setWearableName(const LLUUID& item_id, const std::string& new_name); - //void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index); + void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index); U32 getWearableIndex(const LLWearable *wearable) const; protected: - void setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable ); + void setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append = false); static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLWearable* wearable); void addWearableToAgentInventory(LLPointer cb, LLWearable* wearable, const LLUUID& category_id = LLUUID::null, BOOL notify = TRUE); - - /** - * @brief Only public because of addWearableToAgentInventoryCallback. - * - * NOTE: Do not call this method unless you are the inventory callback. - * NOTE: This can suffer from race conditions when working on the - * same values for index. - * @param index The index in mWearableEntry. - * @param item_id The inventory item id of the new wearable to wear. - * @param wearable The actual wearable data. - */ void addWearabletoAgentInventoryDone(const LLWearableType::EType type, const U32 index, const LLUUID& item_id, @@ -166,15 +146,15 @@ protected: //-------------------------------------------------------------------- public: - //static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null); - //static void editWearable(const LLUUID& item_id); - //bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body); + static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null); + static void editWearable(const LLUUID& item_id); + bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body); - //void requestEditingWearable(const LLUUID& item_id); - //void editWearableIfRequested(const LLUUID& item_id); + void requestEditingWearable(const LLUUID& item_id); + void editWearableIfRequested(const LLUUID& item_id); private: - //LLUUID mItemToEdit; + LLUUID mItemToEdit; //-------------------------------------------------------------------- // Removing wearables @@ -185,7 +165,6 @@ private: void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); - static void userRemoveAllClothesStep2(BOOL proceed); // userdata is NULL //-------------------------------------------------------------------- // Server Communication @@ -201,7 +180,7 @@ protected: void sendAgentWearablesRequest(); void queryWearableCache(); void updateServer(); - static void onInitialWearableAssetArrived(LLWearable* wearable, void* userdata ); + static void onInitialWearableAssetArrived(LLWearable* wearable, void* userdata); //-------------------------------------------------------------------- // Outfits @@ -210,27 +189,20 @@ public: // Should only be called if we *know* we've never done so before, since users may // not want the Library outfits to stay in their quick outfit selector and can delete them. - //void populateMyOutfitsFolder(); - void makeNewOutfit( - const std::string& new_folder_name, - const LLDynamicArray& wearables_to_include, - const LLDynamicArray& attachments_to_include, - BOOL rename_clothing); -private: + void populateMyOutfitsFolder(); +private: void makeNewOutfitDone(S32 type, U32 index); //-------------------------------------------------------------------- // Save Wearables //-------------------------------------------------------------------- public: - void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found ); + void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found); void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, const std::string new_name = ""); - void saveAllWearables(); - void revertWearable( LLWearableType::EType type, const U32 index); - void revertAllWearables(); + void revertWearable(const LLWearableType::EType type, const U32 index, bool set_by_user=false); //-------------------------------------------------------------------- // Static UI hooks @@ -238,15 +210,10 @@ public: public: static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index); static void userRemoveWearablesOfType(const LLWearableType::EType &type); - static void userRemoveAllClothes(); - - typedef std::vector llvo_vec_t; -// static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a - // Not the best way to go about this but other attempts changed far too much LL code to be a viable solution - static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array, bool fAttachOnly = false); -// [/SL:KB] + typedef std::vector llvo_vec_t; + + static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array); static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array); static void userRemoveAllAttachments(); static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); @@ -258,7 +225,7 @@ public: // Signals //-------------------------------------------------------------------- public: - /*typedef boost::function loading_started_callback_t; + typedef boost::function loading_started_callback_t; typedef boost::signals2::signal loading_started_signal_t; boost::signals2::connection addLoadingStartedCallback(loading_started_callback_t cb); @@ -267,9 +234,11 @@ public: boost::signals2::connection addLoadedCallback(loaded_callback_t cb); void notifyLoadingStarted(); - void notifyLoadingFinished();*/ + void notifyLoadingFinished(); private: + loading_started_signal_t mLoadingStartedSignal; // should be called before wearables are changed + loaded_signal_t mLoadedSignal; // emitted when all agent wearables get loaded //-------------------------------------------------------------------- // Member variables @@ -281,6 +250,12 @@ private: static BOOL mInitialWearablesUpdateReceived; BOOL mWearablesLoaded; + std::set mItemsAwaitingWearableUpdate; + + /** + * True if agent's outfit is being changed now. + */ + BOOL mCOFChangeInProgress; //-------------------------------------------------------------------------------- // Support classes @@ -300,31 +275,22 @@ private: class addWearableToAgentInventoryCallback : public LLInventoryCallback { public: - enum { + enum ETodo + { CALL_NONE = 0, CALL_UPDATE = 1, CALL_RECOVERDONE = 2, CALL_CREATESTANDARDDONE = 4, - CALL_MAKENEWOUTFITDONE = 8 - } EType; + CALL_MAKENEWOUTFITDONE = 8, + CALL_WEARITEM = 16 + }; - /** - * @brief Construct a callback for dealing with the wearables. - * - * Would like to pass the agent in here, but we can't safely - * count on it being around later. Just use gAgent directly. - * @param cb callback to execute on completion (??? unused ???) - * @param index Index for the wearable in the agent - * @param wearable The wearable data. - * @param todo Bitmask of actions to take on completion. - */ addWearableToAgentInventoryCallback(LLPointer cb, LLWearableType::EType type, U32 index, LLWearable* wearable, U32 todo = CALL_NONE); virtual void fire(const LLUUID& inv_item); - private: LLWearableType::EType mType; U32 mIndex; diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp new file mode 100644 index 000000000..8cba54347 --- /dev/null +++ b/indra/newview/llagentwearablesfetch.cpp @@ -0,0 +1,607 @@ +/** + * @file llagentwearablesfetch.cpp + * @brief LLAgentWearblesFetch class implementation + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llagentwearablesfetch.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "llstartup.h" +#include "llvoavatarself.h" + + +class LLOrderMyOutfitsOnDestroy: public LLInventoryCallback +{ +public: + LLOrderMyOutfitsOnDestroy() {}; + + virtual ~LLOrderMyOutfitsOnDestroy() + { + if (!LLApp::isRunning()) + { + llwarns << "called during shutdown, skipping" << llendl; + return; + } + + const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + if (my_outfits_id.isNull()) return; + + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(my_outfits_id, cats, items); + if (!cats) return; + + //My Outfits should at least contain saved initial outfit and one another outfit + if (cats->size() < 2) + { + llwarning("My Outfits category was not populated properly", 0); + return; + } + + llinfos << "Starting updating My Outfits with wearables ordering information" << llendl; + + for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin(); + outfit_iter != cats->end(); ++outfit_iter) + { + const LLUUID& cat_id = (*outfit_iter)->getUUID(); + if (cat_id.isNull()) continue; + + // saved initial outfit already contains wearables ordering information + if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue; + + LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id); + } + + llinfos << "Finished updating My Outfits with wearables ordering information" << llendl; + } + + /* virtual */ void fire(const LLUUID& inv_item) {}; +}; + + +LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) : + LLInventoryFetchDescendentsObserver(cof_id) +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->outputRezTiming("Initial wearables fetch started"); + } +} + +LLInitialWearablesFetch::~LLInitialWearablesFetch() +{ +} + +// virtual +void LLInitialWearablesFetch::done() +{ + // Delay processing the actual results of this so it's not handled within + // gInventory.notifyObservers. The results will be handled in the next + // idle tick instead. + gInventory.removeObserver(this); + doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this)); + if (isAgentAvatarValid()) + { + gAgentAvatarp->outputRezTiming("Initial wearables fetch done"); + } +} + +void LLInitialWearablesFetch::add(InitialWearableData &data) + +{ + mAgentInitialWearables.push_back(data); +} + +void LLInitialWearablesFetch::processContents() +{ + if(!gAgentAvatarp) //no need to process wearables if the agent avatar is deleted. + { + delete this; + return ; + } + + // Fetch the wearable items from the Current Outfit Folder + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + LLFindWearables is_wearable; + llassert_always(mComplete.size() != 0); + gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, is_wearable); + + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + if (wearable_array.count() > 0) + { + gAgentWearables.notifyLoadingStarted(); + LLAppearanceMgr::instance().updateAppearanceFromCOF(); + } + else + { + // if we're constructing the COF from the wearables message, we don't have a proper outfit link + LLAppearanceMgr::instance().setOutfitDirty(true); + processWearablesMessage(); + } + delete this; +} + +class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver +{ +public: + LLFetchAndLinkObserver(uuid_vec_t& ids): + LLInventoryFetchItemsObserver(ids) + { + } + ~LLFetchAndLinkObserver() + { + } + virtual void done() + { + gInventory.removeObserver(this); + + // Link to all fetched items in COF. + LLPointer link_waiter = new LLUpdateAppearanceOnDestroy; + for (uuid_vec_t::iterator it = mIDs.begin(); + it != mIDs.end(); + ++it) + { + LLUUID id = *it; + LLViewerInventoryItem *item = gInventory.getItem(*it); + if (!item) + { + llwarns << "fetch failed!" << llendl; + continue; + } + + link_inventory_item(gAgent.getID(), + item->getLinkedUUID(), + LLAppearanceMgr::instance().getCOF(), + item->getName(), + item->getDescription(), + LLAssetType::AT_LINK, + link_waiter); + } + } +}; + +void LLInitialWearablesFetch::processWearablesMessage() +{ + if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. + { + const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF(); + uuid_vec_t ids; + for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) + { + // Populate the current outfit folder with links to the wearables passed in the message + InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. + + if (wearable_data->mAssetID.notNull()) + { + ids.push_back(wearable_data->mItemID); + } + else + { + llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID " + << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl; + delete wearable_data; + } + } + + // Add all current attachments to the requested items as well. + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (!attachment) continue; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = (*attachment_iter); + if (!attached_object) continue; + const LLUUID& item_id = attached_object->getAttachmentItemID(); + if (item_id.isNull()) continue; + ids.push_back(item_id); + } + } + } + + // Need to fetch the inventory items for ids, then create links to them after they arrive. + LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids); + fetcher->startFetch(); + // If no items to be fetched, done will never be triggered. + // TODO: Change LLInventoryFetchItemsObserver::fetchItems to trigger done() on this condition. + if (fetcher->isFinished()) + { + fetcher->done(); + } + else + { + gInventory.addObserver(fetcher); + } + } + else + { + LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; + } +} + +LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) : + LLInventoryFetchDescendentsObserver(my_outfits_id), + mCurrFetchStep(LOFS_FOLDER), + mOutfitsPopulated(false) +{ + llinfos << "created" << llendl; + + mMyOutfitsID = LLUUID::null; + mClothingID = LLUUID::null; + mLibraryClothingID = LLUUID::null; + mImportedClothingID = LLUUID::null; + mImportedClothingName = "Imported Library Clothing"; +} + +LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() +{ + llinfos << "destroyed" << llendl; +} + +void LLLibraryOutfitsFetch::done() +{ + llinfos << "start" << llendl; + + // Delay this until idle() routine, since it's a heavy operation and + // we also can't have it run within notifyObservers. + doOnIdleOneTime(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this)); + gInventory.removeObserver(this); // Prevent doOnIdleOneTime from being added twice. +} + +void LLLibraryOutfitsFetch::doneIdle() +{ + llinfos << "start" << llendl; + + gInventory.addObserver(this); // Add this back in since it was taken out during ::done() + + switch (mCurrFetchStep) + { + case LOFS_FOLDER: + folderDone(); + mCurrFetchStep = LOFS_OUTFITS; + break; + case LOFS_OUTFITS: + outfitsDone(); + mCurrFetchStep = LOFS_LIBRARY; + break; + case LOFS_LIBRARY: + libraryDone(); + mCurrFetchStep = LOFS_IMPORTED; + break; + case LOFS_IMPORTED: + importedFolderDone(); + mCurrFetchStep = LOFS_CONTENTS; + break; + case LOFS_CONTENTS: + contentsDone(); + break; + default: + llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl; + mOutfitsPopulated = TRUE; + break; + } + + // We're completely done. Cleanup. + if (mOutfitsPopulated) + { + gInventory.removeObserver(this); + delete this; + return; + } +} + +void LLLibraryOutfitsFetch::folderDone() +{ + llinfos << "start" << llendl; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + // Early out if we already have items in My Outfits + // except the case when My Outfits contains just initial outfit + if (cat_array.count() > 1) + { + mOutfitsPopulated = true; + return; + } + + mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true); + + // If Library->Clothing->Initial Outfits exists, use that. + LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); + cat_array.clear(); + gInventory.collectDescendentsIf(mLibraryClothingID, + cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, + matchFolderFunctor); + if (cat_array.count() > 0) + { + const LLViewerInventoryCategory *cat = cat_array.get(0); + mLibraryClothingID = cat->getUUID(); + } + + mComplete.clear(); + + // Get the complete information on the items in the inventory. + uuid_vec_t folders; + folders.push_back(mClothingID); + folders.push_back(mLibraryClothingID); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +void LLLibraryOutfitsFetch::outfitsDone() +{ + llinfos << "start" << llendl; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + uuid_vec_t folders; + + // Collect the contents of the Library's Clothing folder + gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + llassert(cat_array.count() > 0); + for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); + iter != cat_array.end(); + ++iter) + { + const LLViewerInventoryCategory *cat = iter->get(); + + // Get the names and id's of every outfit in the library, skip "Ruth" + // because it's a low quality legacy outfit + if (cat->getName() != "Ruth") + { + // Get the name of every outfit in the library + folders.push_back(cat->getUUID()); + mLibraryClothingFolders.push_back(cat->getUUID()); + } + } + cat_array.clear(); + wearable_array.clear(); + + // Check if you already have an "Imported Library Clothing" folder + LLNameCategoryCollector matchFolderFunctor(mImportedClothingName); + gInventory.collectDescendentsIf(mClothingID, + cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, + matchFolderFunctor); + if (cat_array.size() > 0) + { + const LLViewerInventoryCategory *cat = cat_array.get(0); + mImportedClothingID = cat->getUUID(); + } + + mComplete.clear(); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +class LLLibraryOutfitsCopyDone: public LLInventoryCallback +{ +public: + LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): + mFireCount(0), mLibraryOutfitsFetcher(fetcher) + { + } + + virtual ~LLLibraryOutfitsCopyDone() + { + if (!LLApp::isExiting() && mLibraryOutfitsFetcher) + { + gInventory.addObserver(mLibraryOutfitsFetcher); + mLibraryOutfitsFetcher->done(); + } + } + + /* virtual */ void fire(const LLUUID& inv_item) + { + mFireCount++; + } +private: + U32 mFireCount; + LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; +}; + +// Copy the clothing folders from the library into the imported clothing folder +void LLLibraryOutfitsFetch::libraryDone() +{ + llinfos << "start" << llendl; + + if (mImportedClothingID != LLUUID::null) + { + // Skip straight to fetching the contents of the imported folder + importedFolderFetch(); + return; + } + + // Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone. + gInventory.removeObserver(this); + + LLPointer copy_waiter = new LLLibraryOutfitsCopyDone(this); + mImportedClothingID = gInventory.createNewCategory(mClothingID, + LLFolderType::FT_NONE, + mImportedClothingName); + // Copy each folder from library into clothing unless it already exists. + for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); + iter != mLibraryClothingFolders.end(); + ++iter) + { + const LLUUID& src_folder_id = (*iter); // Library clothing folder ID + const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); + if (!cat) + { + llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl; + continue; + } + + if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) + { + llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl; + continue; + } + + // Don't copy the category if it already exists. + LLNameCategoryCollector matchFolderFunctor(cat->getName()); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + gInventory.collectDescendentsIf(mImportedClothingID, + cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, + matchFolderFunctor); + if (cat_array.size() > 0) + { + continue; + } + + LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID, + LLFolderType::FT_NONE, + cat->getName()); + LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter); + } +} + +void LLLibraryOutfitsFetch::importedFolderFetch() +{ + llinfos << "start" << llendl; + + // Fetch the contents of the Imported Clothing Folder + uuid_vec_t folders; + folders.push_back(mImportedClothingID); + + mComplete.clear(); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +void LLLibraryOutfitsFetch::importedFolderDone() +{ + llinfos << "start" << llendl; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + uuid_vec_t folders; + + // Collect the contents of the Imported Clothing folder + gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); + iter != cat_array.end(); + ++iter) + { + const LLViewerInventoryCategory *cat = iter->get(); + + // Get the name of every imported outfit + folders.push_back(cat->getUUID()); + mImportedClothingFolders.push_back(cat->getUUID()); + } + + mComplete.clear(); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +void LLLibraryOutfitsFetch::contentsDone() +{ + llinfos << "start" << llendl; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + + LLPointer order_myoutfits_on_destroy = new LLOrderMyOutfitsOnDestroy; + + for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); + folder_iter != mImportedClothingFolders.end(); + ++folder_iter) + { + const LLUUID &folder_id = (*folder_iter); + const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); + if (!cat) + { + llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl; + continue; + } + + //initial outfit should be already in My Outfits + if (cat->getName() == LLStartUp::getInitialOutfitName()) continue; + + // First, make a folder in the My Outfits directory. + LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); + + cat_array.clear(); + wearable_array.clear(); + // Collect the contents of each imported clothing folder, so we can create new outfit links for it + gInventory.collectDescendents(folder_id, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); + wearable_iter != wearable_array.end(); + ++wearable_iter) + { + const LLViewerInventoryItem *item = wearable_iter->get(); + link_inventory_item(gAgent.getID(), + item->getLinkedUUID(), + new_outfit_folder_id, + item->getName(), + item->getDescription(), + LLAssetType::AT_LINK, + order_myoutfits_on_destroy); + } + } + + mOutfitsPopulated = true; +} + diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h new file mode 100644 index 000000000..bedc445c0 --- /dev/null +++ b/indra/newview/llagentwearablesfetch.h @@ -0,0 +1,114 @@ +/** + * @file llagentwearablesinitialfetch.h + * @brief LLAgentWearablesInitialFetch class header file + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLAGENTWEARABLESINITIALFETCH_H +#define LL_LLAGENTWEARABLESINITIALFETCH_H + +#include "llinventoryobserver.h" +#include "llwearabletype.h" +#include "lluuid.h" + +//-------------------------------------------------------------------- +// InitialWearablesFetch +// +// This grabs contents from the COF and processes them. +// The processing is handled in idle(), i.e. outside of done(), +// to avoid gInventory.notifyObservers recursion. +//-------------------------------------------------------------------- +class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver +{ + LOG_CLASS(LLInitialWearablesFetch); + +public: + LLInitialWearablesFetch(const LLUUID& cof_id); + ~LLInitialWearablesFetch(); + virtual void done(); + + struct InitialWearableData + { + LLWearableType::EType mType; + LLUUID mItemID; + LLUUID mAssetID; + InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) : + mType(type), + mItemID(itemID), + mAssetID(assetID) + {} + }; + + void add(InitialWearableData &data); + +protected: + void processWearablesMessage(); + void processContents(); + +private: + typedef std::vector initial_wearable_data_vec_t; + initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg +}; + +//-------------------------------------------------------------------- +// InitialWearablesFetch +// +// This grabs outfits from the Library and copies those over to the user's +// outfits folder, typically during first-ever login. +//-------------------------------------------------------------------- +class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver +{ +public: + enum ELibraryOutfitFetchStep + { + LOFS_FOLDER = 0, + LOFS_OUTFITS, + LOFS_LIBRARY, + LOFS_IMPORTED, + LOFS_CONTENTS + }; + + LLLibraryOutfitsFetch(const LLUUID& my_outfits_id); + ~LLLibraryOutfitsFetch(); + + virtual void done(); + void doneIdle(); + LLUUID mMyOutfitsID; + void importedFolderFetch(); +protected: + void folderDone(); + void outfitsDone(); + void libraryDone(); + void importedFolderDone(); + void contentsDone(); + enum ELibraryOutfitFetchStep mCurrFetchStep; + uuid_vec_t mLibraryClothingFolders; + uuid_vec_t mImportedClothingFolders; + bool mOutfitsPopulated; + LLUUID mClothingID; + LLUUID mLibraryClothingID; + LLUUID mImportedClothingID; + std::string mImportedClothingName; +}; + +#endif // LL_AGENTWEARABLESINITIALFETCH_H diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp new file mode 100644 index 000000000..3db65ae72 --- /dev/null +++ b/indra/newview/llappearancemgr.cpp @@ -0,0 +1,3138 @@ +/** + * @file llappearancemgr.cpp + * @brief Manager for initiating appearance changes on the viewer + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llattachmentsmgr.h" +#include "llcommandhandler.h" +#include "lleventtimer.h" +#include "llgesturemgr.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" +#include "llnotificationsutil.h" +#include "lloutfitobserver.h" +//#include "lloutfitslist.h" +#include "llselectmgr.h" +//#include "llsidepanelappearance.h" +#include "llviewerobjectlist.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llviewerregion.h" +#include "llwearablelist.h" +#include "rlvhandler.h" + +// RAII thingy to guarantee that a variable gets reset when the Setter +// goes out of scope. More general utility would be handy - TODO: +// check boost. +class BoolSetter +{ +public: + BoolSetter(bool& var): + mVar(var) + { + mVar = true; + } + ~BoolSetter() + { + mVar = false; + } +private: + bool& mVar; +}; + +char ORDER_NUMBER_SEPARATOR('@'); + +class LLOutfitUnLockTimer: public LLEventTimer +{ +public: + LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) + { + // restart timer on BOF changed event + LLOutfitObserver::instance().addBOFChangedCallback(boost::bind( + &LLOutfitUnLockTimer::reset, this)); + stop(); + } + + /*virtual*/ + BOOL tick() + { + if(mEventTimer.hasExpired()) + { + LLAppearanceMgr::instance().setOutfitLocked(false); + } + return FALSE; + } + void stop() { mEventTimer.stop(); } + void start() { mEventTimer.start(); } + void reset() { mEventTimer.reset(); } + BOOL getStarted() { return mEventTimer.getStarted(); } + + LLTimer& getEventTimer() { return mEventTimer;} +}; + +// support for secondlife:///app/appearance SLapps +/*class LLAppearanceHandler : public LLCommandHandler +{ +public: + // requests will be throttled from a non-trusted browser + LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + { + // support secondlife:///app/appearance/show, but for now we just + // make all secondlife:///app/appearance SLapps behave this way + if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAppearance")) + { + LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); + return true; + } +}; + +LLAppearanceHandler gAppearanceHandler;*/ + + +LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLNameCategoryCollector has_name(name); + gInventory.collectDescendentsIf(parent_id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + if (0 == cat_array.count()) + return LLUUID(); + else + { + LLViewerInventoryCategory *cat = cat_array.get(0); + if (cat) + return cat->getUUID(); + else + { + llwarns << "null cat" << llendl; + return LLUUID(); + } + } +} + +class LLWearInventoryCategoryCallback : public LLInventoryCallback +{ +public: + LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append) + { + mCatID = cat_id; + mAppend = append; + } + void fire(const LLUUID& item_id) + { + /* + * Do nothing. We only care about the destructor + * + * The reason for this is that this callback is used in a hack where the + * same callback is given to dozens of items, and the destructor is called + * after the last item has fired the event and dereferenced it -- if all + * the events actually fire! + */ + } + +protected: + ~LLWearInventoryCategoryCallback() + { + llinfos << "done all inventory callbacks" << llendl; + + // Is the destructor called by ordinary dereference, or because the app's shutting down? + // If the inventory callback manager goes away, we're shutting down, no longer want the callback. + if( LLInventoryCallbackManager::is_instantiated() ) + { + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend); + } + else + { + llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl; + } + } + +private: + LLUUID mCatID; + bool mAppend; +}; + + +//Inventory callback updating "dirty" state when destroyed +class LLUpdateDirtyState: public LLInventoryCallback +{ +public: + LLUpdateDirtyState() {} + virtual ~LLUpdateDirtyState() + { + if (LLAppearanceMgr::instanceExists()) + { + LLAppearanceMgr::getInstance()->updateIsDirty(); + } + } + virtual void fire(const LLUUID&) {} +}; + + +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering): + mFireCount(0), + mUpdateBaseOrder(update_base_outfit_ordering) +{ +} + +LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() +{ + llinfos << "done update appearance on destroy" << llendl; + + if (!LLApp::isExiting()) + { + LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder); + } +} + +void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); + const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; +#ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << llendl; +#endif + mFireCount++; +} + +struct LLFoundData +{ + LLFoundData() : + mAssetType(LLAssetType::AT_NONE), + mWearableType(LLWearableType::WT_INVALID), + mWearable(NULL) {} + + LLFoundData(const LLUUID& item_id, + const LLUUID& asset_id, + const std::string& name, + const LLAssetType::EType& asset_type, + const LLWearableType::EType& wearable_type, + const bool is_replacement = false + ) : + mItemID(item_id), + mAssetID(asset_id), + mName(name), + mAssetType(asset_type), + mWearableType(wearable_type), + mIsReplacement(is_replacement), + mWearable( NULL ) {} + + LLUUID mItemID; + LLUUID mAssetID; + std::string mName; + LLAssetType::EType mAssetType; + LLWearableType::EType mWearableType; + LLWearable* mWearable; + bool mIsReplacement; +}; + + +class LLWearableHoldingPattern +{ + LOG_CLASS(LLWearableHoldingPattern); + +public: + LLWearableHoldingPattern(); + ~LLWearableHoldingPattern(); + + bool pollFetchCompletion(); + void onFetchCompletion(); + bool isFetchCompleted(); + bool isTimedOut(); + + void checkMissingWearables(); + bool pollMissingWearables(); + bool isMissingCompleted(); + void recoverMissingWearable(LLWearableType::EType type); + void clearCOFLinksForMissingWearables(); + + void onWearableAssetFetch(LLWearable *wearable); + void onAllComplete(); + + typedef std::list found_list_t; + found_list_t& getFoundList(); + void eraseTypeToLink(LLWearableType::EType type); + void eraseTypeToRecover(LLWearableType::EType type); + void setObjItems(const LLInventoryModel::item_array_t& items); + void setGestItems(const LLInventoryModel::item_array_t& items); + bool isMostRecent(); + void handleLateArrivals(); + void resetTime(F32 timeout); + +private: + found_list_t mFoundList; + LLInventoryModel::item_array_t mObjItems; + LLInventoryModel::item_array_t mGestItems; + typedef std::set type_set_t; + type_set_t mTypesToRecover; + type_set_t mTypesToLink; + S32 mResolved; + LLTimer mWaitTime; + bool mFired; + typedef std::set type_set_hp; + static type_set_hp sActiveHoldingPatterns; + bool mIsMostRecent; + std::set mLateArrivals; + bool mIsAllComplete; +}; + +LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; + +LLWearableHoldingPattern::LLWearableHoldingPattern(): + mResolved(0), + mFired(false), + mIsMostRecent(true), + mIsAllComplete(false) +{ + if (sActiveHoldingPatterns.size()>0) + { + llinfos << "Creating LLWearableHoldingPattern when " + << sActiveHoldingPatterns.size() + << " other attempts are active." + << " Flagging others as invalid." + << llendl; + for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); + it != sActiveHoldingPatterns.end(); + ++it) + { + (*it)->mIsMostRecent = false; + } + + } + sActiveHoldingPatterns.insert(this); +} + +LLWearableHoldingPattern::~LLWearableHoldingPattern() +{ + sActiveHoldingPatterns.erase(this); +} + +bool LLWearableHoldingPattern::isMostRecent() +{ + return mIsMostRecent; +} + +LLWearableHoldingPattern::found_list_t& LLWearableHoldingPattern::getFoundList() +{ + return mFoundList; +} + +void LLWearableHoldingPattern::eraseTypeToLink(LLWearableType::EType type) +{ + mTypesToLink.erase(type); +} + +void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type) +{ + mTypesToRecover.erase(type); +} + +void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items) +{ + mObjItems = items; +} + +void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items) +{ + mGestItems = items; +} + +bool LLWearableHoldingPattern::isFetchCompleted() +{ + return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for? +} + +bool LLWearableHoldingPattern::isTimedOut() +{ + return mWaitTime.hasExpired(); +} + +void LLWearableHoldingPattern::checkMissingWearables() +{ + if (!isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + std::vector found_by_type(LLWearableType::WT_COUNT,0); + std::vector requested_by_type(LLWearableType::WT_COUNT,0); + for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + { + LLFoundData &data = *it; + if (data.mWearableType < LLWearableType::WT_COUNT) + requested_by_type[data.mWearableType]++; + if (data.mWearable) + found_by_type[data.mWearableType]++; + } + + for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type) + { + if (requested_by_type[type] > found_by_type[type]) + { + llwarns << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; + } + if (found_by_type[type] > 0) + continue; + if ( + // If at least one wearable of certain types (pants/shirt/skirt) + // was requested but none was found, create a default asset as a replacement. + // In all other cases, don't do anything. + // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud + // due to logic in LLVOAvatarSelf::getIsCloud(). + // For non-critical types (tatoo, socks, etc.) the wearable will just be missing. + (requested_by_type[type] > 0) && + ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) + { + mTypesToRecover.insert(type); + mTypesToLink.insert(type); + recoverMissingWearable((LLWearableType::EType)type); + llwarns << "need to replace " << type << llendl; + } + } + + resetTime(60.0F); + if (!pollMissingWearables()) + { + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); + } +} + +void LLWearableHoldingPattern::onAllComplete() +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->outputRezTiming("Agent wearables fetch complete"); + } + + if (!isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + // Activate all gestures in this folder + if (mGestItems.count() > 0) + { + llinfos << "Activating " << mGestItems.count() << " gestures" << llendl; + + LLGestureMgr::instance().activateGestures(mGestItems); + + // Update the inventory item labels to reflect the fact + // they are active. + LLViewerInventoryCategory* catp = + gInventory.getCategory(LLAppearanceMgr::instance().getCOF()); + + if (catp) + { + gInventory.updateCategory(catp); + gInventory.notifyObservers(); + } + } + + // Update wearables. + llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl; + LLAppearanceMgr::instance().updateAgentWearables(this, false); + + // Update attachments to match those requested. + if (isAgentAvatarValid()) + { + llinfos << "Updating " << mObjItems.count() << " attachments" << llendl; + LLAgentWearables::userUpdateAttachments(mObjItems); + } + + if (isFetchCompleted() && isMissingCompleted()) + { + // Only safe to delete if all wearable callbacks and all missing wearables completed. + delete this; + } + else + { + mIsAllComplete = true; + handleLateArrivals(); + } +} + +void LLWearableHoldingPattern::onFetchCompletion() +{ + if (!isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + checkMissingWearables(); +} + +// Runs as an idle callback until all wearables are fetched (or we time out). +bool LLWearableHoldingPattern::pollFetchCompletion() +{ + if (!isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + bool completed = isFetchCompleted(); + bool timed_out = isTimedOut(); + bool done = completed || timed_out; + + if (done) + { + llinfos << "polling, done status: " << completed << " timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; + + mFired = true; + + if (timed_out) + { + llwarns << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; + } + + onFetchCompletion(); + } + return done; +} + +class RecoveredItemLinkCB: public LLInventoryCallback +{ +public: + RecoveredItemLinkCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder): + mHolder(holder), + mWearable(wearable), + mType(type) + { + } + void fire(const LLUUID& item_id) + { + if (!mHolder->isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + llinfos << "Recovered item link for type " << mType << llendl; + mHolder->eraseTypeToLink(mType); + // Add wearable to FoundData for actual wearing + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + + if (linked_item) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + + if (item) + { + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, + true // is replacement + ); + found.mWearable = mWearable; + mHolder->getFoundList().push_front(found); + } + else + { + llwarns << "inventory item not found for recovered wearable" << llendl; + } + } + else + { + llwarns << "inventory link not found for recovered wearable" << llendl; + } + } +private: + LLWearableHoldingPattern* mHolder; + LLWearable *mWearable; + LLWearableType::EType mType; +}; + +class RecoveredItemCB: public LLInventoryCallback +{ +public: + RecoveredItemCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder): + mHolder(holder), + mWearable(wearable), + mType(type) + { + } + void fire(const LLUUID& item_id) + { + if (!mHolder->isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + llinfos << "Recovered item for type " << mType << llendl; + LLViewerInventoryItem *itemp = gInventory.getItem(item_id); + mWearable->setItemID(item_id); + LLPointer cb = new RecoveredItemLinkCB(mType,mWearable,mHolder); + mHolder->eraseTypeToRecover(mType); + llassert(itemp); + if (itemp) + { + link_inventory_item( gAgent.getID(), + item_id, + LLAppearanceMgr::instance().getCOF(), + itemp->getName(), + itemp->getDescription(), + LLAssetType::AT_LINK, + cb); + } + } +private: + LLWearableHoldingPattern* mHolder; + LLWearable *mWearable; + LLWearableType::EType mType; +}; + +void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type) +{ + if (!isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + // Try to recover by replacing missing wearable with a new one. + LLNotificationsUtil::add("ReplacedMissingWearable"); + lldebugs << "Wearable " << LLWearableType::getTypeLabel(type) + << " could not be downloaded. Replaced inventory item with default wearable." << llendl; + LLWearable* wearable = LLWearableList::instance().createNewWearable(type); + + // Add a new one in the lost and found folder. + const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + LLPointer cb = new RecoveredItemCB(type,wearable,this); + + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + lost_and_found_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + wearable->getAssetType(), + LLInventoryType::IT_WEARABLE, + wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); +} + +bool LLWearableHoldingPattern::isMissingCompleted() +{ + return mTypesToLink.size()==0 && mTypesToRecover.size()==0; +} + +void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() +{ + for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + { + LLFoundData &data = *it; + if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) + { + // Wearable link that was never resolved; remove links to it from COF + llinfos << "removing link for unresolved item " << data.mItemID.asString() << llendl; + LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID,false); + } + } +} + +bool LLWearableHoldingPattern::pollMissingWearables() +{ + if (!isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + bool timed_out = isTimedOut(); + bool missing_completed = isMissingCompleted(); + bool done = timed_out || missing_completed; + + if (!done) + { + llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size() + << " links " << mTypesToLink.size() + << " wearables, timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() + << " done " << done << llendl; + } + + if (done) + { + gAgentAvatarp->debugWearablesLoaded(); + + // BAP - if we don't call clearCOFLinksForMissingWearables() + // here, we won't have to add the link back in later if the + // wearable arrives late. This is to avoid corruption of + // wearable ordering info. Also has the effect of making + // unworn item links visible in the COF under some + // circumstances. + + //clearCOFLinksForMissingWearables(); + onAllComplete(); + } + return done; +} + +// Handle wearables that arrived after the timeout period expired. +void LLWearableHoldingPattern::handleLateArrivals() +{ + // Only safe to run if we have previously finished the missing + // wearables and other processing - otherwise we could be in some + // intermediate state - but have not been superceded by a later + // outfit change request. + if (mLateArrivals.size() == 0) + { + // Nothing to process. + return; + } + if (!isMostRecent()) + { + llwarns << "Late arrivals not handled - outfit change no longer valid" << llendl; + } + if (!mIsAllComplete) + { + llwarns << "Late arrivals not handled - in middle of missing wearables processing" << llendl; + } + + llinfos << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << llendl; + + // Update mFoundList using late-arriving wearables. + std::set replaced_types; + for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + iter != getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + for (std::set::iterator wear_it = mLateArrivals.begin(); + wear_it != mLateArrivals.end(); + ++wear_it) + { + LLWearable *wearable = *wear_it; + + if(wearable->getAssetID() == data.mAssetID) + { + data.mWearable = wearable; + + replaced_types.insert(data.mWearableType); + + // BAP - if we didn't call + // clearCOFLinksForMissingWearables() earlier, we + // don't need to restore the link here. Fixes + // wearable ordering problems. + + // LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false); + + // BAP failing this means inventory or asset server + // are corrupted in a way we don't handle. + llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType)); + break; + } + } + } + + // Remove COF links for any default wearables previously used to replace the late arrivals. + // All this pussyfooting around with a while loop and explicit + // iterator incrementing is to allow removing items from the list + // without clobbering the iterator we're using to navigate. + LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + while (iter != getFoundList().end()) + { + LLFoundData& data = *iter; + + // If an item of this type has recently shown up, removed the corresponding replacement wearable from COF. + if (data.mWearable && data.mIsReplacement && + replaced_types.find(data.mWearableType) != replaced_types.end()) + { + LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID,false); + std::list::iterator clobber_ator = iter; + ++iter; + getFoundList().erase(clobber_ator); + } + else + { + ++iter; + } + } + + // Clear contents of late arrivals. + mLateArrivals.clear(); + + // Update appearance based on mFoundList + LLAppearanceMgr::instance().updateAgentWearables(this, false); +} + +void LLWearableHoldingPattern::resetTime(F32 timeout) +{ + mWaitTime.reset(); + mWaitTime.setTimerExpirySec(timeout); +} + +void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) +{ + if (!isMostRecent()) + { + llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + } + + mResolved += 1; // just counting callbacks, not successes. + llinfos << "resolved " << mResolved << "/" << getFoundList().size() << llendl; + if (!wearable) + { + llwarns << "no wearable found" << llendl; + } + + if (mFired) + { + llwarns << "called after holder fired" << llendl; + if (wearable) + { + mLateArrivals.insert(wearable); + if (mIsAllComplete) + { + handleLateArrivals(); + } + } + return; + } + + if (!wearable) + { + return; + } + + for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + iter != getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + if(wearable->getAssetID() == data.mAssetID) + { + // Failing this means inventory or asset server are corrupted in a way we don't handle. + if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) + { + llwarns << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; + break; + } + + data.mWearable = wearable; + } + } +} + +static void onWearableAssetFetch(LLWearable* wearable, void* data) +{ + LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; + holder->onWearableAssetFetch(wearable); +} + + +static void removeDuplicateItems(LLInventoryModel::item_array_t& items) +{ + LLInventoryModel::item_array_t new_items; + std::set items_seen; + std::deque tmp_list; + // Traverse from the front and keep the first of each item + // encountered, so we actually keep the *last* of each duplicate + // item. This is needed to give the right priority when adding + // duplicate items to an existing outfit. + for (S32 i=items.count()-1; i>=0; i--) + { + LLViewerInventoryItem *item = items.get(i); + LLUUID item_id = item->getLinkedUUID(); + if (items_seen.find(item_id)!=items_seen.end()) + continue; + items_seen.insert(item_id); + tmp_list.push_front(item); + } + for (std::deque::iterator it = tmp_list.begin(); + it != tmp_list.end(); + ++it) + { + new_items.put(*it); + } + items = new_items; +} + +const LLUUID LLAppearanceMgr::getCOF() const +{ + return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); +} + + +const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() +{ + const LLUUID& current_outfit_cat = getCOF(); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + // Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't + // return preferred type. + LLIsType is_category( LLAssetType::AT_CATEGORY ); + gInventory.collectDescendentsIf(current_outfit_cat, + cat_array, + item_array, + false, + is_category, + false); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter); + const LLViewerInventoryCategory *cat = item->getLinkedCategory(); + if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + const LLUUID parent_id = cat->getParentUUID(); + LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id); + // if base outfit moved to trash it means that we don't have base outfit + if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH) + { + return NULL; + } + return item; + } + } + return NULL; +} + +bool LLAppearanceMgr::getBaseOutfitName(std::string& name) +{ + const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); + if(outfit_link) + { + const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory(); + if (cat) + { + name = cat->getName(); + return true; + } + } + return false; +} + +const LLUUID LLAppearanceMgr::getBaseOutfitUUID() +{ + const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); + if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null; + + const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory(); + if (!outfit_cat) return LLUUID::null; + + if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + llwarns << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << llendl; + return LLUUID::null; + } + + return outfit_cat->getUUID(); +} + +bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer cb) +{ + if (item_id_to_wear.isNull()) return false; + + // *TODO: issue with multi-wearable should be fixed: + // in this case this method will be called N times - loading started for each item + // and than N times will be called - loading completed for each item. + // That means subscribers will be notified that loading is done after first item in a batch is worn. + // (loading indicator disappears for example before all selected items are worn) + // Have not fix this issue for 2.1 because of stability reason. EXT-7777. + + // Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times +// gAgentWearables.notifyLoadingStarted(); + + LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear); + if (!item_to_wear) return false; + + if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID())) + { + LLPointer cb = new WearOnAvatarCallback(replace); + copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb); + return false; + } + else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) + { + return false; // not in library and not in agent's inventory + } + else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) + { + LLNotificationsUtil::add("CannotWearTrash"); + return false; + } + else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), LLAppearanceMgr::instance().getCOF())) // EXT-84911 + { + return false; + } + + switch (item_to_wear->getType()) + { + case LLAssetType::AT_CLOTHING: + if (gAgentWearables.areWearablesLoaded()) + { + S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType()); + if ((replace && wearable_count != 0) || + (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) ) + { + removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1), false); + } + addCOFItemLink(item_to_wear, do_update, cb); + } + break; + case LLAssetType::AT_BODYPART: + // TODO: investigate wearables may not be loaded at this point EXT-8231 + + // Remove the existing wearables of the same type. + // Remove existing body parts anyway because we must not be able to wear e.g. two skins. + removeCOFLinksOfType(item_to_wear->getWearableType(), false); + + addCOFItemLink(item_to_wear, do_update, cb); + break; + case LLAssetType::AT_OBJECT: + rez_attachment(item_to_wear, NULL, replace); + break; + default: return false;; + } + + return true; +} + +// Update appearance from outfit folder. +void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append) +{ + if (!proceed) + return; + LLAppearanceMgr::instance().updateCOF(category,append); +} + +void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit) +{ + LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit); + wearInventoryCategory(cat, false, false); +} + +// Open outfit renaming dialog. +void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id) +{ + LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id); + if (!cat) + { + return; + } + + LLSD args; + args["NAME"] = cat->getName(); + + LLSD payload; + payload["cat_id"] = outfit_id; + + LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2)); +} + +// User typed new outfit name. +// static +void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; // canceled + + std::string outfit_name = response["new_name"].asString(); + LLStringUtil::trim(outfit_name); + if (!outfit_name.empty()) + { + LLUUID cat_id = notification["payload"]["cat_id"].asUUID(); + rename_category(&gInventory, cat_id, outfit_name); + } +} + +void LLAppearanceMgr::setOutfitLocked(bool locked) +{ + if (mOutfitLocked == locked) + { + return; + } + + mOutfitLocked = locked; + if (locked) + { + mUnlockOutfitTimer->reset(); + mUnlockOutfitTimer->start(); + } + else + { + mUnlockOutfitTimer->stop(); + } + + LLOutfitObserver::instance().notifyOutfitLockChanged(); +} + +void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id) +{ + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + wearInventoryCategory(cat, false, true); +} + +void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); + + gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); + + LLInventoryModel::item_array_t::const_iterator it = items.begin(); + const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); + for( ; it_end != it; ++it) + { + LLViewerInventoryItem* item = *it; + removeItemFromAvatar(item->getUUID()); + } +} + +// Create a copy of src_id + contents as a subfolder of dst_id. +void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, + LLPointer cb) +{ + LLInventoryCategory *src_cat = gInventory.getCategory(src_id); + if (!src_cat) + { + llwarns << "folder not found for src " << src_id.asString() << llendl; + return; + } + llinfos << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << llendl; + LLUUID parent_id = dst_id; + if(parent_id.isNull()) + { + parent_id = gInventory.getRootFolderID(); + } + LLUUID subfolder_id = gInventory.createNewCategory( parent_id, + LLFolderType::FT_NONE, + src_cat->getName()); + shallowCopyCategoryContents(src_id, subfolder_id, cb); + + gInventory.notifyObservers(); +} + +// Copy contents of src_id to dst_id. +void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, + LLPointer cb) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(src_id, cats, items); + llinfos << "copying " << items->count() << " items" << llendl; + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + switch (item->getActualType()) + { + case LLAssetType::AT_LINK: + { + //LLInventoryItem::getDescription() is used for a new description + //to propagate ordering information saved in descriptions of links + link_inventory_item(gAgent.getID(), + item->getLinkedUUID(), + dst_id, + item->getName(), + item->LLInventoryItem::getDescription(), + LLAssetType::AT_LINK, cb); + break; + } + case LLAssetType::AT_LINK_FOLDER: + { + LLViewerInventoryCategory *catp = item->getLinkedCategory(); + // Skip copying outfit links. + if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) + { + link_inventory_item(gAgent.getID(), + item->getLinkedUUID(), + dst_id, + item->getName(), + item->getDescription(), + LLAssetType::AT_LINK_FOLDER, cb); + } + break; + } + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_OBJECT: + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_GESTURE: + { + llinfos << "copying inventory item " << item->getName() << llendl; + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + dst_id, + item->getName(), + cb); + break; + } + default: + // Ignore non-outfit asset types + break; + } + } +} + +BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) +{ + // These are the wearable items that are required for considering this + // folder as containing a complete outfit. + U32 required_wearables = 0; + required_wearables |= 1LL << LLWearableType::WT_SHAPE; + required_wearables |= 1LL << LLWearableType::WT_SKIN; + required_wearables |= 1LL << LLWearableType::WT_HAIR; + required_wearables |= 1LL << LLWearableType::WT_EYES; + + // These are the wearables that the folder actually contains. + U32 folder_wearables = 0; + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(folder_id, cats, items); + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + if (item->isWearableType()) + { + const LLWearableType::EType wearable_type = item->getWearableType(); + folder_wearables |= 1LL << wearable_type; + } + } + + // If the folder contains the required wearables, return TRUE. + return ((required_wearables & folder_wearables) == required_wearables); +} + +bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) +{ + // Disallow removing the base outfit. + if (outfit_cat_id == getBaseOutfitUUID()) + { + return false; + } + + // Check if the outfit folder itself is removable. + if (!get_is_category_removable(&gInventory, outfit_cat_id)) + { + return false; + } + + // Check for the folder's non-removable descendants. + LLFindNonRemovableObjects filter_non_removable; + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryModel::item_array_t::const_iterator it; + gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable); + if (!cats.empty() || !items.empty()) + { + return false; + } + + return true; +} + +// static +bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_worn); + return items.size() > 0; +} + +// static +bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) +{ + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } + + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + not_worn); + return items.size() > 0; +} + +bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) +{ + // Don't allow wearing anything while we're changing appearance. + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } + + // Check whether it's the base outfit. + if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID()) + { + return false; + } + + // Check whether the outfit contains any wearables we aren't wearing already (STORM-702). + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_worn); + return items.size() > 0; +} + +void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(category, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < items.count(); ++i) + { + LLViewerInventoryItem *item = items.get(i); + if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) + continue; + if (item->getIsLinkType()) + { + LLViewerInventoryCategory* catp = item->getLinkedCategory(); + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + gInventory.purgeObject(item->getUUID()); + } + } + } +} + +void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(category, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < items.count(); ++i) + { + LLViewerInventoryItem *item = items.get(i); + if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) + continue; + if (item->getIsLinkType()) + { + gInventory.purgeObject(item->getUUID()); + } + } +} + +// Keep the last N wearables of each type. For viewer 2.0, N is 1 for +// both body parts and clothing items. +void LLAppearanceMgr::filterWearableItems( + LLInventoryModel::item_array_t& items, S32 max_per_type) +{ + // Divvy items into arrays by wearable type. + std::vector items_by_type(LLWearableType::WT_COUNT); + divvyWearablesByType(items, items_by_type); + + // rebuild items list, retaining the last max_per_type of each array + items.clear(); + for (S32 i=0; i cb) +{ + for (S32 i=0; igetLinkedUUID(), + cat_uuid, + item->getName(), + item->LLInventoryItem::getDescription(), + LLAssetType::AT_LINK, + cb); + + const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); + const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; +#ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << llendl; +#endif + } +} + + +//void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0b) | Added: RLVa-1.2.0b +void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) +{ + LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new; + getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, false); + getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, false); + getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, false); + getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, false); + updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category); +} +void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, + LLInventoryModel::item_array_t& wear_items_new, + LLInventoryModel::item_array_t& obj_items_new, + LLInventoryModel::item_array_t& gest_items_new, + bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/) +// [/RLVa:KB] +{ + LLViewerInventoryCategory *pcat = gInventory.getCategory(idOutfit); + llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl; + + const LLUUID cof = getCOF(); + + // Deactivate currently active gestures in the COF, if replacing outfit + if (!append) + { + LLInventoryModel::item_array_t gest_items; + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); + for(S32 i = 0; i < gest_items.count(); ++i) + { + LLViewerInventoryItem *gest_item = gest_items.get(i); + if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) + { + LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); + } + } + } + + // Collect and filter descendents to determine new COF contents. + + // - Body parts: always include COF contents as a fallback in case any + // required parts are missing. + // Preserve body parts from COF if appending. + LLInventoryModel::item_array_t body_items; + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); +// getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + // Filter out any new body parts that can't be worn before adding them + if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) + body_items_new.erase(std::remove_if(body_items_new.begin(), body_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR_REPLACE)), body_items_new.end()); + body_items.insert(body_items.end(), body_items_new.begin(), body_items_new.end()); +// [/RLVa:KB] + // NOTE-RLVa: we don't actually want to favour COF body parts over the folder's body parts (if only because it breaks force wear) +// if (append) +// reverse(body_items.begin(), body_items.end()); + // Reduce body items to max of one per type. + removeDuplicateItems(body_items); + filterWearableItems(body_items, 1); + + // - Wearables: include COF contents only if appending. + LLInventoryModel::item_array_t wear_items; + if (append) + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + else if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) + { + // Make sure that all currently locked clothing layers remain in COF when replacing + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); + wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), rlvPredCanRemoveItem), wear_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + // Filter out any new wearables that can't be worn before adding them + if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) + wear_items_new.erase(std::remove_if(wear_items_new.begin(), wear_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), wear_items_new.end()); + wear_items.insert(wear_items.end(), wear_items_new.begin(), wear_items_new.end()); +// [/RLVa:KB] + // Reduce wearables to max of one per type. + removeDuplicateItems(wear_items); +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + //removeDuplicateWearableItemsByAssetID(wear_items); +// [/SL:KB] + filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); + + // - Attachments: include COF contents only if appending. + LLInventoryModel::item_array_t obj_items; + if (append) + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b + else if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + // Make sure that all currently locked attachments remain in COF when replacing + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); + obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), rlvPredCanRemoveItem), obj_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b + // Filter out any new attachments that can't be worn before adding them + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), obj_items_new.end()); + obj_items.insert(obj_items.end(), obj_items_new.begin(), obj_items_new.end()); +// [/RLVa:KB] + removeDuplicateItems(obj_items); + + // + // - Gestures: include COF contents only if appending. + // + LLInventoryModel::item_array_t gest_items; + if (append) + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); +// getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Added: RLVa-1.2.0b + gest_items.insert(gest_items.end(), gest_items_new.begin(), gest_items_new.end()); +// [/RLVa:KB] + removeDuplicateItems(gest_items); + + // Create links to new COF contents. + llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl; + LLPointer link_waiter = new LLUpdateAppearanceOnDestroy(!append); + +// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + //if (!append) + { +// [/SL:KB] + // Remove current COF contents. + bool keep_outfit_links = append; + purgeCategory(cof, keep_outfit_links); + gInventory.notifyObservers(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking body items" << llendl; +#endif + linkAll(cof, body_items, link_waiter); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking wear items" << llendl; +#endif + linkAll(cof, wear_items, link_waiter); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking obj items" << llendl; +#endif + linkAll(cof, obj_items, link_waiter); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking gesture items" << llendl; +#endif + linkAll(cof, gest_items, link_waiter); +// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + } + /*else + { + // Synchronize COF + // -> it's possible that we don't link to any new items in which case 'link_waiter' fires when it goes out of scope below + syncCOF(body_items, LLAssetType::AT_BODYPART, link_waiter); + syncCOF(wear_items, LLAssetType::AT_CLOTHING, link_waiter); + syncCOF(obj_items, LLAssetType::AT_OBJECT, link_waiter); + syncCOF(gest_items, LLAssetType::AT_GESTURE, link_waiter); + gInventory.notifyObservers(); + }*/ +// [/SL:KB] + + // Add link to outfit if category is an outfit. +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Added: RLVa-1.2.0b + /*if ( (!append) && (idOutfit.notNull()) ) + { + createBaseOutfitLink(idOutfit, link_waiter); + }*/ +// [/RLVa:KB] + if (!append) + { + createBaseOutfitLink(idOutfit, link_waiter); + } + llinfos << "waiting for LLUpdateAppearanceOnDestroy" << llendl; +} + +void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) +{ + // MULTI-WEARABLE TODO + /*LLSidepanelAppearance* panel_appearance = + dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel_appearance) + { + panel_appearance->refreshCurrentOutfitName(name); + }*/ +} + +void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer link_waiter) +{ + const LLUUID cof = getCOF(); + LLViewerInventoryCategory* catp = gInventory.getCategory(category); + std::string new_outfit_name = ""; + + purgeBaseOutfitLink(cof); + + if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "", + LLAssetType::AT_LINK_FOLDER, link_waiter); + new_outfit_name = catp->getName(); + } + + updatePanelOutfitName(new_outfit_name); +} + +void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, bool append) +{ + lldebugs << "updateAgentWearables()" << llendl; + LLInventoryItem::item_array_t items; + LLDynamicArray< LLWearable* > wearables; + + // For each wearable type, find the wearables of that type. + for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + { + for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin(); + iter != holder->getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + LLWearable* wearable = data.mWearable; + if( wearable && ((S32)wearable->getType() == i) ) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); + if( item && (item->getAssetUUID() == wearable->getAssetID()) ) + { + items.put(item); + wearables.put(wearable); + } + } + } + } + + if(wearables.count() > 0) + { + gAgentWearables.setWearableOutfit(items, wearables, !append); + } + +// dec_busy_count(); +} + +static void remove_non_link_items(LLInventoryModel::item_array_t &items) +{ + LLInventoryModel::item_array_t pruned_items; + for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); + iter != items.end(); + ++iter) + { + const LLViewerInventoryItem *item = (*iter); + if (item && item->getIsLinkType()) + { + pruned_items.push_back((*iter)); + } + } + items = pruned_items; +} + +//a predicate for sorting inventory items by actual descriptions +bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2) +{ + if (!item1 || !item2) + { + llwarning("either item1 or item2 is NULL", 0); + return true; + } + + return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription(); +} + +void item_array_diff(LLInventoryModel::item_array_t& full_list, + LLInventoryModel::item_array_t& keep_list, + LLInventoryModel::item_array_t& kill_list) + +{ + for (LLInventoryModel::item_array_t::iterator it = full_list.begin(); + it != full_list.end(); + ++it) + { + LLViewerInventoryItem *item = *it; + if (keep_list.find(item) < 0) // Why on earth does LLDynamicArray need to redefine find()? + { + kill_list.push_back(item); + } + } +} + +S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, + LLAssetType::EType type, + S32 max_items, + LLInventoryModel::item_array_t& items_to_kill) +{ + S32 to_kill_count = 0; + + LLInventoryModel::item_array_t items; + getDescendentsOfAssetType(cat_id, items, type, false); + LLInventoryModel::item_array_t curr_items = items; + removeDuplicateItems(items); + if (max_items > 0) + { + filterWearableItems(items, max_items); + } + LLInventoryModel::item_array_t kill_items; + item_array_diff(curr_items,items,kill_items); + for (LLInventoryModel::item_array_t::iterator it = kill_items.begin(); + it != kill_items.end(); + ++it) + { + items_to_kill.push_back(*it); + to_kill_count++; + } + return to_kill_count; +} + + +void LLAppearanceMgr::enforceItemRestrictions() +{ + S32 purge_count = 0; + LLInventoryModel::item_array_t items_to_kill; + + purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART, + 1, items_to_kill); + purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING, + LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); + purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT, + -1, items_to_kill); + + if (items_to_kill.size()>0) + { + for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin(); + it != items_to_kill.end(); + ++it) + { + LLViewerInventoryItem *item = *it; + llinfos << "purging duplicate or excess item " << item->getName() << llendl; + gInventory.purgeObject(item->getUUID()); + } + gInventory.notifyObservers(); + } +} + +void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) +{ + if (mIsInUpdateAppearanceFromCOF) + { + llwarns << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << llendl; + return; + } + + BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); + + llinfos << "starting" << llendl; + + //checking integrity of the COF in terms of ordering of wearables, + //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) + updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); + + // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but + // this should catch anything that gets through. + enforceItemRestrictions(); + + // update dirty flag to see if the state of the COF matches + // the saved outfit stored as a folder link + updateIsDirty(); + + //dumpCat(getCOF(),"COF, start"); + + bool follow_folder_links = true; + LLUUID current_outfit_id = getCOF(); + + // Find all the wearables that are in the COF's subtree. + lldebugs << "LLAppearanceMgr::updateFromCOF()" << llendl; + LLInventoryModel::item_array_t wear_items; + LLInventoryModel::item_array_t obj_items; + LLInventoryModel::item_array_t gest_items; + getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links); + // Get rid of non-links in case somehow the COF was corrupted. + remove_non_link_items(wear_items); + remove_non_link_items(obj_items); + remove_non_link_items(gest_items); + + dumpItemArray(wear_items,"asset_dump: wear_item"); + dumpItemArray(obj_items,"asset_dump: obj_item"); + + if(!wear_items.count()) + { + LLNotificationsUtil::add("CouldNotPutOnOutfit"); + return; + } + + //preparing the list of wearables in the correct order for LLAgentWearables + sortItemsByActualDescription(wear_items); + + + LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; + + holder->setObjItems(obj_items); + holder->setGestItems(gest_items); + + // Note: can't do normal iteration, because if all the + // wearables can be resolved immediately, then the + // callback will be called (and this object deleted) + // before the final getNextData(). + + for(S32 i = 0; i < wear_items.count(); ++i) + { + LLViewerInventoryItem *item = wear_items.get(i); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + + // Fault injection: use debug setting to test asset + // fetch failures (should be replaced by new defaults in + // lost&found). + U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); + + if (item && item->getIsLinkType() && linked_item) + { + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID + ); + + if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) + { + found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + } + //pushing back, not front, to preserve order of wearables for LLAgentWearables + holder->getFoundList().push_back(found); + } + else + { + if (!item) + { + llwarns << "Attempt to wear a null item " << llendl; + } + else if (!linked_item) + { + llwarns << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << llendl; + } + } + } + + for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); + it != holder->getFoundList().end(); ++it) + { + LLFoundData& found = *it; + + lldebugs << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; + + // Fetch the wearables about to be worn. + LLWearableList::instance().getAsset(found.mAssetID, + found.mName, + found.mAssetType, + onWearableAssetFetch, + (void*)holder); + + } + + holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime")); + if (!holder->pollFetchCompletion()) + { + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); + } +} + +void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLAssetType::EType type, + bool follow_folder_links) +{ + LLInventoryModel::cat_array_t cats; + LLIsType is_of_type(type); + gInventory.collectDescendentsIf(category, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_of_type, + follow_folder_links); +} + +void LLAppearanceMgr::getUserDescendents(const LLUUID& category, + LLInventoryModel::item_array_t& wear_items, + LLInventoryModel::item_array_t& obj_items, + LLInventoryModel::item_array_t& gest_items, + bool follow_folder_links) +{ + LLInventoryModel::cat_array_t wear_cats; + LLFindWearables is_wearable; + gInventory.collectDescendentsIf(category, + wear_cats, + wear_items, + LLInventoryModel::EXCLUDE_TRASH, + is_wearable, + follow_folder_links); + + LLInventoryModel::cat_array_t obj_cats; + LLIsType is_object( LLAssetType::AT_OBJECT ); + gInventory.collectDescendentsIf(category, + obj_cats, + obj_items, + LLInventoryModel::EXCLUDE_TRASH, + is_object, + follow_folder_links); + + // Find all gestures in this folder + LLInventoryModel::cat_array_t gest_cats; + LLIsType is_gesture( LLAssetType::AT_GESTURE ); + gInventory.collectDescendentsIf(category, + gest_cats, + gest_items, + LLInventoryModel::EXCLUDE_TRASH, + is_gesture, + follow_folder_links); +} + +void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) +{ + if(!category) return; + + gAgentWearables.notifyLoadingStarted(); + + llinfos << "wearInventoryCategory( " << category->getName() + << " )" << llendl; + + callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, + &LLAppearanceMgr::instance(), + category->getUUID(), copy, append)); +} + +void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) +{ + llinfos << "starting" << llendl; + + // We now have an outfit ready to be copied to agent inventory. Do + // it, and wear that outfit normally. + LLInventoryCategory* cat = gInventory.getCategory(cat_id); + if(copy_items) + { + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + std::string name; + if(!cat) + { + // should never happen. + name = "New Outfit"; + } + else + { + name = cat->getName(); + } + LLViewerInventoryItem* item = NULL; + LLInventoryModel::item_array_t::const_iterator it = items->begin(); + LLInventoryModel::item_array_t::const_iterator end = items->end(); + LLUUID pid; + for(; it < end; ++it) + { + item = *it; + if(item) + { + if(LLInventoryType::IT_GESTURE == item->getInventoryType()) + { + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + } + else + { + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + } + break; + } + } + if(pid.isNull()) + { + pid = gInventory.getRootFolderID(); + } + + LLUUID new_cat_id = gInventory.createNewCategory( + pid, + LLFolderType::FT_NONE, + name); + LLPointer cb = new LLWearInventoryCategoryCallback(new_cat_id, append); + it = items->begin(); + for(; it < end; ++it) + { + item = *it; + if(item) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + new_cat_id, + std::string(), + cb); + } + } + // BAP fixes a lag in display of created dir. + gInventory.notifyObservers(); + } + else + { + // Wear the inventory category. + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append); + } +} + +// *NOTE: hack to get from avatar inventory to avatar +void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append ) +{ + // Avoid unintentionally overwriting old wearables. We have to do + // this up front to avoid having to deal with the case of multiple + // wearables being dirty. + if(!category) return; + + llinfos << "wearInventoryCategoryOnAvatar( " << category->getName() + << " )" << llendl; + + if (gAgentCamera.cameraCustomizeAvatar()) + { + // switching to outfit editor should automagically save any currently edited wearable + //LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); // MULTI-WEARABLES TODO + } + + LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); +} + +void LLAppearanceMgr::wearOutfitByName(const std::string& name) +{ + llinfos << "Wearing category " << name << llendl; + //inc_busy_count(); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLNameCategoryCollector has_name(name); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + bool copy_items = false; + LLInventoryCategory* cat = NULL; + if (cat_array.count() > 0) + { + // Just wear the first one that matches + cat = cat_array.get(0); + } + else + { + gInventory.collectDescendentsIf(LLUUID::null, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + if(cat_array.count() > 0) + { + cat = cat_array.get(0); + copy_items = true; + } + } + + if(cat) + { + LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); + } + else + { + llwarns << "Couldn't find outfit " <isWearableType() && b->isWearableType() && + (a->getWearableType() == b->getWearableType())); +} + +class LLDeferredCOFLinkObserver: public LLInventoryObserver +{ +public: + LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer cb = NULL): + mItemID(item_id), + mDoUpdate(do_update), + mCallback(cb) + { + } + + ~LLDeferredCOFLinkObserver() + { + } + + /* virtual */ void changed(U32 mask) + { + const LLInventoryItem *item = gInventory.getItem(mItemID); + if (item) + { + gInventory.removeObserver(this); + LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback); + delete this; + } + } + +private: + const LLUUID mItemID; + bool mDoUpdate; + LLPointer mCallback; +}; + + +// BAP - note that this runs asynchronously if the item is not already loaded from inventory. +// Dangerous if caller assumes link will exist after calling the function. +void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer cb) +{ + const LLInventoryItem *item = gInventory.getItem(item_id); + if (!item) + { + LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb); + gInventory.addObserver(observer); + } + else + { + addCOFItemLink(item, do_update, cb); + } +} + +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer cb) +{ + const LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem) + { + llwarns << "not an llviewerinventoryitem, failed" << llendl; + return; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID()); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::getCOF(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + bool linked_already = false; + U32 count = 0; + for (S32 i=0; igetWearableType(); + + const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE) + || (wearable_type == LLWearableType::WT_HAIR) + || (wearable_type == LLWearableType::WT_EYES) + || (wearable_type == LLWearableType::WT_SKIN); + + if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) + { + linked_already = true; + } + // Are these links to different items of the same body part + // type? If so, new item will replace old. + else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) + { + ++count; + if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type)) + { + gInventory.purgeObject(inv_item->getUUID()); + } + else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) + { + // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE + gInventory.purgeObject(inv_item->getUUID()); + } +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + else if ( (vitem->getWearableType() == wearable_type) && (vitem->getAssetUUID() == inv_item->getAssetUUID()) ) + { + // Only allow one wearable per unique asset + linked_already = true; + } +// [/SL:KB] + } + } + + if (linked_already) + { + if (do_update) + { + LLAppearanceMgr::updateAppearanceFromCOF(); + } + return; + } + else + { + if(do_update && cb.isNull()) + { + cb = new ModifiedCOFCallback; + } + const std::string description = vitem->getIsLinkType() ? vitem->getDescription() : ""; + link_inventory_item( gAgent.getID(), + vitem->getLinkedUUID(), + getCOF(), + vitem->getName(), + description, + LLAssetType::AT_LINK, + cb); + } + return; +} + +// BAP remove ensemble code for 2.1? +void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update ) +{ +#if SUPPORT_ENSEMBLES + // BAP add check for already in COF. + LLPointer cb = do_update ? new ModifiedCOFCallback : 0; + link_inventory_item( gAgent.getID(), + cat->getLinkedUUID(), + getCOF(), + cat->getName(), + cat->getDescription(), + LLAssetType::AT_LINK_FOLDER, + cb); +#endif +} + +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, bool do_update) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::getCOF(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; igetIsLinkType() && item->getLinkedUUID() == item_id) + { + gInventory.purgeObject(item->getUUID()); + } + } + if (do_update) + { + LLAppearanceMgr::updateAppearanceFromCOF(); + } +} + +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, bool do_update) +{ + LLFindWearablesOfType filter_wearables_of_type(type); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryModel::item_array_t::const_iterator it; + + gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); + for (it = items.begin(); it != items.end(); ++it) + { + const LLViewerInventoryItem* item = *it; + if (item->getIsLinkType()) // we must operate on links only + { + gInventory.purgeObject(item->getUUID()); + } + } + + if (do_update) + { + updateAppearanceFromCOF(); + } +} + +bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2) +{ + if (!item1 || !item2) + { + llwarning("item1, item2 cannot be null, something is very wrong", 0); + return true; + } + + return item1->getLinkedUUID() < item2->getLinkedUUID(); +} + +void LLAppearanceMgr::updateIsDirty() +{ + LLUUID cof = getCOF(); + LLUUID base_outfit; + + // find base outfit link + const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink(); + LLViewerInventoryCategory* catp = NULL; + if (base_outfit_item && base_outfit_item->getIsLinkType()) + { + catp = base_outfit_item->getLinkedCategory(); + } + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + base_outfit = catp->getUUID(); + } + + // Set dirty to "false" if no base outfit found to disable "Save" + // and leave only "Save As" enabled in My Outfits. + mOutfitIsDirty = false; + + if (base_outfit.notNull()) + { + LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK); + + LLInventoryModel::cat_array_t cof_cats; + LLInventoryModel::item_array_t cof_items; + gInventory.collectDescendentsIf(cof, cof_cats, cof_items, + LLInventoryModel::EXCLUDE_TRASH, collector); + + LLInventoryModel::cat_array_t outfit_cats; + LLInventoryModel::item_array_t outfit_items; + gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, + LLInventoryModel::EXCLUDE_TRASH, collector); + + if(outfit_items.count() != cof_items.count()) + { + // Current outfit folder should have one more item than the outfit folder. + // this one item is the link back to the outfit folder itself. + mOutfitIsDirty = true; + return; + } + + //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions) + std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid); + std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid); + + for (U32 i = 0; i < cof_items.size(); ++i) + { + LLViewerInventoryItem *item1 = cof_items.get(i); + LLViewerInventoryItem *item2 = outfit_items.get(i); + + if (item1->getLinkedUUID() != item2->getLinkedUUID() || + item1->getName() != item2->getName() || + item1->LLInventoryItem::getDescription() != item2->LLInventoryItem::getDescription()) + { + mOutfitIsDirty = true; + return; + } + } + } +} + +// *HACK: Must match name in Library or agent inventory +const std::string ROOT_GESTURES_FOLDER = "Gestures"; +const std::string COMMON_GESTURES_FOLDER = "Common Gestures"; +const std::string MALE_GESTURES_FOLDER = "Male Gestures"; +const std::string FEMALE_GESTURES_FOLDER = "Female Gestures"; +const std::string SPEECH_GESTURES_FOLDER = "Speech Gestures"; +const std::string OTHER_GESTURES_FOLDER = "Other Gestures"; + +void LLAppearanceMgr::copyLibraryGestures() +{ + llinfos << "Copying library gestures" << llendl; + + // Copy gestures + LLUUID lib_gesture_cat_id = + gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE,false,true); + if (lib_gesture_cat_id.isNull()) + { + llwarns << "Unable to copy gestures, source category not found" << llendl; + } + LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + + std::vector gesture_folders_to_copy; + gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER); + + for(std::vector::iterator it = gesture_folders_to_copy.begin(); + it != gesture_folders_to_copy.end(); + ++it) + { + std::string& folder_name = *it; + + LLPointer cb(NULL); + + // After copying gestures, activate Common, Other, plus + // Male and/or Female, depending upon the initial outfit gender. + ESex gender = gAgentAvatarp->getSex(); + + std::string activate_male_gestures; + std::string activate_female_gestures; + switch (gender) { + case SEX_MALE: + activate_male_gestures = MALE_GESTURES_FOLDER; + break; + case SEX_FEMALE: + activate_female_gestures = FEMALE_GESTURES_FOLDER; + break; + case SEX_BOTH: + activate_male_gestures = MALE_GESTURES_FOLDER; + activate_female_gestures = FEMALE_GESTURES_FOLDER; + break; + } + + if (folder_name == activate_male_gestures || + folder_name == activate_female_gestures || + folder_name == COMMON_GESTURES_FOLDER || + folder_name == OTHER_GESTURES_FOLDER) + { + cb = new ActivateGestureCallback; + } + + LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); + if (cat_id.isNull()) + { + llwarns << "failed to find gesture folder for " << folder_name << llendl; + } + else + { + llinfos << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << llendl; + callAfterCategoryFetch(cat_id, + boost::bind(&LLAppearanceMgr::shallowCopyCategory, + &LLAppearanceMgr::instance(), + cat_id, dst_id, cb)); + } + } +} + +void LLAppearanceMgr::autopopulateOutfits() +{ + // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) + // then auto-populate outfits from the library into the My Outfits folder. + + llinfos << "avatar fully visible" << llendl; + + static bool check_populate_my_outfits = true; + if (check_populate_my_outfits && + (LLInventoryModel::getIsFirstTimeInViewer2() + || gSavedSettings.getBOOL("MyOutfitsAutofill"))) + { + gAgentWearables.populateMyOutfitsFolder(); + } + check_populate_my_outfits = false; +} + +// Handler for anything that's deferred until avatar de-clouds. +void LLAppearanceMgr::onFirstFullyVisible() +{ + gAgentAvatarp->outputRezTiming("Avatar fully loaded"); + gAgentAvatarp->reportAvatarRezTime(); + gAgentAvatarp->debugAvatarVisible(); + + // The auto-populate is failing at the point of generating outfits + // folders, so don't do the library copy until that is resolved. + // autopopulateOutfits(); + + // If this is the first time we've ever logged in, + // then copy default gestures from the library. + if (gAgent.isFirstLogin()) { + copyLibraryGestures(); + } +} + +bool LLAppearanceMgr::updateBaseOutfit() +{ + if (isOutfitLocked()) + { + // don't allow modify locked outfit + llassert(!isOutfitLocked()); + return false; + } + setOutfitLocked(true); + + gAgentWearables.notifyLoadingStarted(); + + const LLUUID base_outfit_id = getBaseOutfitUUID(); + if (base_outfit_id.isNull()) return false; + + updateClothingOrderingInfo(); + + // in a Base Outfit we do not remove items, only links + purgeCategory(base_outfit_id, false); + + + LLPointer dirty_state_updater = new LLUpdateDirtyState(); + + //COF contains only links so we copy to the Base Outfit only links + shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater); + + return true; +} + +void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type) +{ + items_by_type.resize(LLWearableType::WT_COUNT); + if (items.empty()) return; + + for (S32 i=0; iisWearableType()) + continue; + LLWearableType::EType type = item->getWearableType(); + if(type < 0 || type >= LLWearableType::WT_COUNT) + { + LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; + continue; + } + items_by_type[type].push_back(item); + } +} + +std::string build_order_string(LLWearableType::EType type, U32 i) +{ + std::ostringstream order_num; + order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; + return order_num.str(); +} + +struct WearablesOrderComparator +{ + LOG_CLASS(WearablesOrderComparator); + WearablesOrderComparator(const LLWearableType::EType type) + { + mControlSize = build_order_string(type, 0).size(); + }; + + bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) + { + if (!item1 || !item2) + { + llwarning("either item1 or item2 is NULL", 0); + return true; + } + + const std::string& desc1 = item1->LLInventoryItem::getDescription(); + const std::string& desc2 = item2->LLInventoryItem::getDescription(); + + bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); + bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); + + if (item1_valid && item2_valid) + return desc1 < desc2; + + //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, + //items with ordering information but not for the associated wearables type + if (!item1_valid && item2_valid) + return false; + + return true; + } + + U32 mControlSize; +}; + +void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering) +{ + if (cat_id.isNull()) + { + cat_id = getCOF(); + if (update_base_outfit_ordering) + { + const LLUUID base_outfit_id = getBaseOutfitUUID(); + if (base_outfit_id.notNull()) + { + updateClothingOrderingInfo(base_outfit_id,false); + } + } + } + + // COF is processed if cat_id is not specified + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false); + + wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); + divvyWearablesByType(wear_items, items_by_type); + + bool inventory_changed = false; + for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) + { + + U32 size = items_by_type[type].size(); + if (!size) continue; + + //sinking down invalid items which need reordering + std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); + + //requesting updates only for those links which don't have "valid" descriptions + for (U32 i = 0; i < size; i++) + { + LLViewerInventoryItem* item = items_by_type[type][i]; + if (!item) continue; + + std::string new_order_str = build_order_string((LLWearableType::EType)type, i); + if (new_order_str == item->LLInventoryItem::getDescription()) continue; + + item->setDescription(new_order_str); + item->setComplete(TRUE); + item->updateServer(FALSE); + gInventory.updateItem(item); + + inventory_changed = true; + } + } + + //*TODO do we really need to notify observers? + if (inventory_changed) gInventory.notifyObservers(); +} + + + + +class LLShowCreatedOutfit: public LLInventoryCallback +{ +public: + LLShowCreatedOutfit(LLUUID& folder_id, bool show_panel = true): mFolderID(folder_id), mShowPanel(show_panel) + {} + + virtual ~LLShowCreatedOutfit() + { + if (!LLApp::isRunning()) + { + llwarns << "called during shutdown, skipping" << llendl; + return; + } + + LLSD key; + + //EXT-7727. For new accounts LLShowCreatedOutfit is created during login process + // add may be processed after login process is finished + // MULTI-WEARABLES TODO + /*if (mShowPanel) + { + LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); + + } + LLOutfitsList *outfits_list = + dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); + if (outfits_list) + { + outfits_list->setSelectedOutfitByUUID(mFolderID); + }*/ + + LLAppearanceMgr::getInstance()->updateIsDirty(); + gAgentWearables.notifyLoadingFinished(); // New outfit is saved. + LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + } + + virtual void fire(const LLUUID&) + {} + +private: + LLUUID mFolderID; + bool mShowPanel; +}; + +LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) +{ + if (!isAgentAvatarValid()) return LLUUID::null; + + gAgentWearables.notifyLoadingStarted(); + + // First, make a folder in the My Outfits directory. + const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + LLUUID folder_id = gInventory.createNewCategory( + parent_id, + LLFolderType::FT_OUTFIT, + new_folder_name); + + updateClothingOrderingInfo(); + + LLPointer cb = new LLShowCreatedOutfit(folder_id,show_panel); + shallowCopyCategoryContents(getCOF(),folder_id, cb); + createBaseOutfitLink(folder_id, cb); + + dumpCat(folder_id,"COF, new outfit"); + + return folder_id; +} + +void LLAppearanceMgr::wearBaseOutfit() +{ + const LLUUID& base_outfit_id = getBaseOutfitUUID(); + if (base_outfit_id.isNull()) return; + + updateCOF(base_outfit_id); +} + +void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) +{ + LLViewerInventoryItem * item_to_remove = gInventory.getItem(id_to_remove); + if (!item_to_remove) return; + + switch (item_to_remove->getType()) + { + case LLAssetType::AT_CLOTHING: +// if (get_is_item_worn(id_to_remove)) +// { +// //*TODO move here the exact removing code from LLWearableBridge::removeItemFromAvatar in the future +// LLWearableBridge::removeItemFromAvatar(item_to_remove); +// } +// [SL:KB] - Patch: Appearance-RemoveWearableFromAvatar | Checked: 2010-08-13 (Catznip-3.0.0a) | Added: Catznip-2.1.1d +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + if ( (!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(item_to_remove)) ) +// [/RLVa:KB] + { + const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(item_to_remove->getLinkedUUID()); + if ( (pWearable) && (LLAssetType::AT_BODYPART != pWearable->getAssetType()) ) + { + U32 idxWearable = gAgentWearables.getWearableIndex(pWearable); + if (idxWearable < LLAgentWearables::MAX_CLOTHING_PER_TYPE) + { + gAgentWearables.removeWearable(pWearable->getType(), false, idxWearable); + + LLAppearanceMgr::instance().removeCOFItemLinks(item_to_remove->getLinkedUUID(), false); + gInventory.notifyObservers(); + +// [RLVa:KB] - Checked: 2011-06-07 (RLVa-1.3.1b) | Added: RLVa-1.3.1b + //RlvBehaviourNotifyHandler::onTakeOff(pWearable->getType(), true); +// [/RLVa:KB] + } + } + } +// [/SL:KB] + break; + case LLAssetType::AT_OBJECT: + LLVOAvatarSelf::detachAttachmentIntoInventory(item_to_remove->getLinkedUUID()); + default: + break; + } + + // *HACK: Force to remove garbage from COF. + // Unworn links or objects can't be processed by existed removing functionality + // since it is not designed for such cases. As example attachment object can't be removed + // since sever don't sends message _PREHASH_KillObject in that case. + // Also we can't check is link was successfully removed from COF since in case + // deleting attachment link removing performs asynchronously in process_kill_object callback. + removeCOFItemLinks(id_to_remove,false); +} + +bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) +{ + if (!item || !item->isWearableType()) return false; + if (item->getType() != LLAssetType::AT_CLOTHING) return false; + if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; + + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesOfType filter_wearables_of_type(item->getWearableType()); + gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); + if (items.empty()) return false; + + // We assume that the items have valid descriptions. + std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); + + if (closer_to_body && items.front() == item) return false; + if (!closer_to_body && items.back() == item) return false; + + LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); + if (items.end() == it) return false; + + + //swapping descriptions + closer_to_body ? --it : ++it; + LLViewerInventoryItem* swap_item = *it; + if (!swap_item) return false; + std::string tmp = swap_item->LLInventoryItem::getDescription(); + swap_item->setDescription(item->LLInventoryItem::getDescription()); + item->setDescription(tmp); + + + //items need to be updated on a dataserver + item->setComplete(TRUE); + item->updateServer(FALSE); + gInventory.updateItem(item); + + swap_item->setComplete(TRUE); + swap_item->updateServer(FALSE); + gInventory.updateItem(swap_item); + + //to cause appearance of the agent to be updated + bool result = false; + if (result = gAgentWearables.moveWearable(item, closer_to_body)) + { + gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE); + } + + setOutfitDirty(true); + + //*TODO do we need to notify observers here in such a way? + gInventory.notifyObservers(); + + return result; +} + +//static +void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items) +{ + if (items.size() < 2) return; + + std::sort(items.begin(), items.end(), sort_by_description); +} + +//#define DUMP_CAT_VERBOSE + +void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + +#ifdef DUMP_CAT_VERBOSE + llinfos << llendl; + llinfos << str << llendl; + S32 hitcount = 0; + for(S32 i=0; igetName() <getLinkedItem() : NULL; + LLUUID asset_id; + if (linked_item) + { + asset_id = linked_item->getAssetUUID(); + } + llinfos << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << llendl; + } + llinfos << llendl; +} + +LLAppearanceMgr::LLAppearanceMgr(): + mAttachmentInvLinkEnabled(false), + mOutfitIsDirty(false), + mOutfitLocked(false), + mIsInUpdateAppearanceFromCOF(false) +{ + LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); + + // unlock outfit on save operation completed + outfit_observer.addCOFSavedCallback(boost::bind( + &LLAppearanceMgr::setOutfitLocked, this, false)); + + mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( + "OutfitOperationsTimeout"))); + + gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL); +} + +LLAppearanceMgr::~LLAppearanceMgr() +{ +} + +void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) +{ + llinfos << "setAttachmentInvLinkEnable => " << (int) val << llendl; + mAttachmentInvLinkEnabled = val; +} + +void dumpAttachmentSet(const std::set& atts, const std::string& msg) +{ + llinfos << msg << llendl; + for (std::set::const_iterator it = atts.begin(); + it != atts.end(); + ++it) + { + LLUUID item_id = *it; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item) + llinfos << "atts " << item->getName() << llendl; + else + llinfos << "atts " << "UNKNOWN[" << item_id.asString() << "]" << llendl; + } + llinfos << llendl; +} + +void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + + if (mAttachmentInvLinkEnabled) + { + // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF. + // it will trigger gAgentWariables.notifyLoadingFinished() + // But it is not acceptable solution. See EXT-7777 + LLAppearanceMgr::addCOFItemLink(item_id, false); // Add COF link for item. + } + else + { + //llinfos << "no link changes, inv link not enabled" << llendl; + } +} + +void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + + if (mAttachmentInvLinkEnabled) + { + LLAppearanceMgr::removeCOFItemLinks(item_id, false); + } + else + { + //llinfos << "no link changes, inv link not enabled" << llendl; + } +} + +BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const +{ + return gInventory.isObjectDescendentOf(obj_id, getCOF()); +} + +// static +bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + find_links); + + return !items.empty(); +} + +BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const +{ + if (!getIsInCOF(obj_id)) return FALSE; + + // If a non-link somehow ended up in COF, allow deletion. + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && !obj->getIsLinkType()) + { + return FALSE; + } + + // For now, don't allow direct deletion from the COF. Instead, force users + // to choose "Detach" or "Take Off". + return TRUE; + /* + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (!obj) return FALSE; + + // Can't delete bodyparts, since this would be equivalent to removing the item. + if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; + + // Can't delete the folder link, since this is saved for bookkeeping. + if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; + + return FALSE; + */ +} + +class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver +{ +public: + CallAfterCategoryFetchStage2(const uuid_vec_t& ids, + nullary_func_t callable) : + LLInventoryFetchItemsObserver(ids), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage2() + { + } + virtual void done() + { + llinfos << this << " done with incomplete " << mIncomplete.size() + << " complete " << mComplete.size() << " calling callable" << llendl; + + gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); + delete this; + } +protected: + nullary_func_t mCallable; +}; + +class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver +{ +public: + CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : + LLInventoryFetchDescendentsObserver(cat_id), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage1() + { + } + virtual void done() + { + // What we do here is get the complete information on the items in + // the library, and set up an observer that will wait for that to + // happen. + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(mComplete.front(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + S32 count = item_array.count(); + if(!count) + { + llwarns << "Nothing fetched in category " << mComplete.front() + << llendl; + //dec_busy_count(); + gInventory.removeObserver(this); + + // lets notify observers that loading is finished. + gAgentWearables.notifyLoadingFinished(); + delete this; + return; + } + + llinfos << "stage1 got " << item_array.count() << " items, passing to stage2 " << llendl; + uuid_vec_t ids; + for(S32 i = 0; i < count; ++i) + { + ids.push_back(item_array.get(i)->getUUID()); + } + + gInventory.removeObserver(this); + + // do the fetch + CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); + stage2->startFetch(); + if(stage2->isFinished()) + { + // everything is already here - call done. + stage2->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(stage2); + } + delete this; + } +protected: + nullary_func_t mCallable; +}; + +void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb) +{ + CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb); + stage1->startFetch(); + if (stage1->isFinished()) + { + stage1->done(); + } + else + { + gInventory.addObserver(stage1); + } +} + +void wear_multiple(const uuid_vec_t& ids, bool replace) +{ + LLPointer cb = new LLUpdateAppearanceOnDestroy; + + bool first = true; + uuid_vec_t::const_iterator it; + for (it = ids.begin(); it != ids.end(); ++it) + { + // if replace is requested, the first item worn will replace the current top + // item, and others will be added. + LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb); + first = false; + } +} + +// SLapp for easy-wearing of a stock (library) avatar +// +/* +class LLWearFolderHandler : public LLCommandHandler +{ +public: + // not allowed from outside the app + LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { } + + bool handle(const LLSD& tokens, const LLSD& query_map, + LLMediaCtrl* web) + { + LLPointer category = new LLInventoryCategory(query_map["folder_id"], + LLUUID::null, + LLFolderType::FT_CLOTHING, + "Quick Appearance"); + LLSD::UUID folder_uuid = query_map["folder_id"].asUUID(); + if ( gInventory.getCategory( folder_uuid ) != NULL ) + { + LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); + + // *TODOw: This may not be necessary if initial outfit is chosen already -- josh + gAgent.setGenderChosen(TRUE); + } + + // release avatar picker keyboard focus + gFocusMgr.setKeyboardFocus( NULL ); + + return true; + } +}; + +LLWearFolderHandler gWearFolderHandler;*/ diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h new file mode 100644 index 000000000..6b072075e --- /dev/null +++ b/indra/newview/llappearancemgr.h @@ -0,0 +1,265 @@ +/** + * @file llappearancemgr.h + * @brief Manager for initiating appearance changes on the viewer + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLAPPEARANCEMGR_H +#define LL_LLAPPEARANCEMGR_H + +#include "llsingleton.h" + +#include "llagentwearables.h" +#include "llcallbacklist.h" +#include "llinventorymodel.h" +#include "llinventoryobserver.h" +#include "llviewerinventory.h" + +class LLWearable; +class LLWearableHoldingPattern; +class LLInventoryCallback; +class LLOutfitUnLockTimer; + +class LLAppearanceMgr: public LLSingleton +{ + LOG_CLASS(LLAppearanceMgr); + + friend class LLSingleton; + friend class LLOutfitUnLockTimer; + +public: + typedef std::vector wearables_by_type_t; + + void updateAppearanceFromCOF(bool update_base_outfit_ordering = false); + bool needToSaveCOF(); + void updateCOF(const LLUUID& category, bool append = false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + void updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new, + LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new, + bool append = false, const LLUUID& idOutfit = LLUUID::null); +// [/RLVa:KB] + void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); + void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); + void wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append); + void wearOutfitByName(const std::string& name); + void changeOutfit(bool proceed, const LLUUID& category, bool append); + void replaceCurrentOutfit(const LLUUID& new_outfit); + void renameOutfit(const LLUUID& outfit_id); + void takeOffOutfit(const LLUUID& cat_id); + void addCategoryToCurrentOutfit(const LLUUID& cat_id); + S32 findExcessOrDuplicateItems(const LLUUID& cat_id, + LLAssetType::EType type, + S32 max_items, + LLInventoryModel::item_array_t& items_to_kill); + void enforceItemRestrictions(); + + // Copy all items and the src category itself. + void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, + LLPointer cb); + + // Return whether this folder contains minimal contents suitable for making a full outfit. + BOOL getCanMakeFolderIntoOutfit(const LLUUID& folder_id); + + // Determine whether a given outfit can be removed. + bool getCanRemoveOutfit(const LLUUID& outfit_cat_id); + + // Determine whether we're wearing any of the outfit contents (excluding body parts). + static bool getCanRemoveFromCOF(const LLUUID& outfit_cat_id); + + // Determine whether we can add anything (but body parts) from the outfit contents to COF. + static bool getCanAddToCOF(const LLUUID& outfit_cat_id); + + // Determine whether we can replace current outfit with the given one. + bool getCanReplaceCOF(const LLUUID& outfit_cat_id); + + // Copy all items in a category. + void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, + LLPointer cb); + + // Find the Current Outfit folder. + const LLUUID getCOF() const; + + // Finds the folder link to the currently worn outfit + const LLViewerInventoryItem *getBaseOutfitLink(); + bool getBaseOutfitName(std::string &name); + + // find the UUID of the currently worn outfit (Base Outfit) + const LLUUID getBaseOutfitUUID(); + + // Wear/attach an item (from a user's inventory) on the agent + bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false, LLPointer cb = NULL); + + // Update the displayed outfit name in UI. + void updatePanelOutfitName(const std::string& name); + + void createBaseOutfitLink(const LLUUID& category, LLPointer link_waiter); + + void updateAgentWearables(LLWearableHoldingPattern* holder, bool append); + + // For debugging - could be moved elsewhere. + void dumpCat(const LLUUID& cat_id, const std::string& msg); + void dumpItemArray(const LLInventoryModel::item_array_t& items, const std::string& msg); + + // Attachment link management + void unregisterAttachment(const LLUUID& item_id); + void registerAttachment(const LLUUID& item_id); + void setAttachmentInvLinkEnable(bool val); + + // utility function for bulk linking. + void linkAll(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLPointer cb); + + // Add COF link to individual item. + void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer cb = NULL); + void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer cb = NULL); + + // Remove COF entries + void removeCOFItemLinks(const LLUUID& item_id, bool do_update = true); + void removeCOFLinksOfType(LLWearableType::EType type, bool do_update = true); + + // Add COF link to ensemble folder. + void addEnsembleLink(LLInventoryCategory* item, bool do_update = true); + + //has the current outfit changed since it was loaded? + bool isOutfitDirty() { return mOutfitIsDirty; } + + // set false if you just loaded the outfit, true otherwise + void setOutfitDirty(bool isDirty) { mOutfitIsDirty = isDirty; } + + // manually compare ouftit folder link to COF to see if outfit has changed. + // should only be necessary to do on initial login. + void updateIsDirty(); + + // Called when self avatar is first fully visible. + void onFirstFullyVisible(); + + // Create initial outfits from library. + void autopopulateOutfits(); + + // Copy initial gestures from library. + void copyLibraryGestures(); + + void wearBaseOutfit(); + + // Overrides the base outfit with the content from COF + // @return false if there is no base outfit + bool updateBaseOutfit(); + + //Remove clothing or detach an object from the agent (a bodypart cannot be removed) + void removeItemFromAvatar(const LLUUID& item_id); + + + LLUUID makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true); + + bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body); + + static void sortItemsByActualDescription(LLInventoryModel::item_array_t& items); + + //Divvy items into arrays by wearable type + static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type); + + //Check ordering information on wearables stored in links' descriptions and update if it is invalid + // COF is processed if cat_id is not specified + void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false); + + bool isOutfitLocked() { return mOutfitLocked; } + + bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; } + +protected: + LLAppearanceMgr(); + ~LLAppearanceMgr(); + +private: + + void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type); + + void getDescendentsOfAssetType(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLAssetType::EType type, + bool follow_folder_links); + + void getUserDescendents(const LLUUID& category, + LLInventoryModel::item_array_t& wear_items, + LLInventoryModel::item_array_t& obj_items, + LLInventoryModel::item_array_t& gest_items, + bool follow_folder_links); + + void purgeCategory(const LLUUID& category, bool keep_outfit_links); + void purgeBaseOutfitLink(const LLUUID& category); + + static void onOutfitRename(const LLSD& notification, const LLSD& response); + + void setOutfitLocked(bool locked); + + bool mAttachmentInvLinkEnabled; + bool mOutfitIsDirty; + bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. + + /** + * Lock for blocking operations on outfit until server reply or timeout exceed + * to avoid unsynchronized outfit state or performing duplicate operations. + */ + bool mOutfitLocked; + + std::auto_ptr mUnlockOutfitTimer; + + ////////////////////////////////////////////////////////////////////////////////// + // Item-specific convenience functions +public: + // Is this in the COF? + BOOL getIsInCOF(const LLUUID& obj_id) const; + // Is this in the COF and can the user delete it from the COF? + BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const; + + /** + * Checks if COF contains link to specified object. + */ + static bool isLinkInCOF(const LLUUID& obj_id); +}; + +class LLUpdateAppearanceOnDestroy: public LLInventoryCallback +{ +public: + LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false); + virtual ~LLUpdateAppearanceOnDestroy(); + /* virtual */ void fire(const LLUUID& inv_item); + +private: + U32 mFireCount; + bool mUpdateBaseOrder; +}; + + +#define SUPPORT_ENSEMBLES 0 + +LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name); + +// Invoke a given callable after category contents are fully fetched. +void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb); + +// Wear all items in a uuid vector. +void wear_multiple(const uuid_vec_t& ids, bool replace); + +#endif diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 1b8da5748..0236b08b5 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -123,7 +123,7 @@ private: Impl* mImpl; }; -class LLBakedUploadData; +struct LLBakedUploadData; class LLSendTexLayerResponder : public LLAssetUploadResponder { LOG_CLASS(LLSendTexLayerResponder); diff --git a/indra/newview/llbuildnewviewsscheduler.cpp b/indra/newview/llbuildnewviewsscheduler.cpp index 964155b58..aee02f803 100644 --- a/indra/newview/llbuildnewviewsscheduler.cpp +++ b/indra/newview/llbuildnewviewsscheduler.cpp @@ -65,6 +65,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento objectp->getType(), LLInventoryType::IT_CATEGORY, panelp, + panelp->getRootFolder(), objectp->getUUID()); if (new_listener) @@ -86,6 +87,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento item->getActualType(), item->getInventoryType(), panelp, + panelp->getRootFolder(), item->getUUID(), item->getFlags()); if (new_listener) diff --git a/indra/newview/lldriverparam.cpp b/indra/newview/lldriverparam.cpp index eaca5d3a5..8332a6221 100644 --- a/indra/newview/lldriverparam.cpp +++ b/indra/newview/lldriverparam.cpp @@ -98,12 +98,69 @@ BOOL LLDriverParamInfo::parseXml(LLXmlTreeNode* node) return TRUE; } +//virtual +void LLDriverParamInfo::toStream(std::ostream &out) +{ + LLViewerVisualParamInfo::toStream(out); + out << "driver" << "\t"; + out << mDrivenInfoList.size() << "\t"; + for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++) + { + LLDrivenEntryInfo driven = *iter; + out << driven.mDrivenID << "\t"; + } + + out << std::endl; + + if(isAgentAvatarValid()) + { + for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++) + { + LLDrivenEntryInfo driven = *iter; + LLViewerVisualParam *param = (LLViewerVisualParam*)gAgentAvatarp->getVisualParam(driven.mDrivenID); + if (param) + { + param->getInfo()->toStream(out); + if (param->getWearableType() != mWearableType) + { + if(param->getCrossWearable()) + { + out << "cross-wearable" << "\t"; + } + else + { + out << "ERROR!" << "\t"; + } + } + else + { + out << "valid" << "\t"; + } + } + else + { + llwarns << "could not get parameter " << driven.mDrivenID << " from avatar " << gAgentAvatarp << " for driver parameter " << getID() << llendl; + } + out << std::endl; + } + } +} + //----------------------------------------------------------------------------- // LLDriverParam //----------------------------------------------------------------------------- -LLDriverParam::LLDriverParam(LLVOAvatar *avatarp) - : mCurrentDistortionParam( NULL ), mAvatarp(avatarp) +LLDriverParam::LLDriverParam(LLVOAvatar *avatarp) : + mCurrentDistortionParam( NULL ), + mAvatarp(avatarp), + mWearablep(NULL) +{ +} + +LLDriverParam::LLDriverParam(LLWearable *wearablep) : + mCurrentDistortionParam( NULL ), + mAvatarp(NULL), + mWearablep(wearablep) { } @@ -120,27 +177,48 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) mID = info->mID; setWeight(getDefaultWeight(), FALSE ); - - LLDriverParamInfo::entry_info_list_t::iterator iter; - mDriven.reserve(getInfo()->mDrivenInfoList.size()); - for (iter = getInfo()->mDrivenInfoList.begin(); iter != getInfo()->mDrivenInfoList.end(); iter++) + + return TRUE; +} + +void LLDriverParam::setWearable(LLWearable *wearablep) +{ + if (wearablep) { - LLDrivenEntryInfo *driven_info = &(*iter); - S32 driven_id = driven_info->mDrivenID; - LLViewerVisualParam* param = (LLViewerVisualParam*)mAvatarp->getVisualParam( driven_id ); - if (param) + mWearablep = wearablep; + mAvatarp = NULL; + } +} + +void LLDriverParam::setAvatar(LLVOAvatar *avatarp) +{ + if (avatarp) + { + mWearablep = NULL; + mAvatarp = avatarp; + } +} + +/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const +{ + LLDriverParam *new_param; + if (wearable) + { + new_param = new LLDriverParam(wearable); + } + else + { + if (mWearablep) { - mDriven.push_back(LLDrivenEntry( param, driven_info )); + new_param = new LLDriverParam(mWearablep); } else { - llerrs << " Unable to resolve driven parameter: " << driven_id << llendl; - mInfo = NULL; - return FALSE; + new_param = new LLDriverParam(mAvatarp); } } - - return TRUE; + *new_param = *this; + return new_param; } #if 0 // obsolete @@ -406,6 +484,82 @@ void LLDriverParam::stopAnimating(BOOL upload_bake) } } +/*virtual*/ +BOOL LLDriverParam::linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params) +{ + BOOL success = TRUE; + LLDriverParamInfo::entry_info_list_t::iterator iter; + for (iter = getInfo()->mDrivenInfoList.begin(); iter != getInfo()->mDrivenInfoList.end(); ++iter) + { + LLDrivenEntryInfo *driven_info = &(*iter); + S32 driven_id = driven_info->mDrivenID; + + // check for already existing links. Do not overwrite. + BOOL found = FALSE; + for (entry_list_t::iterator driven_iter = mDriven.begin(); driven_iter != mDriven.end() && !found; ++driven_iter) + { + if (driven_iter->mInfo->mDrivenID == driven_id) + { + found = TRUE; + } + } + + if (!found) + { + LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id); + bool push = param && (!only_cross_params || param->getCrossWearable()); + if (push) + { + mDriven.push_back(LLDrivenEntry( param, driven_info )); + } + else + { + success = FALSE; + } + } + } + + return success; +} + +void LLDriverParam::resetDrivenParams() +{ + mDriven.clear(); + mDriven.reserve(getInfo()->mDrivenInfoList.size()); +} + +void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type) +{ + bool needs_update = (getWearableType()==driven_type); + + // if the driver has a driven entry for the passed-in wearable type, we need to refresh the value + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + if (driven && driven->mParam && driven->mParam->getCrossWearable() && driven->mParam->getWearableType() == driven_type) + { + needs_update = true; + } + } + + + if (needs_update) + { + LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType(); + + // If we've gotten here, we've added a new wearable of type "type" + // Thus this wearable needs to get updates from the driver wearable. + // The call to setVisualParamWeight seems redundant, but is necessary + // as the number of driven wearables has changed since the last update. -Nyx + LLWearable *wearable = gAgentWearables.getTopWearable(driver_type); + if (wearable) + { + wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false); + } + } +} + + //----------------------------------------------------------------------------- // getDrivenWeight() //----------------------------------------------------------------------------- @@ -465,7 +619,7 @@ F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake) { - /*if(isAgentAvatarValid() && + if(isAgentAvatarValid() && mWearablep && driven->mParam->getCrossWearable() && mWearablep->isOnTop()) @@ -473,7 +627,7 @@ void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bo // call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values gAgentAvatarp->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake ); } - else*/ + else { driven->mParam->setWeight( driven_weight, upload_bake ); } diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h index ba627925e..fb1b44458 100644 --- a/indra/newview/lldriverparam.h +++ b/indra/newview/lldriverparam.h @@ -66,6 +66,8 @@ public: /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + /*virtual*/ void toStream(std::ostream &out); + protected: typedef std::deque entry_info_list_t; entry_info_list_t mDrivenInfoList; @@ -78,6 +80,7 @@ class LLDriverParam : public LLViewerVisualParam friend class LLPhysicsMotion; // physics motion needs to access driven params directly. public: LLDriverParam(LLVOAvatar *avatarp); + LLDriverParam(LLWearable *wearablep); ~LLDriverParam(); // Special: These functions are overridden by child classes @@ -85,12 +88,20 @@ public: // This sets mInfo and calls initialization functions BOOL setInfo(LLDriverParamInfo *info); + void setWearable(LLWearable *wearablep); + void setAvatar(LLVOAvatar *avatarp); + void updateCrossDrivenParams(LLWearableType::EType driven_type); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param. /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); /*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake ); /*virtual*/ void stopAnimating(BOOL upload_bake); + /*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); + /*virtual*/ void resetDrivenParams(); // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion(); @@ -111,6 +122,7 @@ protected: LLViewerVisualParam* mCurrentDistortionParam; // Backlink only; don't make this an LLPointer. LLVOAvatar* mAvatarp; + LLWearable* mWearablep; }; #endif // LL_LLDRIVERPARAM_H diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index c3ac0cfa8..02db1cc7b 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -140,7 +140,7 @@ BOOL LLFloaterAvatarPicker::postBuild() inventory_panel->setFollowsAll(); inventory_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); inventory_panel->openDefaultFolderForType(LLAssetType::AT_CALLINGCARD); - inventory_panel->setSelectCallback(LLFloaterAvatarPicker::onCallingCardSelectionChange, this); + inventory_panel->setSelectCallback(boost::bind(&LLFloaterAvatarPicker::onCallingCardSelectionChange, _1, _2, (void*)this)); childSetTabChangeCallback("ResidentChooserTabs", "SearchPanel", onTabChanged, this); childSetTabChangeCallback("ResidentChooserTabs", "CallingCardsPanel", onTabChanged, this); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index afbefb3e5..35c2a902e 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -765,8 +765,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*) ctrl; - LLVOAvatar *avatar = gAgentAvatarp; - if (!avatar) + if (!gAgentAvatarp) { return; } @@ -777,13 +776,13 @@ void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) if (new_invis_state) { LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); - const LLTextureEntry* current_te = avatar->getTE(te); + const LLTextureEntry* current_te = gAgentAvatarp->getTE(te); if (current_te) { self->mPreviousTextureList[(S32)te] = current_te->getID(); } - avatar->setLocTexTE(te, image, TRUE); - avatar->wearableUpdated(self->mType, FALSE); + gAgentAvatarp->setLocalTextureTE(te,image, 0); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); } else { @@ -796,8 +795,8 @@ void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) if (prev_id.notNull()) { LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); - avatar->setLocTexTE(te, image, TRUE); - avatar->wearableUpdated(self->mType, FALSE); + gAgentAvatarp->setLocalTextureTE(te, image, 0); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); } } @@ -894,8 +893,7 @@ void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; LLTextureCtrl* texture_ctrl = (LLTextureCtrl*) ctrl; - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar ) + if( gAgentAvatarp ) { ETextureIndex te = (ETextureIndex)(self->mTextureList[ctrl->getName()]); @@ -908,8 +906,8 @@ void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) self->mTextureList[ctrl->getName()] = te; if (gAgentWearables.getWearable(self->mType, 0)) // TODO: MULTI-WEARABLE { - avatar->setLocTexTE(te, image, TRUE); - avatar->wearableUpdated(self->mType, FALSE); + gAgentAvatarp->setLocalTextureTE(te, image, 0); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); } if (self->mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) { @@ -2039,7 +2037,8 @@ void LLFloaterCustomize::onMakeOutfitCommit( LLMakeOutfitDialog* dialog, void* u dialog->getIncludedItems( wearables_to_include, attachments_to_include ); - gAgentWearables.makeNewOutfit( dialog->getFolderName(), wearables_to_include, attachments_to_include, dialog->getRenameClothing() ); + // MULTI-WEARABLES TODO + //LLAppearanceMgr::getInstance()->makeNewOutfit( dialog->getFolderName(), wearables_to_include, attachments_to_include, dialog->getRenameClothing() ); } } diff --git a/indra/newview/llfloaterlandmark.cpp b/indra/newview/llfloaterlandmark.cpp index 42bbbe0d7..5b25a7138 100644 --- a/indra/newview/llfloaterlandmark.cpp +++ b/indra/newview/llfloaterlandmark.cpp @@ -93,7 +93,7 @@ LLFloaterLandmark::LLFloaterLandmark(const LLSD& data) mInventoryPanel->setFilterTypes(filter_types); //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss. - mInventoryPanel->setSelectCallback(onSelectionChange, this); + mInventoryPanel->setSelectCallback(boost::bind(onSelectionChange, _1, _2, (void*)this)); mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); mInventoryPanel->setAllowMultiSelect(FALSE); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index bfe40f33c..5921a4cfb 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -196,12 +196,12 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) // Default constructor LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, - const LLRect& rect, const LLUUID& source_id, LLView *parent_view ) : + const LLRect& rect, const LLUUID& source_id, LLView *parent_view, LLFolderViewEventListener* listener ) : #if LL_WINDOWS #pragma warning( push ) #pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list #endif - LLFolderViewFolder( name, root_folder_icon, this, NULL ), + LLFolderViewFolder( name, root_folder_icon, this, listener ), #if LL_WINDOWS #pragma warning( pop ) #endif @@ -223,8 +223,6 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic mShowSelectionContext(FALSE), mShowSingleSelection(FALSE), mArrangeGeneration(0), - mUserData(NULL), - mSelectCallback(NULL), mSignalSelectCallback(0), mMinWidth(0), mDragAndDropThisFrame(FALSE) @@ -274,6 +272,8 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic // Destroys the object LLFolderView::~LLFolderView( void ) { + closeRenamer(); + // The release focus call can potentially call the // scrollcontainer, which can potentially be called with a partly // destroyed scollcontainer. Just null it out here, and no worries @@ -292,7 +292,7 @@ LLFolderView::~LLFolderView( void ) mAutoOpenItems.removeAllNodes(); gIdleCallbacks.deleteFunction(idle, this); - LLView::deleteViewByHandle(mPopupMenuHandle); + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); if(mRenamer == gFocusMgr.getTopCtrl()) { @@ -434,6 +434,7 @@ void LLFolderView::closeAllFolders() { // Close all the folders setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + arrangeAll(); } void LLFolderView::openFolder(const std::string& foldername) @@ -541,6 +542,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen reshape( llmax(min_width, total_width), running_height ); } + // move item renamer text field to item's new position + updateRenamerPosition(); + mTargetHeight = (F32)target_height; return llround(mTargetHeight); } @@ -580,6 +584,8 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent) } width = llmax(mMinWidth, min_width); LLView::reshape(width, height, called_from_parent); + + mReshapeSignal(mSelectedItems, FALSE); } void LLFolderView::addToSelectionList(LLFolderViewItem* item) @@ -835,8 +841,7 @@ void LLFolderView::sanitizeSelection() } else { - // nothing selected to start with, so pick "My Inventory" as best guess - new_selection = getItemByID(gInventory.getRootFolderID()); + new_selection = NULL; } if (new_selection) @@ -952,6 +957,7 @@ void LLFolderView::draw() } else { + static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) { mStatusText = std::string("Searching..."); // *TODO:translate @@ -980,17 +986,7 @@ void LLFolderView::finishRenamingItem( void ) mRenameItem->rename( mRenamer->getText() ); } - mRenamer->setCommitOnFocusLost( FALSE ); - mRenamer->setFocus( FALSE ); - mRenamer->setVisible( FALSE ); - mRenamer->setCommitOnFocusLost( TRUE ); - gFocusMgr.setTopCtrl( NULL ); - - if( mRenameItem ) - { - setSelectionFromRoot( mRenameItem, TRUE ); - mRenameItem = NULL; - } + closeRenamer(); // List is re-sorted alphabeticly, so scroll to make sure the selected item is visible. scrollToShowSelection(); @@ -998,15 +994,10 @@ void LLFolderView::finishRenamingItem( void ) void LLFolderView::closeRenamer( void ) { - // will commit current name (which could be same as original name) - mRenamer->setFocus( FALSE ); - mRenamer->setVisible( FALSE ); - gFocusMgr.setTopCtrl( NULL ); - - if( mRenameItem ) + if (mRenamer && mRenamer->getVisible()) { - setSelectionFromRoot( mRenameItem, TRUE ); - mRenameItem = NULL; + // Triggers onRenamerLost() that actually closes the renamer. + gFocusMgr.setTopCtrl( NULL ); } } @@ -1081,7 +1072,7 @@ void LLFolderView::removeSelectedItems( void ) if (!new_selection) { new_selection = last_item->getPreviousOpenNode(FALSE); - while (new_selection && new_selection->isSelected()) + while (new_selection && (new_selection->isSelected()/* || isDescendantOfASelectedItem(new_selection, items)*/)) { new_selection = new_selection->getPreviousOpenNode(FALSE); } @@ -1186,9 +1177,20 @@ void LLFolderView::propertiesSelectedItems( void ) } } +void LLFolderView::changeType(LLInventoryModel *model, LLFolderType::EType new_folder_type) +{ + LLFolderBridge *folder_bridge = LLFolderBridge::sSelf.get(); + + if (!folder_bridge) return; + LLViewerInventoryCategory *cat = folder_bridge->getCategory(); + if (!cat) return; + cat->changeType(new_folder_type); +} void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) { - if (mAutoOpenItems.check() == item || mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) + if ((mAutoOpenItems.check() == item) || + (mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) || + item->isOpen()) { return; } @@ -1298,12 +1300,43 @@ void LLFolderView::copy() BOOL LLFolderView::canCut() const { - return FALSE; + if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0))) + { + return FALSE; + } + + for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) + { + const LLFolderViewItem* item = *selected_it; + const LLFolderViewEventListener* listener = item->getListener(); + + if (!listener || !listener->isItemRemovable()) + { + return FALSE; + } + } + return TRUE; } void LLFolderView::cut() { - // implement Windows-style cut-and-leave + // clear the inventory clipboard + LLInventoryClipboard::instance().reset(); + S32 count = mSelectedItems.size(); + if(getVisible() && getEnabled() && (count > 0)) + { + LLFolderViewEventListener* listener = NULL; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + listener = (*item_it)->getListener(); + if(listener) + { + listener->cutToClipboard(); + } + } + } + mSearchString.clear(); } BOOL LLFolderView::canPaste() const @@ -1386,23 +1419,8 @@ void LLFolderView::startRenamingSelectedItem( void ) { mRenameItem = item; - S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD - 1 + item->getIndentation(); - S32 y = llfloor(item->getRect().getHeight()-sFont->getLineHeight()-2); - item->localPointToScreen( x, y, &x, &y ); - screenPointToLocal( x, y, &x, &y ); - mRenamer->setOrigin( x, y ); + updateRenamerPosition(); - S32 scroller_height = 0; - S32 scroller_width = gViewerWindow->getWindowWidth(); - BOOL dummy_bool; - if (mScrollContainer) - { - mScrollContainer->calcVisibleSize( &scroller_width, &scroller_height, &dummy_bool, &dummy_bool); - } - - S32 width = llmax(llmin(item->getRect().getWidth() - x, scroller_width - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); - S32 height = llfloor(sFont->getLineHeight() + RENAME_HEIGHT_PAD); - mRenamer->reshape( width, height, TRUE ); mRenamer->setText(item->getName()); mRenamer->selectAll(); @@ -2091,11 +2109,11 @@ void LLFolderView::doIdle() } } - if (mSignalSelectCallback && mSelectCallback) + if (mSignalSelectCallback) { //RN: we use keyboard focus as a proxy for user-explicit actions BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS); - mSelectCallback(mSelectedItems, take_keyboard_focus, mUserData); + mSelectSignal(mSelectedItems, take_keyboard_focus); } mSignalSelectCallback = FALSE; } @@ -2111,7 +2129,6 @@ void LLFolderView::idle(void* user_data) } } - void LLFolderView::dumpSelectionInformation() { llinfos << "LLFolderView::dumpSelectionInformation()" << llendl; @@ -2124,6 +2141,29 @@ void LLFolderView::dumpSelectionInformation() llinfos << "****************************************" << llendl; } +void LLFolderView::updateRenamerPosition() +{ + if(mRenameItem) + { + // See also LLFolderViewItem::draw() + S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mRenameItem->getIndentation(); + S32 y = mRenameItem->getRect().getHeight() - mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; + mRenameItem->localPointToScreen( x, y, &x, &y ); + screenPointToLocal( x, y, &x, &y ); + mRenamer->setOrigin( x, y ); + + LLRect scroller_rect(0, 0, gViewerWindow->getWindowWidthScaled(), 0); + if (mScrollContainer) + { + BOOL dummy_bool; + mScrollContainer->calcVisibleSize( &scroller_rect.mRight, &scroller_rect.mTop, &dummy_bool, &dummy_bool); + } + + S32 width = llmax(llmin(mRenameItem->getRect().getWidth() - x, scroller_rect.getWidth() - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); + S32 height = mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; + mRenamer->reshape( width, height, TRUE ); + } +} ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 98e40455d..918c64099 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -74,15 +74,14 @@ class LLTextBox; class LLUICtrl; class LLLineEditor; -class LLFolderView : public LLFolderViewFolder, LLEditMenuHandler +class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler { public: typedef void (*SelectCallback)(const std::deque &items, BOOL user_action, void* data); - static F32 sAutoOpenTime; LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, const LLRect& rect, - const LLUUID& source_id, LLView *parent_view ); + const LLUUID& source_id, LLView *parent_view, LLFolderViewEventListener* listener ); virtual ~LLFolderView( void ); virtual BOOL canFocusChildren() const; @@ -94,7 +93,10 @@ public: void setSortOrder(U32 order); void checkTreeResortForModelChanged(); void setFilterPermMask(PermissionMask filter_perm_mask); - void setSelectCallback(SelectCallback callback, void* user_data) { mSelectCallback = callback, mUserData = user_data; } + + typedef boost::signals2::signal& items, BOOL user_action)> signal_t; + void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); } + void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); } void setAllowMultiSelect(BOOL allow) { mAllowMultiSelect = allow; } LLInventoryFilter* getFilter(); @@ -106,6 +108,7 @@ public: //LLInventoryFilter::EFolderShow getShowFolderState(); U32 getSortOrder() const; BOOL isFilterModified(); + BOOL getAllowMultiSelect() { return mAllowMultiSelect; } U32 toggleSearchType(std::string toggle); @@ -152,6 +155,8 @@ public: BOOL startDrag(LLToolDragAndDrop::ESource source); void setDragAndDropThisFrame() { mDragAndDropThisFrame = TRUE; } + void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; } + LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; } // deletion functionality void removeSelectedItems(); @@ -160,6 +165,9 @@ public: void openSelectedItems( void ); void propertiesSelectedItems( void ); + // change the folder type + void changeType(LLInventoryModel *model, LLFolderType::EType new_folder_type); + void autoOpenItem(LLFolderViewFolder* item); void closeAutoOpenedFolders(); BOOL autoOpenTest(LLFolderViewFolder* item); @@ -238,6 +246,7 @@ public: // DEBUG only void dumpSelectionInformation(); + void updateRenamerPosition(); protected: LLScrollableContainerView* mScrollContainer; // NULL if this is not a child of a scroll container. @@ -282,13 +291,20 @@ protected: LLFrameTimer mMultiSelectionFadeTimer; S32 mArrangeGeneration; - void* mUserData; - SelectCallback mSelectCallback; + signal_t mSelectSignal; + signal_t mReshapeSignal; S32 mSignalSelectCallback; S32 mMinWidth; std::map mItemMap; BOOL mDragAndDropThisFrame; + /** + * Contains item under mouse pointer while dragging + */ + LLFolderViewItem* mDraggingOverItem; // See EXT-719 + +public: + static F32 sAutoOpenTime; }; bool sort_item_name(LLFolderViewItem* a, LLFolderViewItem* b); diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index deefa298b..7640d5878 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -55,23 +55,26 @@ public: virtual const LLUUID& getUUID() const = 0; virtual time_t getCreationDate() const = 0; // UTC seconds virtual PermissionMask getPermissionMask() const = 0; + virtual LLFolderType::EType getPreferredType() const = 0; virtual LLPointer getIcon() const = 0; virtual LLFontGL::StyleFlags getLabelStyle() const = 0; virtual std::string getLabelSuffix() const = 0; virtual void openItem( void ) = 0; + virtual void closeItem( void ) = 0; virtual void previewItem( void ) = 0; virtual void selectItem(void) = 0; virtual void showProperties(void) = 0; virtual BOOL isItemRenameable() const = 0; virtual BOOL renameItem(const std::string& new_name) = 0; - virtual BOOL isItemMovable( void ) = 0; // Can be moved to another folder - virtual BOOL isItemRemovable( void ) = 0; // Can be destroyed + virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder + virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed + virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual. virtual BOOL removeItem() = 0; virtual void removeBatch(LLDynamicArray& batch) = 0; virtual void move( LLFolderViewEventListener* parent_listener ) = 0; virtual BOOL isItemCopyable() const = 0; virtual BOOL copyToClipboard() const = 0; - virtual BOOL cutToClipboard() const = 0; + virtual void cutToClipboard() = 0; virtual BOOL isClipboardPasteable() const = 0; virtual void pasteFromClipboard() = 0; virtual void pasteLinkFromClipboard() = 0; @@ -79,7 +82,8 @@ public: virtual BOOL isUpToDate() const = 0; virtual BOOL hasChildren() const = 0; virtual LLInventoryType::EType getInventoryType() const = 0; - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) {} + virtual void performAction(LLInventoryModel* model, std::string action) = 0; + virtual LLWearableType::EType getWearableType() const = 0; // This method should be called when a drag begins. returns TRUE // if the drag can begin, otherwise FALSE. diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 3f5deb093..4a06d89c9 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -50,13 +50,6 @@ const LLFontGL* LLFolderViewItem::sSmallFont = NULL; const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f; const F32 LLFolderViewItem::FOLDER_OPEN_TIME_CONSTANT = 0.03f; -LLColor4 LLFolderViewItem::sFgColor; -LLColor4 LLFolderViewItem::sHighlightBgColor; -LLColor4 LLFolderViewItem::sHighlightFgColor; -LLColor4 LLFolderViewItem::sFilterBGColor; -LLColor4 LLFolderViewItem::sFilterTextColor; -LLColor4 LLFolderViewItem::sSuffixColor; -LLColor4 LLFolderViewItem::sSearchStatusColor; LLUIImagePtr LLFolderViewItem::sArrowImage; LLUIImagePtr LLFolderViewItem::sBoxImage; @@ -69,13 +62,6 @@ void LLFolderViewItem::initClass() { sFont = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); sSmallFont = LLResMgr::getInstance()->getRes( LLFONT_SMALL ); - sFgColor = gColors.getColor( "MenuItemEnabledColor" ); - sHighlightBgColor = gColors.getColor( "MenuItemHighlightBgColor" ); - sHighlightFgColor = gColors.getColor( "MenuItemHighlightFgColor" ); - sFilterBGColor = gColors.getColor( "FilterBackgroundColor" ); - sFilterTextColor = gColors.getColor( "FilterTextColor" ); - sSuffixColor = gColors.getColor( "InventoryItemSuffixColor" ); - sSearchStatusColor = gColors.getColor( "InventorySearchStatusColor" ); sArrowImage = LLUI::getUIImage("folder_arrow.tga"); sBoxImage = LLUI::getUIImage("rounded_square.tga"); } @@ -117,9 +103,15 @@ LLFolderViewItem::LLFolderViewItem( const std::string& name, LLUIImagePtr icon, mListener(listener) { sFolderViewItems.insert(this); - refresh(); // possible opt: only call refreshFromListener() - setTabStop(FALSE); } + +BOOL LLFolderViewItem::postBuild() +{ + refresh(); + setTabStop(FALSE); + return TRUE; +} + // Destroys the object LLFolderViewItem::~LLFolderViewItem( void ) { @@ -225,8 +217,6 @@ void LLFolderViewItem::setIcon(LLUIImagePtr icon) mIcon = icon; } - - // refresh information from the listener void LLFolderViewItem::refreshFromListener() { @@ -378,7 +368,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height, S32 filter_generation) S32 LLFolderViewItem::getItemHeight() { - S32 icon_height = mIcon->getHeight(); + S32 icon_height = mIcon.notNull() ? mIcon->getHeight() : 0; S32 label_height = llround(sFont->getLineHeight()); return llmax( icon_height, label_height ) + ICON_PAD; } @@ -807,7 +797,10 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, } if(mParentFolder && !handled) { + // store this item to get it in LLFolderBridge::dragItemIntoFolder on drop event. + mRoot->setDraggingOverItem(this); handled = mParentFolder->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + mRoot->setDraggingOverItem(NULL); } if (handled) { @@ -820,35 +813,46 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, void LLFolderViewItem::draw() { - bool possibly_has_children = false; - bool up_to_date = mListener && mListener->isUpToDate(); - if((up_to_date && hasVisibleChildren() ) || // we fetched our children and some of them have passed the filter... - (!up_to_date && mListener && mListener->hasChildren())) // ...or we know we have children but haven't fetched them (doesn't obey filter) + static LLCachedControl sFgColor(gColors, "MenuItemEnabledColor", LLColor4::white ); + static LLCachedControl sHighlightBgColor(gColors, "MenuItemHighlightBgColor", LLColor4::white ); + static LLCachedControl sHighlightFgColor(gColors, "MenuItemHighlightFgColor", LLColor4::white ); + static LLCachedControl sFilterBGColor(gColors, "FilterBackgroundColor", LLColor4::white ); + static LLCachedControl sFilterTextColor(gColors, "FilterTextColor", LLColor4::white ); + static LLCachedControl sSuffixColor(gColors, "InventoryItemSuffixColor", LLColor4::white ); + static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); + + const S32 TOP_PAD = 0; + const S32 FOCUS_LEFT = 0; + const LLFontGL* font = sFont; + + const BOOL in_inventory = getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(), gInventory.getRootFolderID()); + const BOOL in_library = getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(), gInventory.getLibraryRootFolderID()); + + //--------------------------------------------------------------------------------// + // Draw open folder arrow + // + const bool up_to_date = mListener && mListener->isUpToDate(); + const bool possibly_has_children = ((up_to_date && hasVisibleChildren()) // we fetched our children and some of them have passed the filter... + || (!up_to_date && mListener && mListener->hasChildren())); // ...or we know we have children but haven't fetched them (doesn't obey filter) + if (possibly_has_children && sArrowImage) { - possibly_has_children = true; - } - if(/*mControlLabel[0] != '\0' && */possibly_has_children) - { - if (sArrowImage) - { - gl_draw_scaled_rotated_image(mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD, - ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, sArrowImage->getImage(), sFgColor); - } + gl_draw_scaled_rotated_image( + mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD - TOP_PAD, + ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, sArrowImage->getImage(), sFgColor); } - F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); - - // If we have keyboard focus, draw selection filled - BOOL show_context = getRoot()->getShowSelectionContext(); - BOOL filled = show_context || (gFocusMgr.getKeyboardFocus() == getRoot()); - - // always render "current" item, only render other selected items if - // mShowSingleSelection is FALSE - if( mIsSelected ) + //--------------------------------------------------------------------------------// + // Draw highlight for selected items + // + const BOOL show_context = getRoot()->getShowSelectionContext(); + const BOOL filled = show_context || (getRoot()->getParent()->hasFocus()); // If we have keyboard focus, draw selection filled + const S32 focus_top = getRect().getHeight(); + const S32 focus_bottom = getRect().getHeight() - getItemHeight(); + const bool folder_open = (getRect().getHeight() > getItemHeight() + 4); + if (mIsSelected) // always render "current" item. Only render other selected items if mShowSingleSelection is FALSE { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLColor4 bg_color = sHighlightBgColor; - //const S32 TRAILING_PAD = 5; // It just looks better with this. if (!mIsCurSelection) { // do time-based fade of extra objects @@ -864,37 +868,32 @@ void LLFolderViewItem::draw() bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]); } } - - gl_rect_2d( - 0, - getRect().getHeight(), - getRect().getWidth() - 2, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), - bg_color, filled); + gl_rect_2d(FOCUS_LEFT, + focus_top, + getRect().getWidth() - 2, + focus_bottom, + bg_color, filled); if (mIsCurSelection) { - gl_rect_2d( - 0, - getRect().getHeight(), - getRect().getWidth() - 2, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), + gl_rect_2d(FOCUS_LEFT, + focus_top, + getRect().getWidth() - 2, + focus_bottom, sHighlightFgColor, FALSE); } - if (getRect().getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) + if (folder_open) { - gl_rect_2d( - 0, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, - getRect().getWidth() - 2, - 2, + gl_rect_2d(FOCUS_LEFT, + focus_bottom + 1, // overlap with bottom edge of above rect + getRect().getWidth() - 2, + 0, sHighlightFgColor, FALSE); if (show_context) { - gl_rect_2d( - 0, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, - getRect().getWidth() - 2, - 2, + gl_rect_2d(FOCUS_LEFT, + focus_bottom + 1, + getRect().getWidth() - 2, + 0, sHighlightBgColor, TRUE); } } @@ -902,46 +901,49 @@ void LLFolderViewItem::draw() if (mDragAndDropTarget) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d( - 0, - getRect().getHeight(), - getRect().getWidth() - 2, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), - sHighlightBgColor, FALSE); - - if (getRect().getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) + gl_rect_2d(FOCUS_LEFT, + focus_top, + getRect().getWidth() - 2, + focus_bottom, + sHighlightBgColor, FALSE); + if (folder_open) { - gl_rect_2d( - 0, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, - getRect().getWidth() - 2, - 2, - sHighlightBgColor, FALSE); + gl_rect_2d(FOCUS_LEFT, + focus_bottom + 1, // overlap with bottom edge of above rect + getRect().getWidth() - 2, + 0, + sHighlightBgColor, FALSE); } mDragAndDropTarget = FALSE; } - - if(mIcon) + const S32 icon_x = mIndentation + ARROW_SIZE + TEXT_PAD; + if (mIcon) { - mIcon->draw(mIndentation + ARROW_SIZE + TEXT_PAD, getRect().getHeight() - mIcon->getHeight()); + mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + } + + //--------------------------------------------------------------------------------// + // Exit if no label to draw + // + if (mLabel.empty()) + { + return; } + LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor; + F32 right_x = 0; + F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; + F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); - if (!mLabel.empty()) + //--------------------------------------------------------------------------------// + // Highlight filtered text + // + if (getRoot()->getDebugFilters()) { - // highlight filtered text - BOOL debug_filters = getRoot()->getDebugFilters(); - LLColor4 color = ( (mIsSelected && filled) ? sHighlightFgColor : sFgColor ); - F32 right_x; - F32 y = (F32)getRect().getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; - - if (debug_filters) - { if (!getFiltered() && !possibly_has_children) { color.mV[VALPHA] *= 0.5f; } - LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? LLColor4(0.5f, 0.8f, 0.5f, 1.f) : LLColor4(0.8f, 0.5f, 0.5f, 1.f); @@ -950,49 +952,70 @@ void LLFolderViewItem::draw() S32_MAX, S32_MAX, &right_x, FALSE ); text_left = right_x; } + //--------------------------------------------------------------------------------// + // Draw the actual label text + // + font->renderUTF8(mLabel, 0, text_left, y, color, + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, + S32_MAX, getRect().getWidth() - (S32) text_left, &right_x, TRUE); + //--------------------------------------------------------------------------------// + // Draw "Loading..." text + // + bool root_is_loading = false; + if (in_inventory) + { + root_is_loading = LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress(); + } + if (in_library) + { + root_is_loading = LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress(); + } + if ((mIsLoading + && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime")) + || (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() + && root_is_loading)) + { + std::string load_string = " ( Loading... ) "; + font->renderUTF8(load_string, 0, right_x, y, sSearchStatusColor, + LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + S32_MAX, S32_MAX, &right_x, FALSE); + } - if ( mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime") ) - { - // *TODO: Translate - sFont->renderUTF8( std::string("Loading... "), 0, text_left, y, sSearchStatusColor, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE); - text_left = right_x; - } + //--------------------------------------------------------------------------------// + // Draw label suffix + // + if (!mLabelSuffix.empty()) + { + font->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor, + LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + S32_MAX, S32_MAX, &right_x, FALSE ); + } - sFont->renderUTF8( mLabel, 0, text_left, y, color, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, &right_x, FALSE ); - if (!mLabelSuffix.empty()) - { - sFont->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, &right_x, FALSE ); - } - - if (sBoxImage.notNull() && mStringMatchOffset != std::string::npos) - { - // don't draw backgrounds for zero-length strings - std::string combined_string = mLabel + mLabelSuffix; - S32 filter_string_length = getRoot()->getFilterSubString().size(); - std::string combined_string_upper = combined_string; - LLStringUtil::toUpper(combined_string_upper); - if (filter_string_length > 0 && (mRoot->getSearchType() & 1) && + if (sBoxImage.notNull() && mStringMatchOffset != std::string::npos) + { + // don't draw backgrounds for zero-length strings + std::string combined_string = mLabel + mLabelSuffix; + S32 filter_string_length = getRoot()->getFilterSubString().size(); + std::string combined_string_upper = combined_string; + LLStringUtil::toUpper(combined_string_upper); + if (filter_string_length > 0 && (mRoot->getSearchType() & 1) && combined_string_upper.find(mRoot->getFilterSubString()) == mStringMatchOffset) - { - S32 left = llround(text_left) + sFont->getWidth(combined_string, 0, mStringMatchOffset) - 1; - S32 right = left + sFont->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; - S32 bottom = llfloor(getRect().getHeight() - sFont->getLineHeight() - 3); - S32 top = getRect().getHeight(); + { + S32 left = llround(text_left) + font->getWidth(combined_string, 0, mStringMatchOffset) - 1; + S32 right = left + font->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; + S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD); + S32 top = getRect().getHeight() - TOP_PAD; - LLRect box_rect(left, top, right, bottom); - sBoxImage->draw(box_rect, sFilterBGColor); - F32 match_string_left = text_left + sFont->getWidthF32(combined_string, 0, mStringMatchOffset); - F32 y = (F32)getRect().getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; - sFont->renderUTF8( combined_string, mStringMatchOffset, match_string_left, y, - sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, - filter_string_length, S32_MAX, &right_x, FALSE ); - } + LLUIImage* box_image = sBoxImage; + LLRect box_rect(left, top, right, bottom); + box_image->draw(box_rect, sFilterBGColor); + F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, mStringMatchOffset); + F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; + font->renderUTF8( combined_string, mStringMatchOffset, match_string_left, yy, + + sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + filter_string_length, S32_MAX, &right_x, FALSE ); } } @@ -1025,7 +1048,6 @@ LLFolderViewFolder::LLFolderViewFolder( const std::string& name, LLUIImagePtr ic mCompletedFilterGeneration(-1), mMostFilteredDescendantGeneration(-1) { - mType = std::string("(folder)"); } @@ -1505,6 +1527,183 @@ BOOL LLFolderViewFolder::changeSelection(LLFolderViewItem* selection, BOOL selec return rv; } + +LLFolderViewFolder* LLFolderViewFolder::getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse) +{ + if (!item_a->getParentFolder() || !item_b->getParentFolder()) return NULL; + + std::deque item_a_ancestors; + + LLFolderViewFolder* parent = item_a->getParentFolder(); + while(parent) + { + item_a_ancestors.push_back(parent); + parent = parent->getParentFolder(); + } + + std::deque item_b_ancestors; + + parent = item_b->getParentFolder(); + while(parent) + { + item_b_ancestors.push_back(parent); + parent = parent->getParentFolder(); + } + + LLFolderViewFolder* common_ancestor = item_a->getRoot(); + + while(item_a_ancestors.size() > item_b_ancestors.size()) + { + item_a = item_a_ancestors.front(); + item_a_ancestors.pop_front(); + } + + while(item_b_ancestors.size() > item_a_ancestors.size()) + { + item_b = item_b_ancestors.front(); + item_b_ancestors.pop_front(); + } + + while(item_a_ancestors.size()) + { + common_ancestor = item_a_ancestors.front(); + + if (item_a_ancestors.front() == item_b_ancestors.front()) + { + // which came first, sibling a or sibling b? + for (folders_t::iterator it = common_ancestor->mFolders.begin(), end_it = common_ancestor->mFolders.end(); + it != end_it; + ++it) + { + LLFolderViewItem* item = *it; + + if (item == item_a) + { + reverse = false; + return common_ancestor; + } + if (item == item_b) + { + reverse = true; + return common_ancestor; + } + } + + for (items_t::iterator it = common_ancestor->mItems.begin(), end_it = common_ancestor->mItems.end(); + it != end_it; + ++it) + { + LLFolderViewItem* item = *it; + + if (item == item_a) + { + reverse = false; + return common_ancestor; + } + if (item == item_b) + { + reverse = true; + return common_ancestor; + } + } + break; + } + + item_a = item_a_ancestors.front(); + item_a_ancestors.pop_front(); + item_b = item_b_ancestors.front(); + item_b_ancestors.pop_front(); + } + + return NULL; +} + +void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector& items) +{ + bool selecting = start == NULL; + if (reverse) + { + for (items_t::reverse_iterator it = mItems.rbegin(), end_it = mItems.rend(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + if (selecting) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + for (folders_t::reverse_iterator it = mFolders.rbegin(), end_it = mFolders.rend(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + + if (selecting) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + } + else + { + for (folders_t::iterator it = mFolders.begin(), end_it = mFolders.end(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + + if (selecting) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + for (items_t::iterator it = mItems.begin(), end_it = mItems.end(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + + if (selecting) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + } +} + void LLFolderViewFolder::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& selected_items) { // pass on to child folders first @@ -2050,6 +2249,22 @@ void LLFolderViewFolder::openItem( void ) toggleOpen(); } +void LLFolderViewFolder::applyFunctorToChildren(LLFolderViewFunctor& functor) +{ + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + functor.doItem((*fit)); + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + functor.doItem((*iit)); + } +} + void LLFolderViewFolder::applyFunctorRecursively(LLFolderViewFunctor& functor) { functor.doFolder(this); @@ -2157,12 +2372,6 @@ BOOL LLFolderViewFolder::handleHover(S32 x, S32 y, MASK mask) handled = LLFolderViewItem::handleHover(x, y, mask); } - //if(x < LEFT_INDENTATION + mIndentation && x > mIndentation - LEFT_PAD && y > getRect().getHeight() - ) - //{ - // gViewerWindow->setCursor(UI_CURSOR_ARROW); - // mExpanderHighlighted = TRUE; - // handled = TRUE; - //} return handled; } diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 587348efd..cdda18890 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -107,13 +107,6 @@ private: protected: static const LLFontGL* sFont; static const LLFontGL* sSmallFont; - static LLColor4 sFgColor; - static LLColor4 sHighlightBgColor; - static LLColor4 sHighlightFgColor; - static LLColor4 sFilterBGColor; - static LLColor4 sFilterTextColor; - static LLColor4 sSuffixColor; - static LLColor4 sSearchStatusColor; static LLUIImagePtr sArrowImage; static LLUIImagePtr sBoxImage; @@ -122,7 +115,6 @@ protected: std::string mSearchableLabelDesc; std::string mSearchableLabelCreator; std::string mSearchable; - std::string mType; S32 mLabelWidth; U32 mCreationDate; LLFolderViewFolder* mParentFolder; @@ -156,6 +148,8 @@ protected: virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } public: + BOOL postBuild(); + // This function clears the currently selected item, and records // the specified selected item appropriately for display and use // in the UI. If open is TRUE, then folders are opened up along @@ -495,6 +489,8 @@ public: void applyFunctorRecursively(LLFolderViewFunctor& functor); virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor); + // Just apply this functor to the folder's immediate children. + void applyFunctorToChildren(LLFolderViewFunctor& functor); virtual void openItem( void ); virtual BOOL addItem(LLFolderViewItem* item); @@ -510,6 +506,11 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); + BOOL handleDragAndDropToThisFolder(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); virtual void draw(); time_t getCreationDate() const; @@ -523,6 +524,8 @@ public: items_t::const_iterator getItemsBegin() const { return mItems.begin(); } items_t::const_iterator getItemsEnd() const { return mItems.end(); } items_t::size_type getItemsCount() const { return mItems.size(); } + LLFolderViewFolder* getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse); + void gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector& items); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index f136c144e..9fe20b6b0 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -2,31 +2,25 @@ * @file llgesturemgr.cpp * @brief Manager for playing gestures on the viewer * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,11 +31,12 @@ // system #include #include -#include // library +#include "llaudioengine.h" #include "lldatapacker.h" #include "llinventory.h" +#include "llkeyframemotion.h" #include "llmultigesture.h" #include "llnotificationsutil.h" #include "llstl.h" @@ -53,10 +48,11 @@ #include "llagent.h" #include "llchatbar.h" #include "lldelayedgestureerror.h" -#include "llinventoryobserver.h" +#include "llinventorymodel.h" #include "llviewermessage.h" #include "llvoavatarself.h" #include "llviewerstats.h" +#include "llappearancemgr.h" #include "chatbar_as_cmdline.h" @@ -78,7 +74,9 @@ LLGestureMgr::LLGestureMgr() mPlaying(), mActive(), mLoadingCount(0) -{ } +{ + gInventory.addObserver(this); +} // We own the data for gestures, so clean them up. @@ -92,6 +90,7 @@ LLGestureMgr::~LLGestureMgr() delete gesture; gesture = NULL; } + gInventory.removeObserver(this); } @@ -100,6 +99,41 @@ void LLGestureMgr::init() // TODO } +void LLGestureMgr::changed(U32 mask) +{ + LLInventoryFetchItemsObserver::changed(mask); + + if (mask & LLInventoryObserver::GESTURE) + { + // If there was a gesture label changed, update all the names in the + // active gestures and then notify observers + if (mask & LLInventoryObserver::LABEL) + { + for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) + { + if(it->second) + { + LLViewerInventoryItem* item = gInventory.getItem(it->first); + if(item) + { + it->second->mName = item->getName(); + } + } + } + notifyObservers(); + } + // If there was a gesture added or removed notify observers + // STRUCTURE denotes that the inventory item has been moved + // In the case of deleting gesture, it is moved to the trash + else if(mask & LLInventoryObserver::ADD || + mask & LLInventoryObserver::REMOVE || + mask & LLInventoryObserver::STRUCTURE) + { + notifyObservers(); + } + } +} + // Use this version when you have the item_id but not the asset_id, // and you KNOW the inventory is loaded. @@ -307,6 +341,8 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id) gAgent.sendReliableMessage(); + LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, false); + notifyObservers(); } @@ -496,6 +532,66 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) gesture->mPlaying = TRUE; mPlaying.push_back(gesture); + // Load all needed assets to minimize the delays + // when gesture is playing. + for (std::vector::iterator steps_it = gesture->mSteps.begin(); + steps_it != gesture->mSteps.end(); + ++steps_it) + { + LLGestureStep* step = *steps_it; + switch(step->getType()) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + const LLUUID& anim_id = anim_step->mAnimAssetID; + + // Don't request the animation if this step stops it or if it is already in Static VFS + if (!(anim_id.isNull() + || anim_step->mFlags & ANIM_FLAG_STOP + || gAssetStorage->hasLocalAsset(anim_id, LLAssetType::AT_ANIMATION))) + { + mLoadingAssets.insert(anim_id); + + LLUUID* id = new LLUUID(gAgentID); + gAssetStorage->getAssetData(anim_id, + LLAssetType::AT_ANIMATION, + onAssetLoadComplete, + (void *)id, + TRUE); + } + break; + } + case STEP_SOUND: + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + const LLUUID& sound_id = sound_step->mSoundAssetID; + if (!(sound_id.isNull() + || gAssetStorage->hasLocalAsset(sound_id, LLAssetType::AT_SOUND))) + { + mLoadingAssets.insert(sound_id); + + gAssetStorage->getAssetData(sound_id, + LLAssetType::AT_SOUND, + onAssetLoadComplete, + NULL, + TRUE); + } + break; + } + case STEP_CHAT: + case STEP_WAIT: + case STEP_EOF: + { + break; + } + default: + { + llwarns << "Unknown gesture step type: " << step->getType() << llendl; + } + } + } + // And get it going stepGesture(gesture); @@ -711,8 +807,7 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) { return; } - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) return; + if (!isAgentAvatarValid() || hasLoadingAssets(gesture)) return; // Of the ones that started playing, have any stopped? @@ -723,8 +818,8 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) { // look in signaled animations (simulator's view of what is // currently playing. - LLVOAvatar::AnimIterator play_it = avatar->mSignaledAnimations.find(*gest_it); - if (play_it != avatar->mSignaledAnimations.end()) + LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); + if (play_it != gAgentAvatarp->mSignaledAnimations.end()) { ++gest_it; } @@ -742,8 +837,8 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) gest_it != gesture->mRequestedAnimIDs.end(); ) { - LLVOAvatar::AnimIterator play_it = avatar->mSignaledAnimations.find(*gest_it); - if (play_it != avatar->mSignaledAnimations.end()) + LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); + if (play_it != gAgentAvatarp->mSignaledAnimations.end()) { // Hooray, this animation has started playing! // Copy into playing. @@ -998,10 +1093,22 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, } } + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if(item) + { + gesture->mName = item->getName(); + } + else + { + // Watch this item and set gesture name when item exists in inventory + self.setFetchID(item_id); + self.startFetch(); + } self.mActive[item_id] = gesture; // Everything has been successful. Add to the active list. gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + if (inform_server) { // Inform the database of this change @@ -1019,6 +1126,13 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, gAgent.sendReliableMessage(); } + callback_map_t::iterator i_cb = self.mCallbackMap.find(item_id); + + if(i_cb != self.mCallbackMap.end()) + { + i_cb->second(gesture); + self.mCallbackMap.erase(i_cb); + } self.notifyObservers(); } @@ -1055,7 +1169,98 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, } } +// static +void LLGestureMgr::onAssetLoadComplete(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLGestureMgr& self = LLGestureMgr::instance(); + // Complete the asset loading process depending on the type and + // remove the asset id from pending downloads list. + switch(type) + { + case LLAssetType::AT_ANIMATION: + { + LLKeyframeMotion::onLoadComplete(vfs, asset_uuid, type, user_data, status, ext_status); + + self.mLoadingAssets.erase(asset_uuid); + + break; + } + case LLAssetType::AT_SOUND: + { + LLAudioEngine::assetCallback(vfs, asset_uuid, type, user_data, status, ext_status); + + self.mLoadingAssets.erase(asset_uuid); + + break; + } + default: + { + llwarns << "Unexpected asset type: " << type << llendl; + + // We don't want to return from this callback without + // an animation or sound callback being fired + // and *user_data handled to avoid memory leaks. + llassert(type == LLAssetType::AT_ANIMATION || type == LLAssetType::AT_SOUND); + } + } +} + +// static +bool LLGestureMgr::hasLoadingAssets(LLMultiGesture* gesture) +{ + LLGestureMgr& self = LLGestureMgr::instance(); + + for (std::vector::iterator steps_it = gesture->mSteps.begin(); + steps_it != gesture->mSteps.end(); + ++steps_it) + { + LLGestureStep* step = *steps_it; + switch(step->getType()) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + const LLUUID& anim_id = anim_step->mAnimAssetID; + + if (!(anim_id.isNull() + || anim_step->mFlags & ANIM_FLAG_STOP + || self.mLoadingAssets.find(anim_id) == self.mLoadingAssets.end())) + { + return true; + } + break; + } + case STEP_SOUND: + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + const LLUUID& sound_id = sound_step->mSoundAssetID; + + if (!(sound_id.isNull() + || self.mLoadingAssets.find(sound_id) == self.mLoadingAssets.end())) + { + return true; + } + break; + } + case STEP_CHAT: + case STEP_WAIT: + case STEP_EOF: + { + break; + } + default: + { + llwarns << "Unknown gesture step type: " << step->getType() << llendl; + } + } + } + + return false; +} void LLGestureMgr::stopGesture(LLMultiGesture* gesture) { @@ -1181,6 +1386,27 @@ void LLGestureMgr::getItemIDs(uuid_vec_t* ids) } } +void LLGestureMgr::done() +{ + bool notify = false; + for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) + { + if(it->second && it->second->mName.empty()) + { + LLViewerInventoryItem* item = gInventory.getItem(it->first); + if(item) + { + it->second->mName = item->getName(); + notify = true; + } + } + } + if(notify) + { + notifyObservers(); + } +} + // static const LLUUID& get_linked_uuid(const LLUUID &item_id) { diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index 88d3b9c4a..8211496f9 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -2,31 +2,25 @@ * @file llgesturemgr.h * @brief Manager for playing gestures on the viewer * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,6 +32,8 @@ #include #include "llassetstorage.h" // LLAssetType +#include "llinventoryobserver.h" +#include "llsingleton.h" #include "llviewerinventory.h" class LLMultiGesture; @@ -52,11 +48,14 @@ public: virtual void changed() = 0; }; -class LLGestureMgr : public LLSingleton +class LLGestureMgr : public LLSingleton, public LLInventoryFetchItemsObserver { public: + + typedef boost::function gesture_loaded_callback_t; // Maps inventory item_id to gesture typedef std::map item_map_t; + typedef std::map callback_map_t; LLGestureMgr(); ~LLGestureMgr(); @@ -110,7 +109,15 @@ public: // Also remove from playing list void stopGesture(LLMultiGesture* gesture); void stopGesture(const LLUUID& item_id); - + /** + * Add cb into callbackMap. + * Note: + * Manager will call cb after gesture will be loaded and will remove cb automatically. + */ + void setGestureLoadedCallback(LLUUID inv_item_id, gesture_loaded_callback_t cb) + { + mCallbackMap[inv_item_id] = cb; + } // Trigger the first gesture that matches this key. // Returns TRUE if it finds a gesture bound to that key. BOOL triggerGesture(KEY key, MASK mask); @@ -127,6 +134,9 @@ public: void removeObserver(LLGestureManagerObserver* observer); void notifyObservers(); + // Overriding so we can update active gesture names and notify observers + void changed(U32 mask); + BOOL matchPrefix(const std::string& in_str, std::string* out_str); // Copy item ids into the vector @@ -139,14 +149,25 @@ protected: // Do a single step in a gesture void runStep(LLMultiGesture* gesture, LLGestureStep* step); + // LLInventoryCompletionObserver trigger + void done(); + // Used by loadGesture static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + // Used by playGesture to load an asset file + // required to play a gesture step + static void onAssetLoadComplete(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); - + // Checks whether all animation and sound assets + // needed to play a gesture are loaded. + static bool hasLoadingAssets(LLMultiGesture* gesture); private: // Active gestures. @@ -157,9 +178,13 @@ private: S32 mLoadingCount; std::string mDeactivateSimilarNames; - + std::vector mObservers; + callback_map_t mCallbackMap; std::vector mPlaying; BOOL mValid; + + std::set mLoadingAssets; }; + #endif diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 1be9d7550..78177074f 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -41,6 +41,7 @@ #include "message.h" #include "llagent.h" +#include "llagentwearables.h" #include "llcallingcard.h" #include "llcheckboxctrl.h" // for radio buttons #include "llfoldervieweventlistener.h" @@ -163,15 +164,9 @@ bool doToSelected(LLFolderView* folder, std::string action) LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); if(!bridge) continue; - bridge->performAction(folder, model, action); + bridge->performAction(model, action); } - - - - - - LLFloater::setFloaterHost(NULL); if (multi_previewp) { @@ -389,12 +384,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, else { LLWearableType::EType wear_type = LLWearableType::typeNameToType(type); - if(wear_type != LLWearableType::WT_NONE) - { - LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(LLWearableType::getAssetType(wear_type)); - LLUUID parent_id = self ? self->getUUID() : gInventory.findCategoryUUIDForType(folder_type); - LLFolderBridge::createWearable(parent_id, wear_type); - } + LLAgentWearables::createWearable(wear_type, false, self ? self->getUUID() : LLUUID::null); } ptr->getRootFolder()->setNeedsAutoRename(TRUE); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e2fefc4d0..1b8bc3f60 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -41,11 +41,13 @@ #include "llinventoryicon.h" #include "llinventorymodelbackgroundfetch.h" +#include "lltrans.h" + #include "message.h" -#include "cofmgr.h" #include "llagent.h" #include "llagentwearables.h" +#include "llappearancemgr.h" #include "llagentcamera.h" #include "llcallingcard.h" #include "llcheckboxctrl.h" // for radio buttons @@ -128,6 +130,11 @@ #include "llattachmentsmgr.h" // [/RLVa:KB] +bool InventoryLinksEnabled() +{ + return gHippoGridManager->getConnectedGrid()->supportsInvLinks(); +} + typedef std::pair two_uuids_t; typedef std::list two_uuids_list_t; @@ -156,23 +163,24 @@ void dec_busy_count() } // Function declarations - -struct LLWearInfo -{ - LLUUID mCategoryID; - BOOL mAppend; - BOOL mReplace; -}; - -struct LLWearableHoldingPattern; -void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append, BOOL replace = FALSE); -void wear_inventory_category_on_avatar_step2( BOOL proceed, const LLWearInfo wear_info); -void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); -void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append); void remove_inventory_category_from_avatar(LLInventoryCategory* category); -void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata); +void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id); bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); -bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response); +bool confirm_attachment_rez(const LLSD& notification, const LLSD& response); +void teleport_via_landmark(const LLUUID& asset_id); +static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit); + +// Helper functions + +bool isAddAction(const std::string& action) +{ + return ("wear" == action || "attach" == action || "activate" == action); +} + +bool isRemoveAction(const std::string& action) +{ + return ("take_off" == action || "detach" == action || "deactivate" == action); +} // void gotImageForSaveItemAs(BOOL success, @@ -198,10 +206,10 @@ void gotAssetForSaveItemAs(LLVFS *vfs, // +=================================================+ LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : mUUID(uuid), - //mRoot(root), + mRoot(root), mInvType(LLInventoryType::IT_NONE), mIsLink(FALSE) { @@ -228,7 +236,6 @@ const std::string& LLInvFVBridge::getDisplayName() const // Folders have full perms PermissionMask LLInvFVBridge::getPermissionMask() const { - return PERM_ALL; } @@ -246,13 +253,13 @@ time_t LLInvFVBridge::getCreationDate() const } // Can be destroyed (or moved to trash) -BOOL LLInvFVBridge::isItemRemovable() +BOOL LLInvFVBridge::isItemRemovable() const { return get_is_item_removable(getInventoryModel(), mUUID); } // Can be moved to another folder -BOOL LLInvFVBridge::isItemMovable() +BOOL LLInvFVBridge::isItemMovable() const { return TRUE; } @@ -262,10 +269,27 @@ BOOL LLInvFVBridge::isLink() const return mIsLink; } +/*virtual*/ +/** + * @brief Adds this item into clipboard storage + */ +//Unused. +void LLInvFVBridge::cutToClipboard() +{ + if(isItemMovable()) + { + LLInventoryClipboard::instance().cut(mUUID); + } +} // *TODO: make sure this does the right thing void LLInvFVBridge::showProperties() { - LLShowProps::showProperties(mUUID); + show_item_profile(mUUID); + + // Disable old properties floater; this is replaced by the sidepanel. + /* + LLFloaterReg::showInstance("properties", mUUID); + */ } void LLInvFVBridge::removeBatch(LLDynamicArray& batch) @@ -526,7 +550,7 @@ BOOL LLInvFVBridge::isClipboardPasteable() const BOOL LLInvFVBridge::isClipboardPasteableAsLink() const { - if (!gHippoGridManager->getConnectedGrid()->supportsInvLinks()) + if (!InventoryLinksEnabled()) { return FALSE; } @@ -676,10 +700,13 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Paste")); } - items.push_back(std::string("Paste As Link")); - if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) + if(InventoryLinksEnabled()) { - disabled_items.push_back(std::string("Paste As Link")); + items.push_back(std::string("Paste As Link")); + if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Paste As Link")); + } } items.push_back(std::string("Paste Separator")); @@ -760,7 +787,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items, } // "Remove link" and "Delete" are the same operation. - if (obj && obj->getIsLinkType() /* && !get_is_item_worn(mUUID)*/) + if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) { items.push_back(std::string("Remove Link")); } @@ -879,7 +906,7 @@ BOOL LLInvFVBridge::isAgentInventory() const BOOL LLInvFVBridge::isCOFFolder() const { - return LLCOFMgr::instance().getCOF() == mUUID; + return LLAppearanceMgr::instance().getIsInCOF(mUUID); } BOOL LLInvFVBridge::isItemPermissive() const @@ -906,132 +933,137 @@ void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, - LLAssetType::EType actual_asset_type, - LLInventoryType::EType inv_type, - LLInventoryPanel* inventory, - const LLUUID& uuid, - U32 flags) + LLAssetType::EType actual_asset_type, + LLInventoryType::EType inv_type, + LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid, + U32 flags) { LLInvFVBridge* new_listener = NULL; switch(asset_type) { - case LLAssetType::AT_TEXTURE: - if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) - { + case LLAssetType::AT_TEXTURE: + if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) + { llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLTextureBridge(inventory, uuid, inv_type); - break; + } + new_listener = new LLTextureBridge(inventory, root, uuid, inv_type); + break; - case LLAssetType::AT_SOUND: - if(!(inv_type == LLInventoryType::IT_SOUND)) - { + case LLAssetType::AT_SOUND: + if(!(inv_type == LLInventoryType::IT_SOUND)) + { llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLSoundBridge(inventory, uuid); - break; + } + new_listener = new LLSoundBridge(inventory, root, uuid); + break; - case LLAssetType::AT_LANDMARK: - if(!(inv_type == LLInventoryType::IT_LANDMARK)) - { + case LLAssetType::AT_LANDMARK: + if(!(inv_type == LLInventoryType::IT_LANDMARK)) + { llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLLandmarkBridge(inventory, uuid, flags); - break; - - case LLAssetType::AT_CALLINGCARD: - if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLCallingCardBridge(inventory, uuid); - break; + } + new_listener = new LLLandmarkBridge(inventory, root, uuid, flags); + break; - case LLAssetType::AT_SCRIPT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { + case LLAssetType::AT_CALLINGCARD: + if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) + { llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLItemBridge(inventory, uuid); - break; + } + new_listener = new LLCallingCardBridge(inventory, root, uuid); + break; + + case LLAssetType::AT_SCRIPT: + if(!(inv_type == LLInventoryType::IT_LSL)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLItemBridge(inventory, root, uuid); + break; case LLAssetType::AT_OBJECT: if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT) || inv_type == LLInventoryType::IT_TEXTURE ) //There's an abundance of objects in inv that have texture (0) as their inv type, right out of unpack. //May have been bug either in an old client, or server version. Either way... it causes a lot of spam over something ultimately harmless. - { + { llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags); - break; - - case LLAssetType::AT_NOTECARD: - if(!(inv_type == LLInventoryType::IT_NOTECARD)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLNotecardBridge(inventory, uuid); - break; - - case LLAssetType::AT_ANIMATION: - if(!(inv_type == LLInventoryType::IT_ANIMATION)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLAnimationBridge(inventory, uuid); - break; - - case LLAssetType::AT_GESTURE: - if(!(inv_type == LLInventoryType::IT_GESTURE)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLGestureBridge(inventory, uuid); - break; - - case LLAssetType::AT_LSL_TEXT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLLSLTextBridge(inventory, uuid); - break; - - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - if(!(inv_type == LLInventoryType::IT_WEARABLE)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (LLWearableType::EType)flags); - break; - - case LLAssetType::AT_CATEGORY: - //case LLAssetType::AT_ROOT_CATEGORY: - if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) - { - // Create a link folder handler instead. - new_listener = new LLLinkFolderBridge(inventory, uuid); + } + new_listener = new LLObjectBridge(inventory, root, uuid, inv_type, flags); + break; + + case LLAssetType::AT_NOTECARD: + if(!(inv_type == LLInventoryType::IT_NOTECARD)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLNotecardBridge(inventory, root, uuid); + break; + + case LLAssetType::AT_ANIMATION: + if(!(inv_type == LLInventoryType::IT_ANIMATION)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLAnimationBridge(inventory, root, uuid); + break; + + case LLAssetType::AT_GESTURE: + if(!(inv_type == LLInventoryType::IT_GESTURE)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLGestureBridge(inventory, root, uuid); + break; + + case LLAssetType::AT_LSL_TEXT: + if(!(inv_type == LLInventoryType::IT_LSL)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLLSLTextBridge(inventory, root, uuid); + break; + + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + if(!(inv_type == LLInventoryType::IT_WEARABLE)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags); + break; + case LLAssetType::AT_CATEGORY: + if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) + { + // Create a link folder handler instead. + new_listener = new LLLinkFolderBridge(inventory, root, uuid); + break; + } + new_listener = new LLFolderBridge(inventory, root, uuid); + break; + case LLAssetType::AT_LINK: + case LLAssetType::AT_LINK_FOLDER: + // Only should happen for broken links. + new_listener = new LLLinkItemBridge(inventory, root, uuid); + break; + case LLAssetType::AT_MESH: + if(!(inv_type == LLInventoryType::IT_MESH)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLMeshBridge(inventory, root, uuid); + break; + + case LLAssetType::AT_IMAGE_TGA: + case LLAssetType::AT_IMAGE_JPEG: + //llwarns << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << llendl; + break; + + default: + llinfos << "Unhandled asset type (llassetstorage.h): " + << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << llendl; break; - } - new_listener = new LLFolderBridge(inventory, uuid); - break; - case LLAssetType::AT_LINK: - case LLAssetType::AT_LINK_FOLDER: - // Only should happen for broken links. - new_listener = new LLLinkItemBridge(inventory, uuid); - break; - case LLAssetType::AT_MESH: - if(!(inv_type == LLInventoryType::IT_MESH)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLMeshBridge(inventory, uuid); - break; - default: - llinfos << "Unhandled asset type (llassetstorage.h): " - << (S32)asset_type << llendl; - break; } if (new_listener) @@ -1042,18 +1074,33 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, return new_listener; } +void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) +{ + LLInventoryCategory* cat = model->getCategory(uuid); + if(cat) + { + model->purgeDescendentsOf(uuid); + model->notifyObservers(); + } + LLInventoryObject* obj = model->getObject(uuid); + if (obj) + { + model->purgeObject(uuid); + model->notifyObservers(); + } +} // +=================================================+ // | LLItemBridge | // +=================================================+ -void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLItemBridge::performAction(LLInventoryModel* model, std::string action) { - if ("goto" == action) { - gotoItem(folder); + gotoItem(); } - else if ("open" == action) + + if ("open" == action || "open_original" == action) { openItem(); return; @@ -1065,17 +1112,8 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, } else if ("purge" == action) { - LLInventoryCategory* cat = model->getCategory(mUUID); - if(cat) - { - model->purgeDescendentsOf(mUUID); - } - LLInventoryObject* obj = model->getObject(mUUID); - if(!obj) return; - obj->removeFromServer(); - LLPreview::hide(mUUID); - model->deleteObject(mUUID); - model->notifyObservers(); + purgeItem(model, mUUID); + return; } else if ("restoreToWorld" == action) { @@ -1092,11 +1130,11 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, // Single item only LLViewerInventoryItem* item = static_cast(getItem()); if(!item) return; - LLUUID asset_id = item->getAssetUUID(); + LLUUID asset_id = item->getProtectedAssetUUID(); std::string buffer; asset_id.toString(buffer); - gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer)); + gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer)); return; } else if ("copy" == action) @@ -1110,7 +1148,7 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLInventoryItem* itemp = model->getItem(mUUID); if (!itemp) return; - LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); + LLFolderViewItem* folder_view_itemp = mRoot->getItemByID(itemp->getParentUUID()); if (!folder_view_itemp) return; folder_view_itemp->getListener()->pasteFromClipboard(); @@ -1122,7 +1160,7 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLInventoryItem* itemp = model->getItem(mUUID); if (!itemp) return; - LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); + LLFolderViewItem* folder_view_itemp = mRoot->getItemByID(itemp->getParentUUID()); if (!folder_view_itemp) return; folder_view_itemp->getListener()->pasteLinkFromClipboard(); @@ -1154,7 +1192,7 @@ void LLItemBridge::showFloaterImagePreview(LLInventoryItem* item, AIFilePicker* void LLItemBridge::selectItem() { LLViewerInventoryItem* item = static_cast(getItem()); - if(item && !item->isComplete()) + if(item && !item->isFinished()) { // if(!(gInventory.isObjectDescendentOf(mUUID, gSystemFolderRoot))) @@ -1215,15 +1253,15 @@ void LLItemBridge::restoreToWorld() } } -void LLItemBridge::gotoItem(LLFolderView *folder) +void LLItemBridge::gotoItem() { LLInventoryObject *obj = getInventoryObject(); if (obj && obj->getIsLinkType()) { - LLInventoryView *view = LLInventoryView::getActiveInventory(); - if (view) + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) { - view->getPanel()->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); } } } @@ -1245,18 +1283,7 @@ PermissionMask LLItemBridge::getPermissionMask() const { LLViewerInventoryItem* item = getItem(); PermissionMask perm_mask = 0; - if(item) - { - BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); - BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); - BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, - gAgent.getID()); - - if (copy) perm_mask |= PERM_COPY; - if (mod) perm_mask |= PERM_MODIFY; - if (xfer) perm_mask |= PERM_TRANSFER; - - } + if (item) perm_mask = item->getPermissionMask(); return perm_mask; } @@ -1286,7 +1313,7 @@ LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const U8 font = LLFontGL::NORMAL; const LLViewerInventoryItem* item = getItem(); - if (get_is_item_worn(item)) + if (get_is_item_worn(mUUID)) { // llinfos << "BOLD" << llendl; font |= LLFontGL::BOLD; @@ -1301,27 +1328,29 @@ LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const std::string LLItemBridge::getLabelSuffix() const { - // *TODO: Translate - static std::string NO_COPY = " (no copy)"; - static std::string NO_MOD = " (no modify)"; - static std::string NO_XFER = " (no transfer)"; - static std::string TEMPO = " (temporary)"; - static std::string LINK = " (link)"; - static std::string BROKEN_LINK = "(broken_link)"; + // String table is loaded before login screen and inventory items are + // loaded after login, so LLTrans should be ready. + static std::string NO_COPY = LLTrans::getString("no_copy"); + static std::string NO_MOD = LLTrans::getString("no_modify"); + static std::string NO_XFER = LLTrans::getString("no_transfer"); + static std::string TEMPO = LLTrans::getString("temporary"); + static std::string LINK = LLTrans::getString("link"); + static std::string BROKEN_LINK = LLTrans::getString("broken_link"); std::string suffix; LLInventoryItem* item = getItem(); if(item) { - // it's a bit confusing to put nocopy/nomod/etc on calling cards. + // Any type can have the link suffix... + BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType()); + if (broken_link) return BROKEN_LINK; + + BOOL link = item->getIsLinkType(); + if (link) return LINK; + + // ...but it's a bit confusing to put nocopy/nomod/etc suffixes on calling cards. if(LLAssetType::AT_CALLINGCARD != item->getType() && item->getPermissions().getOwner() == gAgent.getID()) { - BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType()); - if (broken_link) return BROKEN_LINK; - - BOOL link = item->getIsLinkType(); - if (link) return LINK; - BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); if (!copy) { @@ -1373,7 +1402,7 @@ BOOL LLItemBridge::isItemRenameable() const return FALSE; } - if (!item->isComplete()) // EXT-8662 + if (!item->isFinished()) // EXT-8662 { return FALSE; } @@ -1428,9 +1457,10 @@ BOOL LLItemBridge::removeItem() if (!item) return FALSE; // Already in trash - if (!model->isObjectDescendentOf(mUUID, trash_id)) - { - // trash problem + if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE; + + //Is this needed? What does it fix? Ascent has bad commenting. + /* // trash problem if(gInventory.isObjectDescendentOf(mUUID, gSystemFolderRoot)) { LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), -1); @@ -1438,18 +1468,63 @@ BOOL LLItemBridge::removeItem() gInventory.accountForUpdate(up); gInventory.notifyObservers(); } - else - // + // */ + + LLNotification::Params params("ConfirmItemDeleteHasLinks"); + params.functor(boost::bind(&LLItemBridge::confirmRemoveItem, this, _1, _2)); + + // Check if this item has any links. If generic inventory linking is enabled, + // we can't do this check because we may have items in a folder somewhere that is + // not yet in memory, so we don't want false negatives. (If disabled, then we + // know we only have links in the Outfits folder which we explicitly fetch.) + if (!InventoryLinksEnabled()) + { + if (!item->getIsLinkType()) + { + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLLinkedItemIDMatches is_linked_item_match(mUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + + const U32 num_links = cat_array.size() + item_array.size(); + if (num_links > 0) + { + // Warn if the user is will break any links when deleting this item. + LLNotifications::instance().add(params); + return FALSE; + } + } + } + + LLNotifications::instance().forceResponse(params, 0); + return TRUE; +} + +BOOL LLItemBridge::confirmRemoveItem(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return FALSE; + + LLInventoryModel* model = getInventoryModel(); + if (!model) return FALSE; + + LLViewerInventoryItem* item = getItem(); + if (!item) return FALSE; + + const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + // if item is not already in trash + if(item && !model->isObjectDescendentOf(mUUID, trash_id)) + { // move to trash, and restamp LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE); // delete was successful return TRUE; } - else - { - // tried to delete already item in trash (should purge?) - return FALSE; - } + return FALSE; } BOOL LLItemBridge::isItemCopyable() const @@ -1463,19 +1538,13 @@ BOOL LLItemBridge::isItemCopyable() const return FALSE; }*/ - if(!gHippoGridManager->getConnectedGrid()->supportsInvLinks()) - return (item->getPermissions().allowCopyBy(gAgent.getID())); // You can never copy a link. - else if (item->getIsLinkType()) + if (item->getIsLinkType()) { return FALSE; } - // All items can be copied in god mode since you can - // at least paste-as-link the item, though you - // still may not be able paste the item. - return TRUE; - // return (item->getPermissions().allowCopyBy(gAgent.getID())); + return item->getPermissions().allowCopyBy(gAgent.getID()) || InventoryLinksEnabled(); } return FALSE; } @@ -1518,7 +1587,7 @@ BOOL LLItemBridge::isItemPermissive() const LLHandle LLFolderBridge::sSelf; // Can be moved to another folder -BOOL LLFolderBridge::isItemMovable() +BOOL LLFolderBridge::isItemMovable() const { LLInventoryObject* obj = getInventoryObject(); if(obj) @@ -1533,90 +1602,49 @@ void LLFolderBridge::selectItem() } -// Can be destroyed (or moved to trash) -BOOL LLFolderBridge::isItemRemovable() +// Iterate through a folder's children to determine if +// all the children are removable. +class LLIsItemRemovable : public LLFolderViewFunctor { - LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) +public: + LLIsItemRemovable() : mPassed(TRUE) {} + virtual void doFolder(LLFolderViewFolder* folder) + { + mPassed &= folder->getListener()->isItemRemovable(); + } + virtual void doItem(LLFolderViewItem* item) + { + mPassed &= item->getListener()->isItemRemovable(); + } + BOOL mPassed; +}; + +// Can be destroyed (or moved to trash) +BOOL LLFolderBridge::isItemRemovable() const +{ + if (!get_is_category_removable(getInventoryModel(), mUUID)) { return FALSE; } - // - // People delete their inventory easily... - if(mUUID == gInventory.getRootFolderID()) + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLFolderViewFolder* folderp = dynamic_cast(panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL); + if (folderp) { - return FALSE; - } - if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) - { - return FALSE; - } - -// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g - if ( ((rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveFolder(mUUID))) ) - { - return FALSE; - } -// [/RLVa:KB] - - LLVOAvatar* avatar = gAgentAvatarp; - if( !avatar ) - { - return FALSE; - } - - LLInventoryCategory* category = model->getCategory(mUUID); - if( !category ) - { - return FALSE; - } - - if ( (LLFolderType::FT_NONE != category->getPreferredType()) && (LLFolderType::FT_OUTFIT != category->getPreferredType()) ) - { - return FALSE; - } - - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE ); - - S32 i; - for( i = 0; i < descendent_categories.count(); i++ ) - { - LLInventoryCategory* category = descendent_categories[i]; - if( LLFolderType::FT_NONE != category->getPreferredType() ) + LLIsItemRemovable folder_test; + folderp->applyFunctorToChildren(folder_test); + if (!folder_test.mPassed) { return FALSE; } } - for( i = 0; i < descendent_items.count(); i++ ) - { - LLInventoryItem* item = descendent_items[i]; - if ((item->getType() == LLAssetType::AT_CLOTHING || - item->getType() == LLAssetType::AT_BODYPART) && !item->getIsLinkType()) - { - if( gAgentWearables.isWearingItem( item->getUUID() ) ) - { - return FALSE; - } - } - else if (item->getType() == LLAssetType::AT_OBJECT && !item->getIsLinkType()) - { - if( avatar->isWearingAttachment( item->getUUID() ) ) - { - return FALSE; - } - } - } - return TRUE; } BOOL LLFolderBridge::isUpToDate() const { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); if( !category ) @@ -1624,12 +1652,26 @@ BOOL LLFolderBridge::isUpToDate() const return FALSE; } - // trying to make it stop trying to fetch Local Inventory return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; - //return (category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) || (mUUID == gSystemFolderRoot) || (gInventory.isObjectDescendentOf(mUUID, gSystemFolderRoot)); - // } +BOOL LLFolderBridge::isItemCopyable() const +{ + // Can copy folders to paste-as-link, but not for straight paste. + return InventoryLinksEnabled(); +} + + +BOOL LLFolderBridge::isClipboardPasteable() const +{ + if(LLInventoryClipboard::instance().hasContents() && isAgentInventory()) + { + return TRUE; + } + return FALSE; +} + + BOOL LLFolderBridge::isClipboardPasteableAsLink() const { // Check normal paste-as-link permissions @@ -1688,6 +1730,49 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const } + +int get_folder_levels(LLInventoryCategory* inv_cat) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + + int max_child_levels = 0; + + for (S32 i=0; i < cats->count(); ++i) + { + LLInventoryCategory* category = cats->get(i); + max_child_levels = llmax(max_child_levels, get_folder_levels(category)); + } + + return 1 + max_child_levels; +} + +int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id) +{ + int depth = 0; + + if (ancestor_id == descendant_id) return depth; + + const LLInventoryCategory* category = gInventory.getCategory(descendant_id); + + while(category) + { + LLUUID parent_id = category->getParentUUID(); + + if (parent_id.isNull()) break; + + depth++; + + if (parent_id == ancestor_id) return depth; + + category = gInventory.getCategory(parent_id); + } + + llwarns << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << llendl; + return -1; +} + BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL drop) { @@ -1699,77 +1784,176 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (!isAgentAvatarValid()) return FALSE; if (!isAgentInventory()) return FALSE; // cannot drag categories into library + const LLUUID &cat_id = inv_cat->getUUID(); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); // check to make sure source is agent inventory, and is represented there. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) + const BOOL is_agent_inventory = (model->getCategory(cat_id) != NULL) && (LLToolDragAndDrop::SOURCE_AGENT == source); BOOL accept = FALSE; - if(is_agent_inventory) + if (is_agent_inventory) { - const LLUUID& cat_id = inv_cat->getUUID(); const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); + const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); + const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - BOOL is_movable = (LLFolderType::FT_NONE == inv_cat->getPreferredType()); - if( is_movable ) + const BOOL move_is_into_outfit = getCategory() && (getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT); + const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); + + //-------------------------------------------------------------------------------- + // Determine if folder can be moved. + // + + BOOL is_movable = TRUE; + + // Can't move a folder into itself + if (is_movable && (mUUID == cat_id)) { - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); + is_movable = FALSE; + // tooltip? + } + // Avoid circularity + if (is_movable && (model->isObjectDescendentOf(mUUID, cat_id))) + { + is_movable = FALSE; + // tooltip? + } + // Can't move protected types. + if (is_movable && LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) + { + is_movable = FALSE; + // tooltip? + } + // Can't drag into the outfit folder + if (is_movable && move_is_into_outfit) + { + is_movable = FALSE; + // tooltip? + } + // Can't move favorites folder. + if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE))) + { + is_movable = FALSE; + // tooltip? + } + // Avoid moves that would change nothing + if (is_movable && (mUUID != inv_cat->getParentUUID())) + { + is_movable = FALSE; + // tooltip? + } + + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + if (is_movable) + { + model->collectDescendents(cat_id, descendent_categories, descendent_items, FALSE); for (S32 i=0; i < descendent_categories.count(); ++i) { LLInventoryCategory* category = descendent_categories[i]; if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) { - // ...can't move "special folders" like Textures + // Can't move "special folders" (e.g. Textures Folder). is_movable = FALSE; break; } } - if( is_movable && move_is_into_trash ) + } + if (is_movable && move_is_into_trash) + { + for (S32 i=0; i < descendent_items.count(); ++i) { - for (S32 i=0; i < descendent_items.count(); ++i) + LLInventoryItem* item = descendent_items[i]; + if (get_is_item_worn(item->getUUID())) + { + is_movable = FALSE; + break; // It's generally movable, but not into the trash. + } + } + } + if (is_movable && move_is_into_landmarks) + { + for (S32 i=0; i < descendent_items.count(); ++i) + { + LLViewerInventoryItem* item = descendent_items[i]; + + // Don't move anything except landmarks and categories into Landmarks folder. + // We use getType() instead of getActua;Type() to allow links to landmarks and folders. + if (LLAssetType::AT_LANDMARK != item->getType() && LLAssetType::AT_CATEGORY != item->getType()) + { + is_movable = FALSE; + break; // It's generally movable, but not into Landmarks. + } + } + } + + accept = is_movable; + + if (accept && drop) + { + // Look for any gestures and deactivate them + if (move_is_into_trash) + { + for (S32 i=0; i < descendent_items.count(); i++) { LLInventoryItem* item = descendent_items[i]; - if (get_is_item_worn(item)) + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureMgr::instance().isGestureActive(item->getUUID())) { - is_movable = FALSE; // It's generally movable, but not into the trash! - break; + LLGestureMgr::instance().deactivateGesture(item->getUUID()); } } } - - // - //-------------------------------------------------------------------------------- - -// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g - if ( (is_movable) && (rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) ) + // if target is an outfit or current outfit folder we use link + if (move_is_into_current_outfit || move_is_into_outfit) { - is_movable = RlvFolderLocks::instance().canMoveFolder(cat_id, mUUID); - } -// [/RLVa:KB] - - accept = is_movable - && (mUUID != cat_id) // Can't move a folder into itself - && (mUUID != inv_cat->getParentUUID()) // Avoid moves that would change nothing - && !(model->isObjectDescendentOf(mUUID, cat_id)); // Avoid circularity - if (accept && drop) - { - // Look for any gestures and deactivate them - if (move_is_into_trash) + if (inv_cat->getPreferredType() == LLFolderType::FT_NONE) { - for (S32 i = 0; i < descendent_items.count(); i++) + if (move_is_into_current_outfit) { - LLInventoryItem* item = descendent_items[i]; - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item->getUUID())) - { - LLGestureMgr::instance().deactivateGesture(item->getUUID()); - } + // traverse category and add all contents to currently worn. + BOOL append = true; + LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append); + } + else + { + // Recursively create links in target outfit. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + model->collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + LLAppearanceMgr::instance().linkAll(mUUID,items,NULL); } } - + else + { +#if SUPPORT_ENSEMBLES + // BAP - should skip if dup. + if (move_is_into_current_outfit) + { + LLAppearanceMgr::instance().addEnsembleLink(inv_cat); + } + else + { + LLPointer cb = NULL; + const std::string empty_description = ""; + link_inventory_item( + gAgent.getID(), + cat_id, + mUUID, + inv_cat->getName(), + empty_description, + LLAssetType::AT_LINK_FOLDER, + cb); + } +#endif + } + } + else + { // Reparent the folder and restamp children if it's moving // into trash. LLInvFVBridge::changeCategoryParent( @@ -1780,13 +1964,21 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } - else if(LLToolDragAndDrop::SOURCE_WORLD == source) + else if (LLToolDragAndDrop::SOURCE_WORLD == source) { - // content category has same ID as object itself - LLUUID object_id = inv_cat->getUUID(); - LLUUID category_id = mUUID; - accept = move_inv_category_world_to_agent(object_id, category_id, drop); + accept = move_inv_category_world_to_agent(cat_id, mUUID, drop); } + else if (LLToolDragAndDrop::SOURCE_LIBRARY == source) + { + // Accept folders that contain complete outfits. + accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id); + + if (accept && drop) + { + LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, true, false); + } + } + return accept; } @@ -1921,7 +2113,6 @@ public: gInventory.removeObserver(this); delete this; } - protected: LLUUID mCatID; @@ -2062,7 +2253,6 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask) if (mFolderAdded) { LLViewerInventoryCategory* category = gInventory.getCategory(mCatID); - if (NULL == category) { llwarns << "gInventory.getCategory(" << mCatID @@ -2074,7 +2264,7 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask) mContentsCount) { gInventory.removeObserver(this); - wear_inventory_category(category, FALSE, TRUE); + LLAppearanceMgr::instance().wearInventoryCategory(category, FALSE, FALSE); delete this; } } @@ -2085,11 +2275,16 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask) -void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) { if ("open" == action) { - openItem(); + LLFolderViewFolder *f = dynamic_cast(mRoot->getItemByID(mUUID)); + if (f) + { + f->setOpen(TRUE); + } + return; } else if ("paste" == action) @@ -2119,7 +2314,7 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model } else if ("wearitems" == action) { - modifyOutfit(TRUE, TRUE); + modifyOutfit(TRUE); } else if ("removefromoutfit" == action) { @@ -2132,19 +2327,9 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model return; } else if ("purge" == action) - { - LLViewerInventoryCategory* cat; - cat = (LLViewerInventoryCategory*)getCategory(); - - if(cat) - { - model->purgeDescendentsOf(mUUID); - } - LLInventoryObject* obj = model->getObject(mUUID); - if(!obj) return; - obj->removeFromServer(); - model->deleteObject(mUUID); - model->notifyObservers(); + { + purgeItem(model, mUUID); + return; } else if ("restore" == action) { @@ -2169,6 +2354,24 @@ void LLFolderBridge::openItem() } } +void LLFolderBridge::closeItem() +{ + determineFolderType(); +} + +void LLFolderBridge::determineFolderType() +{ + if (isUpToDate()) + { + LLInventoryModel* model = getInventoryModel(); + LLViewerInventoryCategory* category = model->getCategory(mUUID); + if (category) + { + category->determineFolderType(); + } + } +} + BOOL LLFolderBridge::isItemRenameable() const { return get_is_category_renameable(getInventoryModel(), mUUID); @@ -2241,80 +2444,48 @@ BOOL LLFolderBridge::removeItem() { return FALSE; } - // move it to the trash - LLPreview::hide(mUUID); - LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) return FALSE; - - LLUUID trash_id; - trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE ); - - S32 i; - for (i = 0; i < descendent_items.count(); i++) - { - LLInventoryItem* item = descendent_items[i]; - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item->getUUID())) - { - LLGestureMgr::instance().deactivateGesture(item->getUUID()); - } - } - - // go ahead and do the normal remove if no 'last calling - // cards' are being removed. - LLViewerInventoryCategory* cat = getCategory(); - if(cat) - { - // trash problem - if(gInventory.isObjectDescendentOf(cat->getUUID(), gSystemFolderRoot)) - { - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLInventoryModel::LLCategoryUpdate up(cat->getUUID(), -descendents); - gInventory.accountForUpdate(up); - } - cat->setDescendentCount(0); - LLInventoryModel::cat_array_t categories; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(cat->getUUID(), - categories, - items, - false); // include trash? - S32 count = items.count(); - S32 i; - for(i = 0; i < count; ++i) - { - gInventory.deleteObject(items.get(i)->getUUID()); - } - count = categories.count(); - for(i = 0; i < count; ++i) - { - gInventory.deleteObject(categories.get(i)->getUUID()); - } - - LLInventoryModel::LLCategoryUpdate up(cat->getParentUUID(), -descendents); - gInventory.deleteObject(cat->getUUID()); - gInventory.accountForUpdate(up); - gInventory.notifyObservers(); - } - else - // - LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE); - } + const LLViewerInventoryCategory *cat = getCategory(); + + LLSD payload; + LLSD args; + args["FOLDERNAME"] = cat->getName(); + LLNotification::Params params("ConfirmDeleteProtectedCategory"); + params.payload(payload).substitutions(args).functor(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2)); + LLNotifications::instance().forceResponse(params, 0); return TRUE; } -BOOL LLFolderBridge::isClipboardPasteable() const +BOOL LLFolderBridge::removeSystemFolder() { - if(LLInventoryClipboard::instance().hasContents() && isAgentInventory()) + const LLViewerInventoryCategory *cat = getCategory(); + if (!LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { + return FALSE; + } + + LLSD payload; + LLSD args; + args["FOLDERNAME"] = cat->getName(); + + LLNotification::Params params("ConfirmDeleteProtectedCategory"); + params.payload(payload).substitutions(args).functor(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2)); + { + LLNotifications::instance().add(params); + } + return TRUE; +} + +bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + + // if they choose delete, do it. Otherwise, don't do anything + if(option == 0) + { + // move it to the trash + LLPreview::hide(mUUID); + remove_category(getInventoryModel(), mUUID); return TRUE; } return FALSE; @@ -2325,6 +2496,10 @@ void LLFolderBridge::pasteFromClipboard() LLInventoryModel* model = getInventoryModel(); if(model && isClipboardPasteable()) { + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const LLUUID parent_id(mUUID); LLDynamicArray objects; @@ -2337,10 +2512,29 @@ void LLFolderBridge::pasteFromClipboard() LLInventoryItem *item = model->getItem(item_id); if (item) { + if (move_is_into_current_outfit || move_is_into_outfit) { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), + if (can_move_to_outfit(item, move_is_into_current_outfit)) + { + dropToOutfit(item, move_is_into_current_outfit); + } + } + else if(LLInventoryClipboard::instance().isCutMode()) + { + // move_inventory_item() is not enough, + //we have to update inventory locally too + LLViewerInventoryItem* viitem = dynamic_cast(item); + llassert(viitem); + if (viitem) + { + changeItemParent(model, viitem, parent_id, FALSE); + } + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), item->getUUID(), parent_id, std::string(), @@ -2356,6 +2550,10 @@ void LLFolderBridge::pasteLinkFromClipboard() LLInventoryModel* model = getInventoryModel(); if(model) { + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const LLUUID parent_id(mUUID); LLDynamicArray objects; @@ -2365,7 +2563,27 @@ void LLFolderBridge::pasteLinkFromClipboard() ++iter) { const LLUUID &object_id = (*iter); - if (LLInventoryItem *item = model->getItem(object_id)) + if (move_is_into_current_outfit || move_is_into_outfit) + { + LLInventoryItem *item = model->getItem(object_id); + if (item && can_move_to_outfit(item, move_is_into_current_outfit)) + { + dropToOutfit(item, move_is_into_current_outfit); + } + } + else if (LLInventoryCategory *cat = model->getCategory(object_id)) + { + const std::string empty_description = ""; + link_inventory_item( + gAgent.getID(), + cat->getUUID(), + parent_id, + cat->getName(), + empty_description, + LLAssetType::AT_LINK_FOLDER, + LLPointer(NULL)); + } + else if (LLInventoryItem *item = model->getItem(object_id)) { link_inventory_item( gAgent.getID(), @@ -2383,13 +2601,133 @@ void LLFolderBridge::pasteLinkFromClipboard() void LLFolderBridge::staticFolderOptionsMenu() { LLFolderBridge* selfp = sSelf.get(); - if (selfp) + + if (selfp && selfp->mRoot) { - selfp->folderOptionsMenu(); + //selfp->mRoot->updateMenu(); + selfp->buildContextMenuFolderOptions(0); } } -void LLFolderBridge::folderOptionsMenu() +BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + model->collectDescendentsIf(mUUID, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_type); + return ((item_array.count() > 0) ? TRUE : FALSE ); +} + +void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) +{ + LLUUID cof_id = LLAppearanceMgr::instance().getCOF(); + LLInventoryModel* model = getInventoryModel(); + llassert(model != NULL); + + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + +// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) + // Fixes LL bug + mItems.clear(); + mDisabledItems.clear(); +// [/RLVa:KB] + + if (lost_and_found_id == mUUID) + { + // This is the lost+found folder. + mItems.push_back(std::string("Empty Lost And Found")); + + mDisabledItems.push_back(std::string("New Folder")); + mDisabledItems.push_back(std::string("New Script")); + mDisabledItems.push_back(std::string("New Note")); + mDisabledItems.push_back(std::string("New Gesture")); + mDisabledItems.push_back(std::string("New Clothes")); + mDisabledItems.push_back(std::string("New Body Parts")); + } + + // clear out old menu and folder pointers + mMenu.markDead(); + if (cof_id == mUUID) + { + mItems.push_back(std::string("Take Off Items")); + } + else if(trash_id == mUUID) + { + // This is the trash. + mItems.push_back(std::string("Empty Trash")); + } + else if(isItemInTrash()) + { + // This is a folder in the trash. + mItems.clear(); // clear any items that used to exist + addTrashContextMenuOptions(mItems, mDisabledItems); + } + else if(isAgentInventory()) // do not allow creating in library + { + LLViewerInventoryCategory *cat = getCategory(); + // BAP removed protected check to re-enable standard ops in untyped folders. + // Not sure what the right thing is to do here. + if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) + { + mItems.push_back(std::string("New Folder")); + mItems.push_back(std::string("New Script")); + mItems.push_back(std::string("New Note")); + mItems.push_back(std::string("New Gesture")); + mItems.push_back(std::string("New Clothes")); + mItems.push_back(std::string("New Body Parts")); + + getClipboardEntries(false, mItems, mDisabledItems, flags); + } + else + { + // Want some but not all of the items from getClipboardEntries for outfits. + if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) + { + mItems.push_back(std::string("Rename")); + + addDeleteContextMenuOptions(mItems, mDisabledItems); + // EXT-4030: disallow deletion of currently worn outfit + const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory())) + { + mDisabledItems.push_back(std::string("Delete")); + } + } + } + + //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 + mCallingCards = mWearables = FALSE; + + LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); + if (checkFolderForContentsOfType(model, is_callingcard)) + { + mCallingCards=TRUE; + } + + LLFindWearables is_wearable; + LLIsType is_object( LLAssetType::AT_OBJECT ); + LLIsType is_gesture( LLAssetType::AT_GESTURE ); + + if (checkFolderForContentsOfType(model, is_wearable) || + checkFolderForContentsOfType(model, is_object) || + checkFolderForContentsOfType(model, is_gesture) ) + { + mWearables=TRUE; + } + } + + // Preemptively disable system folder removal if more than one item selected. + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + mDisabledItems.push_back(std::string("Delete System Folder")); + } +} + +void LLFolderBridge::buildContextMenuFolderOptions(U32 flags) { // *TODO: Translate @@ -2425,6 +2763,13 @@ void LLFolderBridge::folderOptionsMenu() mDisabledItems.push_back(std::string("Delete")); } +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (LLFolderType::lookupIsProtectedType(type)) + { + mItems.push_back(std::string("Delete System Folder")); + } +#endif + // wearables related functionality for folders. //is_wearable LLFindWearables is_wearable; @@ -2441,10 +2786,10 @@ void LLFolderBridge::folderOptionsMenu() // Only enable add/replace outfit for non-default folders. if (!is_system_folder) { - if (gHippoGridManager->getConnectedGrid()->supportsInvLinks() && + if (InventoryLinksEnabled() && // Adding an outfit onto another (versus replacing) doesn't make sense. type != LLFolderType::FT_OUTFIT) - { + { mItems.push_back(std::string("Add To Outfit")); } mItems.push_back(std::string("Wear Items")); @@ -2459,21 +2804,11 @@ void LLFolderBridge::folderOptionsMenu() } } -BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) -{ - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - model->collectDescendentsIf(mUUID, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_type); - return ((item_array.count() > 0) ? TRUE : FALSE ); -} - // Flags unused void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { + sSelf.markDead(); + mItems.clear(); mDisabledItems.clear(); @@ -2482,100 +2817,15 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // std::vector disabled_items; LLInventoryModel* model = getInventoryModel(); if(!model) return; - LLUUID cof_id = LLCOFMgr::instance().getCOF(); - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - const LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - // Fixes LL bug - mItems.clear(); - mDisabledItems.clear(); -// [/RLVa:KB] - - if (lost_and_found_id == mUUID) - { - // This is the lost+found folder. - mItems.push_back(std::string("Empty Lost And Found")); - } - // clear out old menu and folder pointers - mMenu.markDead(); - sSelf.markDead(); - if (cof_id == mUUID) + buildContextMenuBaseOptions(flags); + + // Add menu items that are dependent on the contents of the folder. + LLViewerInventoryCategory* category = (LLViewerInventoryCategory *) model->getCategory(mUUID); + if (category) { - mItems.push_back(std::string("Take Off Items")); - } - else if(trash_id == mUUID) - { - // This is the trash. - mItems.push_back(std::string("Empty Trash")); - } - else if(isItemInTrash()) - { - // This is a folder in the trash. - mItems.clear(); // clear any items that used to exist - addTrashContextMenuOptions(mItems, mDisabledItems); - } - else if(isAgentInventory()) // do not allow creating in library - { - //LLViewerInventoryCategory *cat = getCategory(); - // BAP removed protected check to re-enable standard ops in untyped folders. - // Not sure what the right thing is to do here. - //if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) - { - mItems.push_back(std::string("New Folder")); - mItems.push_back(std::string("New Script")); - mItems.push_back(std::string("New Note")); - mItems.push_back(std::string("New Gesture")); - mItems.push_back(std::string("New Clothes")); - mItems.push_back(std::string("New Body Parts")); - - getClipboardEntries(false, mItems, mDisabledItems, flags); - } - /*else - { - // Want some but not all of the items from getClipboardEntries for outfits. - if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) - { - mItems.push_back(std::string("Rename")); - - addDeleteContextMenuOptions(mItems, mDisabledItems); - // EXT-4030: disallow deletion of currently worn outfit - const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); - if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory())) - { - mDisabledItems.push_back(std::string("Delete")); - } - } - }*/ - - //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 - mCallingCards = mWearables = FALSE; - - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (checkFolderForContentsOfType(model, is_callingcard)) - { - mCallingCards=TRUE; - } - - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) - { - mWearables=TRUE; - } - - uuid_vec_t folders; - LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); - if (category) - { - folders.push_back(category->getUUID()); - } + folders.push_back(category->getUUID()); mMenu = menu.getHandle(); sSelf = getHandle(); @@ -2584,6 +2834,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) inc_busy_count(); if(fetch->isFinished()) { + //buildContextMenuFolderOptions(flags); // everything is already here - call done. fetch->done(); } @@ -2622,27 +2873,45 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, BOOL accept = FALSE; switch(cargo_type) { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_CALLINGCARD: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_CLOTHING: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - case DAD_LINK: - accept = dragItemIntoFolder(inv_item, - drop); - break; - case DAD_CATEGORY: - accept = dragCategoryIntoFolder((LLInventoryCategory*)inv_item, - drop); - break; - default: - break; + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_CALLINGCARD: + case DAD_LANDMARK: + case DAD_SCRIPT: + case DAD_CLOTHING: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: + case DAD_MESH: + accept = dragItemIntoFolder(inv_item, drop); + break; + case DAD_LINK: + // DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER. + // If we have an item of AT_LINK_FOLDER type we should process the linked + // category being dragged or dropped into folder. + if (inv_item && LLAssetType::AT_LINK_FOLDER == inv_item->getActualType()) + { + LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID()); + if (linked_category) + { + accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop); + } + } + else + { + accept = dragItemIntoFolder(inv_item, drop); + } + break; + case DAD_CATEGORY: + accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop); + case DAD_ROOT_CATEGORY: + case DAD_NONE: + break; + default: + llwarns << "Unhandled cargo type for drag&drop " << cargo_type << llendl; + break; } return accept; } @@ -2769,32 +3038,17 @@ void LLFolderBridge::createWearable(LLFolderBridge* bridge, LLWearableType::ETyp { if(!bridge) return; LLUUID parent_id = bridge->getUUID(); - createWearable(parent_id, type); + LLAgentWearables::createWearable(type, false, parent_id); } -// Separate function so can be called by global menu as well as right-click -// menu. -// static -void LLFolderBridge::createWearable(LLUUID parent_id, LLWearableType::EType type) -{ - LLWearable* wearable = LLWearableList::instance().createNewWearable(type); - LLAssetType::EType asset_type = wearable->getAssetType(); - LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - parent_id, wearable->getTransactionID(), wearable->getName(), - wearable->getDescription(), asset_type, inv_type, wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), - LLPointer(NULL)); -} - -void LLFolderBridge::modifyOutfit(BOOL append, BOOL replace) +void LLFolderBridge::modifyOutfit(BOOL append/*, BOOL replace*/) { LLInventoryModel* model = getInventoryModel(); if(!model) return; LLViewerInventoryCategory* cat = getCategory(); if(!cat) return; - - wear_inventory_category_on_avatar(cat, append, replace); + + LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, append ); } // helper stuff @@ -2811,8 +3065,8 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response LLInventoryObject::object_list_t inventory_objects; object->getInventoryContents(inventory_objects); int contents_count = inventory_objects.size()-1; //subtract one for containing folder - LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count, cat_and_wear->mFolderResponded); + gInventory.addObserver(inventoryObserver); } @@ -2837,6 +3091,88 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response return false; } +// Returns true if the item can be moved to Current Outfit or any outfit folder. +static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit) +{ + if ((inv_item->getInventoryType() != LLInventoryType::IT_WEARABLE) && + (inv_item->getInventoryType() != LLInventoryType::IT_GESTURE) && + (inv_item->getInventoryType() != LLInventoryType::IT_ATTACHMENT) && + (inv_item->getInventoryType() != LLInventoryType::IT_OBJECT)) + { + return FALSE; + } + + if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID())) + { + return FALSE; + } + + return TRUE; +} + +// Returns TRUE if item is a landmark or a link to a landmark +// and can be moved to Favorites or Landmarks folder. +static BOOL can_move_to_landmarks(LLInventoryItem* inv_item) +{ + // Need to get the linked item to know its type because LLInventoryItem::getType() + // returns actual type AT_LINK for links, not the asset type of a linked item. + if (LLAssetType::AT_LINK == inv_item->getType()) + { + LLInventoryItem* linked_item = gInventory.getItem(inv_item->getLinkedUUID()); + if (linked_item) + { + return LLAssetType::AT_LANDMARK == linked_item->getType(); + } + } + + return LLAssetType::AT_LANDMARK == inv_item->getType(); +} + +void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item) +{ + // use callback to rearrange favorite landmarks after adding + // to have new one placed before target (on which it was dropped). See EXT-4312. + LLPointer cb = new AddFavoriteLandmarkCallback(); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; + if (drag_over_item && drag_over_item->getListener()) + { + cb.get()->setTargetLandmarkId(drag_over_item->getListener()->getUUID()); + } + + copy_inventory_item( + gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + mUUID, + std::string(), + cb); +} + +void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit) +{ + // BAP - should skip if dup. + if (move_is_into_current_outfit) + { + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item->getUUID(), true, true); + } + else + { + LLPointer cb = NULL; + link_inventory_item( + gAgent.getID(), + inv_item->getLinkedUUID(), + mUUID, + inv_item->getName(), + inv_item->getDescription(), + LLAssetType::AT_LINK, + cb); + } +} + +// This is used both for testing whether an item can be dropped +// into the folder, as well as performing the actual drop, depending +// if drop == TRUE. BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop) { @@ -2847,7 +3183,13 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, if (!isAgentAvatarValid()) return FALSE; const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); + const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + const BOOL move_is_into_favorites = (mUUID == favorites_id); + const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); BOOL accept = FALSE; @@ -2857,7 +3199,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - const BOOL move_is_outof_current_outfit = model->isObjectDescendentOf(inv_item->getUUID(), current_outfit_id); + const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID()); + //-------------------------------------------------------------------------------- // Determine if item can be moved. // @@ -2877,32 +3220,38 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, break; } - if (is_movable && move_is_outof_current_outfit) + if (move_is_outof_current_outfit) { - is_movable = FALSE; // Don't allow dragging links out of COF + is_movable = FALSE; } - else if(is_movable && move_is_into_trash) + if (move_is_into_trash) { is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); } - -// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g - if ( (rlv_handler_t::isEnabled()) && (is_movable) ) - { - if (move_is_into_current_outfit) - { - // RELEASE-RLVa: [RLVa-1.3.0] Keep sync'ed with code below => LLAppearanceMgr::wearItemOnAvatar() with "replace == true" - const LLViewerInventoryItem* pItem = dynamic_cast(inv_item); - is_movable = rlvPredCanWearItem(pItem, RLV_WEAR_REPLACE); - } - if (is_movable) - { - is_movable = (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (RlvFolderLocks::instance().canMoveItem(inv_item->getUUID(), mUUID)); - } - } - // [/RLVa:KB] + + //-------------------------------------------------------------------------------- + // Determine if item can be moved & dropped + // + + accept = TRUE; + + if (!is_movable) + { + accept = FALSE; + } + else if ((mUUID == inv_item->getParentUUID()) && !move_is_into_favorites) + { + accept = FALSE; + } + else if (move_is_into_current_outfit || move_is_into_outfit) + { + accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); + } + else if (move_is_into_favorites || move_is_into_landmarks) + { + accept = can_move_to_landmarks(inv_item); + } - accept = is_movable && (mUUID != inv_item->getParentUUID()); if(accept && drop) { if (inv_item->getType() == LLAssetType::AT_GESTURE @@ -2910,41 +3259,35 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { LLGestureMgr::instance().deactivateGesture(inv_item->getUUID()); } - // If an item is being dragged between windows, unselect - // everything in the active window so that we don't follow - // the selection to its new location (which is very - // annoying). - if (LLInventoryView::getActiveInventory()) + // If an item is being dragged between windows, unselect everything in the active window + // so that we don't follow the selection to its new location (which is very annoying). + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) { - LLInventoryPanel* active_panel = LLInventoryView::getActiveInventory()->getPanel(); - if (active_panel && (mInventoryPanel != active_panel)) + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + if (active_panel && (panel != active_panel)) { active_panel->unSelectAll(); } } - if (move_is_into_current_outfit) + // FAVORITES folder + // (copy the item) + else if (move_is_into_favorites) { - switch (inv_item->getType()) - { - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - wear_inventory_item_on_avatar(inv_item); - break; - case LLAssetType::AT_OBJECT: - rez_attachment((LLViewerInventoryItem*)inv_item, NULL, true); - break; - /* - case LLAssetType::AT_GESTURE: - break; - */ - default: - break; - } + dropToFavorites(inv_item); } + // CURRENT OUTFIT or OUTFIT folder + // (link the item) + else if (move_is_into_current_outfit || move_is_into_outfit) + { + dropToOutfit(inv_item, move_is_into_current_outfit); + } + // NORMAL or TRASH folder + // (move the item, restamp if into trash) else { - // restamp if the move is into the trash. + LLInvFVBridge::changeItemParent( model, (LLViewerInventoryItem*)inv_item, @@ -2975,8 +3318,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, BOOL is_move = FALSE; if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) && perm.allowTransferTo(gAgent.getID()))) -// || gAgent.isGodlike()) - + // || gAgent.isGodlike()) { accept = TRUE; } @@ -2988,7 +3330,22 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, is_move = TRUE; accept = TRUE; } - if(drop && accept) + + // Don't allow placing an original item into Current Outfit or an outfit folder + // because they must contain only links to wearable items. + // *TODO: Probably we should create a link to an item if it was dragged to outfit or COF. + if (move_is_into_current_outfit || move_is_into_outfit) + { + accept = FALSE; + } + // Don't allow to move a single item to Favorites or Landmarks + // if it is not a landmark or a link to a landmark. + else if ((move_is_into_favorites || move_is_into_landmarks) + && !can_move_to_landmarks(inv_item)) + { + accept = FALSE; + } + if (accept && drop) { LLMoveInv* move_inv = new LLMoveInv; move_inv->mObjectID = inv_item->getParentUUID(); @@ -3002,6 +3359,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else { + // store dad inventory item to select added one later. See EXT-4347 + set_dad_inventory_item(inv_item, mUUID); LLNotification::Params params("MoveInventoryFromObject"); params.functor(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); LLNotifications::instance().forceResponse(params, 0); @@ -3011,28 +3370,61 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) { - accept = TRUE; - if(drop) { - copy_inventory_from_notecard(LLToolDragAndDrop::getInstance()->getObjectID(), - LLToolDragAndDrop::getInstance()->getSourceID(), inv_item); + // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder + // because they must contain only links to wearable items. + accept = !(move_is_into_current_outfit || move_is_into_outfit); + } + + if (accept && drop) + { + copy_inventory_from_notecard(mUUID, // Drop to the chosen destination folder + LLToolDragAndDrop::getInstance()->getObjectID(), + LLToolDragAndDrop::getInstance()->getSourceID(), + inv_item); } } else if(LLToolDragAndDrop::SOURCE_LIBRARY == source) { LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item; - if(item && item->isComplete()) + if(item && item->isFinished()) { accept = TRUE; - if(drop) + if (move_is_into_current_outfit || move_is_into_outfit) { - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - mUUID, - std::string(), - LLPointer(NULL)); + accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); + } + // Don't allow to move a single item to Favorites or Landmarks + // if it is not a landmark or a link to a landmark. + else if (move_is_into_favorites || move_is_into_landmarks) + { + accept = can_move_to_landmarks(inv_item); + } + + if (accept && drop) + { + // FAVORITES folder + // (copy the item) + if (move_is_into_favorites) + { + dropToFavorites(inv_item); + } + // CURRENT OUTFIT or OUTFIT folder + // (link the item) + else if (move_is_into_current_outfit || move_is_into_outfit) + { + dropToOutfit(inv_item, move_is_into_current_outfit); + } + else + { + copy_inventory_item( + gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + mUUID, + std::string(), + LLPointer(NULL)); + } } } } @@ -3104,28 +3496,11 @@ void LLTextureBridge::openItem() void LLSoundBridge::openItem() { -// Changed this back to the way it USED to work: -// only open the preview dialog through the contextual right-click menu -// double-click just plays the sound - LLViewerInventoryItem* item = getItem(); if(item) { openSoundPreview((void*)this); - //send_uuid_sound_trigger(item->getAssetUUID(), 1.0); } - -// if(!LLPreview::show(mUUID)) -// { -// S32 left, top; -// gFloaterView->getNewFloaterPosition(&left, &top); -// LLRect rect = gSavedSettings.getRect("PreviewSoundRect"); -// rect.translate(left - rect.mLeft, top - rect.mTop); -// new LLPreviewSound("preview sound", -// rect, -// getPrefix() + getName(), -// mUUID)); -// } } void LLSoundBridge::previewItem() @@ -3158,9 +3533,9 @@ void LLSoundBridge::openSoundPreview(void* which) void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLTextureBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + lldebugs << "LLSoundBridge::buildContextMenu()" << llendl; + menuentry_vec_t items; + menuentry_vec_t disabled_items; // *TODO: Translate if(isItemInTrash()) @@ -3186,10 +3561,10 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // +=================================================+ LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid, U32 flags/* = 0x00*/) : - LLItemBridge(inventory, /*root,*/ uuid) + LLItemBridge(inventory, root, uuid) { mVisited = FALSE; if (flags & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED) @@ -3225,30 +3600,43 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Landmark Separator")); items.push_back(std::string("Teleport To Landmark")); + // Disable "About Landmark" menu item for + // multiple landmarks selected. Only one landmark + // info panel can be shown at a time. + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Teleport To Landmark")); + } hide_context_entries(menu, items, disabled_items); +} +// Convenience function for the two functions below. +void teleport_via_landmark(const LLUUID& asset_id, const LLUUID& item_id) +{ + gAgent.teleportViaLandmark( asset_id ); + + // we now automatically track the landmark you're teleporting to + // because you'll probably arrive at a telehub instead + LLFloaterWorldMap* floater_world_map = gFloaterWorldMap; + if( floater_world_map ) + { + //Emerald says this needs to be the item id instead of the asset ID. -HgB + floater_world_map->trackLandmark( item_id ); + } } // virtual -void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLLandmarkBridge::performAction(LLInventoryModel* model, std::string action) { if ("teleport" == action) { LLViewerInventoryItem* item = getItem(); if(item) { - gAgent.teleportViaLandmark(item->getAssetUUID()); - - // we now automatically track the landmark you're teleporting to - // because you'll probably arrive at a telehub instead - if( gFloaterWorldMap ) - { - //Emerald claims this needs to be the item UUID, rather than the asset UUID. -HgB - gFloaterWorldMap->trackLandmark( item->getUUID() ); - } + teleport_via_landmark(item->getAssetUUID(), item->getUUID()); } } - if ("about" == action) + else if ("about" == action) { LLViewerInventoryItem* item = getItem(); if(item) @@ -3256,7 +3644,10 @@ void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* mod open_landmark(item, std::string(" ") + getPrefix() + item->getName(), FALSE); } } - else LLItemBridge::performAction(folder, model, action); + else + { + LLItemBridge::performAction(model, action); + } } void open_landmark(LLViewerInventoryItem* inv_item, @@ -3295,16 +3686,7 @@ static bool open_landmark_callback(const LLSD& notification, const LLSD& respons LLUUID item_id = notification["payload"]["item_id"].asUUID(); if (option == 0) { - // HACK: This is to demonstrate teleport on double click for landmarks - gAgent.teleportViaLandmark( asset_id ); - - // we now automatically track the landmark you're teleporting to - // because you'll probably arrive at a telehub instead - if( gFloaterWorldMap ) - { - //Emerald says this needs to be the item id instead of the asset ID. -HgB - gFloaterWorldMap->trackLandmark( item_id ); - } + teleport_via_landmark( asset_id, item_id ); } return false; @@ -3349,9 +3731,9 @@ protected: // +=================================================+ LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid ) : - LLItemBridge(inventory, /*root,*/ uuid) + LLItemBridge(inventory, root, uuid) { mObserver = new LLCallingCardObserver(this); LLAvatarTracker::instance().addObserver(mObserver); @@ -3365,7 +3747,8 @@ LLCallingCardBridge::~LLCallingCardBridge() void LLCallingCardBridge::refreshFolderViewItem() { - LLFolderViewItem* itemp = mInventoryPanel ? mInventoryPanel->getRootFolder()->getItemByID(mUUID) : NULL; + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL; if (itemp) { itemp->refresh(); @@ -3373,7 +3756,7 @@ void LLCallingCardBridge::refreshFolderViewItem() } // virtual -void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string action) { if ("begin_im" == action) { @@ -3394,7 +3777,7 @@ void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* handle_lure(item->getCreatorUUID()); } } - else LLItemBridge::performAction(folder, model, action); + else LLItemBridge::performAction(model, action); } LLUIImagePtr LLCallingCardBridge::getIcon() const @@ -3488,16 +3871,17 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, // check the type switch(cargo_type) { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_CLOTHING: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_LANDMARK: + case DAD_SCRIPT: + case DAD_CLOTHING: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: + case DAD_MESH: { LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; const LLPermissions& perm = inv_item->getPermissions(); @@ -3644,7 +4028,9 @@ std::string LLGestureBridge::getLabelSuffix() const { if( LLGestureMgr::instance().isGestureActive(mUUID) ) { - return LLItemBridge::getLabelSuffix() + " (active)"; + LLStringUtil::format_map_t args; + args["[GESLABEL]"] = LLItemBridge::getLabelSuffix(); + return LLTrans::getString("ActiveGesture", args); } else { @@ -3653,9 +4039,9 @@ std::string LLGestureBridge::getLabelSuffix() const } // virtual -void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLGestureBridge::performAction(LLInventoryModel* model, std::string action) { - if ("activate" == action) + if (isAddAction(action)) { LLGestureMgr::instance().activateGesture(mUUID); @@ -3667,7 +4053,7 @@ void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* mode gInventory.updateItem(item); gInventory.notifyObservers(); } - else if ("deactivate" == action) + else if (isRemoveAction(action)) { LLGestureMgr::instance().deactivateGesture(mUUID); @@ -3679,7 +4065,27 @@ void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* mode gInventory.updateItem(item); gInventory.notifyObservers(); } - else LLItemBridge::performAction(folder, model, action); + else if("play" == action) + { + if(!LLGestureMgr::instance().isGestureActive(mUUID)) + { + // we need to inform server about gesture activating to be consistent with LLPreviewGesture and LLGestureComboList. + BOOL inform_server = TRUE; + BOOL deactivate_similar = FALSE; + LLGestureMgr::instance().setGestureLoadedCallback(mUUID, boost::bind(&LLGestureBridge::playGesture, mUUID)); + LLViewerInventoryItem* item = gInventory.getItem(mUUID); + llassert(item); + if (item) + { + LLGestureMgr::instance().activateGestureWithAsset(mUUID, item->getAssetUUID(), inform_server, deactivate_similar); + } + } + else + { + playGesture(mUUID); + } + } + else LLItemBridge::performAction(model, action); } void LLGestureBridge::openItem() @@ -3757,6 +4163,20 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } +// static +void LLGestureBridge::playGesture(const LLUUID& item_id) +{ + if (LLGestureMgr::instance().isGesturePlaying(item_id)) + { + LLGestureMgr::instance().stopGesture(item_id); + } + else + { + LLGestureMgr::instance().playGesture(item_id); + } +} + + // +=================================================+ // | LLAnimationBridge | // +=================================================+ @@ -3789,7 +4209,7 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } // virtual -void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLAnimationBridge::performAction(LLInventoryModel* model, std::string action) { if ((action == "playworld") || (action == "playlocal")) { @@ -3801,8 +4221,8 @@ void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* mo if( item ) { S32 activate = 0; - if ("playworld" == action) activate = 1; - if ("playlocal" == action) activate = 2; + if ("playworld" == action) activate = 1; + if ("playlocal" == action) activate = 2; S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); @@ -3819,7 +4239,7 @@ void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* mo } else { - LLItemBridge::performAction(folder, model, action); + LLItemBridge::performAction(model, action); } } @@ -3829,9 +4249,9 @@ void LLAnimationBridge::openItem() if(LLPreview::show( mUUID )) return; - LLViewerInventoryItem* item = getItem(); - if( item ) - { + LLViewerInventoryItem* item = getItem(); + if( item ) + { S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); LLRect rect = gSavedSettings.getRect("PreviewAnimRect"); @@ -3841,11 +4261,11 @@ void LLAnimationBridge::openItem() getPrefix() + item->getName(), mUUID, 0); - preview->setFocus(TRUE); - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); - } + preview->setFocus(TRUE); + // Force to be entirely onscreen. + gFloaterView->adjustToFitScreen(preview, FALSE); } +} // +=================================================+ // | LLObjectBridge | @@ -3855,42 +4275,17 @@ void LLAnimationBridge::openItem() LLUUID LLObjectBridge::sContextMenuItemID; LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory, + LLFolderView* root, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : - LLItemBridge(inventory, uuid) + LLItemBridge(inventory, root, uuid) { mAttachPt = (flags & 0xff); // low bye of inventory flags mIsMultiObject = ( flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; mInvType = type; } -BOOL LLObjectBridge::isItemRemovable() -{ - LLInventoryModel* model = mInventoryPanel->getModel(); - if (!model) - { - return FALSE; - } -// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g - if ( (rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveItem(mUUID)) ) - { - return FALSE; - } -// [/RLVa:KB] - const LLInventoryObject *obj = model->getItem(mUUID); - if (obj && obj->getIsLinkType()) - { - return TRUE; - } - // - //LLVOAvatar* avatar = gAgentAvatarp; - //if(!avatar) return FALSE; - //if(avatar->isWearingAttachment(mUUID)) return FALSE; - // - return LLInvFVBridge::isItemRemovable(); -} - LLUIImagePtr LLObjectBridge::getIcon() const { return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject ); @@ -3908,22 +4303,21 @@ LLInventoryObject* LLObjectBridge::getObject() const } // virtual -void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) { - if ("attach" == action || "wear_add" == action) + if (isAddAction(action)) { - bool replace = ("attach" == action); // Replace if "Wear"ing. LLUUID object_id = mUUID; LLViewerInventoryItem* item; item = (LLViewerInventoryItem*)gInventory.getItem(object_id); if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID())) { - rez_attachment(item, NULL, replace); + rez_attachment(item, NULL, true); } - else if(item && item->isComplete()) + else if(item && item->isFinished()) { // must be in library. copy it to our inventory and put it on. - LLPointer cb = new RezAttachmentCallback(0, replace); + LLPointer cb = new RezAttachmentCallback(0); copy_inventory_item( gAgent.getID(), item->getPermissions().getOwner(), @@ -3934,12 +4328,16 @@ void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model } gFocusMgr.setKeyboardFocus(NULL); } - else if ("detach" == action) + else if ("wear_add" == action) + { + LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding. + } + else if (isRemoveAction(action)) { LLInventoryItem* item = gInventory.getItem(mUUID); if(item) { - LLVOAvatar::detachAttachmentIntoInventory(item->getLinkedUUID()); + LLVOAvatarSelf::detachAttachmentIntoInventory(item->getLinkedUUID()); } } else if ("edit" == action) @@ -3991,84 +4389,63 @@ void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model // Could be first use LLFirstUse::useBuild(); } - else LLItemBridge::performAction(folder, model, action); + else LLItemBridge::performAction(model, action); } void LLObjectBridge::openItem() { - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) - { - return; - } - if (avatar->isWearingAttachment(mUUID)) - { -// [RLVa:KB] - if ( !(rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(getItem()))) - performAction(NULL, NULL, "detach"); -// [/RLVa:KB] - } - else - { - performAction(NULL, NULL, "attach"); - } + // object double-click action is to wear/unwear object + performAction(getInventoryModel(), + get_is_item_worn(mUUID) ? "detach" : "attach"); } std::string LLObjectBridge::getLabelSuffix() const { - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar && avatar->isWearingAttachment( mUUID ) ) + if (get_is_item_worn(mUUID)) { - std::string attachment_point_name = avatar->getAttachedPointName(mUUID); - LLStringUtil::toLower(attachment_point_name); - LLViewerObject* pObj = (rlv_handler_t::isEnabled()) ? avatar->getWornAttachment( mUUID ) : NULL; -// [RLVa:KB] - if ( pObj && (gRlvAttachmentLocks.isLockedAttachment(pObj) || - gRlvAttachmentLocks.isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pObj),RLV_LOCK_REMOVE))) + if (!isAgentAvatarValid()) // Error condition, can't figure out attach point { - return LLItemBridge::getLabelSuffix() + std::string(" (locked to ") + attachment_point_name + std::string(")"); + return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); } -// [/RLVa:KB] - return LLItemBridge::getLabelSuffix() + std::string(" (worn on ") + attachment_point_name + std::string(")"); - } - else - { - // testzone attachpt - if(avatar) + std::string attachment_point_name = gAgentAvatarp->getAttachedPointName(mUUID); + if (attachment_point_name == LLStringUtil::null) // Error condition, invalid attach point { - std::map >::iterator iter = avatar->mUnsupportedAttachmentPoints.begin(); - std::map >::iterator end = avatar->mUnsupportedAttachmentPoints.end(); + attachment_point_name = "Invalid Attachment"; + std::map >::iterator iter = gAgentAvatarp->mUnsupportedAttachmentPoints.begin(); + std::map >::iterator end = gAgentAvatarp->mUnsupportedAttachmentPoints.end(); for( ; iter != end; ++iter) + { if((*iter).second.first == mUUID) { -// [RLVa:KB] - LLViewerObject* pObj = (rlv_handler_t::isEnabled()) ? gObjectList.findObject((*iter).second.second) : NULL; - if ( pObj && (gRlvAttachmentLocks.isLockedAttachment(pObj) || - gRlvAttachmentLocks.isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pObj),RLV_LOCK_REMOVE))) - { - return LLItemBridge::getLabelSuffix() + std::string(" (locked to unsupported point %d)", (*iter).first); - } -// [/RLVa:KB] - return LLItemBridge::getLabelSuffix() + llformat(" (worn on unsupported point %d)", (*iter).first); + attachment_point_name = llformat("unsupported point %d)", (*iter).first); } + } } - // - return LLItemBridge::getLabelSuffix(); + // e.g. "(worn on ...)" / "(attached to ...)" + LLStringUtil::format_map_t args; + args["[ATTACHMENT_POINT]"] = attachment_point_name; + + return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args); } + return LLItemBridge::getLabelSuffix(); } void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) { -// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Added: RLVa-1.2.1a - // If no attachment point was specified, try looking it up from the item name - if ( (rlv_handler_t::isEnabled()) && (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + const LLUUID& item_id = item->getLinkedUUID(); + + // Check for duplicate request. + if (isAgentAvatarValid() && + (gAgentAvatarp->attachmentWasRequested(item_id) || + gAgentAvatarp->isWearingAttachment(item_id))) { - attachment = RlvAttachPtLookup::getAttachPoint(item); + llwarns << "duplicate attachment request, ignoring" << llendl; + return; } -// [/RLVa:KB] + gAgentAvatarp->addAttachmentRequest(item_id); S32 attach_pt = 0; - if (gAgentAvatarp && attachment) + if (isAgentAvatarValid() && attachment) { for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) @@ -4082,31 +4459,22 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach } LLSD payload; - payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link. + payload["item_id"] = item_id; // Wear the base object in case this is a link. payload["attachment_point"] = attach_pt; payload["is_add"] = !replace; - if (replace && attachment && attachment->getNumObjects() > 0) + if (replace && + (attachment && attachment->getNumObjects() > 0)) { -// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a - // Block if we can't "replace wear" what's currently there - if ( (rlv_handler_t::isEnabled()) && ((gRlvAttachmentLocks.canAttach(attachment) & RLV_WEAR_REPLACE) == 0) ) - return; -// [/RLVa:KB] - LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); + LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez); } else { -// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i - // Block wearing anything on a non-attachable attachment point - if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachmentPoint(attach_pt, RLV_LOCK_ADD)) ) - return; -// [/RLVa:KB] LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); } } -bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response) +bool confirm_attachment_rez(const LLSD& notification, const LLSD& response) { if (!gAgentAvatarp->canAttachMoreObjects()) { @@ -4124,22 +4492,44 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon if (itemp) { + /* + { + U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); + msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); + msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); + pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); + msg->addStringFast(_PREHASH_Name, itemp->getName()); + msg->addStringFast(_PREHASH_Description, itemp->getDescription()); + msg->sendReliable(gAgent.getRegion()->getHost()); + return false; + } + */ + // Queue up attachments to be sent in next idle tick, this way the // attachments are batched up all into one message versus each attachment // being sent in its own separate attachments message. U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); BOOL is_add = notification["payload"]["is_add"].asBoolean(); - LLAttachmentsMgr::instance().addAttachment(item_id, attachment_pt, is_add); + LLAttachmentsMgr::instance().addAttachment(item_id, + attachment_pt, + is_add); } } return false; } -LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_replace_attachment_rez); +static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_attachment_rez); void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - // *TODO: Translate menuentry_vec_t items; menuentry_vec_t disabled_items; if(isItemInTrash()) @@ -4158,16 +4548,11 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) LLInventoryItem* item = getItem(); if(item) { - LLVOAvatar *avatarp = gAgentAvatarp; - if( !avatarp ) - { - return; - } - + if (!isAgentAvatarValid()) return; if( get_is_item_worn( mUUID ) ) { - items.push_back(std::string("Attach Separator")); + items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Detach From Yourself")); items.push_back(std::string("Wearable Edit")); // [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a | OK @@ -4177,31 +4562,26 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else // testzone attachpt - if( avatarp->isWearingUnsupportedAttachment( mUUID ) ) + if( gAgentAvatarp->isWearingUnsupportedAttachment( mUUID ) ) { items.push_back(std::string("Detach From Yourself")); } - else // - if( !isItemInTrash() ) + else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder()) { - items.push_back(std::string("Attach Separator")); - items.push_back(std::string("Object Wear")); - if (gHippoGridManager->getConnectedGrid()->supportsInvLinks()) - items.push_back(std::string("Object Add")); - if (!avatarp->canAttachMoreObjects()) - { - disabled_items.push_back(std::string("Object Add")); - } + items.push_back(std::string("Wearable And Object Separator")); + items.push_back(std::string("Wearable And Object Wear")); + if (InventoryLinksEnabled()) + items.push_back(std::string("Wearable Add")); items.push_back(std::string("Attach To")); items.push_back(std::string("Attach To HUD")); // commented out for DEV-32347 - AND Commented back in for non-morons. -HgB items.push_back(std::string("Restore to Last Position")); - if (!avatarp->canAttachMoreObjects()) + if (!gAgentAvatarp->canAttachMoreObjects()) { - disabled_items.push_back(std::string("Object Wear")); - disabled_items.push_back(std::string("Object Add")); + disabled_items.push_back(std::string("Wearable And Object Wear")); + disabled_items.push_back(std::string("Wearable Add")); disabled_items.push_back(std::string("Attach To")); disabled_items.push_back(std::string("Attach To HUD")); } @@ -4222,10 +4602,10 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) && (attach_menu->getChildCount() == 0) && attach_hud_menu && (attach_hud_menu->getChildCount() == 0) - && avatarp) + && isAgentAvatarValid()) { - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end(); ) + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; @@ -4344,632 +4724,29 @@ void LLLSLTextBridge::openItem() // +=================================================+ LLWearableBridge::LLWearableBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid, LLAssetType::EType asset_type, LLInventoryType::EType inv_type, - LLWearableType::EType wearable_type) : - LLItemBridge(inventory, /*root,*/ uuid), + LLWearableType::EType wearable_type) : + LLItemBridge(inventory, root, uuid), mAssetType( asset_type ), mWearableType(wearable_type) { mInvType = inv_type; } -// *NOTE: hack to get from avatar inventory to avatar -void wear_inventory_item_on_avatar( LLInventoryItem* item ) -{ - if(item) - { - lldebugs << "wear_inventory_item_on_avatar( " << item->getName() - << " )" << llendl; - - LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - LLWearableBridge::onWearOnAvatarArrived, - new LLUUID(item->getLinkedUUID())); - } -} - -// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i -// Moved to llinventorybridge.h because we need it in RlvForceWearLegacy -/* -struct LLFoundData -{ - LLFoundData(const LLUUID& item_id, - const LLUUID& asset_id, - const std::string& name, - LLAssetType::EType asset_type) : - mItemID(item_id), - mAssetID(asset_id), - mName(name), - mAssetType(asset_type), - mWearable( NULL ) {} - - LLUUID mItemID; - LLUUID mAssetID; - std::string mName; - LLAssetType::EType mAssetType; - LLWearable* mWearable; -}; - -struct LLWearableHoldingPattern -{ - LLWearableHoldingPattern() : mResolved(0) {} - ~LLWearableHoldingPattern() - { - for_each(mFoundList.begin(), mFoundList.end(), DeletePointer()); - mFoundList.clear(); - } - typedef std::list found_list_t; - found_list_t mFoundList; - S32 mResolved; -}; - -*/ -// [/RLVa:KB] - -class LLOutfitObserver : public LLInventoryFetchItemsObserver -{ -public: - LLOutfitObserver(const uuid_vec_t& ids, const LLUUID& cat_id, bool copy_items, bool append) : - LLInventoryFetchItemsObserver(ids), - mCatID(cat_id), - mCopyItems(copy_items), - mAppend(append) - {} - ~LLOutfitObserver() {} - virtual void done(); //public - -protected: - LLUUID mCatID; - bool mCopyItems; - bool mAppend; -}; - - -class LLWearInventoryCategoryCallback : public LLInventoryCallback -{ -public: - LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append) - { - mCatID = cat_id; - mAppend = append; - } - void fire(const LLUUID& item_id) - { - /* - * Do nothing. We only care about the destructor - * - * The reason for this is that this callback is used in a hack where the - * same callback is given to dozens of items, and the destructor is called - * after the last item has fired the event and dereferenced it -- if all - * the events actually fire! - */ - } - -protected: - ~LLWearInventoryCategoryCallback() - { - // Is the destructor called by ordinary dereference, or because the app's shutting down? - // If the inventory callback manager goes away, we're shutting down, no longer want the callback. - if( LLInventoryCallbackManager::is_instantiated() ) - { - wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend); - } - else - { - llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl; - } - } - -private: - LLUUID mCatID; - bool mAppend; -}; - -void LLOutfitObserver::done() -{ - // We now have an outfit ready to be copied to agent inventory. Do - // it, and wear that outfit normally. - if(mCopyItems) - { - LLInventoryCategory* cat = gInventory.getCategory(mCatID); - std::string name; - if(!cat) - { - // should never happen. - name = "New Outfit"; - } - else - { - name = cat->getName(); - } - LLViewerInventoryItem* item = NULL; - uuid_vec_t::iterator it = mComplete.begin(); - uuid_vec_t::iterator end = mComplete.end(); - LLUUID pid; - for(; it < end; ++it) - { - item = (LLViewerInventoryItem*)gInventory.getItem(*it); - if(item) - { - if(LLInventoryType::IT_GESTURE == item->getInventoryType()) - { - pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); - } - else - { - pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); - } - break; - } - } - if(pid.isNull()) - { - pid = gInventory.getRootFolderID(); - } - - LLUUID cat_id = gInventory.createNewCategory( - pid, - LLFolderType::FT_NONE, - name); - mCatID = cat_id; - LLPointer cb = new LLWearInventoryCategoryCallback(mCatID, mAppend); - it = mComplete.begin(); - for(; it < end; ++it) - { - item = (LLViewerInventoryItem*)gInventory.getItem(*it); - if(item) - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - cat_id, - std::string(), - cb); - } - } - } - else - { - // Wear the inventory category. - wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend); - } -} - -class LLOutfitFetch : public LLInventoryFetchDescendentsObserver -{ -public: - LLOutfitFetch(const LLUUID& id, bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {} - ~LLOutfitFetch() {} - virtual void done(); -protected: - bool mCopyItems; - bool mAppend; -}; - -void LLOutfitFetch::done() -{ - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mComplete.front(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - S32 count = item_array.count(); - if(!count) - { - llwarns << "Nothing fetched in category " << mComplete.front() - << llendl; - dec_busy_count(); - gInventory.removeObserver(this); - delete this; - return; - } - - uuid_vec_t ids; - for(S32 i = 0; i < count; ++i) - { - ids.push_back(item_array.get(i)->getUUID()); - } - - LLOutfitObserver* outfit = new LLOutfitObserver(ids, mComplete.front(), mCopyItems, mAppend); - - - // clean up, and remove this as an observer since the call to the - // outfit could notify observers and throw us into an infinite - // loop. - dec_busy_count(); - gInventory.removeObserver(this); - delete this; - - // increment busy count and either tell the inventory to check & - // call done, or add this object to the inventory for observation. - inc_busy_count(); - - // do the fetch - outfit->startFetch(); - if(outfit->isFinished()) - { - // everything is already here - call done. - outfit->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - } -} - -void wear_outfit_by_name(const std::string& name) -{ - llinfos << "Wearing category " << name << llendl; - inc_busy_count(); - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLNameCategoryCollector has_name(name); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - bool copy_items = false; - LLInventoryCategory* cat = NULL; - if (cat_array.count() > 0) - { - // Just wear the first one that matches - cat = cat_array.get(0); - } - else - { - gInventory.collectDescendentsIf(LLUUID::null, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - if(cat_array.count() > 0) - { - cat = cat_array.get(0); - copy_items = true; - } - } - - if(cat) - { - wear_inventory_category(cat, copy_items, false); - } - else - { - llwarns << "Couldn't find outfit " <getName() - << " )" << llendl; - // What we do here is get the complete information on the items in - // the inventory, and set up an observer that will wait for that to - // happen. - LLOutfitFetch* outfit = new LLOutfitFetch(category->getUUID(), copy, append); - outfit->startFetch(); - inc_busy_count(); - if(outfit->isFinished()) - { - // everything is already here - call done. - outfit->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - } -} - -// *NOTE: hack to get from avatar inventory to avatar -void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append, BOOL replace) -{ - // Avoid unintentionally overwriting old wearables. We have to do - // this up front to avoid having to deal with the case of multiple - // wearables being dirty. - if(!category) return; - lldebugs << "wear_inventory_category_on_avatar( " << category->getName() - << " )" << llendl; - - LLWearInfo wear_info; - wear_info.mAppend = append; - wear_info.mReplace = replace; - wear_info.mCategoryID = category->getUUID(); - - if( gFloaterCustomize ) - { - gFloaterCustomize->askToSaveIfDirty( - boost::bind(wear_inventory_category_on_avatar_step2,_1,wear_info)); - } - else - { - wear_inventory_category_on_avatar_step2( - TRUE, - wear_info ); - } -} - - -void wear_inventory_category_on_avatar_step2( BOOL proceed, const LLWearInfo wear_info ) -{ - // Find all the wearables that are in the category's subtree. - lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl; - if(proceed) - { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(wear_info.mCategoryID, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_wearable); - S32 i; - S32 wearable_count = item_array.count(); - - LLInventoryModel::item_array_t obj_items_new; - LLCOFMgr::getDescendentsOfAssetType(wear_info.mCategoryID, obj_items_new, LLAssetType::AT_OBJECT, false); - S32 obj_count = obj_items_new.count(); - - // Find all gestures in this folder - LLInventoryModel::cat_array_t gest_cat_array; - LLInventoryModel::item_array_t gest_item_array; - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(wear_info.mCategoryID, - gest_cat_array, - gest_item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_gesture); - S32 gest_count = gest_item_array.count(); - - if( !wearable_count && !obj_count && !gest_count) - { - LLNotificationsUtil::add("CouldNotPutOnOutfit"); - return; - } - - // Processes that take time should show the busy cursor - if (wearable_count > 0 || obj_count > 0) - { - inc_busy_count(); - } - - // Activate all gestures in this folder - if (gest_count > 0) - { - llinfos << "Activating " << gest_count << " gestures" << llendl; - - LLGestureMgr::instance().activateGestures(gest_item_array); - - // Update the inventory item labels to reflect the fact - // they are active. - LLViewerInventoryCategory* catp = gInventory.getCategory(wear_info.mCategoryID); - if (catp) - { - gInventory.updateCategory(catp); - gInventory.notifyObservers(); - } - } - - if(wearable_count > 0) - { - // Note: can't do normal iteration, because if all the - // wearables can be resolved immediately, then the - // callback will be called (and this object deleted) - // before the final getNextData(). -// LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; -// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i - LLWearableHoldingPattern* holder = new LLWearableHoldingPattern(wear_info.mAppend); -// [/RLVa:KB] - LLFoundData* found; - LLDynamicArray found_container; - for(i = 0; i < wearable_count; ++i) - { - found = new LLFoundData(item_array.get(i)->getLinkedUUID(), - item_array.get(i)->getAssetUUID(), - item_array.get(i)->getName(), - item_array.get(i)->getType()); - holder->mFoundList.push_front(found); - found_container.put(found); - } - for(i = 0; i < wearable_count; ++i) - { -// [RLVa:KB] - Part of LLWearableHoldingPattern -// gAddToOutfit = wear_info->mAppend; -// [/RLVa:KB] - - found = found_container.get(i); - LLWearableList::instance().getAsset(found->mAssetID, - found->mName, - found->mAssetType, - wear_inventory_category_on_avatar_loop, - (void*)holder); - } - } - - const LLUUID idCOF = LLCOFMgr::instance().getCOF(); - - // - // - Attachments: include COF contents only if appending. - // - if (!wear_info.mReplace) - { - LLInventoryModel::item_array_t obj_items; - if (wear_info.mAppend) - LLCOFMgr::getDescendentsOfAssetType(idCOF, obj_items, LLAssetType::AT_OBJECT, false); -// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b - else if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) - { - // Make sure that all currently locked attachments remain in COF when replacing - LLCOFMgr::getDescendentsOfAssetType(idCOF, obj_items, LLAssetType::AT_OBJECT, false); - obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), rlvPredCanRemoveItem), obj_items.end()); - } -// [/RLVa:KB] -// getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); -// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b - // Filter out any new attachments that can't be worn before adding them - if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) - obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), - RlvPredCanNotWearItem(RLV_WEAR_ADD)), obj_items_new.end()); - for (S32 idxObjNew = 0; idxObjNew < obj_items_new.count(); idxObjNew++) - RlvAttachmentLockWatchdog::instance().onWearAttachment(obj_items_new.get(idxObjNew).get() , RLV_WEAR_ADD); - obj_items.insert(obj_items.end(), obj_items_new.begin(), obj_items_new.end()); -// [/RLVa:KB] - - LLAgentWearables::userUpdateAttachments(obj_items); - } - else - { - for (S32 idxItem = 0, cntItem = obj_items_new.count(); idxItem < cntItem; idxItem++) - { - LLInventoryItem* pItem = obj_items_new.get(idxItem); - -// [RLVa:KB] - Checked: 2010-11-21 (RLVa-1.1.3c) | Added: RLVa-1.1.3c - if ( (rlv_handler_t::isEnabled()) && (!(RLV_WEAR_REPLACE & gRlvAttachmentLocks.canAttach(pItem))) ) - continue; -// [/RLVa:KB] - - LLAttachmentsMgr::instance().addAttachment(pItem->getLinkedUUID(), 0, false); - } - } - - if (!wear_info.mAppend) - LLCOFMgr::instance().addBOFLink(wear_info.mCategoryID); - } -} - -void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void* data) -{ - LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; -// [RLVa:KB] - Part of LLWearableHoldingPattern -// BOOL append= gAddToOutfit; -// [/RLVa:KB] - - - - if(wearable) - { - for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); - iter != holder->mFoundList.end(); ++iter) - { - LLFoundData* data = *iter; - if(wearable->getAssetID() == data->mAssetID) - { - data->mWearable = wearable; - break; - } - } - } - holder->mResolved += 1; - if(holder->mResolved >= (S32)holder->mFoundList.size()) - { -// wear_inventory_category_on_avatar_step3(holder, append); -// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i - wear_inventory_category_on_avatar_step3(holder, holder->mAddToOutfit); -// [/RLVa:KB] - } -} - - - - -void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append) -{ - lldebugs << "wear_inventory_category_on_avatar_step3()" << llendl; - LLInventoryItem::item_array_t items; - LLDynamicArray< LLWearable* > wearables; - - // For each wearable type, find the first instance in the category - // that we recursed through. - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) - { - for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); - iter != holder->mFoundList.end(); ++iter) - { - LLFoundData* data = *iter; - LLWearable* wearable = data->mWearable; - if( wearable && ((S32)wearable->getType() == i) ) - { - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getLinkedItem(data->mItemID); - if( item && (item->getAssetUUID() == wearable->getAssetID()) ) - { - //RN: after discussing with Brashears, I disabled this code - //Metadata should reside in the item, not the asset - //And this code does not handle failed asset uploads properly -// if(!wearable->isMatchedToInventoryItem(item )) -// { -// wearable = LLWearableList::instance().createWearableMatchedToInventoryItem( wearable, item ); -// // Now that we have an asset that matches the -// // item, update the item to point to the new -// // asset. -// item->setAssetUUID(wearable->getID()); -// item->updateAssetOnServer(); -// } -// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.4a - if (!gRlvWearableLocks.canWear(item)) - { - continue; - } -// [/RLVa:KB] - items.put(item); - wearables.put(wearable); - } - break; - } - } - } - - if(wearables.count() > 0) - { - gAgentWearables.setWearableOutfit(items, wearables, !append); - gInventory.notifyObservers(); - } - - delete holder; - - dec_busy_count(); -} - void remove_inventory_category_from_avatar( LLInventoryCategory* category ) { if(!category) return; lldebugs << "remove_inventory_category_from_avatar( " << category->getName() << " )" << llendl; - - - LLUUID* uuid = new LLUUID(category->getUUID()); - - if( gFloaterCustomize ) + if (gAgentCamera.cameraCustomizeAvatar()) { - gFloaterCustomize->askToSaveIfDirty( - boost::bind(remove_inventory_category_from_avatar_step2,_1,uuid)); + gFloaterCustomize->askToSaveIfDirty(boost::bind(&remove_inventory_category_from_avatar_step2,_1,category->getUUID())); } else - { - remove_inventory_category_from_avatar_step2( - TRUE, - uuid ); - } + remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() ); } struct OnRemoveStruct @@ -4981,19 +4758,17 @@ struct OnRemoveStruct } }; -void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) +void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id) { // Find all the wearables that are in the category's subtree. - LLUUID* category_id = (LLUUID *)userdata; - lldebugs << "remove_inventory_category_from_avatar_step2()" << llendl; if(proceed) { LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; LLFindWearables is_wearable; - gInventory.collectDescendentsIf(*category_id, + gInventory.collectDescendentsIf(category_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -5004,7 +4779,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) LLInventoryModel::cat_array_t obj_cat_array; LLInventoryModel::item_array_t obj_item_array; LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(*category_id, + gInventory.collectDescendentsIf(category_id, obj_cat_array, obj_item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -5015,7 +4790,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) LLInventoryModel::cat_array_t gest_cat_array; LLInventoryModel::item_array_t gest_item_array; LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(*category_id, + gInventory.collectDescendentsIf(category_id, gest_cat_array, gest_item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -5027,13 +4802,14 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) for(i = 0; i < wearable_count; ++i) { LLViewerInventoryItem *item = item_array.get(i); -// if( gAgentWearables.isWearingItem (item_array.get(i)->getUUID()) ) -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.1.3b) | Modified: RLVa-0.2.2a - LLWearable* pWearable = gAgentWearables.getWearableFromItemID(item_array.get(i)->getLinkedUUID()); - if ( (pWearable) && ( (!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(pWearable->getType())) ) ) -// [/RLVa:KB] + if (item->getType() == LLAssetType::AT_BODYPART) + continue; + if (gAgent.isTeen() && item->isWearableType() && + (item->getWearableType() == LLWearableType::WT_UNDERPANTS || item->getWearableType() == LLWearableType::WT_UNDERSHIRT)) + continue; + if (get_is_item_worn(item->getUUID())) { - LLWearableList::instance().getAsset( item->getAssetUUID(), + LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), LLWearableBridge::onRemoveFromAvatarArrived, @@ -5049,7 +4825,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) LLViewerInventoryItem *obj_item = obj_item_array.get(i); if (get_is_item_worn(obj_item->getUUID())) { - LLVOAvatar::detachAttachmentIntoInventory(obj_item->getLinkedUUID()); + LLVOAvatarSelf::detachAttachmentIntoInventory(obj_item->getLinkedUUID()); } } } @@ -5061,7 +4837,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) LLViewerInventoryItem *gest_item = gest_item_array.get(i); if (get_is_item_worn(gest_item->getUUID())) { - LLGestureMgr::instance().deactivateGesture( gest_item_array.get(i)->getLinkedUUID() ); + LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); gInventory.updateItem( gest_item ); gInventory.notifyObservers(); } @@ -5069,58 +4845,26 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) } } } - delete category_id; - category_id = NULL; } BOOL LLWearableBridge::renameItem(const std::string& new_name) { - if (get_is_item_worn(getItem())) + if (get_is_item_worn(mUUID)) { gAgentWearables.setWearableName( mUUID, new_name ); } return LLItemBridge::renameItem(new_name); } -BOOL LLWearableBridge::isItemRemovable() -{ - LLInventoryModel* model = mInventoryPanel->getModel(); - if (!model) - { - return FALSE; - } -// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g - if ( (rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveItem(mUUID)) ) - { - return FALSE; - } -// [/RLVa:KB] -// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g - if ( (rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveItem(mUUID)) ) - { - return FALSE; - } -// [/RLVa:KB] - const LLInventoryObject *obj = model->getItem(mUUID); - if (obj && obj->getIsLinkType()) - { - return TRUE; - } - // - //if(gAgentWearables.isWearingItem(mUUID)) return FALSE; - // - return LLInvFVBridge::isItemRemovable(); -} - std::string LLWearableBridge::getLabelSuffix() const { - if (get_is_item_worn(getItem())) + if (get_is_item_worn(mUUID)) { if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(getItem())) ) { - return LLItemBridge::getLabelSuffix() + " (locked)"; + return LLItemBridge::getLabelSuffix() + LLTrans::getString("locked"); } - return LLItemBridge::getLabelSuffix() + " (worn)"; + return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); } else { @@ -5134,33 +4878,27 @@ LLUIImagePtr LLWearableBridge::getIcon() const } // virtual -void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLWearableBridge::performAction(LLInventoryModel* model, std::string action) { - if ("wear" == action) + if (isAddAction(action)) { wearOnAvatar(); } + else if ("wear_add" == action) + { + wearAddOnAvatar(); + } else if ("edit" == action) { editOnAvatar(); return; } - else if ("take_off" == action) + else if (isRemoveAction(action)) { - if(gAgentWearables.isWearingItem(mUUID)) - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - LLWearableBridge::onRemoveFromAvatarArrived, - new OnRemoveStruct(item->getLinkedUUID())); - } - } + removeFromAvatar(); + return; } - else LLItemBridge::performAction(folder, model, action); + else LLItemBridge::performAction(model, action); } void LLWearableBridge::openItem() @@ -5173,11 +4911,11 @@ void LLWearableBridge::openItem() { if (gAgentWearables.isWearingItem(mUUID)) { - performAction(NULL, NULL, "take_off"); + performAction(NULL, "take_off"); } else { - performAction(NULL, NULL, "wear"); + performAction(NULL, "wear"); } } else @@ -5226,6 +4964,10 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) can_open = (item->getType() != LLAssetType::AT_CLOTHING) && (item->getType() != LLAssetType::AT_BODYPART); } + if (isLinkedObjectMissing()) + { + can_open = FALSE; + } if (can_open) { addOpenRightClickMenuOption(items); @@ -5240,7 +4982,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) getClipboardEntries(true, items, disabled_items, flags); - items.push_back(std::string("Wearable Separator")); + items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Wearable Wear")); items.push_back(std::string("Wearable Edit")); @@ -5279,17 +5021,17 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) case LLAssetType::AT_BODYPART: if (get_is_item_worn(item->getUUID())) { - disabled_items.push_back(std::string("Wearable And Wear")); + disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Add")); } else { - items.push_back(std::string("Wearable Wear")); + items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Take Off")); disabled_items.push_back(std::string("Wearable Edit")); } - /*if (LLWearableType::getAllowMultiwear(mWearableType)) + if (LLWearableType::getAllowMultiwear(mWearableType)) { items.push_back(std::string("Wearable Add")); if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) @@ -5297,7 +5039,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Wearable Add")); } } - break;*/ + break; default: break; } @@ -5315,9 +5057,9 @@ BOOL LLWearableBridge::canWearOnAvatar(void* user_data) if(!self->isAgentInventory()) { LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); - if(!item || !item->isComplete()) return FALSE; + if(!item || !item->isFinished()) return FALSE; } - return (!get_is_item_worn(self->getItem())); + return (!get_is_item_worn(self->mUUID)); } // Called from menus @@ -5342,21 +5084,18 @@ void LLWearableBridge::wearOnAvatar() LLViewerInventoryItem* item = getItem(); if(item) { - if(!isAgentInventory()) - { - LLPointer cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_inventory_item_on_avatar(item); - } + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true); + } +} + +void LLWearableBridge::wearAddOnAvatar() +{ + // TODO: investigate wearables may not be loaded at this point EXT-8231 + + LLViewerInventoryItem* item = getItem(); + if(item) + { + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, false); } } @@ -5400,13 +5139,40 @@ void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userda delete item_id; } +// static +// BAP remove the "add" code path once everything is fully COF-ified. +void LLWearableBridge::onWearAddOnAvatarArrived( LLWearable* wearable, void* userdata ) +{ + LLUUID* item_id = (LLUUID*) userdata; + if(wearable) + { + LLViewerInventoryItem* item = NULL; + item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); + if(item) + { + if(item->getAssetUUID() == wearable->getAssetID()) + { + bool do_append = true; + gAgentWearables.setWearableItem(item, wearable, do_append); + gInventory.notifyObservers(); + //self->getFolderItem()->refreshFromRoot(); + } + else + { + llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; + } + } + } + delete item_id; +} + // static BOOL LLWearableBridge::canEditOnAvatar(void* user_data) { LLWearableBridge* self = (LLWearableBridge*)user_data; if(!self) return FALSE; - return (get_is_item_worn(self->getItem())); + return (get_is_item_worn(self->mUUID)); } // static @@ -5421,19 +5187,7 @@ void LLWearableBridge::onEditOnAvatar(void* user_data) void LLWearableBridge::editOnAvatar() { - LLUUID linked_id = gInventory.getLinkedItemID(mUUID); - LLWearable* wearable = gAgentWearables.getWearableFromItemID(linked_id); - if( wearable ) - { - // Set the tab to the right wearable. - LLFloaterCustomize::setCurrentWearableType( wearable->getType() ); - - if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() ) - { - // Start Avatar Customization - gAgentCamera.changeCameraToCustomizeAvatar(); - } - } + LLAgentWearables::editWearable(mUUID); } // static @@ -5442,7 +5196,7 @@ BOOL LLWearableBridge::canRemoveFromAvatar(void* user_data) LLWearableBridge* self = (LLWearableBridge*)user_data; if( self && (LLAssetType::AT_BODYPART != self->mAssetType) ) { - return get_is_item_worn(self->getItem()); + return get_is_item_worn( self->mUUID ); } return FALSE; } @@ -5452,16 +5206,17 @@ void LLWearableBridge::onRemoveFromAvatar(void* user_data) { LLWearableBridge* self = (LLWearableBridge*)user_data; if(!self) return; - if(get_is_item_worn(self->getItem())) + if(get_is_item_worn(self->mUUID)) { LLViewerInventoryItem* item = self->getItem(); if (item) { + LLUUID parent_id = item->getParentUUID(); LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - onRemoveFromAvatarArrived, - new OnRemoveStruct(LLUUID(self->mUUID))); + item->getName(), + item->getType(), + onRemoveFromAvatarArrived, + new OnRemoveStruct(LLUUID(self->mUUID))); } } } @@ -5479,16 +5234,66 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, LLWearableType::EType type = wearable->getType(); if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES) ) //&& - //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) + //!((!gAgent.isTeen()) && ( type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT )) ) { - gAgentWearables.removeWearable( type, false, 0 ); // TODO: MULTI-WEARABLE + bool do_remove_all = false; + U32 index = gAgentWearables.getWearableIndex(wearable); + gAgentWearables.removeWearable( type, do_remove_all, index ); } } } + + // Find and remove this item from the COF. + LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false); + gInventory.notifyObservers(); + delete on_remove_struct; } +// static +void LLWearableBridge::removeAllClothesFromAvatar() +{ + // Fetch worn clothes (i.e. the ones in COF). + LLInventoryModel::item_array_t clothing_items; + LLInventoryModel::cat_array_t dummy; + LLIsType is_clothing(LLAssetType::AT_CLOTHING); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), + dummy, + clothing_items, + LLInventoryModel::EXCLUDE_TRASH, + is_clothing, + false); + + // Take them off by removing from COF. + for (LLInventoryModel::item_array_t::const_iterator it = clothing_items.begin(); it != clothing_items.end(); ++it) + { + LLAppearanceMgr::instance().removeItemFromAvatar((*it)->getUUID()); + } +} + +// static +void LLWearableBridge::removeItemFromAvatar(LLViewerInventoryItem *item) +{ + if (item) + { + LLWearableList::instance().getAsset(item->getAssetUUID(), + item->getName(), + item->getType(), + LLWearableBridge::onRemoveFromAvatarArrived, + new OnRemoveStruct(item->getUUID())); + } +} + +void LLWearableBridge::removeFromAvatar() +{ + if (get_is_item_worn(mUUID)) + { + LLViewerInventoryItem* item = getItem(); + removeItemFromAvatar(item); + } +} + // +=================================================+ // | LLLinkItemBridge | // +=================================================+ @@ -5527,79 +5332,10 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Properties")); addDeleteContextMenuOptions(items, disabled_items); - } - hide_context_entries(menu, items, disabled_items); } - -// +=================================================+ -// | LLLinkBridge | -// +=================================================+ -// For broken folder links. -std::string LLLinkFolderBridge::sPrefix("Link: "); -LLUIImagePtr LLLinkFolderBridge::getIcon() const -{ - return LLUI::getUIImage("inv_link_folder.tga"); -} - -void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - // *TODO: Translate - lldebugs << "LLLink::buildContextMenu()" << llendl; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - if (isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Find Original")); - addDeleteContextMenuOptions(items, disabled_items); - } hide_context_entries(menu, items, disabled_items); } -void LLLinkFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("goto" == action) - { - gotoItem(folder); - return; - } - LLItemBridge::performAction(folder,model,action); -} - -void LLLinkFolderBridge::gotoItem(LLFolderView *folder) -{ - const LLUUID &cat_uuid = getFolderID(); - if (!cat_uuid.isNull()) - { - if (LLFolderViewItem *base_folder = folder->getItemByID(cat_uuid)) - { - if (LLInventoryModel* model = getInventoryModel()) - { - model->fetchDescendentsOf(cat_uuid); - } - base_folder->setOpen(TRUE); - folder->setSelectionFromRoot(base_folder,TRUE); - folder->scrollToShowSelection(); - } - } -} - -const LLUUID &LLLinkFolderBridge::getFolderID() const -{ - if (LLViewerInventoryItem *link_item = getItem()) - { - if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory()) - { - const LLUUID& cat_uuid = cat->getUUID(); - return cat_uuid; - } - } - return LLUUID::null; -} // +=================================================+ // | LLMeshBridge | @@ -5657,3 +5393,70 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } +// +=================================================+ +// | LLLinkBridge | +// +=================================================+ +// For broken folder links. +std::string LLLinkFolderBridge::sPrefix("Link: "); +LLUIImagePtr LLLinkFolderBridge::getIcon() const +{ + return LLUI::getUIImage("inv_link_folder.tga"); +} + +void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + // *TODO: Translate + lldebugs << "LLLink::buildContextMenu()" << llendl; + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + if (isItemInTrash()) + { + addTrashContextMenuOptions(items, disabled_items); + } + else + { + items.push_back(std::string("Find Original")); + addDeleteContextMenuOptions(items, disabled_items); + } + hide_context_entries(menu, items, disabled_items); +} +void LLLinkFolderBridge::performAction(LLInventoryModel* model, std::string action) +{ + if ("goto" == action) + { + gotoItem(); + return; + } + LLItemBridge::performAction(model,action); +} +void LLLinkFolderBridge::gotoItem() +{ + const LLUUID &cat_uuid = getFolderID(); + if (!cat_uuid.isNull()) + { + if (LLFolderViewItem *base_folder = mRoot->getItemByID(cat_uuid)) + { + if (LLInventoryModel* model = getInventoryModel()) + { + model->fetchDescendentsOf(cat_uuid); + } + base_folder->setOpen(TRUE); + mRoot->setSelectionFromRoot(base_folder,TRUE); + mRoot->scrollToShowSelection(); + } + } +} +const LLUUID &LLLinkFolderBridge::getFolderID() const +{ + if (LLViewerInventoryItem *link_item = getItem()) + { + if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory()) + { + const LLUUID& cat_uuid = cat->getUUID(); + return cat_uuid; + } + } + return LLUUID::null; +} + diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 381646b39..3b191498a 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -48,75 +48,9 @@ class LLMenuGL; class LLCallingCardObserver; class LLViewerJointAttachment; + typedef std::vector menuentry_vec_t; -struct LLAttachmentRezAction -{ - LLUUID mItemID; - S32 mAttachPt; -}; - -// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i -// Moved from llinventorybridge.cpp because we need it in RlvForceWearLegacy -struct LLFoundData -{ - LLFoundData(const LLUUID& item_id, - const LLUUID& asset_id, - const std::string& name, - LLAssetType::EType asset_type) : - mItemID(item_id), - mAssetID(asset_id), - mName(name), - mAssetType(asset_type), - mWearable( NULL ) {} - - LLUUID mItemID; - LLUUID mAssetID; - std::string mName; - LLAssetType::EType mAssetType; - LLWearable* mWearable; -}; - -struct LLWearableHoldingPattern -{ - LLWearableHoldingPattern(BOOL fAddToOutfit) : mResolved(0), mAddToOutfit(fAddToOutfit) {} - ~LLWearableHoldingPattern() - { - for_each(mFoundList.begin(), mFoundList.end(), DeletePointer()); - mFoundList.clear(); - } - typedef std::list found_list_t; - found_list_t mFoundList; - S32 mResolved; - BOOL mAddToOutfit; -}; -// [/RLVa:KB] - -//helper functions -class LLShowProps -{ -public: - - static void showProperties(const LLUUID& uuid) - { - if(!LLFloaterProperties::show(uuid, LLUUID::null)) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PropertiesRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - LLFloaterProperties* floater; - floater = new LLFloaterProperties("item properties", - rect, - "Inventory Item Properties", - uuid, - LLUUID::null); - // keep onscreen - gFloaterView->adjustToFitScreen(floater, FALSE); - } - } -}; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridge (& it's derived classes) // @@ -137,6 +71,7 @@ public: LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, LLInventoryPanel* inventory, + LLFolderView* root, const LLUUID& uuid, U32 flags = 0x00); virtual ~LLInvFVBridge() {} @@ -162,12 +97,13 @@ public: virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; } virtual std::string getLabelSuffix() const { return LLStringUtil::null; } virtual void openItem() {} + virtual void closeItem() {} virtual void previewItem() {openItem();} virtual void showProperties(); virtual BOOL isItemRenameable() const { return TRUE; } //virtual BOOL renameItem(const std::string& new_name) {} - virtual BOOL isItemRemovable(); - virtual BOOL isItemMovable(); + virtual BOOL isItemRemovable() const; + virtual BOOL isItemMovable() const; virtual BOOL isItemInTrash() const; virtual BOOL isLink() const; //virtual BOOL removeItem() = 0; @@ -175,7 +111,7 @@ public: virtual void move(LLFolderViewEventListener* new_parent_bridge) {} virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL copyToClipboard() const { return FALSE; } - virtual BOOL cutToClipboard() const { return FALSE; } + virtual void cutToClipboard(); virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard() {} @@ -197,7 +133,7 @@ protected: menuentry_vec_t &disabled_items); virtual void addOpenRightClickMenuOption(menuentry_vec_t &items); protected: - LLInvFVBridge(LLInventoryPanel* inventory, /*LLFolderView* root,*/ const LLUUID& uuid); + LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid); LLInventoryObject* getInventoryObject() const; LLInventoryModel* getInventoryModel() const; @@ -221,9 +157,11 @@ protected: protected: LLInventoryPanel* mInventoryPanel; + LLFolderView* mRoot; LLUUID mUUID; // item id LLInventoryType::EType mInvType; BOOL mIsLink; + void purgeItem(LLInventoryModel *model, const LLUUID &uuid); }; class AIFilePicker; @@ -231,15 +169,16 @@ class AIFilePicker; class LLItemBridge : public LLInvFVBridge { public: - LLItemBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : - LLInvFVBridge(inventory, uuid) {} - - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + LLItemBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid) : + LLInvFVBridge(inventory, root, uuid) {} + virtual void performAction(LLInventoryModel* model, std::string action); virtual void selectItem(); virtual void restoreItem(); virtual void restoreToWorld(); - virtual void gotoItem(LLFolderView *folder); + virtual void gotoItem(); virtual LLUIImagePtr getIcon() const; virtual const std::string& getDisplayName() const; virtual std::string getLabelSuffix() const; @@ -261,26 +200,28 @@ public: LLViewerInventoryItem* getItem() const; protected: + BOOL confirmRemoveItem(const LLSD& notification, const LLSD& response); virtual BOOL isItemPermissive() const; static void buildDisplayName(LLInventoryItem* item, std::string& name); + mutable std::string mDisplayName; }; - class LLFolderBridge : public LLInvFVBridge { public: LLFolderBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : - LLInvFVBridge(inventory, /*root,*/ uuid), + LLInvFVBridge(inventory, root, uuid), mCallingCards(FALSE), mWearables(FALSE) {} BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop); BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop); - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); + virtual void closeItem(); virtual BOOL isItemRenameable() const; virtual void selectItem(); virtual void restoreItem(); @@ -293,6 +234,9 @@ public: virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); + BOOL removeSystemFolder(); + bool removeItemResponse(const LLSD& notification, const LLSD& response); + virtual void pasteFromClipboard(); virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -301,19 +245,22 @@ public: EDragAndDropType cargo_type, void* cargo_data); - virtual BOOL isItemRemovable(); - virtual BOOL isItemMovable(); + virtual BOOL isItemRemovable() const; + virtual BOOL isItemMovable() const ; virtual BOOL isUpToDate() const; + virtual BOOL isItemCopyable() const; virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteableAsLink() const; static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type); - static void createWearable(LLUUID parent_folder_id, LLWearableType::EType type); + //static void createWearable(LLUUID parent_folder_id, LLWearableType::EType type); LLViewerInventoryCategory* getCategory() const; LLHandle getHandle() { mHandle.bind(this); return mHandle; } protected: + void buildContextMenuBaseOptions(U32 flags); + void buildContextMenuFolderOptions(U32 flags); // menu callbacks static void pasteClipboard(void* user_data); static void createNewCategory(void* user_data); @@ -337,16 +284,24 @@ protected: BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck); - void modifyOutfit(BOOL append, BOOL replace = FALSE); + void modifyOutfit(BOOL append); + void determineFolderType(); + menuentry_vec_t getMenuItems() { return mItems; } // returns a copy of current menu items + + void dropToFavorites(LLInventoryItem* inv_item); + void dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit); + + //-------------------------------------------------------------------- + // Messy hacks for handling folder options + //-------------------------------------------------------------------- public: static LLHandle sSelf; static void staticFolderOptionsMenu(); - void folderOptionsMenu(); private: - BOOL mCallingCards; - BOOL mWearables; + BOOL mCallingCards; + BOOL mWearables; LLHandle mMenu; menuentry_vec_t mItems; menuentry_vec_t mDisabledItems; @@ -359,24 +314,27 @@ class LLTextureBridge : public LLItemBridge public: virtual const std::string& getPrefix() { static std::string ret("Texture: ");return ret; } LLTextureBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid, LLInventoryType::EType type) : - LLItemBridge(inventory, /*root,*/ uuid) + LLItemBridge(inventory, root, uuid) { mInvType = type; } virtual LLUIImagePtr getIcon() const; virtual void openItem(); + //virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + //virtual void performAction(LLInventoryModel* model, std::string action); + bool canSaveTexture(void); }; class LLSoundBridge : public LLItemBridge { public: LLSoundBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : - LLItemBridge(inventory, /*root,*/ uuid) {} + LLItemBridge(inventory, root, uuid) {} virtual void openItem(); virtual void previewItem(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -390,10 +348,10 @@ public: static const std::string& prefix() { static std::string ret("Landmark: ");return ret; } virtual const std::string& getPrefix() { return prefix(); } LLLandmarkBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid, U32 flags = 0x00); - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual LLUIImagePtr getIcon() const; virtual void openItem(); @@ -406,17 +364,15 @@ class LLCallingCardBridge : public LLItemBridge public: virtual const std::string& getPrefix() { static std::string ret("Calling Card: ");return ret; } LLCallingCardBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* folder, const LLUUID& uuid ); ~LLCallingCardBridge(); virtual std::string getLabelSuffix() const; //virtual const std::string& getDisplayName() const; virtual LLUIImagePtr getIcon() const; - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - //virtual void renameItem(const std::string& new_name); - //virtual BOOL removeItem(); virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data); @@ -431,9 +387,9 @@ class LLNotecardBridge : public LLItemBridge public: virtual const std::string& getPrefix() { static std::string ret("Notecard: ");return ret; } LLNotecardBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : - LLItemBridge(inventory, /*root,*/ uuid) {} + LLItemBridge(inventory, root, uuid) {} virtual void openItem(); }; @@ -442,17 +398,18 @@ class LLGestureBridge : public LLItemBridge public: virtual const std::string& getPrefix() { static std::string ret("Gesture: ");return ret; } LLGestureBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : - LLItemBridge(inventory, /*root,*/ uuid) {} + LLItemBridge(inventory, root, uuid) {} // Only suffix for gesture items, not task items, because only // gestures in your inventory can be active. virtual LLFontGL::StyleFlags getLabelStyle() const; virtual std::string getLabelSuffix() const; - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); virtual BOOL removeItem(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + static void playGesture(const LLUUID& item_id); }; @@ -461,10 +418,10 @@ class LLAnimationBridge : public LLItemBridge public: virtual const std::string& getPrefix() { static std::string ret("Animation: ");return ret; } LLAnimationBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : - LLItemBridge(inventory, /*root,*/ uuid) {} - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + LLItemBridge(inventory, root, uuid) {} + virtual void performAction(LLInventoryModel* model, std::string action); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void openItem(); }; @@ -475,16 +432,15 @@ class LLObjectBridge : public LLItemBridge public: virtual const std::string& getPrefix() { static std::string ret("Object: ");return ret; } LLObjectBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid, LLInventoryType::EType type, U32 flags); virtual LLUIImagePtr getIcon() const; - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); virtual std::string getLabelSuffix() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual BOOL isItemRemovable(); virtual BOOL renameItem(const std::string& new_name); LLInventoryObject* getObject() const; protected: @@ -498,9 +454,9 @@ class LLLSLTextBridge : public LLItemBridge public: virtual const std::string& getPrefix() { static std::string ret("Script: ");return ret; } LLLSLTextBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid ) : - LLItemBridge(inventory, /*root,*/ uuid) {} + LLItemBridge(inventory, root, uuid) {} virtual void openItem(); }; @@ -509,17 +465,16 @@ class LLWearableBridge : public LLItemBridge { public: LLWearableBridge(LLInventoryPanel* inventory, - /*LLFolderView* root,*/ + LLFolderView* root, const LLUUID& uuid, LLAssetType::EType asset_type, LLInventoryType::EType inv_type, LLWearableType::EType wearable_type); virtual LLUIImagePtr getIcon() const; - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual std::string getLabelSuffix() const; - virtual BOOL isItemRemovable(); virtual BOOL renameItem(const std::string& new_name); virtual LLWearableType::EType getWearableType() const { return mWearableType; } @@ -528,13 +483,19 @@ public: static void onWearOnAvatarArrived( LLWearable* wearable, void* userdata ); void wearOnAvatar(); + static void onWearAddOnAvatarArrived( LLWearable* wearable, void* userdata ); + void wearAddOnAvatar(); + static BOOL canEditOnAvatar( void* userdata ); // Access to editOnAvatar() from menu static void onEditOnAvatar( void* userdata ); void editOnAvatar(); static BOOL canRemoveFromAvatar( void* userdata ); static void onRemoveFromAvatar( void* userdata ); - static void onRemoveFromAvatarArrived( LLWearable* wearable, void* userdata ); + static void onRemoveFromAvatarArrived( LLWearable* wearable, void* userdata ); + static void removeItemFromAvatar(LLViewerInventoryItem *item); + static void removeAllClothesFromAvatar(); + void removeFromAvatar(); protected: LLAssetType::EType mAssetType; LLWearableType::EType mWearableType; @@ -544,9 +505,9 @@ class LLLinkItemBridge : public LLItemBridge { public: LLLinkItemBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : - LLItemBridge(inventory, /*root,*/ uuid) {} + LLItemBridge(inventory, root, uuid) {} virtual const std::string& getPrefix() { return sPrefix; } virtual LLUIImagePtr getIcon() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -558,32 +519,34 @@ class LLLinkFolderBridge : public LLItemBridge { public: LLLinkFolderBridge(LLInventoryPanel* inventory, - //LLFolderView* root, + LLFolderView* root, const LLUUID& uuid) : - LLItemBridge(inventory, /*root,*/ uuid) {} + LLItemBridge(inventory, root, uuid) {} virtual const std::string& getPrefix() { return sPrefix; } virtual LLUIImagePtr getIcon() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); - virtual void gotoItem(LLFolderView *folder); + virtual void performAction(LLInventoryModel* model, std::string action); + virtual void gotoItem(); protected: const LLUUID &getFolderID() const; static std::string sPrefix; }; + class LLMeshBridge : public LLItemBridge { - friend class LLInvFVBridge; + friend class LLInvFVBridge; public: - virtual LLUIImagePtr getIcon() const; - virtual void openItem(); - virtual void previewItem(); - virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual void previewItem(); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); protected: - LLMeshBridge(LLInventoryPanel* inventory, - const LLUUID& uuid) : - LLItemBridge(inventory, uuid) {} + LLMeshBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid) : + LLItemBridge(inventory, root, uuid) {} }; void rez_attachment(LLViewerInventoryItem* item, @@ -597,4 +560,13 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, BOOL drop, void (*callback)(S32, void*) = NULL, void* user_data = NULL); + +// Utility function to hide all entries except those in the list +// Can be called multiple times on the same menu (e.g. if multiple items +// are selected). If "append" is false, then only common enabled items +// are set as enabled. +void hide_context_entries(LLMenuGL& menu, + const menuentry_vec_t &entries_to_show, + const menuentry_vec_t &disabled_entries); + #endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/llinventoryclipboard.cpp b/indra/newview/llinventoryclipboard.cpp index 5c2eb9f7c..53da34f44 100644 --- a/indra/newview/llinventoryclipboard.cpp +++ b/indra/newview/llinventoryclipboard.cpp @@ -41,6 +41,7 @@ LLInventoryClipboard LLInventoryClipboard::sInstance; ///---------------------------------------------------------------------------- LLInventoryClipboard::LLInventoryClipboard() +: mCutMode(false) { } @@ -71,6 +72,16 @@ void LLInventoryClipboard::store(const LLDynamicArray& inv_objects) } } +void LLInventoryClipboard::cut(const LLUUID& object) +{ + if(!mCutMode && !mObjects.empty()) + { + //looks like there are some stored items, reset clipboard state + reset(); + } + mCutMode = true; + add(object); +} void LLInventoryClipboard::retrieve(LLDynamicArray& inv_objects) const { inv_objects.reset(); @@ -84,6 +95,7 @@ void LLInventoryClipboard::retrieve(LLDynamicArray& inv_objects) const void LLInventoryClipboard::reset() { mObjects.reset(); + mCutMode = false; } // returns true if the clipboard has something pasteable in it. diff --git a/indra/newview/llinventoryclipboard.h b/indra/newview/llinventoryclipboard.h index e9b069eeb..b9f1451e5 100644 --- a/indra/newview/llinventoryclipboard.h +++ b/indra/newview/llinventoryclipboard.h @@ -54,6 +54,7 @@ public: // this method stores an array of objects void store(const LLDynamicArray& inventory_objects); + void cut(const LLUUID& object); // this method gets the objects in the clipboard by copying them // into the array provided. void retrieve(LLDynamicArray& inventory_objects) const; @@ -63,11 +64,13 @@ public: // returns true if the clipboard has something pasteable in it. BOOL hasContents() const; + bool isCutMode() const { return mCutMode; } protected: static LLInventoryClipboard sInstance; LLDynamicArray mObjects; + bool mCutMode; public: // please don't actually call these diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index d9c508e03..ddcc57776 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -41,6 +41,7 @@ #include "message.h" // newview includes +#include "llappearancemgr.h" #include "llappviewer.h" //#include "llfirstuse.h" #include "llfloaterinventory.h" @@ -52,9 +53,11 @@ #include "llinventorybridge.h" #include "llinventoryclipboard.h" #include "llinventorymodel.h" +#include "llinventorypanel.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llnotificationsutil.h" +#include "llpanelmaininventory.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" #include "llpreviewnotecard.h" @@ -75,13 +78,13 @@ #include "llvoavatarself.h" #include "llwearablelist.h" +#include + // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] -#include "cofmgr.h" - BOOL LLInventoryState::sWearNewClothing = FALSE; LLUUID LLInventoryState::sWearNewClothingTransactionID; @@ -164,7 +167,7 @@ void change_category_parent(LLInventoryModel* model, model->notifyObservers(); } -/*void remove_category(LLInventoryModel* model, const LLUUID& cat_id) +void remove_category(LLInventoryModel* model, const LLUUID& cat_id) { if (!model || !get_is_category_removable(model, cat_id)) { @@ -195,7 +198,7 @@ void change_category_parent(LLInventoryModel* model, const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); change_category_parent(model, cat, trash_id, TRUE); } -}*/ +} void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) { @@ -237,7 +240,7 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id) LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; LLInventoryCollectAllItems collect_all; - gInventory.collectDescendentsIf(LLCOFMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) { @@ -313,13 +316,13 @@ BOOL get_can_item_be_worn(const LLUUID& id) if (!item) return FALSE; - if (LLCOFMgr::instance().isLinkInCOF(item->getLinkedUUID())) + if (LLAppearanceMgr::isLinkInCOF(item->getLinkedUUID())) { // an item having links in COF (i.e. a worn item) return FALSE; } - if (gInventory.isObjectDescendentOf(id, LLCOFMgr::instance().getCOF())) + if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF())) { // a non-link object in COF (should not normally happen) return FALSE; @@ -363,12 +366,10 @@ BOOL get_can_item_be_worn(const LLUUID& id) // Not being worn yet. return TRUE; } - break; - - default: - break; + break; + default: + break; } - return FALSE; } @@ -379,6 +380,11 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) return FALSE; } + if(id == gInventory.getRootFolderID()) + { + return FALSE; + } + // Can't delete an item that's in the library. if(!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) { @@ -387,7 +393,7 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) // Disable delete from COF folder; have users explicitly choose "detach/take off", // unless the item is not worn but in the COF (i.e. is bugged). - if (LLCOFMgr::instance().getIsProtectedCOFItem(id)) + if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) { if (get_is_item_worn(id)) { @@ -415,7 +421,7 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) return TRUE; } -/*BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) +BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) { // NOTE: This function doesn't check the folder's children. // See LLFolderBridge::isItemRemovable for a function that does @@ -465,7 +471,7 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) } return TRUE; -}*/ +} BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) { @@ -492,6 +498,26 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) } +void show_item_profile(const LLUUID& item_uuid) +{ + LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid); + if(!LLFloaterProperties::show(linked_uuid, LLUUID::null)) + { + S32 left, top; + gFloaterView->getNewFloaterPosition(&left, &top); + LLRect rect = gSavedSettings.getRect("PropertiesRect"); + rect.translate( left - rect.mLeft, top - rect.mTop ); + LLFloaterProperties* floater; + floater = new LLFloaterProperties("item properties", + rect, + "Inventory Item Properties", + linked_uuid, + LLUUID::null); + // keep onscreen + gFloaterView->adjustToFitScreen(floater, FALSE); + } +} + ///---------------------------------------------------------------------------- /// LLInventoryCollectFunctor implementations ///---------------------------------------------------------------------------- @@ -641,6 +667,33 @@ bool LLNameCategoryCollector::operator()( return false; } +bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, + LLInventoryItem* item) +{ + // Valid COF items are: + // - links to wearables (body parts or clothing) + // - links to attachments + // - links to gestures + // - links to ensemble folders + LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); + if (linked_item) + { + LLAssetType::EType type = linked_item->getType(); + return (type == LLAssetType::AT_CLOTHING || + type == LLAssetType::AT_BODYPART || + type == LLAssetType::AT_GESTURE || + type == LLAssetType::AT_OBJECT); + } + else + { + LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); + // BAP remove AT_NONE support after ensembles are fully working? + return (linked_category && + ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || + (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); + } +} + bool LLFindWearables::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { @@ -686,6 +739,40 @@ bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* it return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; } +bool LLFindWearablesOfType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + if (!item) return false; + if (item->getType() != LLAssetType::AT_CLOTHING && + item->getType() != LLAssetType::AT_BODYPART) + { + return false; + } + + LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem || vitem->getWearableType() != mWearableType) return false; + + return true; +} + +void LLFindWearablesOfType::setType(LLWearableType::EType type) +{ + mWearableType = type; +} + +bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + if (item) + { + return !get_is_item_removable(&gInventory, item->getUUID()); + } + if (cat) + { + return !get_is_category_removable(&gInventory, cat->getUUID()); + } + + llwarns << "Not a category and not an item?" << llendl; + return false; +} ///---------------------------------------------------------------------------- /// LLAssetIDMatches diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index edae3872f..20bc90d0d 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -53,6 +53,8 @@ BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id); BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id); +void show_item_profile(const LLUUID& item_uuid); + void change_item_parent(LLInventoryModel* model, LLViewerInventoryItem* item, const LLUUID& new_parent_id, @@ -262,6 +264,77 @@ protected: std::string mName; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindCOFValidItems +// +// Collects items that can be legitimately linked to in the COF. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindCOFValidItems : public LLInventoryCollectFunctor +{ +public: + LLFindCOFValidItems() {} + virtual ~LLFindCOFValidItems() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindByMask +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindByMask : public LLInventoryCollectFunctor +{ +public: + LLFindByMask(U64 mask) + : mFilterMask(mask) + {} + + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + //converting an inventory type to a bitmap filter mask + if(item && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } + + return false; + } + +private: + U64 mFilterMask; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindNonLinksByMask +// +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindNonLinksByMask : public LLInventoryCollectFunctor +{ +public: + LLFindNonLinksByMask(U64 mask) + : mFilterMask(mask) + {} + + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } + + return false; + } + + void setFilterMask(U64 mask) + { + mFilterMask = mask; + } + +private: + U64 mFilterMask; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFindWearables // @@ -292,6 +365,52 @@ private: bool mIsWorn; }; +//Inventory collect functor collecting wearables of a specific wearable type +class LLFindWearablesOfType : public LLInventoryCollectFunctor +{ +public: + LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {} + virtual ~LLFindWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + void setType(LLWearableType::EType type); + +private: + LLWearableType::EType mWearableType; +}; + +/** Filter out wearables-links */ +class LLFindActualWearablesOfType : public LLFindWearablesOfType +{ +public: + LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {} + virtual ~LLFindActualWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLFindWearablesOfType::operator()(cat, item); + } +}; + +/* Filters out items of a particular asset type */ +class LLIsTypeActual : public LLIsType +{ +public: + LLIsTypeActual(LLAssetType::EType type) : LLIsType(type) {} + virtual ~LLIsTypeActual() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLIsType::operator()(cat, item); + } +}; + +// Collect non-removable folders and items. +class LLFindNonRemovableObjects : public LLInventoryCollectFunctor +{ +public: + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +}; + /** Inventory Collector Functions ** ** *******************************************************************************/ diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 2bcac85a1..62ab2d8e7 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2,31 +2,25 @@ * @file llinventorymodel.cpp * @brief Implementation of the inventory model used to track agent inventory. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,6 +28,8 @@ #include "llinventorymodel.h" #include "llagent.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" #include "llinventorypanel.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" @@ -64,6 +60,7 @@ // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewers with link items support, former caches are incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; +BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE; ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -244,6 +241,38 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons return NULL; } +// +// Search up the parent chain until we get to the specified parent, then return the first child category under it +// +const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const +{ + if (master_parent_id == obj_id) + { + return NULL; + } + + const LLViewerInventoryCategory* current_cat = getCategory(obj_id); + + if (current_cat == NULL) + { + current_cat = getCategory(getObject(obj_id)->getParentUUID()); + } + + while (current_cat != NULL) + { + const LLUUID& current_parent_id = current_cat->getParentUUID(); + + if (current_parent_id == master_parent_id) + { + return current_cat; + } + + current_cat = getCategory(current_parent_id); + } + + return NULL; +} + // Get the object by id. Returns NULL if not found. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { @@ -1091,6 +1120,7 @@ void LLInventoryModel::deleteObject(const LLUUID& id) } addChangedMask(LLInventoryObserver::REMOVE, id); obj = NULL; // delete obj + updateLinkedObjectsFromPurge(id); gInventory.notifyObservers(); } @@ -1107,6 +1137,25 @@ void LLInventoryModel::purgeObject(const LLUUID &id) } } +void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id) +{ + LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id); + + // REBUILD is expensive, so clear the current change list first else + // everything else on the changelist will also get rebuilt. + gInventory.notifyObservers(); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + const LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + if (item_id == baseobj_id) continue; + addChangedMask(LLInventoryObserver::REBUILD, item_id); + } + gInventory.notifyObservers(); +} + // This is a method which collects the descendents of the id // provided. If the category is not found, no action is // taken. This method goes through the long winded process of @@ -1990,6 +2039,10 @@ void LLInventoryModel::buildParentChildMap() llwarns << "Found " << lost << " lost categories." << llendl; } + const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null); + sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); + + // Now the items. We allocated in the last step, so now all we // have to do is iterate over the items and put them in the right // place. @@ -2870,7 +2923,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { LLViewerInventoryItem* wearable_item; wearable_item = gInventory.getItem(wearable_ids[i]); - wear_inventory_item_on_avatar(wearable_item); + LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); } } @@ -3094,6 +3147,139 @@ void LLInventoryModel::setLibraryOwnerID(const LLUUID& val) mLibraryOwnerID = val; } +// static +BOOL LLInventoryModel::getIsFirstTimeInViewer2() +{ + // Do not call this before parentchild map is built. + if (!gInventory.mIsAgentInvUsable) + { + llwarns << "Parent Child Map not yet built; guessing as first time in viewer2." << llendl; + return TRUE; + } + + return sFirstTimeInViewer2; +} + +LLInventoryModel::item_array_t::iterator LLInventoryModel::findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) +{ + LLInventoryModel::item_array_t::iterator curr_item = items.begin(); + + while (curr_item != items.end()) + { + if ((*curr_item)->getUUID() == id) + { + break; + } + ++curr_item; + } + + return curr_item; +} + +// static +// * @param[in, out] items - vector with items to be updated. It should be sorted in a right way +// * before calling this method. +// * @param src_item_id - LLUUID of inventory item to be moved in new position +// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should +// * be placed. +// * @param insert_before - bool indicating if src_item_id should be placed before or after +// * dest_item_id. Default is true. +void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id, bool insert_before) +{ + LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id); + LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id); + + // If one of the passed UUID is not in the item list, bail out + if ((it_src == items.end()) || (it_dest == items.end())) + return; + + // Erase the source element from the list, keep a copy before erasing. + LLViewerInventoryItem* src_item = *it_src; + items.erase(it_src); + + // Note: Target iterator is not valid anymore because the container was changed, so update it. + it_dest = findItemIterByUUID(items, dest_item_id); + + // Go to the next element if one wishes to insert after the dest element + if (!insert_before) + { + ++it_dest; + } + + // Reinsert the source item in the right place + if (it_dest != items.end()) + { + items.insert(it_dest, src_item); + } + else + { + // Append to the list if it_dest reached the end + items.push_back(src_item); + } +} + +//* @param[in] items vector of items in order to be saved. +/*void LLInventoryModel::saveItemsOrder(const LLInventoryModel::item_array_t& items) +{ + int sortField = 0; + + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field + for (item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) + { + LLViewerInventoryItem* item = *i; + + item->setSortField(++sortField); + item->setComplete(TRUE); + item->updateServer(FALSE); + + updateItem(item); + + // Tell the parent folder to refresh its sort order. + addChangedMask(LLInventoryObserver::SORT, item->getParentUUID()); + } + + notifyObservers(); +}*/ + +// See also LLInventorySort where landmarks in the Favorites folder are sorted. +/*class LLViewerInventoryItemSort +{ +public: + bool operator()(const LLPointer& a, const LLPointer& b) + { + return a->getSortField() < b->getSortField(); + } +};*/ + +/** + * Sorts passed items by LLViewerInventoryItem sort field. + * + * @param[in, out] items - array of items, not sorted. + */ +/*static void rearrange_item_order_by_sort_field(LLInventoryModel::item_array_t& items) +{ + static LLViewerInventoryItemSort sort_functor; + std::sort(items.begin(), items.end(), sort_functor); +}*/ + +// * @param source_item_id - LLUUID of the source item to be moved into new position +// * @param target_item_id - LLUUID of the target item before which source item should be placed. +/*void LLInventoryModel::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsType is_type(LLAssetType::AT_LANDMARK); + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + gInventory.collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + // ensure items are sorted properly before changing order. EXT-3498 + rearrange_item_order_by_sort_field(items); + + // update order + updateItemsOrder(items, source_item_id, target_item_id); + + saveItemsOrder(items); +}*/ // *NOTE: DEBUG functionality void LLInventoryModel::dumpInventory() const { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index e788baba9..90e841fef 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -2,31 +2,25 @@ * @file llinventorymodel.h * @brief LLInventoryModel class header file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,6 +30,7 @@ #include "llassettype.h" #include "llfoldertype.h" #include "lldarray.h" +#include "llframetimer.h" #include "llhttpclient.h" #include "lluuid.h" #include "llpermissionsflags.h" @@ -72,7 +67,10 @@ class LLInventoryCollectFunctor; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryModel { + LOG_CLASS(LLInventoryModel); public: + friend class LLInventoryModelFetchDescendentsResponder; + enum EHasChildren { CHILDREN_NO, @@ -90,8 +88,6 @@ public: fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; void result(const LLSD& content); void error(U32 status, const std::string& reason); - public: - typedef std::vector folder_ref_t; protected: LLSD mRequestSD; }; @@ -251,6 +247,9 @@ public: // Get whatever special folder this object is a child of, if any. const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const; + + // Get first descendant of the child object under the specified parent + const LLViewerInventoryCategory *getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const; // Get the object by id. Returns NULL if not found. // NOTE: Use the pointer returned for read operations - do @@ -339,28 +338,33 @@ public: // cache accounting in a fairly efficient manner. This method does // not notify observers (though maybe it should...) void purgeDescendentsOf(const LLUUID& id); - - // This method optimally removes the referenced categories and - // items from the current agent's inventory in the database. It - // performs all of the during deletion. The local representation - // is not removed. - void deleteFromServer(LLDynamicArray& category_ids, - LLDynamicArray& item_ids); - - // - // Misc Methods - // - - - // This method to prepares a set of mock inventory which provides - // minimal functionality before the actual arrival of inventory. - //void mock(const LLUUID& root_id); - +protected: + void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); + //-------------------------------------------------------------------- + // Reorder + //-------------------------------------------------------------------- +public: + // Changes items order by insertion of the item identified by src_item_id + // before (or after) the item identified by dest_item_id. Both items must exist in items array. + // Sorting is stored after method is finished. Only src_item_id is moved before (or after) dest_item_id. + // The parameter "insert_before" controls on which side of dest_item_id src_item_id gets rensinserted. + static void updateItemsOrder(LLInventoryModel::item_array_t& items, + const LLUUID& src_item_id, + const LLUUID& dest_item_id, + bool insert_before = true); + // Gets an iterator on an item vector knowing only the item UUID. + // Returns end() of the vector if not found. + static LLInventoryModel::item_array_t::iterator findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id); - // call this method to request the inventory. - //void requestFromServer(const LLUUID& agent_id); + // Saves current order of the passed items using inventory item sort field. + // Resets 'items' sort fields and saves them on server. + // Is used to save order for Favorites folder. + //void saveItemsOrder(const LLInventoryModel::item_array_t& items); + // Rearranges Landmarks inside Favorites folder. + // Moves source landmark before target one. + void rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id); //-------------------------------------------------------------------- // Creation diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 9be69dffb..3fc36a290 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -439,6 +439,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) { cat->setVersion(version); cat->setDescendentCount(descendents); + cat->determineFolderType(); } } @@ -532,7 +533,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) U32 folder_count=0; U32 max_batch_size=5; - U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; + U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1; uuid_vec_t recursive_cats; diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index bf45db43d..55b2b29dd 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -56,7 +56,9 @@ public: STRUCTURE = 16, // structural change, eg, item or folder moved CALLING_CARD = 32, // online, grant status, cancel, etc change GESTURE = 64, - ALL = 0xffffffff + REBUILD = 128, // Item UI changed (e.g. item type different) + SORT = 256, // Folder needs to be resorted. + ALL = 0xffffffff }; LLInventoryObserver(); virtual ~LLInventoryObserver(); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 76e0f3770..f085c7ba2 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -121,7 +121,15 @@ BOOL LLInventoryPanel::postBuild() 0, getRect().getWidth(), 0); - mFolderRoot = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this); + + LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(LLAssetType::AT_CATEGORY, + LLAssetType::AT_CATEGORY, + LLInventoryType::IT_CATEGORY, + this, + NULL, + LLUUID::null); + + mFolderRoot = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this, new_listener); mFolderRoot->setAllowMultiSelect(mAllowMultiSelect); // scroller @@ -475,16 +483,16 @@ const LLUUID& LLInventoryPanel::getRootFolderID() const { return mFolderRoot->getListener()->getUUID(); } -void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) +LLFolderViewItem* LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) { // Destroy the old view for this ID so we can rebuild it. LLFolderViewItem* old_view = mFolderRoot->getItemByID(id); - if (old_view && id.notNull()) + if (old_view) { old_view->destroyView(); } - buildNewViews(id); + return buildNewViews(id); } LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge) @@ -506,71 +514,74 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge bridge); } -void LLInventoryPanel::buildNewViews(const LLUUID& id) +LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) { - LLInventoryObject* const objectp = gInventory.getObject(id); + LLInventoryObject const* objectp = gInventory.getObject(id); + LLUUID root_id = mFolderRoot->getListener()->getUUID(); + LLFolderViewFolder* parent_folder = NULL; LLFolderViewItem* itemp = NULL; - - if (objectp) - { - const LLUUID &parent_id = objectp->getParentUUID(); - LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolderRoot->getItemByID(parent_id); - if (objectp->getType() <= LLAssetType::AT_NONE || - objectp->getType() >= LLAssetType::AT_COUNT) - { + if (id == root_id) + { + parent_folder = mFolderRoot; + } + else if (objectp) + { + const LLUUID &parent_id = objectp->getParentUUID(); + parent_folder = (LLFolderViewFolder*)mFolderRoot->getItemByID(parent_id); + + if (parent_folder) + { + if (objectp->getType() <= LLAssetType::AT_NONE || + objectp->getType() >= LLAssetType::AT_COUNT) + { llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() << llendl; - } - else if ((objectp->getType() == LLAssetType::AT_CATEGORY) && - (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) // build new view for category - { - LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), + return NULL; + } + + if ((objectp->getType() == LLAssetType::AT_CATEGORY) && + (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) + { + LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), objectp->getType(), LLInventoryType::IT_CATEGORY, this, + mFolderRoot, objectp->getUUID()); - - if (new_listener) + if (new_listener) + { + LLFolderViewFolder* folderp = createFolderViewFolder(new_listener); + if (folderp) + { + folderp->setItemSortOrder(mFolderRoot->getSortOrder()); + } + itemp = folderp; + } + } + else { - LLFolderViewFolder* folderp = createFolderViewFolder(new_listener); - if (folderp) - { - folderp->setItemSortOrder(mFolderRoot->getSortOrder()); - } - itemp = folderp; - } - } - else // build new view for item - { - LLInventoryItem* item = (LLInventoryItem*)objectp; - LLInvFVBridge* new_listener = LLInvFVBridge::createBridge( - item->getType(), + // Build new view for item. + LLInventoryItem* item = (LLInventoryItem*)objectp; + LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(item->getType(), item->getActualType(), item->getInventoryType(), - this, - item->getUUID(), - item->getFlags()); + this, + mFolderRoot, + item->getUUID(), + item->getFlags()); + if (new_listener) { itemp = createFolderViewItem(new_listener); } - } - - - - if (itemp) - { - if (parent_folder) - { - itemp->addToFolder(parent_folder, mFolderRoot); - } - else - { - llwarns << "Couldn't find parent folder for child " << itemp->getLabel() << llendl; - delete itemp; - } + } + + if (itemp) + { + itemp->addToFolder(parent_folder, mFolderRoot); + } } } @@ -595,7 +606,7 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) } } - if(items) + if(items && parent_folder) { for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin(); item_iter != items->end(); @@ -607,6 +618,8 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) } mInventory->unlockDirectDescendentArrays(id); } + + return itemp; } struct LLConfirmPurgeData @@ -728,19 +741,33 @@ void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_foc mSelectThisID = obj_id; } } -void LLInventoryPanel::setSelectCallback(LLFolderView::SelectCallback callback, void* user_data) -{ +void LLInventoryPanel::setSelectCallback(const boost::function& items, BOOL user_action)>& cb) +{ if (mFolderRoot) { - mFolderRoot->setSelectCallback(callback, user_data); + mFolderRoot->setSelectCallback(cb); } } + void LLInventoryPanel::clearSelection() { mFolderRoot->clearSelection(); mSelectThisID.setNull(); } +void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) +{ + LLFolderView* fv = getRootFolder(); + if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename + { + fv->setNeedsAutoRename(FALSE); + if (items.size()) // new asset is visible and selected + { + fv->startRenamingSelectedItem(); + } + } +} + void LLInventoryPanel::createNewItem(const std::string& name, const LLUUID& parent_id, LLAssetType::EType asset_type, diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index d18097f73..af5888691 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -99,7 +99,7 @@ public: void closeAllFolders(); void openDefaultFolderForType(LLAssetType::EType); void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); - void setSelectCallback(LLFolderView::SelectCallback callback, void* user_data); + void setSelectCallback(const boost::function& items, BOOL user_action)>& cb); void clearSelection(); LLInventoryFilter* getFilter(); const LLInventoryFilter* getFilter() const; @@ -123,17 +123,14 @@ public: void modelChanged(U32 mask); LLFolderView* getRootFolder(); LLScrollableContainerView* getScrollableContainer() { return mScroller; } - + + void onSelectionChange(const std::deque &items, BOOL user_action); // DEBUG ONLY: static void dumpSelectionInformation(void* user_data); void openSelected(); void unSelectAll(); -protected: - // Given the id and the parent, build all of the folder views. - void rebuildViewsFor(const LLUUID& id, U32 mask); - void buildNewViews(const LLUUID& id); public: // TomY TODO: Move this elsewhere? @@ -174,6 +171,10 @@ private: public: const LLUUID& getRootFolderID() const; protected: + // Given the id and the parent, build all of the folder views. + LLFolderViewItem* rebuildViewsFor(const LLUUID& id, U32 mask); + + LLFolderViewItem* buildNewViews(const LLUUID& id); virtual LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge); virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge); }; @@ -195,11 +196,6 @@ void init_inventory_panel_actions(LLInventoryPanel *panel); class LLInventoryCategory; class LLInventoryItem; -//void wear_inventory_category_on_avatar(LLInventoryCategory* category); - -void wear_inventory_item_on_avatar(LLInventoryItem* item); -void wear_outfit_by_name(const std::string& name); -void wear_inventory_category(LLInventoryCategory* category, bool copy, bool append); // These methods can open items without the inventory being visible void open_notecard(LLViewerInventoryItem* inv_item, const std::string& title, const LLUUID& object_id, BOOL show_keep_discard, const LLUUID& source_id = LLUUID::null, BOOL take_focus = TRUE); diff --git a/indra/newview/lllocaltextureobject.cpp b/indra/newview/lllocaltextureobject.cpp new file mode 100644 index 000000000..07ec0fab9 --- /dev/null +++ b/indra/newview/lllocaltextureobject.cpp @@ -0,0 +1,212 @@ +/** + * @file lllocaltextureobject.cpp + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lllocaltextureobject.h" + +#include "lltexlayer.h" +#include "llviewertexture.h" +#include "lltextureentry.h" +#include "lluuid.h" +#include "llwearable.h" + + +LLLocalTextureObject::LLLocalTextureObject() : + mIsBakedReady(FALSE), + mDiscard(MAX_DISCARD_LEVEL+1) +{ + mImage = NULL; +} + +LLLocalTextureObject::LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id) : + mIsBakedReady(FALSE), + mDiscard(MAX_DISCARD_LEVEL+1) +{ + mImage = image; + gGL.getTexUnit(0)->bind(mImage); + mID = id; +} + +LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) : + mImage(lto.mImage), + mID(lto.mID), + mIsBakedReady(lto.mIsBakedReady), + mDiscard(lto.mDiscard) +{ + U32 num_layers = lto.getNumTexLayers(); + mTexLayers.reserve(num_layers); + for (U32 index = 0; index < num_layers; index++) + { + LLTexLayer* original_layer = lto.getTexLayer(index); + if (!original_layer) + { + llerrs << "could not clone Local Texture Object: unable to extract texlayer!" << llendl; + continue; + } + + LLTexLayer* new_layer = new LLTexLayer(*original_layer); + new_layer->setLTO(this); + mTexLayers.push_back(new_layer); + } +} + +LLLocalTextureObject::~LLLocalTextureObject() +{ +} + +LLViewerFetchedTexture* LLLocalTextureObject::getImage() const +{ + return mImage; +} + +LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const +{ + if (index >= getNumTexLayers()) + { + return NULL; + } + + return mTexLayers[index]; +} + +LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name) +{ + for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); iter++) + { + LLTexLayer *layer = *iter; + if (layer->getName().compare(name) == 0) + { + return layer; + } + } + + return NULL; +} + +U32 LLLocalTextureObject::getNumTexLayers() const +{ + return mTexLayers.size(); +} + +LLUUID LLLocalTextureObject::getID() const +{ + return mID; +} + +S32 LLLocalTextureObject::getDiscard() const +{ + return mDiscard; +} + +BOOL LLLocalTextureObject::getBakedReady() const +{ + return mIsBakedReady; +} + +void LLLocalTextureObject::setImage(LLViewerFetchedTexture* new_image) +{ + mImage = new_image; +} + +BOOL LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer, U32 index) +{ + if (index >= getNumTexLayers() ) + { + return FALSE; + } + + if (new_tex_layer == NULL) + { + return removeTexLayer(index); + } + + LLTexLayer *layer = new LLTexLayer(*new_tex_layer); + layer->setLTO(this); + + if (mTexLayers[index]) + { + delete mTexLayers[index]; + } + mTexLayers[index] = layer; + + return TRUE; +} + +BOOL LLLocalTextureObject::addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable) +{ + if (new_tex_layer == NULL) + { + return FALSE; + } + + LLTexLayer *layer = new LLTexLayer(*new_tex_layer, wearable); + layer->setLTO(this); + mTexLayers.push_back(layer); + return TRUE; +} + +BOOL LLLocalTextureObject::addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable) +{ + if (new_tex_layer == NULL) + { + return FALSE; + } + + LLTexLayer *layer = new LLTexLayer(*new_tex_layer, this, wearable); + layer->setLTO(this); + mTexLayers.push_back(layer); + return TRUE; +} + +BOOL LLLocalTextureObject::removeTexLayer(U32 index) +{ + if (index >= getNumTexLayers()) + { + return FALSE; + } + tex_layer_vec_t::iterator iter = mTexLayers.begin(); + iter += index; + + delete *iter; + mTexLayers.erase(iter); + return TRUE; +} + +void LLLocalTextureObject::setID(LLUUID new_id) +{ + mID = new_id; +} + +void LLLocalTextureObject::setDiscard(S32 new_discard) +{ + mDiscard = new_discard; +} + +void LLLocalTextureObject::setBakedReady(BOOL ready) +{ + mIsBakedReady = ready; +} + diff --git a/indra/newview/lllocaltextureobject.h b/indra/newview/lllocaltextureobject.h new file mode 100644 index 000000000..b9bfc5472 --- /dev/null +++ b/indra/newview/lllocaltextureobject.h @@ -0,0 +1,87 @@ +/** + * @file lllocaltextureobject.h + * @brief LLLocalTextureObject class header file + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LOCALTEXTUREOBJECT_H +#define LL_LOCALTEXTUREOBJECT_H + +#include + +#include "llviewertexture.h" + +class LLUUID; +class LLTexLayer; +class LLTextureEntry; +class LLTexLayerTemplate; +class LLWearable; + +// Stores all relevant information for a single texture +// assumed to have ownership of all objects referred to - +// will delete objects when being replaced or if object is destroyed. +class LLLocalTextureObject +{ +public: + LLLocalTextureObject(); + LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id); + LLLocalTextureObject(const LLLocalTextureObject& lto); + ~LLLocalTextureObject(); + + LLViewerFetchedTexture* getImage() const; + LLTexLayer* getTexLayer(U32 index) const; + LLTexLayer* getTexLayer(const std::string &name); + U32 getNumTexLayers() const; + LLUUID getID() const; + S32 getDiscard() const; + BOOL getBakedReady() const; + + void setImage(LLViewerFetchedTexture* new_image); + BOOL setTexLayer(LLTexLayer *new_tex_layer, U32 index); + BOOL addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable); + BOOL addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable); + BOOL removeTexLayer(U32 index); + + void setID(LLUUID new_id); + void setDiscard(S32 new_discard); + void setBakedReady(BOOL ready); + +protected: + +private: + + LLPointer mImage; + // NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer + // using shared pointers here only for smart assignment & cleanup + // do NOT create new shared pointers to these objects, or keep pointers to them around + typedef std::vector tex_layer_vec_t; + tex_layer_vec_t mTexLayers; + + LLUUID mID; + + BOOL mIsBakedReady; + S32 mDiscard; +}; + + #endif // LL_LOCALTEXTUREOBJECT_H + diff --git a/indra/newview/lloutfitobserver.cpp b/indra/newview/lloutfitobserver.cpp new file mode 100644 index 000000000..5bb69367a --- /dev/null +++ b/indra/newview/lloutfitobserver.cpp @@ -0,0 +1,153 @@ +/** + * @file lloutfitobserver.cpp + * @brief Outfit observer facade. + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llappearancemgr.h" +#include "lloutfitobserver.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" + +LLOutfitObserver::LLOutfitObserver() : + mCOFLastVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) +{ + mItemNameHash.finalize(); + gInventory.addObserver(this); +} + +LLOutfitObserver::~LLOutfitObserver() +{ + if (gInventory.containsObserver(this)) + { + gInventory.removeObserver(this); + } +} + +void LLOutfitObserver::changed(U32 mask) +{ + if (!gInventory.isInventoryUsable()) + return; + + checkCOF(); + + checkBaseOutfit(); +} + +// static +S32 LLOutfitObserver::getCategoryVersion(const LLUUID& cat_id) +{ + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (!cat) + return LLViewerInventoryCategory::VERSION_UNKNOWN; + + return cat->getVersion(); +} + +// static +const std::string& LLOutfitObserver::getCategoryName(const LLUUID& cat_id) +{ + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (!cat) + return LLStringUtil::null; + + return cat->getName(); +} + +bool LLOutfitObserver::checkCOF() +{ + LLUUID cof = LLAppearanceMgr::getInstance()->getCOF(); + if (cof.isNull()) + return false; + + bool cof_changed = false; + LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cof); + if (item_name_hash != mItemNameHash) + { + cof_changed = true; + mItemNameHash = item_name_hash; + } + + S32 cof_version = getCategoryVersion(cof); + if (cof_version != mCOFLastVersion) + { + cof_changed = true; + mCOFLastVersion = cof_version; + } + + if (!cof_changed) + return false; + + // dirtiness state should be updated before sending signal + LLAppearanceMgr::getInstance()->updateIsDirty(); + mCOFChanged(); + + return true; +} + +void LLOutfitObserver::checkBaseOutfit() +{ + LLUUID baseoutfit_id = + LLAppearanceMgr::getInstance()->getBaseOutfitUUID(); + + if (baseoutfit_id == mBaseOutfitId) + { + if (baseoutfit_id.isNull()) + return; + + const S32 baseoutfit_ver = getCategoryVersion(baseoutfit_id); + const std::string& baseoutfit_name = getCategoryName(baseoutfit_id); + + if (baseoutfit_ver == mBaseOutfitLastVersion + // renaming category doesn't change version, so it's need to check it + && baseoutfit_name == mLastBaseOutfitName) + return; + } + else + { + mBaseOutfitId = baseoutfit_id; + mBOFReplaced(); + + if (baseoutfit_id.isNull()) + return; + } + + mBaseOutfitLastVersion = getCategoryVersion(mBaseOutfitId); + mLastBaseOutfitName = getCategoryName(baseoutfit_id); + + LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + // dirtiness state should be updated before sending signal + app_mgr.updateIsDirty(); + mBOFChanged(); + + if (mLastOutfitDirtiness != app_mgr.isOutfitDirty()) + { + if(!app_mgr.isOutfitDirty()) + { + mCOFSaved(); + } + mLastOutfitDirtiness = app_mgr.isOutfitDirty(); + } +} diff --git a/indra/newview/lloutfitobserver.h b/indra/newview/lloutfitobserver.h new file mode 100644 index 000000000..87d4b0c99 --- /dev/null +++ b/indra/newview/lloutfitobserver.h @@ -0,0 +1,96 @@ +/** + * @file lloutfitobserver.h + * @brief Outfit observer facade. + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_OUTFITOBSERVER_H +#define LL_OUTFITOBSERVER_H + +#include "llsingleton.h" +#include "llmd5.h" + +/** + * Outfit observer facade that provides simple possibility to subscribe on + * BOF(base outfit) replaced, BOF changed, COF(current outfit) changed events. + */ +class LLOutfitObserver: public LLInventoryObserver, public LLSingleton +{ +public: + virtual ~LLOutfitObserver(); + + friend class LLSingleton; + + virtual void changed(U32 mask); + + void notifyOutfitLockChanged() { mOutfitLockChanged(); } + + typedef boost::signals2::signal signal_t; + + void addBOFReplacedCallback(const signal_t::slot_type& cb) { mBOFReplaced.connect(cb); } + + void addBOFChangedCallback(const signal_t::slot_type& cb) { mBOFChanged.connect(cb); } + + void addCOFChangedCallback(const signal_t::slot_type& cb) { mCOFChanged.connect(cb); } + + void addCOFSavedCallback(const signal_t::slot_type& cb) { mCOFSaved.connect(cb); } + + void addOutfitLockChangedCallback(const signal_t::slot_type& cb) { mOutfitLockChanged.connect(cb); } + +protected: + LLOutfitObserver(); + + /** Get a version of an inventory category specified by its UUID */ + static S32 getCategoryVersion(const LLUUID& cat_id); + + static const std::string& getCategoryName(const LLUUID& cat_id); + + bool checkCOF(); + + void checkBaseOutfit(); + + //last version number of a COF category + S32 mCOFLastVersion; + + LLUUID mBaseOutfitId; + + S32 mBaseOutfitLastVersion; + std::string mLastBaseOutfitName; + + bool mLastOutfitDirtiness; + + LLMD5 mItemNameHash; + +private: + signal_t mBOFReplaced; + signal_t mBOFChanged; + signal_t mCOFChanged; + signal_t mCOFSaved; + + /** + * Signal for changing state of outfit lock. + */ + signal_t mOutfitLockChanged; +}; + +#endif /* LL_OUTFITOBSERVER_H */ diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 200cc1c4b..3743a49b8 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -152,7 +152,7 @@ BOOL LLInventoryView::postBuild() mActivePanel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); mActivePanel->getFilter()->markDefault(); mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - mActivePanel->setSelectCallback(onSelectionChange, mActivePanel); + mActivePanel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, mActivePanel, _1, _2)); } LLInventoryPanel* recent_items_panel = getChild("Recent Items"); if (recent_items_panel) @@ -161,7 +161,7 @@ BOOL LLInventoryView::postBuild() recent_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::RECENTITEMS_SORT_ORDER)); recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); recent_items_panel->getFilter()->markDefault(); - recent_items_panel->setSelectCallback(onSelectionChange, recent_items_panel); + recent_items_panel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, recent_items_panel, _1, _2)); } LLInventoryPanel* worn_items_panel = getChild("Worn Items"); if (worn_items_panel) @@ -170,7 +170,7 @@ BOOL LLInventoryView::postBuild() worn_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); worn_items_panel->getFilter()->markDefault(); worn_items_panel->setFilterWorn(true); - worn_items_panel->setSelectCallback(onSelectionChange, worn_items_panel); + worn_items_panel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, worn_items_panel, _1, _2)); } // Now load the stored settings from disk, if available. @@ -581,79 +581,54 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ self->mActivePanel->setFilterSubString(uppercase_search_string); } +struct FilterEntry : public LLDictionaryEntry +{ + FilterEntry(const std::string &filter_name) : + LLDictionaryEntry(filter_name){} +}; + +class LLFilterDictionary : public LLSingleton, + public LLDictionary +{ +public: + LLFilterDictionary() + {} + void init(LLInventoryView *view) + { + addEntry(0x1 << LLInventoryType::IT_ANIMATION, new FilterEntry(view->getString("filter_type_animation"))); + addEntry(0x1 << LLInventoryType::IT_CALLINGCARD, new FilterEntry(view->getString("filter_type_callingcard"))); + addEntry(0x1 << LLInventoryType::IT_WEARABLE, new FilterEntry(view->getString("filter_type_wearable"))); + addEntry(0x1 << LLInventoryType::IT_GESTURE, new FilterEntry(view->getString("filter_type_gesture"))); + addEntry(0x1 << LLInventoryType::IT_LANDMARK, new FilterEntry(view->getString("filter_type_landmark"))); + addEntry(0x1 << LLInventoryType::IT_NOTECARD, new FilterEntry(view->getString("filter_type_notecard"))); + addEntry(0x1 << LLInventoryType::IT_OBJECT, new FilterEntry(view->getString("filter_type_object"))); + addEntry(0x1 << LLInventoryType::IT_LSL, new FilterEntry(view->getString("filter_type_script"))); + addEntry(0x1 << LLInventoryType::IT_SOUND, new FilterEntry(view->getString("filter_type_sound"))); + addEntry(0x1 << LLInventoryType::IT_TEXTURE, new FilterEntry(view->getString("filter_type_texture"))); + addEntry(0x1 << LLInventoryType::IT_SNAPSHOT, new FilterEntry(view->getString("filter_type_snapshot"))); + addEntry(0xffffffff, new FilterEntry(view->getString("filter_type_all"))); + } + virtual U32 notFound() const + { + return 0; + } +}; + //static void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) { LLComboBox* quickfilter = (LLComboBox*)ctrl; - LLInventoryView* view = (LLInventoryView*)(quickfilter->getParent()); if (!view->mActivePanel) { return; } - std::string item_type = quickfilter->getSimple(); - U32 filter_type; - if (view->getString("filter_type_animation") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_ANIMATION; - } - - else if (view->getString("filter_type_callingcard") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_CALLINGCARD; - } - - else if (view->getString("filter_type_wearable") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_WEARABLE; - } - - else if (view->getString("filter_type_gesture") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_GESTURE; - } - - else if (view->getString("filter_type_landmark") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_LANDMARK; - } - - else if (view->getString("filter_type_notecard") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_NOTECARD; - } - - else if (view->getString("filter_type_object") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_OBJECT; - } - - else if (view->getString("filter_type_script") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_LSL; - } - - else if (view->getString("filter_type_sound") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_SOUND; - } - - else if (view->getString("filter_type_texture") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_TEXTURE; - } - - else if (view->getString("filter_type_snapshot") == item_type) - { - filter_type = 0x1 << LLInventoryType::IT_SNAPSHOT; - } - - else if (view->getString("filter_type_custom") == item_type) + if (view->getString("filter_type_custom") == item_type) { // When they select custom, show the floater then return if( !(view->filtersVisible(view)) ) @@ -662,31 +637,27 @@ void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) } return; } - - else if (view->getString("filter_type_all") == item_type) + else { - // Show all types - filter_type = 0xffffffff; + if(!LLFilterDictionary::instanceExists()) + LLFilterDictionary::instance().init(view); + + U32 filter_type = LLFilterDictionary::instance().lookup(item_type); + if(!filter_type) + { + llwarns << "Ignoring unknown filter: " << item_type << llendl; + return; + } + else + { + view->mActivePanel->setFilterTypes( filter_type ); + + // Force the filters window to update itself, if it's open. + LLFloaterInventoryFinder* finder = view->getFinder(); + if( finder ) + finder->updateElementsFromFilter(); + } } - - else - { - llwarns << "Ignoring unknown filter: " << item_type << llendl; - return; - } - - view->mActivePanel->setFilterTypes( filter_type ); - - - // Force the filters window to update itself, if it's open. - LLFloaterInventoryFinder* finder = view->getFinder(); - if( finder ) - { - finder->updateElementsFromFilter(); - } - - // llinfos << "Quick Filter: " << item_type << llendl; - } @@ -694,7 +665,6 @@ void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) //static void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) { - LLInventoryView* view = (LLInventoryView*)(ctrl->getParent()); if (!view->mActivePanel) { @@ -707,147 +677,48 @@ void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) return; } - U32 filter_type = view->mActivePanel->getFilterTypes(); + if(!LLFilterDictionary::instanceExists()) + LLFilterDictionary::instance().init(view); - // Mask to extract only the bit fields we care about. - // *TODO: There's probably a cleaner way to construct this mask. - U32 filter_mask = 0; - filter_mask |= (0x1 << LLInventoryType::IT_ANIMATION); - filter_mask |= (0x1 << LLInventoryType::IT_CALLINGCARD); - filter_mask |= (0x1 << LLInventoryType::IT_WEARABLE); - filter_mask |= (0x1 << LLInventoryType::IT_GESTURE); - filter_mask |= (0x1 << LLInventoryType::IT_LANDMARK); - filter_mask |= (0x1 << LLInventoryType::IT_NOTECARD); - filter_mask |= (0x1 << LLInventoryType::IT_OBJECT); - filter_mask |= (0x1 << LLInventoryType::IT_LSL); - filter_mask |= (0x1 << LLInventoryType::IT_SOUND); - filter_mask |= (0x1 << LLInventoryType::IT_TEXTURE); - filter_mask |= (0x1 << LLInventoryType::IT_SNAPSHOT); - - - filter_type &= filter_mask; - - + // Mask to extract only the bit fields we care about. + // *TODO: There's probably a cleaner way to construct this mask. + U32 filter_mask = 0; + for (LLFilterDictionary::const_iterator_t dictionary_iter = LLFilterDictionary::instance().map_t::begin(); + dictionary_iter != LLFilterDictionary::instance().map_t::end(); dictionary_iter++) + { + if(filter_mask != 0xffffffff) + filter_mask |= dictionary_iter->first; + } + + filter_type &= filter_mask; + //llinfos << "filter_type: " << filter_type << llendl; - std::string selection; - if (filter_type == filter_mask) { selection = view->getString("filter_type_all"); } - - else if (filter_type == (0x1 << LLInventoryType::IT_ANIMATION)) - { - selection = view->getString("filter_type_animation"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_CALLINGCARD)) - { - selection = view->getString("filter_type_callingcard"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_WEARABLE)) - { - selection = view->getString("filter_type_wearable"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_GESTURE)) - { - selection = view->getString("filter_type_gesture"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_LANDMARK)) - { - selection = view->getString("filter_type_landmark"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_NOTECARD)) - { - selection = view->getString("filter_type_notecard"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_OBJECT)) - { - selection = view->getString("filter_type_object"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_LSL)) - { - selection = view->getString("filter_type_script"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_SOUND)) - { - selection = view->getString("filter_type_sound"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_TEXTURE)) - { - selection = view->getString("filter_type_texture"); - } - - else if (filter_type == (0x1 << LLInventoryType::IT_SNAPSHOT)) - { - selection = view->getString("filter_type_snapshot"); - } - else { - selection = view->getString("filter_type_custom"); + const FilterEntry *entry = LLFilterDictionary::instance().lookup(filter_type); + if(entry) + selection = view->getString(entry->mName); + else + selection = view->getString("filter_type_custom"); } - // Select the chosen item by label text BOOL result = quickfilter->setSimple( (selection) ); - if( !result ) - { - llinfos << "The item didn't exist: " << selection << llendl; - } - + if( !result ) + { + llinfos << "The item didn't exist: " << selection << llendl; + } } - - -// static -// BOOL LLInventoryView::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) -// { -// LLInventoryView* active_view = NULL; - -// for (S32 i = 0; i < sActiveViews.count(); i++) -// { -// if (gFocusMgr.childHasKeyboardFocus(sActiveViews[i])) -// { -// active_view = sActiveViews[i]; -// break; -// } -// } - -// if (!active_view) -// { -// return FALSE; -// } - -// std::string search_string(find_text); - -// if (search_string.empty()) -// { -// return FALSE; -// } - -// if (active_view->mActivePanel && -// active_view->mActivePanel->getRootFolder()->search(first_item, search_string, backward)) -// { -// return TRUE; -// } - -// return FALSE; -// } - void LLInventoryView::onResetAll(void* userdata) { LLInventoryView* self = (LLInventoryView*) userdata; @@ -920,21 +791,6 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) self->updateSortControls(); } -// static -void LLInventoryView::onSelectionChange(const std::deque &items, BOOL user_action, void* data) -{ - LLInventoryPanel* panel = (LLInventoryPanel*)data; - LLFolderView* fv = panel->getRootFolder(); - if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename - { - fv->setNeedsAutoRename(FALSE); - if (items.size()) // new asset is visible and selected - { - fv->startRenamingSelectedItem(); - } - } -} - const std::string LLInventoryView::getFilterSubString() { return mActivePanel->getFilterSubString(); @@ -1040,9 +896,23 @@ void LLInventoryView::toggleFindOptions() mFloaterControls[std::string("Inventory.ShowFilters")]->setValue(FALSE); } } + +void LLInventoryView::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) +{ + getChild("All Items")->setSelectCallback(cb); + getChild("Recent Items")->setSelectCallback(cb); + getChild("Worn Items")->setSelectCallback(cb); +} + +void LLInventoryView::onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action) +{ + panel->onSelectionChange(items, user_action); +} + ///---------------------------------------------------------------------------- /// LLFloaterInventoryFinder ///---------------------------------------------------------------------------- + LLFloaterInventoryFinder* LLInventoryView::getFinder() { return (LLFloaterInventoryFinder*)mFinderHandle.get(); @@ -1056,7 +926,7 @@ LLFloaterInventoryFinder::LLFloaterInventoryFinder(const std::string& name, INV_FINDER_WIDTH, INV_FINDER_HEIGHT, DRAG_ON_TOP, MINIMIZE_NO, CLOSE_YES), mInventoryView(inventory_view), - mFilter(inventory_view->mActivePanel->getFilter()) + mFilter(inventory_view->getPanel()->getFilter()) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml"); diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 43d4184d1..60d7d73b9 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -89,6 +89,8 @@ public: const LLInventoryPanel* getActivePanel() const { return mActivePanel; } const std::string& getFilterText() const { return mFilterText; } + + void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); static void onSearchEdit(const std::string& search_string, void* user_data ); // // Misc functions @@ -97,7 +99,8 @@ public: void startSearch(); void toggleFindOptions(); - static void onSelectionChange(const std::deque &items, BOOL user_action, void* data); + void onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action); + static BOOL filtersVisible(void* user_data); static void onClearSearch(void* user_data); static void onFoldersByName(void *user_data); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 7744b52b6..08908b79c 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -83,7 +83,10 @@ protected: mutable std::string mDisplayName; LLPanelObjectInventory* mPanel; U32 mFlags; + LLAssetType::EType mAssetType; + LLInventoryType::EType mInventoryType; + LLInventoryObject* findInvObject() const; LLInventoryItem* findItem() const; public: @@ -107,30 +110,34 @@ public: virtual const std::string& getName() const; virtual const std::string& getDisplayName() const; virtual PermissionMask getPermissionMask() const { return PERM_NONE; } + /*virtual*/ LLFolderType::EType getPreferredType() const { return LLFolderType::FT_NONE; } virtual const LLUUID& getUUID() const { return mUUID; } virtual time_t getCreationDate() const; virtual LLUIImagePtr getIcon() const; virtual void openItem(); + virtual BOOL canOpenItem() const { return FALSE; } + virtual void closeItem() {} virtual void previewItem(); virtual void selectItem() {} virtual BOOL isItemRenameable() const; virtual BOOL renameItem(const std::string& new_name); - virtual BOOL isItemMovable(); - virtual BOOL isItemRemovable(); + virtual BOOL isItemMovable() const; + virtual BOOL isItemRemovable() const; virtual BOOL removeItem(); virtual void removeBatch(LLDynamicArray& batch); virtual void move(LLFolderViewEventListener* parent_listener); virtual BOOL isItemCopyable() const; virtual BOOL copyToClipboard() const; - virtual BOOL cutToClipboard() const; + virtual void cutToClipboard(); virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard(); virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual BOOL isUpToDate() const { return TRUE; } virtual BOOL hasChildren() const { return FALSE; } virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; } + virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; } // LLDragAndDropBridge functionality virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; @@ -149,19 +156,32 @@ LLTaskInvFVBridge::LLTaskInvFVBridge( mUUID(uuid), mName(name), mPanel(panel), - mFlags(flags) + mFlags(flags), + mAssetType(LLAssetType::AT_NONE), + mInventoryType(LLInventoryType::IT_NONE) { - + const LLInventoryItem *item = findItem(); + if (item) + { + mAssetType = item->getType(); + mInventoryType = item->getInventoryType(); + } } +LLInventoryObject* LLTaskInvFVBridge::findInvObject() const +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if (object) + { + return object->getInventoryObject(mUUID); + } + return NULL; +} + + LLInventoryItem* LLTaskInvFVBridge::findItem() const { - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - return (LLInventoryItem*)(object->getInventoryObject(mUUID)); - } - return NULL; + return dynamic_cast(findInvObject()); } void LLTaskInvFVBridge::showProperties() @@ -333,7 +353,7 @@ LLUIImagePtr LLTaskInvFVBridge::getIcon() const { const BOOL item_is_multi = (mFlags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS); - return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi ); + return LLInventoryIcon::getIcon(mAssetType, mInventoryType, 0, item_is_multi ); } void LLTaskInvFVBridge::openItem() @@ -400,7 +420,7 @@ BOOL LLTaskInvFVBridge::renameItem(const std::string& new_name) return TRUE; } -BOOL LLTaskInvFVBridge::isItemMovable() +BOOL LLTaskInvFVBridge::isItemMovable() const { //LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); //if(object && (object->permModify() || gAgent.isGodlike())) @@ -430,7 +450,7 @@ BOOL LLTaskInvFVBridge::isItemMovable() return TRUE; } -BOOL LLTaskInvFVBridge::isItemRemovable() +BOOL LLTaskInvFVBridge::isItemRemovable() const { LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); // [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a @@ -566,9 +586,8 @@ BOOL LLTaskInvFVBridge::copyToClipboard() const return FALSE; } -BOOL LLTaskInvFVBridge::cutToClipboard() const +void LLTaskInvFVBridge::cutToClipboard() { - return FALSE; } BOOL LLTaskInvFVBridge::isClipboardPasteable() const @@ -643,7 +662,7 @@ BOOL LLTaskInvFVBridge::dragOrDrop(MASK mask, BOOL drop, //} // virtual -void LLTaskInvFVBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLTaskInvFVBridge::performAction(LLInventoryModel* model, std::string action) { if (action == "task_buy") { @@ -720,7 +739,7 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } } } - else + else if (canOpenItem()) { items.push_back(std::string("Task Open")); if (!isItemCopyable()) @@ -780,16 +799,19 @@ public: const std::string& name); virtual LLUIImagePtr getIcon() const; - virtual const std::string& getDisplayName() const { return getName(); } + virtual const std::string& getDisplayName() const; virtual BOOL isItemRenameable() const; + // virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL renameItem(const std::string& new_name); - virtual BOOL isItemRemovable(); + virtual BOOL isItemRemovable() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual BOOL hasChildren() const; virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data); + virtual BOOL canOpenItem() const { return TRUE; } + virtual void openItem(); }; LLTaskCategoryBridge::LLTaskCategoryBridge( @@ -805,6 +827,12 @@ LLUIImagePtr LLTaskCategoryBridge::getIcon() const return LLUI::getUIImage("inv_folder_plain_closed.tga"); } +// virtual +const std::string& LLTaskCategoryBridge::getDisplayName() const +{ + return getName(); +} + BOOL LLTaskCategoryBridge::isItemRenameable() const { return FALSE; @@ -815,7 +843,7 @@ BOOL LLTaskCategoryBridge::renameItem(const std::string& new_name) return FALSE; } -BOOL LLTaskCategoryBridge::isItemRemovable() +BOOL LLTaskCategoryBridge::isItemRemovable() const { return FALSE; } @@ -835,10 +863,14 @@ BOOL LLTaskCategoryBridge::hasChildren() const return FALSE; } +void LLTaskCategoryBridge::openItem() +{ +} + BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; - if(mPanel) + if(mPanel && mUUID.notNull()) { LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) @@ -943,21 +975,13 @@ class LLTaskTextureBridge : public LLTaskInvFVBridge public: LLTaskTextureBridge(LLPanelObjectInventory* panel, const LLUUID& uuid, - LLInventoryType::EType it, const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name), mInventoryType(it){} + LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; + virtual BOOL canOpenItem() const { return TRUE; } virtual void openItem(); -protected: - LLInventoryType::EType mInventoryType; }; -LLUIImagePtr LLTaskTextureBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInventoryType, 0, FALSE); -} - void LLTaskTextureBridge::openItem() { // [RLVa:KB] - Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a @@ -998,18 +1022,13 @@ public: const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; + virtual BOOL canOpenItem() const { return TRUE; } virtual void openItem(); - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void performAction(LLInventoryModel* model, std::string action); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); static void openSoundPreview(void* data); }; - -LLUIImagePtr LLTaskSoundBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); -} void LLTaskSoundBridge::openItem() { openSoundPreview((void*)this); @@ -1037,7 +1056,7 @@ void LLTaskSoundBridge::openSoundPreview(void* data) } // virtual -void LLTaskSoundBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +void LLTaskSoundBridge::performAction(LLInventoryModel* model, std::string action) { if (action == "task_play") { @@ -1047,7 +1066,7 @@ void LLTaskSoundBridge::performAction(LLFolderView* folder, LLInventoryModel* mo send_sound_trigger(item->getAssetUUID(), 1.0); } } - LLTaskInvFVBridge::performAction(folder, model, action); + LLTaskInvFVBridge::performAction(model, action); } void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) @@ -1128,14 +1147,8 @@ public: const LLUUID& uuid, const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; }; -LLUIImagePtr LLTaskLandmarkBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, 0, FALSE); -} - ///---------------------------------------------------------------------------- /// Class LLTaskCallingCardBridge ///---------------------------------------------------------------------------- @@ -1148,14 +1161,9 @@ public: const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; virtual BOOL isItemRenameable() const; virtual BOOL renameItem(const std::string& new_name); }; -LLUIImagePtr LLTaskCallingCardBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, 0, FALSE); -} BOOL LLTaskCallingCardBridge::isItemRenameable() const { @@ -1180,16 +1188,9 @@ public: const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; //static BOOL enableIfCopyable( void* userdata ); }; - -LLUIImagePtr LLTaskScriptBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); -} - class LLTaskLSLBridge : public LLTaskScriptBridge { public: @@ -1198,6 +1199,7 @@ public: const std::string& name) : LLTaskScriptBridge(panel, uuid, name) {} + virtual BOOL canOpenItem() const { return TRUE; } virtual void openItem(); virtual BOOL removeItem(); //virtual void buildContextMenu(LLMenuGL& menu); @@ -1273,22 +1275,8 @@ public: const std::string& name, U32 flags = 0) : LLTaskInvFVBridge(panel, uuid, name, flags) {} - - virtual LLUIImagePtr getIcon() const; }; - -LLUIImagePtr LLTaskObjectBridge::getIcon() const -{ - BOOL item_is_multi = FALSE; - if ( mFlags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) - { - item_is_multi = TRUE; - } - - return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi); -} - ///---------------------------------------------------------------------------- /// Class LLTaskNotecardBridge ///---------------------------------------------------------------------------- @@ -1301,16 +1289,11 @@ public: const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; + virtual BOOL canOpenItem() const { return TRUE; } virtual void openItem(); virtual BOOL removeItem(); }; -LLUIImagePtr LLTaskNotecardBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); -} - void LLTaskNotecardBridge::openItem() { if(LLPreview::show(mUUID)) @@ -1367,16 +1350,11 @@ public: const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; + virtual BOOL canOpenItem() const { return TRUE; } virtual void openItem(); virtual BOOL removeItem(); }; -LLUIImagePtr LLTaskGestureBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); -} - void LLTaskGestureBridge::openItem() { if(LLPreview::show(mUUID)) @@ -1419,16 +1397,11 @@ public: const std::string& name) : LLTaskInvFVBridge(panel, uuid, name) {} - virtual LLUIImagePtr getIcon() const; + virtual BOOL canOpenItem() const { return TRUE; } virtual void openItem(); virtual BOOL removeItem(); }; -LLUIImagePtr LLTaskAnimationBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); -} - void LLTaskAnimationBridge::openItem() { if(LLPreview::show(mUUID)) @@ -1487,19 +1460,15 @@ public: LLTaskWearableBridge(LLPanelObjectInventory* panel, const LLUUID& uuid, const std::string& name, - LLAssetType::EType asset_type, U32 flags) : - LLTaskInvFVBridge(panel, uuid, name, flags), mAssetType(asset_type) {} + LLTaskInvFVBridge(panel, uuid, name, flags) {} virtual LLUIImagePtr getIcon() const; - -protected: - LLAssetType::EType mAssetType; }; LLUIImagePtr LLTaskWearableBridge::getIcon() const { - return LLInventoryIcon::getIcon(mAssetType, LLInventoryType::IT_WEARABLE, mFlags, FALSE ); + return LLInventoryIcon::getIcon(mAssetType, mInventoryType, mFlags, FALSE ); } ///---------------------------------------------------------------------------- @@ -1521,7 +1490,6 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* case LLAssetType::AT_TEXTURE: new_bridge = new LLTaskTextureBridge(panel, object_id, - item->getInventoryType(), object_name); break; case LLAssetType::AT_SOUND: @@ -1549,7 +1517,8 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* case LLAssetType::AT_OBJECT: new_bridge = new LLTaskObjectBridge(panel, object_id, - object_name); + object_name, + itemflags); break; case LLAssetType::AT_NOTECARD: new_bridge = new LLTaskNotecardBridge(panel, @@ -1571,7 +1540,6 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* new_bridge = new LLTaskWearableBridge(panel, object_id, object_name, - type, itemflags); break; case LLAssetType::AT_CATEGORY: @@ -1650,7 +1618,7 @@ void LLPanelObjectInventory::reset() setBorderVisible(FALSE); LLRect dummy_rect(0, 1, 1, 0); - mFolders = new LLFolderView(std::string("task inventory"), NULL, dummy_rect, getTaskUUID(), this); + mFolders = new LLFolderView(std::string("task inventory"), NULL, dummy_rect, getTaskUUID(), this, LLTaskInvFVBridge::createObjectBridge(this, NULL)); // this ensures that we never say "searching..." or "no items found" mFolders->getFilter()->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index fb50d65ce..3a2fc59cb 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -37,12 +37,6 @@ class LLFolderView; class LLFolderViewFolder; class LLViewerObject; -// Utility function to hide all entries except those in the list -class LLMenuGL; -void hide_context_entries(LLMenuGL& menu, - const std::vector &entries_to_show, - const std::vector &disabled_entries); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLPanelObjectInventory // diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index 2e6664071..491cf43f3 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -1882,6 +1882,13 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) return TRUE; } +/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const +{ + LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar); + *new_param = *this; + return new_param; +} + //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h index bed0f2cd1..4b7927564 100644 --- a/indra/newview/llpolymesh.h +++ b/indra/newview/llpolymesh.h @@ -433,6 +433,8 @@ public: // This sets mInfo and calls initialization functions BOOL setInfo(LLPolySkeletalDistortionInfo *info); + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex sex ); diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index e595a3f67..73a0b525c 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -446,10 +446,10 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) } // If we have a vertex mask, just remove it. It will be recreated. - if (param->undoMask(TRUE)) + /*if (param->undoMask(TRUE)) { continue; - } + }*/ LLVector4 *mesh_coords = mesh->getWritableCoords(); LLVector4 *mesh_normals = mesh->getWritableNormals(); @@ -630,6 +630,13 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) return TRUE; } +/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const +{ + LLPolyMorphTarget *new_param = new LLPolyMorphTarget(mMesh); + *new_param = *this; + return new_param; +} + #if 0 // obsolete //----------------------------------------------------------------------------- // parseData() @@ -876,32 +883,10 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 else { // remove effect of previous mask - undoMask(FALSE); - } + F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; - mLastWeight = 0.f; - - mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights); - - apply(mLastSex); -} - -//----------------------------------------------------------------------------- -// undoMask() -//----------------------------------------------------------------------------- -BOOL LLPolyMorphTarget::undoMask(BOOL delete_mask) -{ - if (!mVertMask) + if (maskWeights) { - return FALSE; - } - - // remove effect of previous mask - - LLVector4 *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; - - F32 *mask_weights = mVertMask->getMorphMaskWeights(); - LLVector4 *coords = mMesh->getWritableCoords(); LLVector3 *scaled_normals = mMesh->getScaledNormals(); LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); @@ -909,13 +894,7 @@ BOOL LLPolyMorphTarget::undoMask(BOOL delete_mask) for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++) { - F32 mask_weight = 1.f; - if (mask_weights) - { - mask_weight = mask_weights[vert]; - } - - F32 lastMaskWeight = mLastWeight * mask_weights[vert]; + F32 lastMaskWeight = mLastWeight * maskWeights[vert]; S32 out_vert = mMorphData->mVertexIndices[vert]; // remove effect of existing masked morph @@ -933,18 +912,15 @@ BOOL LLPolyMorphTarget::undoMask(BOOL delete_mask) clothing_weight->mV[VZ] -= clothing_offset.mV[VZ]; } } + } + } // set last weight to 0, since we've removed the effect of this morph mLastWeight = 0.f; - if (delete_mask) - { - delete mVertMask; - mVertMask = NULL; - addPendingMorphMask(); - } + mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights); - return TRUE; + apply(mLastSex); } diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h index 749ac6d97..be7019fdf 100644 --- a/indra/newview/llpolymorph.h +++ b/indra/newview/llpolymorph.h @@ -159,6 +159,8 @@ public: // This sets mInfo and calls initialization functions BOOL setInfo(LLPolyMorphTargetInfo *info); + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex sex ); @@ -172,7 +174,6 @@ public: /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); - BOOL undoMask(BOOL delete_mask); void addPendingMorphMask() { mNumMorphMasksPending++; } protected: diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 5019814e0..afc2a3c77 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -458,9 +458,10 @@ void LLPreview::onBtnCopyToInv(void* userdata) // Copy to inventory if (self->mNotecardInventoryID.notNull()) { - copy_inventory_from_notecard(self->mObjectID, - self->mNotecardInventoryID, - item); + copy_inventory_from_notecard(LLUUID::null, + self->mObjectID, + self->mNotecardInventoryID, + item); } else { diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index dea4215df..45de56e14 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -484,7 +484,7 @@ void LLPreviewNotecard::onClickGetItems(void* user_data) LLInventoryItem* item = static_cast(*iter); if(use_caps) { - copy_inventory_from_notecard(preview->getObjectID(), preview->getNotecardItemID(), item, 0); + copy_inventory_from_notecard(LLUUID::null, preview->getObjectID(), preview->getNotecardItemID(), item, 0); } else { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index f995787b0..7372023e0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -206,6 +206,7 @@ #include "llagentlanguage.h" #include "llwearable.h" #include "llinventorybridge.h" +#include "llappearancemgr.h" #include "llsocks5.h" #include "jcfloaterareasearch.h" @@ -258,6 +259,7 @@ static BOOL gSkipOptionalUpdate = FALSE; static bool gGotUseCircuitCodeAck = false; static std::string sInitialOutfit; static std::string sInitialOutfitGender; // "male" or "female" +static boost::signals2::connection sWearablesLoadedCon; static bool gUseCircuitCallbackCalled = false; @@ -2870,23 +2872,8 @@ bool idle_startup() LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); } - display_startup(); - // We now have an inventory skeleton, so if this is a user's first - // login, we can start setting up their clothing and avatar - // appearance. This helps to avoid the generic "Ruth" avatar in - // the orientation island tutorial experience. JC - if (gAgent.isFirstLogin() - && !sInitialOutfit.empty() // registration set up an outfit - && !sInitialOutfitGender.empty() // and a gender - && gAgentAvatarp // can't wear clothes without object - && !gAgent.isGenderChosen() ) // nothing already loading - { - // Start loading the wearables, textures, gestures - LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); - } - display_startup(); - + // wait precache-delay and for agent's avatar or a lot longer. if(((timeout_frac > 1.f) && isAgentAvatarValid()) || (timeout_frac > 3.f)) @@ -3573,7 +3560,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); - msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatar::processRebakeAvatarTextures); + msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); @@ -3771,44 +3758,79 @@ bool callback_choose_gender(const LLSD& notification, const LLSD& response) void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, const std::string& gender_name ) { - S32 gender = 0; - std::string gestures; + lldebugs << "starting" << llendl; + + // Not going through the processAgentInitialWearables path, so need to set this here. + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + // Initiate creation of COF, since we're also bypassing that. + gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + + ESex gender; if (gender_name == "male") { - gender = OPT_MALE; - gestures = MALE_GESTURES_FOLDER; + lldebugs << "male" << llendl; + gender = SEX_MALE; } else { - gender = OPT_FEMALE; - gestures = FEMALE_GESTURES_FOLDER; + lldebugs << "female" << llendl; + gender = SEX_FEMALE; } + if (!isAgentAvatarValid()) + { + llwarns << "Trying to load an initial outfit for an invalid agent avatar" << llendl; + return; + } + + gAgentAvatarp->setSex(gender); + // try to find the outfit - if not there, create some default // wearables. - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLNameCategoryCollector has_name(outfit_folder_name); - gInventory.collectDescendentsIf(LLUUID::null, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - if (0 == cat_array.count()) + LLUUID cat_id = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + if (cat_id.isNull()) { - gAgentWearables.createStandardWearables(gender); + lldebugs << "standard wearables" << llendl; + gAgentWearables.createStandardWearables(); } else { - wear_outfit_by_name(outfit_folder_name); + sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit); + + bool do_copy = true; + bool do_append = false; + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + LLAppearanceMgr::instance().wearInventoryCategory(cat, do_copy, do_append); + lldebugs << "initial outfit category id: " << cat_id << llendl; } - wear_outfit_by_name(gestures); - wear_outfit_by_name(COMMON_GESTURES_FOLDER); // This is really misnamed -- it means we have started loading // an outfit/shape that will give the avatar a gender eventually. JC gAgent.setGenderChosen(TRUE); +} +//static +void LLStartUp::saveInitialOutfit() +{ + if (sInitialOutfit.empty()) { + lldebugs << "sInitialOutfit is empty" << llendl; + return; + } + + if (sWearablesLoadedCon.connected()) + { + lldebugs << "sWearablesLoadedCon is connected, disconnecting" << llendl; + sWearablesLoadedCon.disconnect(); + } + lldebugs << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << llendl; + LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false); +} + +std::string& LLStartUp::getInitialOutfitName() +{ + return sInitialOutfit; } // Loads a bitmap to display during load diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index 2574f0907..0d79293af 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -110,6 +110,11 @@ public: static void loadInitialOutfit( const std::string& outfit_folder_name, const std::string& gender_name ); + //save loaded initial outfit into My Outfits category + static void saveInitialOutfit(); + + static std::string& getInitialOutfitName(); + // Load MD5 of user's password from local disk file. static std::string loadPasswordFromDisk(); diff --git a/indra/newview/lltexglobalcolor.cpp b/indra/newview/lltexglobalcolor.cpp new file mode 100644 index 000000000..ebe5ccd6c --- /dev/null +++ b/indra/newview/lltexglobalcolor.cpp @@ -0,0 +1,152 @@ +/** + * @file lltexlayerglobalcolor.cpp + * @brief Color for texture layers. + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "lltexlayer.h" +#include "llvoavatar.h" +#include "llwearable.h" +#include "lltexglobalcolor.h" + +//----------------------------------------------------------------------------- +// LLTexGlobalColor +//----------------------------------------------------------------------------- + +LLTexGlobalColor::LLTexGlobalColor(LLVOAvatar* avatar) + : + mAvatar(avatar), + mInfo(NULL) +{ +} + +LLTexGlobalColor::~LLTexGlobalColor() +{ + // mParamColorList are LLViewerVisualParam's and get deleted with ~LLCharacter() + //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer()); +} + +BOOL LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info) +{ + llassert(mInfo == NULL); + mInfo = info; + //mID = info->mID; // No ID + + mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size()); + for (param_color_info_list_t::iterator iter = mInfo->mParamColorInfoList.begin(); + iter != mInfo->mParamColorInfoList.end(); + iter++) + { + LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this); + if (!param_color->setInfo(*iter, TRUE)) + { + mInfo = NULL; + return FALSE; + } + mParamGlobalColorList.push_back(param_color); + } + + return TRUE; +} + +LLColor4 LLTexGlobalColor::getColor() const +{ + // Sum of color params + if (mParamGlobalColorList.empty()) + return LLColor4(1.f, 1.f, 1.f, 1.f); + + LLColor4 net_color(0.f, 0.f, 0.f, 0.f); + LLTexLayer::calculateTexLayerColor(mParamGlobalColorList, net_color); + return net_color; +} + +const std::string& LLTexGlobalColor::getName() const +{ + return mInfo->mName; +} + +//----------------------------------------------------------------------------- +// LLTexParamGlobalColor +//----------------------------------------------------------------------------- +LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) : + LLTexLayerParamColor(tex_global_color->getAvatar()), + mTexGlobalColor(tex_global_color) +{ +} + +/*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const +{ + LLTexParamGlobalColor *new_param = new LLTexParamGlobalColor(mTexGlobalColor); + *new_param = *this; + return new_param; +} + +void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake) +{ + mAvatar->onGlobalColorChanged(mTexGlobalColor, upload_bake); +} + +//----------------------------------------------------------------------------- +// LLTexGlobalColorInfo +//----------------------------------------------------------------------------- + +LLTexGlobalColorInfo::LLTexGlobalColorInfo() +{ +} + + +LLTexGlobalColorInfo::~LLTexGlobalColorInfo() +{ + for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer()); +} + +BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node) +{ + // name attribute + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!node->getFastAttributeString(name_string, mName)) + { + llwarns << " element is missing name attribute." << llendl; + return FALSE; + } + // sub-element + for (LLXmlTreeNode* child = node->getChildByName("param"); + child; + child = node->getNextNamedChild()) + { + if (child->getChildByName("param_color")) + { + // + LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo(); + if (!info->parseXml(child)) + { + delete info; + return FALSE; + } + mParamColorInfoList.push_back(info); + } + } + return TRUE; +} diff --git a/indra/newview/lltexglobalcolor.h b/indra/newview/lltexglobalcolor.h new file mode 100644 index 000000000..ae0479844 --- /dev/null +++ b/indra/newview/lltexglobalcolor.h @@ -0,0 +1,83 @@ +/** + * @file lltexglobalcolor.h + * @brief This is global texture color info used by llvoavatar. + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXGLOBALCOLOR_H +#define LL_LLTEXGLOBALCOLOR_H + +#include "lltexlayer.h" +#include "lltexlayerparams.h" + +class LLVOAvatar; +class LLWearable; +class LLTexGlobalColorInfo; + +class LLTexGlobalColor +{ +public: + LLTexGlobalColor( LLVOAvatar* avatar ); + ~LLTexGlobalColor(); + + LLTexGlobalColorInfo* getInfo() const { return mInfo; } + // This sets mInfo and calls initialization functions + BOOL setInfo(LLTexGlobalColorInfo *info); + + LLVOAvatar* getAvatar() const { return mAvatar; } + LLColor4 getColor() const; + const std::string& getName() const; + +private: + param_color_list_t mParamGlobalColorList; + LLVOAvatar* mAvatar; // just backlink, don't LLPointer + LLTexGlobalColorInfo *mInfo; +}; + +// Used by llvoavatar to determine skin/eye/hair color. +class LLTexGlobalColorInfo +{ + friend class LLTexGlobalColor; +public: + LLTexGlobalColorInfo(); + ~LLTexGlobalColorInfo(); + + BOOL parseXml(LLXmlTreeNode* node); + +private: + param_color_info_list_t mParamColorInfoList; + std::string mName; +}; + +class LLTexParamGlobalColor : public LLTexLayerParamColor +{ +public: + LLTexParamGlobalColor(LLTexGlobalColor *tex_color); + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; +protected: + /*virtual*/ void onGlobalColorChanged(bool upload_bake); +private: + LLTexGlobalColor* mTexGlobalColor; +}; + +#endif diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 9bd5ebf94..b55346c02 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -32,97 +32,120 @@ #include "llviewerprecompiledheaders.h" -#include "imageids.h" +#include "lltexlayer.h" + #include "llagent.h" -#include "llagentcamera.h" -#include "llagentwearables.h" -#include "llcrc.h" -#include "lldir.h" -#include "llglheaders.h" -#include "llimagebmp.h" #include "llimagej2c.h" #include "llimagetga.h" -#include "llpolymorph.h" -#include "llquantize.h" -#include "lltexlayer.h" -#include "llui.h" +#include "llnotificationsutil.h" #include "llvfile.h" -#include "llviewertexturelist.h" -#include "llviewertexturelist.h" -#include "llviewerregion.h" +#include "llvfs.h" #include "llviewerstats.h" -#include "llviewerwindow.h" +#include "llviewerregion.h" +#include "llvoavatar.h" #include "llvoavatarself.h" -#include "llxmltree.h" #include "pipeline.h" -#include "v4coloru.h" -#include "llrender.h" #include "llassetuploadresponders.h" +#include "lltexlayerparams.h" +#include "llui.h" +#include "llagentwearables.h" +#include "llwearable.h" +#include "llviewercontrol.h" #include "llviewershadermgr.h" +#include "llviewervisualparam.h" //#include "../tools/imdebug/imdebug.h" using namespace LLVOAvatarDefines; -const S32 MAX_BAKE_UPLOAD_ATTEMPTS = 4; +static const S32 BAKE_UPLOAD_ATTEMPTS = 7; +static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power of 2 each attempt -// static -S32 LLTexLayerSetBuffer::sGLByteCount = 0; +class LLTexLayerInfo +{ + friend class LLTexLayer; + friend class LLTexLayerTemplate; + friend class LLTexLayerInterface; +public: + LLTexLayerInfo(); + ~LLTexLayerInfo(); + + BOOL parseXml(LLXmlTreeNode* node); + BOOL createVisualParams(LLVOAvatar *avatar); + BOOL isUserSettable() { return mLocalTexture != -1; } + S32 getLocalTexture() const { return mLocalTexture; } + BOOL getOnlyAlpha() const { return mUseLocalTextureAlphaOnly; } + std::string getName() const { return mName; } + +private: + std::string mName; + + BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer, + LLTexLayerInterface::ERenderPass mRenderPass; + + std::string mGlobalColor; + LLColor4 mFixedColor; + + S32 mLocalTexture; + std::string mStaticImageFileName; + BOOL mStaticImageIsMask; + BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask + BOOL mIsVisibilityMask; + + typedef std::vector< std::pair< std::string,BOOL > > morph_name_list_t; + morph_name_list_t mMorphNameList; + param_color_info_list_t mParamColorInfoList; + param_alpha_info_list_t mParamAlphaInfoList; +}; //----------------------------------------------------------------------------- // LLBakedUploadData() //----------------------------------------------------------------------------- -LLBakedUploadData::LLBakedUploadData( LLVOAvatar* avatar, - LLTexLayerSet* layerset, - LLTexLayerSetBuffer* layerset_buffer, - const LLUUID & id ) : - mAvatar( avatar ), - mTexLayerSet( layerset ), - mLayerSetBuffer( layerset_buffer ), - mID(id) +LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar, + LLTexLayerSet* layerset, + const LLUUID& id, + bool highest_res) : + mAvatar(avatar), + mTexLayerSet(layerset), + mID(id), + mStartTime(LLFrameTimer::getTotalTime()), // Record starting time + mIsHighestRes(highest_res) { - mStartTime = LLFrameTimer::getTotalTime(); // Record starting time - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) - { - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE - if( wearable ) - { - mWearableAssets[i] = wearable->getAssetID(); - } - } } //----------------------------------------------------------------------------- // LLTexLayerSetBuffer // The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one. //----------------------------------------------------------------------------- -LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* owner, S32 width, S32 height) - : + +// static +S32 LLTexLayerSetBuffer::sGLByteCount = 0; + +LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner, + S32 width, S32 height) : // ORDER_LAST => must render these after the hints are created. LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ), - mNeedsUpdate( TRUE ), - mNeedsUpload( FALSE ), - mUploadPending( FALSE ), // Not used for any logic here, just to sync sending of updates - mUploadFailCount( 0 ), - mUploadAfter( 0 ), - mTexLayerSet( owner ) + mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates + mNeedsUpload(FALSE), + mNumLowresUploads(0), + mUploadFailCount(0), + mNeedsUpdate(TRUE), + mNumLowresUpdates(0), + mTexLayerSet(owner) { LLTexLayerSetBuffer::sGLByteCount += getSize(); + mNeedsUploadTimer.start(); + mNeedsUpdateTimer.start(); } LLTexLayerSetBuffer::~LLTexLayerSetBuffer() { LLTexLayerSetBuffer::sGLByteCount -= getSize(); destroyGLTexture(); - for (S32 order = 0; order < ORDER_COUNT; order++) + for( S32 order = 0; order < ORDER_COUNT; order++ ) { LLViewerDynamicTexture::sInstances[order].erase(this); // will fail in all but one case. } - if (mTexLayerSet->mComposite == this) - { - // Destroy the pointer on this now gone buffer. - mTexLayerSet->mComposite = NULL; - } } //virtual @@ -151,8 +174,9 @@ void LLTexLayerSetBuffer::dumpTotalByteCount() void LLTexLayerSetBuffer::requestUpdate() { + restartUpdateTimer(); mNeedsUpdate = TRUE; - + mNumLowresUpdates = 0; // If we're in the middle of uploading a baked texture, we don't care about it any more. // When it's downloaded, ignore it. mUploadID.setNull(); @@ -160,40 +184,40 @@ void LLTexLayerSetBuffer::requestUpdate() void LLTexLayerSetBuffer::requestUpload() { - if (!mNeedsUpload) + conditionalRestartUploadTimer(); + mNeedsUpload = TRUE; + mNumLowresUploads = 0; + mUploadPending = TRUE; +} + +void LLTexLayerSetBuffer::conditionalRestartUploadTimer() +{ + // If we requested a new upload but haven't even uploaded + // a low res version of our last upload request, then + // keep the timer ticking instead of resetting it. + if (mNeedsUpload && (mNumLowresUploads == 0)) { - mNeedsUpload = TRUE; - mUploadPending = TRUE; - mUploadAfter = 0; + mNeedsUploadTimer.unpause(); + } + else + { + mNeedsUploadTimer.reset(); + mNeedsUploadTimer.start(); } } -// request an upload to start delay_usec microseconds from now -void LLTexLayerSetBuffer::requestDelayedUpload(U64 delay_usec) +void LLTexLayerSetBuffer::restartUpdateTimer() { - if (!mNeedsUpload) - { - mNeedsUpload = TRUE; - mUploadPending = TRUE; - mUploadAfter = LLFrameTimer::getTotalTime() + delay_usec; - } + mNeedsUpdateTimer.reset(); + mNeedsUpdateTimer.start(); } void LLTexLayerSetBuffer::cancelUpload() { - if (mNeedsUpload) - { - mNeedsUpload = FALSE; - } + mNeedsUpload = FALSE; mUploadPending = FALSE; - mUploadAfter = 0; -} - -// do we need to upload, and do we have sufficient data to create an uploadable composite? -BOOL LLTexLayerSetBuffer::needsUploadNow() const -{ - BOOL upload = mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal() && gAgentQueryManager.hasNoPendingQueries(); - return (upload && (LLFrameTimer::getTotalTime() > mUploadAfter)); + mNeedsUploadTimer.pause(); + mUploadRetryTimer.reset(); } void LLTexLayerSetBuffer::pushProjection() const @@ -219,26 +243,34 @@ void LLTexLayerSetBuffer::popProjection() const BOOL LLTexLayerSetBuffer::needsRender() { - LLVOAvatar* avatar = mTexLayerSet->getAvatar(); - BOOL upload_now = needsUploadNow(); - BOOL needs_update = (mNeedsUpdate || upload_now) && !avatar->getIsAppearanceAnimating(); - if (needs_update) + llassert(mTexLayerSet->getAvatar() == gAgentAvatarp); + if (!isAgentAvatarValid()) return FALSE; + + const BOOL upload_now = mNeedsUpload && isReadyToUpload(); + const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); + + // Don't render if we don't want to (or aren't ready to) upload or update. + if (!(update_now || upload_now)) { - BOOL invalid_skirt = avatar->getBakedTE(mTexLayerSet) == TEX_SKIRT_BAKED && !avatar->isWearingWearableType(LLWearableType::WT_SKIRT); - if (invalid_skirt) - { - // we were trying to create a skirt texture - // but we're no longer wearing a skirt... - needs_update = FALSE; - cancelUpload(); - } - else - { - needs_update &= (avatar->isSelf() || (avatar->isVisible() && !avatar->isCulled())); - needs_update &= mTexLayerSet->isLocalTextureDataAvailable(); - } + return FALSE; } - return needs_update; + + // Don't render if we're animating our appearance. + if (gAgentAvatarp->getIsAppearanceAnimating()) + { + return FALSE; + } + + // Don't render if we are trying to create a shirt texture but aren't wearing a skirt. + if (gAgentAvatarp->getBakedTE(mTexLayerSet) == LLVOAvatarDefines::TEX_SKIRT_BAKED && + !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) + { + cancelUpload(); + return FALSE; + } + + // Render if we have at least minimal level of detail for each local texture. + return mTexLayerSet->isLocalTextureDataAvailable(); } void LLTexLayerSetBuffer::preRender(BOOL clear_depth) @@ -263,8 +295,10 @@ BOOL LLTexLayerSetBuffer::render() gGL.setColorMask(true, true); // do we need to upload, and do we have sufficient data to create an uploadable composite? - // When do we upload the texture if gAgent.mNumPendingQueries is non-zero? - BOOL upload_now = needsUploadNow(); + // TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero? + const BOOL upload_now = mNeedsUpload && isReadyToUpload(); + const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); + BOOL success = TRUE; bool use_shaders = LLGLSLShader::sNoFixedFunction; @@ -282,32 +316,35 @@ BOOL LLTexLayerSetBuffer::render() success &= mTexLayerSet->render( mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight ); gGL.flush(); - if( upload_now ) + if(upload_now) { if (!success) { - llinfos << "Failed attempt to bake " << mTexLayerSet->getBodyRegion() << llendl; + llinfos << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << llendl; mUploadPending = FALSE; } else { if (mTexLayerSet->isVisible()) { - readBackAndUpload(); + mTexLayerSet->getAvatar()->debugBakedTextureUpload(mTexLayerSet->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish. + doUpload(); } else { mUploadPending = FALSE; mNeedsUpload = FALSE; - LLVOAvatar* avatar = mTexLayerSet->getAvatar(); - if (avatar) - { - avatar->setNewBakedTexture(avatar->getBakedTE(mTexLayerSet), IMG_INVISIBLE); - llinfos << "Invisible baked texture set for " << mTexLayerSet->getBodyRegion() << llendl; - } + mNeedsUploadTimer.pause(); + mTexLayerSet->getAvatar()->setNewBakedTexture(mTexLayerSet->getBakedTexIndex(),IMG_INVISIBLE); } } } + + if (update_now) + { + doUpdate(); + } + if (use_shaders) { gAlphaMaskProgram.unbind(); @@ -321,17 +358,92 @@ BOOL LLTexLayerSetBuffer::render() // we have valid texture data now mGLTexturep->setGLTextureCreated(true); - mNeedsUpdate = FALSE; return success; } -bool LLTexLayerSetBuffer::isInitialized(void) const +BOOL LLTexLayerSetBuffer::isInitialized(void) const { return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated(); } -BOOL LLTexLayerSetBuffer::updateImmediate() +BOOL LLTexLayerSetBuffer::uploadPending() const +{ + return mUploadPending; +} + +BOOL LLTexLayerSetBuffer::uploadNeeded() const +{ + return mNeedsUpload; +} + +BOOL LLTexLayerSetBuffer::uploadInProgress() const +{ + return !mUploadID.isNull(); +} + +BOOL LLTexLayerSetBuffer::isReadyToUpload() const +{ + if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries. + if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) return FALSE; // Don't upload if avatar is using composites. + + BOOL ready = FALSE; + if (mTexLayerSet->isLocalTextureDataFinal()) + { + // If we requested an upload and have the final LOD ready, upload (or wait a while if this is a retry) + if (mUploadFailCount == 0) + { + ready = TRUE; + } + else + { + ready = mUploadRetryTimer.getElapsedTimeF32() >= BAKE_UPLOAD_RETRY_DELAY * (1 << (mUploadFailCount - 1)); + } + } + else + { + // Upload if we've hit a timeout. Upload is a pretty expensive process so we need to make sure + // we aren't doing uploads too frequently. + const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout"); + if (texture_timeout != 0) + { + // The timeout period increases exponentially between every lowres upload in order to prevent + // spamming the server with frequent uploads. + const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads); + + // If we hit our timeout and have textures available at even lower resolution, then upload. + const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold; + const BOOL has_lower_lod = mTexLayerSet->isLocalTextureDataAvailable(); + ready = has_lower_lod && is_upload_textures_timeout; + } + } + + return ready; +} + +BOOL LLTexLayerSetBuffer::isReadyToUpdate() const +{ + // If we requested an update and have the final LOD ready, then update. + if (mTexLayerSet->isLocalTextureDataFinal()) return TRUE; + + // If we haven't done an update yet, then just do one now regardless of state of textures. + if (mNumLowresUpdates == 0) return TRUE; + + // Update if we've hit a timeout. Unlike for uploads, we can make this timeout fairly small + // since render unnecessarily doesn't cost much. + const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedLocalTextureUpdateTimeout"); + if (texture_timeout != 0) + { + // If we hit our timeout and have textures available at even lower resolution, then update. + const BOOL is_update_textures_timeout = mNeedsUpdateTimer.getElapsedTimeF32() >= texture_timeout; + const BOOL has_lower_lod = mTexLayerSet->isLocalTextureDataAvailable(); + if (has_lower_lod && is_update_textures_timeout) return TRUE; + } + + return FALSE; +} + +BOOL LLTexLayerSetBuffer::requestUpdateImmediate() { mNeedsUpdate = TRUE; BOOL result = FALSE; @@ -346,9 +458,11 @@ BOOL LLTexLayerSetBuffer::updateImmediate() return result; } -void LLTexLayerSetBuffer::readBackAndUpload() +// Create the baked texture, send it out to the server, then wait for it to come +// back so we can switch to using it. +void LLTexLayerSetBuffer::doUpload() { - llinfos << "Baked " << mTexLayerSet->getBodyRegion() << llendl; + llinfos << "Uploading baked " << mTexLayerSet->getBodyRegionName() << llendl; LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_BAKES); // Don't need caches since we're baked now. (note: we won't *really* be baked @@ -362,15 +476,13 @@ void LLTexLayerSetBuffer::readBackAndUpload() // Get the MASK information from our texture LLGLSUIDefault gls_ui; - LLPointer baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 ); U8* baked_mask_data = baked_mask_image->getData(); - - mTexLayerSet->gatherAlphaMasks(baked_mask_data, mFullWidth, mFullHeight); -// imdebug("lum b=8 w=%d h=%d %p", mWidth, mHeight, baked_mask_data); + mTexLayerSet->gatherMorphMaskAlpha(baked_mask_data, mFullWidth, mFullHeight); - S32 baked_image_components = 5; // red green blue bump clothing + // Create the baked image from our color and mask information + const S32 baked_image_components = 5; // red green blue [bump] clothing LLPointer baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components ); U8* baked_image_data = baked_image->getData(); S32 i = 0; @@ -378,11 +490,11 @@ void LLTexLayerSetBuffer::readBackAndUpload() { for (S32 v=0; v < mFullHeight; v++) { - baked_image_data[5 * i + 0] = baked_color_data[4 * i + 0]; - baked_image_data[5 * i + 1] = baked_color_data[4 * i + 1]; - baked_image_data[5 * i + 2] = baked_color_data[4 * i + 2]; - baked_image_data[5 * i + 3] = baked_color_data[4 * i + 3]; // alpha should be correct for eyelashes. - baked_image_data[5 * i + 4] = baked_mask_data[i]; + baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; + baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; + baked_image_data[5*i + 2] = baked_color_data[4*i + 2]; + baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes. + baked_image_data[5*i + 4] = baked_mask_data[i]; i++; } } @@ -412,17 +524,22 @@ void LLTexLayerSetBuffer::readBackAndUpload() integrity_test->setLastError("Unable to read entire file"); } - if( valid ) + if (valid) { - // baked_upload_data is owned by the responder and deleted after the request completes - LLBakedUploadData* baked_upload_data = - new LLBakedUploadData( gAgentAvatarp, this->mTexLayerSet, this, asset_id ); + const bool highest_lod = mTexLayerSet->isLocalTextureDataFinal(); + // Baked_upload_data is owned by the responder and deleted after the request completes. + LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp, + this->mTexLayerSet, + asset_id, + highest_lod); + // upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit. mUploadID = asset_id; - + // Upload the image const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); if(!url.empty() - && !LLPipeline::sForceOldBakedUpload) // toggle debug setting UploadBakedTexOld to change between the new caps method and old method + && !LLPipeline::sForceOldBakedUpload // toggle debug setting UploadBakedTexOld to change between the new caps method and old method + && (mUploadFailCount < (BAKE_UPLOAD_ATTEMPTS - 1))) // Try last ditch attempt via asset store if cap upload is failing. { LLSD body = LLSD::emptyMap(); // The responder will call LLTexLayerSetBuffer::onTextureUploadComplete() @@ -440,8 +557,34 @@ void LLTexLayerSetBuffer::readBackAndUpload() TRUE); // store_local llinfos << "Baked texture upload via Asset Store." << llendl; } - - mNeedsUpload = FALSE; + + if (highest_lod) + { + // Sending the final LOD for the baked texture. All done, pause + // the upload timer so we know how long it took. + mNeedsUpload = FALSE; + mNeedsUploadTimer.pause(); + } + else + { + // Sending a lower level LOD for the baked texture. Restart the upload timer. + mNumLowresUploads++; + mNeedsUploadTimer.unpause(); + mNeedsUploadTimer.reset(); + } + + // Print out notification that we uploaded this texture. + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + const std::string lod_str = highest_lod ? "HighRes" : "LowRes"; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mTexLayerSet->getAvatar()->debugGetExistenceTimeElapsedF32()); + args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32()); + args["BODYREGION"] = mTexLayerSet->getBodyRegionName(); + args["RESOLUTION"] = lod_str; + LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args); + llinfos << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << llendl; + } } else { @@ -463,6 +606,40 @@ void LLTexLayerSetBuffer::readBackAndUpload() delete [] baked_color_data; } +// Mostly bookkeeping; don't need to actually "do" anything since +// render() will actually do the update. +void LLTexLayerSetBuffer::doUpdate() +{ + const BOOL highest_lod = mTexLayerSet->isLocalTextureDataFinal(); + if (highest_lod) + { + mNeedsUpdate = FALSE; + } + else + { + mNumLowresUpdates++; + } + + restartUpdateTimer(); + + // need to swtich to using this layerset if this is the first update + // after getting the lowest LOD + mTexLayerSet->getAvatar()->updateMeshTextures(); + + // Print out notification that we uploaded this texture. + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + const BOOL highest_lod = mTexLayerSet->isLocalTextureDataFinal(); + const std::string lod_str = highest_lod ? "HighRes" : "LowRes"; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mTexLayerSet->getAvatar()->debugGetExistenceTimeElapsedF32()); + args["TIME"] = llformat("%d",(U32)mNeedsUpdateTimer.getElapsedTimeF32()); + args["BODYREGION"] = mTexLayerSet->getBodyRegionName(); + args["RESOLUTION"] = lod_str; + LLNotificationsUtil::add("AvatarRezSelfBakedTextureUpdateNotification",args); + llinfos << "Locally updating [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUpdateTimer.getElapsedTimeF32() << " ]" << llendl; + } +} // static void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, @@ -472,8 +649,7 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, { LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata; - if ((result == 0) && - isAgentAvatarValid() && + if (isAgentAvatarValid() && !gAgentAvatarp->isDead() && (baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures. (baked_upload_data->mTexLayerSet->hasComposite())) @@ -497,31 +673,28 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, { // This is the upload we're currently waiting for. layerset_buffer->mUploadID.setNull(); - layerset_buffer->mUploadPending = FALSE; - + const std::string name(baked_upload_data->mTexLayerSet->getBodyRegionName()); + const std::string resolution = baked_upload_data->mIsHighestRes ? " full res " : " low res "; if (result >= 0) { - ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->mTexLayerSet); + layerset_buffer->mUploadPending = FALSE; // Allows sending of AgentSetAppearance later + LLVOAvatarDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->mTexLayerSet); + // Update baked texture info with the new UUID U64 now = LLFrameTimer::getTotalTime(); // Record starting time - llinfos << "Baked texture upload took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << llendl; + llinfos << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << llendl; gAgentAvatarp->setNewBakedTexture(baked_te, uuid); } else { ++failures; - llinfos << "Baked upload failed (attempt " << failures << "/" << MAX_BAKE_UPLOAD_ATTEMPTS << "), "; - if (failures >= MAX_BAKE_UPLOAD_ATTEMPTS) + S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes + llwarns << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << llendl; + if (failures < max_attempts) { - llcont << "giving up."; - } - else - { - const F32 delay = 5.f; - llcont << llformat("retrying in %.2f seconds.", delay); layerset_buffer->mUploadFailCount = failures; - layerset_buffer->requestDelayedUpload((U64)(delay * 1000000)); + layerset_buffer->mUploadRetryTimer.start(); + layerset_buffer->requestUpload(); } - llcont << llendl; } } else @@ -531,16 +704,17 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, gAgentAvatarp->dirtyMesh(); } - else - { + else + { + // Baked texture failed to upload (in which case since we // didn't set the new baked texture, it means that they'll try // and rebake it at some point in the future (after login?)), // or this response to upload is out of date, in which case a // current response should be on the way or already processed. - llwarns << "Baked upload failed" << llendl; - } - - delete baked_upload_data; + llwarns << "Baked upload failed" << llendl; + } + + delete baked_upload_data; } //----------------------------------------------------------------------------- @@ -548,8 +722,7 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, // An ordered set of texture layers that get composited into a single texture. //----------------------------------------------------------------------------- -LLTexLayerSetInfo::LLTexLayerSetInfo( ) - : +LLTexLayerSetInfo::LLTexLayerSetInfo() : mBodyRegion( "" ), mWidth( 512 ), mHeight( 512 ), @@ -614,6 +787,19 @@ BOOL LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node) return TRUE; } +// creates visual params without generating layersets or layers +void LLTexLayerSetInfo::createVisualParams(LLVOAvatar *avatar) +{ + //layer_info_list_t mLayerInfoList; + for (layer_info_list_t::iterator layer_iter = mLayerInfoList.begin(); + layer_iter != mLayerInfoList.end(); + layer_iter++) + { + LLTexLayerInfo *layer_info = *layer_iter; + layer_info->createVisualParams(avatar); + } +} + //----------------------------------------------------------------------------- // LLTexLayerSet // An ordered set of texture layers that get composited into a single texture. @@ -621,13 +807,12 @@ BOOL LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node) BOOL LLTexLayerSet::sHasCaches = FALSE; -LLTexLayerSet::LLTexLayerSet( LLVOAvatar* avatar ) - : +LLTexLayerSet::LLTexLayerSet(LLVOAvatarSelf* const avatar) : mComposite( NULL ), mAvatar( avatar ), mUpdatesEnabled( FALSE ), - mIsVisible(TRUE), - mBakedTexIndex(BAKED_HEAD), + mIsVisible( TRUE ), + mBakedTexIndex(LLVOAvatarDefines::BAKED_HEAD), mInfo( NULL ) { } @@ -637,32 +822,41 @@ LLTexLayerSet::~LLTexLayerSet() deleteCaches(); std::for_each(mLayerList.begin(), mLayerList.end(), DeletePointer()); std::for_each(mMaskLayerList.begin(), mMaskLayerList.end(), DeletePointer()); - mComposite = NULL; } //----------------------------------------------------------------------------- // setInfo //----------------------------------------------------------------------------- -BOOL LLTexLayerSet::setInfo(LLTexLayerSetInfo *info) +BOOL LLTexLayerSet::setInfo(const LLTexLayerSetInfo *info) { llassert(mInfo == NULL); mInfo = info; //mID = info->mID; // No ID - LLTexLayerSetInfo::layer_info_list_t::iterator iter; mLayerList.reserve(info->mLayerInfoList.size()); - for (iter = info->mLayerInfoList.begin(); iter != info->mLayerInfoList.end(); iter++) + for (LLTexLayerSetInfo::layer_info_list_t::const_iterator iter = info->mLayerInfoList.begin(); + iter != info->mLayerInfoList.end(); + iter++) { - LLTexLayer* layer = new LLTexLayer( this ); - if (!layer->setInfo(*iter)) + LLTexLayerInterface *layer = NULL; + if ( (*iter)->isUserSettable() ) + { + layer = new LLTexLayerTemplate( this ); + } + else + { + layer = new LLTexLayer(this); + } + // this is the first time this layer (of either type) is being created - make sure you add the parameters to the avatar + if (!layer->setInfo(*iter, NULL)) { mInfo = NULL; return FALSE; } if (!layer->isVisibilityMask()) { - mLayerList.push_back(layer); + mLayerList.push_back( layer ); } else { @@ -704,50 +898,238 @@ void LLTexLayerSet::deleteCaches() { for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { - LLTexLayer* layer = *iter; + LLTexLayerInterface* layer = *iter; layer->deleteCaches(); } for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) { - LLTexLayer* layer = *iter; + LLTexLayerInterface* layer = *iter; layer->deleteCaches(); } } // Returns TRUE if at least one packet of data has been received for each of the textures that this layerset depends on. -BOOL LLTexLayerSet::isLocalTextureDataAvailable() +BOOL LLTexLayerSet::isLocalTextureDataAvailable() const { - return mAvatar->isLocalTextureDataAvailable( this ); + if (!mAvatar->isSelf()) return FALSE; + return ((LLVOAvatarSelf *)mAvatar)->isLocalTextureDataAvailable(this); } // Returns TRUE if all of the data for the textures that this layerset depends on have arrived. -BOOL LLTexLayerSet::isLocalTextureDataFinal() +BOOL LLTexLayerSet::isLocalTextureDataFinal() const { - return mAvatar->isLocalTextureDataFinal( this ); + if (!mAvatar->isSelf()) return FALSE; + return ((LLVOAvatarSelf *)mAvatar)->isLocalTextureDataFinal(this); } +BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) +{ + BOOL success = TRUE; + mIsVisible = TRUE; + + if (mMaskLayerList.size() > 0) + { + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + { + LLTexLayerInterface* layer = *iter; + if (layer->isInvisibleAlphaMask()) + { + mIsVisible = FALSE; + } + } + } + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + LLGLSUIDefault gls_ui; + LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); + gGL.setColorMask(true, true); + + // clear buffer area to ensure we don't pick up UI elements + { + gGL.flush(); + LLGLDisable no_alpha(GL_ALPHA_TEST); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.0f); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f( 0.f, 0.f, 0.f, 1.f ); + + gl_rect_2d_simple( width, height ); + + gGL.flush(); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + + if (mIsVisible) + { + // composite color layers + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + if (layer->getRenderPass() == LLTexLayer::RP_COLOR) + { + gGL.flush(); + success &= layer->render(x, y, width, height); + gGL.flush(); + } + } + + renderAlphaMaskTextures(x, y, width, height, false); + + stop_glerror(); + } + else + { + gGL.flush(); + + gGL.setSceneBlendType(LLRender::BT_REPLACE); + LLGLDisable no_alpha(GL_ALPHA_TEST); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f( 0.f, 0.f, 0.f, 0.f ); + + gl_rect_2d_simple( width, height ); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + gGL.flush(); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + + return success; +} + + +BOOL LLTexLayerSet::isBodyRegion(const std::string& region) const +{ + return mInfo->mBodyRegion == region; +} + +const std::string LLTexLayerSet::getBodyRegionName() const +{ + return mInfo->mBodyRegion; +} + +void LLTexLayerSet::requestUpdate() +{ + if( mUpdatesEnabled ) + { + createComposite(); + mComposite->requestUpdate(); + } +} + +void LLTexLayerSet::requestUpload() +{ + createComposite(); + mComposite->requestUpload(); +} + +void LLTexLayerSet::cancelUpload() +{ + if(mComposite) + { + mComposite->cancelUpload(); + } +} + +void LLTexLayerSet::createComposite() +{ + if(!mComposite) + { + S32 width = mInfo->mWidth; + S32 height = mInfo->mHeight; + // Composite other avatars at reduced resolution + if( !mAvatar->isSelf() ) + { + llerrs << "composites should not be created for non-self avatars!" << llendl; + } + mComposite = new LLTexLayerSetBuffer( this, width, height ); + } +} + +void LLTexLayerSet::destroyComposite() +{ + if( mComposite ) + { + mComposite = NULL; + } +} + +void LLTexLayerSet::setUpdatesEnabled( BOOL b ) +{ + mUpdatesEnabled = b; +} + + +void LLTexLayerSet::updateComposite() +{ + createComposite(); + mComposite->requestUpdateImmediate(); +} + +LLTexLayerSetBuffer* LLTexLayerSet::getComposite() +{ + if (!mComposite) + { + createComposite(); + } + return mComposite; +} + +const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const +{ + return mComposite; +} + +void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 width, S32 height) +{ + memset(data, 255, width * height); + + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + layer->gatherAlphaMasks(data, mComposite->getOriginX(),mComposite->getOriginY(), width, height); + } + + // Set alpha back to that of our alpha masks. + renderAlphaMaskTextures(mComposite->getOriginX(), mComposite->getOriginY(), width, height, true); +} + void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear) { const LLTexLayerSetInfo *info = getInfo(); + bool use_shaders = LLGLSLShader::sNoFixedFunction; gGL.setColorMask(false, true); gGL.setSceneBlendType(LLRender::BT_REPLACE); - + // (Optionally) replace alpha with a single component image from a tga file. if (!info->mStaticAlphaFileName.empty()) { gGL.flush(); { - LLViewerTexture* tex = gTexStaticImageList.getTexture(info->mStaticAlphaFileName, TRUE); - if (tex) + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(info->mStaticAlphaFileName, TRUE); + if( tex ) { LLGLSUIDefault gls_ui; gGL.getTexUnit(0)->bind(tex); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_REPLACE); - gl_rect_2d_simple_tex(width, height); + gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); + gl_rect_2d_simple_tex( width, height ); } } gGL.flush(); @@ -778,225 +1160,61 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, if (mMaskLayerList.size() > 0) { gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_REPLACE); + gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) { - LLTexLayer* layer = *iter; + LLTexLayerInterface* layer = *iter; gGL.flush(); - layer->blendAlphaTexture(x, y, width, height); + layer->blendAlphaTexture(x,y,width, height); gGL.flush(); } + } - + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); gGL.setColorMask(true, true); gGL.setSceneBlendType(LLRender::BT_ALPHA); } -BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) -{ - BOOL success = TRUE; - mIsVisible = TRUE; - - if (mMaskLayerList.size() > 0) - { - for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) - { - LLTexLayer* layer = *iter; - if (layer->isInvisibleAlphaMask()) - { - mIsVisible = FALSE; - } - } - } - - bool use_shaders = LLGLSLShader::sNoFixedFunction; - LLGLSUIDefault gls_ui; - LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); - gGL.setColorMask(true, true); - - // clear buffer area to ensure we don't pick up UI elements - { - gGL.flush(); - LLGLDisable no_alpha(GL_ALPHA_TEST); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.0f); - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f( 0.f, 0.f, 0.f, 1.f ); - - gl_rect_2d_simple( width, height ); - - gGL.flush(); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } - } - - if (mIsVisible) - { - // composite color layers - for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++) - { - LLTexLayer* layer = *iter; - if (layer->getRenderPass() == RP_COLOR || layer->getRenderPass() == RP_BUMP) - { - gGL.flush(); - success &= layer->render(x, y, width, height); - gGL.flush(); - } - } - - renderAlphaMaskTextures(x, y, width, height, false); - - stop_glerror(); - } - else - { - gGL.flush(); - - gGL.setSceneBlendType(LLRender::BT_REPLACE); - LLGLDisable no_alpha(GL_ALPHA_TEST); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f( 0.f, 0.f, 0.f, 0.f ); - - gl_rect_2d_simple( width, height ); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - gGL.flush(); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } - } - return success; - } - -void LLTexLayerSet::requestUpdate() -{ - if( mUpdatesEnabled ) - { - createComposite(); - mComposite->requestUpdate(); - } -} - -void LLTexLayerSet::requestUpload() -{ - createComposite(); - mComposite->requestUpload(); -} - -void LLTexLayerSet::cancelUpload() -{ - if(mComposite) - { - mComposite->cancelUpload(); - } -} - -void LLTexLayerSet::createComposite() -{ - if( !mComposite ) - { - S32 width = mInfo->mWidth; - S32 height = mInfo->mHeight; - // Composite other avatars at reduced resolution - if( !mAvatar->isSelf() ) - { - width /= 2; - height /= 2; - } - mComposite = new LLTexLayerSetBuffer(this, width, height); - } -} - -void LLTexLayerSet::destroyComposite() -{ - if( mComposite ) - { - mComposite = NULL; - } -} - -void LLTexLayerSet::setUpdatesEnabled( BOOL b ) -{ - mUpdatesEnabled = b; -} - - -void LLTexLayerSet::updateComposite() -{ - createComposite(); - mComposite->updateImmediate(); -} - -LLTexLayerSetBuffer* LLTexLayerSet::getComposite() -{ - createComposite(); - return mComposite; -} - -void LLTexLayerSet::gatherAlphaMasks(U8 *data, S32 width, S32 height) -{ - S32 size = width * height; - - memset(data, 255, width * height); - - for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) - { - LLTexLayer* layer = *iter; - U8* alphaData = layer->getAlphaData(); - if (!alphaData && layer->hasAlphaParams()) - { - LLColor4 net_color; - layer->findNetColor( &net_color ); - layer->invalidateMorphMasks(); - layer->renderAlphaMasks(mComposite->getOriginX(), mComposite->getOriginY(), width, height, &net_color); - alphaData = layer->getAlphaData(); - } - if (alphaData) - { - for( S32 i = 0; i < size; i++ ) - { - U8 curAlpha = data[i]; - U16 resultAlpha = curAlpha; - resultAlpha *= (alphaData[i] + 1); - resultAlpha = resultAlpha >> 8; - data[i] = (U8)resultAlpha; - } - } - } - - // Set alpha back to that of our alpha masks. - renderAlphaMaskTextures(mComposite->getOriginX(), mComposite->getOriginY(), width, height, true); -} - void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components) +{ + mAvatar->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex); +} + +BOOL LLTexLayerSet::isMorphValid() const +{ + for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + const LLTexLayerInterface* layer = *iter; + if (layer && !layer->isMorphValid()) + { + return FALSE; + } + } + return TRUE; +} + +void LLTexLayerSet::invalidateMorphMasks() { for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { - LLTexLayer* layer = *iter; - layer->applyMorphMask(tex_data, width, height, num_components); + LLTexLayerInterface* layer = *iter; + if (layer) + { + layer->invalidateMorphMasks(); + } } } + //----------------------------------------------------------------------------- // LLTexLayerInfo //----------------------------------------------------------------------------- -LLTexLayerInfo::LLTexLayerInfo( ) - : +LLTexLayerInfo::LLTexLayerInfo() : mWriteAllChannels( FALSE ), - mRenderPass( RP_COLOR ), + mRenderPass(LLTexLayer::RP_COLOR), mFixedColor( 0.f, 0.f, 0.f, 0.f ), mLocalTexture( -1 ), mStaticImageIsMask( FALSE ), @@ -1007,8 +1225,8 @@ LLTexLayerInfo::LLTexLayerInfo( ) LLTexLayerInfo::~LLTexLayerInfo( ) { - std::for_each(mColorInfoList.begin(), mColorInfoList.end(), DeletePointer()); - std::for_each(mAlphaInfoList.begin(), mAlphaInfoList.end(), DeletePointer()); + std::for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer()); + std::for_each(mParamAlphaInfoList.begin(), mParamAlphaInfoList.end(), DeletePointer()); } BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) @@ -1031,7 +1249,7 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) { if( render_pass_name == "bump" ) { - mRenderPass = RP_BUMP; + mRenderPass = LLTexLayer::RP_BUMP; } } @@ -1061,7 +1279,7 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) texture_node; texture_node = node->getNextNamedChild()) { - std::string local_texture; + std::string local_texture_name; static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file"); static LLStdStringHandle local_texture_string = LLXmlTree::addAttributeString("local_texture"); static LLStdStringHandle file_is_mask_string = LLXmlTree::addAttributeString("file_is_mask"); @@ -1070,105 +1288,27 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) { texture_node->getFastAttributeBOOL( file_is_mask_string, mStaticImageIsMask ); } - else if( texture_node->getFastAttributeString( local_texture_string, local_texture ) ) + else if (texture_node->getFastAttributeString(local_texture_string, local_texture_name)) { texture_node->getFastAttributeBOOL( local_texture_alpha_only_string, mUseLocalTextureAlphaOnly ); - if( "upper_shirt" == local_texture ) + /* if ("upper_shirt" == local_texture_name) + mLocalTexture = TEX_UPPER_SHIRT; */ + mLocalTexture = TEX_NUM_INDICES; + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + iter++) { - mLocalTexture = TEX_UPPER_SHIRT; + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (local_texture_name == texture_dict->mName) + { + mLocalTexture = iter->first; + break; } - else if( "upper_bodypaint" == local_texture ) - { - mLocalTexture = TEX_UPPER_BODYPAINT; } - else if( "lower_pants" == local_texture ) + if (mLocalTexture == TEX_NUM_INDICES) { - mLocalTexture = TEX_LOWER_PANTS; - } - else if( "lower_bodypaint" == local_texture ) - { - mLocalTexture = TEX_LOWER_BODYPAINT; - } - else if( "lower_shoes" == local_texture ) - { - mLocalTexture = TEX_LOWER_SHOES; - } - else if( "head_bodypaint" == local_texture ) - { - mLocalTexture = TEX_HEAD_BODYPAINT; - } - else if( "lower_socks" == local_texture ) - { - mLocalTexture = TEX_LOWER_SOCKS; - } - else if( "upper_jacket" == local_texture ) - { - mLocalTexture = TEX_UPPER_JACKET; - } - else if( "lower_jacket" == local_texture ) - { - mLocalTexture = TEX_LOWER_JACKET; - } - else if( "upper_gloves" == local_texture ) - { - mLocalTexture = TEX_UPPER_GLOVES; - } - else if( "upper_undershirt" == local_texture ) - { - mLocalTexture = TEX_UPPER_UNDERSHIRT; - } - else if( "lower_underpants" == local_texture ) - { - mLocalTexture = TEX_LOWER_UNDERPANTS; - } - else if( "eyes_iris" == local_texture ) - { - mLocalTexture = TEX_EYES_IRIS; - } - else if( "skirt" == local_texture ) - { - mLocalTexture = TEX_SKIRT; - } - else if( "hair_grain" == local_texture ) - { - mLocalTexture = TEX_HAIR; - } - else if ("hair_alpha" == local_texture) - { - mLocalTexture = TEX_HAIR_ALPHA; - } - else if ("head_alpha" == local_texture) - { - mLocalTexture = TEX_HEAD_ALPHA; - } - else if ("upper_alpha" == local_texture) - { - mLocalTexture = TEX_UPPER_ALPHA; - } - else if ("lower_alpha" == local_texture) - { - mLocalTexture = TEX_LOWER_ALPHA; - } - else if ("eyes_alpha" == local_texture) - { - mLocalTexture = TEX_EYES_ALPHA; - } - else if ("head_tattoo" == local_texture) - { - mLocalTexture = TEX_HEAD_TATTOO; - } - else if ("upper_tattoo" == local_texture) - { - mLocalTexture = TEX_UPPER_TATTOO; - } - else if ("lower_tattoo" == local_texture) - { - mLocalTexture = TEX_LOWER_TATTOO; - } - else - { - llwarns << " element has invalid local_texture attribute: " << mName << " " << local_texture << llendl; + llwarns << " element has invalid local_texture attribute: " << mName << " " << local_texture_name << llendl; return FALSE; } } @@ -1202,13 +1342,13 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) if( child->getChildByName( "param_color" ) ) { // - LLTexParamColorInfo* info = new LLTexParamColorInfo( ); + LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo(); if (!info->parseXml(child)) { delete info; return FALSE; } - mColorInfoList.push_back( info ); + mParamColorInfoList.push_back(info); } else if( child->getChildByName( "param_alpha" ) ) { @@ -1219,13 +1359,184 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) delete info; return FALSE; } - mAlphaInfoList.push_back( info ); + mParamAlphaInfoList.push_back(info); } } return TRUE; } +BOOL LLTexLayerInfo::createVisualParams(LLVOAvatar *avatar) +{ + BOOL success = TRUE; + for (param_color_info_list_t::iterator color_info_iter = mParamColorInfoList.begin(); + color_info_iter != mParamColorInfoList.end(); + color_info_iter++) + { + LLTexLayerParamColorInfo * color_info = *color_info_iter; + LLTexLayerParamColor* param_color = new LLTexLayerParamColor(avatar); + if (!param_color->setInfo(color_info, TRUE)) + { + llwarns << "NULL TexLayer Color Param could not be added to visual param list. Deleting." << llendl; + delete param_color; + success = FALSE; + } + } + + for (param_alpha_info_list_t::iterator alpha_info_iter = mParamAlphaInfoList.begin(); + alpha_info_iter != mParamAlphaInfoList.end(); + alpha_info_iter++) + { + LLTexLayerParamAlphaInfo * alpha_info = *alpha_info_iter; + LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha(avatar); + if (!param_alpha->setInfo(alpha_info, TRUE)) + { + llwarns << "NULL TexLayer Alpha Param could not be added to visual param list. Deleting." << llendl; + delete param_alpha; + success = FALSE; + } + } + + return success; +} + +LLTexLayerInterface::LLTexLayerInterface(LLTexLayerSet* const layer_set): + mTexLayerSet( layer_set ), + mMorphMasksValid( FALSE ), + mInfo(NULL), + mHasMorph(FALSE) +{ +} + +LLTexLayerInterface::LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable): + mTexLayerSet( layer.mTexLayerSet ), + mInfo(NULL) +{ + // don't add visual params for cloned layers + setInfo(layer.getInfo(), wearable); + + mHasMorph = layer.mHasMorph; +} + +BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearable ) // This sets mInfo and calls initialization functions +{ + // setInfo should only be called once. Code is not robust enough to handle redefinition of a texlayer. + // Not a critical warning, but could be useful for debugging later issues. -Nyx + if (mInfo != NULL) + { + llwarns << "mInfo != NULL" << llendl; + } + mInfo = info; + //mID = info->mID; // No ID + + mParamColorList.reserve(mInfo->mParamColorInfoList.size()); + for (param_color_info_list_t::const_iterator iter = mInfo->mParamColorInfoList.begin(); + iter != mInfo->mParamColorInfoList.end(); + iter++) + { + LLTexLayerParamColor* param_color; + if (!wearable) + { + param_color = new LLTexLayerParamColor(this); + if (!param_color->setInfo(*iter, TRUE)) + { + mInfo = NULL; + return FALSE; + } + } + else + { + param_color = (LLTexLayerParamColor*)wearable->getVisualParam((*iter)->getID()); + if (!param_color) + { + mInfo = NULL; + return FALSE; + } + } + mParamColorList.push_back( param_color ); + } + + mParamAlphaList.reserve(mInfo->mParamAlphaInfoList.size()); + for (param_alpha_info_list_t::const_iterator iter = mInfo->mParamAlphaInfoList.begin(); + iter != mInfo->mParamAlphaInfoList.end(); + iter++) + { + LLTexLayerParamAlpha* param_alpha; + if (!wearable) + { + param_alpha = new LLTexLayerParamAlpha( this ); + if (!param_alpha->setInfo(*iter, TRUE)) + { + mInfo = NULL; + return FALSE; + } + } + else + { + param_alpha = (LLTexLayerParamAlpha*) wearable->getVisualParam((*iter)->getID()); + if (!param_alpha) + { + mInfo = NULL; + return FALSE; + } + } + mParamAlphaList.push_back( param_alpha ); + } + + return TRUE; +} + +/*virtual*/ void LLTexLayerInterface::requestUpdate() +{ + mTexLayerSet->requestUpdate(); +} + +const std::string& LLTexLayerInterface::getName() const +{ + return mInfo->mName; +} + +LLTexLayerInterface::ERenderPass LLTexLayerInterface::getRenderPass() const +{ + return mInfo->mRenderPass; +} + +const std::string& LLTexLayerInterface::getGlobalColor() const +{ + return mInfo->mGlobalColor; +} + +BOOL LLTexLayerInterface::isVisibilityMask() const +{ + return mInfo->mIsVisibilityMask; +} + +void LLTexLayerInterface::invalidateMorphMasks() +{ + mMorphMasksValid = FALSE; +} + +LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index) const +{ + LLViewerVisualParam *result = NULL; + for (param_color_list_t::const_iterator color_iter = mParamColorList.begin(); color_iter != mParamColorList.end() && !result; ++color_iter) + { + if ((*color_iter)->getID() == index) + { + result = *color_iter; + } + } + for (param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin(); alpha_iter != mParamAlphaList.end() && !result; ++alpha_iter) + { + if ((*alpha_iter)->getID() == index) + { + result = *alpha_iter; + } + } + + return result; +} + //----------------------------------------------------------------------------- // LLTexLayer // A single texture layer, consisting of: @@ -1239,12 +1550,21 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) // * a texture entry index (TE) // * (optional) one or more alpha parameters (weighted alpha textures) //----------------------------------------------------------------------------- -LLTexLayer::LLTexLayer( LLTexLayerSet* layer_set ) - : - mTexLayerSet( layer_set ), - mMorphMasksValid( FALSE ), - mStaticImageInvalid( FALSE ), - mInfo( NULL ) +LLTexLayer::LLTexLayer(LLTexLayerSet* const layer_set) : + LLTexLayerInterface( layer_set ), + mLocalTextureObject(NULL) +{ +} + +LLTexLayer::LLTexLayer(const LLTexLayer &layer, LLWearable *wearable) : + LLTexLayerInterface( layer, wearable ), + mLocalTextureObject(NULL) +{ +} + +LLTexLayer::LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable) : + LLTexLayerInterface( layer_template, wearable ), + mLocalTextureObject(lto) { } @@ -1261,109 +1581,58 @@ LLTexLayer::~LLTexLayer() U8* alpha_data = iter->second; delete [] alpha_data; } + } //----------------------------------------------------------------------------- // setInfo //----------------------------------------------------------------------------- -BOOL LLTexLayer::setInfo(LLTexLayerInfo* info) +BOOL LLTexLayer::setInfo(const LLTexLayerInfo* info, LLWearable* wearable ) { - //llassert(mInfo == NULL); // nyx says this is probably bogus but needs investigating - if (mInfo != NULL) // above llassert(), but softened into a warning - { - llwarns << "BAD STUFF! mInfo != NULL" << llendl; - } - mInfo = info; - //mID = info->mID; // No ID - - { - LLTexLayerInfo::morph_name_list_t::iterator iter; - for (iter = mInfo->mMorphNameList.begin(); iter != mInfo->mMorphNameList.end(); iter++) - { - // *FIX: we assume that the referenced visual param is a - // morph target, need a better way of actually looking - // this up. - LLPolyMorphTarget *morph_param; - std::string *name = &(iter->first); - morph_param = (LLPolyMorphTarget *)(getTexLayerSet()->getAvatar()->getVisualParam(name->c_str())); - if (morph_param) - { - BOOL invert = iter->second; - addMaskedMorph(morph_param, invert); - } - } - } - - { - LLTexLayerInfo::color_info_list_t::iterator iter; - mParamColorList.reserve(mInfo->mColorInfoList.size()); - for (iter = mInfo->mColorInfoList.begin(); iter != mInfo->mColorInfoList.end(); iter++) - { - LLTexParamColor* param_color = new LLTexParamColor( this ); - if (!param_color->setInfo(*iter)) - { - mInfo = NULL; - return FALSE; - } - mParamColorList.push_back( param_color ); - } - } - { - LLTexLayerInfo::alpha_info_list_t::iterator iter; - mParamAlphaList.reserve(mInfo->mAlphaInfoList.size()); - for (iter = mInfo->mAlphaInfoList.begin(); iter != mInfo->mAlphaInfoList.end(); iter++) - { - LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha( this ); - if (!param_alpha->setInfo(*iter)) - { - mInfo = NULL; - return FALSE; - } - mParamAlphaList.push_back( param_alpha ); - } - } - - return TRUE; + return LLTexLayerInterface::setInfo(info, wearable); } -#if 0 // obsolete -//----------------------------------------------------------------------------- -// parseData -//----------------------------------------------------------------------------- -BOOL LLTexLayer::parseData( LLXmlTreeNode* node ) +//static +void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color) { - LLTexLayerInfo *info = new LLTexLayerInfo; - - if (!info->parseXml(node)) + for (param_color_list_t::const_iterator iter = param_list.begin(); + iter != param_list.end(); iter++) { - delete info; - return FALSE; + const LLTexLayerParamColor* param = *iter; + LLColor4 param_net = param->getNetColor(); + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)param->getInfo(); + switch(info->getOperation()) + { + case LLTexLayerParamColor::OP_ADD: + net_color += param_net; + break; + case LLTexLayerParamColor::OP_MULTIPLY: + net_color = net_color * param_net; + break; + case LLTexLayerParamColor::OP_BLEND: + net_color = lerp(net_color, param_net, param->getWeight()); + break; + default: + llassert(0); + break; + } } - if (!setInfo(info)) - { - delete info; - return FALSE; - } - return TRUE; + net_color.clamp(); } -#endif -//----------------------------------------------------------------------------- - - -void LLTexLayer::deleteCaches() +/*virtual*/ void LLTexLayer::deleteCaches() { - for( alpha_list_t::iterator iter = mParamAlphaList.begin(); + // Only need to delete caches for alpha params. Color params don't hold extra memory + for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) { LLTexLayerParamAlpha* param = *iter; param->deleteCaches(); } - mStaticImageRaw = NULL; } -BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) +BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { LLGLEnable color_mat(GL_COLOR_MATERIAL); gPipeline.disableLights(); @@ -1372,7 +1641,7 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) LLColor4 net_color; BOOL color_specified = findNetColor(&net_color); - + if (mTexLayerSet->getAvatar()->mIsDummy) { color_specified = true; @@ -1388,18 +1657,18 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) } BOOL alpha_mask_specified = FALSE; - alpha_list_t::iterator iter = mParamAlphaList.begin(); + param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); if( iter != mParamAlphaList.end() ) { // If we have alpha masks, but we're skipping all of them, skip the whole layer. // However, we can't do this optimization if we have morph masks that need updating. -/* if( mMaskedMorphs.empty() ) +/* if (!mHasMorph) { BOOL skip_layer = TRUE; while( iter != mParamAlphaList.end() ) { - LLTexLayerParamAlpha* param = *iter; + const LLTexLayerParamAlpha* param = *iter; if( !param->getSkip() ) { @@ -1414,9 +1683,9 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) { return success; } - }*/ + }//*/ - renderAlphaMasks( x, y, width, height, &net_color ); + renderMorphMasks(x, y, width, height, net_color); alpha_mask_specified = TRUE; gGL.flush(); gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA); @@ -1429,22 +1698,25 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) gGL.flush(); gGL.setSceneBlendType(LLRender::BT_REPLACE); } - else if (getInfo()->mUseLocalTextureAlphaOnly) - { - // Use the alpha channel only - gGL.setColorMask(false, true); - } if( (getInfo()->mLocalTexture != -1) && !getInfo()->mUseLocalTextureAlphaOnly ) { { LLViewerTexture* tex = NULL; - if( mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &tex ) ) + if (mLocalTextureObject && mLocalTextureObject->getImage()) { - if (mTexLayerSet->getAvatar()->getLocalTextureID((ETextureIndex)getInfo()->mLocalTexture) == IMG_DEFAULT_AVATAR) + tex = mLocalTextureObject->getImage(); + if (mLocalTextureObject->getID() == IMG_DEFAULT_AVATAR) { tex = NULL; } + } + else + { + llinfos << "lto not defined or image not defined: " << getInfo()->getLocalTexture() << " lto: " << mLocalTextureObject << llendl; + } +// if( mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &image_gl ) ) + { if( tex ) { bool no_alpha_test = getInfo()->mWriteAllChannels; @@ -1470,13 +1742,17 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) } } +// else +// { +// success = FALSE; +// } } } if( !getInfo()->mStaticImageFileName.empty() ) { { - LLViewerTexture* tex = gTexStaticImageList.getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); if( tex ) { gGL.getTexUnit(0)->bind(tex, TRUE); @@ -1490,15 +1766,23 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) } } - if( ((-1 == getInfo()->mLocalTexture) || + if(((-1 == getInfo()->mLocalTexture) || getInfo()->mUseLocalTextureAlphaOnly) && getInfo()->mStaticImageFileName.empty() && color_specified ) { LLGLDisable no_alpha(GL_ALPHA_TEST); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( net_color.mV); + gGL.color4fv( net_color.mV ); gl_rect_2d_simple( width, height ); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } } if( alpha_mask_specified || getInfo()->mWriteAllChannels ) @@ -1509,12 +1793,6 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) stop_glerror(); } - if (getInfo()->mUseLocalTextureAlphaOnly) - { - // Restore color + alpha mode. - gGL.setColorMask(true, true); - } - if( !success ) { llinfos << "LLTexLayer::render() partial: " << getInfo()->mName << llendl; @@ -1522,6 +1800,70 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) return success; } +const U8* LLTexLayer::getAlphaData() const +{ + LLCRC alpha_mask_crc; + const LLUUID& uuid = getUUID(); + alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); + + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) + { + const LLTexLayerParamAlpha* param = *iter; + // MULTI-WEARABLE: verify visual parameters used here + F32 param_weight = param->getWeight(); + alpha_mask_crc.update((U8*)¶m_weight, sizeof(F32)); + } + + U32 cache_index = alpha_mask_crc.getCRC(); + + alpha_cache_t::const_iterator iter2 = mAlphaCache.find(cache_index); + return (iter2 == mAlphaCache.end()) ? 0 : iter2->second; +} + +BOOL LLTexLayer::findNetColor(LLColor4* net_color) const +{ + // Color is either: + // * one or more color parameters (weighted colors) (which may make use of a global color or fixed color) + // * a reference to a global color + // * a fixed color with non-zero alpha + // * opaque white (the default) + + if( !mParamColorList.empty() ) + { + if( !getGlobalColor().empty() ) + { + net_color->setVec( mTexLayerSet->getAvatar()->getGlobalColor( getInfo()->mGlobalColor ) ); + } + else if (getInfo()->mFixedColor.mV[VW]) + { + net_color->setVec( getInfo()->mFixedColor ); + } + else + { + net_color->setVec( 0.f, 0.f, 0.f, 0.f ); + } + + calculateTexLayerColor(mParamColorList, *net_color); + return TRUE; + } + + if( !getGlobalColor().empty() ) + { + net_color->setVec( mTexLayerSet->getAvatar()->getGlobalColor( getGlobalColor() ) ); + return TRUE; + } + + if( getInfo()->mFixedColor.mV[VW] ) + { + net_color->setVec( getInfo()->mFixedColor ); + return TRUE; + } + + net_color->setToWhite(); + + return FALSE; // No need to draw a separate colored polygon +} + BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { BOOL success = TRUE; @@ -1529,10 +1871,11 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) gGL.flush(); bool use_shaders = LLGLSLShader::sNoFixedFunction; - if (!getInfo()->mStaticImageFileName.empty()) + + if( !getInfo()->mStaticImageFileName.empty() ) { - LLViewerTexture* tex = gTexStaticImageList.getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); - if (tex) + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); + if( tex ) { LLGLSNoAlphaTest gls_no_alpha_test; if (use_shaders) @@ -1556,24 +1899,21 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { if (getInfo()->mLocalTexture >=0 && getInfo()->mLocalTexture < TEX_NUM_INDICES) { - LLViewerTexture* tex = NULL; - if (mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &tex)) + LLViewerTexture* tex = mLocalTextureObject->getImage(); + if (tex) { - if (tex) + LLGLSNoAlphaTest gls_no_alpha_test; + if (use_shaders) { - LLGLSNoAlphaTest gls_no_alpha_test; - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } - gGL.getTexUnit(0)->bind(tex); - gl_rect_2d_simple_tex( width, height ); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - success = TRUE; - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + gGL.getTexUnit(0)->bind(tex); + gl_rect_2d_simple_tex( width, height ); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + success = TRUE; + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); } } } @@ -1582,95 +1922,12 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) return success; } -U8* LLTexLayer::getAlphaData() +/*virtual*/ void LLTexLayer::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) { - LLCRC alpha_mask_crc; - const LLUUID& uuid = mTexLayerSet->getAvatar()->getLocalTextureID((ETextureIndex)getInfo()->mLocalTexture); - alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); - - for( alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) - { - LLTexLayerParamAlpha* param = *iter; - F32 param_weight = param->getWeight(); - alpha_mask_crc.update((U8*)¶m_weight, sizeof(F32)); - } - - U32 cache_index = alpha_mask_crc.getCRC(); - - alpha_cache_t::iterator iter2 = mAlphaCache.find(cache_index); - return (iter2 == mAlphaCache.end()) ? 0 : iter2->second; + addAlphaMask(data, originX, originY, width, height); } -BOOL LLTexLayer::findNetColor( LLColor4* net_color ) -{ - // Color is either: - // * one or more color parameters (weighted colors) (which may make use of a global color or fixed color) - // * a reference to a global color - // * a fixed color with non-zero alpha - // * opaque white (the default) - - if( !mParamColorList.empty() ) - { - if( !getGlobalColor().empty() ) - { - net_color->setVec( mTexLayerSet->getAvatar()->getGlobalColor( getInfo()->mGlobalColor ) ); - } - else - if( getInfo()->mFixedColor.mV[VW] ) - { - net_color->setVec( getInfo()->mFixedColor ); - } - else - { - net_color->setVec( 0.f, 0.f, 0.f, 0.f ); - } - - for( color_list_t::iterator iter = mParamColorList.begin(); - iter != mParamColorList.end(); iter++ ) - { - LLTexParamColor* param = *iter; - LLColor4 param_net = param->getNetColor(); - switch( param->getOperation() ) - { - case OP_ADD: - *net_color += param_net; - break; - case OP_MULTIPLY: - net_color->mV[VX] *= param_net.mV[VX]; - net_color->mV[VY] *= param_net.mV[VY]; - net_color->mV[VZ] *= param_net.mV[VZ]; - net_color->mV[VW] *= param_net.mV[VW]; - break; - case OP_BLEND: - net_color->setVec( lerp(*net_color, param_net, param->getWeight()) ); - break; - default: - llassert(0); - break; - } - } - return TRUE; - } - - if( !getGlobalColor().empty() ) - { - net_color->setVec( mTexLayerSet->getAvatar()->getGlobalColor( getGlobalColor() ) ); - return TRUE; - } - - if( getInfo()->mFixedColor.mV[VW] ) - { - net_color->setVec( getInfo()->mFixedColor ); - return TRUE; - } - - net_color->setToWhite(); - - return FALSE; // No need to draw a separate colored polygon -} - - -BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4* colorp ) +BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color) { BOOL success = TRUE; @@ -1682,11 +1939,10 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 { gAlphaMaskProgram.setMinimumAlpha(0.f); } + gGL.setColorMask(false, true); - alpha_list_t::iterator iter = mParamAlphaList.begin(); - LLTexLayerParamAlpha* first_param = *iter; - + LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin(); // Note: if the first param is a mulitply, multiply against the current buffer's alpha if( !first_param || !first_param->getMultiplyBlend() ) { @@ -1704,8 +1960,7 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 // Accumulate alphas LLGLSNoAlphaTest gls_no_alpha_test; gGL.color4f( 1.f, 1.f, 1.f, 1.f ); - - for( iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) + for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) { LLTexLayerParamAlpha* param = *iter; success &= param->render( x, y, width, height ); @@ -1718,31 +1973,25 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 // Accumulate the alpha component of the texture if( getInfo()->mLocalTexture != -1 ) { + LLViewerTexture* tex = mLocalTextureObject->getImage(); + if( tex && (tex->getComponents() == 4) ) { - LLViewerTexture* tex = NULL; - if( mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &tex ) ) - { - if( tex && (tex->getComponents() == 4) ) - { - LLGLSNoAlphaTest gls_no_alpha_test; + LLGLSNoAlphaTest gls_no_alpha_test; + LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); + + gGL.getTexUnit(0)->bind(tex, TRUE); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); - - gGL.getTexUnit(0)->bind(tex, TRUE); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + gl_rect_2d_simple_tex( width, height ); - gl_rect_2d_simple_tex( width, height ); - - gGL.getTexUnit(0)->setTextureAddressMode(old_mode); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - } + gGL.getTexUnit(0)->setTextureAddressMode(old_mode); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } } if( !getInfo()->mStaticImageFileName.empty() ) { - LLViewerTexture* tex = gTexStaticImageList.getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); if( tex ) { if( (tex->getComponents() == 4) || @@ -1758,11 +2007,11 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 // Draw a rectangle with the layer color to multiply the alpha by that color's alpha. // Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO ); - if( colorp->mV[VW] != 1.f ) + if (layer_color.mV[VW] != 1.f) { LLGLDisable no_alpha(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( colorp->mV ); + gGL.color4fv(layer_color.mV); gl_rect_2d_simple( width, height ); } @@ -1775,34 +2024,28 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 gGL.setColorMask(true, true); - if (success && !mMorphMasksValid && !mMaskedMorphs.empty()) + if (hasMorph() && success) { LLCRC alpha_mask_crc; - const LLUUID& uuid = mTexLayerSet->getAvatar()->getLocalTextureID((ETextureIndex)getInfo()->mLocalTexture); + const LLUUID& uuid = getUUID(); alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); - for( alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) { - LLTexLayerParamAlpha* param = *iter; + const LLTexLayerParamAlpha* param = *iter; F32 param_weight = param->getWeight(); alpha_mask_crc.update((U8*)¶m_weight, sizeof(F32)); } U32 cache_index = alpha_mask_crc.getCRC(); - - alpha_cache_t::iterator iter2 = mAlphaCache.find(cache_index); - U8* alpha_data; - if (iter2 != mAlphaCache.end()) - { - alpha_data = iter2->second; - } - else + U8* alpha_data = get_if_there(mAlphaCache,cache_index,(U8*)NULL); + if (!alpha_data) { // clear out a slot if we have filled our cache S32 max_cache_entries = getTexLayerSet()->getAvatar()->isSelf() ? 4 : 1; while ((S32)mAlphaCache.size() >= max_cache_entries) { - iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry + alpha_cache_t::iterator iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry alpha_data = iter2->second; delete [] alpha_data; mAlphaCache.erase(iter2); @@ -1815,784 +2058,331 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 getTexLayerSet()->getAvatar()->dirtyMesh(); mMorphMasksValid = TRUE; + getTexLayerSet()->applyMorphMask(alpha_data, width, height, 1); + } - for( morph_list_t::iterator iter3 = mMaskedMorphs.begin(); - iter3 != mMaskedMorphs.end(); iter3++ ) + return success; +} + +void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height) +{ + S32 size = width * height; + const U8* alphaData = getAlphaData(); + if (!alphaData && hasAlphaParams()) + { + LLColor4 net_color; + findNetColor( &net_color ); + // TODO: eliminate need for layer morph mask valid flag + invalidateMorphMasks(); + renderMorphMasks(originX, originY, width, height, net_color); + alphaData = getAlphaData(); + } + if (alphaData) + { + for( S32 i = 0; i < size; i++ ) { - LLVOAvatar::LLMaskedMorph* maskedMorph = &(*iter3); - maskedMorph->mMorphTarget->applyMask(alpha_data, width, height, 1, maskedMorph->mInvert); + U8 curAlpha = data[i]; + U16 resultAlpha = curAlpha; + resultAlpha *= (alphaData[i] + 1); + resultAlpha = resultAlpha >> 8; + data[i] = (U8)resultAlpha; + } + } +} + +/*virtual*/ BOOL LLTexLayer::isInvisibleAlphaMask() const +{ + if (mLocalTextureObject) + { + if (mLocalTextureObject->getID() == IMG_INVISIBLE) + { + return TRUE; + } + } + + return FALSE; +} + +LLUUID LLTexLayer::getUUID() const +{ + LLUUID uuid; + if( getInfo()->mLocalTexture != -1 ) + { + LLViewerTexture* tex = mLocalTextureObject->getImage(); + if (tex) + { + uuid = mLocalTextureObject->getID(); + } + } + if( !getInfo()->mStaticImageFileName.empty() ) + { + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + if( tex ) + { + uuid = tex->getID(); + } + } + return uuid; +} + + +//----------------------------------------------------------------------------- +// LLTexLayerTemplate +// A single texture layer, consisting of: +// * color, consisting of either +// * one or more color parameters (weighted colors) +// * a reference to a global color +// * a fixed color with non-zero alpha +// * opaque white (the default) +// * (optional) a texture defined by either +// * a GUID +// * a texture entry index (TE) +// * (optional) one or more alpha parameters (weighted alpha textures) +//----------------------------------------------------------------------------- +LLTexLayerTemplate::LLTexLayerTemplate(LLTexLayerSet* layer_set) : + LLTexLayerInterface(layer_set) +{ +} + +LLTexLayerTemplate::LLTexLayerTemplate(const LLTexLayerTemplate &layer) : + LLTexLayerInterface(layer) +{ +} + +LLTexLayerTemplate::~LLTexLayerTemplate() +{ +} + +//----------------------------------------------------------------------------- +// setInfo +//----------------------------------------------------------------------------- + +/*virtual*/ BOOL LLTexLayerTemplate::setInfo(const LLTexLayerInfo* info, LLWearable* wearable ) +{ + return LLTexLayerInterface::setInfo(info, wearable); +} + +U32 LLTexLayerTemplate::updateWearableCache() const +{ + mWearableCache.clear(); + + S32 te = mInfo->mLocalTexture; + if (te == -1) + { + //this isn't a cloneable layer + return 0; + } + LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te); + U32 num_wearables = gAgentWearables.getWearableCount(wearable_type); + U32 added = 0; + for (U32 i = 0; i < num_wearables; i++) + { + LLWearable* wearable = gAgentWearables.getWearable(wearable_type, i); + if (!wearable) + { + continue; + } + mWearableCache.push_back(wearable); + added++; + } + return added; +} +LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const +{ + if (mWearableCache.size() <= i) + { + return NULL; + } + LLWearable *wearable = mWearableCache[i]; + LLLocalTextureObject *lto = NULL; + LLTexLayer *layer = NULL; + if (wearable) + { + lto = wearable->getLocalTextureObject(mInfo->mLocalTexture); + } + if (lto) + { + layer = lto->getTexLayer(getName()); + } + return layer; +} + +/*virtual*/ BOOL LLTexLayerTemplate::render(S32 x, S32 y, S32 width, S32 height) +{ + if(!mInfo) + { + return FALSE ; + } + + BOOL success = TRUE; + updateWearableCache(); + for (wearable_cache_t::const_iterator iter = mWearableCache.begin(); iter!= mWearableCache.end(); iter++) + { + LLWearable* wearable = NULL; + LLLocalTextureObject *lto = NULL; + LLTexLayer *layer = NULL; + wearable = *iter; + if (wearable) + { + lto = wearable->getLocalTextureObject(mInfo->mLocalTexture); + } + if (lto) + { + layer = lto->getTexLayer(getName()); + } + if (layer) + { + wearable->writeToAvatar(); + layer->setLTO(lto); + success &= layer->render(x,y,width,height); } } return success; } -void LLTexLayer::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components) -{ - for( morph_list_t::iterator iter = mMaskedMorphs.begin(); - iter != mMaskedMorphs.end(); iter++ ) - { - LLVOAvatar::LLMaskedMorph* maskedMorph = &(*iter); - maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert); - } -} - -// Returns TRUE on success. -BOOL LLTexLayer::renderImageRaw( U8* in_data, S32 in_width, S32 in_height, S32 in_components, S32 width, S32 height, BOOL is_mask ) -{ - if (!in_data) - { - return FALSE; - } - GLenum format_options[4] = { GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA }; - GLenum format = format_options[in_components-1]; - if( is_mask ) - { - llassert( 1 == in_components ); - format = GL_ALPHA; - } - - if( (in_width != SCRATCH_TEX_WIDTH) || (in_height != SCRATCH_TEX_HEIGHT) ) - { - LLGLSNoAlphaTest gls_no_alpha_test; - - GLenum internal_format_options[4] = { GL_LUMINANCE8, GL_LUMINANCE8_ALPHA8, GL_RGB8, GL_RGBA8 }; - GLenum internal_format = internal_format_options[in_components-1]; - if( is_mask ) - { - llassert( 1 == in_components ); - internal_format = GL_ALPHA8; - } - - U32 name = 0; - LLImageGL::generateTextures(1, &name ); - stop_glerror(); - - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, name); - stop_glerror(); - - LLImageGL::setManualImage( - GL_TEXTURE_2D, 0, internal_format, - in_width, in_height, - format, GL_UNSIGNED_BYTE, in_data ); - stop_glerror(); - - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - - gl_rect_2d_simple_tex( width, height ); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLImageGL::deleteTextures(1, &name ); - stop_glerror(); - } - else - { - LLGLSNoAlphaTest gls_no_alpha_test; - - if( !mTexLayerSet->getAvatar()->bindScratchTexture(format) ) - { - return FALSE; - } - - glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, in_width, in_height, format, GL_UNSIGNED_BYTE, in_data ); - stop_glerror(); - - gl_rect_2d_simple_tex( width, height ); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - - return TRUE; -} - -void LLTexLayer::requestUpdate() -{ - mTexLayerSet->requestUpdate(); -} - -void LLTexLayer::addMaskedMorph(LLPolyMorphTarget* morph_target, BOOL invert) -{ - mMaskedMorphs.push_front(LLVOAvatar::LLMaskedMorph(morph_target, invert)); -} - -void LLTexLayer::invalidateMorphMasks() -{ - mMorphMasksValid = FALSE; -} - -BOOL LLTexLayer::isVisibilityMask() const -{ - return mInfo->mIsVisibilityMask; -} - -BOOL LLTexLayer::isInvisibleAlphaMask() -{ - const LLTexLayerInfo *info = getInfo(); - - if (info && info->mLocalTexture >= 0 && info->mLocalTexture < TEX_NUM_INDICES) - { - if (mTexLayerSet->getAvatar()->getLocalTextureID((ETextureIndex)info->mLocalTexture) == IMG_INVISIBLE) - { - return TRUE; - } - } - - return FALSE; -} - -//----------------------------------------------------------------------------- -// LLTexLayerParamAlphaInfo -//----------------------------------------------------------------------------- -LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo( ) - : - mMultiplyBlend( FALSE ), - mSkipIfZeroWeight( FALSE ), - mDomain( 0.f ) -{ -} - -BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node) -{ - llassert( node->hasName( "param" ) && node->getChildByName( "param_alpha" ) ); - - if( !LLViewerVisualParamInfo::parseXml(node) ) - return FALSE; - - LLXmlTreeNode* param_alpha_node = node->getChildByName( "param_alpha" ); - if( !param_alpha_node ) - { - return FALSE; - } - - static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file"); - if( param_alpha_node->getFastAttributeString( tga_file_string, mStaticImageFileName ) ) - { - // Don't load the image file until it's actually needed. - } -// else -// { -// llwarns << " element is missing tga_file attribute." << llendl; -// } - - static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend"); - param_alpha_node->getFastAttributeBOOL( multiply_blend_string, mMultiplyBlend ); - - static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero"); - param_alpha_node->getFastAttributeBOOL( skip_if_zero_string, mSkipIfZeroWeight ); - - static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain"); - param_alpha_node->getFastAttributeF32( domain_string, mDomain ); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLTexLayerParamAlpha -//----------------------------------------------------------------------------- - -// static -LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances; - -// static -void LLTexLayerParamAlpha::dumpCacheByteCount() -{ - S32 gl_bytes = 0; - getCacheByteCount( &gl_bytes ); - llinfos << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << llendl; -} - -// static -void LLTexLayerParamAlpha::getCacheByteCount( S32* gl_bytes ) -{ - *gl_bytes = 0; - - for( param_alpha_ptr_list_t::iterator iter = sInstances.begin(); - iter != sInstances.end(); iter++ ) - { - LLTexLayerParamAlpha* instance = *iter; - LLViewerTexture* tex = instance->mCachedProcessedTexture; - if( tex ) - { - S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents(); - - if( tex->hasGLTexture() ) - { - *gl_bytes += bytes; - } - } - } -} - -LLTexLayerParamAlpha::LLTexLayerParamAlpha( LLTexLayer* layer ) - : - mCachedProcessedTexture( NULL ), - mTexLayer( layer ), - mNeedsCreateTexture( FALSE ), - mStaticImageInvalid( FALSE ), - mAvgDistortionVec(1.f, 1.f, 1.f), - mCachedEffectiveWeight(0.f) -{ - sInstances.push_front( this ); -} - -LLTexLayerParamAlpha::~LLTexLayerParamAlpha() -{ - deleteCaches(); - sInstances.remove( this ); -} - -//----------------------------------------------------------------------------- -// setInfo() -//----------------------------------------------------------------------------- -BOOL LLTexLayerParamAlpha::setInfo(LLTexLayerParamAlphaInfo *info) -{ - llassert(mInfo == NULL); - if (info->mID < 0) - return FALSE; - mInfo = info; - mID = info->mID; - - mTexLayer->getTexLayerSet()->getAvatar()->addVisualParam( this ); - setWeight(getDefaultWeight(), FALSE ); - - return TRUE; -} - -//----------------------------------------------------------------------------- - -void LLTexLayerParamAlpha::deleteCaches() -{ - mStaticImageTGA = NULL; // deletes image - mCachedProcessedTexture = NULL; - mStaticImageRaw = NULL; - mNeedsCreateTexture = FALSE; -} - -void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL set_by_user) -{ - if (mIsAnimating) - { - return; - } - F32 min_weight = getMinWeight(); - F32 max_weight = getMaxWeight(); - F32 new_weight = llclamp(weight, min_weight, max_weight); - U8 cur_u8 = F32_to_U8( mCurWeight, min_weight, max_weight ); - U8 new_u8 = F32_to_U8( new_weight, min_weight, max_weight ); - if( cur_u8 != new_u8) - { - mCurWeight = new_weight; - - LLVOAvatar* avatar = mTexLayer->getTexLayerSet()->getAvatar(); - if( avatar->getSex() & getSex() ) - { - if ( gAgentCamera.cameraCustomizeAvatar() ) - { - set_by_user = FALSE; - } - avatar->invalidateComposite( mTexLayer->getTexLayerSet(), set_by_user ); - mTexLayer->invalidateMorphMasks(); - avatar->updateMeshTextures(); - } - } -} - -void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL set_by_user) -{ - mTargetWeight = target_value; - setWeight(target_value, set_by_user); - mIsAnimating = TRUE; - if (mNext) - { - mNext->setAnimationTarget(target_value, set_by_user); - } -} - -void LLTexLayerParamAlpha::animate(F32 delta, BOOL set_by_user) -{ - if (mNext) - { - mNext->animate(delta, set_by_user); - } -} - -BOOL LLTexLayerParamAlpha::getSkip() -{ - LLVOAvatar *avatar = mTexLayer->getTexLayerSet()->getAvatar(); - - if( getInfo()->mSkipIfZeroWeight ) - { - F32 effective_weight = ( avatar->getSex() & getSex() ) ? mCurWeight : getDefaultWeight(); - if (is_approx_zero( effective_weight )) - { - return TRUE; - } - } - - LLWearableType::EType type = (LLWearableType::EType)getWearableType(); - if( (type != LLWearableType::WT_INVALID) && !avatar->isWearingWearableType( type ) ) - { - return TRUE; - } - - return FALSE; -} - - -BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height ) +/*virtual*/ BOOL LLTexLayerTemplate::blendAlphaTexture( S32 x, S32 y, S32 width, S32 height) // Multiplies a single alpha texture against the frame buffer { BOOL success = TRUE; - - F32 effective_weight = ( mTexLayer->getTexLayerSet()->getAvatar()->getSex() & getSex() ) ? mCurWeight : getDefaultWeight(); - BOOL weight_changed = effective_weight != mCachedEffectiveWeight; - if( getSkip() ) + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) { - return success; - } - - gGL.flush(); - if( getInfo()->mMultiplyBlend ) - { - gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function - } - else - { - gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function - } - - if( !getInfo()->mStaticImageFileName.empty() && !mStaticImageInvalid) - { - if( mStaticImageTGA.isNull() ) + LLTexLayer *layer = getLayer(i); + if (layer) { - // Don't load the image file until we actually need it the first time. Like now. - mStaticImageTGA = gTexStaticImageList.getImageTGA( getInfo()->mStaticImageFileName ); - // We now have something in one of our caches - LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull() ? TRUE : FALSE; - - if( mStaticImageTGA.isNull() ) - { - llwarns << "Unable to load static file: " << getInfo()->mStaticImageFileName << llendl; - mStaticImageInvalid = TRUE; // don't try again. - return FALSE; - } - } - - const S32 image_tga_width = mStaticImageTGA->getWidth(); - const S32 image_tga_height = mStaticImageTGA->getHeight(); - if( !mCachedProcessedTexture || - (mCachedProcessedTexture->getWidth() != image_tga_width) || - (mCachedProcessedTexture->getHeight() != image_tga_height) || - (weight_changed) ) - { -// llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl; - mCachedEffectiveWeight = effective_weight; - - if( !mCachedProcessedTexture ) - { - mCachedProcessedTexture = LLViewerTextureManager::getLocalTexture( image_tga_width, image_tga_height, 1, FALSE ); - - // We now have something in one of our caches - LLTexLayerSet::sHasCaches |= mCachedProcessedTexture ? TRUE : FALSE; - - mCachedProcessedTexture->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); - } - - // Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed. - mStaticImageRaw = NULL; - mStaticImageRaw = new LLImageRaw; - mStaticImageTGA->decodeAndProcess( mStaticImageRaw, getInfo()->mDomain, effective_weight ); - mNeedsCreateTexture = TRUE; - } - - if( mCachedProcessedTexture ) - { - { - // Create the GL texture, and then hang onto it for future use. - if( mNeedsCreateTexture ) - { - mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw, 0, TRUE, LLViewerTexture::BOOST_AVATAR_SELF); - mNeedsCreateTexture = FALSE; - gGL.getTexUnit(0)->bind(mCachedProcessedTexture); - mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP); - } - - LLGLSNoAlphaTest gls_no_alpha_test; - gGL.getTexUnit(0)->bind(mCachedProcessedTexture, TRUE); - gl_rect_2d_simple_tex( width, height ); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - stop_glerror(); - } - } - - // Don't keep the cache for other people's avatars - // (It's not really a "cache" in that case, but the logic is the same) - if( !mTexLayer->getTexLayerSet()->getAvatar()->isSelf() ) - { - mCachedProcessedTexture = NULL; + success &= layer->blendAlphaTexture(x,y,width,height); } } - else - { - LLGLDisable no_alpha(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f( 0.f, 0.f, 0.f, effective_weight ); - gl_rect_2d_simple( width, height ); - } - return success; } -//----------------------------------------------------------------------------- -// LLTexGlobalColorInfo -//----------------------------------------------------------------------------- - -LLTexGlobalColorInfo::LLTexGlobalColorInfo() +/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) { -} - - -LLTexGlobalColorInfo::~LLTexGlobalColorInfo() -{ - for_each(mColorInfoList.begin(), mColorInfoList.end(), DeletePointer()); -} - -BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node) -{ - // name attribute - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if( !node->getFastAttributeString( name_string, mName ) ) + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) { - llwarns << " element is missing name attribute." << llendl; - return FALSE; - } - // sub-element - for (LLXmlTreeNode* child = node->getChildByName( "param" ); - child; - child = node->getNextNamedChild()) - { - if( child->getChildByName( "param_color" ) ) + LLTexLayer *layer = getLayer(i); + if (layer) { - // - LLTexParamColorInfo* info = new LLTexParamColorInfo(); - if (!info->parseXml(child)) - { - delete info; - return FALSE; - } - mColorInfoList.push_back( info ); + layer->addAlphaMask(data, originX, originY, width, height); } } - return TRUE; } -//----------------------------------------------------------------------------- -// LLTexGlobalColor -//----------------------------------------------------------------------------- - -LLTexGlobalColor::LLTexGlobalColor( LLVOAvatar* avatar ) - : - mAvatar( avatar ), - mInfo( NULL ) -{ -} - - -LLTexGlobalColor::~LLTexGlobalColor() -{ - // mParamList are LLViewerVisualParam's and get deleted with ~LLCharacter() - //std::for_each(mParamList.begin(), mParamList.end(), DeletePointer()); -} - -BOOL LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info) -{ - llassert(mInfo == NULL); - mInfo = info; - //mID = info->mID; // No ID - - LLTexGlobalColorInfo::color_info_list_t::iterator iter; - mParamList.reserve(mInfo->mColorInfoList.size()); - for (iter = mInfo->mColorInfoList.begin(); iter != mInfo->mColorInfoList.end(); iter++) - { - LLTexParamColor* param_color = new LLTexParamColor( this ); - if (!param_color->setInfo(*iter)) - { - mInfo = NULL; - return FALSE; - } - mParamList.push_back( param_color ); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- - -LLColor4 LLTexGlobalColor::getColor() -{ - // Sum of color params - if( !mParamList.empty() ) - { - LLColor4 net_color( 0.f, 0.f, 0.f, 0.f ); - - for( param_list_t::iterator iter = mParamList.begin(); - iter != mParamList.end(); iter++ ) - { - LLTexParamColor* param = *iter; - LLColor4 param_net = param->getNetColor(); - switch( param->getOperation() ) - { - case OP_ADD: - net_color += param_net; - break; - case OP_MULTIPLY: - net_color.mV[VX] *= param_net.mV[VX]; - net_color.mV[VY] *= param_net.mV[VY]; - net_color.mV[VZ] *= param_net.mV[VZ]; - net_color.mV[VW] *= param_net.mV[VW]; - break; - case OP_BLEND: - net_color = lerp(net_color, param_net, param->getWeight()); - break; - default: - llassert(0); - break; - } - } - - net_color.mV[VX] = llclampf( net_color.mV[VX] ); - net_color.mV[VY] = llclampf( net_color.mV[VY] ); - net_color.mV[VZ] = llclampf( net_color.mV[VZ] ); - net_color.mV[VW] = llclampf( net_color.mV[VW] ); - - return net_color; - } - return LLColor4( 1.f, 1.f, 1.f, 1.f ); -} - -//----------------------------------------------------------------------------- -// LLTexParamColorInfo -//----------------------------------------------------------------------------- -LLTexParamColorInfo::LLTexParamColorInfo() - : - mOperation( OP_ADD ), - mNumColors( 0 ) -{ -} - -BOOL LLTexParamColorInfo::parseXml(LLXmlTreeNode *node) -{ - llassert( node->hasName( "param" ) && node->getChildByName( "param_color" ) ); - - if (!LLViewerVisualParamInfo::parseXml(node)) - return FALSE; - - LLXmlTreeNode* param_color_node = node->getChildByName( "param_color" ); - if( !param_color_node ) - { - return FALSE; - } - - std::string op_string; - static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation"); - if( param_color_node->getFastAttributeString( operation_string, op_string ) ) - { - LLStringUtil::toLower(op_string); - if ( op_string == "add" ) mOperation = OP_ADD; - else if ( op_string == "multiply" ) mOperation = OP_MULTIPLY; - else if ( op_string == "blend" ) mOperation = OP_BLEND; - } - - mNumColors = 0; - - LLColor4U color4u; - for (LLXmlTreeNode* child = param_color_node->getChildByName( "value" ); - child; - child = param_color_node->getNextNamedChild()) - { - if( (mNumColors < MAX_COLOR_VALUES) ) - { - static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color"); - if( child->getFastAttributeColor4U( color_string, color4u ) ) - { - mColors[ mNumColors ].setVec(color4u); - mNumColors++; - } - } - } - if( !mNumColors ) - { - llwarns << " is missing sub-elements" << llendl; - return FALSE; - } - - if( (mOperation == OP_BLEND) && (mNumColors != 1) ) - { - llwarns << " with operation\"blend\" must have exactly one " << llendl; - return FALSE; - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLTexParamColor -//----------------------------------------------------------------------------- -LLTexParamColor::LLTexParamColor( LLTexGlobalColor* tex_global_color ) - : - mAvgDistortionVec(1.f, 1.f, 1.f), - mTexGlobalColor( tex_global_color ), - mTexLayer( NULL ), - mAvatar( tex_global_color->getAvatar() ) -{ -} - -LLTexParamColor::LLTexParamColor( LLTexLayer* layer ) - : - mAvgDistortionVec(1.f, 1.f, 1.f), - mTexGlobalColor( NULL ), - mTexLayer( layer ), - mAvatar( layer->getTexLayerSet()->getAvatar() ) -{ -} - - -LLTexParamColor::~LLTexParamColor() -{ -} - -//----------------------------------------------------------------------------- -// setInfo() -//----------------------------------------------------------------------------- - -BOOL LLTexParamColor::setInfo(LLTexParamColorInfo *info) -{ - llassert(mInfo == NULL); - if (info->mID < 0) - return FALSE; - mID = info->mID; - mInfo = info; - - mAvatar->addVisualParam( this ); - setWeight( getDefaultWeight(), FALSE ); - - return TRUE; -} - -LLColor4 LLTexParamColor::getNetColor() -{ - llassert( getInfo()->mNumColors >= 1 ); - - F32 effective_weight = ( mAvatar && (mAvatar->getSex() & getSex()) ) ? mCurWeight : getDefaultWeight(); - - S32 index_last = getInfo()->mNumColors - 1; - F32 scaled_weight = effective_weight * index_last; - S32 index_start = (S32) scaled_weight; - S32 index_end = index_start + 1; - if( index_start == index_last ) - { - return getInfo()->mColors[index_last]; - } - else - { - F32 weight = scaled_weight - index_start; - const LLColor4 *start = &getInfo()->mColors[ index_start ]; - const LLColor4 *end = &getInfo()->mColors[ index_end ]; - return LLColor4( - (1.f - weight) * start->mV[VX] + weight * end->mV[VX], - (1.f - weight) * start->mV[VY] + weight * end->mV[VY], - (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ], - (1.f - weight) * start->mV[VW] + weight * end->mV[VW] ); - } -} - -void LLTexParamColor::setWeight(F32 weight, BOOL set_by_user) -{ - if (mIsAnimating) - { - return; - } - F32 min_weight = getMinWeight(); - F32 max_weight = getMaxWeight(); - F32 new_weight = llclamp(weight, min_weight, max_weight); - U8 cur_u8 = F32_to_U8( mCurWeight, min_weight, max_weight ); - U8 new_u8 = F32_to_U8( new_weight, min_weight, max_weight ); - if( cur_u8 != new_u8) - { - mCurWeight = new_weight; - - if( getInfo()->mNumColors <= 0 ) - { - // This will happen when we set the default weight the first time. - return; - } - - if( mAvatar->getSex() & getSex() ) - { - if( mTexGlobalColor ) - { - mAvatar->onGlobalColorChanged( mTexGlobalColor, set_by_user ); - } - else - if( mTexLayer ) - { - mAvatar->invalidateComposite( mTexLayer->getTexLayerSet(), set_by_user ); - } - } -// llinfos << "param " << mName << " = " << new_weight << llendl; - } -} - -void LLTexParamColor::setAnimationTarget(F32 target_value, BOOL set_by_user) +/*virtual*/ void LLTexLayerTemplate::setHasMorph(BOOL newval) { - // set value first then set interpolating flag to ignore further updates - mTargetWeight = target_value; - setWeight(target_value, set_by_user); - mIsAnimating = TRUE; - if (mNext) + mHasMorph = newval; + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) { - mNext->setAnimationTarget(target_value, set_by_user); + LLTexLayer *layer = getLayer(i); + if (layer) + { + layer->setHasMorph(newval); + } } } -void LLTexParamColor::animate(F32 delta, BOOL set_by_user) +/*virtual*/ void LLTexLayerTemplate::deleteCaches() { - if (mNext) + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) { - mNext->animate(delta, set_by_user); + LLTexLayer *layer = getLayer(i); + if (layer) + { + layer->deleteCaches(); + } } } +/*virtual*/ BOOL LLTexLayerTemplate::isInvisibleAlphaMask() const +{ + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) + { + LLTexLayer *layer = getLayer(i); + if (layer) + { + if (layer->isInvisibleAlphaMask()) + { + return TRUE; + } + } + } + + return FALSE; +} + //----------------------------------------------------------------------------- -// LLTexStaticImageList +// finds a specific layer based on a passed in name +//----------------------------------------------------------------------------- +LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name) +{ + for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + if (layer->getName() == name) + { + return layer; + } + } + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + if (layer->getName() == name) + { + return layer; + } + } + return NULL; +} + +void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable *wearable) +{ + // initialize all texlayers with this texture type for this LTO + for( LLTexLayerSet::layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter; + if (layer->getInfo()->getLocalTexture() == (S32) tex_index) + { + lto->addTexLayer(layer, wearable); + } + } + for( LLTexLayerSet::layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) + { + LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter; + if (layer->getInfo()->getLocalTexture() == (S32) tex_index) + { + lto->addTexLayer(layer, wearable); + } + } +} +//----------------------------------------------------------------------------- +// LLTexLayerStaticImageList //----------------------------------------------------------------------------- -// static -LLTexStaticImageList gTexStaticImageList; -LLStringTable LLTexStaticImageList::sImageNames(16384); +LLTexLayerStaticImageList::LLTexLayerStaticImageList() : + mGLBytes(0), + mTGABytes(0), + mImageNames(16384) +{ +} -LLTexStaticImageList::LLTexStaticImageList() - : - mGLBytes( 0 ), - mTGABytes( 0 ) -{} - -LLTexStaticImageList::~LLTexStaticImageList() +LLTexLayerStaticImageList::~LLTexLayerStaticImageList() { deleteCachedImages(); } -void LLTexStaticImageList::dumpByteCount() const +void LLTexLayerStaticImageList::dumpByteCount() const { llinfos << "Avatar Static Textures " << "KB GL:" << (mGLBytes / 1024) << "KB TGA:" << (mTGABytes / 1024) << "KB" << llendl; } -void LLTexStaticImageList::deleteCachedImages() +void LLTexLayerStaticImageList::deleteCachedImages() { if( mGLBytes || mTGABytes ) { @@ -2610,16 +2400,16 @@ void LLTexStaticImageList::deleteCachedImages() } } -// Note: in general, for a given image image we'll call either getImageTga() or getImageGL(). +// Note: in general, for a given image image we'll call either getImageTga() or getTexture(). // We call getImageTga() if the image is used as an alpha gradient. -// Otherwise, we call getImageGL() +// Otherwise, we call getTexture() // Returns an LLImageTGA that contains the encoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -LLImageTGA* LLTexStaticImageList::getImageTGA(const std::string& file_name) +LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) { - const char *namekey = sImageNames.addString(file_name); - image_tga_map_t::iterator iter = mStaticImageListTGA.find(namekey); + const char *namekey = mImageNames.addString(file_name); + image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey); if( iter != mStaticImageListTGA.end() ) { return iter->second; @@ -2642,14 +2432,12 @@ LLImageTGA* LLTexStaticImageList::getImageTGA(const std::string& file_name) } } - - // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -LLViewerTexture* LLTexStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) +LLViewerTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) { LLPointer tex; - const char *namekey = sImageNames.addString(file_name); + const char *namekey = mImageNames.addString(file_name); texture_map_t::const_iterator iter = mStaticImageList.find(namekey); if( iter != mStaticImageList.end() ) @@ -2687,7 +2475,7 @@ LLViewerTexture* LLTexStaticImageList::getTexture(const std::string& file_name, // Reads a .tga file, decodes it, and puts the decoded data in image_raw. // Returns TRUE if successful. -BOOL LLTexStaticImageList::loadImageRaw( const std::string& file_name, LLImageRaw* image_raw ) +BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw) { BOOL success = FALSE; std::string path; @@ -2702,3 +2490,23 @@ BOOL LLTexStaticImageList::loadImageRaw( const std::string& file_name, LLImageRa return success; } +const std::string LLTexLayerSetBuffer::dumpTextureInfo() const +{ + if (!isAgentAvatarValid()) return ""; + + const BOOL is_high_res = !mNeedsUpload; + const U32 num_low_res = mNumLowresUploads; + const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32(); + const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(mTexLayerSet); + + std::string status = "CREATING "; + if (!uploadNeeded()) status = "DONE "; + if (uploadInProgress()) status = "UPLOADING"; + + std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s", + status.c_str(), + is_high_res, num_low_res, + upload_time, + local_texture_info.c_str()); + return text; +} diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h index 771b5e027..94fec5f80 100644 --- a/indra/newview/lltexlayer.h +++ b/indra/newview/lltexlayer.h @@ -34,524 +34,354 @@ #define LL_LLTEXLAYER_H #include -#include "llassetstorage.h" #include "lldynamictexture.h" -#include "llrect.h" -#include "llstring.h" -#include "lluuid.h" -#include "llviewertexture.h" -#include "llviewervisualparam.h" #include "llvoavatardefines.h" -#include "llwearable.h" -#include "v4color.h" -#include "llfloater.h" -#include "llvoavatar.h" +#include "lltexlayerparams.h" +#include "lllocaltextureobject.h" -class LLTexLayerSetInfo; -class LLTexLayerSet; -class LLTexLayerInfo; -class LLTexLayer; -class LLViewerTexture; -class LLImageTGA; -class LLTexGlobalColorInfo; -class LLTexLayerParamAlphaInfo; -class LLTexLayerParamAlpha; -class LLTexParamColorInfo; -class LLTexParamColor; -class LLPolyMesh; -class LLXmlTreeNode; -class LLImageRaw; -class LLPolyMorphTarget; -class LLViewerTexture; - -class LLTextureCtrl; class LLVOAvatar; +class LLVOAvatarSelf; +class LLImageTGA; +class LLImageRaw; +class LLXmlTreeNode; +class LLTexLayerSet; +class LLTexLayerSetInfo; +class LLTexLayerInfo; +class LLTexLayerSetBuffer; +class LLWearable; +class LLViewerVisualParam; - -enum EColorOperation +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerInterface +// +// Interface class to generalize functionality shared by LLTexLayer +// and LLTexLayerTemplate. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerInterface { - OP_ADD = 0, - OP_MULTIPLY = 1, - OP_BLEND = 2, - OP_COUNT = 3 // Number of operations -}; - - -//----------------------------------------------------------------------------- -// LLTexLayerParamAlphaInfo -//----------------------------------------------------------------------------- -class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo -{ - friend class LLTexLayerParamAlpha; public: - LLTexLayerParamAlphaInfo(); - /*virtual*/ ~LLTexLayerParamAlphaInfo() {}; + enum ERenderPass + { + RP_COLOR, + RP_BUMP, + RP_SHINE + }; - /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + LLTexLayerInterface(LLTexLayerSet* const layer_set); + LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable); + virtual ~LLTexLayerInterface() {} + + virtual BOOL render(S32 x, S32 y, S32 width, S32 height) = 0; + virtual void deleteCaches() = 0; + virtual BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) = 0; + virtual BOOL isInvisibleAlphaMask() const = 0; + + const LLTexLayerInfo* getInfo() const { return mInfo; } + virtual BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions + + const std::string& getName() const; + const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; } + LLTexLayerSet* const getTexLayerSet() { return mTexLayerSet; } + + void invalidateMorphMasks(); + virtual void setHasMorph(BOOL newval) { mHasMorph = newval; } + BOOL hasMorph() const { return mHasMorph; } + BOOL isMorphValid() const { return mMorphMasksValid; } + + void requestUpdate(); + virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) = 0; + BOOL hasAlphaParams() const { return !mParamAlphaList.empty(); } + + ERenderPass getRenderPass() const; + BOOL isVisibilityMask() const; protected: - std::string mStaticImageFileName; - BOOL mMultiplyBlend; - BOOL mSkipIfZeroWeight; - F32 mDomain; -}; + const std::string& getGlobalColor() const; + LLViewerVisualParam* getVisualParamPtr(S32 index) const; -//----------------------------------------------------------------------------- -// LLTexParamColorInfo -//----------------------------------------------------------------------------- -class LLTexParamColorInfo : public LLViewerVisualParamInfo -{ - friend class LLTexParamColor; - -public: - LLTexParamColorInfo(); - virtual ~LLTexParamColorInfo() {}; - BOOL parseXml( LLXmlTreeNode* node ); - protected: - enum { MAX_COLOR_VALUES = 20 }; - EColorOperation mOperation; - LLColor4 mColors[MAX_COLOR_VALUES]; - S32 mNumColors; + LLTexLayerSet* const mTexLayerSet; + const LLTexLayerInfo* mInfo; + BOOL mMorphMasksValid; + BOOL mHasMorph; + + // Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order. + param_color_list_t mParamColorList; + param_alpha_list_t mParamAlphaList; + // mGlobalColor name stored in mInfo + // mFixedColor value stored in mInfo }; -//----------------------------------------------------------------------------- -// LLTexGlobalColorInfo -//----------------------------------------------------------------------------- -class LLTexGlobalColorInfo +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerTemplate +// +// Only exists for llvoavatarself. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerTemplate : public LLTexLayerInterface { - friend class LLTexGlobalColor; public: - LLTexGlobalColorInfo(); - ~LLTexGlobalColorInfo(); + LLTexLayerTemplate(LLTexLayerSet* const layer_set); + LLTexLayerTemplate(const LLTexLayerTemplate &layer); + /*virtual*/ ~LLTexLayerTemplate(); + /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height); + /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions + /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer + /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + /*virtual*/ void setHasMorph(BOOL newval); + /*virtual*/ void deleteCaches(); + /*virtual*/ BOOL isInvisibleAlphaMask() const; +protected: + U32 updateWearableCache() const; + LLTexLayer* getLayer(U32 i) const; +private: + typedef std::vector wearable_cache_t; + mutable wearable_cache_t mWearableCache; // mutable b/c most get- require updating this cache +}; - BOOL parseXml(LLXmlTreeNode* node); +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayer +// +// A single texture layer. Only exists for llvoavatarself. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayer : public LLTexLayerInterface +{ +public: + LLTexLayer(LLTexLayerSet* const layer_set); + LLTexLayer(const LLTexLayer &layer, LLWearable *wearable); + LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable); + /*virtual*/ ~LLTexLayer(); + + /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions + /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height); + + /*virtual*/ void deleteCaches(); + const U8* getAlphaData() const; + + BOOL findNetColor(LLColor4* color) const; + /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer + /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + BOOL renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color); + void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + /*virtual*/ BOOL isInvisibleAlphaMask() const; + + void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; } + LLLocalTextureObject* getLTO() { return mLocalTextureObject; } + + static void calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color); +protected: + LLUUID getUUID() const; +private: + typedef std::map alpha_cache_t; + alpha_cache_t mAlphaCache; + LLLocalTextureObject* mLocalTextureObject; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerSet +// +// An ordered set of texture layers that gets composited into a single texture. +// Only exists for llvoavatarself. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerSet +{ + friend class LLTexLayerSetBuffer; +public: + LLTexLayerSet(LLVOAvatarSelf* const avatar); + ~LLTexLayerSet(); + + const LLTexLayerSetInfo* getInfo() const { return mInfo; } + BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions + + BOOL render(S32 x, S32 y, S32 width, S32 height); + void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear = false); + + BOOL isBodyRegion(const std::string& region) const; + LLTexLayerSetBuffer* getComposite(); + const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist. + void requestUpdate(); + void requestUpload(); + void cancelUpload(); + void updateComposite(); + BOOL isLocalTextureDataAvailable() const; + BOOL isLocalTextureDataFinal() const; + void createComposite(); + void destroyComposite(); + void setUpdatesEnabled(BOOL b); + BOOL getUpdatesEnabled() const { return mUpdatesEnabled; } + void deleteCaches(); + void gatherMorphMaskAlpha(U8 *data, S32 width, S32 height); + void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); + BOOL isMorphValid() const; + void invalidateMorphMasks(); + LLTexLayerInterface* findLayerByName(const std::string& name); + void cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable* wearable); -protected: - typedef std::vector color_info_list_t; - color_info_list_t mColorInfoList; - std::string mName; + LLVOAvatarSelf* getAvatar() const { return mAvatar; } + const std::string getBodyRegionName() const; + BOOL hasComposite() const { return (mComposite.notNull()); } + LLVOAvatarDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } + void setBakedTexIndex(LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } + BOOL isVisible() const { return mIsVisible; } + + static BOOL sHasCaches; + +private: + typedef std::vector layer_list_t; + layer_list_t mLayerList; + layer_list_t mMaskLayerList; + LLPointer mComposite; + LLVOAvatarSelf* const mAvatar; // note: backlink only; don't make this an LLPointer. + BOOL mUpdatesEnabled; + BOOL mIsVisible; + + LLVOAvatarDefines::EBakedTextureIndex mBakedTexIndex; + const LLTexLayerSetInfo* mInfo; }; -//----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLTexLayerSetInfo -// Containes shared layer set data -//----------------------------------------------------------------------------- +// +// Contains shared layer set data. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLTexLayerSetInfo { friend class LLTexLayerSet; public: LLTexLayerSetInfo(); ~LLTexLayerSetInfo(); - BOOL parseXml(LLXmlTreeNode* node); - -protected: + void createVisualParams(LLVOAvatar *avatar); +private: std::string mBodyRegion; S32 mWidth; S32 mHeight; std::string mStaticAlphaFileName; - BOOL mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName) - + BOOL mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName) typedef std::vector layer_info_list_t; layer_info_list_t mLayerInfoList; }; -//----------------------------------------------------------------------------- -// LLTexLayerInfo -//----------------------------------------------------------------------------- -enum ERenderPass -{ - RP_COLOR, - RP_BUMP, - RP_SHINE -}; - -class LLTexLayerInfo -{ - friend class LLTexLayer; -public: - LLTexLayerInfo(); - ~LLTexLayerInfo(); - - BOOL parseXml(LLXmlTreeNode* node); - -protected: - std::string mName; - - BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer, - ERenderPass mRenderPass; - - std::string mGlobalColor; - LLColor4 mFixedColor; - - S32 mLocalTexture; - std::string mStaticImageFileName; - BOOL mStaticImageIsMask; - BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask - BOOL mIsVisibilityMask; - - typedef std::vector > morph_name_list_t; - morph_name_list_t mMorphNameList; - - typedef std::vector color_info_list_t; - color_info_list_t mColorInfoList; - - typedef std::vector alpha_info_list_t; - alpha_info_list_t mAlphaInfoList; - -}; - -//----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLTexLayerSetBuffer +// // The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one. -//----------------------------------------------------------------------------- +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLTexLayerSetBuffer : public LLViewerDynamicTexture { + LOG_CLASS(LLTexLayerSetBuffer); + public: - LLTexLayerSetBuffer(LLTexLayerSet* owner, S32 width, S32 height); + LLTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height); virtual ~LLTexLayerSetBuffer(); - virtual void preRender(BOOL clear_depth); - virtual void postRender(BOOL success); - virtual BOOL render(); - BOOL updateImmediate(); - bool isInitialized(void) const; - BOOL needsRender(); - void requestUpdate(); - void requestUpload(); - void requestDelayedUpload(U64 delay_usec); - void cancelUpload(); - BOOL uploadPending() { return mUploadPending; } - BOOL render( S32 x, S32 y, S32 width, S32 height ); - void readBackAndUpload(); - - static void onTextureUploadComplete( const LLUUID& uuid, - void* userdata, - S32 result, LLExtStat ext_status); +public: + /*virtual*/ S8 getType() const; + BOOL isInitialized(void) const; static void dumpTotalByteCount(); - - virtual S8 getType() const ; - virtual void restoreGLTexture() ; - virtual void destroyGLTexture() ; - -private: + const std::string dumpTextureInfo() const; + virtual void restoreGLTexture(); + virtual void destroyGLTexture(); +protected: void pushProjection() const; void popProjection() const; - BOOL needsUploadNow() const; - private: - BOOL mNeedsUpdate; - BOOL mNeedsUpload; - BOOL mUploadPending; - LLUUID mUploadID; // Identifys the current upload process (null if none). Used to avoid overlaps (eg, when the user rapidly makes two changes outside of Face Edit) - S32 mUploadFailCount; - U64 mUploadAfter; // delay upload until after this time (in microseconds) - LLTexLayerSet* mTexLayerSet; - + LLTexLayerSet* const mTexLayerSet; static S32 sGLByteCount; -}; -//----------------------------------------------------------------------------- -// LLTexLayerSet -// An ordered set of texture layers that get composited into a single texture. -//----------------------------------------------------------------------------- -class LLTexLayerSet -{ - friend class LLTexLayerSetBuffer; + //-------------------------------------------------------------------- + // Render + //-------------------------------------------------------------------- public: - LLTexLayerSet( LLVOAvatar* avatar ); - ~LLTexLayerSet(); - - //BOOL parseData(LLXmlTreeNode* node); - LLTexLayerSetInfo* getInfo() const { return mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexLayerSetInfo *info); + /*virtual*/ BOOL needsRender(); +protected: + BOOL render(S32 x, S32 y, S32 width, S32 height); + virtual void preRender(BOOL clear_depth); + virtual void postRender(BOOL success); + virtual BOOL render(); - BOOL render( S32 x, S32 y, S32 width, S32 height ); - void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear = false); - BOOL isBodyRegion( const std::string& region ) { return mInfo->mBodyRegion == region; } - LLTexLayerSetBuffer* getComposite(); - void requestUpdate(); + //-------------------------------------------------------------------- + // Uploads + //-------------------------------------------------------------------- +public: void requestUpload(); void cancelUpload(); - LLVOAvatar* getAvatar() { return mAvatar; } - void updateComposite(); - BOOL isLocalTextureDataAvailable(); - BOOL isLocalTextureDataFinal(); - void createComposite(); - void destroyComposite(); - void setUpdatesEnabled( BOOL b ); - BOOL getUpdatesEnabled() { return mUpdatesEnabled; } - void deleteCaches(); - void gatherAlphaMasks(U8 *data, S32 width, S32 height); - void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); - const std::string getBodyRegion() { return mInfo->mBodyRegion; } - BOOL hasComposite() { return (mComposite.notNull()); } - LLVOAvatarDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } - void setBakedTexIndex(LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } - BOOL isVisible() const { return mIsVisible; } - -public: - static BOOL sHasCaches; - + BOOL uploadNeeded() const; // We need to upload a new texture + BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result + BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point + static void onTextureUploadComplete(const LLUUID& uuid, + void* userdata, + S32 result, LLExtStat ext_status); protected: - typedef std::vector layer_list_t; - layer_list_t mLayerList; - layer_list_t mMaskLayerList; - LLPointer mComposite; - // Backlink only; don't make this an LLPointer. - LLVOAvatar* mAvatar; - BOOL mUpdatesEnabled; - BOOL mIsVisible; + BOOL isReadyToUpload() const; + void doUpload(); // Does a read back and upload. + void conditionalRestartUploadTimer(); +private: + BOOL mNeedsUpload; // Whether we need to send our baked textures to the server + U32 mNumLowresUploads; // Number of times we've sent a lowres version of our baked textures to the server + BOOL mUploadPending; // Whether we have received back the new baked textures + LLUUID mUploadID; // The current upload process (null if none). + LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested and performed. + S32 mUploadFailCount; // Number of consecutive upload failures + LLFrameTimer mUploadRetryTimer; // Tracks time since last upload failure. - LLVOAvatarDefines::EBakedTextureIndex mBakedTexIndex; - - LLTexLayerSetInfo *mInfo; -}; - -//----------------------------------------------------------------------------- -// LLTexLayer -// A single texture layer -//----------------------------------------------------------------------------- -class LLTexLayer -{ + //-------------------------------------------------------------------- + // Updates + //-------------------------------------------------------------------- public: - LLTexLayer( LLTexLayerSet* layer_set ); - ~LLTexLayer(); - - //BOOL parseData(LLXmlTreeNode* node); - LLTexLayerInfo* getInfo() const { return mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexLayerInfo *info); - - BOOL render( S32 x, S32 y, S32 width, S32 height ); void requestUpdate(); - LLTexLayerSet* getTexLayerSet() { return mTexLayerSet; } - - const std::string& getName() { return mInfo->mName; } - - void addMaskedMorph(LLPolyMorphTarget* morph_target, BOOL invert); - void deleteCaches(); - U8* getAlphaData(); - void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); - - void invalidateMorphMasks(); - ERenderPass getRenderPass() { return mInfo->mRenderPass; } - const std::string& getGlobalColor() { return mInfo->mGlobalColor; } - BOOL findNetColor( LLColor4* color ); - BOOL renderImageRaw( U8* in_data, S32 in_width, S32 in_height, S32 in_components, S32 width, S32 height, BOOL is_mask ); - BOOL renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4* colorp ); - BOOL hasAlphaParams() { return (!mParamAlphaList.empty());} - BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); - BOOL isVisibilityMask() const; - BOOL isInvisibleAlphaMask(); - + BOOL requestUpdateImmediate(); protected: - LLTexLayerSet* mTexLayerSet; - LLPointer mStaticImageRaw; - - // Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order. - typedef std::vector color_list_t; - color_list_t mParamColorList; - // mGlobalColor name stored in mInfo - // mFixedColor value stored in mInfo - - typedef std::vector alpha_list_t; - alpha_list_t mParamAlphaList; - - - typedef std::deque morph_list_t; - morph_list_t mMaskedMorphs; - typedef std::map alpha_cache_t; - alpha_cache_t mAlphaCache; - BOOL mMorphMasksValid; - BOOL mStaticImageInvalid; - - LLTexLayerInfo *mInfo; + BOOL isReadyToUpdate() const; + void doUpdate(); + void restartUpdateTimer(); +private: + BOOL mNeedsUpdate; // Whether we need to locally update our baked textures + U32 mNumLowresUpdates; // Number of times we've locally updated with lowres version of our baked textures + LLFrameTimer mNeedsUpdateTimer; // Tracks time since update was requested and performed. }; -//----------------------------------------------------------------------------- -// LLTexLayerParamAlpha -//----------------------------------------------------------------------------- -class LLTexLayerParamAlpha : public LLViewerVisualParam +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerStaticImageList +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerStaticImageList : public LLSingleton { public: - LLTexLayerParamAlpha( LLTexLayer* layer ); - /*virtual*/ ~LLTexLayerParamAlpha(); - - // Special: These functions are overridden by child classes - LLTexLayerParamAlphaInfo* getInfo() const { return (LLTexLayerParamAlphaInfo*)mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexLayerParamAlphaInfo *info); - - // LLVisualParam Virtual functions - ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); - /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight, BOOL set_by_user); - /*virtual*/ void setAnimationTarget(F32 target_value, BOOL set_by_user); - /*virtual*/ void animate(F32 delta, BOOL set_by_user); - - // LLViewerVisualParam Virtual functions - /*virtual*/ F32 getTotalDistortion() { return 1.f; } - /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } - /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f);} - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; - - // New functions - BOOL render( S32 x, S32 y, S32 width, S32 height ); - BOOL getSkip(); - void deleteCaches(); - LLTexLayer* getTexLayer() { return mTexLayer; } - BOOL getMultiplyBlend() { return getInfo()->mMultiplyBlend; } - -protected: - LLPointer mCachedProcessedTexture; - LLTexLayer* mTexLayer; - LLPointer mStaticImageTGA; - LLPointer mStaticImageRaw; - BOOL mNeedsCreateTexture; - BOOL mStaticImageInvalid; - LLVector3 mAvgDistortionVec; - F32 mCachedEffectiveWeight; - -public: - // Global list of instances for gathering statistics - static void dumpCacheByteCount(); - static void getCacheByteCount( S32* gl_bytes ); - - typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t; - static param_alpha_ptr_list_t sInstances; -}; - - -//----------------------------------------------------------------------------- -// LLTexGlobalColor -//----------------------------------------------------------------------------- -class LLTexGlobalColor -{ -public: - LLTexGlobalColor( LLVOAvatar* avatar ); - ~LLTexGlobalColor(); - - //BOOL parseData(LLXmlTreeNode* node); - LLTexGlobalColorInfo* getInfo() const { return mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexGlobalColorInfo *info); - - void requstUpdate(); - LLVOAvatar* getAvatar() { return mAvatar; } - LLColor4 getColor(); - const std::string& getName() { return mInfo->mName; } - -protected: - typedef std::vector param_list_t; - param_list_t mParamList; - LLVOAvatar* mAvatar; // just backlink, don't LLPointer - - LLTexGlobalColorInfo *mInfo; -}; - - -//----------------------------------------------------------------------------- -// LLTexParamColor -//----------------------------------------------------------------------------- -class LLTexParamColor : public LLViewerVisualParam -{ -public: - LLTexParamColor( LLTexGlobalColor* tex_color ); - LLTexParamColor( LLTexLayer* layer ); - /* virtual */ ~LLTexParamColor(); - - // Special: These functions are overridden by child classes - LLTexParamColorInfo* getInfo() const { return (LLTexParamColorInfo*)mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexParamColorInfo *info); - - // LLVisualParam Virtual functions - ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); - /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight, BOOL set_by_user); - /*virtual*/ void setAnimationTarget(F32 target_value, BOOL set_by_user); - /*virtual*/ void animate(F32 delta, BOOL set_by_user); - - - // LLViewerVisualParam Virtual functions - /*virtual*/ F32 getTotalDistortion() { return 1.f; } - /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } - /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f); } - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; - - // New functions - LLColor4 getNetColor(); - EColorOperation getOperation() const { return getInfo()->mOperation; } - - -protected: - LLVector3 mAvgDistortionVec; - LLTexGlobalColor* mTexGlobalColor; // either has mTexGlobalColor or mTexLayer as its parent - LLTexLayer* mTexLayer; - LLVOAvatar* mAvatar; // redundant, but simplifies the code (don't LLPointer) -}; - -//----------------------------------------------------------------------------- -// LLTexStaticImageList -//----------------------------------------------------------------------------- - -class LLTexStaticImageList -{ -public: - LLTexStaticImageList(); - ~LLTexStaticImageList(); - - LLImageRaw* getImageRaw( const std::string& file_name ); - LLViewerTexture* getTexture( const std::string& file_name, BOOL is_mask ); - LLImageTGA* getImageTGA( const std::string& file_name ); - + LLTexLayerStaticImageList(); + ~LLTexLayerStaticImageList(); + LLViewerTexture* getTexture(const std::string& file_name, BOOL is_mask); + LLImageTGA* getImageTGA(const std::string& file_name); void deleteCachedImages(); void dumpByteCount() const; protected: BOOL loadImageRaw(const std::string& file_name, LLImageRaw* image_raw); - private: - static LLStringTable sImageNames; - + LLStringTable mImageNames; typedef std::map > texture_map_t; texture_map_t mStaticImageList; typedef std::map > image_tga_map_t; image_tga_map_t mStaticImageListTGA; -public: S32 mGLBytes; S32 mTGABytes; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLBakedUploadData +// // Used by LLTexLayerSetBuffer for a callback. - -// For DEV-DEV-31590, "Heap corruption and crash after outfit -// changes", added the mLayerSet member. The current -// LLTexLayerSetBuffer can be found by querying mLayerSet->mComposite, -// but we still store the original mLayerSetBuffer here so we can -// detect when an upload is out of date. This prevents a memory -// stomp. See LLTexLayerSetBuffer::onTextureUploadComplete() for usage. -class LLBakedUploadData +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +struct LLBakedUploadData { -public: - LLBakedUploadData( LLVOAvatar* avatar, LLTexLayerSet* layerset, LLTexLayerSetBuffer* layerset_buffer, const LLUUID & id); + LLBakedUploadData(const LLVOAvatarSelf* avatar, + LLTexLayerSet* layerset, + const LLUUID& id, + bool highest_res); ~LLBakedUploadData() {} - - LLUUID mID; - LLVOAvatar* mAvatar; // just backlink, don't LLPointer - LLTexLayerSet* mTexLayerSet; - LLTexLayerSetBuffer* mLayerSetBuffer; - LLUUID mWearableAssets[LLWearableType::WT_COUNT]; - U64 mStartTime; // Used to measure time baked texture upload requires + const LLUUID mID; + const LLVOAvatarSelf* mAvatar; // note: backlink only; don't LLPointer + LLTexLayerSet* mTexLayerSet; + const U64 mStartTime; // for measuring baked texture upload time + const bool mIsHighestRes; // whether this is a "final" bake, or intermediate low res }; -extern LLTexStaticImageList gTexStaticImageList; - - #endif // LL_LLTEXLAYER_H diff --git a/indra/newview/lltexlayerparams.h b/indra/newview/lltexlayerparams.h new file mode 100644 index 000000000..74c22b0cd --- /dev/null +++ b/indra/newview/lltexlayerparams.h @@ -0,0 +1,193 @@ +/** + * @file lltexlayerparams.h + * @brief Texture layer parameters, used by lltexlayer. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXLAYERPARAMS_H +#define LL_LLTEXLAYERPARAMS_H + +#include "llviewervisualparam.h" + +class LLImageRaw; +class LLImageTGA; +class LLTexLayer; +class LLTexLayerInterface; +class LLViewerTexture; +class LLVOAvatar; +class LLWearable; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerParam +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerParam : public LLViewerVisualParam +{ +public: + LLTexLayerParam(LLTexLayerInterface *layer); + LLTexLayerParam(LLVOAvatar *avatar); + /*virtual*/ BOOL setInfo(LLViewerVisualParamInfo *info, BOOL add_to_avatar ); + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0; + +protected: + LLTexLayerInterface* mTexLayer; + LLVOAvatar* mAvatar; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerParamAlpha +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerParamAlpha : public LLTexLayerParam +{ +public: + LLTexLayerParamAlpha( LLTexLayerInterface* layer ); + LLTexLayerParamAlpha( LLVOAvatar* avatar ); + /*virtual*/ ~LLTexLayerParamAlpha(); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex avatar_sex ) {} + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake); + /*virtual*/ void animate(F32 delta, BOOL upload_bake); + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion() { return 1.f; } + /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() { return 3.f; } + /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f);} + /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + + // New functions + BOOL render( S32 x, S32 y, S32 width, S32 height ); + BOOL getSkip() const; + void deleteCaches(); + BOOL getMultiplyBlend() const; + +private: + LLPointer mCachedProcessedTexture; + LLPointer mStaticImageTGA; + LLPointer mStaticImageRaw; + BOOL mNeedsCreateTexture; + BOOL mStaticImageInvalid; + LLVector3 mAvgDistortionVec; + F32 mCachedEffectiveWeight; + +public: + // Global list of instances for gathering statistics + static void dumpCacheByteCount(); + static void getCacheByteCount( S32* gl_bytes ); + + typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t; + static param_alpha_ptr_list_t sInstances; +}; +class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo +{ + friend class LLTexLayerParamAlpha; +public: + LLTexLayerParamAlphaInfo(); + /*virtual*/ ~LLTexLayerParamAlphaInfo() {}; + + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + +private: + std::string mStaticImageFileName; + BOOL mMultiplyBlend; + BOOL mSkipIfZeroWeight; + F32 mDomain; +}; +// +// LLTexLayerParamAlpha +//----------------------------------------------------------------------------- + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerParamColor +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerParamColor : public LLTexLayerParam +{ +public: + enum EColorOperation + { + OP_ADD = 0, + OP_MULTIPLY = 1, + OP_BLEND = 2, + OP_COUNT = 3 // Number of operations + }; + + LLTexLayerParamColor( LLTexLayerInterface* layer ); + LLTexLayerParamColor( LLVOAvatar* avatar ); + /* virtual */ ~LLTexLayerParamColor(); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex avatar_sex ) {} + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake); + /*virtual*/ void animate(F32 delta, BOOL upload_bake); + + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion() { return 1.f; } + /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() { return 3.f; } + /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f); } + /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + + // New functions + LLColor4 getNetColor() const; +protected: + virtual void onGlobalColorChanged(bool upload_bake) {} +private: + LLVector3 mAvgDistortionVec; +}; + +class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo +{ + friend class LLTexLayerParamColor; + +public: + LLTexLayerParamColorInfo(); + virtual ~LLTexLayerParamColorInfo() {}; + BOOL parseXml( LLXmlTreeNode* node ); + LLTexLayerParamColor::EColorOperation getOperation() const { return mOperation; } +private: + enum { MAX_COLOR_VALUES = 20 }; + LLTexLayerParamColor::EColorOperation mOperation; + LLColor4 mColors[MAX_COLOR_VALUES]; + S32 mNumColors; +}; + +typedef std::vector param_color_list_t; +typedef std::vector param_alpha_list_t; +typedef std::vector param_color_info_list_t; +typedef std::vector param_alpha_info_list_t; + +#endif diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index a6ab683b4..1662af54e 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -292,7 +292,7 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mInventoryPanel->setFilterTypes(filter_types); //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss. mInventoryPanel->setFilterPermMask(immediate_filter_perm_mask); - mInventoryPanel->setSelectCallback(onSelectionChange, this); + mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterTexturePicker::onSelectionChange, _1, _2, (void*)this)); mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); mInventoryPanel->setAllowMultiSelect(FALSE); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index d25c4df77..3872337ed 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -42,6 +42,9 @@ #include "llagent.h" #include "llagentcamera.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "lldictionary.h" #include "llviewercontrol.h" #include "llfirstuse.h" #include "llfloater.h" @@ -1731,10 +1734,11 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( { if(mSource == SOURCE_LIBRARY) { -// LLPointer cb = new RezAttachmentCallback(0); + LLPointer cb = new RezAttachmentCallback(0); + //Reapply this patch later. // [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-08 (Catznip-2.2.0a) | Added: Catznip-2.2.0a // Make this behave consistent with dad3dWearItem - LLPointer cb = new RezAttachmentCallback(0, !(mask & MASK_CONTROL)); + //LLPointer cb = new RezAttachmentCallback(0, !(mask & MASK_CONTROL)); // MULTI-WEARABLES TODO // [/SL:KB] copy_inventory_item( gAgent.getID(), @@ -2074,23 +2078,9 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( return ACCEPT_NO; } - if(mSource == SOURCE_LIBRARY) - { - // create item based on that one, and put it on if that - // was a success. - LLPointer cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_inventory_item_on_avatar( item ); - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 + + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL)); } return ACCEPT_YES_MULTI; } @@ -2181,7 +2171,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( if(drop) { BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE ); - wear_inventory_category(category, false, append); + LLAppearanceMgr::instance().wearInventoryCategory(category, false, append); } return ACCEPT_YES_MULTI; } @@ -2189,7 +2179,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( { if(drop) { - wear_inventory_category(category, true, false); + LLAppearanceMgr::instance().wearInventoryCategory(category, true, false); } return ACCEPT_YES_MULTI; } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 915b6483f..6b24bcde8 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -190,7 +190,7 @@ static bool handleAvatarBoobXYInfluence(const LLSD& newvalue) static bool handleSetSelfInvisible( const LLSD& newvalue) { - LLVOAvatar::onChangeSelfInvisible( newvalue.asBoolean() ); + LLVOAvatarSelf::onChangeSelfInvisible( newvalue.asBoolean() ); return true; } diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index 85dbcc562..b005857b1 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -40,6 +40,7 @@ struct ViewerFolderEntry : public LLDictionaryEntry const std::string &icon_name_open, // name of the folder icon const std::string &icon_name_closed, BOOL is_quiet, // folder doesn't need a UI update when changed + bool hide_if_empty, // folder not shown if empty const std::string &dictionary_name = empty_string // no reverse lookup needed on non-ensembles, so in most cases just leave this blank ) : @@ -47,7 +48,8 @@ struct ViewerFolderEntry : public LLDictionaryEntry mNewCategoryName(new_category_name), mIconNameOpen(icon_name_open), mIconNameClosed(icon_name_closed), - mIsQuiet(is_quiet) + mIsQuiet(is_quiet), + mHideIfEmpty(hide_if_empty) { mAllowedNames.clear(); } @@ -64,9 +66,10 @@ struct ViewerFolderEntry : public LLDictionaryEntry mIconNameOpen(icon_name), mIconNameClosed(icon_name), */ - mIconNameOpen("Inv_FolderOpen"), mIconNameClosed("Inv_FolderClosed"), + mIconNameOpen("inv_folder_plain_closed.tga"), mIconNameClosed("inv_folder_plain_closed.tga"), mNewCategoryName(new_category_name), - mIsQuiet(FALSE) + mIsQuiet(FALSE), + mHideIfEmpty(false) { const std::string delims (","); LLStringUtilBase::getTokens(allowed_names, mAllowedNames, delims); @@ -91,6 +94,7 @@ struct ViewerFolderEntry : public LLDictionaryEntry typedef std::vector name_vec_t; name_vec_t mAllowedNames; BOOL mIsQuiet; + bool mHideIfEmpty; }; class LLViewerFolderDictionary : public LLSingleton, @@ -104,43 +108,43 @@ protected: LLViewerFolderDictionary::LLViewerFolderDictionary() { - // NEW CATEGORY NAME FOLDER OPEN FOLDER CLOSED QUIET? - // |-------------------------|-----------------------|----------------------|-----------| - addEntry(LLFolderType::FT_TEXTURE, new ViewerFolderEntry("Textures", "inv_folder_texture.tga", "inv_folder_texture.tga", FALSE)); - addEntry(LLFolderType::FT_SOUND, new ViewerFolderEntry("Sounds", "inv_folder_sound.tga", "inv_folder_sound.tga", FALSE)); - addEntry(LLFolderType::FT_CALLINGCARD, new ViewerFolderEntry("Calling Cards", "inv_folder_callingcard.tga", "inv_folder_callingcard.tga", FALSE)); - addEntry(LLFolderType::FT_LANDMARK, new ViewerFolderEntry("Landmarks", "inv_folder_landmark.tga", "inv_folder_landmark.tga", FALSE)); - addEntry(LLFolderType::FT_CLOTHING, new ViewerFolderEntry("Clothing", "inv_folder_clothing.tga", "inv_folder_clothing.tga", FALSE)); - addEntry(LLFolderType::FT_OBJECT, new ViewerFolderEntry("Objects", "inv_folder_object.tga", "inv_folder_object.tga", FALSE)); - addEntry(LLFolderType::FT_NOTECARD, new ViewerFolderEntry("Notecards", "inv_folder_notecard.tga", "inv_folder_notecard.tga", FALSE)); - addEntry(LLFolderType::FT_ROOT_INVENTORY, new ViewerFolderEntry("My Inventory", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); - addEntry(LLFolderType::FT_LSL_TEXT, new ViewerFolderEntry("Scripts", "inv_folder_script.tga", "inv_folder_script.tga", FALSE)); - addEntry(LLFolderType::FT_BODYPART, new ViewerFolderEntry("Body Parts", "inv_folder_bodypart.tga", "inv_folder_bodypart.tga", FALSE)); - addEntry(LLFolderType::FT_TRASH, new ViewerFolderEntry("Trash", "inv_folder_trash.tga", "inv_folder_trash.tga", TRUE)); - addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new ViewerFolderEntry("Photo Album", "inv_folder_snapshot.tga", "inv_folder_snapshot.tga", FALSE)); - addEntry(LLFolderType::FT_LOST_AND_FOUND, new ViewerFolderEntry("Lost And Found", "inv_folder_lostandfound.tga", "inv_folder_lostandfound.tga", TRUE)); - addEntry(LLFolderType::FT_ANIMATION, new ViewerFolderEntry("Animations", "inv_folder_animation.tga", "inv_folder_animation.tga", FALSE)); - addEntry(LLFolderType::FT_GESTURE, new ViewerFolderEntry("Gestures", "inv_folder_gesture.tga", "inv_folder_gesture.tga", FALSE)); - addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + // NEW CATEGORY NAME FOLDER OPEN FOLDER CLOSED QUIET? HIDE IF EMPTY? + // |-------------------------|-----------------------------------|---------------------------|--------------|------------| + addEntry(LLFolderType::FT_TEXTURE, new ViewerFolderEntry("Textures", "inv_folder_texture.tga", "inv_folder_texture.tga", FALSE, false)); + addEntry(LLFolderType::FT_SOUND, new ViewerFolderEntry("Sounds", "inv_folder_sound.tga", "inv_folder_sound.tga", FALSE, false)); + addEntry(LLFolderType::FT_CALLINGCARD, new ViewerFolderEntry("Calling Cards", "inv_folder_callingcard.tga", "inv_folder_callingcard.tga", FALSE, false)); + addEntry(LLFolderType::FT_LANDMARK, new ViewerFolderEntry("Landmarks", "inv_folder_landmark.tga", "inv_folder_landmark.tga", FALSE, false)); + addEntry(LLFolderType::FT_CLOTHING, new ViewerFolderEntry("Clothing", "inv_folder_clothing.tga", "inv_folder_clothing.tga", FALSE, false)); + addEntry(LLFolderType::FT_OBJECT, new ViewerFolderEntry("Objects", "inv_folder_object.tga", "inv_folder_object.tga", FALSE, false)); + addEntry(LLFolderType::FT_NOTECARD, new ViewerFolderEntry("Notecards", "inv_folder_notecard.tga", "inv_folder_notecard.tga", FALSE, false)); + addEntry(LLFolderType::FT_ROOT_INVENTORY, new ViewerFolderEntry("My Inventory", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_LSL_TEXT, new ViewerFolderEntry("Scripts", "inv_folder_script.tga", "inv_folder_script.tga", FALSE, false)); + addEntry(LLFolderType::FT_BODYPART, new ViewerFolderEntry("Body Parts", "inv_folder_bodypart.tga", "inv_folder_bodypart.tga", FALSE, false)); + addEntry(LLFolderType::FT_TRASH, new ViewerFolderEntry("Trash", "inv_folder_trash.tga", "inv_folder_trash.tga", TRUE, false)); + addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new ViewerFolderEntry("Photo Album", "inv_folder_snapshot.tga", "inv_folder_snapshot.tga", FALSE, false)); + addEntry(LLFolderType::FT_LOST_AND_FOUND, new ViewerFolderEntry("Lost And Found", "inv_folder_lostandfound.tga", "inv_folder_lostandfound.tga", TRUE, false)); + addEntry(LLFolderType::FT_ANIMATION, new ViewerFolderEntry("Animations", "inv_folder_animation.tga", "inv_folder_animation.tga", FALSE, false)); + addEntry(LLFolderType::FT_GESTURE, new ViewerFolderEntry("Gestures", "inv_folder_gesture.tga", "inv_folder_gesture.tga", FALSE, false)); + addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE)); - addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE)); - addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE)); - addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE, false)); + addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE, false)); + addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE, false)); + addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); - addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Outbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Outbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, "default")); + addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false, "default")); #if SUPPORT_ENSEMBLES initEnsemblesFromFile(); #else for (U32 type = (U32)LLFolderType::FT_ENSEMBLE_START; type <= (U32)LLFolderType::FT_ENSEMBLE_END; ++type) { - addEntry((LLFolderType::EType)type, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + addEntry((LLFolderType::EType)type, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); } #endif } @@ -259,6 +263,15 @@ BOOL LLViewerFolderType::lookupIsQuietType(LLFolderType::EType folder_type) return FALSE; } +bool LLViewerFolderType::lookupIsHiddenIfEmpty(LLFolderType::EType folder_type) +{ + const ViewerFolderEntry *entry = LLViewerFolderDictionary::getInstance()->lookup(folder_type); + if (entry) + { + return entry->mHideIfEmpty; + } + return false; +} const std::string &LLViewerFolderType::lookupNewCategoryName(LLFolderType::EType folder_type) { diff --git a/indra/newview/llviewerfoldertype.h b/indra/newview/llviewerfoldertype.h index f5938de61..13d5a8fbb 100644 --- a/indra/newview/llviewerfoldertype.h +++ b/indra/newview/llviewerfoldertype.h @@ -40,6 +40,7 @@ public: static const std::string& lookupIconName(EType folder_type, BOOL is_open = FALSE); // folder icon name static BOOL lookupIsQuietType(EType folder_type); // folder doesn't require UI update when changes have occured + static bool lookupIsHiddenIfEmpty(EType folder_type); // folder is not displayed if empty static const std::string& lookupNewCategoryName(EType folder_type); // default name when creating new category static LLFolderType::EType lookupTypeFromNewCategoryName(const std::string& name); // default name when creating new category diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 60491e952..e328bbc66 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -34,29 +34,39 @@ #include "llviewerinventory.h" #include "llnotificationsutil.h" +#include "llsdserialize.h" #include "message.h" -#include "indra_constants.h" #include "llagent.h" #include "llagentcamera.h" -#include "llfloaterinventory.h" +#include "llagentwearables.h" +#include "llviewerfoldertype.h" +#include "llfolderview.h" #include "llviewercontrol.h" #include "llconsole.h" +#include "llinventorydefines.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" -#include "llnotify.h" -#include "llimview.h" +#include "llinventorymodelbackgroundfetch.h" #include "llgesturemgr.h" #include "llinventorybridge.h" -#include "llinventorydefines.h" -#include "llinventorymodelbackgroundfetch.h" #include "llinventorypanel.h" +#include "llfloaterinventory.h" +#include "lllandmark.h" +#include "llviewerassettype.h" #include "llviewerregion.h" #include "llviewerobjectlist.h" #include "llpreviewgesture.h" #include "llviewerwindow.h" +#include "lltrans.h" +#include "llappearancemgr.h" +#include "llcommandhandler.h" +#include "llviewermessage.h" +#include "llavatarnamecache.h" +#include "llfloatercustomize.h" // #include "llappviewer.h" // System Folders // @@ -276,8 +286,7 @@ BOOL LLViewerInventoryItem::unpackMessage(LLSD item) } // virtual -BOOL LLViewerInventoryItem::unpackMessage( - LLMessageSystem* msg, const char* block, S32 block_num) +BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) { BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num); mIsComplete = TRUE; @@ -634,6 +643,78 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const return true; } +void LLViewerInventoryCategory::determineFolderType() +{ + /* Do NOT uncomment this code. This is for future 2.1 support of ensembles. + llassert(FALSE); + LLFolderType::EType original_type = getPreferredType(); + if (LLFolderType::lookupIsProtectedType(original_type)) + return; + + U64 folder_valid = 0; + U64 folder_invalid = 0; + LLInventoryModel::cat_array_t category_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getUUID(),category_array,item_array,FALSE); + + // For ensembles + if (category_array.empty()) + { + for (LLInventoryModel::item_array_t::iterator item_iter = item_array.begin(); + item_iter != item_array.end(); + item_iter++) + { + const LLViewerInventoryItem *item = (*item_iter); + if (item->getIsLinkType()) + return; + if (item->isWearableType()) + { + const LLWearableType::EType wearable_type = item->getWearableType(); + const std::string& wearable_name = LLWearableType::getTypeName(wearable_type); + U64 valid_folder_types = LLViewerFolderType::lookupValidFolderTypes(wearable_name); + folder_valid |= valid_folder_types; + folder_invalid |= ~valid_folder_types; + } + } + for (U8 i = LLFolderType::FT_ENSEMBLE_START; i <= LLFolderType::FT_ENSEMBLE_END; i++) + { + if ((folder_valid & (1LL << i)) && + !(folder_invalid & (1LL << i))) + { + changeType((LLFolderType::EType)i); + return; + } + } + } + if (LLFolderType::lookupIsEnsembleType(original_type)) + { + changeType(LLFolderType::FT_NONE); + } + llassert(FALSE); + */ +} + +void LLViewerInventoryCategory::changeType(LLFolderType::EType new_folder_type) +{ + const LLUUID &folder_id = getUUID(); + const LLUUID &parent_id = getParentUUID(); + const std::string &name = getName(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->addUUIDFast(_PREHASH_ParentID, parent_id); + msg->addS8Fast(_PREHASH_Type, new_folder_type); + msg->addStringFast(_PREHASH_Name, name); + gAgent.sendReliableMessage(); + + setPreferredType(new_folder_type); + gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); +} ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- @@ -661,6 +742,21 @@ LLInventoryCallbackManager::~LLInventoryCallbackManager() sInstance = NULL; } +//static +void LLInventoryCallbackManager::destroyClass() +{ + if (sInstance) + { + for (callback_map_t::iterator it = sInstance->mMap.begin(), end_it = sInstance->mMap.end(); it != end_it; ++it) + { + // drop LLPointer reference to callback + it->second = NULL; + } + sInstance->mMap.clear(); + } +} + + U32 LLInventoryCallbackManager::registerCB(LLPointer cb) { if (cb.isNull()) @@ -697,14 +793,33 @@ void WearOnAvatarCallback::fire(const LLUUID& inv_item) LLViewerInventoryItem *item = gInventory.getItem(inv_item); if (item) { - wear_inventory_item_on_avatar(item); + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, mReplace); } } -RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp, bool replace) +void ModifiedCOFCallback::fire(const LLUUID& inv_item) +{ + LLAppearanceMgr::instance().updateAppearanceFromCOF(); + + // Start editing the item if previously requested. + gAgentWearables.editWearableIfRequested(inv_item); + + // TODO: camera mode may not be changed if a debug setting is tweaked + if( gAgentCamera.cameraCustomizeAvatar() ) + { + // If we're in appearance editing mode, the current tab may need to be refreshed + /*LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel) + { + panel->showDefaultSubpart(); + }*/ + gFloaterCustomize->switchToDefaultSubpart(); + } +} + +RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp) { mAttach = attachmentp; - mReplace = replace; } RezAttachmentCallback::~RezAttachmentCallback() { @@ -718,7 +833,7 @@ void RezAttachmentCallback::fire(const LLUUID& inv_item) LLViewerInventoryItem *item = gInventory.getItem(inv_item); if (item) { - rez_attachment(item, mAttach, mReplace); + rez_attachment(item, mAttach); } } @@ -755,6 +870,13 @@ void CreateGestureCallback::fire(const LLUUID& inv_item) } } +void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) +{ + if (mTargetLandmarkId.isNull()) return; + + //gInventory.rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); // MULTI-WEARABLES TODO +} + LLInventoryCallbackManager gInventoryCallbacks; void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, @@ -784,6 +906,16 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, gAgent.sendReliableMessage(); } +void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer cb/*=NULL*/) +{ + std::string item_desc = avatar_id.asString(); + std::string item_name; + gCacheName->getFullName(avatar_id, item_name); + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD, + LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); +} + void copy_inventory_item( const LLUUID& agent_id, const LLUUID& current_owner, @@ -893,25 +1025,23 @@ void move_inventory_item( gAgent.sendReliableMessage(); } -class LLCopyInventoryFromNotecardResponder : public LLHTTPClient::Responder +const LLUUID get_folder_by_itemtype(const LLInventoryItem *src) { -public: - //If we get back a normal response, handle it here - virtual void result(const LLSD& content) + LLUUID retval = LLUUID::null; + + if (src) { - // What do we do here? - llinfos << "CopyInventoryFromNotecard request successful." << llendl; + retval = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(src->getType())); } + + return retval; +} - //If we get back an error (not found, etc...), handle it here - virtual void error(U32 status, const std::string& reason) - { - llinfos << "LLCopyInventoryFromNotecardResponder::error " - << status << ": " << reason << llendl; - } -}; - -void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecard_inv_id, const LLInventoryItem *src, U32 callback_id) +void copy_inventory_from_notecard(const LLUUID& destination_id, + const LLUUID& object_id, + const LLUUID& notecard_inv_id, + const LLInventoryItem *src, + U32 callback_id) { if (NULL == src) { @@ -957,12 +1087,114 @@ void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecar body["notecard-id"] = notecard_inv_id; body["object-id"] = object_id; body["item-id"] = src->getUUID(); - body["folder-id"] = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(src->getType())); + body["folder-id"] = destination_id; body["callback-id"] = (LLSD::Integer)callback_id; - LLHTTPClient::post(url, body, new LLCopyInventoryFromNotecardResponder()); + LLHTTPClient::post(url, body, new LLHTTPClient::Responder() ); } +void create_new_item(const std::string& name, + const LLUUID& parent_id, + LLAssetType::EType asset_type, + LLInventoryType::EType inv_type, + U32 next_owner_perm) +{ + std::string desc; + LLViewerAssetType::generateDescriptionFor(asset_type, desc); + next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER; + + + if (inv_type == LLInventoryType::IT_GESTURE) + { + LLPointer cb = new CreateGestureCallback(); + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type, + NOT_WEARABLE, next_owner_perm, cb); + } + else + { + LLPointer cb = NULL; + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type, + NOT_WEARABLE, next_owner_perm, cb); + } + +} + +const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) +const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) +const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) + +// ! REFACTOR ! Really need to refactor this so that it's not a bunch of if-then statements... +/*void menu_create_inventory_item(LLFolderView* root, LLFolderBridge *bridge, const LLSD& userdata, const LLUUID& default_parent_uuid) +{ + std::string type_name = userdata.asString(); + + if (("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) + { + LLFolderType::EType preferred_type = LLFolderType::lookup(type_name); + + LLUUID parent_id; + if (bridge) + { + parent_id = bridge->getUUID(); + } + else if (default_parent_uuid.notNull()) + { + parent_id = default_parent_uuid; + } + else + { + parent_id = gInventory.getRootFolderID(); + } + + LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null); + gInventory.notifyObservers(); + root->setSelectionByID(category, TRUE); + } + else if ("lsl" == type_name) + { + const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT); + create_new_item(NEW_LSL_NAME, + parent_id, + LLAssetType::AT_LSL_TEXT, + LLInventoryType::IT_LSL, + PERM_MOVE | PERM_TRANSFER); + } + else if ("notecard" == type_name) + { + const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD); + create_new_item(NEW_NOTECARD_NAME, + parent_id, + LLAssetType::AT_NOTECARD, + LLInventoryType::IT_NOTECARD, + PERM_ALL); + } + else if ("gesture" == type_name) + { + const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + create_new_item(NEW_GESTURE_NAME, + parent_id, + LLAssetType::AT_GESTURE, + LLInventoryType::IT_GESTURE, + PERM_ALL); + } + else + { + // Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary. + LLWearableType::EType wearable_type = LLWearableType::typeNameToType(type_name); + if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT) + { + const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null; + LLAgentWearables::createWearable(wearable_type, false, parent_id); + } + else + { + llwarns << "Can't create unrecognized type " << type_name << llendl; + } + } + root->setNeedsAutoRename(TRUE); +}*/ LLAssetType::EType LLViewerInventoryItem::getType() const { @@ -987,6 +1219,23 @@ const LLUUID& LLViewerInventoryItem::getAssetUUID() const return LLInventoryItem::getAssetUUID(); } +const LLUUID& LLViewerInventoryItem::getProtectedAssetUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getProtectedAssetUUID(); + } + + // check for conditions under which we may return a visible UUID to the user + bool item_is_fullperm = getIsFullPerm(); + bool agent_is_godlike = gAgent.isGodlikeWithoutAdminMenuFakery(); + if (item_is_fullperm || agent_is_godlike) + { + return LLInventoryItem::getAssetUUID(); + } + + return LLUUID::null; +} const bool LLViewerInventoryItem::getIsFullPerm() const { @@ -1003,6 +1252,7 @@ const bool LLViewerInventoryItem::getIsFullPerm() const gAgent.getID(), gAgent.getGroupID()) ); } + const std::string& LLViewerInventoryItem::getName() const { if (const LLViewerInventoryItem *linked_item = getLinkedItem()) @@ -1017,6 +1267,327 @@ const std::string& LLViewerInventoryItem::getName() const return LLInventoryItem::getName(); } +#if 0 +/** + * Class to store sorting order of favorites landmarks in a local file. EXT-3985. + * It replaced previously implemented solution to store sort index in landmark's name as a "@" prefix. + * Data are stored in user home directory. + */ +class LLFavoritesOrderStorage : public LLSingleton + , public LLDestroyClass +{ +public: + /** + * Sets sort index for specified with LLUUID favorite landmark + */ + void setSortIndex(const LLUUID& inv_item_id, S32 sort_index); + + /** + * Gets sort index for specified with LLUUID favorite landmark + */ + S32 getSortIndex(const LLUUID& inv_item_id); + void removeSortIndex(const LLUUID& inv_item_id); + + void getSLURL(const LLUUID& asset_id); + + /** + * Implementation of LLDestroyClass. Calls cleanup() instance method. + * + * It is important this callback is called before gInventory is cleaned. + * For now it is called from LLAppViewer::cleanup() -> LLAppViewer::disconnectViewer(), + * Inventory is cleaned later from LLAppViewer::cleanup() after LLAppViewer::disconnectViewer() is called. + * @see cleanup() + */ + static void destroyClass(); + + const static S32 NO_INDEX; +private: + friend class LLSingleton; + LLFavoritesOrderStorage() : mIsDirty(false) { load(); } + ~LLFavoritesOrderStorage() { save(); } + + /** + * Removes sort indexes for items which are not in Favorites bar for now. + */ + void cleanup(); + + const static std::string SORTING_DATA_FILE_NAME; + + void load(); + void save(); + + void saveFavoritesSLURLs(); + + // Remove record of current user's favorites from file on disk. + void removeFavoritesRecordOfUser(); + + void onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark); + void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl); + + typedef std::map sort_index_map_t; + sort_index_map_t mSortIndexes; + + typedef std::map slurls_map_t; + slurls_map_t mSLURLs; + + bool mIsDirty; + + struct IsNotInFavorites + { + IsNotInFavorites(const LLInventoryModel::item_array_t& items) + : mFavoriteItems(items) + { + + } + + /** + * Returns true if specified item is not found among inventory items + *// + bool operator()(const sort_index_map_t::value_type& id_index_pair) const + { + LLPointer item = gInventory.getItem(id_index_pair.first); + if (item.isNull()) return true; + + LLInventoryModel::item_array_t::const_iterator found_it = + std::find(mFavoriteItems.begin(), mFavoriteItems.end(), item); + + return found_it == mFavoriteItems.end(); + } + private: + LLInventoryModel::item_array_t mFavoriteItems; + }; + +}; + +const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml"; +const S32 LLFavoritesOrderStorage::NO_INDEX = -1; + +void LLFavoritesOrderStorage::setSortIndex(const LLUUID& inv_item_id, S32 sort_index) +{ + mSortIndexes[inv_item_id] = sort_index; + mIsDirty = true; +} + +S32 LLFavoritesOrderStorage::getSortIndex(const LLUUID& inv_item_id) +{ + sort_index_map_t::const_iterator it = mSortIndexes.find(inv_item_id); + if (it != mSortIndexes.end()) + { + return it->second; + } + return NO_INDEX; +} + +void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id) +{ + mSortIndexes.erase(inv_item_id); + mIsDirty = true; +} + +void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) +{ + slurls_map_t::iterator slurl_iter = mSLURLs.find(asset_id); + if (slurl_iter != mSLURLs.end()) return; // SLURL for current landmark is already cached + + LLLandmark* lm = gLandmarkList.getAsset(asset_id, + boost::bind(&LLFavoritesOrderStorage::onLandmarkLoaded, this, asset_id, _1)); + if (lm) + { + onLandmarkLoaded(asset_id, lm); + } +} + +// static +void LLFavoritesOrderStorage::destroyClass() +{ + LLFavoritesOrderStorage::instance().cleanup(); + if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) + { + LLFavoritesOrderStorage::instance().saveFavoritesSLURLs(); + } + else + { + LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser(); + } +} + +void LLFavoritesOrderStorage::load() +{ + // load per-resident sorting information + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME); + + LLSD settings_llsd; + llifstream file; + file.open(filename); + if (file.is_open()) + { + LLSDSerialize::fromXML(settings_llsd, file); + } + + for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); + iter != settings_llsd.endMap(); ++iter) + { + mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); + } +} + +void LLFavoritesOrderStorage::saveFavoritesSLURLs() +{ + // Do not change the file if we are not logged in yet. + if (!LLLoginInstance::getInstance()->authSuccess()) return; + + std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + if (user_dir.empty()) return; + + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); + llifstream in_file; + in_file.open(filename); + LLSD fav_llsd; + if (in_file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, in_file); + } + + const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + + LLSD user_llsd; + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) + { + LLSD value; + value["name"] = (*it)->getName(); + value["asset_id"] = (*it)->getAssetUUID(); + + slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); + if (slurl_iter != mSLURLs.end()) + { + value["slurl"] = slurl_iter->second; + user_llsd[(*it)->getSortField()] = value; + } + } + + LLAvatarName av_name; + LLAvatarNameCache::get( gAgentID, &av_name ); + fav_llsd[av_name.getLegacyName()] = user_llsd; + + llofstream file; + file.open(filename); + LLSDSerialize::toPrettyXML(fav_llsd, file); +} + +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() +{ + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); + LLSD fav_llsd; + llifstream file; + file.open(filename); + if (!file.is_open()) return; + LLSDSerialize::fromXML(fav_llsd, file); + + LLAvatarName av_name; + LLAvatarNameCache::get( gAgentID, &av_name ); + if (fav_llsd.has(av_name.getLegacyName())) + { + fav_llsd.erase(av_name.getLegacyName()); + } + + llofstream out_file; + out_file.open(filename); + LLSDSerialize::toPrettyXML(fav_llsd, out_file); + +} + +void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark) +{ + if (!landmark) return; + + LLVector3d pos_global; + if (!landmark->getGlobalPos(pos_global)) + { + // If global position was unknown on first getGlobalPos() call + // it should be set for the subsequent calls. + landmark->getGlobalPos(pos_global); + } + + if (!pos_global.isExactlyZero()) + { + LLLandmarkActions::getSLURLfromPosGlobal(pos_global, + boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1)); + } +} + +void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl) +{ + mSLURLs[asset_id] = slurl; +} + +void LLFavoritesOrderStorage::save() +{ + // nothing to save if clean + if (!mIsDirty) return; + + // If we quit from the login screen we will not have an SL account + // name. Don't try to save, otherwise we'll dump a file in + // C:\Program Files\SecondLife\ or similar. JC + std::string user_dir = gDirUtilp->getLindenUserDir(); + if (!user_dir.empty()) + { + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME); + LLSD settings_llsd; + + for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter) + { + settings_llsd[iter->first.asString()] = iter->second; + } + + llofstream file; + file.open(filename); + LLSDSerialize::toPrettyXML(settings_llsd, file); + } +} + +void LLFavoritesOrderStorage::cleanup() +{ + // nothing to clean + if (!mIsDirty) return; + + const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + + IsNotInFavorites is_not_in_fav(items); + + sort_index_map_t aTempMap; + //copy unremoved values from mSortIndexes to aTempMap + std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), + inserter(aTempMap, aTempMap.begin()), + is_not_in_fav); + + //Swap the contents of mSortIndexes and aTempMap + mSortIndexes.swap(aTempMap); +} + + +S32 LLViewerInventoryItem::getSortField() const +{ + return LLFavoritesOrderStorage::instance().getSortIndex(mUUID); +} + +void LLViewerInventoryItem::setSortField(S32 sortField) +{ + LLFavoritesOrderStorage::instance().setSortIndex(mUUID, sortField); + getSLURL(); +} + +void LLViewerInventoryItem::getSLURL() +{ + LLFavoritesOrderStorage::instance().getSLURL(mAssetUUID); +} +#endif + const LLPermissions& LLViewerInventoryItem::getPermissions() const { // Use the actual permissions of the symlink, not its parent. @@ -1181,3 +1752,75 @@ void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std: gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID()); gInventory.notifyObservers(); } + +class LLRegenerateLinkCollector : public LLInventoryCollectFunctor +{ +public: + LLRegenerateLinkCollector(const LLViewerInventoryItem *target_item) : mTargetItem(target_item) {} + virtual ~LLRegenerateLinkCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + if (item) + { + if ((item->getName() == mTargetItem->getName()) && + (item->getInventoryType() == mTargetItem->getInventoryType()) && + (!item->getIsLinkType())) + { + return true; + } + } + return false; + } +protected: + const LLViewerInventoryItem* mTargetItem; +}; + +LLUUID find_possible_item_for_regeneration(const LLViewerInventoryItem *target_item) +{ + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + + LLRegenerateLinkCollector candidate_matches(target_item); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + candidate_matches); + for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + const LLViewerInventoryItem *item = (*item_iter); + if (true) return item->getUUID(); + } + return LLUUID::null; +} + +// This currently dosen't work, because the sim does not allow us +// to change an item's assetID. +BOOL LLViewerInventoryItem::regenerateLink() +{ + const LLUUID target_item_id = find_possible_item_for_regeneration(this); + if (target_item_id.isNull()) + return FALSE; + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(getAssetUUID()); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + asset_id_matches); + for (LLViewerInventoryItem::item_array_t::iterator item_iter = items.begin(); + item_iter != items.end(); + item_iter++) + { + LLViewerInventoryItem *item = (*item_iter); + item->setAssetUUID(target_item_id); + item->updateServer(FALSE); + gInventory.addChangedMask(LLInventoryObserver::REBUILD, item->getUUID()); + } + gInventory.notifyObservers(); + return TRUE; +} diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 95b4d1519..1939def08 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -36,7 +36,12 @@ #include "llinventory.h" #include "llframetimer.h" #include "llwearable.h" +#include "llui.h" //for LLDestroyClass +#include // boost::signals2::trackable + +class LLFolderView; +class LLFolderBridge; class LLViewerInventoryCategory; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -46,7 +51,7 @@ class LLViewerInventoryCategory; // their inventory. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryItem : public LLInventoryItem +class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::trackable { public: typedef LLDynamicArray > item_array_t; @@ -57,6 +62,7 @@ protected: public: virtual LLAssetType::EType getType() const; virtual const LLUUID& getAssetUUID() const; + virtual const LLUUID& getProtectedAssetUUID() const; // returns LLUUID::null if current agent does not have permission to expose this asset's UUID to the user virtual const std::string& getName() const; virtual const LLPermissions& getPermissions() const; virtual const bool getIsFullPerm() const; // 'fullperm' in the popular sense: modify-ok & copy-ok & transfer-ok, no special god rules applied @@ -153,7 +159,11 @@ public: // callback void onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group); -protected: + + // If this is a broken link, try to fix it and any other identical link. + BOOL regenerateLink(); + +public: BOOL mIsComplete; LLTransactionID mTransactionID; }; @@ -212,6 +222,11 @@ public: // other than cacheing. bool exportFileLocal(LLFILE* fp) const; bool importFileLocal(LLFILE* fp); + void determineFolderType(); + void changeType(LLFolderType::EType new_folder_type); + +private: + friend class LLInventoryModel; protected: LLUUID mOwnerID; @@ -228,15 +243,25 @@ public: class WearOnAvatarCallback : public LLInventoryCallback { +public: + WearOnAvatarCallback(bool do_replace = false) : mReplace(do_replace) {} + void fire(const LLUUID& inv_item); + +protected: + bool mReplace; }; +class ModifiedCOFCallback : public LLInventoryCallback +{ + void fire(const LLUUID& inv_item); +}; class LLViewerJointAttachment; class RezAttachmentCallback : public LLInventoryCallback { public: - RezAttachmentCallback(LLViewerJointAttachment *attachmentp, bool replace = false); + RezAttachmentCallback(LLViewerJointAttachment *attachmentp); void fire(const LLUUID& inv_item); protected: @@ -244,7 +269,6 @@ protected: private: LLViewerJointAttachment* mAttach; - bool mReplace; }; class ActivateGestureCallback : public LLInventoryCallback @@ -259,11 +283,24 @@ public: void fire(const LLUUID& inv_item); }; +class AddFavoriteLandmarkCallback : public LLInventoryCallback +{ +public: + AddFavoriteLandmarkCallback() : mTargetLandmarkId(LLUUID::null) {} + void setTargetLandmarkId(const LLUUID& target_uuid) { mTargetLandmarkId = target_uuid; } + +private: + void fire(const LLUUID& inv_item); + + LLUUID mTargetLandmarkId; +}; + // misc functions //void inventory_reliable_callback(void**, S32 status); -class LLInventoryCallbackManager +class LLInventoryCallbackManager : public LLDestroyClass { + friend class LLDestroyClass; public: LLInventoryCallbackManager(); ~LLInventoryCallbackManager(); @@ -275,6 +312,8 @@ private: callback_map_t mMap; U32 mLastCallback; static LLInventoryCallbackManager *sInstance; + static void destroyClass(); + public: static bool is_instantiated() { return sInstance != NULL; } }; @@ -291,6 +330,8 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, U32 next_owner_perm, LLPointer cb); +void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent = LLUUID::null, LLPointer cb=NULL); + /** * @brief Securely create a new inventory item by copying from another. */ @@ -319,10 +360,18 @@ void move_inventory_item( const std::string& new_name, LLPointer cb); -void copy_inventory_from_notecard(const LLUUID& object_id, +const LLUUID get_folder_by_itemtype(const LLInventoryItem *src); + +void copy_inventory_from_notecard(const LLUUID& destination_id, + const LLUUID& object_id, const LLUUID& notecard_inv_id, const LLInventoryItem *src, U32 callback_id = 0); +void menu_create_inventory_item(LLFolderView* root, + LLFolderBridge* bridge, + const LLSD& userdata, + const LLUUID& default_parent_uuid = LLUUID::null); + #endif // LL_LLVIEWERINVENTORY_H diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index e833845df..de35bf0d6 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -176,7 +176,7 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object) object->markDead(); // If this happens to be attached to self, then detach. - LLVOAvatar::detachAttachmentIntoInventory(object->getAttachmentItemID()); + LLVOAvatarSelf::detachAttachmentIntoInventory(object->getAttachmentItemID()); return FALSE; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 982089f31..9ac3ca3cf 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -76,6 +76,7 @@ // newview includes #include "llagent.h" #include "llagentcamera.h" +#include "llappearancemgr.h" #include "llagentwearables.h" #include "jcfloaterareasearch.h" @@ -271,7 +272,6 @@ void init_debug_rendering_menu(LLMenuGL* menu); void init_debug_ui_menu(LLMenuGL* menu); void init_debug_xui_menu(LLMenuGL* menu); void init_debug_avatar_menu(LLMenuGL* menu); -void init_debug_baked_texture_menu(LLMenuGL* menu); // [RLVa:KB] #include "rlvhandler.h" #include "rlvfloaterbehaviour.h" @@ -590,8 +590,6 @@ void handle_mesh_load_obj(void*); void handle_morph_save_obj(void*); void handle_morph_load_obj(void*); void handle_debug_avatar_textures(void*); -void handle_grab_texture(void*); -BOOL enable_grab_texture(void*); void handle_dump_region_object_cache(void*); BOOL menu_ui_enabled(void *user_data); @@ -1596,11 +1594,8 @@ void init_debug_rendering_menu(LLMenuGL* menu) void init_debug_avatar_menu(LLMenuGL* menu) { - LLMenuGL* sub_menu = new LLMenuGL("Grab Baked Texture"); - init_debug_baked_texture_menu(sub_menu); + LLMenuGL* sub_menu = new LLMenuGL("Character Tests"); menu->appendMenu(sub_menu); - - sub_menu = new LLMenuGL("Character Tests"); sub_menu->append(new LLMenuItemToggleGL("Go Away/AFK When Idle", &gAllowIdleAFK)); @@ -1672,17 +1667,6 @@ void init_debug_avatar_menu(LLMenuGL* menu) menu->createJumpKeys(); } -void init_debug_baked_texture_menu(LLMenuGL* menu) -{ - menu->append(new LLMenuItemCallGL("Iris", handle_grab_texture, enable_grab_texture, (void*) TEX_EYES_BAKED)); - menu->append(new LLMenuItemCallGL("Head", handle_grab_texture, enable_grab_texture, (void*) TEX_HEAD_BAKED)); - menu->append(new LLMenuItemCallGL("Upper Body", handle_grab_texture, enable_grab_texture, (void*) TEX_UPPER_BAKED)); - menu->append(new LLMenuItemCallGL("Lower Body", handle_grab_texture, enable_grab_texture, (void*) TEX_LOWER_BAKED)); - menu->append(new LLMenuItemCallGL("Skirt", handle_grab_texture, enable_grab_texture, (void*) TEX_SKIRT_BAKED)); - menu->append(new LLMenuItemCallGL("Hair", handle_grab_texture, enable_grab_texture, (void*) TEX_HAIR_BAKED)); - menu->createJumpKeys(); -} - // [RLVa:KB] - Checked: 2009-11-17 (RLVa-1.1.0d) | Modified: RLVa-1.1.0d | OK void init_debug_rlva_menu(LLMenuGL* menu) { @@ -3080,10 +3064,10 @@ class LLAvatarDebug : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if( avatar ) + //LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if (isAgentAvatarValid()) { - avatar->dumpLocalTextures(); + gAgentAvatarp->dumpLocalTextures(); // hell no don't tell them about that /* llinfos << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << llendl; @@ -3093,7 +3077,7 @@ class LLAvatarDebug : public view_listener_t send_generic_message("dumptempassetdata", strings, invoice); */ // - LLFloaterAvatarTextures::show( avatar->getID() ); + LLFloaterAvatarTextures::show( gAgentAvatarp->getID() ); } return true; } @@ -7628,7 +7612,7 @@ void handle_test_male(void*) } // [/RLVa:KB] - wear_outfit_by_name("Male Shape & Outfit"); + LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); //gGestureList.requestResetFromServer( TRUE ); } @@ -7643,7 +7627,7 @@ void handle_test_female(void*) } // [/RLVa:KB] - wear_outfit_by_name("Female Shape & Outfit"); + LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); //gGestureList.requestResetFromServer( FALSE ); } @@ -8318,7 +8302,7 @@ void handle_meshes_and_morphs(void* menu_item) LLVOAvatar::mesh_info_t mesh_info; LLVOAvatar::getMeshInfo(&mesh_info); - for(LLVOAvatar::mesh_info_t::iterator info_iter = mesh_info.begin(); + for(LLVOAvatarSelf::mesh_info_t::iterator info_iter = mesh_info.begin(); info_iter != mesh_info.end(); ++info_iter) { const std::string& type = info_iter->first; @@ -8725,110 +8709,6 @@ void handle_debug_avatar_textures(void*) // } -void handle_grab_texture(void* data) -{ - ETextureIndex index = (ETextureIndex)((intptr_t)data); - LLVOAvatar* avatar = gAgentAvatarp; - if ( avatar ) - { - const LLUUID& asset_id = avatar->grabLocalTexture(index); - LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << llendl; - LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; - LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; - LLUUID folder_id(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); - if(folder_id.notNull()) - { - std::string name = "Baked "; - switch (index) - { - case TEX_EYES_BAKED: - name.append("Iris"); - break; - case TEX_HEAD_BAKED: - name.append("Head"); - break; - case TEX_UPPER_BAKED: - name.append("Upper Body"); - break; - case TEX_LOWER_BAKED: - name.append("Lower Body"); - break; - case TEX_SKIRT_BAKED: - name.append("Skirt"); - break; - case TEX_HAIR_BAKED: - name.append("Hair"); - break; - default: - name.append("Unknown"); - break; - } - name.append(" Texture"); - - LLUUID item_id; - item_id.generate(); - LLPermissions perm; - perm.init(gAgentID, - gAgentID, - LLUUID::null, - LLUUID::null); - U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; - perm.initMasks(PERM_ALL, - PERM_ALL, - PERM_NONE, - PERM_NONE, - next_owner_perm); - time_t creation_date_now = time_corrected(); - LLPointer item - = new LLViewerInventoryItem(item_id, - folder_id, - perm, - asset_id, - asset_type, - inv_type, - name, - LLStringUtil::null, - LLSaleInfo::DEFAULT, - LLInventoryItemFlags::II_FLAGS_NONE, - creation_date_now); - - item->updateServer(TRUE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - LLInventoryView* view = LLInventoryView::getActiveInventory(); - - // Show the preview panel for textures to let - // user know that the image is now in inventory. - if(view) - { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - - view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO); - view->getPanel()->openSelected(); - //LLInventoryView::dumpSelectionInformation((void*)view); - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus_ctrl); - } - } - else - { - llwarns << "Can't find a folder to put it in" << llendl; - } - } -} - -BOOL enable_grab_texture(void* data) -{ - ETextureIndex index = (ETextureIndex)((intptr_t)data); - LLVOAvatar* avatar = gAgentAvatarp; - if ( avatar ) - { - return avatar->canGrabLocalTexture(index); - } - return FALSE; -} - // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) @@ -9204,15 +9084,19 @@ class LLEditTakeOff : public view_listener_t { std::string clothing = userdata.asString(); if (clothing == "all") - { - LLAgentWearables::userRemoveAllClothes(); - } + LLWearableBridge::removeAllClothesFromAvatar(); else { LLWearableType::EType type = LLWearableType::typeNameToType(clothing); if (type >= LLWearableType::WT_SHAPE - && type < LLWearableType::WT_COUNT) - LLAgentWearables::userRemoveWearable(type,0); // TODO: MULTI-WEARABLE + && type < LLWearableType::WT_COUNT + && (gAgentWearables.getWearableCount(type) > 0)) + { + // MULTI-WEARABLES: assuming user wanted to remove top shirt. + U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; + LLViewerInventoryItem *item = dynamic_cast(gAgentWearables.getWearableInventoryItem(type,wearable_index)); + LLWearableBridge::removeItemFromAvatar(item); + } } return true; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 0e524aaa6..e958e99c7 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -199,8 +199,6 @@ static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds extern BOOL gDebugClicks; // function prototypes -void open_offer(const std::vector& items, const std::string& from_name); -bool highlight_offered_object(const LLUUID& obj_id); bool check_offer_throttle(const std::string& from_name, bool check_only); void callbackCacheEstateOwnerName(const LLUUID& id, const std::string& full_name, bool is_group); @@ -810,6 +808,51 @@ bool join_group_response(const LLSD& notification, const LLSD& response) return false; } + +static void highlight_inventory_objects_in_panel(const std::vector& items, LLInventoryPanel *inventory_panel) +{ + if (NULL == inventory_panel) return; + + for (std::vector::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + const LLUUID& item_id = (*item_iter); + if(!highlight_offered_object(item_id)) + { + continue; + } + + LLInventoryObject* item = gInventory.getObject(item_id); + llassert(item); + if (!item) { + continue; + } + + LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL; + LLFolderView* fv = inventory_panel->getRootFolder(); + if (fv) + { + LLFolderViewItem* fv_item = fv->getItemByID(item_id); + if (fv_item) + { + LLFolderViewItem* fv_folder = fv_item->getParentFolder(); + if (fv_folder) + { + // Parent folders can be different in case of 2 consecutive drag and drop + // operations when the second one is started before the first one completes. + LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL; + fv_folder->setOpen(TRUE); + if (fv_folder->isSelected()) + { + fv->changeSelection(fv_folder, FALSE); + } + } + fv->changeSelection(fv_item, TRUE); + } + } + } +} static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response); static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response); static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response); @@ -825,9 +868,21 @@ public: const std::string& from_name) : LLInventoryFetchItemsObserver(object_id), mFromName(from_name) {} + /*virtual*/ void startFetch() + { + for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if (cat) + { + mComplete.push_back((*it)); + } + } + LLInventoryFetchItemsObserver::startFetch(); + } /*virtual*/ void done() { - open_offer(mComplete, mFromName); + open_inventory_offer(mComplete, mFromName); gInventory.removeObserver(this); delete this; } @@ -835,6 +890,178 @@ private: std::string mFromName; }; +/** + * Class to observe adding of new items moved from the world to user's inventory to select them in inventory. + * + * We can't create it each time items are moved because "drop" event is sent separately for each + * element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347. + */ +class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver +{ +public: + LLViewerInventoryMoveFromWorldObserver() + : LLInventoryAddItemByAssetObserver() + { + + } + + void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } + +private: + /*virtual */void onAssetAdded(const LLUUID& asset_id) + { + // Store active Inventory panel. + if (LLInventoryPanel::getActiveInventoryPanel()) + { + mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); + } + + // Store selected items (without destination folder) + mSelectedItems.clear(); + if (LLInventoryPanel::getActiveInventoryPanel()) + { + LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(mSelectedItems); + } + mSelectedItems.erase(mMoveIntoFolderID); + } + + /** + * Selects added inventory items watched by their Asset UUIDs if selection was not changed since + * all items were started to watch (dropped into a folder). + */ + void done() + { + LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); + + // if selection is not changed since watch started lets hightlight new items. + if (active_panel && !isSelectionChanged()) + { + LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL; + active_panel->clearSelection(); + highlight_inventory_objects_in_panel(mAddedItems, active_panel); + } + } + + /** + * Returns true if selected inventory items were changed since moved inventory items were started to watch. + */ + bool isSelectionChanged() + { + LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); + + if (NULL == active_panel) + { + return true; + } + + // get selected items (without destination folder) + selected_items_t selected_items; + active_panel->getRootFolder()->getSelectionList(selected_items); + selected_items.erase(mMoveIntoFolderID); + + // compare stored & current sets of selected items + selected_items_t different_items; + std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(), + selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin())); + + LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() + << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; + + return different_items.size() > 0; + } + + LLHandle mActivePanel; + typedef std::set selected_items_t; + selected_items_t mSelectedItems; + + /** + * UUID of FolderViewFolder into which watched items are moved. + * + * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped). + * + * If mouse is moved out it set unselected and number of selected items is changed + * even if selected items in Inventory stay the same. + * So, it is used to update stored selection list. + * + * @see onAssetAdded() + * @see isSelectionChanged() + */ + LLUUID mMoveIntoFolderID; +}; + +LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL; + +void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid) +{ + start_new_inventory_observer(); + + gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid); + gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID()); +} + + +/** + * Class to observe moving of items and to select them in inventory. + * + * Used currently for dragging from inbox to regular inventory folders + */ + +class LLViewerInventoryMoveObserver : public LLInventoryObserver +{ +public: + + LLViewerInventoryMoveObserver(const LLUUID& object_id) + : LLInventoryObserver() + , mObjectID(object_id) + { + if (LLInventoryPanel::getActiveInventoryPanel()) + { + mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); + } + } + + virtual ~LLViewerInventoryMoveObserver() {} + virtual void changed(U32 mask); + +private: + LLUUID mObjectID; + LLHandle mActivePanel; + +}; + +void LLViewerInventoryMoveObserver::changed(U32 mask) +{ + LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); + + if (NULL == active_panel) + { + gInventory.removeObserver(this); + return; + } + + if((mask & (LLInventoryObserver::STRUCTURE)) != 0) + { + const std::set& changed_items = gInventory.getChangedIDs(); + + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + if ((*id_it) == mObjectID) + { + active_panel->clearSelection(); + std::vector items; + items.push_back(mObjectID); + highlight_inventory_objects_in_panel(items, active_panel); + active_panel->getRootFolder()->scrollToShowSelection(); + + gInventory.removeObserver(this); + break; + } + } + } +} + //unlike the FetchObserver for AgentOffer, we only make one //instance of the AddedObserver for TaskOffers //and it never dies. We do this because we don't know the UUID of @@ -845,13 +1072,62 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver protected: /*virtual*/ void done() { - open_offer(mAdded, ""); + for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();) + { + const LLUUID& item_uuid = *it; + bool was_moved = false; + LLInventoryObject* added_object = gInventory.getObject(item_uuid); + if (added_object) + { + // cast to item to get Asset UUID + LLInventoryItem* added_item = dynamic_cast(added_object); + if (added_item) + { + const LLUUID& asset_uuid = added_item->getAssetUUID(); + if (gInventoryMoveObserver->isAssetWatched(asset_uuid)) + { + LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; + was_moved = true; + } + } + } + + if (was_moved) + { + it = mAdded.erase(it); + } + else ++it; + } + + open_inventory_offer(mAdded, ""); mAdded.clear(); } }; +class LLOpenTaskGroupOffer : public LLInventoryAddedObserver +{ +protected: + /*virtual*/ void done() + { + open_inventory_offer(mAdded, "group_offer"); + mAdded.clear(); + gInventory.removeObserver(this); + delete this; + } +}; + //one global instance to bind them LLOpenTaskOffer* gNewInventoryObserver=NULL; +class LLNewInventoryHintObserver : public LLInventoryAddedObserver +{ +protected: + /*virtual*/ void done() + { + //LLFirstUse::newInventory(); + } +}; + +LLNewInventoryHintObserver* gNewInventoryHintObserver=NULL; void start_new_inventory_observer() { @@ -861,10 +1137,19 @@ void start_new_inventory_observer() gNewInventoryObserver = new LLOpenTaskOffer; gInventory.addObserver(gNewInventoryObserver); } + + if (!gInventoryMoveObserver) //inventory move from the world observer + { + // Observer is deleted by gInventory + gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; + gInventory.addObserver(gInventoryMoveObserver); + } } class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver { + LOG_CLASS(LLDiscardAgentOffer); + public: LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : LLInventoryFetchItemsObserver(object_id), @@ -954,7 +1239,7 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) } } -void open_offer(const std::vector& items, const std::string& from_name) +void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name) { uuid_vec_t::const_iterator it = items.begin(); uuid_vec_t::const_iterator end = items.end(); @@ -1059,16 +1344,9 @@ bool highlight_offered_object(const LLUUID& obj_id) if (parent) { const LLFolderType::EType parent_type = parent->getPreferredType(); - switch (parent_type) + if (LLViewerFolderType::lookupIsQuietType(parent_type)) { - case LLFolderType::FT_TRASH: - case LLFolderType::FT_LOST_AND_FOUND: - case LLFolderType::FT_CURRENT_OUTFIT: - case LLFolderType::FT_OUTFIT: - case LLFolderType::FT_MY_OUTFITS: - return false; - default: - break; + return false; } } } diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 709e582ad..bf109e789 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -206,6 +206,14 @@ void invalid_message_callback(LLMessageSystem*, void*, EMessageException); void process_initiate_download(LLMessageSystem* msg, void**); void start_new_inventory_observer(); +void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name); + +// Returns true if item is not in certain "quiet" folder which don't need UI +// notification (e.g. trash, cof, lost-and-found) and agent is not AFK, false otherwise. +// Returns false if item is not found. +bool highlight_offered_object(const LLUUID& obj_id); + +void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid); struct LLOfferInfo { diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 11cb1a868..3fd56f842 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -55,7 +55,7 @@ #include "lldebugview.h" #include "llfasttimerview.h" #include "llviewerregion.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llviewerwindow.h" // *TODO: remove, only used for width/height #include "llworld.h" #include "llfeaturemanager.h" @@ -525,10 +525,10 @@ void output_statistics(void*) llinfos << "--------------------------------" << llendl; llinfos << "Avatar Memory (partly overlaps with above stats):" << llendl; - gTexStaticImageList.dumpByteCount(); - LLVOAvatar::dumpScratchTextureByteCount(); + LLTexLayerStaticImageList::getInstance()->dumpByteCount(); + LLVOAvatarSelf::dumpScratchTextureByteCount(); LLTexLayerSetBuffer::dumpTotalByteCount(); - LLVOAvatar::dumpTotalLocalTextureByteCount(); + LLVOAvatarSelf::dumpTotalLocalTextureByteCount(); LLTexLayerParamAlpha::dumpCacheByteCount(); LLVOAvatar::dumpBakedStatus(); diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 35b1dba5d..12ae059a4 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -1565,7 +1565,8 @@ bool LLViewerTextEditor::importStream(std::istream& str) void LLViewerTextEditor::copyInventory(const LLInventoryItem* item, U32 callback_id) { - copy_inventory_from_notecard(mObjectID, + copy_inventory_from_notecard(LLUUID::null, // Don't specify a destination -- let the sim do that + mObjectID, mNotecardInventoryID, item, callback_id); diff --git a/indra/newview/llviewervisualparam.cpp b/indra/newview/llviewervisualparam.cpp index 187db674e..422e530dc 100644 --- a/indra/newview/llviewervisualparam.cpp +++ b/indra/newview/llviewervisualparam.cpp @@ -46,6 +46,7 @@ LLViewerVisualParamInfo::LLViewerVisualParamInfo() : mWearableType( LLWearableType::WT_INVALID ), + mCrossWearable(FALSE), mCamDist( 0.5f ), mCamAngle( 0.f ), mCamElevation( 0.f ), @@ -85,6 +86,12 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node) mEditGroup = ""; } + static LLStdStringHandle cross_wearable_string = LLXmlTree::addAttributeString("cross_wearable"); + if (!node->getFastAttributeBOOL(cross_wearable_string, mCrossWearable)) + { + mCrossWearable = FALSE; + } + // Optional camera offsets from the current joint center. Used for generating "hints" (thumbnails). static LLStdStringHandle camera_distance_string = LLXmlTree::addAttributeString("camera_distance"); node->getFastAttributeF32( camera_distance_string, mCamDist ); @@ -112,6 +119,15 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node) return TRUE; } +/*virtual*/ void LLViewerVisualParamInfo::toStream(std::ostream &out) +{ + LLVisualParamInfo::toStream(out); + + out << mWearableType << "\t"; + out << mEditGroup << "\t"; + out << mEditGroupDisplayOrder << "\t"; +} + //----------------------------------------------------------------------------- // LLViewerVisualParam() //----------------------------------------------------------------------------- diff --git a/indra/newview/llviewervisualparam.h b/indra/newview/llviewervisualparam.h index 09052ae56..8eaa0af0a 100644 --- a/indra/newview/llviewervisualparam.h +++ b/indra/newview/llviewervisualparam.h @@ -45,8 +45,11 @@ public: /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + /*virtual*/ void toStream(std::ostream &out); + protected: S32 mWearableType; + BOOL mCrossWearable; std::string mEditGroup; F32 mCamDist; F32 mCamAngle; // degrees @@ -73,6 +76,8 @@ public: LLViewerVisualParamInfo *getInfo() const { return (LLViewerVisualParamInfo*)mInfo; }; // This sets mInfo and calls initialization functions BOOL setInfo(LLViewerVisualParamInfo *info); + + virtual LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0; // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); @@ -86,7 +91,7 @@ public: virtual const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0; // interface methods - F32 getDisplayOrder() { return getInfo()->mEditGroupDisplayOrder; } + F32 getDisplayOrder() const { return getInfo()->mEditGroupDisplayOrder; } S32 getWearableType() const { return getInfo()->mWearableType; } const std::string& getEditGroup() const { return getInfo()->mEditGroup; } @@ -98,6 +103,9 @@ public: BOOL getShowSimple() const { return getInfo()->mShowSimple; } F32 getSimpleMin() const { return getInfo()->mSimpleMin; } F32 getSimpleMax() const { return getInfo()->mSimpleMax; } + + BOOL getCrossWearable() const { return getInfo()->mCrossWearable; } + }; #endif // LL_LLViewerVisualParam_H diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 590625b72..6e488346d 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -30,6 +30,12 @@ * $/LicenseInfo$ */ +#if LL_MSVC +// disable warning about boost::lexical_cast returning uninitialized data +// when it fails to parse the string +#pragma warning (disable:4701) +#endif + #include "llviewerprecompiledheaders.h" #include "llvoavatar.h" @@ -41,12 +47,13 @@ #include "noise.h" #include "llsdserialize.h" -#include "cofmgr.h" #include "llagent.h" // Get state values from here #include "llagentcamera.h" #include "llagentwearables.h" #include "llanimationstates.h" +#include "llavatarnamecache.h" #include "llavatarpropertiesprocessor.h" +#include "llphysicsmotion.h" #include "llviewercontrol.h" #include "lldrawpoolavatar.h" #include "lldriverparam.h" @@ -97,6 +104,8 @@ #include "llviewershadermgr.h" #include "llsky.h" #include "llanimstatelabels.h" +#include "lltrans.h" +#include "llappearancemgr.h" #include "llgesturemgr.h" //needed to trigger the voice gesticulations #include "llvoiceclient.h" #include "llvoicevisualizer.h" // Ventrella @@ -111,9 +120,6 @@ // #include "llavatarname.h" -#include "llavatarnamecache.h" - -#include "llphysicsmotion.h" // [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) #include "rlvhandler.h" @@ -179,8 +185,7 @@ const S32 MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX = 40; const S32 TEX_IMAGE_SIZE_SELF = 512; const S32 TEX_IMAGE_AREA_SELF = TEX_IMAGE_SIZE_SELF * TEX_IMAGE_SIZE_SELF; -const S32 TEX_IMAGE_SIZE_OTHER = TEX_IMAGE_SIZE_SELF / 4; // The size of local textures for other (!isSelf()) avatars -const S32 TEX_IMAGE_AREA_OTHER = TEX_IMAGE_SIZE_OTHER * TEX_IMAGE_SIZE_OTHER; +const S32 TEX_IMAGE_SIZE_OTHER = 512 / 4; // The size of local textures for other (!isSelf()) avatars const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f; @@ -208,8 +213,6 @@ const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f; const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); -const F32 DERUTHING_TIMEOUT_SECONDS = 30.f; - //Singu note: FADE and ALWAYS are swapped around from LL's source to match our preference panel. // Changing the "RenderName" order would cause confusion when 'always' setting suddenly gets // interpreted as 'fade', and vice versa. @@ -223,13 +226,6 @@ enum ERenderName //----------------------------------------------------------------------------- // Callback data //----------------------------------------------------------------------------- -struct LLAvatarTexData -{ - LLAvatarTexData( const LLUUID& id, ETextureIndex index ) - : mAvatarID(id), mIndex(index) {} - LLUUID mAvatarID; - ETextureIndex mIndex; -}; struct LLTextureMaskData { @@ -666,14 +662,10 @@ F32 LLVOAvatar::sGreyUpdateTime = 0.f; //Move to LLVOAvatarSelf BOOL LLVOAvatar::sDebugAvatarRotation = FALSE; -LLMap< LLGLenum, LLGLuint*> LLVOAvatar::sScratchTexNames; -LLMap< LLGLenum, F32*> LLVOAvatar::sScratchTexLastBindTime; -S32 LLVOAvatar::sScratchTexBytes = 0; //Custom stuff. LLSD LLVOAvatar::sClientResolutionList; EmeraldGlobalBoobConfig LLVOAvatar::sBoobConfig; -bool LLVOAvatar::sDoProperArc = true; //----------------------------------------------------------------------------- // Helper functions @@ -720,8 +712,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNameFromChatOverride(false), mNameFromChatChanged(false), mRenderTag(false), - mLastRegionHandle(0), - mRegionCrossingCount(0), mFirstTEMessageReceived( FALSE ), mFirstAppearanceMessageReceived( FALSE ), mCulled( FALSE ), @@ -732,10 +722,13 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsSkin(FALSE), mLastSkinTime(0.f), mUpdatePeriod(1), + mFullyLoaded(FALSE), + mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), - mHasBakedHair( FALSE ), mSupportsAlphaLayers(FALSE), + mLoadedCallbacksPaused(FALSE), mHasPelvisOffset( FALSE ), + mRenderUnloadedAvatar(LLCachedControl(gSavedSettings, "RenderUnloadedAvatar")), mFirstSetActualBoobGravRan( false ), mSupportsPhysics( false ) //mFirstSetActualButtGravRan( false ), @@ -759,14 +752,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mPelvisp = NULL; - for( S32 i=0; imarkDead(); + LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ; LLViewerObject::markDead(); } @@ -971,12 +987,6 @@ BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) return res; } -// static -void LLVOAvatar::dumpScratchTextureByteCount() -{ - llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl; -} - // static void LLVOAvatar::getMeshInfo (mesh_info_t* mesh_info) { @@ -1099,17 +1109,14 @@ void LLVOAvatar::dumpBakedStatus() //static void LLVOAvatar::restoreGL() { - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + if (!isAgentAvatarValid()) return; + + gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); + for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++) { - LLVOAvatar* inst = (LLVOAvatar*) *iter; - inst->setCompositeUpdatesEnabled( TRUE ); - for (U32 i = 0; i < inst->mBakedTextureDatas.size(); i++) - { - inst->invalidateComposite( inst->mBakedTextureDatas[i].mTexLayerSet, FALSE ); - } - inst->updateMeshTextures(); + gAgentAvatarp->invalidateComposite(gAgentAvatarp->mBakedTextureDatas[i].mTexLayerSet, FALSE); } + gAgentAvatarp->updateMeshTextures(); } //static @@ -1133,50 +1140,7 @@ void LLVOAvatar::resetImpostors() // static void LLVOAvatar::deleteCachedImages(bool clearAll) -{ -if(gAuditTexture) - { - S32 total_tex_size = sScratchTexBytes ; - S32 tex_size = SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT ; - - if( LLVOAvatar::sScratchTexNames.checkData( GL_LUMINANCE ) ) - { - LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= tex_size ; - } - if( LLVOAvatar::sScratchTexNames.checkData( GL_ALPHA ) ) - { - LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= tex_size ; - } - if( LLVOAvatar::sScratchTexNames.checkData( GL_COLOR_INDEX ) ) - { - LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= tex_size ; - } - if( LLVOAvatar::sScratchTexNames.checkData( GL_LUMINANCE_ALPHA ) ) - { - LLImageGL::decTextureCounter(tex_size, 2, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 2 * tex_size ; - } - if( LLVOAvatar::sScratchTexNames.checkData( GL_RGB ) ) - { - LLImageGL::decTextureCounter(tex_size, 3, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 3 * tex_size ; - } - if( LLVOAvatar::sScratchTexNames.checkData( GL_RGBA ) ) - { - LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 4 * tex_size ; - } - //others - while(total_tex_size > 0) - { - LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 4 * tex_size ; - } - } - +{ if (LLTexLayerSet::sHasCaches) { lldebugs << "Deleting layer set caches" << llendl; @@ -1188,26 +1152,8 @@ if(gAuditTexture) } LLTexLayerSet::sHasCaches = FALSE; } - - for( LLGLuint* namep = sScratchTexNames.getFirstData(); - namep; - namep = sScratchTexNames.getNextData() ) - { - LLImageGL::deleteTextures(1, (U32 *)namep ); - stop_glerror(); - } - - if( sScratchTexBytes ) - { - lldebugs << "Clearing Scratch Textures " << (sScratchTexBytes/1024) << "KB" << llendl; - - sScratchTexNames.deleteAllData(); - LLVOAvatar::sScratchTexLastBindTime.deleteAllData(); - LLImageGL::sGlobalTextureMemoryInBytes -= sScratchTexBytes; - sScratchTexBytes = 0; - } - - gTexStaticImageList.deleteCachedImages(); + LLVOAvatarSelf::deleteScratchTextures(); + LLTexLayerStaticImageList::getInstance()->deleteCachedImages(); } @@ -1315,7 +1261,10 @@ void LLVOAvatar::initClass() { llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } - + if (!sAvatarXmlInfo->parseXmlMorphNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } { if (gSavedSettings.getBOOL("AscentUpdateTagsOnLoad")) { @@ -1350,11 +1299,10 @@ void LLVOAvatar::initInstance(void) for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); - iter++) + ++iter) { const EMeshIndex mesh_index = iter->first; const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; - LLViewerJoint* joint = new LLViewerJoint(); joint->setName(mesh_dict->mName); joint->setMeshID(mesh_index); @@ -1397,17 +1345,17 @@ void LLVOAvatar::initInstance(void) //------------------------------------------------------------------------- for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); - iter++) + ++iter) { const EMeshIndex mesh_index = iter->first; const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID; - // Skip it if there's no associated baked texture. if (baked_texture_index == BAKED_NUM_INDICES) continue; - + for (std::vector::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin(); - iter != mMeshLOD[mesh_index]->mMeshParts.end(); iter++) + iter != mMeshLOD[mesh_index]->mMeshParts.end(); + ++iter) { LLViewerJointMesh* mesh = (LLViewerJointMesh*) *iter; mBakedTextureDatas[(int)baked_texture_index].mMeshes.push_back(mesh); @@ -1483,7 +1431,6 @@ void LLVOAvatar::initInstance(void) sBoobConfig.friction = EmeraldBoobUtils::convertFriction(gSavedSettings.getF32("EmeraldBoobFriction")); sBoobConfig.enabled = gSavedSettings.getBOOL("EmeraldBreastPhysicsToggle"); sBoobConfig.XYInfluence = gSavedSettings.getF32("EmeraldBoobXYInfluence"); - sDoProperArc = (bool)gSavedSettings.getBOOL("EmeraldUseProperArc"); if (gNoRender) { @@ -2389,43 +2336,30 @@ void LLVOAvatar::computeBodySize() ankle.mV[VZ] * knee_scale.mV[VZ] - foot.mV[VZ] * ankle_scale.mV[VZ]; - mBodySize.mV[VZ] = mPelvisToFoot + + LLVector3 new_body_size; + new_body_size.mV[VZ] = mPelvisToFoot + // the sqrt(2) correction below is an approximate // correction to get to the top of the head - F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + - head.mV[VZ] * neck_scale.mV[VZ] + - neck.mV[VZ] * chest_scale.mV[VZ] + - chest.mV[VZ] * torso_scale.mV[VZ] + - torso.mV[VZ] * pelvis_scale.mV[VZ]; + F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + + head.mV[VZ] * neck_scale.mV[VZ] + + neck.mV[VZ] * chest_scale.mV[VZ] + + chest.mV[VZ] * torso_scale.mV[VZ] + + torso.mV[VZ] * pelvis_scale.mV[VZ]; // TODO -- measure the real depth and width - mBodySize.mV[VX] = DEFAULT_AGENT_DEPTH; - mBodySize.mV[VY] = DEFAULT_AGENT_WIDTH; + new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; + new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; -/* debug spam - std::cout << "skull = " << skull << std::endl; // adebug - std::cout << "head = " << head << std::endl; // adebug - std::cout << "head_scale = " << head_scale << std::endl; // adebug - std::cout << "neck = " << neck << std::endl; // adebug - std::cout << "neck_scale = " << neck_scale << std::endl; // adebug - std::cout << "chest = " << chest << std::endl; // adebug - std::cout << "chest_scale = " << chest_scale << std::endl; // adebug - std::cout << "torso = " << torso << std::endl; // adebug - std::cout << "torso_scale = " << torso_scale << std::endl; // adebug - std::cout << std::endl; // adebug + if (new_body_size != mBodySize) + { + mBodySize = new_body_size; - std::cout << "pelvis_scale = " << pelvis_scale << std::endl;// adebug - std::cout << std::endl; // adebug - - std::cout << "hip = " << hip << std::endl; // adebug - std::cout << "hip_scale = " << hip_scale << std::endl; // adebug - std::cout << "ankle = " << ankle << std::endl; // adebug - std::cout << "ankle_scale = " << ankle_scale << std::endl; // adebug - std::cout << "foot = " << foot << std::endl; // adebug - std::cout << "mBodySize = " << mBodySize << std::endl; // adebug - std::cout << "mPelvisToFoot = " << mPelvisToFoot << std::endl; // adebug - std::cout << std::endl; // adebug -*/ + if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) + { // notify simulator of change in size + // but not if we are in the middle of updating appearance + gAgent.sendAgentSetAppearance(); + } + } } //------------------------------------------------------------------------ @@ -2439,9 +2373,24 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, LLMemType mt(LLMemType::MTYPE_AVATAR); LLVector3 old_vel = getVelocity(); + const BOOL has_name = !getNVPair("FirstName"); + // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); + // Print out arrival information once we have name of avatar. + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (has_name && getNVPair("FirstName")) + { + mDebugExistenceTimer.reset(); + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezArrivedNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl; + } + } if(retval & LLViewerObject::INVALID_UPDATE) { if(isSelf()) @@ -2495,7 +2444,32 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar"); static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints"); -// setTEImage +//------------------------------------------------------------------------ +// LLVOAvatar::dumpAnimationState() +//------------------------------------------------------------------------ +void LLVOAvatar::dumpAnimationState() +{ + llinfos << "==============================================" << llendl; + for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it) + { + LLUUID id = it->first; + std::string playtag = ""; + if (mPlayingAnimations.find(id) != mPlayingAnimations.end()) + { + playtag = "*"; + } + llinfos << gAnimLibrary.animationName(id) << playtag << llendl; + } + for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it) + { + LLUUID id = it->first; + bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end(); + if (!is_signaled) + { + llinfos << gAnimLibrary.animationName(id) << "!S" << llendl; + } + } +} //------------------------------------------------------------------------ // idleUpdate() @@ -2515,6 +2489,8 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { return TRUE; } + + checkTextureLoading() ; // force immediate pixel area update on avatars using last frames data (before drawable or camera updates) setPixelAreaAndAngle(gAgent); @@ -2571,12 +2547,6 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // attach objects that were waiting for a drawable lazyAttach(); -/* - if (isSelf()) - { - checkAttachments(); - } -*/ // animate the character // store off last frame's root position to be consistent with camera position @@ -2606,38 +2576,6 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) return TRUE; } -// static -BOOL LLVOAvatar::detachAttachmentIntoInventory(const LLUUID &item_id) -{ - LLInventoryItem* item = gInventory.getLinkedItem(item_id); - if ( (item) && (gAgentAvatarp) && (!gAgentAvatarp->isWearingAttachment(item->getUUID())) ) - { - LLCOFMgr::instance().removeAttachment(item->getUUID()); - return FALSE; - } -// if (item) -// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1c) | Added: RLVa-1.2.1c - if ( (item) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(item))) ) -// [/RLVa:KB] - { - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); - gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); - - // This object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = gObjectList.findObject(item_id); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - } - - return TRUE; - } - return FALSE; -} - void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) { bool render_visualizer = voice_enabled; @@ -3092,6 +3030,17 @@ void LLVOAvatar::idleUpdateLoadingEffect() // update visibility when avatar is partially loaded if (updateIsFullyLoaded()) // changed? { + if (isFullyLoaded() && isSelf()) + { + static bool first_fully_visible = true; + if (first_fully_visible) + { + llinfos << "self isFullyLoaded, first_fully_visible" << llendl; + + first_fully_visible = false; + LLAppearanceMgr::instance().onFirstFullyVisible(); + } + } if (isFullyLoaded()) { deleteParticleSource(); @@ -4279,7 +4228,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // of the agent's physical representation root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; - LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); if (newPosition != mRoot.getXform()->getWorldPosition()) @@ -4772,7 +4720,7 @@ void LLVOAvatar::updateVisibility() bool LLVOAvatar::shouldAlphaMask() { const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha // Don't alpha mask if "Highlight Transparent" checked - && !LLDrawPoolAvatar::sSkipTransparent && mHasBakedHair; + && !LLDrawPoolAvatar::sSkipTransparent; return should_alpha_mask; @@ -4999,7 +4947,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) } // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair) // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible(); - if (getTEImage(TEX_HAIR_BAKED)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha) + if (getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha) { num_indices += mMeshLOD[MESH_ID_HAIR]->render(mAdjustedPixelArea, first_pass, mIsDummy); first_pass = FALSE; @@ -5177,7 +5125,7 @@ void LLVOAvatar::updateTextures() { if (layer_baked[i] && !mBakedTextureDatas[i].mIsLoaded) { - gGL.getTexUnit(0)->bind(getTEImage( mBakedTextureDatas[i].mTextureIndex )); + gGL.getTexUnit(0)->bind(getImage( mBakedTextureDatas[i].mTextureIndex, 0 )); } } } @@ -5210,118 +5158,134 @@ void LLVOAvatar::updateTextures() mMaxPixelArea = 0.f; mMinPixelArea = 99999999.f; mHasGrey = FALSE; // debug - for (U32 index = 0; index < getNumTEs(); index++) + for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) { - LLViewerFetchedTexture *imagep = LLViewerTextureManager::staticCastToFetchedTexture(getTEImage(index)); - if (imagep) + LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index); + U32 num_wearables = gAgentWearables.getWearableCount(wearable_type); + const LLTextureEntry *te = getTE(texture_index); + const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); + LLViewerFetchedTexture *imagep = NULL; + for (U32 wearable_index = 0; wearable_index < num_wearables; wearable_index++) { - // Debugging code - maybe non-self avatars are downloading textures? - //llinfos << "avatar self " << isSelf() << " tex " << index - // << " decode " << imagep->getDecodePriority() - // << " boost " << imagep->getBoostLevel() - // << " size " << imagep->getWidth() << "x" << imagep->getHeight() - // << " discard " << imagep->getDiscardLevel() - // << " desired " << imagep->getDesiredDiscardLevel() - // << llendl; - - const LLTextureEntry *te = getTE(index); - F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); - S32 boost_level = isSelf() ? LLViewerTexture::BOOST_AVATAR_BAKED_SELF : LLViewerTexture::BOOST_AVATAR_BAKED; - + imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE); + if (imagep) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)texture_index); + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + if (texture_dict->mIsLocalTexture) + { + addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]); + } + } + } + if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar) + { + const S32 boost_level = getAvatarBakedBoostLevel(); + imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); // Spam if this is a baked texture, not set to default image, without valid host info - if (isIndexBakedTexture((ETextureIndex)index) + if (isIndexBakedTexture((ETextureIndex)texture_index) && imagep->getID() != IMG_DEFAULT_AVATAR && imagep->getID() != IMG_INVISIBLE && !imagep->getTargetHost().isOk()) { LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " - << imagep->getID() << " for avatar " - << (isSelf() ? "" : getID().asString()) - << " on host " << getRegion()->getHost() << llendl; + << imagep->getID() << " for avatar " + << (isSelf() ? "" : getID().asString()) + << " on host " << getRegion()->getHost() << llendl; } - /* switch(index) - case TEX_HEAD_BODYPAINT: - addLocalTextureStats( LOCTEX_HEAD_BODYPAINT, imagep, texel_area_ratio, render_avatar, head_baked ); */ - const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)index); - if (texture_dict->mIsUsedByBakedTexture) - { - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - if (texture_dict->mIsLocalTexture) - { - addLocalTextureStats((ETextureIndex)index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]); - } - else if (texture_dict->mIsBakedTexture) - { - if (layer_baked[baked_index]) - { - addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); - } - } - } + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } - } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) { setDebugText(llformat("%4.0f:%4.0f", (F32) sqrt(mMinPixelArea),(F32) sqrt(mMaxPixelArea))); } - - if( render_avatar ) - { - mShadowImagep->addTextureStats(mPixelArea); - } } -void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerTexture* imagep, - F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked ) +void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture* imagep, + F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index ) { - if (!isIndexLocalTexture(idx)) return; + // No local texture stats for non-self avatars + return; +} - if (!covered_by_baked && render_avatar) // render_avatar is always true if isSelf() +const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. +const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +void LLVOAvatar::checkTextureLoading() +{ + static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds + + BOOL pause = !isVisible() ; + if(!pause) { - if (getLocalTextureID(idx) != IMG_DEFAULT_AVATAR) - { - F32 desired_pixels; - if( isSelf() ) - { - desired_pixels = llmax(mPixelArea, (F32)TEX_IMAGE_AREA_SELF ); - imagep->setBoostLevel(LLViewerTexture::BOOST_AVATAR_SELF); - // SNOW-8 : temporary snowglobe1.0 fix for baked textures - if (render_avatar && !gGLManager.mIsDisabled ) - { - // bind the texture so that its boost level won't be slammed - gGL.getTexUnit(0)->bind(imagep); - } - } - else - { - desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_OTHER ); - imagep->setBoostLevel(LLViewerTexture::BOOST_AVATAR); - } - imagep->addTextureStats( desired_pixels / texel_area_ratio ); - if (imagep->getDiscardLevel() < 0) - { - mHasGrey = TRUE; // for statistics gathering - } - } - else - { - // texture asset is missing - mHasGrey = TRUE; // for statistics gathering - } + mInvisibleTimer.reset() ; } + if(mLoadedCallbacksPaused == pause) + { + return ; + } + + if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty. + { + mLoadedCallbacksPaused = pause ; + return ; //nothing to check. + } + + if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME) + { + return ; //have not been invisible for enough time. + } + + for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin(); + iter != mCallbackTextureList.end(); ++iter) + { + LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ; + if(tex) + { + if(pause)//pause texture fetching. + { + tex->pauseLoadedCallbacks(&mCallbackTextureList) ; + + //set to terminate texture fetching after MAX_TEXTURE_UPDATE_INTERVAL frames. + tex->setMaxVirtualSizeResetInterval(MAX_TEXTURE_UPDATE_INTERVAL); + tex->resetMaxVirtualSizeResetCounter() ; + } + else//unpause + { + static const F32 START_AREA = 100.f ; + + tex->unpauseLoadedCallbacks(&mCallbackTextureList) ; + tex->addTextureStats(START_AREA); //jump start the fetching again + } + } + } + + if(!pause) + { + updateTextures() ; //refresh texture stats. + } + mLoadedCallbacksPaused = pause ; + return ; } const F32 SELF_ADDITIONAL_PRI = 0.75f ; const F32 ADDITIONAL_PRI = 0.5f; void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) { + //Note: + //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, + //the texture pipeline will stop fetching this texture. + + imagep->resetTextureStats(); imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures. + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->resetMaxVirtualSizeResetCounter() ; + mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); - mMinPixelArea = llmin(pixel_area, mMinPixelArea); + mMinPixelArea = llmin(pixel_area, mMinPixelArea); imagep->addTextureStats(pixel_area / texel_area_ratio); imagep->setBoostLevel(boost_level); @@ -5335,6 +5299,29 @@ void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel } } +//virtual +void LLVOAvatar::setImage(const U8 te, LLViewerTexture *imagep, const U32 index) +{ + setTEImage(te, imagep); +} + +//virtual +LLViewerTexture* LLVOAvatar::getImage(const U8 te, const U32 index) const +{ + return getTEImage(te); +} +//virtual +const LLTextureEntry* LLVOAvatar::getTexEntry(const U8 te_num) const +{ + return getTE(te_num); +} + +//virtual +void LLVOAvatar::setTexEntry(const U8 index, const LLTextureEntry &te) +{ + setTE(index, te); +} + //----------------------------------------------------------------------------- // resolveHeight() //----------------------------------------------------------------------------- @@ -6117,54 +6104,53 @@ BOOL LLVOAvatar::loadAvatar() llwarns << "avatar file: missing node" << llendl; return FALSE; } - else + + if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) { - LLVOAvatarXmlInfo::layer_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mLayerInfoList.begin(); - iter != sAvatarXmlInfo->mLayerInfoList.end(); iter++) + llwarns << "avatar file: missing node" << llendl; + return FALSE; + } + + // avatar_lad.xml : + for (LLVOAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin(); + iter != sAvatarXmlInfo->mMorphMaskInfoList.end(); + ++iter) + { + LLVOAvatarXmlInfo::LLVOAvatarMorphInfo *info = *iter; + + EBakedTextureIndex baked = LLVOAvatarDictionary::findBakedByRegionName(info->mRegion); + if (baked != BAKED_NUM_INDICES) { - LLTexLayerSetInfo *info = *iter; - LLTexLayerSet* layer_set = new LLTexLayerSet( this ); - if (!layer_set->setInfo(info)) + LLPolyMorphTarget *morph_param; + const std::string *name = &info->mName; + morph_param = (LLPolyMorphTarget *)(getVisualParam(name->c_str())); + if (morph_param) { - stop_glerror(); - delete layer_set; - llwarns << "avatar file: layer_set->parseData() failed" << llendl; - return FALSE; - } - bool found_baked_entry = false; - for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - baked_iter++) - { - const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; - if (layer_set->isBodyRegion(baked_dict->mName)) - { - mBakedTextureDatas[baked_iter->first].mTexLayerSet = layer_set; - layer_set->setBakedTexIndex(baked_iter->first); - found_baked_entry = true; - break; - } - } - if (!found_baked_entry) - { - llwarns << " has invalid body_region attribute" << llendl; - delete layer_set; - return FALSE; + BOOL invert = info->mInvert; + addMaskedMorph(baked, morph_param, invert, info->mLayer); } } + } + + loadLayersets(); // avatar_lad.xml : - LLVOAvatarXmlInfo::driver_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mDriverInfoList.begin(); - iter != sAvatarXmlInfo->mDriverInfoList.end(); iter++) + for (LLVOAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); + iter != sAvatarXmlInfo->mDriverInfoList.end(); + ++iter) { LLDriverParamInfo *info = *iter; LLDriverParam* driver_param = new LLDriverParam( this ); if (driver_param->setInfo(info)) { addVisualParam( driver_param ); + LLVisualParam*(LLVOAvatar::*avatar_function)(S32)const = &LLVOAvatar::getVisualParam; + if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLVOAvatar*)this,_1 ), false)) + { + llwarns << "could not link driven params for avatar " << this->getFullname() << " id: " << driver_param->getID() << llendl; + continue; + } } else { @@ -6173,6 +6159,7 @@ BOOL LLVOAvatar::loadAvatar() return FALSE; } } + return TRUE; } @@ -6439,6 +6426,23 @@ BOOL LLVOAvatar::loadMeshNodes() return TRUE; } +//----------------------------------------------------------------------------- +// loadLayerSets() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::loadLayersets() +{ + BOOL success = TRUE; + for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin(); + layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); + ++layerset_iter) + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + LLTexLayerSetInfo *layerset_info = *layerset_iter; + layerset_info->createVisualParams(this); + } + return success; +} + //----------------------------------------------------------------------------- // updateVisualParams() //----------------------------------------------------------------------------- @@ -6509,7 +6513,7 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) // We always want to look good to ourselves if( isSelf() ) { - mPixelArea = llmax( mPixelArea, F32(TEX_IMAGE_SIZE_SELF / 16) ); + mPixelArea = llmax( mPixelArea, F32(getTexImageSize() / 16) ); } } @@ -6771,26 +6775,6 @@ LLPolyMesh* LLVOAvatar::getMesh( LLPolyMeshSharedData *shared_data ) return NULL; } -//----------------------------------------------------------------------------- -// requestLayerSetUpdate() -//----------------------------------------------------------------------------- -void LLVOAvatar::requestLayerSetUpdate(ETextureIndex index ) -{ - /* switch(index) - case LOCTEX_UPPER_BODYPAINT: - case LOCTEX_UPPER_SHIRT: - if( mUpperBodyLayerSet ) - mUpperBodyLayerSet->requestUpdate(); */ - const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); - if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) - return; - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - if (mBakedTextureDatas[baked_index].mTexLayerSet) - { - mBakedTextureDatas[baked_index].mTexLayerSet->requestUpdate(); - } -} - BOOL LLVOAvatar::setParent(LLViewerObject* parent) { BOOL ret ; @@ -6831,7 +6815,10 @@ void LLVOAvatar::addChild(LLViewerObject *childp) void LLVOAvatar::removeChild(LLViewerObject *childp) { LLViewerObject::removeChild(childp); - detachObject(childp); + if (!detachObject(childp)) + { + llwarns << "Calling detach on non-attached object " << llendl; + } } //LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) @@ -6869,7 +6856,7 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(const LLViewerObje //----------------------------------------------------------------------------- // attachObject() //----------------------------------------------------------------------------- -BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) +const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object) { LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object); @@ -6893,15 +6880,6 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) LLSelectMgr::getInstance()->updateSelectionCenter(); LLSelectMgr::getInstance()->updatePointAt(); } - - if (isSelf()) - { - updateAttachmentVisibility(gAgentCamera.getCameraMode()); - - // Then make sure the inventory is in sync with the avatar. - gInventory.addChangedMask( LLInventoryObserver::LABEL, item_id ); - gInventory.notifyObservers(); - } } else llwarns << "No item ID" << llendl; @@ -6909,7 +6887,7 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) // if (!attachment || !attachment->addObject(viewer_object)) { - return FALSE; + return 0; } if (viewer_object->isSelected()) @@ -6918,37 +6896,12 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) LLSelectMgr::getInstance()->updatePointAt(); } - if (isSelf()) - { - updateAttachmentVisibility(gAgentCamera.getCameraMode()); - -// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a - // NOTE: RLVa event handlers should be invoked *after* LLVOAvatar::attachObject() calls LLViewerJointAttachment::addObject() - if (rlv_handler_t::isEnabled()) - { - RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment); - gRlvHandler.onAttach(viewer_object, attachment); - - if ( (attachment->getIsHUDAttachment()) && (!gRlvAttachmentLocks.hasLockedHUD()) ) - gRlvAttachmentLocks.updateLockedHUD(); - } -// [/RLVa:KB] - - // Then make sure the inventory is in sync with the avatar. - gInventory.addChangedMask(LLInventoryObserver::LABEL, viewer_object->getAttachmentItemID()); - gInventory.notifyObservers(); - - // Should just be the last object added - if (attachment->isObjectAttached(viewer_object)) - { - LLCOFMgr::instance().addAttachment(viewer_object->getAttachmentItemID()); - updateLODRiggedAttachments(); - } - } - - return TRUE; + return attachment; } +//----------------------------------------------------------------------------- +// attachObject() +//----------------------------------------------------------------------------- U32 LLVOAvatar::getNumAttachments() const { U32 num_attachments = 0; @@ -6970,6 +6923,15 @@ BOOL LLVOAvatar::canAttachMoreObjects() const return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); } +//----------------------------------------------------------------------------- +// canAttachMoreObjects() +// Returns true if we can attach more objects. +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const +{ + return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; +} + //----------------------------------------------------------------------------- // lazyAttach() //----------------------------------------------------------------------------- @@ -7033,7 +6995,6 @@ void LLVOAvatar::rebuildRiggedAttachments( void ) } } } - //----------------------------------------------------------------------------- // cleanupAttachedMesh() //----------------------------------------------------------------------------- @@ -7083,66 +7044,21 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) if (attachment->isObjectAttached(viewer_object)) { -// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a - // NOTE: RLVa event handlers should be invoked *before* LLVOAvatar::detachObject() calls LLViewerJointAttachment::removeObject() - if ( (rlv_handler_t::isEnabled()) && (isSelf()) ) - { - for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt) - { - const LLViewerJointAttachment* pAttachPt = itAttachPt->second; - if (pAttachPt->isObjectAttached(viewer_object)) - { - RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt); - gRlvHandler.onDetach(viewer_object, pAttachPt); - } - } - } -// [/RLVa:KB] cleanupAttachedMesh( viewer_object ); - LLUUID item_id = viewer_object->getAttachmentItemID(); attachment->removeObject(viewer_object); - if (isSelf()) - { - // the simulator should automatically handle - // permission revocation - - stopMotionFromSource(viewer_object->getID()); - LLFollowCamMgr::setCameraActive(viewer_object->getID(), FALSE); - - LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child_objectp = *iter; - // the simulator should automatically handle - // permissions revocation - - stopMotionFromSource(child_objectp->getID()); - LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE); - } - -// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a - if ( (rlv_handler_t::isEnabled()) && (viewer_object->isHUDAttachment()) && (gRlvAttachmentLocks.hasLockedHUD()) ) - gRlvAttachmentLocks.updateLockedHUD(); -// [/RLVa:KB] - } lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl; - if (isSelf()) - { - // Then make sure the inventory is in sync with the avatar. - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - gInventory.notifyObservers(); - - // Update COF contents (unless the avatar is being destroyed) - if ( (getRegion()) && (!isDead()) ) - { - LLCOFMgr::instance().removeAttachment(item_id); - } - } return TRUE; } } + std::vector >::iterator iter = std::find(mPendingAttachment.begin(), mPendingAttachment.end(), viewer_object); + if (iter != mPendingAttachment.end()) + { + mPendingAttachment.erase(iter); + return TRUE; + } + + // testzone attachpt LLUUID item_id; LLNameValue* item_id_nv = viewer_object->getNVPair("AttachItemID"); @@ -7348,16 +7264,6 @@ void LLVOAvatar::getOffObject() } } - - - - - - - - - - //----------------------------------------------------------------------------- // findAvatarFromAttachment() //----------------------------------------------------------------------------- @@ -7380,6 +7286,12 @@ LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj ) return NULL; } +S32 LLVOAvatar::getAttachmentCount() +{ + S32 count = mAttachmentPoints.size(); + return count; +} + //----------------------------------------------------------------------------- // isWearingAttachment() //----------------------------------------------------------------------------- @@ -7474,84 +7386,6 @@ const std::string LLVOAvatar::getAttachedPointName(const LLUUID& inv_item_id) - - - -//----------------------------------------------------------------------------- -// static -// onLocalTextureLoaded() -//----------------------------------------------------------------------------- - -void LLVOAvatar::onLocalTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) -{ - //llinfos << "onLocalTextureLoaded: " << src_vi->getID() << llendl; - - const LLUUID& src_id = src_vi->getID(); - LLAvatarTexData *data = (LLAvatarTexData *)userdata; - if (success) - { - LLVOAvatar *self = gObjectList.findAvatar(data->mAvatarID); - if (self) - { - ETextureIndex index = data->mIndex; - if (!self->isIndexLocalTexture(index)) return; - LocalTextureData &local_tex_data = self->mLocalTextureData[index]; - if(!local_tex_data.mIsBakedReady && - local_tex_data.mImage.notNull() && - (local_tex_data.mImage->getID() == src_id) && - discard_level < local_tex_data.mDiscard) - { - local_tex_data.mDiscard = discard_level; - if ( self->isSelf() && !gAgentCamera.cameraCustomizeAvatar() ) - { - self->requestLayerSetUpdate( index ); - } - else if( self->isSelf() && gAgentCamera.cameraCustomizeAvatar() ) - { - LLVisualParamHint::requestHintUpdates(); - } - self->updateMeshTextures(); - } - } - } - else if (final) - { - LLVOAvatar *self = gObjectList.findAvatar(data->mAvatarID); - if (self) - { - ETextureIndex index = data->mIndex; - if (!self->isIndexLocalTexture(index)) return; - LocalTextureData &local_tex_data = self->mLocalTextureData[index]; - // Failed: asset is missing - if(!local_tex_data.mIsBakedReady && - local_tex_data.mImage.notNull() && - local_tex_data.mImage->getID() == src_id) - { - local_tex_data.mDiscard = 0; - self->requestLayerSetUpdate( index ); - self->updateMeshTextures(); - } - } - } - - if( final || !success ) - { - delete data; - } -} - -void LLVOAvatar::updateComposites() -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - if ( mBakedTextureDatas[i].mTexLayerSet - && ((i != BAKED_SKIRT) || isWearingWearableType( LLWearableType::WT_SKIRT )) ) - { - mBakedTextureDatas[i].mTexLayerSet->updateComposite(); - } - } -} - LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) const { if (color_name=="skin_color" && mTexSkinColor) @@ -7576,63 +7410,10 @@ LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) const void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) { - if( !layerset || !layerset->getUpdatesEnabled() ) - { - return; - } - - /* Debug spam. JC - const char* layer_name = ""; - if (layerset == mHeadLayerSet) - { - layer_name = "head"; - } - else if (layerset == mUpperBodyLayerSet) - { - layer_name = "upperbody"; - } - else if (layerset == mLowerBodyLayerSet) - { - layer_name = "lowerbody"; - } - else if (layerset == mEyesLayerSet) - { - layer_name = "eyes"; - } - else if (layerset == mHairLayerSet) - { - layer_name = "hair"; - } - else if (layerset == mSkirtLayerSet) - { - layer_name = "skirt"; - } - else - { - layer_name = "unknown"; - } - llinfos << "LLVOAvatar::invalidComposite() " << layer_name << llendl; - */ - - layerset->requestUpdate(); - - if( upload_result ) - { - llassert( isSelf() ); - - ETextureIndex baked_te = getBakedTE( layerset ); - setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR,0)); - layerset->requestUpload(); - } } void LLVOAvatar::invalidateAll() { - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, TRUE); - } - updateMeshTextures(); } void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake ) @@ -7673,227 +7454,77 @@ BOOL LLVOAvatar::isVisible() const && (mDrawable->isVisible() || mIsDummy); } -void LLVOAvatar::forceBakeAllTextures(bool slam_for_debug) +// Determine if we have enough avatar data to render +BOOL LLVOAvatar::getIsCloud() { - llinfos << "TAT: forced full rebake. " << llendl; - - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + // Do we have a shape? + if (visualParamWeightsAreDefault()) { - ETextureIndex baked_index = mBakedTextureDatas[i].mTextureIndex; - LLTexLayerSet* layer_set = getLayerSet(baked_index); - if (layer_set) - { - if (slam_for_debug) - { - layer_set->setUpdatesEnabled(TRUE); - layer_set->cancelUpload(); - } - - BOOL set_by_user = TRUE; - invalidateComposite(layer_set, set_by_user); - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); - } - else - { - llwarns << "TAT: NO LAYER SET FOR " << (S32)baked_index << llendl; - } + return TRUE; } - // Don't know if this is needed - updateMeshTextures(); + if (!isTextureDefined(TEX_LOWER_BAKED) || + !isTextureDefined(TEX_UPPER_BAKED) || + !isTextureDefined(TEX_HEAD_BAKED)) + { + return TRUE; + } + + /*if (isTooComplex()) + { + return TRUE; + }*/ + return FALSE; } - -// static -void LLVOAvatar::processRebakeAvatarTextures(LLMessageSystem* msg, void**) -{ - LLUUID texture_id; - msg->getUUID("TextureData", "TextureID", texture_id); - - LLVOAvatar* self = gAgentAvatarp; - if (!self) return; - - // If this is a texture corresponding to one of our baked entries, - // just rebake that layer set. - BOOL found = FALSE; - - /* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = - TEX_HEAD_BAKED, - TEX_UPPER_BAKED, */ - for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - iter++) - { - const ETextureIndex index = iter->first; - const LLVOAvatarDictionary::TextureEntry *text_dict = iter->second; - if (text_dict->mIsBakedTexture) - { - if (texture_id == self->getTEImage(index)->getID()) - { - LLTexLayerSet* layer_set = self->getLayerSet(index); - if (layer_set) - { - llinfos << "TAT: rebake - matched entry " << (S32)index << llendl; - // Apparently set_by_user == force upload - BOOL set_by_user = TRUE; - self->invalidateComposite(layer_set, set_by_user); - found = TRUE; - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); - } - } - } - } - - // If texture not found, rebake all entries. - if (!found) - { - self->forceBakeAllTextures(); - } - else - { - // Not sure if this is necessary, but forceBakeAllTextures() does it. - self->updateMeshTextures(); - } -} - - -/*BOOL LLVOAvatar::getLocalTextureRaw(ETextureIndex index, LLImageRaw* image_raw) -{ - if (!isIndexLocalTexture(index)) return FALSE; - - BOOL success = FALSE; - - if (getLocalTextureID(index) == IMG_DEFAULT_AVATAR) - { - success = TRUE; - } - else - { - LocalTextureData &local_tex_data = mLocalTextureData[index]; - if(local_tex_data.mImage->readBackRaw(-1, image_raw, false)) - { - success = TRUE; - } - else - { - // No data loaded yet - setLocalTexture( (ETextureIndex)index, getTEImage( index ), FALSE ); - } - } - return success; -}*/ - -BOOL LLVOAvatar::getLocalTextureGL(ETextureIndex index, LLViewerTexture** image_gl_pp) -{ - if (!isIndexLocalTexture(index)) return FALSE; - - BOOL success = FALSE; - *image_gl_pp = NULL; - - if (getLocalTextureID(index) == IMG_DEFAULT_AVATAR) - { - success = TRUE; - } - else - { - LocalTextureData &local_tex_data = mLocalTextureData[index]; - *image_gl_pp = local_tex_data.mImage; - success = TRUE; - } - - if( !success ) - { -// llinfos << "getLocalTextureGL(" << index << ") had no data" << llendl; - } - return success; -} - -const LLUUID& LLVOAvatar::getLocalTextureID(ETextureIndex index) -{ - if (!isIndexLocalTexture(index)) return IMG_DEFAULT_AVATAR; - - if (mLocalTextureData[index].mImage.notNull()) - { - return mLocalTextureData[index].mImage->getID(); - } - else - { - return IMG_DEFAULT_AVATAR; - } -} - -// static -void LLVOAvatar::dumpTotalLocalTextureByteCount() -{ - S32 total_gl_bytes = 0; - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* cur = (LLVOAvatar*) *iter; - S32 gl_bytes = 0; - cur->getLocalTextureByteCount(&gl_bytes ); - total_gl_bytes += gl_bytes; - } - llinfos << "Total Avatar LocTex GL:" << (total_gl_bytes/1024) << "KB" << llendl; -} - - // call periodically to keep isFullyLoaded up to date. // returns true if the value has changed. BOOL LLVOAvatar::updateIsFullyLoaded() { - // a "heuristic" to determine if we have enough avatar data to render - // (to avoid rendering a "Ruth" - DEV-3168) + const BOOL loading = getIsCloud(); + updateRuthTimer(loading); + return processFullyLoadedChange(loading); +} - BOOL loading = FALSE; - - // do we have a shape? - if (visualParamWeightsAreDefault()) +void LLVOAvatar::updateRuthTimer(bool loading) +{ + if (isSelf() || !loading) { - loading = TRUE; + return; } - // - if (isSelf()) + if (mPreviousFullyLoaded) { - if (!isTextureDefined(TEX_HAIR)) + mRuthTimer.reset(); + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) { - loading = TRUE; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezCloudNotification",args); } - } - else if (!isTextureDefined(TEX_LOWER_BAKED) || !isTextureDefined(TEX_UPPER_BAKED) || !isTextureDefined(TEX_HEAD_BAKED)) - { - loading = TRUE; + mRuthDebugTimer.reset(); } - // special case to keep nudity off orientation island - - // this is fragilely dependent on the compositing system, - // which gets available textures in the following order: - // - // 1) use the baked texture - // 2) use the layerset - // 3) use the previously baked texture - // - // on orientation island case (3) can show naked skin. - // so we test for that here: - // - // if we were previously unloaded, and we don't have enough - // texture info for our shirt/pants, stay unloaded: - if (!mPreviousFullyLoaded) + const F32 LOADING_TIMEOUT__SECONDS = 120.f; + if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS) { - if ((!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_LOWER].mTexLayerSet)) && - (!isTextureDefined(TEX_LOWER_BAKED))) - { - loading = TRUE; - } - - if ((!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_UPPER].mTexLayerSet)) && - (!isTextureDefined(TEX_UPPER_BAKED))) - { - loading = TRUE; - } + llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " + << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " + << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " + << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " + << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." + << llendl; + + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); + mRuthTimer.reset(); } - +} + +BOOL LLVOAvatar::processFullyLoadedChange(bool loading) +{ // we wait a little bit before giving the all clear, // to let textures settle down const F32 PAUSE = 1.f; @@ -7902,8 +7533,19 @@ BOOL LLVOAvatar::updateIsFullyLoaded() mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); - updateRuthTimer(loading); - + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (!mPreviousFullyLoaded && !loading && mFullyLoaded) + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezNotification",args); + } + } + // did our loading state "change" from last call? const S32 UPDATE_RATE = 30; BOOL changed = @@ -7925,43 +7567,13 @@ BOOL LLVOAvatar::isFullyLoaded() const // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a // Changes to LLAppearanceMgr::updateAppearanceFromCOF() expect this function to actually return mFullyLoaded for gAgentAvatarp static const LLCachedControl rener_unloaded_avatar("RenderUnloadedAvatar"); - if ( (!isSelf()) && (rener_unloaded_avatar) ) + if ( (!isSelf()) && (mRenderUnloadedAvatar) ) return TRUE; else return mFullyLoaded; // [/SL:KB] } -bool LLVOAvatar::sendAvatarTexturesRequest() -{ - bool sent = false; - if (mRuthTimer.getElapsedTimeF32() > DERUTHING_TIMEOUT_SECONDS) - { - LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); - mRuthTimer.reset(); - sent = true; - } - return sent; -} - -void LLVOAvatar::updateRuthTimer(bool loading) -{ - if (isSelf() || !loading) - { - return; - } - - if (!mPreviousFullyLoaded && sendAvatarTexturesRequest()) - { - llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " - << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " - << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " - << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " - << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." - << llendl; - } -} - //----------------------------------------------------------------------------- // findMotion() //----------------------------------------------------------------------------- @@ -7970,179 +7582,6 @@ LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const return mMotionController.findMotion(id); } -// Counts the memory footprint of local textures. -void LLVOAvatar::getLocalTextureByteCount( S32* gl_bytes ) -{ - *gl_bytes = 0; - for( S32 i = 0; i < TEX_NUM_INDICES; i++ ) - { - if (!isIndexLocalTexture((ETextureIndex)i)) continue; - LLViewerTexture* image_gl = mLocalTextureData[(ETextureIndex)i].mImage; - if( image_gl ) - { - S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents(); - - if( image_gl->hasGLTexture() ) - { - *gl_bytes += bytes; - } - } - } -} - - -BOOL LLVOAvatar::bindScratchTexture( LLGLenum format ) -{ - U32 texture_bytes = 0; - GLuint gl_name = getScratchTexName( format, &texture_bytes ); - if( gl_name ) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); - stop_glerror(); - - F32* last_bind_time = LLVOAvatar::sScratchTexLastBindTime.getIfThere( format ); - if( last_bind_time ) - { - if( *last_bind_time != LLImageGL::sLastFrameTime ) - { - *last_bind_time = LLImageGL::sLastFrameTime; - LLImageGL::updateBoundTexMem(texture_bytes, SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - } - } - else - { - LLImageGL::updateBoundTexMem(texture_bytes, SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - LLVOAvatar::sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) ); - } - - - return TRUE; - } - else - { - return FALSE; - } -} - - -LLGLuint LLVOAvatar::getScratchTexName( LLGLenum format, U32* texture_bytes ) -{ - S32 components; - GLenum internal_format; - switch( format ) - { - case GL_LUMINANCE: components = 1; internal_format = GL_LUMINANCE8; break; - case GL_ALPHA: components = 1; internal_format = GL_ALPHA8; break; -// Support for GL_EXT_paletted_texture is deprecated -// case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break; - case GL_LUMINANCE_ALPHA: components = 2; internal_format = GL_LUMINANCE8_ALPHA8; break; - case GL_RGB: components = 3; internal_format = GL_RGB8; break; - case GL_RGBA: components = 4; internal_format = GL_RGBA8; break; - default: llassert(0); components = 4; internal_format = GL_RGBA8; break; - } - - *texture_bytes = components * SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT; - - if( LLVOAvatar::sScratchTexNames.checkData( format ) ) - { - return *( LLVOAvatar::sScratchTexNames.getData( format ) ); - } - else - { - - LLGLSUIDefault gls_ui; - - U32 name = 0; - LLImageGL::generateTextures(1, &name ); - stop_glerror(); - - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, name); - stop_glerror(); - - LLImageGL::setManualImage( - GL_TEXTURE_2D, 0, internal_format, - SCRATCH_TEX_WIDTH, SCRATCH_TEX_HEIGHT, - format, GL_UNSIGNED_BYTE, NULL ); - stop_glerror(); - - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - stop_glerror(); - - LLVOAvatar::sScratchTexNames.addData( format, new LLGLuint( name ) ); - - LLVOAvatar::sScratchTexBytes += *texture_bytes; - LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes; - - if(gAuditTexture) - { - LLImageGL::incTextureCounter(SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - } - - return name; - } -} - - - -//----------------------------------------------------------------------------- -// setLocalTextureTE() -//----------------------------------------------------------------------------- -void LLVOAvatar::setLocTexTE( U8 te, LLViewerTexture* image, BOOL set_by_user ) -{ - if( !isSelf() ) - { - llassert( 0 ); - return; - } - - if( te >= TEX_NUM_INDICES ) - { - llassert(0); - return; - } - - if( getTEImage( te )->getID() == image->getID() ) - { - return; - } - - if (isIndexBakedTexture((ETextureIndex)te)) - { - llassert(0); - return; - } - - LLTexLayerSet* layer_set = getLayerSet((ETextureIndex)te); - if (layer_set) - { - invalidateComposite(layer_set, set_by_user); - } - - setTEImage( te, image ); - updateMeshTextures(); - - if( gAgentCamera.cameraCustomizeAvatar() ) - { - LLVisualParamHint::requestHintUpdates(); - } -} - -void LLVOAvatar::setupComposites() -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - bool layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); - if (mBakedTextureDatas[i].mTexLayerSet) - { - mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( !layer_baked ); - } - } -} - //----------------------------------------------------------------------------- // updateMeshTextures() // Uses the current TE values to set the meshes' and layersets' textures. @@ -8155,20 +7594,27 @@ void LLVOAvatar::updateMeshTextures() // if user has never specified a texture, assign the default for (U32 i=0; i < getNumTEs(); i++) { - const LLViewerTexture* te_image = getTEImage(i); + const LLViewerTexture* te_image = getImage(i, 0); if(!te_image || te_image->getID().isNull() || (te_image->getID() == IMG_DEFAULT)) { - setTEImage(i, LLViewerTextureManager::getFetchedTexture(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR)); // IMG_DEFAULT_AVATAR = a special texture that's never rendered. + setImage(i, LLViewerTextureManager::getFetchedTexture(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR), 0); // IMG_DEFAULT_AVATAR = a special texture that's never rendered. } } const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures const BOOL other_culled = !isSelf() && mCulled; + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; + BOOL paused = FALSE; + if(!isSelf()) + { + src_callback_list = &mCallbackTextureList ; + paused = mLoadedCallbacksPaused ; + } - std::vector is_layer_baked; + std::vector is_layer_baked; is_layer_baked.resize(mBakedTextureDatas.size(), false); - std::vector use_lkg_baked_layer; // lkg = "last known good" + std::vector use_lkg_baked_layer; // lkg = "last known good" use_lkg_baked_layer.resize(mBakedTextureDatas.size(), false); for (U32 i=0; i < mBakedTextureDatas.size(); i++) @@ -8180,10 +7626,12 @@ void LLVOAvatar::updateMeshTextures() // When an avatar is changing clothes and not in Appearance mode, // use the last-known good baked texture until it finish the first // render of the new layerset. - use_lkg_baked_layer[i] = (!is_layer_baked[i] - && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) - && mBakedTextureDatas[i].mTexLayerSet - && !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized()); + const BOOL layerset_invalid = mBakedTextureDatas[i].mTexLayerSet + && ( !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized() + || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable() ); + use_lkg_baked_layer[i] = (!is_layer_baked[i] + && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) + && layerset_invalid); if (use_lkg_baked_layer[i]) { mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE); @@ -8224,7 +7672,7 @@ void LLVOAvatar::updateMeshTextures() } else if (!self_customizing && is_layer_baked[i]) { - LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getTEImage( mBakedTextureDatas[i].mTextureIndex ), TRUE) ; + LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ; if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureIndex ) { // Even though the file may not be finished loading, we'll consider it loaded and use it (rather than doing compositing). @@ -8234,15 +7682,16 @@ void LLVOAvatar::updateMeshTextures() { mBakedTextureDatas[i].mIsLoaded = FALSE; if ( (baked_img->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) - { - baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), NULL); + { + baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), + src_callback_list, paused); } - baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), NULL); + baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), + src_callback_list, paused ); } } else if (mBakedTextureDatas[i].mTexLayerSet - && !other_culled - && (i != BAKED_HAIR || is_layer_baked[i] || isSelf())) // ! BACKWARDS COMPATIBILITY ! workaround for old viewers. + && !other_culled) { mBakedTextureDatas[i].mTexLayerSet->createComposite(); mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( TRUE ); @@ -8253,29 +7702,22 @@ void LLVOAvatar::updateMeshTextures() } } } - - // ! BACKWARDS COMPATIBILITY ! - // Workaround for viewing avatars from old viewers that haven't baked hair textures. - // if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex)) + + // set texture and color of hair manually if we are not using a baked image. + // This can happen while loading hair for yourself, or for clients that did not + // bake a hair texture. Still needed for yourself after 1.22 is depricated. if (!is_layer_baked[BAKED_HAIR] || self_customizing) { const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1); - LLViewerTexture* hair_img = getTEImage( TEX_HAIR ); + LLViewerTexture* hair_img = getImage( TEX_HAIR, 0 ); for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) { mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setTexture( hair_img ); } - mHasBakedHair = FALSE; - } - else - { - mHasBakedHair = TRUE; - } + } + - /* // Head - BOOL head_baked_ready = (is_layer_baked[BAKED_HEAD] && mBakedTextureDatas[BAKED_HEAD].mIsLoaded) || other_culled; - setLocalTexture( TEX_HEAD_BODYPAINT, getTEImage( TEX_HEAD_BODYPAINT ), head_baked_ready ); */ for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); ++baked_iter) @@ -8289,90 +7731,32 @@ void LLVOAvatar::updateMeshTextures() { const ETextureIndex texture_index = *local_tex_iter; const BOOL is_baked_ready = (is_layer_baked[baked_index] && mBakedTextureDatas[baked_index].mIsLoaded) || other_culled; - setLocalTexture(texture_index, LLViewerTextureManager::staticCastToFetchedTexture(getTEImage(texture_index)), is_baked_ready ); + if (isSelf()) + { + setBakedReady(texture_index, is_baked_ready); + } } } removeMissingBakedTextures(); } +// virtual //----------------------------------------------------------------------------- // setLocalTexture() //----------------------------------------------------------------------------- -void LLVOAvatar::setLocalTexture( ETextureIndex index, LLViewerFetchedTexture* tex, BOOL baked_version_ready ) +void LLVOAvatar::setLocalTexture( ETextureIndex type, LLViewerTexture* in_tex, BOOL baked_version_ready, U32 index ) { - if (!isIndexLocalTexture(index)) return; - - S32 desired_discard = isSelf() ? 0 : 2; - LocalTextureData &local_tex_data = mLocalTextureData[index]; - if (!baked_version_ready) - { - if (tex != local_tex_data.mImage || local_tex_data.mIsBakedReady) - { - local_tex_data.mDiscard = MAX_DISCARD_LEVEL+1; - } - if (tex->getID() != IMG_DEFAULT_AVATAR) - { - if (local_tex_data.mDiscard > desired_discard) - { - S32 tex_discard = tex->getDiscardLevel(); - if (tex_discard >= 0 && tex_discard <= desired_discard) - { - local_tex_data.mDiscard = tex_discard; - if( isSelf() && !gAgentCamera.cameraCustomizeAvatar() ) - { - requestLayerSetUpdate( index ); - } - else if( isSelf() && gAgentCamera.cameraCustomizeAvatar() ) - { - LLVisualParamHint::requestHintUpdates(); - } - } - else - { - tex->setLoadedCallback( onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), index), NULL ); - } - } - tex->setMinDiscardLevel(desired_discard); - } - } - local_tex_data.mIsBakedReady = baked_version_ready; - local_tex_data.mImage = tex; + // invalid for anyone but self + llassert(0); } -//----------------------------------------------------------------------------- -// requestLayerSetUploads() -//----------------------------------------------------------------------------- -void LLVOAvatar::requestLayerSetUploads() +//virtual +void LLVOAvatar::setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index) { - llassert_always(isSelf()); - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - requestLayerSetUpload((EBakedTextureIndex)i); - } + // invalid for anyone but self + llassert(0); } -void LLVOAvatar::requestLayerSetUpload(LLVOAvatarDefines::EBakedTextureIndex i) -{ - bool layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); - if ( !layer_baked && mBakedTextureDatas[i].mTexLayerSet ) - { - mBakedTextureDatas[i].mTexLayerSet->requestUpload(); - } -} - -//----------------------------------------------------------------------------- -// setCompositeUpdatesEnabled() -//----------------------------------------------------------------------------- -void LLVOAvatar::setCompositeUpdatesEnabled( BOOL b ) -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - if (mBakedTextureDatas[i].mTexLayerSet ) - { - mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( b ); - } - } -} void LLVOAvatar::setNameFromChat(const std::string &text) { static const LLCachedControl allow_nameplate_override ("CCSAllowNameplateOverride", true); @@ -8419,180 +7803,59 @@ void LLVOAvatar::clearChat() mChats.clear(); } -S32 LLVOAvatar::getLocalDiscardLevel( ETextureIndex index ) +// adds a morph mask to the appropriate baked texture structure +void LLVOAvatar::addMaskedMorph(EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer) { - // If the texture is not local, we don't care and treat it as fully loaded - if (!isIndexLocalTexture(index)) return FALSE; - - LocalTextureData &local_tex_data = mLocalTextureData[index]; - if (index >= 0 - && getLocalTextureID(index) != IMG_DEFAULT_AVATAR - && !local_tex_data.mImage->isMissingAsset()) + if (index < BAKED_NUM_INDICES) { - return local_tex_data.mImage->getDiscardLevel(); - } - else - { - // We don't care about this (no image associated with the layer) treat as fully loaded. - return 0; + LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer); + mBakedTextureDatas[index].mMaskedMorphs.push_front(morph); } } -//----------------------------------------------------------------------------- -// isLocalTextureDataFinal() -// Returns true if the highest quality discard level exists for every texture -// in the layerset. -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::isLocalTextureDataFinal( const LLTexLayerSet* layerset ) +// returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise +BOOL LLVOAvatar::morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index) { - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + if (index >= BAKED_NUM_INDICES) { - if (layerset == mBakedTextureDatas[i].mTexLayerSet) + return FALSE; + } + + if (!mBakedTextureDatas[index].mMaskedMorphs.empty()) + { + if (isSelf()) { - const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); - for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); - local_tex_iter != baked_dict->mLocalTextures.end(); - local_tex_iter++) + LLTexLayerSet *layer_set = mBakedTextureDatas[index].mTexLayerSet; + if (layer_set) { - if (getLocalDiscardLevel(*local_tex_iter) != 0) - { - return FALSE; - } + return !layer_set->isMorphValid(); } - return TRUE; + } + else + { + return FALSE; } } - llassert(0); return FALSE; } -//----------------------------------------------------------------------------- -// isLocalTextureDataAvailable() -// Returns true if at least the lowest quality discard level exists for every texture -// in the layerset. -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::isLocalTextureDataAvailable( const LLTexLayerSet* layerset ) +void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index) { - /* if( layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet ) - return getLocalDiscardLevel( TEX_HEAD_BODYPAINT ) >= 0; */ - for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - baked_iter++) + if (index >= BAKED_NUM_INDICES) { - const EBakedTextureIndex baked_index = baked_iter->first; - if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet) - { - bool ret = true; - const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; - for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); - local_tex_iter != baked_dict->mLocalTextures.end(); - local_tex_iter++) - { - ret &= (getLocalDiscardLevel(*local_tex_iter) >= 0); - } - return ret; - } - } - llassert(0); - return FALSE; -} - - -//----------------------------------------------------------------------------- -// getBakedTE() -// Used by the LayerSet. (Layer sets don't in general know what textures depend on them.) -//----------------------------------------------------------------------------- -ETextureIndex LLVOAvatar::getBakedTE( LLTexLayerSet* layerset ) -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - if (layerset == mBakedTextureDatas[i].mTexLayerSet ) - { - return mBakedTextureDatas[i].mTextureIndex; - } + llwarns << "invalid baked texture index passed to applyMorphMask" << llendl; + return; } - llassert(0); - return TEX_HEAD_BAKED; -} - -//----------------------------------------------------------------------------- -// setNewBakedTexture() -// A new baked texture has been successfully uploaded and we can start using it now. -//----------------------------------------------------------------------------- -void LLVOAvatar::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ - // Baked textures live on other sims. - LLHost target_host = getObjectHost(); - setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, target_host ) ); - if (uuid != IMG_INVISIBLE) + for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin(); + iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter) { - // Do not update textures when setting a new invisible baked texture as - // it would result in destroying the calling object (setNewBakedTexture() - // is called by LLTexLayerSetBuffer::render()) ! - updateMeshTextures(); - } - dirtyMesh(); - - - LLVOAvatar::cullAvatarsByPixelArea(); - - /* switch(te) - case TEX_HEAD_BAKED: - llinfos << "New baked texture: HEAD" << llendl; */ - const LLVOAvatarDictionary::TextureEntry *text_dict = LLVOAvatarDictionary::getInstance()->getTexture(te); - if (text_dict->mIsBakedTexture) - { - llinfos << "New baked texture: " << text_dict->mName << " UUID: " << uuid <mBakedTextureIndex].mTexLayerSet->requestUpdate(); - } - else - { - llwarns << "New baked texture: unknown te " << te << llendl; - } - - // dumpAvatarTEs( "setNewBakedTexture() send" ); - // RN: throttle uploads - if (!hasPendingBakedUploads()) - { - gAgent.sendAgentSetAppearance(); + const LLMaskedMorph* maskedMorph = (*iter); + maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert); } } -bool LLVOAvatar::hasPendingBakedUploads() -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - bool upload_pending = (mBakedTextureDatas[i].mTexLayerSet && mBakedTextureDatas[i].mTexLayerSet->getComposite()->uploadPending()); - if (upload_pending) - { - return true; - } - } - return false; -} - -//----------------------------------------------------------------------------- -// setCachedBakedTexture() -// A baked texture id was received from a cache query, make it active -//----------------------------------------------------------------------------- -void LLVOAvatar::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ - setTETexture( te, uuid ); - - /* switch(te) - case TEX_HEAD_BAKED: - if( mHeadLayerSet ) - mHeadLayerSet->cancelUpload(); */ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - if ( mBakedTextureDatas[i].mTextureIndex == te && mBakedTextureDatas[i].mTexLayerSet) - { - mBakedTextureDatas[i].mTexLayerSet->cancelUpload(); - } - } -} //----------------------------------------------------------------------------- // releaseComponentTextures() @@ -8605,9 +7868,9 @@ void LLVOAvatar::releaseComponentTextures() { // ! BACKWARDS COMPATIBILITY ! // Detect if the baked hair texture actually wasn't sent, and if so set to default - if (isTextureDefined(TEX_HAIR_BAKED) && getTEImage(TEX_HAIR_BAKED)->getID() == getTEImage(TEX_SKIRT_BAKED)->getID()) + if (isTextureDefined(TEX_HAIR_BAKED) && getImage(TEX_HAIR_BAKED,0)->getID() == getImage(TEX_SKIRT_BAKED,0)->getID()) { - if (getTEImage(TEX_HAIR_BAKED)->getID() != IMG_INVISIBLE) + if (getImage(TEX_HAIR_BAKED,0)->getID() != IMG_INVISIBLE) { // Regression case of messaging system. Expected 21 textures, received 20. last texture is not valid so set to default setTETexture(TEX_HAIR_BAKED, IMG_DEFAULT_AVATAR); @@ -8653,102 +7916,84 @@ void LLVOAvatar::onCustomizeStart() //----------------------------------------------------------------------------- void LLVOAvatar::onCustomizeEnd() { - LLVOAvatar *avatarp = gAgentAvatarp; - if (avatarp) + if (isAgentAvatarValid()) { - avatarp->invalidateAll(); - avatarp->requestLayerSetUploads(); - } -} - -void LLVOAvatar::onChangeSelfInvisible(BOOL newvalue) -{ - LLVOAvatar *avatarp = gAgentAvatarp; - if (avatarp) - { - if (newvalue) - { - // we have just requested to set the avatar's baked textures to invisible - avatarp->setInvisible(TRUE); - } - else - { - avatarp->setInvisible(FALSE); - } + gAgentAvatarp->invalidateAll(); + gAgentAvatarp->requestLayerSetUploads(); } } //static -BOOL LLVOAvatar::teToColorParams( ETextureIndex te, const char* param_name[3] ) +BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name ) { switch( te ) { - case TEX_UPPER_SHIRT: - param_name[0] = "shirt_red"; - param_name[1] = "shirt_green"; - param_name[2] = "shirt_blue"; - break; + case TEX_UPPER_SHIRT: + param_name[0] = 803; //"shirt_red"; + param_name[1] = 804; //"shirt_green"; + param_name[2] = 805; //"shirt_blue"; + break; - case TEX_LOWER_PANTS: - param_name[0] = "pants_red"; - param_name[1] = "pants_green"; - param_name[2] = "pants_blue"; - break; + case TEX_LOWER_PANTS: + param_name[0] = 806; //"pants_red"; + param_name[1] = 807; //"pants_green"; + param_name[2] = 808; //"pants_blue"; + break; - case TEX_LOWER_SHOES: - param_name[0] = "shoes_red"; - param_name[1] = "shoes_green"; - param_name[2] = "shoes_blue"; - break; + case TEX_LOWER_SHOES: + param_name[0] = 812; //"shoes_red"; + param_name[1] = 813; //"shoes_green"; + param_name[2] = 817; //"shoes_blue"; + break; - case TEX_LOWER_SOCKS: - param_name[0] = "socks_red"; - param_name[1] = "socks_green"; - param_name[2] = "socks_blue"; - break; + case TEX_LOWER_SOCKS: + param_name[0] = 818; //"socks_red"; + param_name[1] = 819; //"socks_green"; + param_name[2] = 820; //"socks_blue"; + break; - case TEX_UPPER_JACKET: - case TEX_LOWER_JACKET: - param_name[0] = "jacket_red"; - param_name[1] = "jacket_green"; - param_name[2] = "jacket_blue"; - break; + case TEX_UPPER_JACKET: + case TEX_LOWER_JACKET: + param_name[0] = 834; //"jacket_red"; + param_name[1] = 835; //"jacket_green"; + param_name[2] = 836; //"jacket_blue"; + break; - case TEX_UPPER_GLOVES: - param_name[0] = "gloves_red"; - param_name[1] = "gloves_green"; - param_name[2] = "gloves_blue"; - break; + case TEX_UPPER_GLOVES: + param_name[0] = 827; //"gloves_red"; + param_name[1] = 829; //"gloves_green"; + param_name[2] = 830; //"gloves_blue"; + break; - case TEX_UPPER_UNDERSHIRT: - param_name[0] = "undershirt_red"; - param_name[1] = "undershirt_green"; - param_name[2] = "undershirt_blue"; - break; + case TEX_UPPER_UNDERSHIRT: + param_name[0] = 821; //"undershirt_red"; + param_name[1] = 822; //"undershirt_green"; + param_name[2] = 823; //"undershirt_blue"; + break; - case TEX_LOWER_UNDERPANTS: - param_name[0] = "underpants_red"; - param_name[1] = "underpants_green"; - param_name[2] = "underpants_blue"; - break; + case TEX_LOWER_UNDERPANTS: + param_name[0] = 824; //"underpants_red"; + param_name[1] = 825; //"underpants_green"; + param_name[2] = 826; //"underpants_blue"; + break; - case TEX_SKIRT: - param_name[0] = "skirt_red"; - param_name[1] = "skirt_green"; - param_name[2] = "skirt_blue"; - break; + case TEX_SKIRT: + param_name[0] = 921; //"skirt_red"; + param_name[1] = 922; //"skirt_green"; + param_name[2] = 923; //"skirt_blue"; + break; - case TEX_HEAD_TATTOO: //-ASC-TTRFE - case TEX_LOWER_TATTOO: - case TEX_UPPER_TATTOO: - param_name[0] = "tattoo_red"; - param_name[1] = "tattoo_green"; - param_name[2] = "tattoo_blue"; - break; + case TEX_HEAD_TATTOO: + case TEX_LOWER_TATTOO: + case TEX_UPPER_TATTOO: + param_name[0] = 1071; //"tattoo_red"; + param_name[1] = 1072; //"tattoo_green"; + param_name[2] = 1073; //"tattoo_blue"; + break; - default: - llassert(0); - return FALSE; + default: + llassert(0); + return FALSE; } return TRUE; @@ -8756,7 +8001,7 @@ BOOL LLVOAvatar::teToColorParams( ETextureIndex te, const char* param_name[3] ) void LLVOAvatar::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) { - const char* param_name[3]; + U32 param_name[3]; if( teToColorParams( te, param_name ) ) { setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake ); @@ -8768,7 +8013,7 @@ void LLVOAvatar::setClothesColor( ETextureIndex te, const LLColor4& new_color, B LLColor4 LLVOAvatar::getClothesColor( ETextureIndex te ) { LLColor4 color; - const char* param_name[3]; + U32 param_name[3]; if( teToColorParams( te, param_name ) ) { color.mV[VX] = getVisualParamWeight( param_name[0] ); @@ -8795,7 +8040,8 @@ void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const ++iter) { const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; - const LLViewerTexture* te_image = getTEImage(iter->first); + // TODO: MULTI-WEARABLE: handle multiple textures for self + const LLViewerTexture* te_image = getImage(iter->first,0); if( !te_image ) { llinfos << " " << texture_dict->mName << ": null ptr" << llendl; @@ -8823,62 +8069,6 @@ void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const } } -//----------------------------------------------------------------------------- -// updateAttachmentVisibility() -//----------------------------------------------------------------------------- -void LLVOAvatar::updateAttachmentVisibility(U32 camera_mode) -{ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getIsHUDAttachment()) - { - attachment->setAttachmentVisibility(TRUE); - } - else - { - switch (camera_mode) - { - case CAMERA_MODE_MOUSELOOK: - if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) - { - attachment->setAttachmentVisibility(TRUE); - } - else - { - attachment->setAttachmentVisibility(FALSE); - } - break; - default: - attachment->setAttachmentVisibility(TRUE); - break; - } - } - } -} - -void LLVOAvatar::setInvisible(BOOL newvalue) -{ - if (newvalue) - { - setCompositeUpdatesEnabled(FALSE); - for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) - { - setNewBakedTexture(mBakedTextureDatas[i].mTextureIndex, IMG_INVISIBLE); - } - gAgent.sendAgentSetAppearance(); - } - else - { - setCompositeUpdatesEnabled(TRUE); - invalidateAll(); - requestLayerSetUploads(); - gAgent.sendAgentSetAppearance(); - } -} - // Unlike most wearable functions, this works for both self and other. BOOL LLVOAvatar::isWearingWearableType( LLWearableType::EType type ) const { @@ -8896,51 +8086,24 @@ BOOL LLVOAvatar::isWearingWearableType( LLWearableType::EType type ) const } /* switch(type) - case WT_SHIRT: + case LLWearableType::WT_SHIRT: indicator_te = TEX_UPPER_SHIRT; */ for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); ++tex_iter) { - const LLVOAvatarDefines::ETextureIndex index = tex_iter->first; - const LLVOAvatarDictionary::TextureEntry *text_dict = tex_iter->second; - if (text_dict->mWearableType == type) + const LLVOAvatarDictionary::TextureEntry *texture_dict = tex_iter->second; + if (texture_dict->mWearableType == type) { - // If you're checking your own clothing, check the component texture - if (isSelf()) - { - if (isTextureDefined(index)) - { - return TRUE; - } - else - { - return FALSE; - } - } - // If you're checking another avatar's clothing, you don't have component textures. // Thus, you must check to see if the corresponding baked texture is defined. // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that // gets baked into a texture that always exists (upper or lower). - const std::string name = text_dict->mName; - for (LLVOAvatarDictionary::BakedTextures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - iter++) + if (texture_dict->mIsUsedByBakedTexture) { - const LLVOAvatarDictionary::BakedEntry *baked_dict = iter->second; - if (baked_dict->mName == name) - { - if (isTextureDefined(baked_dict->mTextureIndex)) - { - return TRUE; - } - else - { - return FALSE; - } - } + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + return isTextureDefined(LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); } return FALSE; } @@ -8948,49 +8111,6 @@ BOOL LLVOAvatar::isWearingWearableType( LLWearableType::EType type ) const return FALSE; } -//----------------------------------------------------------------------------- -// wearableUpdated(EWearableType type, BOOL upload_result) -// forces an update to any baked textures relevant to type. -// will force an upload of the resulting bake if the second parameter is TRUE -//----------------------------------------------------------------------------- -void LLVOAvatar::wearableUpdated(LLWearableType::EType type, BOOL upload_result) -{ - for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - ++baked_iter) - { - const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; - const LLVOAvatarDefines::EBakedTextureIndex index = baked_iter->first; - - if (baked_dict) - { - for (LLVOAvatarDefines::wearables_vec_t::const_iterator type_iter = baked_dict->mWearables.begin(); - type_iter != baked_dict->mWearables.end(); - ++type_iter) - { - const LLWearableType::EType comp_type = *type_iter; - if (comp_type == type) - { - if (mBakedTextureDatas[index].mTexLayerSet) - { - invalidateComposite(mBakedTextureDatas[index].mTexLayerSet, upload_result); - updateMeshTextures(); - } - break; - } - } - } - } - - // Physics type has no associated baked textures, but change of params needs to be sent to - // other avatars. - if (isSelf() && type == LLWearableType::WT_PHYSICS) - { - gAgent.sendAgentSetAppearance(); - } -} - - //----------------------------------------------------------------------------- // clampAttachmentPositions() //----------------------------------------------------------------------------- @@ -9079,22 +8199,32 @@ void LLVOAvatar::onFirstTEMessageReceived() { mFirstTEMessageReceived = TRUE; + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; + BOOL paused = FALSE ; + if(!isSelf()) + { + src_callback_list = &mCallbackTextureList ; + paused = mLoadedCallbacksPaused ; + } + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - const bool layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); + const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); // Use any baked textures that we have even if they haven't downloaded yet. // (That is, don't do a transition from unbaked to baked.) if (layer_baked) { - LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getTEImage( mBakedTextureDatas[i].mTextureIndex )); + LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ; mBakedTextureDatas[i].mLastTextureIndex = image->getID(); // If we have more than one texture for the other baked layers, we'll want to call this for them too. if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) { - image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), NULL); + image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), + src_callback_list, paused); } - image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), NULL ); + image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), + src_callback_list, paused ); } } @@ -9103,6 +8233,41 @@ void LLVOAvatar::onFirstTEMessageReceived() } } +//----------------------------------------------------------------------------- +// bool visualParamWeightsAreDefault() +//----------------------------------------------------------------------------- +bool LLVOAvatar::visualParamWeightsAreDefault() +{ + bool rtn = true; + + bool is_wearing_skirt = isWearingWearableType(LLWearableType::WT_SKIRT); + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + if (param->isTweakable()) + { + LLViewerVisualParam* vparam = dynamic_cast(param); + llassert(vparam); + bool is_skirt_param = vparam && + LLWearableType::WT_SKIRT == vparam->getWearableType(); + if (param->getWeight() != param->getDefaultWeight() && + // we have to not care whether skirt weights are default, if we're not actually wearing a skirt + (is_wearing_skirt || !is_skirt_param)) + { + //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl; + rtn = false; + break; + } + } + } + + //llinfos << "params are default ? " << int(rtn) << llendl; + + return rtn; +} + + //----------------------------------------------------------------------------- // processAvatarAppearance() //----------------------------------------------------------------------------- @@ -9187,13 +8352,13 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mMeshTexturesDirty = TRUE; gPipeline.markGLRebuild(this); + // ! BACKWARDS COMPATIBILITY ! + // Non-self avatars will no longer have component textures if (!isSelf()) { //releaseUnnecessaryTextures(); Commented out to ensure that users get the right client data -HgB } - updateMeshTextures(); // enables updates for laysets without baked textures. - mSupportsPhysics = false; // parse visual params @@ -9204,6 +8369,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) BOOL interp_params = FALSE; LLVisualParam* param = getFirstVisualParam(); + llassert(param); // if this ever fires, we should do the same as when num_blocks<=1 if (!param) { llwarns << "No visual params!" << llendl; @@ -9212,15 +8378,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) { for( S32 i = 0; i < num_blocks; i++ ) { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT { param = getNextVisualParam(); } - + if( !param ) { - llwarns << "Number of params in AvatarAppearance msg does not match number of params in avatar xml file for " << getFullname() << " (Too many)." << llendl; + // more visual params supplied than expected - just process what we know about break; } @@ -9295,23 +8460,31 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) updateSexDependentLayerSets( FALSE ); } } + + llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) ); } else { llwarns << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl; - // ehr, don't trust old shapes any longer -SG - if (sendAvatarTexturesRequest()) + const F32 LOADING_TIMEOUT_SECONDS = 60.f; + // this isn't really a problem if we already have a non-default shape + if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS) { // re-request appearance, hoping that it comes back with a shape next time - llinfos << "Re-requested AvatarAppearance for object: " << getID() << llendl; + llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl; + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); + mRuthTimer.reset(); + } + else + { + llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl; + // we don't really care. } } setCompositeUpdatesEnabled( TRUE ); - llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) ); - // If all of the avatars are completely baked, release the global image caches to conserve memory. LLVOAvatar::cullAvatarsByPixelArea(); @@ -9364,7 +8537,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture { if (!aux_src->getData()) { - llwarns << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; + llerrs << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; return; } @@ -9388,35 +8561,27 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture //llinfos << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << llendl; self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); maskData->mLastDiscardLevel = discard_level; */ - bool found_texture_id = false; + BOOL found_texture_id = false; for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); ++iter) { - const LLVOAvatarDictionary::TextureEntry *text_dict = iter->second; - if (text_dict->mIsUsedByBakedTexture) + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsUsedByBakedTexture) { const ETextureIndex texture_index = iter->first; - const LLViewerTexture *baked_img = self->getTEImage(texture_index); + const LLViewerTexture *baked_img = self->getImage(texture_index, 0); if (baked_img && id == baked_img->getID()) { - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - if (self->mBakedTextureDatas[baked_index].mTexLayerSet) + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + self->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1, baked_index); + maskData->mLastDiscardLevel = discard_level; + if (self->mBakedTextureDatas[baked_index].mMaskTexName) { - //llinfos << "onBakedTextureMasksLoaded for " << text_dict->mName << " " << id << " discard = " << discard_level << llendl; - self->mBakedTextureDatas[baked_index].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); - maskData->mLastDiscardLevel = discard_level; - if (self->mBakedTextureDatas[baked_index].mMaskTexName) - { - LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); - } - self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; - } - else - { - llwarns << "onBakedTextureMasksLoaded: no LayerSet for " << text_dict->mName << "." << llendl; + LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); } + self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; found_texture_id = true; break; } @@ -9493,7 +8658,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) mHeadMesh1.setTexture( head_baked ); */ for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - LLViewerTexture* image_baked = getTEImage( mBakedTextureDatas[i].mTextureIndex ); + LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); if (id == image_baked->getID()) { mBakedTextureDatas[i].mIsLoaded = true; @@ -9505,14 +8670,14 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) } if (mBakedTextureDatas[i].mTexLayerSet) { - mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); + //mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); } const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); local_tex_iter != baked_dict->mLocalTextures.end(); ++local_tex_iter) { - setLocalTexture(*local_tex_iter, LLViewerTextureManager::staticCastToFetchedTexture(getTEImage(*local_tex_iter)), TRUE); + if (isSelf()) setBakedReady(*local_tex_iter, TRUE); } // ! BACKWARDS COMPATIBILITY ! @@ -9682,144 +8847,6 @@ void LLVOAvatar::cullAvatarsByPixelArea() } } -const LLUUID& LLVOAvatar::grabLocalTexture(ETextureIndex index) -{ - if (canGrabLocalTexture(index)) - { - return getTEImage( index )->getID(); - } - return LLUUID::null; -} - -BOOL LLVOAvatar::canGrabLocalTexture(ETextureIndex index) -{ - // Check if the texture hasn't been baked yet. - if (!isTextureDefined(index)) - { - lldebugs << "getTEImage( " << (U32) index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl; - return FALSE; - } - - if (gAgent.isGodlike() && !gAgent.getAdminOverride()) - return TRUE; - - // Check permissions of textures that show up in the - // baked texture. We don't want people copying people's - // work via baked textures. - /* switch(index) - case TEX_EYES_BAKED: - textures.push_back(TEX_EYES_IRIS); */ - const LLVOAvatarDictionary::TextureEntry *text_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); - if (!text_dict->mIsUsedByBakedTexture) return FALSE; - - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index); - for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin(); - iter != baked_dict->mLocalTextures.end(); - iter++) - { - const ETextureIndex t_index = (*iter); - lldebugs << "Checking index " << (U32) t_index << llendl; - const LLUUID& texture_id = getTEImage( t_index )->getID(); - if (texture_id != IMG_DEFAULT_AVATAR) - { - // Search inventory for this texture. - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(texture_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - BOOL can_grab = FALSE; - lldebugs << "item count for asset " << texture_id << ": " << items.count() << llendl; - if (items.count()) - { - // search for full permissions version - for (S32 i = 0; i < items.count(); i++) - { - LLInventoryItem* itemp = items[i]; - LLPermissions item_permissions = itemp->getPermissions(); - if ( item_permissions.allowOperationBy( - PERM_MODIFY, gAgent.getID(), gAgent.getGroupID()) && - item_permissions.allowOperationBy( - PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && - item_permissions.allowOperationBy( - PERM_TRANSFER, gAgent.getID(), gAgent.getGroupID()) ) - { - can_grab = TRUE; - break; - } - } - } - if (!can_grab) return FALSE; - } - } - - return TRUE; -} - -void LLVOAvatar::dumpLocalTextures() -{ - llinfos << "Local Textures:" << llendl; - - /* ETextureIndex baked_equiv[] = { - TEX_UPPER_BAKED, - if (isTextureDefined(baked_equiv[i])) */ - for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - iter++) - { - const LLVOAvatarDictionary::TextureEntry *text_dict = iter->second; - if (!text_dict->mIsLocalTexture || !text_dict->mIsUsedByBakedTexture) - continue; - - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - const ETextureIndex baked_equiv = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex; - - const std::string &name = text_dict->mName; - const LocalTextureData &local_tex_data = mLocalTextureData[iter->first]; - if (isTextureDefined(baked_equiv)) - { -#if LL_RELEASE_FOR_DOWNLOAD - // End users don't get to trivially see avatar texture IDs, makes textures - // easier to steal. JC - llinfos << "LocTex " << name << ": Baked " << llendl; -#else - llinfos << "LocTex " << name << ": Baked " << getTEImage( baked_equiv )->getID() << llendl; -#endif - } - else if (local_tex_data.mImage.notNull()) - { - if( local_tex_data.mImage->getID() == IMG_DEFAULT_AVATAR ) - { - llinfos << "LocTex " << name << ": None" << llendl; - } - else - { - const LLViewerFetchedTexture* image = local_tex_data.mImage; - - llinfos << "LocTex " << name << ": " - << "Discard " << image->getDiscardLevel() << ", " - << "(" << image->getWidth() << ", " << image->getHeight() << ") " -#if !LL_RELEASE_FOR_DOWNLOAD - // End users don't get to trivially see avatar texture IDs, - // makes textures easier to steal - << image->getID() << " " -#endif - << "Priority: " << image->getDecodePriority() - << llendl; - } - } - else - { - llinfos << "LocTex " << name << ": No LLViewerTexture" << llendl; - } - } -} - void LLVOAvatar::startAppearanceAnimation(BOOL set_by_user, BOOL play_sound) { if(!mAppearanceAnimating) @@ -9855,6 +8882,7 @@ LLVOAvatar::LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo() deleteAndClear(mTexEyeColorInfo); std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); + std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer()); } //----------------------------------------------------------------------------- @@ -10276,13 +9304,56 @@ BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) return TRUE; } -// warning: order(N) not order(1) -S32 LLVOAvatar::getAttachmentCount() +//----------------------------------------------------------------------------- +// parseXmlDriverNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root) { - S32 count = mAttachmentPoints.size(); - return count; -} + LLXmlTreeNode* masks = root->getChildByName( "morph_masks" ); + if( !masks ) + { + return FALSE; + } + for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" ); + grand_child; + grand_child = masks->getNextNamedChild()) + { + LLVOAvatarMorphInfo* info = new LLVOAvatarMorphInfo(); + + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name"); + if (!grand_child->getFastAttributeString(name_string, info->mName)) + { + llwarns << "No name supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); + if (!grand_child->getFastAttributeString(region_string, info->mRegion)) + { + llwarns << "No region supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); + if (!grand_child->getFastAttributeString(layer_string, info->mLayer)) + { + llwarns << "No layer supplied for morph mask." << llendl; + delete info; + continue; + } + + // optional parameter. don't throw a warning if not present. + static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert"); + grand_child->getFastAttributeBOOL(invert_string, info->mInvert); + + mMorphMaskInfoList.push_back(info); + } + + return TRUE; +} //virtual void LLVOAvatar::updateRegion(LLViewerRegion *regionp) @@ -10304,21 +9375,6 @@ std::string LLVOAvatar::getFullname() const return name; } -LLTexLayerSet* LLVOAvatar::getLayerSet(ETextureIndex index) const -{ - /* switch(index) - case TEX_HEAD_BAKED: - case TEX_HEAD_BODYPAINT: - return mHeadLayerSet; */ - const LLVOAvatarDictionary::TextureEntry *text_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); - if (text_dict->mIsUsedByBakedTexture) - { - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - return mBakedTextureDatas[baked_index].mTexLayerSet; - } - return NULL; -} - LLHost LLVOAvatar::getObjectHost() const { LLViewerRegion* region = getRegion(); @@ -10558,7 +9614,7 @@ void LLVOAvatar::idleUpdateRenderCost() { const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; // TODO: MULTI-WEARABLE: handle multiple textures for self - const LLViewerTexture* te_image = getTEImage(iter->first);//getImage(iter->first,0); + const LLViewerTexture* te_image = getImage(iter->first,0); if (!te_image) continue; LLUUID image_id = te_image->getID(); @@ -10616,6 +9672,55 @@ const std::string LLVOAvatar::getBakedStatusForPrintout() const return line; } +//virtual +S32 LLVOAvatar::getTexImageSize() const +{ + return TEX_IMAGE_SIZE_OTHER; +} + +//----------------------------------------------------------------------------- +// Utility functions +//----------------------------------------------------------------------------- + +F32 calc_bouncy_animation(F32 x) +{ + return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f; +} + +//virtual +BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index ) const +{ + if (isIndexLocalTexture(te)) + { + return FALSE; + } + + return (getImage(te, index)->getID() != IMG_DEFAULT_AVATAR && + getImage(te, index)->getID() != IMG_DEFAULT); +} + +//virtual +BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const +{ + if (isIndexLocalTexture(type)) + { + return isTextureDefined(type, index); + } + else + { + // baked textures can use TE images directly + return ((isTextureDefined(type) || isSelf()) + && (getTEImage(type)->getID() != IMG_INVISIBLE + || LLDrawPoolAlpha::sShowDebugAlpha)); + } +} + +//virtual +BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const +{ + // non-self avatars don't have wearables + return FALSE; +} U32 calc_shame(LLVOVolume* volume, std::set &textures) { @@ -10720,12 +9825,3 @@ U32 calc_shame(LLVOVolume* volume, std::set &textures) return shame; } - -//----------------------------------------------------------------------------- -// Utility functions -//----------------------------------------------------------------------------- - -F32 calc_bouncy_animation(F32 x) -{ - return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f; -} diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 84bdda8fd..83197f3d8 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -39,20 +39,25 @@ #include #include +#include + #include "imageids.h" // IMG_INVISIBLE #include "llchat.h" #include "lldrawpoolalpha.h" #include "llviewerobject.h" #include "llcharacter.h" +#include "llcontrol.h" #include "llviewerjointmesh.h" #include "llviewerjointattachment.h" #include "llrendertarget.h" -#include "llwearable.h" #include "llvoavatardefines.h" +#include "lltexglobalcolor.h" +#include "lldriverparam.h" +#include "material_codes.h" // LL_MCODE_END + #include "emeraldboobutils.h" #include "llavatarname.h" - extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; extern const LLUUID ANIM_AGENT_PHYSICS_MOTION; @@ -70,9 +75,6 @@ class LLVoiceVisualizer; class LLHUDNameTag; class LLHUDEffectSpiral; class LLTexGlobalColor; -class LLTexGlobalColorInfo; -class LLTexLayerSetInfo; -class LLDriverParamInfo; class LLVOAvatarBoneInfo; class LLVOAvatarSkeletonInfo; @@ -82,12 +84,14 @@ class LLVOAvatarSkeletonInfo; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLVOAvatar : public LLViewerObject, - public LLCharacter + public LLCharacter, + public boost::signals2::trackable { public: friend class LLVOAvatarSelf; protected: struct LLVOAvatarXmlInfo; + struct LLMaskedMorph; /******************************************************************************** ** ** @@ -104,6 +108,7 @@ protected: virtual ~LLVOAvatar(); BOOL loadSkeletonNode(); BOOL loadMeshNodes(); + virtual BOOL loadLayersets(); /** Initialization ** ** @@ -177,6 +182,7 @@ public: virtual void requestStopMotion(LLMotion* motion); LLMotion* findMotion(const LLUUID& id) const; void startDefaultMotions(); + void dumpAnimationState(); virtual LLJoint* getJoint(const std::string &name); virtual LLJoint* getRootJoint() { return &mRoot; } @@ -239,8 +245,6 @@ public: void idleUpdateBelowWater(); void idleUpdateBoobEffect(); //Emerald - void updateAttachmentVisibility(U32 camera_mode); //Agent only - LLFrameTimer mIdleTimer; std::string getIdleTime(); @@ -276,10 +280,12 @@ public: //-------------------------------------------------------------------- public: BOOL isFullyLoaded() const; - //BOOL isReallyFullyLoaded(); - BOOL updateIsFullyLoaded(); + bool visualParamWeightsAreDefault(); protected: - bool sendAvatarTexturesRequest(); + virtual BOOL getIsCloud(); + BOOL updateIsFullyLoaded(); + BOOL processFullyLoadedChange(bool loading); + void updateRuthTimer(bool loading); F32 calcMorphAmount(); private: @@ -290,6 +296,8 @@ private: S32 mVisualComplexity; LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; +protected: + LLFrameTimer mInvisibleTimer; /** State ** ** @@ -405,6 +413,14 @@ private: S32 mUpdatePeriod; S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. + //-------------------------------------------------------------------- + // Morph masks + //-------------------------------------------------------------------- +public: + BOOL morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); + void addMaskedMorph(LLVOAvatarDefines::EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer); + void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); + //-------------------------------------------------------------------- // Visibility //-------------------------------------------------------------------- @@ -448,6 +464,8 @@ private: F32 mImpostorDistance; F32 mImpostorPixelArea; LLVector3 mLastAnimExtents[2]; + + LLCachedControl mRenderUnloadedAvatar; //-------------------------------------------------------------------- // Wind rippling in clothes @@ -480,6 +498,15 @@ public: private: static S32 sFreezeCounter; + //-------------------------------------------------------------------- + // Constants + //-------------------------------------------------------------------- +public: + virtual LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLViewerTexture::BOOST_AVATAR; } + virtual LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_BAKED; } + virtual S32 getTexImageSize() const; + virtual S32 getTexImageArea() const { return getTexImageSize()*getTexImageSize(); } + /** Rendering ** ** *******************************************************************************/ @@ -493,8 +520,9 @@ private: // Loading status //-------------------------------------------------------------------- public: - BOOL isTextureDefined(U8 te) const; - BOOL isTextureVisible(U8 te) const; + virtual BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const; protected: BOOL isFullyBaked(); @@ -512,6 +540,7 @@ protected: virtual void removeMissingBakedTextures(); void useBakedTexture(const LLUUID& id); + typedef std::deque morph_list_t; struct BakedTextureData { LLUUID mLastTextureIndex; @@ -522,15 +551,35 @@ protected: U32 mMaskTexName; // Stores pointers to the joint meshes that this baked texture deals with std::vector< LLViewerJointMesh * > mMeshes; // std::vector mJoints[i]->mMeshParts + morph_list_t mMaskedMorphs; }; typedef std::vector bakedtexturedata_vec_t; bakedtexturedata_vec_t mBakedTextureDatas; + LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; + BOOL mLoadedCallbacksPaused; + +public: + const BakedTextureData& getBakedTextureData(LLVOAvatarDefines::ETextureIndex idx) const {return mBakedTextureDatas[idx];} //-------------------------------------------------------------------- // Local Textures //-------------------------------------------------------------------- protected: - void setLocalTexture(LLVOAvatarDefines::ETextureIndex i, LLViewerFetchedTexture* tex, BOOL baked_version_exits); - void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex i, LLViewerTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked); + virtual void setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index = 0); + virtual void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex type, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked, U32 index = 0); + // MULTI-WEARABLE: make self-only? + virtual void setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index = 0); + + //-------------------------------------------------------------------- + // Texture accessors + //-------------------------------------------------------------------- +private: + virtual void setImage(const U8 te, LLViewerTexture *imagep, const U32 index); + virtual LLViewerTexture* getImage(const U8 te, const U32 index) const; + + virtual const LLTextureEntry* getTexEntry(const U8 te_num) const; + virtual void setTexEntry(const U8 index, const LLTextureEntry &te); + + void checkTextureLoading() ; //-------------------------------------------------------------------- // Layers //-------------------------------------------------------------------- @@ -544,6 +593,9 @@ protected: public: virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); virtual void invalidateAll(); + virtual void setCompositeUpdatesEnabled(bool b) {} + virtual void setCompositeUpdatesEnabled(U32 index, bool b) {} + virtual bool isCompositeUpdateEnabled(U32 index) { return false; } //-------------------------------------------------------------------- // Static texture/mesh/baked dictionary @@ -565,74 +617,7 @@ public: private: BOOL mFirstTEMessageReceived; BOOL mFirstAppearanceMessageReceived; - - -//Most this stuff is Agent only - - //-------------------------------------------------------------------- - // Textures and Layers - //-------------------------------------------------------------------- -protected: - void requestLayerSetUpdate(LLVOAvatarDefines::ETextureIndex i); - - - LLTexLayerSet* getLayerSet(LLVOAvatarDefines::ETextureIndex index) const; - S32 getLocalDiscardLevel(LLVOAvatarDefines::ETextureIndex index); - - //-------------------------------------------------------------------- - // Other public functions - //-------------------------------------------------------------------- -public: - static void dumpTotalLocalTextureByteCount(); -protected: - void getLocalTextureByteCount( S32* gl_byte_count ); - -public: - void dumpLocalTextures(); - const LLUUID& grabLocalTexture(LLVOAvatarDefines::ETextureIndex index); - BOOL canGrabLocalTexture(LLVOAvatarDefines::ETextureIndex index); - - void setCompositeUpdatesEnabled(BOOL b); - - void setNameFromChat(const std::string &text); - void clearNameFromChat(); - -public: - - //-------------------------------------------------------------------- - // texture compositing (used only by the LLTexLayer series of classes) - //-------------------------------------------------------------------- -public: - BOOL isLocalTextureDataAvailable( const LLTexLayerSet* layerset ); - BOOL isLocalTextureDataFinal( const LLTexLayerSet* layerset ); - LLVOAvatarDefines::ETextureIndex getBakedTE( LLTexLayerSet* layerset ); - void updateComposites(); - //BOOL getLocalTextureRaw( LLVOAvatarDefines::ETextureIndex index, LLImageRaw* image_raw_pp ); - BOOL getLocalTextureGL( LLVOAvatarDefines::ETextureIndex index, LLViewerTexture** image_gl_pp ); - const LLUUID& getLocalTextureID( LLVOAvatarDefines::ETextureIndex index ); - LLGLuint getScratchTexName( LLGLenum format, U32* texture_bytes ); - BOOL bindScratchTexture( LLGLenum format ); - void forceBakeAllTextures(bool slam_for_debug = false); - static void processRebakeAvatarTextures(LLMessageSystem* msg, void**); - void setNewBakedTexture( LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid ); - void setCachedBakedTexture( LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid ); - void requestLayerSetUploads(); - void requestLayerSetUpload(LLVOAvatarDefines::EBakedTextureIndex i); - bool hasPendingBakedUploads(); - static void onLocalTextureLoaded( BOOL succcess, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); - static void onChangeSelfInvisible(BOOL newvalue); - void setInvisible(BOOL newvalue); - - void wearableUpdated(LLWearableType::EType type, BOOL upload_result = TRUE); - - //-------------------------------------------------------------------- - // texture compositing - //-------------------------------------------------------------------- -public: - void setLocTexTE( U8 te, LLViewerTexture* image, BOOL set_by_user ); - void setupComposites(); - /** Textures ** ** *******************************************************************************/ @@ -702,16 +687,16 @@ public: // Clothing colors (convenience functions to access visual parameters) //-------------------------------------------------------------------- public: - void setClothesColor( LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL set_by_user ); + void setClothesColor(LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); LLColor4 getClothesColor(LLVOAvatarDefines::ETextureIndex te); - static BOOL teToColorParams( LLVOAvatarDefines::ETextureIndex te, const char* param_name[3] ); + static BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, U32 *param_name); //-------------------------------------------------------------------- // Global colors //-------------------------------------------------------------------- public: LLColor4 getGlobalColor(const std::string& color_name ) const; - void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL set_by_user ); + void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake); private: LLTexGlobalColor* mTexSkinColor; LLTexGlobalColor* mTexHairColor; @@ -743,17 +728,17 @@ public: **/ public: - BOOL isWearingWearableType( LLWearableType::EType type ) const; + virtual BOOL isWearingWearableType(LLWearableType::EType type ) const; //-------------------------------------------------------------------- // Attachments //-------------------------------------------------------------------- public: void clampAttachmentPositions(); - BOOL attachObject(LLViewerObject *viewer_object); - BOOL detachObject(LLViewerObject *viewer_object); + virtual const LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object); + virtual BOOL detachObject(LLViewerObject *viewer_object); void cleanupAttachedMesh( LLViewerObject* pVO ); - static LLVOAvatar* findAvatarFromAttachment( LLViewerObject* obj ); + static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj); protected: // [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i LLViewerJointAttachment* getTargetAttachmentPoint(const LLViewerObject* viewer_object) const; @@ -779,6 +764,7 @@ public: void rebuildHUD(); void resetHUDAttachments(); BOOL canAttachMoreObjects() const; + BOOL canAttachMoreObjects(U32 n) const; protected: U32 getNumAttachments() const; // O(N), not O(1) @@ -786,7 +772,6 @@ protected: // Old/nonstandard/Agent-only functions //-------------------------------------------------------------------- public: - static BOOL detachAttachmentIntoInventory(const LLUUID& item_id); BOOL isWearingAttachment( const LLUUID& inv_item_id ); // testzone attachpt BOOL isWearingUnsupportedAttachment( const LLUUID& inv_item_id ); @@ -839,6 +824,8 @@ public: // Chat //-------------------------------------------------------------------- public: + void setNameFromChat(const std::string &text); + void clearNameFromChat(); void addChat(const LLChat& chat); void clearChat(); void startTyping() { mTyping = TRUE; mTypingTimer.reset(); mIdleTimer.reset();} @@ -1066,7 +1053,6 @@ private: //-------------------------------------------------------------------- public: static void dumpArchetypeXML(void*); - static void dumpScratchTextureByteCount(); //Agent only static void dumpBakedStatus(); const std::string getBakedStatusForPrintout() const; void dumpAvatarTEs(const std::string& context) const; @@ -1079,13 +1065,20 @@ protected: S32 getUnbakedPixelAreaRank(); BOOL mHasGrey; private: - LLUUID mSavedTE[ LLVOAvatarDefines::TEX_NUM_INDICES ]; - BOOL mHasBakedHair; F32 mMinPixelArea; F32 mMaxPixelArea; F32 mAdjustedPixelArea; std::string mDebugText; + //-------------------------------------------------------------------- + // Avatar Rez Metrics + //-------------------------------------------------------------------- +public: + F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); } +protected: + LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez + LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. + /** Diagnostics ** ** *******************************************************************************/ @@ -1107,6 +1100,7 @@ protected: // Shared with LLVOAvatarSelf BOOL parseXmlColorNodes(LLXmlTreeNode* root); BOOL parseXmlLayerNodes(LLXmlTreeNode* root); BOOL parseXmlDriverNodes(LLXmlTreeNode* root); + BOOL parseXmlMorphNodes(LLXmlTreeNode* root); struct LLVOAvatarMeshInfo { @@ -1166,26 +1160,39 @@ protected: // Shared with LLVOAvatarSelf typedef std::vector driver_info_list_t; driver_info_list_t mDriverInfoList; + + struct LLVOAvatarMorphInfo + { + LLVOAvatarMorphInfo() + : mInvert(FALSE) {} + std::string mName; + std::string mRegion; + std::string mLayer; + BOOL mInvert; + }; + + typedef std::vector morph_info_list_t; + morph_info_list_t mMorphMaskInfoList; }; -public: //Public until pulled out of LLTexLayer struct LLMaskedMorph { - LLMaskedMorph(LLPolyMorphTarget *morph_target, BOOL invert) : + LLMaskedMorph(LLPolyMorphTarget *morph_target, BOOL invert, std::string layer) : mMorphTarget(morph_target), - mInvert(invert) + mInvert(invert), + mLayer(layer) { morph_target->addPendingMorphMask(); } LLPolyMorphTarget *mMorphTarget; BOOL mInvert; + std::string mLayer; }; /** Support classes ** ** *******************************************************************************/ - // public: @@ -1196,61 +1203,11 @@ public: LLUUID mFocusObject; LLVector3d mFocusVector; //void resetIdleTime(); -// -private: - //----------------------------------------------------------------------------------------------- - // Per-avatar information about texture data. - // To-do: Move this to private implementation class - //----------------------------------------------------------------------------------------------- - - struct LocalTextureData - { - LocalTextureData() : mIsBakedReady(false), mDiscard(MAX_DISCARD_LEVEL+1), mImage(NULL) - {} - LLPointer mImage; - bool mIsBakedReady; - S32 mDiscard; - }; - typedef std::map localtexture_map_t; - localtexture_map_t mLocalTextureData; - - - //-------------------------------------------------------------------- - // Private member variables. - //-------------------------------------------------------------------- - // Scratch textures used for compositing - static LLMap< LLGLenum, LLGLuint*> sScratchTexNames; - static LLMap< LLGLenum, F32*> sScratchTexLastBindTime; - static S32 sScratchTexBytes; - static LLSD sClientResolutionList; - - bool isUnknownClient(); - static void resolveClient(LLColor4& avatar_name_color, std::string& client, LLVOAvatar* avatar); - friend class LLFloaterAvatarList; - - - U64 mLastRegionHandle; - LLFrameTimer mRegionCrossingTimer; - S32 mRegionCrossingCount; - - static bool sDoProperArc; -}; - -//----------------------------------------------------------------------------------------------- -// Inlines -//----------------------------------------------------------------------------------------------- -inline BOOL LLVOAvatar::isTextureDefined(U8 te) const -{ - return (getTEImage(te)->getID() != IMG_DEFAULT_AVATAR && getTEImage(te)->getID() != IMG_DEFAULT); -} - -inline BOOL LLVOAvatar::isTextureVisible(U8 te) const -{ - return ((isTextureDefined(te) || isSelf()) - && (getTEImage(te)->getID() != IMG_INVISIBLE - || LLDrawPoolAlpha::sShowDebugAlpha)); -} +// +}; // LLVOAvatar +extern const F32 SELF_ADDITIONAL_PRI; +extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; #endif // LL_VO_AVATAR_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index ce1077c9c..15aac7dd5 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -23,6 +23,13 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ + +#if LL_MSVC +// disable warning about boost::lexical_cast returning uninitialized data +// when it fails to parse the string +#pragma warning (disable:4701) +#endif + #include "llviewerprecompiledheaders.h" #include "llvoavatarself.h" @@ -35,11 +42,13 @@ #include "llagentwearables.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" +#include "llinventoryfunctions.h" #include "llnotificationsutil.h" #include "llselectmgr.h" #include "lltoolgrab.h" // for needsRenderBeam #include "lltoolmgr.h" // for needsRenderBeam #include "lltoolmorph.h" +#include "lltrans.h" #include "llviewercamera.h" #include "llviewercontrol.h" #include "llviewermedia.h" @@ -47,8 +56,17 @@ #include "llviewerobjectlist.h" #include "llviewerstats.h" #include "llviewerregion.h" +#include "llappearancemgr.h" #include "llmeshrepository.h" #include "llvovolume.h" + +#if LL_MSVC +// disable boost::lexical_cast warning +#pragma warning (disable:4702) +#endif + +#include + LLVOAvatarSelf *gAgentAvatarp = NULL; BOOL isAgentAvatarValid() { @@ -57,6 +75,50 @@ BOOL isAgentAvatarValid() (!gAgentAvatarp->isDead())); } +using namespace LLVOAvatarDefines; + +/********************************************************************************* + ** ** + ** Begin private LLVOAvatarSelf Support classes + ** + **/ + +struct LocalTextureData +{ + LocalTextureData() : + mIsBakedReady(false), + mDiscard(MAX_DISCARD_LEVEL+1), + mImage(NULL), + mWearableID(IMG_DEFAULT_AVATAR), + mTexEntry(NULL) + {} + LLPointer mImage; + bool mIsBakedReady; + S32 mDiscard; + LLUUID mWearableID; // UUID of the wearable that this texture belongs to, not of the image itself + LLTextureEntry *mTexEntry; +}; + +//----------------------------------------------------------------------------- +// Callback data +//----------------------------------------------------------------------------- + + +/** + ** + ** End LLVOAvatarSelf Support classes + ** ** + *********************************************************************************/ + + +//----------------------------------------------------------------------------- +// Static Data +//----------------------------------------------------------------------------- +S32 LLVOAvatarSelf::sScratchTexBytes = 0; +LLMap< LLGLenum, LLGLuint*> LLVOAvatarSelf::sScratchTexNames; +LLMap< LLGLenum, F32*> LLVOAvatarSelf::sScratchTexLastBindTime; + + /********************************************************************************* ** ** ** Begin LLVOAvatarSelf Constructor routines @@ -89,7 +151,7 @@ void LLVOAvatarSelf::initInstance() LLVOAvatar::initInstance(); llinfos << "Self avatar object created. Starting timer." << llendl; - /*mDebugSelfLoadTimer.reset(); + mDebugSelfLoadTimer.reset(); // clear all times to -1 for debugging for (U32 i =0; i < LLVOAvatarDefines::TEX_NUM_INDICES; ++i) { @@ -103,7 +165,7 @@ void LLVOAvatarSelf::initInstance() { mDebugBakedTextureTimes[i][0] = -1.0f; mDebugBakedTextureTimes[i][1] = -1.0f; - }*/ + } status &= buildMenus(); if (!status) @@ -123,6 +185,21 @@ void LLVOAvatarSelf::markDead() /*virtual*/ BOOL LLVOAvatarSelf::loadAvatar() { BOOL success = LLVOAvatar::loadAvatar(); + + // set all parameters sotred directly in the avatar to have + // the isSelfParam to be TRUE - this is used to prevent + // them from being animated or trigger accidental rebakes + // when we copy params from the wearable to the base avatar. + for (LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) getNextVisualParam()) + { + if (param->getWearableType() != LLWearableType::WT_INVALID) + { + param->setIsDummy(TRUE); + } + } + return success; } @@ -291,6 +368,11 @@ BOOL LLVOAvatarSelf::buildMenus() for (S32 pass = 0; pass < 2; pass++) { + // *TODO: Skinning - gAttachSubMenu is an awful, awful hack + if (!gAttachSubMenu) + { + break; + } for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -391,6 +473,78 @@ LLVOAvatarSelf::~LLVOAvatarSelf() { cleanup(); } + +/** + ** + ** End LLVOAvatarSelf Constructor routines + ** ** + *********************************************************************************/ + +//virtual +BOOL LLVOAvatarSelf::loadLayersets() +{ + BOOL success = TRUE; + for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator iter = sAvatarXmlInfo->mLayerInfoList.begin(); + iter != sAvatarXmlInfo->mLayerInfoList.end(); + ++iter) + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + const LLTexLayerSetInfo *info = *iter; + LLTexLayerSet* layer_set = new LLTexLayerSet( this ); + + if (!layer_set->setInfo(info)) + { + stop_glerror(); + delete layer_set; + llwarns << "avatar file: layer_set->parseData() failed" << llendl; + return FALSE; + } + + // scan baked textures and associate the layerset with the appropriate one + EBakedTextureIndex baked_index = BAKED_NUM_INDICES; + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + ++baked_iter) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + if (layer_set->isBodyRegion(baked_dict->mName)) + { + baked_index = baked_iter->first; + // ensure both structures are aware of each other + mBakedTextureDatas[baked_index].mTexLayerSet = layer_set; + layer_set->setBakedTexIndex(baked_index); + break; + } + } + // if no baked texture was found, warn and cleanup + if (baked_index == BAKED_NUM_INDICES) + { + llwarns << " has invalid body_region attribute" << llendl; + delete layer_set; + return FALSE; + } + + // scan morph masks and let any affected layers know they have an associated morph + for (LLVOAvatar::morph_list_t::const_iterator morph_iter = mBakedTextureDatas[baked_index].mMaskedMorphs.begin(); + morph_iter != mBakedTextureDatas[baked_index].mMaskedMorphs.end(); + ++morph_iter) + { + LLMaskedMorph *morph = *morph_iter; + LLTexLayerInterface* layer = layer_set->findLayerByName(morph->mLayer); + if (layer) + { + layer->setHasMorph(TRUE); + } + else + { + llwarns << "Could not find layer named " << morph->mLayer << " to set morph flag" << llendl; + success = FALSE; + } + } + } + return success; +} +// virtual BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent) { LLMemType mt(LLMemType::MTYPE_AVATAR); @@ -445,6 +599,86 @@ void LLVOAvatarSelf::resetJointPositions( void ) { return LLVOAvatar::resetJointPositions(); } +// virtual +BOOL LLVOAvatarSelf::setVisualParamWeight(LLVisualParam *which_param, F32 weight, BOOL upload_bake ) +{ + if (!which_param) + { + return FALSE; + } + LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID()); + return setParamWeight(param,weight,upload_bake); +} + +// virtual +BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake ) +{ + if (!param_name) + { + return FALSE; + } + LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name); + return setParamWeight(param,weight,upload_bake); +} + +// virtual +BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake ) +{ + LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index); + return setParamWeight(param,weight,upload_bake); +} + +BOOL LLVOAvatarSelf::setParamWeight(LLViewerVisualParam *param, F32 weight, BOOL upload_bake ) +{ + if (!param) + { + return FALSE; + } + + if (param->getCrossWearable()) + { + LLWearableType::EType type = (LLWearableType::EType)param->getWearableType(); + U32 size = gAgentWearables.getWearableCount(type); + for (U32 count = 0; count < size; ++count) + { + LLWearable *wearable = gAgentWearables.getWearable(type,count); + if (wearable) + { + wearable->setVisualParamWeight(param->getID(), weight, upload_bake); + } + } + } + + return LLCharacter::setVisualParamWeight(param,weight,upload_bake); +} + +/*virtual*/ +void LLVOAvatarSelf::updateVisualParams() +{ + LLVOAvatar::updateVisualParams(); +} + +/*virtual*/ +void LLVOAvatarSelf::idleUpdateAppearanceAnimation() +{ + // Animate all top-level wearable visual parameters + gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE); + + // apply wearable visual params to avatar + for (U32 type = 0; type < LLWearableType::WT_COUNT; type++) + { + LLWearable *wearable = gAgentWearables.getTopWearable((LLWearableType::EType)type); + if (wearable) + { + wearable->writeToAvatar(); + } + } + + //allow avatar to process updates + LLVOAvatar::idleUpdateAppearanceAnimation(); + +} + // virtual void LLVOAvatarSelf::requestStopMotion(LLMotion* motion) { @@ -469,6 +703,29 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) object->mFlags &= ~FLAGS_ANIM_SOURCE; } } + +void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index) +{ + if (te >= TEX_NUM_INDICES) + { + llassert(0); + return; + } + + if (getTEImage(te)->getID() == image->getID()) + { + return; + } + + if (isIndexBakedTexture((ETextureIndex)te)) + { + llassert(0); + return; + } + + setTEImage(te, image); +} + //virtual void LLVOAvatarSelf::removeMissingBakedTextures() { @@ -494,8 +751,9 @@ void LLVOAvatarSelf::removeMissingBakedTextures() if (removed) { - for(U32 i = 0; i < mBakedTextureDatas.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE); invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, FALSE); } updateMeshTextures(); @@ -652,6 +910,1594 @@ void LLVOAvatarSelf::restoreMeshData() // force mesh update as LOD might not have changed to trigger this gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); } + + + +//----------------------------------------------------------------------------- +// updateAttachmentVisibility() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) +{ + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment()) + { + attachment->setAttachmentVisibility(TRUE); + } + else + { + switch (camera_mode) + { + case CAMERA_MODE_MOUSELOOK: + if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) + { + attachment->setAttachmentVisibility(TRUE); + } + else + { + attachment->setAttachmentVisibility(FALSE); + } + break; + default: + attachment->setAttachmentVisibility(TRUE); + break; + } + } + } +} + +/*virtual*/ BOOL LLVOAvatarSelf::isWearingWearableType(LLWearableType::EType type ) const +{ + return gAgentWearables.getWearableCount(type) > 0; +} + +//----------------------------------------------------------------------------- +// updatedWearable( LLWearableType::EType type ) +// forces an update to any baked textures relevant to type. +// will force an upload of the resulting bake if the second parameter is TRUE +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_result ) +{ + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + ++baked_iter) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + const LLVOAvatarDefines::EBakedTextureIndex index = baked_iter->first; + + if (baked_dict) + { + for (LLVOAvatarDefines::wearables_vec_t::const_iterator type_iter = baked_dict->mWearables.begin(); + type_iter != baked_dict->mWearables.end(); + ++type_iter) + { + const LLWearableType::EType comp_type = *type_iter; + if (comp_type == type) + { + if (mBakedTextureDatas[index].mTexLayerSet) + { + mBakedTextureDatas[index].mTexLayerSet->setUpdatesEnabled(true); + invalidateComposite(mBakedTextureDatas[index].mTexLayerSet, upload_result); + } + break; + } + } + } + } + + // Physics type has no associated baked textures, but change of params needs to be sent to + // other avatars. + if (type == LLWearableType::WT_PHYSICS) + { + gAgent.sendAgentSetAppearance(); + } +} + +//----------------------------------------------------------------------------- +// isWearingAttachment() +//----------------------------------------------------------------------------- +BOOL LLVOAvatarSelf::isWearingAttachment(const LLUUID& inv_item_id) const +{ + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment* attachment = iter->second; + if (attachment->getAttachedObject(base_inv_item_id)) + { + return TRUE; + } + } + return FALSE; +} + +//----------------------------------------------------------------------------- +BOOL LLVOAvatarSelf::attachmentWasRequested(const LLUUID& inv_item_id) const +{ + const F32 REQUEST_EXPIRATION_SECONDS = 5.0; // any request older than this is ignored/removed. + std::map::iterator it = mAttachmentRequests.find(inv_item_id); + if (it != mAttachmentRequests.end()) + { + const LLTimer& request_time = it->second; + F32 request_time_elapsed = request_time.getElapsedTimeF32(); + if (request_time_elapsed > REQUEST_EXPIRATION_SECONDS) + { + mAttachmentRequests.erase(it); + return FALSE; + } + else + { + return TRUE; + } + } + else + { + return FALSE; + } +} + +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::addAttachmentRequest(const LLUUID& inv_item_id) +{ + LLTimer current_time; + mAttachmentRequests[inv_item_id] = current_time; +} + +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::removeAttachmentRequest(const LLUUID& inv_item_id) +{ + mAttachmentRequests.erase(inv_item_id); +} + +//----------------------------------------------------------------------------- +// getWornAttachment() +//----------------------------------------------------------------------------- +LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id) +{ + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (LLViewerObject *attached_object = attachment->getAttachedObject(base_inv_item_id)) + { + return attached_object; + } + } + return NULL; +} + +const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id) const +{ + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment* attachment = iter->second; + if (attachment->getAttachedObject(base_inv_item_id)) + { + return attachment->getName(); + } + } + + return LLStringUtil::null; +} + +//virtual +const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_object) +{ + const LLViewerJointAttachment *attachment = LLVOAvatar::attachObject(viewer_object); + if (!attachment) + { + return 0; + } + + updateAttachmentVisibility(gAgentCamera.getCameraMode()); + + // Then make sure the inventory is in sync with the avatar. + + // Should just be the last object added + if (attachment->isObjectAttached(viewer_object)) + { + const LLUUID& attachment_id = viewer_object->getAttachmentItemID(); + LLAppearanceMgr::instance().registerAttachment(attachment_id); + // Clear any pending requests once the attachment arrives. + removeAttachmentRequest(attachment_id); + updateLODRiggedAttachments(); + } + + return attachment; +} + +//virtual +BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) +{ + const LLUUID attachment_id = viewer_object->getAttachmentItemID(); + if ( LLVOAvatar::detachObject(viewer_object) ) + { + LLVOAvatar::cleanupAttachedMesh( viewer_object ); + + // the simulator should automatically handle permission revocation + + stopMotionFromSource(attachment_id); + LLFollowCamMgr::setCameraActive(viewer_object->getID(), FALSE); + + LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); + ++iter) + { + LLViewerObject* child_objectp = *iter; + // the simulator should automatically handle + // permissions revocation + + stopMotionFromSource(child_objectp->getID()); + LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE); + } + + // Make sure the inventory is in sync with the avatar. + + // Update COF contents, don't trigger appearance update. + if (!isAgentAvatarValid()) + { + llinfos << "removeItemLinks skipped, avatar is under destruction" << llendl; + } + else + { + LLAppearanceMgr::instance().unregisterAttachment(attachment_id); + } + + return TRUE; + } + return FALSE; +} + +// static +BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id) +{ + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); + gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); + + // This object might have been selected, so let the selection manager know it's gone now + LLViewerObject *found_obj = gObjectList.findObject(item_id); + if (found_obj) + { + LLSelectMgr::getInstance()->remove(found_obj); + } + + // Error checking in case this object was attached to an invalid point + // In that case, just remove the item from COF preemptively since detach + // will fail. + if (isAgentAvatarValid()) + { + const LLViewerObject *attached_obj = gAgentAvatarp->getWornAttachment(item_id); + if (!attached_obj) + { + LLAppearanceMgr::instance().removeCOFItemLinks(item_id, false); + } + } + return TRUE; + } + return FALSE; +} + +U32 LLVOAvatarSelf::getNumWearables(LLVOAvatarDefines::ETextureIndex i) const +{ + LLWearableType::EType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i); + return gAgentWearables.getWearableCount(type); +} + +// virtual +void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +{ + + const LLUUID& src_id = src_vi->getID(); + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + ETextureIndex index = data->mIndex; + if (!isIndexLocalTexture(index)) return; + + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(index, 0); + + // fix for EXT-268. Preventing using of NULL pointer + if(NULL == local_tex_obj) + { + LL_WARNS("TAG") << "There is no Local Texture Object with index: " << index + << ", final: " << final + << LL_ENDL; + return; + } + if (success) + { + if (!local_tex_obj->getBakedReady() && + local_tex_obj->getImage() != NULL && + (local_tex_obj->getID() == src_id) && + discard_level < local_tex_obj->getDiscard()) + { + local_tex_obj->setDiscard(discard_level); + if (isUsingBakedTextures()) + { + requestLayerSetUpdate(index); + } + else + { + LLVisualParamHint::requestHintUpdates(); + } + updateMeshTextures(); + } + } + else if (final) + { + // Failed: asset is missing + if (!local_tex_obj->getBakedReady() && + local_tex_obj->getImage() != NULL && + local_tex_obj->getImage()->getID() == src_id) + { + local_tex_obj->setDiscard(0); + requestLayerSetUpdate(index); + updateMeshTextures(); + } + } +} + +// virtual +BOOL LLVOAvatarSelf::getLocalTextureGL(ETextureIndex type, LLViewerTexture** tex_pp, U32 index) const +{ + *tex_pp = NULL; + + if (!isIndexLocalTexture(type)) return FALSE; + if (getLocalTextureID(type, index) == IMG_DEFAULT_AVATAR) return TRUE; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (!local_tex_obj) + { + return FALSE; + } + *tex_pp = local_tex_obj->getImage(); + return TRUE; +} + +LLViewerFetchedTexture* LLVOAvatarSelf::getLocalTextureGL(LLVOAvatarDefines::ETextureIndex type, U32 index) const +{ + if (!isIndexLocalTexture(type)) + { + return NULL; + } + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (!local_tex_obj) + { + return NULL; + } + if (local_tex_obj->getID() == IMG_DEFAULT_AVATAR) + { + return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); + } + return local_tex_obj->getImage(); +} + +const LLUUID& LLVOAvatarSelf::getLocalTextureID(ETextureIndex type, U32 index) const +{ + if (!isIndexLocalTexture(type)) return IMG_DEFAULT_AVATAR; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (local_tex_obj && local_tex_obj->getImage() != NULL) + { + return local_tex_obj->getImage()->getID(); + } + return IMG_DEFAULT_AVATAR; +} + + +//----------------------------------------------------------------------------- +// isLocalTextureDataAvailable() +// Returns true if at least the lowest quality discard level exists for every texture +// in the layerset. +//----------------------------------------------------------------------------- +BOOL LLVOAvatarSelf::isLocalTextureDataAvailable(const LLTexLayerSet* layerset) const +{ + /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) + return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */ + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + ++baked_iter) + { + const EBakedTextureIndex baked_index = baked_iter->first; + if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet) + { + BOOL ret = true; + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + ret &= (getLocalDiscardLevel(tex_index, wearable_index) >= 0); + } + } + return ret; + } + } + llassert(0); + return FALSE; +} + +//----------------------------------------------------------------------------- +// virtual +// isLocalTextureDataFinal() +// Returns true if the highest quality discard level exists for every texture +// in the layerset. +//----------------------------------------------------------------------------- +BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLTexLayerSet* layerset) const +{ + const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels. + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (layerset == mBakedTextureDatas[i].mTexLayerSet) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + if (getLocalDiscardLevel(*local_tex_iter, wearable_index) > (S32)(desired_tex_discard_level)) + { + return FALSE; + } + } + } + return TRUE; + } + } + llassert(0); + return FALSE; +} + +BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const +{ + const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + if (getLocalDiscardLevel(*local_tex_iter, wearable_index) > (S32)(desired_tex_discard_level)) + { + return FALSE; + } + } + } + } + return TRUE; +} + +BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLVOAvatarDefines::EBakedTextureIndex index) const +{ + const LLTexLayerSet *layerset = mBakedTextureDatas[index].mTexLayerSet; + if (!layerset) return FALSE; + const LLTexLayerSetBuffer *layerset_buffer = layerset->getComposite(); + if (!layerset_buffer) return FALSE; + return !layerset_buffer->uploadNeeded(); +} + +BOOL LLVOAvatarSelf::isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index) const +{ + LLUUID id; + BOOL isDefined = TRUE; + if (isIndexLocalTexture(type)) + { + const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(type); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + if (index >= wearable_count) + { + // invalid index passed in. check all textures of a given type + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + id = getLocalTextureID(type, wearable_index); + isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT); + } + } + else + { + id = getLocalTextureID(type, index); + isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT); + } + } + else + { + id = getTEImage(type)->getID(); + isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT); + } + + return isDefined; +} + +//virtual +BOOL LLVOAvatarSelf::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const +{ + if (isIndexBakedTexture(type)) + { + return LLVOAvatar::isTextureVisible(type, (U32)0); + } + + LLUUID tex_id = getLocalTextureID(type,index); + return (tex_id != IMG_INVISIBLE) + || (LLDrawPoolAlpha::sShowDebugAlpha); +} + +//virtual +BOOL LLVOAvatarSelf::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const +{ + if (isIndexBakedTexture(type)) + { + return LLVOAvatar::isTextureVisible(type); + } + + U32 index = gAgentWearables.getWearableIndex(wearable); + return isTextureVisible(type,index); +} + + +//----------------------------------------------------------------------------- +// requestLayerSetUploads() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::requestLayerSetUploads() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + requestLayerSetUpload((EBakedTextureIndex)i); + } +} + +void LLVOAvatarSelf::requestLayerSetUpload(LLVOAvatarDefines::EBakedTextureIndex i) +{ + ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex; + const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index)); + if (!layer_baked && mBakedTextureDatas[i].mTexLayerSet) + { + mBakedTextureDatas[i].mTexLayerSet->requestUpload(); + } +} + +bool LLVOAvatarSelf::areTexturesCurrent() const +{ + return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded(); +} + +// virtual +bool LLVOAvatarSelf::hasPendingBakedUploads() const +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + LLTexLayerSet* layerset = mBakedTextureDatas[i].mTexLayerSet; + if (layerset && layerset->getComposite() && layerset->getComposite()->uploadPending()) + { + return true; + } + } + return false; +} + +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +{ + if( !layerset || !layerset->getUpdatesEnabled() ) + { + return; + } + // llinfos << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegionName() << llendl; + + layerset->requestUpdate(); + layerset->invalidateMorphMasks(); + + if( upload_result ) + { + llassert(isSelf()); + + ETextureIndex baked_te = getBakedTE( layerset ); + setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) ); + layerset->requestUpload(); + updateMeshTextures(); + } +} + +void LLVOAvatarSelf::invalidateAll() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, TRUE); + } + //mDebugSelfLoadTimer.reset(); +} + +//----------------------------------------------------------------------------- +// setCompositeUpdatesEnabled() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setCompositeUpdatesEnabled( bool b ) +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + setCompositeUpdatesEnabled(i, b); + } +} + +void LLVOAvatarSelf::setCompositeUpdatesEnabled(U32 index, bool b) +{ + if (mBakedTextureDatas[index].mTexLayerSet ) + { + mBakedTextureDatas[index].mTexLayerSet->setUpdatesEnabled( b ); + } +} + +bool LLVOAvatarSelf::isCompositeUpdateEnabled(U32 index) +{ + if (mBakedTextureDatas[index].mTexLayerSet) + { + return mBakedTextureDatas[index].mTexLayerSet->getUpdatesEnabled(); + } + return false; +} + +void LLVOAvatarSelf::setupComposites() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex; + BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index)); + if (mBakedTextureDatas[i].mTexLayerSet) + { + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(!layer_baked); + } + } +} + +void LLVOAvatarSelf::updateComposites() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (mBakedTextureDatas[i].mTexLayerSet + && ((i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT))) + { + mBakedTextureDatas[i].mTexLayerSet->updateComposite(); + } + } +} + +// virtual +S32 LLVOAvatarSelf::getLocalDiscardLevel(ETextureIndex type, U32 wearable_index) const +{ + if (!isIndexLocalTexture(type)) return FALSE; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, wearable_index); + if (local_tex_obj) + { + if (type >= 0 + && local_tex_obj->getID() != IMG_DEFAULT_AVATAR + && !local_tex_obj->getImage()->isMissingAsset()) + { + return local_tex_obj->getImage()->getDiscardLevel(); + } + else + { + // We don't care about this (no image associated with the layer) treat as fully loaded. + return 0; + } + } + return 0; +} + +// virtual +// Counts the memory footprint of local textures. +void LLVOAvatarSelf::getLocalTextureByteCount(S32* gl_bytes) const +{ + *gl_bytes = 0; + for (S32 type = 0; type < TEX_NUM_INDICES; type++) + { + if (!isIndexLocalTexture((ETextureIndex)type)) continue; + U32 max_tex = getNumWearables((ETextureIndex) type); + for (U32 num = 0; num < max_tex; num++) + { + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject((ETextureIndex) type, num); + if (local_tex_obj) + { + const LLViewerFetchedTexture* image_gl = local_tex_obj->getImage(); + if (image_gl) + { + S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents(); + + if (image_gl->hasGLTexture()) + { + *gl_bytes += bytes; + } + } + } + } + } +} + +// virtual +void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_tex, BOOL baked_version_ready, U32 index) +{ + if (!isIndexLocalTexture(type)) return; + + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(src_tex, TRUE) ; + if(!tex) + { + return ; + } + + S32 desired_discard = isSelf() ? 0 : 2; + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type,index); + if (!local_tex_obj) + { + if (type >= TEX_NUM_INDICES) + { + llerrs << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << llendl; + return; + } + LLWearableType::EType wearable_type = LLVOAvatarDictionary::getInstance()->getTEWearableType(type); + if (!gAgentWearables.getWearable(wearable_type,index)) + { + // no wearable is loaded, cannot set the texture. + return; + } + gAgentWearables.addLocalTextureObject(wearable_type,type,index); + local_tex_obj = getLocalTextureObject(type,index); + if (!local_tex_obj) + { + llerrs << "Unable to create LocalTextureObject for wearable type & index: (" << (U32) wearable_type << ", " << index << ")" << llendl; + return; + } + + LLTexLayerSet *layer_set = getLayerSet(type); + if (layer_set) + { + layer_set->cloneTemplates(local_tex_obj, type, gAgentWearables.getWearable(wearable_type,index)); + } + + } + if (!baked_version_ready) + { + if (tex != local_tex_obj->getImage() || local_tex_obj->getBakedReady()) + { + local_tex_obj->setDiscard(MAX_DISCARD_LEVEL+1); + } + if (tex->getID() != IMG_DEFAULT_AVATAR) + { + if (local_tex_obj->getDiscard() > desired_discard) + { + S32 tex_discard = tex->getDiscardLevel(); + if (tex_discard >= 0 && tex_discard <= desired_discard) + { + local_tex_obj->setDiscard(tex_discard); + if (isSelf()) + { + if (gAgentAvatarp->isUsingBakedTextures()) + { + requestLayerSetUpdate(type); + } + else + { + LLVisualParamHint::requestHintUpdates(); + } + } + } + else + { + tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type), NULL); + } + } + tex->setMinDiscardLevel(desired_discard); + } + } + local_tex_obj->setImage(tex); + local_tex_obj->setID(tex->getID()); + setBakedReady(type,baked_version_ready,index); +} +//virtual +void LLVOAvatarSelf::setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index) +{ + if (!isIndexLocalTexture(type)) return; + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type,index); + if (local_tex_obj) + { + local_tex_obj->setBakedReady( baked_version_exists ); + } +} + + +// virtual +void LLVOAvatarSelf::dumpLocalTextures() const +{ + llinfos << "Local Textures:" << llendl; + + /* ETextureIndex baked_equiv[] = { + TEX_UPPER_BAKED, + if (isTextureDefined(baked_equiv[i])) */ + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) + continue; + + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + const ETextureIndex baked_equiv = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex; + + const std::string &name = texture_dict->mName; + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(iter->first, 0); + // index is baked texture - index is not relevant. putting in 0 as placeholder + if (isTextureDefined(baked_equiv, 0)) + { +#if LL_RELEASE_FOR_DOWNLOAD + // End users don't get to trivially see avatar texture IDs, makes textures + // easier to steal. JC + llinfos << "LocTex " << name << ": Baked " << llendl; +#else + llinfos << "LocTex " << name << ": Baked " << getTEImage(baked_equiv)->getID() << llendl; +#endif + } + else if (local_tex_obj && local_tex_obj->getImage() != NULL) + { + if (local_tex_obj->getImage()->getID() == IMG_DEFAULT_AVATAR) + { + llinfos << "LocTex " << name << ": None" << llendl; + } + else + { + const LLViewerFetchedTexture* image = local_tex_obj->getImage(); + + llinfos << "LocTex " << name << ": " + << "Discard " << image->getDiscardLevel() << ", " + << "(" << image->getWidth() << ", " << image->getHeight() << ") " +#if !LL_RELEASE_FOR_DOWNLOAD + // End users don't get to trivially see avatar texture IDs, + // makes textures easier to steal + << image->getID() << " " +#endif + << "Priority: " << image->getDecodePriority() + << llendl; + } + } + else + { + llinfos << "LocTex " << name << ": No LLViewerTexture" << llendl; + } + } +} + +//----------------------------------------------------------------------------- +// static +// onLocalTextureLoaded() +//----------------------------------------------------------------------------- + +void LLVOAvatarSelf::onLocalTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +{ + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + LLVOAvatarSelf *self = (LLVOAvatarSelf *)gObjectList.findObject(data->mAvatarID); + if (self) + { + // We should only be handling local textures for ourself + self->localTextureLoaded(success, src_vi, src_raw, aux_src, discard_level, final, userdata); + } + // ensure data is cleaned up + if (final || !success) + { + delete data; + } +} + +/*virtual*/ void LLVOAvatarSelf::setImage(const U8 te, LLViewerTexture *imagep, const U32 index) +{ + if (isIndexLocalTexture((ETextureIndex)te)) + { + setLocalTexture((ETextureIndex)te, imagep, FALSE ,index); + } + else + { + setTEImage(te,imagep); + } +} + +/*virtual*/ LLViewerTexture* LLVOAvatarSelf::getImage(const U8 te, const U32 index) const +{ + if (isIndexLocalTexture((ETextureIndex)te)) + { + return getLocalTextureGL((ETextureIndex)te,index); + } + else + { + return getTEImage(te); + } +} + + +// static +void LLVOAvatarSelf::dumpTotalLocalTextureByteCount() +{ + S32 gl_bytes = 0; + gAgentAvatarp->getLocalTextureByteCount(&gl_bytes); + llinfos << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << llendl; +} + +BOOL LLVOAvatarSelf::getIsCloud() +{ + // do we have our body parts? + if (gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE) == 0 || + gAgentWearables.getWearableCount(LLWearableType::WT_HAIR) == 0 || + gAgentWearables.getWearableCount(LLWearableType::WT_EYES) == 0 || + gAgentWearables.getWearableCount(LLWearableType::WT_SKIN) == 0) + { + lldebugs << "No body parts" << llendl; + return TRUE; + } + + if (!isTextureDefined(TEX_HAIR, 0)) + { + lldebugs << "No hair texture" << llendl; + return TRUE; + } + + if (!mPreviousFullyLoaded) + { + if (!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_LOWER].mTexLayerSet) && + (!isTextureDefined(TEX_LOWER_BAKED, 0))) + { + lldebugs << "Lower textures not baked" << llendl; + return TRUE; + } + + if (!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_UPPER].mTexLayerSet) && + (!isTextureDefined(TEX_UPPER_BAKED, 0))) + { + lldebugs << "Upper textures not baked" << llendl; + return TRUE; + } + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (i == BAKED_SKIRT && !isWearingWearableType(LLWearableType::WT_SKIRT)) + continue; + + const BakedTextureData& texture_data = mBakedTextureDatas[i]; + if (!isTextureDefined(texture_data.mTextureIndex, 0)) + continue; + + // Check for the case that texture is defined but not sufficiently loaded to display anything. + const LLViewerTexture* baked_img = getImage( texture_data.mTextureIndex, 0 ); + if (!baked_img || !baked_img->hasGLTexture()) + { + lldebugs << "Texture at index " << i << " (texture index is " << texture_data.mTextureIndex << ") is not loaded" << llendl; + return TRUE; + } + } + + lldebugs << "Avatar de-clouded" << llendl; + } + return FALSE; +} + +/*static*/ +void LLVOAvatarSelf::debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +{ + gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); +} + +void LLVOAvatarSelf::debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +{ + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + if (!data) + { + return; + } + + ETextureIndex index = data->mIndex; + + if (index < 0 || index >= TEX_NUM_INDICES) + { + return; + } + + if (discard_level >=0 && discard_level <= MAX_DISCARD_LEVEL) // ignore discard level -1, as it means we have no data. + { + mDebugTextureLoadTimes[(U32)index][(U32)discard_level] = mDebugSelfLoadTimer.getElapsedTimeF32(); + } + if (final) + { + delete data; + } +} + +void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, BOOL finished) +{ + U32 done = 0; + if (finished) + { + done = 1; + } + mDebugBakedTextureTimes[index][done] = mDebugSelfLoadTimer.getElapsedTimeF32(); +} + +const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLTexLayerSet* layerset) const +{ + std::string text=""; + + text = llformat("[Final:%d Avail:%d] ",isLocalTextureDataFinal(layerset), isLocalTextureDataAvailable(layerset)); + + /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) + return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */ + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + ++baked_iter) + { + const EBakedTextureIndex baked_index = baked_iter->first; + if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + text += llformat("%d-%s ( ",baked_index, baked_dict->mName.c_str()); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + if (wearable_count > 0) + { + text += LLWearableType::getTypeName(wearable_type) + ":"; + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + const U32 discard_level = getLocalDiscardLevel(tex_index, wearable_index); + std::string discard_str = llformat("%d ",discard_level); + text += llformat("%d ",discard_level); + } + } + } + text += ")"; + break; + } + } + return text; +} + +const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const +{ + std::string text; + const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + BOOL is_texture_final = TRUE; + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + is_texture_final &= (getLocalDiscardLevel(*local_tex_iter, wearable_index) <= (S32)(override_tex_discard_level)); + } + } + text += llformat("%s:%d ",baked_dict->mName.c_str(),is_texture_final); + } + return text; +} + +const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const +{ + if (canGrabBakedTexture(baked_index)) + { + ETextureIndex tex_index = LLVOAvatarDictionary::bakedToLocalTextureIndex(baked_index); + if (tex_index == TEX_NUM_INDICES) + { + return LLUUID::null; + } + return getTEImage( tex_index )->getID(); + } + return LLUUID::null; +} + +BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const +{ + ETextureIndex tex_index = LLVOAvatarDictionary::bakedToLocalTextureIndex(baked_index); + if (tex_index == TEX_NUM_INDICES) + { + return FALSE; + } + // Check if the texture hasn't been baked yet. + if (!isTextureDefined(tex_index, 0)) + { + lldebugs << "getTEImage( " << (U32) tex_index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl; + return FALSE; + } + + if (gAgent.isGodlikeWithoutAdminMenuFakery()) + return TRUE; + + // Check permissions of textures that show up in the + // baked texture. We don't want people copying people's + // work via baked textures. + + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index); + for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin(); + iter != baked_dict->mLocalTextures.end(); + ++iter) + { + const ETextureIndex t_index = (*iter); + LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(t_index); + U32 count = gAgentWearables.getWearableCount(wearable_type); + lldebugs << "Checking index " << (U32) t_index << " count: " << count << llendl; + + for (U32 wearable_index = 0; wearable_index < count; ++wearable_index) + { + LLWearable *wearable = gAgentWearables.getWearable(wearable_type, wearable_index); + if (wearable) + { + const LLLocalTextureObject *texture = wearable->getLocalTextureObject((S32)t_index); + const LLUUID& texture_id = texture->getID(); + if (texture_id != IMG_DEFAULT_AVATAR) + { + // Search inventory for this texture. + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(texture_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + BOOL can_grab = FALSE; + lldebugs << "item count for asset " << texture_id << ": " << items.count() << llendl; + if (items.count()) + { + // search for full permissions version + for (S32 i = 0; i < items.count(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp->getIsFullPerm()) + { + can_grab = TRUE; + break; + } + } + } + if (!can_grab) return FALSE; + } + } + } + } + + return TRUE; +} + +void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTexture* imagep, + F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index ) +{ + if (!isIndexLocalTexture(type)) return; + + if (!covered_by_baked) + { + if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR && imagep->getDiscardLevel() != 0) + { + F32 desired_pixels; + desired_pixels = llmin(mPixelArea, (F32)getTexImageArea()); + imagep->setBoostLevel(getAvatarBoostLevel()); + + imagep->resetTextureStats(); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->addTextureStats( desired_pixels / texel_area_ratio ); + imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; + imagep->forceUpdateBindStats() ; + if (imagep->getDiscardLevel() < 0) + { + mHasGrey = TRUE; // for statistics gathering + } + } + else + { + // texture asset is missing + mHasGrey = TRUE; // for statistics gathering + } + } +} + +LLLocalTextureObject* LLVOAvatarSelf::getLocalTextureObject(LLVOAvatarDefines::ETextureIndex i, U32 wearable_index) const +{ + LLWearableType::EType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i); + LLWearable* wearable = gAgentWearables.getWearable(type, wearable_index); + if (wearable) + { + return wearable->getLocalTextureObject(i); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// getBakedTE() +// Used by the LayerSet. (Layer sets don't in general know what textures depend on them.) +//----------------------------------------------------------------------------- +ETextureIndex LLVOAvatarSelf::getBakedTE( const LLTexLayerSet* layerset ) const +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (layerset == mBakedTextureDatas[i].mTexLayerSet ) + { + return mBakedTextureDatas[i].mTextureIndex; + } + } + llassert(0); + return TEX_HEAD_BAKED; +} + + +void LLVOAvatarSelf::setNewBakedTexture(LLVOAvatarDefines::EBakedTextureIndex i, const LLUUID &uuid) +{ + ETextureIndex index = LLVOAvatarDictionary::bakedToLocalTextureIndex(i); + setNewBakedTexture(index, uuid); +} + + +//----------------------------------------------------------------------------- +// setNewBakedTexture() +// A new baked texture has been successfully uploaded and we can start using it now. +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) +{ + // Baked textures live on other sims. + LLHost target_host = getObjectHost(); + setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, target_host ) ); + updateMeshTextures(); + dirtyMesh(); + + LLVOAvatar::cullAvatarsByPixelArea(); + + /* switch(te) + case TEX_HEAD_BAKED: + llinfos << "New baked texture: HEAD" << llendl; */ + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(te); + if (texture_dict->mIsBakedTexture) + { + debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish. + llinfos << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <getBakedTextures().begin(); + baked_iter != LLVOAvatarDefines::LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + ++baked_iter) + { + const LLVOAvatarDefines::EBakedTextureIndex baked_index = baked_iter->first; + const LLTexLayerSet *layerset = debugGetLayerSet(baked_index); + if (!layerset) continue; + const LLTexLayerSetBuffer *layerset_buffer = layerset->getComposite(); + if (!layerset_buffer) continue; + llinfos << layerset_buffer->dumpTextureInfo() << llendl; + } +} + +void LLVOAvatarSelf::outputRezTiming(const std::string& msg) const +{ + LL_DEBUGS("Avatar Rez") + << llformat("%s. Time from avatar creation: %.2f", msg.c_str(), mDebugSelfLoadTimer.getElapsedTimeF32()) + << llendl; +} + +void LLVOAvatarSelf::reportAvatarRezTime() const +{ + // TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow. +} + +//----------------------------------------------------------------------------- +// setCachedBakedTexture() +// A baked texture id was received from a cache query, make it active +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid ) +{ + setTETexture( te, uuid ); + + /* switch(te) + case TEX_HEAD_BAKED: + if( mHeadLayerSet ) + mHeadLayerSet->cancelUpload(); */ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if ( mBakedTextureDatas[i].mTextureIndex == te && mBakedTextureDatas[i].mTexLayerSet) + { + mBakedTextureDatas[i].mTexLayerSet->cancelUpload(); + } + } +} + +// static +void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) +{ + LLUUID texture_id; + msg->getUUID("TextureData", "TextureID", texture_id); + if (!isAgentAvatarValid()) return; + + // If this is a texture corresponding to one of our baked entries, + // just rebake that layer set. + BOOL found = FALSE; + + /* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = + TEX_HEAD_BAKED, + TEX_UPPER_BAKED, */ + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsBakedTexture) + { + if (texture_id == gAgentAvatarp->getTEImage(index)->getID()) + { + LLTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index); + if (layer_set) + { + llinfos << "TAT: rebake - matched entry " << (S32)index << llendl; + gAgentAvatarp->invalidateComposite(layer_set, TRUE); + found = TRUE; + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); + } + } + } + } + + // If texture not found, rebake all entries. + if (!found) + { + gAgentAvatarp->forceBakeAllTextures(); + } + else + { + // Not sure if this is necessary, but forceBakeAllTextures() does it. + gAgentAvatarp->updateMeshTextures(); + } +} + +BOOL LLVOAvatarSelf::isUsingBakedTextures() const +{ + // Composite textures are used during appearance mode. + if (gAgentCamera.cameraCustomizeAvatar()) + return FALSE; + + return TRUE; +} + + +void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) +{ + llinfos << "TAT: forced full rebake. " << llendl; + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + ETextureIndex baked_index = mBakedTextureDatas[i].mTextureIndex; + LLTexLayerSet* layer_set = getLayerSet(baked_index); + if (layer_set) + { + if (slam_for_debug) + { + layer_set->setUpdatesEnabled(TRUE); + layer_set->cancelUpload(); + } + + invalidateComposite(layer_set, TRUE); + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); + } + else + { + llwarns << "TAT: NO LAYER SET FOR " << (S32)baked_index << llendl; + } + } + + // Don't know if this is needed + updateMeshTextures(); +} + +//----------------------------------------------------------------------------- +// requestLayerSetUpdate() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index ) +{ + /* switch(index) + case LOCTEX_UPPER_BODYPAINT: + case LOCTEX_UPPER_SHIRT: + if( mUpperBodyLayerSet ) + mUpperBodyLayerSet->requestUpdate(); */ + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); + if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) + return; + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + if (mBakedTextureDatas[baked_index].mTexLayerSet) + { + mBakedTextureDatas[baked_index].mTexLayerSet->requestUpdate(); + } +} + +LLTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const +{ + /* switch(index) + case TEX_HEAD_BAKED: + case TEX_HEAD_BODYPAINT: + return mHeadLayerSet; */ + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); + if (texture_dict->mIsUsedByBakedTexture) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + return mBakedTextureDatas[baked_index].mTexLayerSet; + } + return NULL; +} + +// static +void LLVOAvatarSelf::onCustomizeStart() +{ + // We're no longer doing any baking or invalidating on entering + // appearance editing mode. Leaving function in place in case + // further changes require us to do something at this point - Nyx +} + +// static +void LLVOAvatarSelf::onCustomizeEnd() +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->invalidateAll(); + } +} + +// HACK: this will null out the avatar's local texture IDs before the TE message is sent +// to ensure local texture IDs are not sent to other clients in the area. +// this is a short-term solution. The long term solution will be to not set the texture +// IDs in the avatar object, and keep them only in the wearable. +// This will involve further refactoring that is too risky for the initial release of 2.0. +bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const +{ + LLUUID texture_id[TEX_NUM_INDICES]; + // pack away current TEs to make sure we don't send them out + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (!texture_dict->mIsBakedTexture) + { + LLTextureEntry* entry = getTE((U8) index); + texture_id[index] = entry->getID(); + entry->setID(IMG_DEFAULT_AVATAR); + } + } + + bool success = packTEMessage(mesgsys); + + // unpack TEs to make sure we don't re-trigger a bake + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (!texture_dict->mIsBakedTexture) + { + LLTextureEntry* entry = getTE((U8) index); + entry->setID(texture_id[index]); + } + } + + return success; +} + //------------------------------------------------------------------------ // needsRenderBeam() //------------------------------------------------------------------------ @@ -671,4 +2517,104 @@ BOOL LLVOAvatarSelf::needsRenderBeam() is_touching_or_grabbing = FALSE; } return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); +} + +// static +void LLVOAvatarSelf::deleteScratchTextures() +{ + if(gAuditTexture) + { + S32 total_tex_size = sScratchTexBytes ; + S32 tex_size = SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT ; + + if( sScratchTexNames.checkData( GL_LUMINANCE ) ) + { + LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; + total_tex_size -= tex_size ; + } + if( sScratchTexNames.checkData( GL_ALPHA ) ) + { + LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; + total_tex_size -= tex_size ; + } + if( sScratchTexNames.checkData( GL_COLOR_INDEX ) ) + { + LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; + total_tex_size -= tex_size ; + } + if( sScratchTexNames.checkData( LLRender::sGLCoreProfile ? GL_RG : GL_LUMINANCE_ALPHA ) ) + { + LLImageGL::decTextureCounter(tex_size, 2, LLViewerTexture::AVATAR_SCRATCH_TEX) ; + total_tex_size -= 2 * tex_size ; + } + if( sScratchTexNames.checkData( GL_RGB ) ) + { + LLImageGL::decTextureCounter(tex_size, 3, LLViewerTexture::AVATAR_SCRATCH_TEX) ; + total_tex_size -= 3 * tex_size ; + } + if( sScratchTexNames.checkData( GL_RGBA ) ) + { + LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ; + total_tex_size -= 4 * tex_size ; + } + //others + while(total_tex_size > 0) + { + LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ; + total_tex_size -= 4 * tex_size ; + } + } + + for( LLGLuint* namep = sScratchTexNames.getFirstData(); + namep; + namep = sScratchTexNames.getNextData() ) + { + LLImageGL::deleteTextures(1, (U32 *)namep ); + stop_glerror(); + } + + if( sScratchTexBytes ) + { + lldebugs << "Clearing Scratch Textures " << (sScratchTexBytes/1024) << "KB" << llendl; + + sScratchTexNames.deleteAllData(); + sScratchTexLastBindTime.deleteAllData(); + LLImageGL::sGlobalTextureMemoryInBytes -= sScratchTexBytes; + sScratchTexBytes = 0; + } +} + +// static +void LLVOAvatarSelf::dumpScratchTextureByteCount() +{ + llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl; +} + +// static +void LLVOAvatarSelf::onChangeSelfInvisible(bool invisible) +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->setInvisible(invisible); + } +} + +void LLVOAvatarSelf::setInvisible(bool invisible) +{ + if (invisible) + { + setCompositeUpdatesEnabled(FALSE); + for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) + { + setNewBakedTexture(mBakedTextureDatas[i].mTextureIndex, IMG_INVISIBLE); + } + gAgent.sendAgentSetAppearance(); + } + else + { + setCompositeUpdatesEnabled(TRUE); + invalidateAll(); + requestLayerSetUploads(); + gAgent.sendAgentSetAppearance(); + } } \ No newline at end of file diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 24ee48517..2ee684799 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -31,6 +31,8 @@ #include "llviewertexture.h" #include "llvoavatar.h" +struct LocalTextureData; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLVOAvatarSelf @@ -39,6 +41,7 @@ class LLVOAvatarSelf : public LLVOAvatar { + LOG_CLASS(LLVOAvatarSelf); /******************************************************************************** ** ** @@ -56,6 +59,7 @@ protected: BOOL loadAvatarSelf(); BOOL buildSkeletonSelf(const LLVOAvatarSkeletonInfo *info); BOOL buildMenus(); + /*virtual*/ BOOL loadLayersets(); /** Initialization ** ** @@ -83,6 +87,15 @@ public: void resetJointPositions( void ); + /*virtual*/ BOOL setVisualParamWeight(LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); + /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); + /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); + /*virtual*/ void updateVisualParams(); + /*virtual*/ void idleUpdateAppearanceAnimation(); + +private: + // helper function. Passed in param is assumed to be in avatar's parameter list. + BOOL setParamWeight(LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE ); /** Initialization @@ -104,7 +117,16 @@ public: /*virtual*/ BOOL updateCharacter(LLAgent &agent); /*virtual*/ void idleUpdateTractorBeam(); + //-------------------------------------------------------------------- + // Loading state + //-------------------------------------------------------------------- +public: + /*virtual*/ BOOL getIsCloud(); + //-------------------------------------------------------------------- + // Region state + //-------------------------------------------------------------------- + void resetRegionCrossingTimer() { mRegionCrossingTimer.reset(); } private: U64 mLastRegionHandle; @@ -129,12 +151,114 @@ private: LLPointer mBeam; LLFrameTimer mBeamTimer; + //-------------------------------------------------------------------- + // LLVOAvatar Constants + //-------------------------------------------------------------------- +public: + /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_SELF; } + /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_BAKED_SELF; } + /*virtual*/ S32 getTexImageSize() const { return LLVOAvatar::getTexImageSize()*4; } /** Rendering ** ** *******************************************************************************/ + +/******************************************************************************** + ** ** + ** TEXTURES + **/ + + //-------------------------------------------------------------------- + // Loading status + //-------------------------------------------------------------------- +public: + /*virtual*/ bool hasPendingBakedUploads() const; + S32 getLocalDiscardLevel(LLVOAvatarDefines::ETextureIndex type, U32 index) const; + bool areTexturesCurrent() const; + BOOL isLocalTextureDataAvailable(const LLTexLayerSet* layerset) const; + BOOL isLocalTextureDataFinal(const LLTexLayerSet* layerset) const; + BOOL isBakedTextureFinal(const LLVOAvatarDefines::EBakedTextureIndex index) const; + // If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index + /*virtual*/ BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index) const; + /*virtual*/ BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + /*virtual*/ BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const; + + + //-------------------------------------------------------------------- + // Local Textures + //-------------------------------------------------------------------- +public: + BOOL getLocalTextureGL(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture** image_gl_pp, U32 index) const; + LLViewerFetchedTexture* getLocalTextureGL(LLVOAvatarDefines::ETextureIndex type, U32 index) const; + const LLUUID& getLocalTextureID(LLVOAvatarDefines::ETextureIndex type, U32 index) const; + void setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index); + /*virtual*/ void setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index); +protected: + /*virtual*/ void setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index); + void localTextureLoaded(BOOL succcess, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + void getLocalTextureByteCount(S32* gl_byte_count) const; + /*virtual*/ void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex i, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked, U32 index); + LLLocalTextureObject* getLocalTextureObject(LLVOAvatarDefines::ETextureIndex i, U32 index) const; + +private: + static void onLocalTextureLoaded(BOOL succcess, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + + /*virtual*/ void setImage(const U8 te, LLViewerTexture *imagep, const U32 index); + /*virtual*/ LLViewerTexture* getImage(const U8 te, const U32 index) const; + + + //-------------------------------------------------------------------- + // Baked textures + //-------------------------------------------------------------------- +public: + LLVOAvatarDefines::ETextureIndex getBakedTE(const LLTexLayerSet* layerset ) const; + void setNewBakedTexture(LLVOAvatarDefines::EBakedTextureIndex i, const LLUUID &uuid); + void setNewBakedTexture(LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid); + void setCachedBakedTexture(LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid); + void forceBakeAllTextures(bool slam_for_debug = false); + static void processRebakeAvatarTextures(LLMessageSystem* msg, void**); + BOOL isUsingBakedTextures() const; // e.g. false if in appearance edit mode protected: /*virtual*/ void removeMissingBakedTextures(); + + //-------------------------------------------------------------------- + // Layers + //-------------------------------------------------------------------- +public: + void requestLayerSetUploads(); + void requestLayerSetUpload(LLVOAvatarDefines::EBakedTextureIndex i); + void requestLayerSetUpdate(LLVOAvatarDefines::ETextureIndex i); + LLTexLayerSet* getLayerSet(LLVOAvatarDefines::ETextureIndex index) const; + + //-------------------------------------------------------------------- + // Composites + //-------------------------------------------------------------------- +public: + /* virtual */ void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); + /* virtual */ void invalidateAll(); + /* virtual */ void setCompositeUpdatesEnabled(bool b); // only works for self + /* virtual */ void setCompositeUpdatesEnabled(U32 index, bool b); + /* virtual */ bool isCompositeUpdateEnabled(U32 index); + void setupComposites(); + void updateComposites(); + + const LLUUID& grabBakedTexture(LLVOAvatarDefines::EBakedTextureIndex baked_index) const; + BOOL canGrabBakedTexture(LLVOAvatarDefines::EBakedTextureIndex baked_index) const; + + + //-------------------------------------------------------------------- + // Scratch textures (used for compositing) + //-------------------------------------------------------------------- +public: + static void deleteScratchTextures(); +private: + static S32 sScratchTexBytes; + static LLMap< LLGLenum, LLGLuint*> sScratchTexNames; + static LLMap< LLGLenum, F32*> sScratchTexLastBindTime; + +/** Textures + ** ** + *******************************************************************************/ /******************************************************************************** ** ** ** MESHES @@ -146,6 +270,36 @@ protected: ** ** *******************************************************************************/ +/******************************************************************************** + ** ** + ** WEARABLES + **/ + +public: + /*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type) const; + void wearableUpdated(LLWearableType::EType type, BOOL upload_result); +protected: + U32 getNumWearables(LLVOAvatarDefines::ETextureIndex i) const; + + //-------------------------------------------------------------------- + // Attachments + //-------------------------------------------------------------------- +public: + void updateAttachmentVisibility(U32 camera_mode); + BOOL isWearingAttachment(const LLUUID& inv_item_id) const; + BOOL attachmentWasRequested(const LLUUID& inv_item_id) const; + void addAttachmentRequest(const LLUUID& inv_item_id); + void removeAttachmentRequest(const LLUUID& inv_item_id); + LLViewerObject* getWornAttachment(const LLUUID& inv_item_id); + const std::string getAttachedPointName(const LLUUID& inv_item_id) const; + /*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); + /*virtual*/ BOOL detachObject(LLViewerObject *viewer_object); + static BOOL detachAttachmentIntoInventory(const LLUUID& item_id); + +private: + // Track attachments that have been requested but have not arrived yet. + mutable std::map mAttachmentRequests; + //-------------------------------------------------------------------- // HUDs //-------------------------------------------------------------------- @@ -155,6 +309,80 @@ private: /** Attachments ** ** *******************************************************************************/ + +/******************************************************************************** + ** ** + ** APPEARANCE + **/ + +public: + static void onCustomizeStart(); + static void onCustomizeEnd(); + + //-------------------------------------------------------------------- + // Visibility + //-------------------------------------------------------------------- +public: + bool sendAppearanceMessage(LLMessageSystem *mesgsys) const; + +/** Appearance + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** DIAGNOSTICS + **/ + + //-------------------------------------------------------------------- + // General + //-------------------------------------------------------------------- +public: + static void dumpTotalLocalTextureByteCount(); + void dumpLocalTextures() const; + static void dumpScratchTextureByteCount(); + + //-------------------------------------------------------------------- + // Avatar Rez Metrics + //-------------------------------------------------------------------- +public: + struct LLAvatarTexData + { + LLAvatarTexData(const LLUUID& id, LLVOAvatarDefines::ETextureIndex index) : + mAvatarID(id), + mIndex(index) + {} + LLUUID mAvatarID; + LLVOAvatarDefines::ETextureIndex mIndex; + }; + void debugWearablesLoaded() { mDebugTimeWearablesLoaded = mDebugSelfLoadTimer.getElapsedTimeF32(); } + void debugAvatarVisible() { mDebugTimeAvatarVisible = mDebugSelfLoadTimer.getElapsedTimeF32(); } + void outputRezDiagnostics() const; + void outputRezTiming(const std::string& msg) const; + void reportAvatarRezTime() const; + void debugBakedTextureUpload(LLVOAvatarDefines::EBakedTextureIndex index, BOOL finished); + static void debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + + BOOL isAllLocalTextureDataFinal() const; + + const LLTexLayerSet* debugGetLayerSet(LLVOAvatarDefines::EBakedTextureIndex index) const { return mBakedTextureDatas[index].mTexLayerSet; } + const std::string debugDumpLocalTextureDataInfo(const LLTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer + const std::string debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD +private: + LLFrameTimer mDebugSelfLoadTimer; + F32 mDebugTimeWearablesLoaded; + F32 mDebugTimeAvatarVisible; + F32 mDebugTextureLoadTimes[LLVOAvatarDefines::TEX_NUM_INDICES][MAX_DISCARD_LEVEL+1]; // load time for each texture at each discard level + F32 mDebugBakedTextureTimes[LLVOAvatarDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture + void debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + +/** Diagnostics + ** ** + *******************************************************************************/ + +public: + static void onChangeSelfInvisible(bool invisible); + void setInvisible(bool invisible); }; extern LLVOAvatarSelf *gAgentAvatarp; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 5f7c79786..82917326c 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -32,32 +32,58 @@ #include "llviewerprecompiledheaders.h" -#include "imageids.h" -#include "llassetstorage.h" -#include "lldbstrings.h" -#include "lldir.h" -#include "llquantize.h" - #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "lldictionary.h" -#include "llnotificationsutil.h" -#include "llassetuploadresponders.h" -#include "llviewerwindow.h" #include "llfloatercustomize.h" -#include "llinventoryobserver.h" +#include "lllocaltextureobject.h" +#include "llnotificationsutil.h" #include "llviewertexturelist.h" -#include "llviewerinventory.h" +#include "llinventorymodel.h" +#include "llinventoryobserver.h" +#include "lltexlayer.h" +#include "lltexglobalcolor.h" +#include "lltrans.h" #include "llviewerregion.h" +#include "llvisualparam.h" +#include "llvoavatar.h" #include "llvoavatarself.h" +#include "llvoavatardefines.h" #include "llwearable.h" +#include "llviewercontrol.h" using namespace LLVOAvatarDefines; // static S32 LLWearable::sCurrentDefinitionVersion = 1; +// support class - remove for 2.1 (hackity hack hack) +class LLOverrideBakedTextureUpdate +{ +public: + LLOverrideBakedTextureUpdate(bool temp_state) + { + U32 num_bakes = (U32) LLVOAvatarDefines::BAKED_NUM_INDICES; + for( U32 index = 0; index < num_bakes; ++index ) + { + composite_enabled[index] = gAgentAvatarp->isCompositeUpdateEnabled(index); + } + gAgentAvatarp->setCompositeUpdatesEnabled(temp_state); + } + + ~LLOverrideBakedTextureUpdate() + { + U32 num_bakes = (U32)LLVOAvatarDefines::BAKED_NUM_INDICES; + for( U32 index = 0; index < num_bakes; ++index ) + { + gAgentAvatarp->setCompositeUpdatesEnabled(index, composite_enabled[index]); + } + } +private: + bool composite_enabled[LLVOAvatarDefines::BAKED_NUM_INDICES]; +}; + // Private local functions static std::string terse_F32_to_string(F32 f); static std::string asset_id_to_filename(const LLUUID &asset_id); @@ -106,14 +132,14 @@ BOOL LLWearable::FileExportParams( FILE* file ) fprintf( file, "type %d\n", type ); // parameters - S32 num_parameters = mVisualParamMap.size(); + S32 num_parameters = mVisualParamIndexMap.size(); fprintf( file, "parameters %d\n", num_parameters ); - for (param_map_t::iterator iter = mVisualParamMap.begin(); - iter != mVisualParamMap.end(); ++iter) + for (visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); + iter != mVisualParamIndexMap.end(); ++iter) { S32 param_id = iter->first; - F32 param_weight = iter->second; + F32 param_weight = iter->second->getWeight(); fprintf( file, "%d %s\n", param_id, terse_F32_to_string(param_weight).c_str() ); } @@ -135,7 +161,7 @@ BOOL LLWearable::FileExportTextures( FILE* file ) iter != mTEMap.end(); ++iter) { S32 te = iter->first; - LLUUID& image_id = iter->second; + LLUUID& image_id = iter->second->getID(); fprintf( file, "%d %s\n", te, image_id.asString().c_str() ); } @@ -182,17 +208,19 @@ BOOL LLWearable::exportFile(LLFILE* file) const } // parameters - S32 num_parameters = mVisualParamMap.size(); + S32 num_parameters = mVisualParamIndexMap.size(); if( fprintf( file, "parameters %d\n", num_parameters ) < 0 ) { return FALSE; } - for (param_map_t::const_iterator iter = mVisualParamMap.begin(); - iter != mVisualParamMap.end(); ++iter) + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); + iter != mVisualParamIndexMap.end(); + ++iter) { S32 param_id = iter->first; - F32 param_weight = iter->second; + const LLVisualParam* param = iter->second; + F32 param_weight = param->getWeight(); if( fprintf( file, "%d %s\n", param_id, terse_F32_to_string( param_weight ).c_str() ) < 0 ) { return FALSE; @@ -206,11 +234,10 @@ BOOL LLWearable::exportFile(LLFILE* file) const return FALSE; } - for (te_map_t::const_iterator iter = mTEMap.begin(); - iter != mTEMap.end(); ++iter) + for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) { S32 te = iter->first; - const LLUUID& image_id = iter->second; + const LLUUID& image_id = iter->second->getID(); if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) { return FALSE; @@ -220,6 +247,38 @@ BOOL LLWearable::exportFile(LLFILE* file) const } +void LLWearable::createVisualParams() +{ + for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam()) + { + if (param->getWearableType() == mType) + { + addVisualParam(param->cloneParam(this)); + } + } + + // resync driver parameters to point to the newly cloned driven parameters + for (visual_param_index_map_t::iterator param_iter = mVisualParamIndexMap.begin(); + param_iter != mVisualParamIndexMap.end(); + ++param_iter) + { + LLVisualParam* param = param_iter->second; + LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam; + // need this line to disambiguate between versions of LLCharacter::getVisualParam() + LLVisualParam*(LLVOAvatarSelf::*avatar_function)(S32)const = &LLVOAvatarSelf::getVisualParam; + param->resetDrivenParams(); + if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false)) + { + if( !param->linkDrivenParams(boost::bind(avatar_function,gAgentAvatarp,_1 ), true)) + { + llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl; + continue; + } + } + } +} BOOL LLWearable::importFile( LLFILE* file ) { @@ -229,6 +288,10 @@ BOOL LLWearable::importFile( LLFILE* file ) char text_buffer[2048]; /* Flawfinder: ignore */ S32 fields_read = 0; + // suppress texlayerset updates while wearables are being imported. Layersets will be updated + // when the wearables are "worn", not loaded. Note state will be restored when this object is destroyed. + LLOverrideBakedTextureUpdate stop_bakes(false); + // read header and version fields_read = fscanf( file, "LLWearable version %d\n", &mDefinitionVersion ); if( fields_read != 1 ) @@ -240,7 +303,13 @@ BOOL LLWearable::importFile( LLFILE* file ) return FALSE; } - if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion ) + + // Temoprary hack to allow wearables with definition version 24 to still load. + // This should only affect lindens and NDA'd testers who have saved wearables in 2.0 + // the extra check for version == 24 can be removed before release, once internal testers + // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that + // these wearables get re-saved with version definition 22. + if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 ) { llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; return FALSE; @@ -361,6 +430,11 @@ BOOL LLWearable::importFile( LLFILE* file ) return FALSE; } + if( num_parameters != mVisualParamIndexMap.size() ) + { + llwarns << "Wearable parameter mismatch. Reading in " << num_parameters << " from file, but created " << mVisualParamIndexMap.size() << " from avatar parameters. type: " << mType << llendl; + } + // parameters S32 i; for( i = 0; i < num_parameters; i++ ) @@ -373,7 +447,7 @@ BOOL LLWearable::importFile( LLFILE* file ) llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl; return FALSE; } - mVisualParamMap[param_id] = param_weight; + mSavedVisualParamMap[param_id] = param_weight; } // textures header @@ -404,10 +478,30 @@ BOOL LLWearable::importFile( LLFILE* file ) llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; return FALSE; } + LLUUID id = LLUUID(text_buffer); + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( id ); + if( mTEMap.find(te) != mTEMap.end() ) + { + delete mTEMap[te]; + } + if( mSavedTEMap.find(te) != mSavedTEMap.end() ) + { + delete mSavedTEMap[te]; + } - mTEMap[te] = LLUUID(text_buffer ); + if(gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime")) + { + image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te), NULL); + } + LLUUID textureid(text_buffer); + mTEMap[te] = new LLLocalTextureObject(image, textureid); + mSavedTEMap[te] = new LLLocalTextureObject(image, textureid); + createLayers(te); } + // copy all saved param values to working params + revertValues(); + return TRUE; } @@ -438,13 +532,13 @@ BOOL LLWearable::isOldVersion() const if( (param->getWearableType() == mType) && (param->isTweakable()) ) { param_count++; - if( !is_in_map(mVisualParamMap, param->getID() ) ) + if( !is_in_map(mVisualParamIndexMap, param->getID() ) ) { return TRUE; } } } - if( param_count != mVisualParamMap.size() ) + if( param_count != mVisualParamIndexMap.size() ) { return TRUE; } @@ -485,34 +579,30 @@ BOOL LLWearable::isDirty() const param; param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) { - if( (param->getWearableType() == mType) && (param->isTweakable()) ) + if( (param->getWearableType() == mType) + && (param->isTweakable() ) + && !param->getCrossWearable()) { - F32 weight = get_if_there(mVisualParamMap, param->getID(), param->getDefaultWeight()); - weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() ); + F32 current_weight = getVisualParamWeight(param->getID()); + current_weight = llclamp( current_weight, param->getMinWeight(), param->getMaxWeight() ); + F32 saved_weight = get_if_there(mSavedVisualParamMap, param->getID(), param->getDefaultWeight()); + saved_weight = llclamp( saved_weight, param->getMinWeight(), param->getMaxWeight() ); - U8 a = F32_to_U8( param->getWeight(), param->getMinWeight(), param->getMaxWeight() ); + U8 a = F32_to_U8( saved_weight, param->getMinWeight(), param->getMaxWeight() ); + U8 b = F32_to_U8( current_weight, param->getMinWeight(), param->getMaxWeight() ); if(gAgentAvatarp->getAppearanceFlag() == true) { //boob if(param->getID() == 507) { - weight = get_if_there(mVisualParamMap, param->getID(), gAgentAvatarp->getActualBoobGrav()); - weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() ); + if( is_in_map(mVisualParamIndexMap, param->getID() ) ) + current_weight = mVisualParamIndexMap.find(param->getID())->second->getWeight(); + else + current_weight = gAgentAvatarp->getActualBoobGrav(); + current_weight = llclamp( current_weight, param->getMinWeight(), param->getMaxWeight() ); + b = F32_to_U8( current_weight, param->getMinWeight(), param->getMaxWeight() ); } - /*//butt - if(param->getID() == 795) - { - weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualButtGrav()); - weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() ); - } - //fat - if(param->getID() == 157) - { - weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualFatGrav()); - weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() ); - } - */ } else { @@ -521,21 +611,8 @@ BOOL LLWearable::isDirty() const { a = F32_to_U8( gAgentAvatarp->getActualBoobGrav(), param->getMinWeight(), param->getMaxWeight() ); } - /*//butt - if(param->getID() == 795) - { - a = F32_to_U8( gAgentAvatarp->getActualButtGrav(), param->getMinWeight(), param->getMaxWeight() ); - } - //fat - if(param->getID() == 157) - { - a = F32_to_U8( gAgentAvatarp->getActualFatGrav(), param->getMinWeight(), param->getMaxWeight() ); - } - */ } - - U8 b = F32_to_U8( weight, param->getMinWeight(), param->getMaxWeight() ); if( a != b ) { llwarns << "param ID " << param->getID() << " was changed." << llendl; @@ -546,31 +623,31 @@ BOOL LLWearable::isDirty() const for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - LLViewerTexture* avatar_image = gAgentAvatarp->getTEImage( te ); - if( !avatar_image ) + te_map_t::const_iterator current_iter = mTEMap.find(te); + if(current_iter != mTEMap.end()) { - llassert( 0 ); - continue; - } - const LLUUID& image_id = get_if_there(mTEMap, te, LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te ) ); - if( avatar_image->getID() != image_id ) - { - llwarns << "image ID " << avatar_image->getID() << " was changed." << llendl; - return TRUE; + const LLUUID& current_image_id = current_iter->second->getID(); + te_map_t::const_iterator saved_iter = mSavedTEMap.find(te); + if(saved_iter != mSavedTEMap.end()) + { + const LLUUID& saved_image_id = saved_iter->second->getID(); + if (saved_image_id != current_image_id) + { + // saved vs current images are different, wearable is dirty + return TRUE; + } + } + else + { + // image found in current image list but not saved image list + return TRUE; + } } } } - //if( gFloaterCustomize ) - //{ - // if( mDescription != gFloaterCustomize->getWearableDescription( mType ) ) - // { - // return TRUE; - // } - //} - return FALSE; } @@ -579,30 +656,41 @@ void LLWearable::setParamsToDefaults() { if (!isAgentAvatarValid()) return; - mVisualParamMap.clear(); for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) { - if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable()) ) + if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) ) { - mVisualParamMap[param->getID()] = param->getDefaultWeight(); + setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); } } } void LLWearable::setTexturesToDefaults() { - mTEMap.clear(); for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - mTEMap[te] = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + LLUUID id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + LLViewerFetchedTexture * image = LLViewerTextureManager::getFetchedTexture( id ); + if( mTEMap.find(te) == mTEMap.end() ) + { + mTEMap[te] = new LLLocalTextureObject(image, id); + createLayers(te); + } + else + { + // Local Texture Object already created, just set image and UUID + LLLocalTextureObject *lto = mTEMap[te]; + lto->setID(id); + lto->setImage(image); + } } } } // Updates the user's avatar's appearance -void LLWearable::writeToAvatar( BOOL set_by_user ) +void LLWearable::writeToAvatar() { if (!isAgentAvatarValid()) return; @@ -611,10 +699,12 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) // Pull params for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) { - if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->isTweakable()) ) + // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the + // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way. + if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) ) { S32 param_id = param->getID(); - F32 weight = get_if_there(mVisualParamMap, param_id, param->getDefaultWeight()); + F32 weight = getVisualParamWeight(param_id); //ZOMG: When switching shapes from inventory if(param_id == 507) @@ -626,37 +716,32 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) */ // only animate with user-originated changes - if (set_by_user) - { - param->setAnimationTarget(weight, set_by_user); - } - else - { - gAgentAvatarp->setVisualParamWeight( param_id, weight, set_by_user ); - } + gAgentAvatarp->setVisualParamWeight( param_id, weight, FALSE ); } } - // only interpolate with user-originated changes - if (set_by_user) - { - gAgentAvatarp->startAppearanceAnimation(TRUE, TRUE); - } - // Pull texture entries for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - const LLUUID& image_id = get_if_there(mTEMap, te, LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te ) ); - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id ); - gAgentAvatarp->setLocTexTE( te, image, set_by_user ); + te_map_t::const_iterator iter = mTEMap.find(te); + LLUUID image_id; + if(iter != mTEMap.end()) + { + image_id = iter->second->getID(); + } + else + { + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + } + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE ); + // MULTI-WEARABLE: assume index 0 will be used when writing to avatar. TODO: eliminate the need for this. + gAgentAvatarp->setLocalTextureTE(te, image, 0); } } - - gAgentAvatarp->updateVisualParams(); - - if( gFloaterCustomize ) + + /*if( gFloaterCustomize ) { LLViewerInventoryItem* item; item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType, 0)); // TODO: MULTI-WEARABLE @@ -673,22 +758,21 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) } gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); LLFloaterCustomize::setCurrentWearableType( mType ); - } + }*/ ESex new_sex = gAgentAvatarp->getSex(); if( old_sex != new_sex ) { - gAgentAvatarp->updateSexDependentLayerSets( set_by_user ); + gAgentAvatarp->updateSexDependentLayerSets( FALSE ); } - gAgentAvatarp->updateMeshTextures(); - -// if( set_by_user ) +// if( upload_bake ) // { // gAgent.sendAgentSetAppearance(); // } } + // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values. // static void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ) @@ -714,17 +798,7 @@ void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake } } - // Pull textures - LLViewerTexture* image =LLViewerTextureManager::getFetchedTexture( IMG_DEFAULT_AVATAR ); - for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) - { - if( LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te ) == type ) - { - gAgentAvatarp->setLocTexTE( te, image, upload_bake ); - } - } - - if( gFloaterCustomize ) + if(gAgentCamera.cameraCustomizeAvatar()) { gFloaterCustomize->setWearable(type, NULL, PERM_ALL, TRUE); } @@ -740,7 +814,7 @@ void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake // Does not copy mAssetID. // Definition version is current: removes obsolete enties and creates default values for new ones. -void LLWearable::copyDataFrom( LLWearable* src ) +void LLWearable::copyDataFrom(const LLWearable* src) { if (!isAgentAvatarValid()) return; @@ -750,17 +824,19 @@ void LLWearable::copyDataFrom( LLWearable* src ) mDescription = src->mDescription; mPermissions = src->mPermissions; mSaleInfo = src->mSaleInfo; + setType(src->mType); + mSavedVisualParamMap.clear(); // Deep copy of mVisualParamMap (copies only those params that are current, filling in defaults where needed) - for( LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); param; param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) { - if( (param->getWearableType() == mType) && (param->isTweakable()) ) + if( (param->getWearableType() == mType) ) { S32 id = param->getID(); - F32 weight = get_if_there(src->mVisualParamMap, id, param->getDefaultWeight() ); + F32 weight = src->getVisualParamWeight(id); //llwarns << "------------------------------" << llendl; //llwarns << "copydatafrom" << llendl; //llwarns << "------------------------------" << llendl; @@ -781,20 +857,42 @@ void LLWearable::copyDataFrom( LLWearable* src ) gAgentAvatarp->setActualFatGrav(weight); */ - - mVisualParamMap[id] = weight; + mSavedVisualParamMap[id] = weight; } } + destroyTextures(); // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - const LLUUID& image_id = get_if_there(src->mTEMap, te, LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te ) ); - mTEMap[te] = image_id; + te_map_t::const_iterator iter = src->mTEMap.find(te); + LLUUID image_id; + LLViewerFetchedTexture *image = NULL; + if(iter != src->mTEMap.end()) + { + image = src->getLocalTextureObject(te)->getImage(); + image_id = src->getLocalTextureObject(te)->getID(); + mTEMap[te] = new LLLocalTextureObject(image, image_id); + mSavedTEMap[te] = new LLLocalTextureObject(image, image_id); + mTEMap[te]->setBakedReady(src->getLocalTextureObject(te)->getBakedReady()); + mTEMap[te]->setDiscard(src->getLocalTextureObject(te)->getDiscard()); + } + else + { + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + image = LLViewerTextureManager::getFetchedTexture( image_id ); + mTEMap[te] = new LLLocalTextureObject(image, image_id); + mSavedTEMap[te] = new LLLocalTextureObject(image, image_id); + } + createLayers(te); } } + + // Probably reduntant, but ensure that the newly created wearable is not dirty by setting current value of params in new wearable + // to be the same as the saved values (which were loaded from src at param->cloneParam(this)) + revertValues(); } void LLWearable::setItemID(const LLUUID& item_id) @@ -806,13 +904,325 @@ const LLUUID& LLWearable::getItemID() const { return mItemID; } + void LLWearable::setType(LLWearableType::EType type) { mType = type; + createVisualParams(); } -// Updates asset from the user's avatar -void LLWearable::readFromAvatar() +LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) +{ + te_map_t::iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const +{ + te_map_t::const_iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + const LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o) +{ + if( mTEMap.find(index) != mTEMap.end() ) + { + mTEMap.erase(index); + } + mTEMap[index] = new LLLocalTextureObject(lto); +} + + +void LLWearable::addVisualParam(LLVisualParam *param) +{ + if( mVisualParamIndexMap[param->getID()] ) + { + delete mVisualParamIndexMap[param->getID()]; + } + param->setIsDummy(FALSE); + mVisualParamIndexMap[param->getID()] = param; + mSavedVisualParamMap[param->getID()] = param->getDefaultWeight(); +} + +void LLWearable::setVisualParams() +{ + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); iter++) + { + S32 id = iter->first; + LLVisualParam *wearable_param = iter->second; + F32 value = wearable_param->getWeight(); + gAgentAvatarp->setVisualParamWeight(id, value, FALSE); + } +} + + +void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) +{ + if( is_in_map(mVisualParamIndexMap, param_index ) ) + { + LLVisualParam *wearable_param = mVisualParamIndexMap[param_index]; + wearable_param->setWeight(value, upload_bake); + } + else + { + llerrs << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + } +} + +F32 LLWearable::getVisualParamWeight(S32 param_index) const +{ + if( is_in_map(mVisualParamIndexMap, param_index ) ) + { + const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second; + return wearable_param->getWeight(); + } + else + { + llwarns << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + } + return (F32)-1.0; +} + +LLVisualParam* LLWearable::getVisualParam(S32 index) const +{ + visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index); + return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second; +} + + +void LLWearable::getVisualParams(visual_param_vec_t &list) +{ + visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); + visual_param_index_map_t::iterator end = mVisualParamIndexMap.end(); + + // add all visual params to the passed-in vector + for( ; iter != end; ++iter ) + { + list.push_back(iter->second); + } +} + +void LLWearable::animateParams(F32 delta, BOOL upload_bake) +{ + for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); + iter != mVisualParamIndexMap.end(); + ++iter) + { + LLVisualParam *param = (LLVisualParam*) iter->second; + param->animate(delta, upload_bake); + } +} + +LLColor4 LLWearable::getClothesColor(S32 te) const +{ + LLColor4 color; + U32 param_name[3]; + if( LLVOAvatar::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + { + for( U8 index = 0; index < 3; index++ ) + { + color.mV[index] = getVisualParamWeight(param_name[index]); + } + } + return color; +} + +void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ) +{ + U32 param_name[3]; + if( LLVOAvatar::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + { + for( U8 index = 0; index < 3; index++ ) + { + setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake); + } + } +} + +void LLWearable::revertValues() +{ + //update saved settings so wearable is no longer dirty + // non-driver params first + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + F32 value = iter->second; + LLVisualParam *param = getVisualParam(id); + if(param && !dynamic_cast(param) ) + { + //param->setAnimationTarget(value, TRUE); + setVisualParamWeight(id, value, TRUE); + } + } + + //then driver params + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + F32 value = iter->second; + LLVisualParam *param = getVisualParam(id); + if(param && dynamic_cast(param) ) + { + //param->setAnimationTarget(value, TRUE); + setVisualParamWeight(id, value, TRUE); + } + } + + // make sure that saved values are sane + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + LLVisualParam *param = getVisualParam(id); + if( param ) + { + mSavedVisualParamMap[id] = param->getWeight(); + } + } + + syncImages(mSavedTEMap, mTEMap); + + + /*LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if( panel ) + { + panel->updateScrollingPanelList(); + }*/ +} + +BOOL LLWearable::isOnTop() const +{ + return (this == gAgentWearables.getTopWearable(mType)); +} + +void LLWearable::createLayers(S32 te) +{ + LLTexLayerSet *layer_set = gAgentAvatarp->getLayerSet((ETextureIndex)te); + if (layer_set) + { + layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this); + } + else + { + llerrs << "could not find layerset for LTO in wearable!" << llendl; + } +} + +void LLWearable::saveValues() +{ + //update saved settings so wearable is no longer dirty + mSavedVisualParamMap.clear(); + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter) + { + S32 id = iter->first; + LLVisualParam *wearable_param = iter->second; + F32 value = wearable_param->getWeight(); + mSavedVisualParamMap[id] = value; + } + + // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) + syncImages(mTEMap, mSavedTEMap); + + + /*LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if( panel ) + { + panel->updateScrollingPanelList(); + }*/ +} + +void LLWearable::syncImages(te_map_t &src, te_map_t &dst) +{ + // Deep copy of src (copies only those tes that are current, filling in defaults where needed) + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + te_map_t::const_iterator iter = src.find(te); + LLUUID image_id; + LLViewerFetchedTexture *image = NULL; + LLLocalTextureObject *lto = NULL; + if(iter != src.end()) + { + // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map. + lto = iter->second; + image = lto->getImage(); + image_id = lto->getID(); + } + else + { + // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map. + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + image = LLViewerTextureManager::getFetchedTexture( image_id ); + } + + if( dst.find(te) != dst.end() ) + { + // there's already an entry in the destination map for the texture. Just update its values. + dst[te]->setImage(image); + dst[te]->setID(image_id); + } + else + { + // no entry found in the destination map, we need to create a new Local Texture Object + dst[te] = new LLLocalTextureObject(image, image_id); + } + + if( lto ) + { + // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map. + dst[te]->setBakedReady(lto->getBakedReady()); + dst[te]->setDiscard(lto->getDiscard()); + } + } + } +} + +void LLWearable::destroyTextures() +{ + for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter ) + { + LLLocalTextureObject *lto = iter->second; + delete lto; + } + mTEMap.clear(); + for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter ) + { + LLLocalTextureObject *lto = iter->second; + delete lto; + } + mSavedTEMap.clear(); +} + +void LLWearable::pullCrossWearableValues() +{ + // scan through all of the avatar's visual parameters + for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam()) + { + if( param ) + { + LLDriverParam *driver_param = dynamic_cast(param); + if(driver_param) + { + // parameter is a driver parameter, have it update its + driver_param->updateCrossDrivenParams(getType()); + } + } + } +} + +/*void LLWearable::readFromAvatar() { LLVOAvatar* avatar = gAgentAvatarp; llassert( avatar ); @@ -828,6 +1238,7 @@ void LLWearable::readFromAvatar() { if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->isTweakable()) ) { + //pretty sure is right if(param->getID() == 507) @@ -836,7 +1247,7 @@ void LLWearable::readFromAvatar() avatar->setActualButtGrav(param->getWeight()); if(param->getID() == 157) avatar->setActualFatGrav(param->getWeight()); - */ + *//* //if(param->getID() == 507) //{ // llwarns << "current = " << avatar->getActualBoobGrav() << llendl; @@ -865,7 +1276,7 @@ void LLWearable::readFromAvatar() //{ // mDescription = gFloaterCustomize->getWearableDescription( mType ); //} -} +}*/ void LLWearable::setLabelUpdated() const @@ -969,31 +1380,24 @@ void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userda // delete the context data delete data; -} -BOOL LLWearable::isMatchedToInventoryItem( LLViewerInventoryItem* item ) -{ - return - ( mName == item->getName() ) && - ( mDescription == item->getDescription() ) && - ( mPermissions == item->getPermissions() ) && - ( mSaleInfo == item->getSaleInfo() ); } std::ostream& operator<<(std::ostream &s, const LLWearable &w) { - s << "wearable " << LLWearableType::getTypeName( w.mType ) << "\n"; + s << "wearable " << LLWearableType::getTypeName(w.mType) << "\n"; s << " Name: " << w.mName << "\n"; s << " Desc: " << w.mDescription << "\n"; //w.mPermissions //w.mSaleInfo s << " Params:" << "\n"; - for (LLWearable::param_map_t::const_iterator iter = w.mVisualParamMap.begin(); - iter != w.mVisualParamMap.end(); ++iter) + for (LLWearable::visual_param_index_map_t::const_iterator iter = w.mVisualParamIndexMap.begin(); + iter != w.mVisualParamIndexMap.end(); ++iter) { S32 param_id = iter->first; - F32 param_weight = iter->second; + LLVisualParam *wearable_param = iter->second; + F32 param_weight = wearable_param->getWeight(); s << " " << param_id << " " << param_weight << "\n"; } @@ -1002,7 +1406,7 @@ std::ostream& operator<<(std::ostream &s, const LLWearable &w) iter != w.mTEMap.end(); ++iter) { S32 te = iter->first; - const LLUUID& image_id = iter->second; + const LLUUID& image_id = iter->second->getID(); s << " " << te << " " << image_id << "\n"; } return s; diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h index 1459f4f6a..9a4d658da 100644 --- a/indra/newview/llwearable.h +++ b/indra/newview/llwearable.h @@ -39,8 +39,13 @@ #include "llsaleinfo.h" #include "llassetstorage.h" #include "llwearabletype.h" +#include "llfile.h" +#include "lllocaltextureobject.h" class LLViewerInventoryItem; +class LLVisualParam; +class LLTexGlobalColorInfo; +class LLTexGlobalColor; class LLWearable { @@ -73,22 +78,24 @@ public: const std::string& getName() const { return mName; } void setName( const std::string& name ) { mName = name; } const std::string& getDescription() const { return mDescription; } - void setDescription( const std::string& desc ) { mDescription = desc; } + void setDescription(const std::string& desc) { mDescription = desc; } const LLPermissions& getPermissions() const { return mPermissions; } - void setPermissions( const LLPermissions& p ) { mPermissions = p; } + void setPermissions(const LLPermissions& p) { mPermissions = p; } const LLSaleInfo& getSaleInfo() const { return mSaleInfo; } - - - void setSaleInfo( const LLSaleInfo& info ) { mSaleInfo = info; } + void setSaleInfo(const LLSaleInfo& info) { mSaleInfo = info; } const std::string& getTypeLabel() const; const std::string& getTypeName() const; LLAssetType::EType getAssetType() const; + S32 getDefinitionVersion() const { return mDefinitionVersion; } + void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; } + +public: + typedef std::vector visual_param_vec_t; BOOL isDirty() const; BOOL isOldVersion() const; - void writeToAvatar( BOOL set_by_user ); - void readFromAvatar(); + void writeToAvatar(); void removeFromAvatar( BOOL upload_bake ) { LLWearable::removeFromAvatar( mType, upload_bake ); } static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ); @@ -101,15 +108,34 @@ public: void saveNewAsset() const; static void onSaveNewAssetComplete( const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status ); - BOOL isMatchedToInventoryItem( LLViewerInventoryItem* item ); - - void copyDataFrom( LLWearable* src ); + void copyDataFrom(const LLWearable* src); static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; } friend std::ostream& operator<<(std::ostream &s, const LLWearable &w); void setItemID(const LLUUID& item_id); + LLLocalTextureObject* getLocalTextureObject(S32 index); + const LLLocalTextureObject* getLocalTextureObject(S32 index) const; + + void setLocalTextureObject(S32 index, LLLocalTextureObject <o); + void addVisualParam(LLVisualParam *param); + void setVisualParams(); + void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); + F32 getVisualParamWeight(S32 index) const; + LLVisualParam* getVisualParam(S32 index) const; + void getVisualParams(visual_param_vec_t &list); + void animateParams(F32 delta, BOOL upload_bake); + + LLColor4 getClothesColor(S32 te) const; + void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); + + void revertValues(); + void saveValues(); + void pullCrossWearableValues(); + + BOOL isOnTop() const; + // Something happened that requires the wearable's label to be updated (e.g. worn/unworn). void setLabelUpdated() const; @@ -118,7 +144,13 @@ public: void refreshName(); private: - typedef std::map te_map_t; + typedef std::map te_map_t; + typedef std::map visual_param_index_map_t; + + void createLayers(S32 te); + void createVisualParams(); + void syncImages(te_map_t &src, te_map_t &dst); + void destroyTextures(); static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. @@ -131,9 +163,12 @@ private: LLWearableType::EType mType; typedef std::map param_map_t; - param_map_t mVisualParamMap; // maps visual param id to weight - - te_map_t mTEMap; // maps TE to Image ID + param_map_t mSavedVisualParamMap; // last saved version of visual params + + visual_param_index_map_t mVisualParamIndexMap; + + te_map_t mTEMap; // maps TE to LocalTextureObject + te_map_t mSavedTEMap; // last saved version of TEMap LLUUID mItemID; // ID of the inventory item in the agent's inventory }; diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 535beb3ad..853375cc2 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -38,10 +38,10 @@ #include "llassetstorage.h" #include "llagent.h" #include "llvoavatar.h" -#include "llviewerinventory.h" -//#include "llfloaterchat.h" #include "llviewerstats.h" #include "llnotificationsutil.h" +#include "llinventorymodel.h" +#include "lltrans.h" // Callback struct struct LLWearableArrivedData @@ -71,7 +71,7 @@ struct LLWearableArrivedData LLWearableList::~LLWearableList() { - llassert_always(mList.empty()) ; + cleanup(); } void LLWearableList::cleanup() @@ -231,7 +231,7 @@ LLWearable* LLWearableList::createWearableMatchedToInventoryItem( LLWearable* ol return wearable; } -LLWearable* LLWearableList::createCopyFromAvatar( LLWearable* old_wearable, const std::string& new_name ) +/*LLWearable* LLWearableList::createCopyFromAvatar( LLWearable* old_wearable, const std::string& new_name ) { lldebugs << "LLWearableList::createCopyFromAvatar()" << llendl; @@ -248,10 +248,10 @@ LLWearable* LLWearableList::createCopyFromAvatar( LLWearable* old_wearable, cons wearable->saveNewAsset(); return wearable; -} +}*/ -LLWearable* LLWearableList::createCopy( LLWearable* old_wearable ) +LLWearable* LLWearableList::createCopy(const LLWearable* old_wearable, const std::string& new_name) { lldebugs << "LLWearableList::createCopy()" << llendl; @@ -262,6 +262,7 @@ LLWearable* LLWearableList::createCopy( LLWearable* old_wearable ) perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true); wearable->setPermissions(perm); + if (!new_name.empty()) wearable->setName(new_name); // Send to the dataserver wearable->saveNewAsset(); @@ -276,8 +277,7 @@ LLWearable* LLWearableList::createNewWearable( LLWearableType::EType type ) LLWearable *wearable = generateNewWearable(); wearable->setType( type ); - std::string name = "New "; - name.append( wearable->getTypeLabel() ); + std::string name = LLWearableType::getTypeDefaultNewName(wearable->getType()); wearable->setName( name ); LLPermissions perm; @@ -289,6 +289,9 @@ LLWearable* LLWearableList::createNewWearable( LLWearableType::EType type ) wearable->setParamsToDefaults(); wearable->setTexturesToDefaults(); + //mark all values (params & images) as saved + wearable->saveValues(); + // Send to the dataserver wearable->saveNewAsset(); diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h index 6f64549ae..7063384f6 100644 --- a/indra/newview/llwearablelist.h +++ b/indra/newview/llwearablelist.h @@ -61,8 +61,8 @@ public: void* userdata); LLWearable* createWearableMatchedToInventoryItem( LLWearable* old_wearable, LLViewerInventoryItem* item ); - LLWearable* createCopyFromAvatar( LLWearable* old_wearable, const std::string& new_name = std::string() ); - LLWearable* createCopy( LLWearable* old_wearable ); + //LLWearable* createCopyFromAvatar( LLWearable* old_wearable, const std::string& new_name = std::string() ); + LLWearable* createCopy(const LLWearable* old_wearable, const std::string& new_name = std::string()); LLWearable* createNewWearable( LLWearableType::EType type ); // Callback diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp index 18507f262..fa27f81ff 100644 --- a/indra/newview/llwearabletype.cpp +++ b/indra/newview/llwearabletype.cpp @@ -26,6 +26,7 @@ #include "llviewerprecompiledheaders.h" #include "llwearabletype.h" +#include "llinventoryfunctions.h" #include "lltrans.h" struct WearableEntry : public LLDictionaryEntry @@ -150,9 +151,9 @@ BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type) // static BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type) { - return false; //Disabled - /*const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); if (!entry) return FALSE; - return entry->mAllowMultiwear;*/ + return entry->mAllowMultiwear; } + diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index db7c27c79..4547d9016 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -1721,7 +1721,7 @@ ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmd.getObjectID()); if ( (pAttachObj) && (pAttachObj->isAttachment()) ) { - LLVOAvatar::detachAttachmentIntoInventory(pAttachObj->getAttachmentItemID()); + LLVOAvatarSelf::detachAttachmentIntoInventory(pAttachObj->getAttachmentItemID()); } } break; diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 3a485d135..9b68ecd62 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -17,6 +17,7 @@ #include "llviewerprecompiledheaders.h" #include "llagent.h" #include "llagentwearables.h" +#include "llappearancemgr.h" #include "llattachmentsmgr.h" #include "llfloaterinventory.h" #include "llfloaterwindlight.h" @@ -39,9 +40,6 @@ #include -// Defined in llinventorybridge.cpp -void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); - // ============================================================================ // RlvCommmand // @@ -830,6 +828,8 @@ void RlvForceWear::done() return; } + LLAppearanceMgr* pAppearanceMgr = LLAppearanceMgr::getInstance(); + // // Process removals // @@ -838,20 +838,16 @@ void RlvForceWear::done() if (m_remWearables.size()) { for (std::list::const_iterator itWearable = m_remWearables.begin(); itWearable != m_remWearables.end(); ++itWearable) - gAgentWearables.removeWearable((*itWearable)->getType(), false, 0); // TODO: MULTI-WEARABLE + pAppearanceMgr->removeItemFromAvatar((*itWearable)->getItemID()); m_remWearables.clear(); } // Gestures if (m_remGestures.size()) { - for (S32 idxGesture = 0, cntGesture = m_remGestures.count(); idxGesture < cntGesture; idxGesture++) - { - LLViewerInventoryItem* pItem = m_remGestures.get(idxGesture); - LLGestureMgr::instance().deactivateGesture(pItem->getUUID()); - gInventory.updateItem(pItem); - gInventory.notifyObservers(); - } + // NOTE: LLGestureMgr::deactivateGesture() will call LLAppearanceMgr::removeCOFItemLinks() for us + for (S32 idxItem = 0, cntItem = m_remGestures.count(); idxItem < cntItem; idxItem++) + LLGestureMgr::instance().deactivateGesture(m_remGestures.get(idxItem)->getUUID()); m_remGestures.clear(); } @@ -871,6 +867,12 @@ void RlvForceWear::done() } gMessageSystem->sendReliable(gAgent.getRegionHost()); + for (std::list::const_iterator itAttachObj = m_remAttachments.begin(); + itAttachObj != m_remAttachments.end(); ++itAttachObj) + { + pAppearanceMgr->removeCOFItemLinks((*itAttachObj)->getAttachmentItemID(), false); + } + m_remAttachments.clear(); } @@ -878,48 +880,24 @@ void RlvForceWear::done() // Process additions // - // Process wearables - if (m_addWearables.size()) + // Wearables need to be split into AT_BODYPART and AT_CLOTHING for COF + LLInventoryModel::item_array_t addBodyParts, addClothing; + for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); itAddWearables != m_addWearables.end(); ++itAddWearables) { - // [See wear_inventory_category_on_avatar_step2()] - LLWearableHoldingPattern* pWearData = new LLWearableHoldingPattern(TRUE); - - // We need to populate 'pWearData->mFoundList' before doing anything else because (some of) the assets might already be available - for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); - itAddWearables != m_addWearables.end(); ++itAddWearables) + const LLInventoryModel::item_array_t& wearItems = itAddWearables->second; + for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++) { - const LLInventoryModel::item_array_t& wearItems = itAddWearables->second; - - RLV_VERIFY(1 == wearItems.count()); - if (wearItems.count() > 0) + LLViewerInventoryItem* pItem = wearItems.get(idxItem); + if (!pAppearanceMgr->isLinkInCOF(pItem->getUUID())) // It's important to examine COF here and *not* gAgentWearables { - LLViewerInventoryItem* pItem = wearItems.get(0); - if ( (pItem) && ((LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType())) ) - { - LLFoundData* pFound = new LLFoundData(pItem->getLinkedUUID(), pItem->getAssetUUID(), pItem->getName(), pItem->getType()); - pWearData->mFoundList.push_front(pFound); - } + if (LLAssetType::AT_BODYPART == pItem->getType()) + addBodyParts.push_back(pItem); + else + addClothing.push_back(pItem); } } - - if (!pWearData->mFoundList.size()) - { - delete pWearData; - return; - } - - // If all the assets are available locally then "pWearData" will be freed *before* the last "LLWearableList::instance().getAsset()" call returns - bool fContinue = true; LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin(); - while ( (fContinue) && (itWearable != pWearData->mFoundList.end()) ) - { - const LLFoundData* pFound = *itWearable; - ++itWearable; - fContinue = (itWearable != pWearData->mFoundList.end()); - LLWearableList::instance().getAsset(pFound->mAssetID, pFound->mName, pFound->mAssetType, wear_inventory_category_on_avatar_loop, (void*)pWearData); - } - - m_addWearables.clear(); } + m_addWearables.clear(); // Until LL provides a way for updateCOF to selectively attach add/replace we have to deal with attachments ourselves for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); @@ -929,22 +907,20 @@ void RlvForceWear::done() for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++) { const LLUUID& idItem = wearItems.get(idxItem)->getLinkedUUID(); -// if (gAgentAvatarp->attachmentWasRequested(idItem)) -// continue; -// gAgentAvatarp->addAttachmentRequest(idItem); + if (gAgentAvatarp->attachmentWasRequested(idItem)) + continue; + gAgentAvatarp->addAttachmentRequest(idItem); LLAttachmentsMgr::instance().addAttachment(idItem, itAddAttachments->first & ~ATTACHMENT_ADD, itAddAttachments->first & ATTACHMENT_ADD); } } m_addAttachments.clear(); - // Process gestures - if (m_addGestures.size()) + // If there are additions we need to call LLAppearanceManager::updateCOF(), otherwise LLAppearanceManager::updateAppearanceFromCOF() + if ( (!addBodyParts.empty()) || (!addClothing.empty()) || (!m_addGestures.empty()) ) { - LLGestureMgr::instance().activateGestures(m_addGestures); - for (S32 idxGesture = 0, cntGesture = m_addGestures.count(); idxGesture < cntGesture; idxGesture++) - gInventory.updateItem(m_addGestures.get(idxGesture)); - gInventory.notifyObservers(); + LLInventoryModel::item_array_t addAttachments; + pAppearanceMgr->updateCOF(addBodyParts, addClothing, addAttachments, m_addGestures, true); m_addGestures.clear(); } diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp index b9271540b..43cebb6d3 100644 --- a/indra/newview/rlvinventory.cpp +++ b/indra/newview/rlvinventory.cpp @@ -200,16 +200,6 @@ void RlvInventory::fetchWornItems() itemFetcher.startFetch(); } -// Checked: 2010-09-27 (RLVa-1.1.3a) | Added: RLVa-1.1.3a -void RlvInventory::fetchWornItem(const LLUUID& idItem) -{ - if (idItem.notNull()) - { - RlvItemFetcher itemFetcher(idItem); - itemFetcher.startFetch(); - } -} - // Checked: 2010-04-07 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h bool RlvInventory::findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const { diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h index c1d648420..11ca8491d 100644 --- a/indra/newview/rlvinventory.h +++ b/indra/newview/rlvinventory.h @@ -66,7 +66,6 @@ public: public: void fetchSharedInventory(); void fetchWornItems(); - void fetchWornItem(const LLUUID& idItem); protected: void fetchSharedLinks(); diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp index 471e48858..9e7886aad 100644 --- a/indra/newview/rlvlocks.cpp +++ b/indra/newview/rlvlocks.cpp @@ -15,15 +15,17 @@ */ #include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llappearancemgr.h" #include "llattachmentsmgr.h" +#include "llinventoryobserver.h" +#include "lloutfitobserver.h" #include "llviewerobjectlist.h" #include "pipeline.h" -#include "cofmgr.h" -#include "llagentwearables.h" +#include "rlvlocks.h" #include "rlvhelper.h" #include "rlvinventory.h" -#include "rlvlocks.h" // ============================================================================ // RlvAttachPtLookup member functions @@ -1023,7 +1025,7 @@ protected: RlvFolderLocks::RlvFolderLocks() : m_fLookupDirty(false), m_fLockedRoot(false) { - LLCOFObserver::instance().addCOFChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); + LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); RlvInventory::instance().addSharedRootIDChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); } @@ -1272,7 +1274,7 @@ void RlvFolderLocks::refreshLockedLookups() const m_LockedWearableRem.clear(); LLInventoryModel::item_array_t lockedItems; - if (getLockedItems(LLCOFMgr::instance().getCOF(), lockedItems, true)) + if (getLockedItems(LLAppearanceMgr::instance().getCOF(), lockedItems, true)) { for (S32 idxItem = 0, cntItem = lockedItems.count(); idxItem < cntItem; idxItem++) { diff --git a/indra/newview/rlvviewer2.cpp b/indra/newview/rlvviewer2.cpp index 80c54812e..38268f1fc 100644 --- a/indra/newview/rlvviewer2.cpp +++ b/indra/newview/rlvviewer2.cpp @@ -26,106 +26,4 @@ #include "llgesturemgr.h" #include "llviewerinventory.h" #include "llvoavatar.h" -#include "cofmgr.h" #include "rlvviewer2.h" - -// ============================================================================ -// From lloutfitobserver.cpp - -LLCOFObserver::LLCOFObserver() : - mCOFLastVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) -{ - mItemNameHash.finalize(); - gInventory.addObserver(this); -} - -LLCOFObserver::~LLCOFObserver() -{ - if (gInventory.containsObserver(this)) - { - gInventory.removeObserver(this); - } -} - -void LLCOFObserver::changed(U32 mask) -{ - if (!gInventory.isInventoryUsable()) - return; - - checkCOF(); -} - -// static -S32 LLCOFObserver::getCategoryVersion(const LLUUID& cat_id) -{ - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - if (!cat) - return LLViewerInventoryCategory::VERSION_UNKNOWN; - - return cat->getVersion(); -} - -// static -const std::string& LLCOFObserver::getCategoryName(const LLUUID& cat_id) -{ - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - if (!cat) - return LLStringUtil::null; - - return cat->getName(); -} - -bool LLCOFObserver::checkCOF() -{ - LLUUID cof = LLCOFMgr::getInstance()->getCOF(); - if (cof.isNull()) - return false; - - bool cof_changed = false; - LLMD5 item_name_hash = hashDirectDescendentNames(cof); - if (item_name_hash != mItemNameHash) - { - cof_changed = true; - mItemNameHash = item_name_hash; - } - - S32 cof_version = getCategoryVersion(cof); - if (cof_version != mCOFLastVersion) - { - cof_changed = true; - mCOFLastVersion = cof_version; - } - - if (!cof_changed) - return false; - - mCOFChanged(); - - return true; -} - -LLMD5 LLCOFObserver::hashDirectDescendentNames(const LLUUID& cat_id) -{ - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - LLMD5 item_name_hash; - if (!item_array) - { - item_name_hash.finalize(); - return item_name_hash; - } - for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); - iter != item_array->end(); - iter++) - { - const LLViewerInventoryItem *item = (*iter); - if (!item) - continue; - item_name_hash.update(item->getName()); - } - item_name_hash.finalize(); - return item_name_hash; -} - -// ============================================================================ diff --git a/indra/newview/rlvviewer2.h b/indra/newview/rlvviewer2.h index f61b2409d..6d7442025 100644 --- a/indra/newview/rlvviewer2.h +++ b/indra/newview/rlvviewer2.h @@ -29,35 +29,4 @@ #include "boost/function.hpp" -// ============================================================================ -// From lloutfitobserver.h - -class LLCOFObserver : public LLInventoryObserver, public LLSingleton -{ - friend class LLSingleton; -protected: - LLCOFObserver(); -public: - virtual ~LLCOFObserver(); - - virtual void changed(U32 mask); - - typedef boost::signals2::signal signal_t; - void addCOFChangedCallback(const signal_t::slot_type& cb) { mCOFChanged.connect(cb); } - void addCOFSavedCallback(const signal_t::slot_type& cb) { mCOFSaved.connect(cb); } - -protected: - bool checkCOF(); - static S32 getCategoryVersion(const LLUUID& cat_id); - static const std::string& getCategoryName(const LLUUID& cat_id); - static LLMD5 hashDirectDescendentNames(const LLUUID& cat_id); - -private: - signal_t mCOFChanged; - signal_t mCOFSaved; - S32 mCOFLastVersion; - LLMD5 mItemNameHash; -}; - - #endif // RLV_VIEWER2_H diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 37f0f9d21..2cf58f0bf 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -274,13 +274,13 @@ name="Deactivate" width="128"> - + + name="Wearable And Object Wear" width="128"> + name="Wearable Add" width="128"> + +At least one of the items you has link items that point to it. If you delete this item, its links will permanently stop working. It is strongly advised to delete the links first. + +Are you sure you want to delete these items? + + + + +The folder '[FOLDERNAME]' is a system folder. Deleting system folders can cause instability. Are you sure you want to delete it? + + + Press ESC to return to World View + + + + + + + + + + Loading contents... + No contents + + + Stone Metal Glass From 1810a7c7f917ee4d4f26ee95b5faec593651911f Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 18 Feb 2012 01:58:02 -0600 Subject: [PATCH 03/32] Updated LLFocusMgr to use boost::signals2 instead of vanilla function pointers. Also removed top-focus handling from lluictrl because it doesn't belong there. --- indra/llui/llcombobox.cpp | 22 +-- indra/llui/llcombobox.h | 2 +- indra/llui/llfocusmgr.cpp | 248 +++++++++++++++----------- indra/llui/llfocusmgr.h | 77 ++++---- indra/llui/lllineeditor.cpp | 3 +- indra/llui/llmultisliderctrl.cpp | 12 +- indra/llui/llmultisliderctrl.h | 1 - indra/llui/llpanel.cpp | 10 -- indra/llui/llpanel.h | 1 - indra/llui/llscrollcontainer.cpp | 17 ++ indra/llui/llscrollcontainer.h | 3 +- indra/llui/llsliderctrl.cpp | 13 +- indra/llui/llsliderctrl.h | 1 - indra/llui/llspinctrl.cpp | 11 +- indra/llui/llspinctrl.h | 1 - indra/llui/lluictrl.cpp | 11 -- indra/llui/lluictrl.h | 3 - indra/llui/llview.cpp | 22 ++- indra/llui/llview.h | 2 + indra/newview/llchatbar.cpp | 8 +- indra/newview/llchatbar.h | 4 +- indra/newview/llfloaterland.cpp | 2 +- indra/newview/llfloaterlandmark.cpp | 2 +- indra/newview/llfloaterpostcard.cpp | 15 +- indra/newview/llfloaterpostcard.h | 2 +- indra/newview/llfloaterworldmap.cpp | 27 ++- indra/newview/llfloaterworldmap.h | 4 +- indra/newview/llfolderview.cpp | 8 +- indra/newview/llfolderview.h | 2 +- indra/newview/llimpanel.cpp | 21 +-- indra/newview/llimpanel.h | 8 +- indra/newview/llpanelclassified.cpp | 4 +- indra/newview/llpanelgroupgeneral.cpp | 13 +- indra/newview/llpanelgroupgeneral.h | 2 +- indra/newview/llpanelgrouproles.cpp | 12 +- indra/newview/llpanelgrouproles.h | 2 +- indra/newview/llpanellogin.cpp | 15 +- indra/newview/llpanellogin.h | 3 +- 38 files changed, 298 insertions(+), 316 deletions(-) diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 507414958..a54b8deed 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -110,13 +110,11 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std:: mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT); updateLayout(); + + mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this)); } -LLComboBox::~LLComboBox() -{ - // children automatically deleted, including mMenu, mButton -} // virtual LLXMLNodePtr LLComboBox::getXML(bool save_children) const @@ -228,6 +226,16 @@ void LLComboBox::setEnabled(BOOL enabled) mButton->setEnabled(enabled); } + +LLComboBox::~LLComboBox() +{ + // children automatically deleted, including mMenu, mButton + + // explicitly disconect this signal, since base class destructor might fire top lost + mTopLostSignalConnection.disconnect(); +} + + void LLComboBox::clear() { if (mTextEntry) @@ -481,12 +489,6 @@ void LLComboBox::onFocusLost() LLUICtrl::onFocusLost(); } -void LLComboBox::onLostTop() -{ - hideList(); -} - - void LLComboBox::setButtonVisible(BOOL visible) { mButton->setVisible(visible); diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 3ed035187..a1be4cab3 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -80,7 +80,6 @@ public: virtual void draw(); virtual void onFocusLost(); - virtual void onLostTop(); virtual void setEnabled(BOOL enabled); @@ -212,6 +211,7 @@ private: bool mSuppressTentative; void (*mPrearrangeCallback)(LLUICtrl*,void*); void (*mTextEntryCallback)(LLLineEditor*, void*); + boost::signals2::connection mTopLostSignalConnection; }; class LLFlyoutButton : public LLComboBox diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 96b01b98f..66834a6a1 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -2,31 +2,25 @@ * @file llfocusmgr.cpp * @brief LLFocusMgr base class * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,13 +32,11 @@ const F32 FOCUS_FADE_TIME = 0.3f; -// NOTE: the LLFocusableElement implementation has been here from lluictrl.cpp. - LLFocusableElement::LLFocusableElement() : mFocusLostCallback(NULL), mFocusReceivedCallback(NULL), mFocusChangedCallback(NULL), - mFocusCallbackUserData(NULL) + mTopLostCallback(NULL) { } @@ -63,31 +55,27 @@ BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_pa // virtual LLFocusableElement::~LLFocusableElement() { + delete mFocusLostCallback; + delete mFocusReceivedCallback; + delete mFocusChangedCallback; + delete mTopLostCallback; } void LLFocusableElement::onFocusReceived() { - if( mFocusReceivedCallback ) - { - mFocusReceivedCallback( this, mFocusCallbackUserData ); - } - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } + if (mFocusReceivedCallback) (*mFocusReceivedCallback)(this); + if (mFocusChangedCallback) (*mFocusChangedCallback)(this); } void LLFocusableElement::onFocusLost() { - if( mFocusLostCallback ) - { - mFocusLostCallback( this, mFocusCallbackUserData ); - } + if (mFocusLostCallback) (*mFocusLostCallback)(this); + if (mFocusChangedCallback) (*mFocusChangedCallback)(this); +} - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } +void LLFocusableElement::onTopLost() +{ + if (mTopLostCallback) (*mTopLostCallback)(this); } BOOL LLFocusableElement::hasFocus() const @@ -99,28 +87,63 @@ void LLFocusableElement::setFocus(BOOL b) { } +boost::signals2::connection LLFocusableElement::setFocusLostCallback( const focus_signal_t::slot_type& cb) +{ + if (!mFocusLostCallback) mFocusLostCallback = new focus_signal_t(); + return mFocusLostCallback->connect(cb); +} + +boost::signals2::connection LLFocusableElement::setFocusReceivedCallback(const focus_signal_t::slot_type& cb) +{ + if (!mFocusReceivedCallback) mFocusReceivedCallback = new focus_signal_t(); + return mFocusReceivedCallback->connect(cb); +} + +boost::signals2::connection LLFocusableElement::setFocusChangedCallback(const focus_signal_t::slot_type& cb) +{ + if (!mFocusChangedCallback) mFocusChangedCallback = new focus_signal_t(); + return mFocusChangedCallback->connect(cb); +} + +boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_signal_t::slot_type& cb) +{ + if (!mTopLostCallback) mTopLostCallback = new focus_signal_t(); + return mTopLostCallback->connect(cb); +} + + + +typedef std::list > view_handle_list_t; +typedef std::map, LLHandle > focus_history_map_t; +struct LLFocusMgr::Impl +{ + // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost + view_handle_list_t mCachedKeyboardFocusList; + + focus_history_map_t mFocusHistory; +}; LLFocusMgr gFocusMgr; LLFocusMgr::LLFocusMgr() - : - mLockedView( NULL ), +: mLockedView( NULL ), mMouseCaptor( NULL ), mKeyboardFocus( NULL ), mLastKeyboardFocus( NULL ), mDefaultKeyboardFocus( NULL ), mKeystrokesOnly(FALSE), mTopCtrl( NULL ), - mFocusWeight(0.f), - mAppHasFocus(TRUE) // Macs don't seem to notify us that we've gotten focus, so default to true - #ifdef _DEBUG - , mMouseCaptorName("none") - , mKeyboardFocusName("none") - , mTopCtrlName("none") - #endif + mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true + mImpl(new LLFocusMgr::Impl) { } +LLFocusMgr::~LLFocusMgr() +{ + mImpl->mFocusHistory.clear(); + delete mImpl; + mImpl = NULL; +} void LLFocusMgr::releaseFocusIfNeeded( const LLView* view ) { @@ -151,6 +174,12 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view ) void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only) { + // notes if keyboard focus is changed again (by onFocusLost/onFocusReceived) + // making the rest of our processing unnecessary since it will already be + // handled by the recursive call + static bool focus_dirty; + focus_dirty = false; + if (mLockedView && (new_focus == NULL || (new_focus != mLockedView @@ -162,8 +191,6 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL return; } - //llinfos << "Keyboard focus handled by " << (new_focus ? new_focus->getName() : "nothing") << llendl; - mKeystrokesOnly = keystrokes_only; if( new_focus != mKeyboardFocus ) @@ -171,23 +198,58 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL mLastKeyboardFocus = mKeyboardFocus; mKeyboardFocus = new_focus; - if( mLastKeyboardFocus ) + // list of the focus and it's ancestors + view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList; + view_handle_list_t new_focus_list; + + // walk up the tree to root and add all views to the new_focus_list + for (LLView* ctrl = dynamic_cast(mKeyboardFocus); ctrl; ctrl = ctrl->getParent()) { - mLastKeyboardFocus->onFocusLost(); + new_focus_list.push_back(ctrl->getHandle()); } - // clear out any existing flash - if (new_focus) + // remove all common ancestors since their focus is unchanged + while (!new_focus_list.empty() && + !old_focus_list.empty() && + new_focus_list.back() == old_focus_list.back()) { - mFocusWeight = 0.f; - new_focus->onFocusReceived(); + new_focus_list.pop_back(); + old_focus_list.pop_back(); } - mFocusTimer.reset(); - #ifdef _DEBUG - LLUICtrl* focus_ctrl = dynamic_cast(new_focus); - mKeyboardFocusName = focus_ctrl ? focus_ctrl->getName() : std::string("none"); - #endif + // walk up the old focus branch calling onFocusLost + // we bubble up the tree to release focus, and back down to add + for (view_handle_list_t::iterator old_focus_iter = old_focus_list.begin(); + old_focus_iter != old_focus_list.end() && !focus_dirty; + old_focus_iter++) + { + LLView* old_focus_view = old_focus_iter->get(); + if (old_focus_view) + { + mImpl->mCachedKeyboardFocusList.pop_front(); + old_focus_view->onFocusLost(); + } + } + + // walk down the new focus branch calling onFocusReceived + for (view_handle_list_t::reverse_iterator new_focus_riter = new_focus_list.rbegin(); + new_focus_riter != new_focus_list.rend() && !focus_dirty; + new_focus_riter++) + { + LLView* new_focus_view = new_focus_riter->get(); + if (new_focus_view) + { + mImpl->mCachedKeyboardFocusList.push_front(new_focus_view->getHandle()); + new_focus_view->onFocusReceived(); + } + } + + // if focus was changed as part of an onFocusLost or onFocusReceived call + // stop iterating on current list since it is now invalid + if (focus_dirty) + { + return; + } // If we've got a default keyboard focus, and the caller is // releasing keyboard focus, move to the default. @@ -212,7 +274,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL if (focus_subtree) { LLView* focused_view = dynamic_cast(mKeyboardFocus); - mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle(); + mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle(); } } @@ -220,6 +282,8 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL { lockFocus(); } + + focus_dirty = true; } @@ -241,7 +305,7 @@ BOOL LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const // Returns TRUE is parent or any descedent of parent is the mouse captor. BOOL LLFocusMgr::childHasMouseCapture( const LLView* parent ) const { - if( mMouseCaptor && mMouseCaptor->isView() ) + if( mMouseCaptor && dynamic_cast(mMouseCaptor) != NULL ) { LLView* captor_view = (LLView*)mMouseCaptor; while( captor_view ) @@ -268,65 +332,42 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f if( mKeyboardFocus == focus ) { mKeyboardFocus = NULL; - #ifdef _DEBUG - mKeyboardFocusName = std::string("none"); - #endif } } void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor ) { - //if (mFocusLocked) - //{ - // return; - //} - if( new_captor != mMouseCaptor ) { LLMouseHandler* old_captor = mMouseCaptor; mMouseCaptor = new_captor; - /* - if (new_captor) + + if (LLView::sDebugMouseHandling) { - if ( new_captor->getName() == "Stickto") + if (new_captor) { llinfos << "New mouse captor: " << new_captor->getName() << llendl; } else { - llinfos << "New mouse captor: " << new_captor->getName() << llendl; + llinfos << "New mouse captor: NULL" << llendl; } } - else - { - llinfos << "New mouse captor: NULL" << llendl; - } - */ - + if( old_captor ) { old_captor->onMouseCaptureLost(); } - #ifdef _DEBUG - mMouseCaptorName = new_captor ? new_captor->getName() : std::string("none"); - #endif } } void LLFocusMgr::removeMouseCaptureWithoutCallback( const LLMouseHandler* captor ) { - //if (mFocusLocked) - //{ - // return; - //} if( mMouseCaptor == captor ) { mMouseCaptor = NULL; - #ifdef _DEBUG - mMouseCaptorName = std::string("none"); - #endif } } @@ -355,13 +396,9 @@ void LLFocusMgr::setTopCtrl( LLUICtrl* new_top ) { mTopCtrl = new_top; - #ifdef _DEBUG - mTopCtrlName = new_top ? new_top->getName() : std::string("none"); - #endif - if (old_top) { - old_top->onLostTop(); + old_top->onTopLost(); } } } @@ -371,9 +408,6 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view ) if( mTopCtrl == top_view ) { mTopCtrl = NULL; - #ifdef _DEBUG - mTopCtrlName = std::string("none"); - #endif } } @@ -389,12 +423,13 @@ void LLFocusMgr::unlockFocus() F32 LLFocusMgr::getFocusFlashAmt() const { - return clamp_rescale(getFocusTime(), 0.f, FOCUS_FADE_TIME, mFocusWeight, 0.f); + return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f); } LLColor4 LLFocusMgr::getFocusColor() const { - LLColor4 focus_color = lerp(LLUI::sColorsGroup->getColor( "FocusColor" ), LLColor4::white, getFocusFlashAmt()); + static LLCachedControl focus_color_cached(*LLUI::sColorsGroup,"FocusColor", LLColor4::white); + LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt()); // de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem) if (!mAppHasFocus) { @@ -405,8 +440,7 @@ LLColor4 LLFocusMgr::getFocusColor() const void LLFocusMgr::triggerFocusFlash() { - mFocusTimer.reset(); - mFocusWeight = 1.f; + mFocusFlashTimer.reset(); } void LLFocusMgr::setAppHasFocus(BOOL focus) @@ -428,8 +462,8 @@ LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const { if (subtree_root) { - focus_history_map_t::const_iterator found_it = mFocusHistory.find(subtree_root->getHandle()); - if (found_it != mFocusHistory.end()) + focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle()); + if (found_it != mImpl->mFocusHistory.end()) { // found last focus for this subtree return static_cast(found_it->second.get()); @@ -442,6 +476,6 @@ void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root) { if (subtree_root) { - mFocusHistory.erase(subtree_root->getHandle()); + mImpl->mFocusHistory.erase(subtree_root->getHandle()); } } diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index ce0c75063..14c711b5e 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -2,31 +2,25 @@ * @file llfocusmgr.h * @brief LLFocusMgr base class * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,12 +32,12 @@ #include "llstring.h" #include "llframetimer.h" #include "llui.h" -#include "llhandle.h" class LLUICtrl; class LLMouseHandler; class LLView; +// NOTE: the LLFocusableElement class declaration has been moved here from lluictrl.h. class LLFocusableElement { friend class LLFocusMgr; // allow access to focus change handlers @@ -54,21 +48,25 @@ public: virtual void setFocus( BOOL b ); virtual BOOL hasFocus() const; - void setFocusLostCallback(void (*cb)(LLFocusableElement* caller, void*), void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusReceivedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL) { mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusChangedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL ) { mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; } + typedef boost::signals2::signal focus_signal_t; + + boost::signals2::connection setFocusLostCallback( const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusChangedCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setTopLostCallback(const focus_signal_t::slot_type& cb); // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere protected: virtual void onFocusReceived(); virtual void onFocusLost(); - void (*mFocusLostCallback)( LLFocusableElement* caller, void* userdata ); - void (*mFocusReceivedCallback)( LLFocusableElement* ctrl, void* userdata ); - void (*mFocusChangedCallback)( LLFocusableElement* ctrl, void* userdata ); - void* mFocusCallbackUserData; + focus_signal_t* mFocusLostCallback; + focus_signal_t* mFocusReceivedCallback; + focus_signal_t* mFocusChangedCallback; + focus_signal_t* mTopLostCallback; }; @@ -76,7 +74,7 @@ class LLFocusMgr { public: LLFocusMgr(); - ~LLFocusMgr() { mFocusHistory.clear(); } + ~LLFocusMgr(); // Mouse Captor void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse. @@ -93,7 +91,7 @@ public: BOOL getKeystrokesOnly() { return mKeystrokesOnly; } void setKeystrokesOnly(BOOL keystrokes_only) { mKeystrokesOnly = keystrokes_only; } - F32 getFocusTime() const { return mFocusTimer.getElapsedTimeF32(); } + F32 getFocusTime() const { return mFocusFlashTimer.getElapsedTimeF32(); } F32 getFocusFlashAmt() const; S32 getFocusFlashWidth() const { return llround(lerp(1.f, 3.f, getFocusFlashAmt())); } LLColor4 getFocusColor() const; @@ -121,6 +119,9 @@ public: void unlockFocus(); BOOL focusLocked() const { return mLockedView != NULL; } + + struct Impl; + private: LLUICtrl* mLockedView; @@ -132,23 +133,15 @@ private: LLFocusableElement* mLastKeyboardFocus; // who last had focus LLFocusableElement* mDefaultKeyboardFocus; BOOL mKeystrokesOnly; - + // Top View LLUICtrl* mTopCtrl; - LLFrameTimer mFocusTimer; - F32 mFocusWeight; + LLFrameTimer mFocusFlashTimer; BOOL mAppHasFocus; - typedef std::map, LLHandle > focus_history_map_t; - focus_history_map_t mFocusHistory; - - #ifdef _DEBUG - std::string mMouseCaptorName; - std::string mKeyboardFocusName; - std::string mTopCtrlName; - #endif + Impl * mImpl; }; extern LLFocusMgr gFocusMgr; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 60f8f9934..9caaf70fd 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -156,7 +156,8 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, mGLFont = LLFontGL::getFontSansSerifSmall(); } - setFocusLostCallback(focus_lost_callback); + if(focus_lost_callback) + setFocusLostCallback(boost::bind(focus_lost_callback,_1,(void*)NULL)); setTextPadding(0, 0); diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index b8ebb3d6b..c3a0f5a6b 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -127,7 +127,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const std::string& name, const LLRect& rect &LLLineEditor::prevalidateFloat ); mEditor->setFollowsLeft(); mEditor->setFollowsBottom(); - mEditor->setFocusReceivedCallback( &LLMultiSliderCtrl::onEditorGainFocus, this ); + mEditor->setFocusReceivedCallback( boost::bind(&LLMultiSliderCtrl::onFocusReceived, this) ); mEditor->setIgnoreTab(TRUE); // don't do this, as selecting the entire text is single clicking in some cases // and double clicking in others @@ -151,16 +151,6 @@ LLMultiSliderCtrl::~LLMultiSliderCtrl() // Children all cleaned up by default view destructor. } -// static -void LLMultiSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) -{ - LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; - llassert( caller == self->mEditor ); - - self->onFocusReceived(); -} - - void LLMultiSliderCtrl::setValue(const LLSD& value) { mMultiSlider->setValue(value); diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h index 47b1d1fb1..05e15178c 100644 --- a/indra/llui/llmultisliderctrl.h +++ b/indra/llui/llmultisliderctrl.h @@ -126,7 +126,6 @@ public: static void onSliderCommit(LLUICtrl* caller, void* userdata); static void onEditorCommit(LLUICtrl* ctrl, void* userdata); - static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); private: diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 9dc217e21..ea8b72ba9 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -760,16 +760,6 @@ BOOL LLPanel::childHasFocus(const std::string& id) } } - -void LLPanel::childSetFocusChangedCallback(const std::string& id, void (*cb)(LLFocusableElement*, void*), void* user_data) -{ - LLUICtrl* child = getChild(id, true); - if (child) - { - child->setFocusChangedCallback(cb, user_data); - } -} - void LLPanel::childSetCommitCallback(const std::string& id, void (*cb)(LLUICtrl*, void*), void *userdata ) { LLUICtrl* child = getChild(id, true); diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index f6373f71c..317efbc40 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -170,7 +170,6 @@ public: // LLUICtrl void childSetFocus(const std::string& id, BOOL focus = TRUE); BOOL childHasFocus(const std::string& id); - void childSetFocusChangedCallback(const std::string& id, void (*cb)(LLFocusableElement*, void*), void* user_data = NULL); void childSetCommitCallback(const std::string& id, void (*cb)(LLUICtrl*, void*), void* userdata = NULL ); void childSetDoubleClickCallback(const std::string& id, void (*cb)(void*), void* userdata = NULL ); diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 28890b199..7af52ce2a 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -578,6 +578,23 @@ void LLScrollableContainerView::setBorderVisible(BOOL b) mBorder->setVisible( b ); } +LLRect LLScrollableContainerView::getContentWindowRect() +{ + updateScroll(); + LLRect scroller_view_rect; + S32 visible_width = 0; + S32 visible_height = 0; + BOOL show_h_scrollbar = FALSE; + BOOL show_v_scrollbar = FALSE; + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + S32 border_width = mBorder->getBorderWidth(); + scroller_view_rect.setOriginAndSize(border_width, + show_h_scrollbar ? mScrollbar[HORIZONTAL]->getRect().mTop : border_width, + visible_width, + visible_height); + return scroller_view_rect; +} + // Scroll so that as much of rect as possible is showing (where rect is defined in the space of scroller view, not scrolled) void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLCoordGL& desired_offset) { diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 70fc9087d..7aa08ce06 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -78,7 +78,8 @@ public: void scrollToShowRect( const LLRect& rect, const LLCoordGL& desired_offset ); void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; } - const LLRect& getScrolledViewRect() const { return mScrolledView->getRect(); } + LLRect getContentWindowRect(); + const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } void pageUp(S32 overlap = 0); void pageDown(S32 overlap = 0); void goToTop(); diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 60907fd58..41c4c0560 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -121,7 +121,7 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, &LLLineEditor::prevalidateFloat ); mEditor->setFollowsLeft(); mEditor->setFollowsBottom(); - mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus, this ); + mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onFocusReceived, this) ); mEditor->setIgnoreTab(TRUE); // don't do this, as selecting the entire text is single clicking in some cases // and double clicking in others @@ -140,17 +140,6 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, updateText(); } - -// static -void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) -{ - LLSliderCtrl* self = (LLSliderCtrl*) userdata; - llassert( caller == self->mEditor ); - - self->onFocusReceived(); -} - - void LLSliderCtrl::setValue(F32 v, BOOL from_event) { mSlider->setValue( v, from_event ); diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index 68748eb4d..f7c321235 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -117,7 +117,6 @@ public: static void onSliderCommit(LLUICtrl* caller, void* userdata); static void onEditorCommit(LLUICtrl* caller, void* userdata); - static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); private: diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index ce13a2697..e3a659e86 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -126,7 +126,7 @@ LLSpinCtrl::LLSpinCtrl( const std::string& name, const LLRect& rect, const std:: &LLLineEditor::prevalidateASCII ); mEditor->setFollowsLeft(); mEditor->setFollowsBottom(); - mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this ); + mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onFocusReceived, this) ); //RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus // than when it doesn't. Instead, if you always have to double click to select all the text, // it's easier to understand @@ -243,15 +243,6 @@ void LLSpinCtrl::onDownBtn( void *userdata ) } } -// static -void LLSpinCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) -{ - LLSpinCtrl* self = (LLSpinCtrl*) userdata; - llassert( caller == self->mEditor ); - - self->onFocusReceived(); -} - void LLSpinCtrl::setValue(const LLSD& value ) { F32 v = (F32)value.asReal(); diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h index b9d94e57c..9e53c362f 100644 --- a/indra/llui/llspinctrl.h +++ b/indra/llui/llspinctrl.h @@ -110,7 +110,6 @@ public: virtual void draw(); static void onEditorCommit(LLUICtrl* caller, void* userdata); - static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); static void onUpBtn(void *userdata); diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 49767a547..0fd4c908f 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -45,7 +45,6 @@ LLUICtrl::LLUICtrl() : mCommitSignal(NULL), mValidateSignal(NULL), mCommitCallback(NULL), - mLostTopCallback(NULL), mValidateCallback(NULL), mCallbackUserData(NULL), mTentative(FALSE), @@ -64,7 +63,6 @@ LLUICtrl::LLUICtrl(const std::string& name, const LLRect& rect, BOOL mouse_opaqu mCommitSignal(NULL), mValidateSignal(NULL), mCommitCallback( on_commit_callback), - mLostTopCallback( NULL ), mValidateCallback( NULL ), mCallbackUserData( callback_userdata ), mTentative( FALSE ), @@ -210,15 +208,6 @@ void LLUICtrl::onFocusLost() } } -void LLUICtrl::onLostTop() -{ - if (mLostTopCallback) - { - mLostTopCallback(this, mCallbackUserData); - } -} - - // virtual void LLUICtrl::setTabStop( BOOL b ) { diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 519b45c0b..66dc12637 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -89,7 +89,6 @@ public: virtual void resetDirty(); //Defaults to no-op // Call appropriate callbacks - virtual void onLostTop(); // called when registered as top ctrl and user clicks elsewhere virtual void onCommit(); // Default to no-op: @@ -125,7 +124,6 @@ public: void setCommitCallback( void (*cb)(LLUICtrl*, void*) ) { mCommitCallback = cb; } void setValidateBeforeCommit( BOOL(*cb)(LLUICtrl*, void*) ) { mValidateCallback = cb; } - void setLostTopCallback( void (*cb)(LLUICtrl*, void*) ) { mLostTopCallback = cb; } static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory); @@ -144,7 +142,6 @@ protected: commit_signal_t* mCommitSignal; enable_signal_t* mValidateSignal; void (*mCommitCallback)( LLUICtrl* ctrl, void* userdata ); - void (*mLostTopCallback)( LLUICtrl* ctrl, void* userdata ); BOOL (*mValidateCallback)( LLUICtrl* ctrl, void* userdata ); void* mCallbackUserData; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 61030a8f1..b357ebaf2 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1787,6 +1787,7 @@ LLView* LLView::getRootView() return view; } + BOOL LLView::deleteViewByHandle(LLHandle handle) { LLView* viewp = handle.get(); @@ -1801,9 +1802,26 @@ BOOL LLView::deleteViewByHandle(LLHandle handle) return viewp != NULL; } +LLView* LLView::findPrevSibling(LLView* child) +{ + child_list_t::iterator prev_it = std::find(mChildList.begin(), mChildList.end(), child); + if (prev_it != mChildList.end() && prev_it != mChildList.begin()) + { + return *(--prev_it); + } + return NULL; +} -// Moves the view so that it is entirely inside of constraint. -// If the view will not fit because it's too big, aligns with the top and left. +LLView* LLView::findNextSibling(LLView* child) +{ + child_list_t::iterator next_it = std::find(mChildList.begin(), mChildList.end(), child); + if (next_it != mChildList.end()) + { + next_it++; + } + + return (next_it != mChildList.end()) ? *next_it : NULL; +} // (Why top and left? That's where the drag bars are for floaters.) BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside ) { diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 524dba010..6d156464f 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -372,6 +372,8 @@ public: LLView* getRootView(); LLView* getParent() const { return mParentView; } LLView* getFirstChild() const { return (mChildList.empty()) ? NULL : *(mChildList.begin()); } + LLView* findPrevSibling(LLView* child); + LLView* findNextSibling(LLView* child); S32 getChildCount() const { return (S32)mChildList.size(); } template void sortChildren(_Pr3 _Pred) { mChildList.sort(_Pred); } BOOL hasAncestor(const LLView* parentp) const; diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index ef1413954..b91ad1f4d 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -153,8 +153,8 @@ BOOL LLChatBar::postBuild() { mInputEditor->setCallbackUserData(this); mInputEditor->setKeystrokeCallback(&onInputEditorKeystroke); - mInputEditor->setFocusLostCallback(&onInputEditorFocusLost, this); - mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus, this ); + mInputEditor->setFocusLostCallback(boost::bind(&LLChatBar::onInputEditorFocusLost)); + mInputEditor->setFocusReceivedCallback(boost::bind(&LLChatBar::onInputEditorGainFocus)); mInputEditor->setCommitOnFocusLost( FALSE ); mInputEditor->setRevertOnEsc( FALSE ); mInputEditor->setIgnoreTab(TRUE); @@ -623,14 +623,14 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata ) } // static -void LLChatBar::onInputEditorFocusLost( LLFocusableElement* caller, void* userdata) +void LLChatBar::onInputEditorFocusLost() { // stop typing animation gAgent.stopTyping(); } // static -void LLChatBar::onInputEditorGainFocus( LLFocusableElement* caller, void* userdata ) +void LLChatBar::onInputEditorGainFocus() { LLFloaterChat::setHistoryCursorAndScrollToEnd(); } diff --git a/indra/newview/llchatbar.h b/indra/newview/llchatbar.h index 56a98a78f..3fa826ab9 100644 --- a/indra/newview/llchatbar.h +++ b/indra/newview/llchatbar.h @@ -86,8 +86,8 @@ public: static void onTabClick( void* userdata ); static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata); - static void onInputEditorFocusLost(LLFocusableElement* caller,void* userdata); - static void onInputEditorGainFocus(LLFocusableElement* caller,void* userdata); + static void onInputEditorFocusLost(); + static void onInputEditorGainFocus(); static void onCommitGesture(LLUICtrl* ctrl, void* data); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 451d4472b..1cc3fc820 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -1105,7 +1105,7 @@ BOOL LLPanelLandObjects::postBuild() mSelectedObjects = getChild("selected_objects_text"); mCleanOtherObjectsTime = getChild("clean other time"); - mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus, this); + mCleanOtherObjectsTime->setFocusLostCallback(boost::bind(&LLPanelLandObjects::onLostFocus, _1, this)); mCleanOtherObjectsTime->setCommitCallback(onCommitClean); childSetPrevalidate("clean other time", LLLineEditor::prevalidateNonNegativeS32); diff --git a/indra/newview/llfloaterlandmark.cpp b/indra/newview/llfloaterlandmark.cpp index 5b25a7138..2f39ac963 100644 --- a/indra/newview/llfloaterlandmark.cpp +++ b/indra/newview/llfloaterlandmark.cpp @@ -93,7 +93,7 @@ LLFloaterLandmark::LLFloaterLandmark(const LLSD& data) mInventoryPanel->setFilterTypes(filter_types); //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss. - mInventoryPanel->setSelectCallback(boost::bind(onSelectionChange, _1, _2, (void*)this)); + mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterLandmark::onSelectionChange, _1, _2, (void*)this)); mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); mInventoryPanel->setAllowMultiSelect(FALSE); diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index f4aa77aa9..6ff9d6695 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -135,7 +135,7 @@ BOOL LLFloaterPostcard::postBuild() MsgField->setWordWrap(TRUE); // For the first time a user focusess to .the msg box, all text will be selected. - MsgField->setFocusChangedCallback(onMsgFormFocusRecieved, this); + MsgField->setFocusChangedCallback(boost::bind(&LLFloaterPostcard::onMsgFormFocusRecieved, this, _1, MsgField)); } childSetFocus("to_form", TRUE); @@ -339,17 +339,12 @@ void LLFloaterPostcard::updateUserInfo(const std::string& email) } } -void LLFloaterPostcard::onMsgFormFocusRecieved(LLFocusableElement* receiver, void* data) +void LLFloaterPostcard::onMsgFormFocusRecieved(LLFocusableElement* receiver, LLTextEditor* msg_form) { - LLFloaterPostcard* self = (LLFloaterPostcard *)data; - if(self) + if(msg_form && msg_form == receiver && msg_form->hasFocus() && !(mHasFirstMsgFocus)) { - LLTextEditor* msgForm = self->getChild("msg_form"); - if(msgForm && msgForm == receiver && msgForm->hasFocus() && !(self->mHasFirstMsgFocus)) - { - self->mHasFirstMsgFocus = true; - msgForm->setText(LLStringUtil::null); - } + mHasFirstMsgFocus = true; + msg_form->setText(LLStringUtil::null); } } diff --git a/indra/newview/llfloaterpostcard.h b/indra/newview/llfloaterpostcard.h index bce14609d..e2ad154ef 100644 --- a/indra/newview/llfloaterpostcard.h +++ b/indra/newview/llfloaterpostcard.h @@ -68,7 +68,7 @@ public: static void updateUserInfo(const std::string& email); - static void onMsgFormFocusRecieved(LLFocusableElement* receiver, void* data); + void onMsgFormFocusRecieved(LLFocusableElement* receiver, LLTextEditor* msg_form); bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response); void sendPostcard(); diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 5e6ecf2b4..8cd9ea972 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -208,13 +208,9 @@ BOOL LLFloaterWorldMap::postBuild() childSetAction("DoSearch", onLocationCommit, this); - childSetFocusChangedCallback("location", onLocationFocusChanged, this); - LLLineEditor *location_editor = getChild("location"); - if (location_editor) - { - location_editor->setKeystrokeCallback( onSearchTextEntry ); - } + location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1)); + location_editor->setKeystrokeCallback( onSearchTextEntry ); childSetCommitCallback("search_results", onCommitSearchResult, this); childSetDoubleClickCallback("search_results", onClickTeleportBtn); @@ -1132,7 +1128,7 @@ void LLFloaterWorldMap::onComboTextEntry( LLLineEditor* ctrl, void* userdata ) void LLFloaterWorldMap::onSearchTextEntry( LLLineEditor* ctrl, void* userdata ) { onComboTextEntry(ctrl, userdata); - updateSearchEnabled(ctrl, userdata); + gFloaterWorldMap->updateSearchEnabled(); } // static @@ -1239,24 +1235,21 @@ void LLFloaterWorldMap::onAvatarComboCommit( LLUICtrl* ctrl, void* userdata ) } } -//static -void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus, void* userdata ) +void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus ) { - updateSearchEnabled((LLUICtrl*)focus, userdata); + updateSearchEnabled(); } -// static -void LLFloaterWorldMap::updateSearchEnabled( LLUICtrl* ctrl, void* userdata ) +void LLFloaterWorldMap::updateSearchEnabled() { - LLFloaterWorldMap *self = gFloaterWorldMap; - if (self->childHasKeyboardFocus("location") && - self->childGetValue("location").asString().length() > 0) + if (childHasKeyboardFocus("location") && + childGetValue("location").asString().length() > 0) { - self->setDefaultBtn("DoSearch"); + setDefaultBtn("DoSearch"); } else { - self->setDefaultBtn(NULL); + setDefaultBtn(NULL); } } diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index 03baa3eef..80cc25abd 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -151,8 +151,8 @@ protected: void flyToAvatar(); void teleportToAvatar(); - static void updateSearchEnabled( LLUICtrl* ctrl, void* userdata ); - static void onLocationFocusChanged( LLFocusableElement* ctrl, void* userdata ); + void updateSearchEnabled(); + void onLocationFocusChanged( LLFocusableElement* focus ); static void onLocationCommit( void* userdata ); static void onCommitLocation( LLUICtrl* ctrl, void* userdata ); static void onCommitSearchResult( LLUICtrl* ctrl, void* userdata ); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 5921a4cfb..c970cf688 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1427,7 +1427,7 @@ void LLFolderView::startRenamingSelectedItem( void ) mRenamer->setVisible( TRUE ); // set focus will fail unless item is visible mRenamer->setFocus( TRUE ); - mRenamer->setLostTopCallback(onRenamerLost); + mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this)); gFocusMgr.setTopCtrl( mRenamer ); } } @@ -2168,11 +2168,9 @@ void LLFolderView::updateRenamerPosition() /// Local function definitions ///---------------------------------------------------------------------------- - -//static -void LLFolderView::onRenamerLost( LLUICtrl* renamer, void* user_data) +void LLFolderView::onRenamerLost() { - renamer->setVisible(FALSE); + mRenamer->setVisible(FALSE); } LLInventoryFilter* LLFolderView::getFilter() diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 918c64099..36d250ae1 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -251,7 +251,7 @@ protected: LLScrollableContainerView* mScrollContainer; // NULL if this is not a child of a scroll container. static void commitRename( LLUICtrl* renamer, void* user_data ); - static void onRenamerLost( LLUICtrl* renamer, void* user_data); + void onRenamerLost(); void finishRenamingItem( void ); void closeRenamer( void ); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 56375829a..a60c3b0a1 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -1344,10 +1344,7 @@ LLFloaterIMPanel::~LLFloaterIMPanel() mVoiceChannel = NULL; //delete focus lost callback - if(mInputEditor) - { - mInputEditor->setFocusLostCallback( NULL ); - } + mFocusLostSignal.disconnect(); } BOOL LLFloaterIMPanel::postBuild() @@ -1360,8 +1357,8 @@ BOOL LLFloaterIMPanel::postBuild() mRPMode = false; mInputEditor = getChild("chat_editor"); - mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); - mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); + mInputEditor->setFocusReceivedCallback( boost::bind(&LLFloaterIMPanel::onInputEditorFocusReceived, this) ); + mFocusLostSignal = mInputEditor->setFocusLostCallback( boost::bind(&LLFloaterIMPanel::onInputEditorFocusLost, this) ); mInputEditor->setKeystrokeCallback( onInputEditorKeystroke ); mInputEditor->setCommitCallback( onCommitChat ); mInputEditor->setCallbackUserData(this); @@ -2003,18 +2000,14 @@ void LLFloaterIMPanel::onCommitChat(LLUICtrl* caller, void* userdata) self->sendMsg(); } -// static -void LLFloaterIMPanel::onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata ) +void LLFloaterIMPanel::onInputEditorFocusReceived() { - LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata; - self->mHistoryEditor->setCursorAndScrollToEnd(); + mHistoryEditor->setCursorAndScrollToEnd(); } -// static -void LLFloaterIMPanel::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata) +void LLFloaterIMPanel::onInputEditorFocusLost() { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->setTyping(FALSE); + setTyping(FALSE); } // static diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index 69cd8f19e..9daed909f 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -231,8 +231,8 @@ public: void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); - static void onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata ); - static void onInputEditorFocusLost(LLFocusableElement* caller, void* userdata); + void onInputEditorFocusReceived(); + void onInputEditorFocusLost(); static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata); static void onCommitChat(LLUICtrl* caller, void* userdata); static void onTabClick( void* userdata ); @@ -382,6 +382,10 @@ private: // Timer to detect when user has stopped typing. LLFrameTimer mLastKeystrokeTimer; + boost::signals2::connection mFocusLostSignal; + + + void disableWhileSessionStarting(); typedef std::map styleMap; diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 9625cfcdc..9751c2d7a 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -255,14 +255,14 @@ BOOL LLPanelClassified::postBuild() mNameEditor = getChild("given_name_editor"); mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN); mNameEditor->setCommitOnFocusLost(TRUE); - mNameEditor->setFocusReceivedCallback(focusReceived, this); + mNameEditor->setFocusReceivedCallback(boost::bind(focusReceived, _1, this)); mNameEditor->setCommitCallback(onCommitAny); mNameEditor->setCallbackUserData(this); mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII ); mDescEditor = getChild("desc_editor"); mDescEditor->setCommitOnFocusLost(TRUE); - mDescEditor->setFocusReceivedCallback(focusReceived, this); + mDescEditor->setFocusReceivedCallback(boost::bind(focusReceived, _1, this)); mDescEditor->setCommitCallback(onCommitAny); mDescEditor->setCallbackUserData(this); mDescEditor->setTabsToNextField(TRUE); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index d608f7a98..6aa23b24e 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -127,8 +127,8 @@ BOOL LLPanelGroupGeneral::postBuild() if(mEditCharter) { mEditCharter->setCommitCallback(onCommitAny); - mEditCharter->setFocusReceivedCallback(onFocusEdit, this); - mEditCharter->setFocusChangedCallback(onFocusEdit, this); + mEditCharter->setFocusReceivedCallback(boost::bind(&LLPanelGroupGeneral::onFocusEdit, this)); + mEditCharter->setFocusChangedCallback(boost::bind(&LLPanelGroupGeneral::onFocusEdit, this)); mEditCharter->setCallbackUserData(this); } @@ -279,15 +279,12 @@ BOOL LLPanelGroupGeneral::postBuild() return LLPanelGroupTab::postBuild(); } -// static -void LLPanelGroupGeneral::onFocusEdit(LLFocusableElement* ctrl, void* data) +void LLPanelGroupGeneral::onFocusEdit() { - LLPanelGroupGeneral* self = (LLPanelGroupGeneral*)data; - self->updateChanged(); - self->notifyObservers(); + updateChanged(); + notifyObservers(); } -// static void LLPanelGroupGeneral::onCommitAny(LLUICtrl* ctrl, void* data) { LLPanelGroupGeneral* self = (LLPanelGroupGeneral*)data; diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h index c4572e2d4..2eeb901c7 100644 --- a/indra/newview/llpanelgroupgeneral.h +++ b/indra/newview/llpanelgroupgeneral.h @@ -67,7 +67,7 @@ public: virtual void draw(); private: - static void onFocusEdit(LLFocusableElement* ctrl, void* data); + void onFocusEdit(); static void onCommitAny(LLUICtrl* ctrl, void* data); static void onCommitUserOnly(LLUICtrl* ctrl, void* data); static void onCommitTitle(LLUICtrl* ctrl, void* data); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index be41b0f87..e044a163d 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1810,7 +1810,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) mRoleDescription->setCommitOnFocusLost(TRUE); mRoleDescription->setCallbackUserData(this); mRoleDescription->setCommitCallback(onDescriptionCommit); - mRoleDescription->setFocusReceivedCallback(onDescriptionFocus, this); + mRoleDescription->setFocusReceivedCallback(boost::bind(&LLPanelGroupRolesSubTab::onDescriptionFocus, this)); setFooterEnabled(FALSE); @@ -2273,14 +2273,10 @@ void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_dat self->notifyObservers(); } -// static -void LLPanelGroupRolesSubTab::onDescriptionFocus(LLFocusableElement* ctrl, void* user_data) +void LLPanelGroupRolesSubTab::onDescriptionFocus() { - LLPanelGroupRolesSubTab* self = static_cast(user_data); - if (!self) return; - - self->mHasRoleChange = TRUE; - self->notifyObservers(); + mHasRoleChange = TRUE; + notifyObservers(); } // static diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 95057bbfa..5b51fa03f 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -255,7 +255,7 @@ public: static void onPropertiesKey(LLLineEditor*, void*); static void onDescriptionCommit(LLUICtrl*, void*); - static void onDescriptionFocus(LLFocusableElement*, void*); + void onDescriptionFocus(); static void onMemberVisibilityChange(LLUICtrl*, void*); void handleMemberVisibilityChange(bool value); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 9c698b1b7..dcb5d75f3 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -263,7 +263,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, #if !USE_VIEWER_AUTH LLComboBox* name_combo = sInstance->getChild("name_combo"); name_combo->setCommitCallback(onSelectLoginEntry); - name_combo->setFocusLostCallback(onLoginComboLostFocus); + name_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLoginComboLostFocus, this, name_combo)); name_combo->setPrevalidate(LLLineEditor::prevalidatePrintableNotPipe); name_combo->setSuppressTentative(true); name_combo->setSuppressAutoComplete(true); @@ -1242,17 +1242,12 @@ void LLPanelLogin::onSelectLoginEntry(LLUICtrl* ctrl, void* data) } } -// static -void LLPanelLogin::onLoginComboLostFocus(LLFocusableElement* fe, void*) +void LLPanelLogin::onLoginComboLostFocus(LLComboBox* combo_box) { - if (sInstance) + if(combo_box->isTextDirty()) { - LLComboBox* combo = sInstance->getChild("name_combo"); - if(fe == combo && combo->isTextDirty()) - { - clearPassword(); - combo->resetTextDirty(); - } + clearPassword(); + combo_box->resetTextDirty(); } } diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 3c4887b85..3fd697b34 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -39,6 +39,7 @@ #include "llsavedlogins.h" class LLUIImage; +class LLComboBox; // extern std::string gFullName; @@ -118,7 +119,7 @@ private: //static void onSelectServer(LLUICtrl*, void*); //static void onServerComboLostFocus(LLFocusableElement*, void*); static void onSelectLoginEntry(LLUICtrl*, void*); - static void onLoginComboLostFocus(LLFocusableElement* fe, void*); + void onLoginComboLostFocus(LLComboBox* combo_box); static void onNameCheckChanged(LLUICtrl* ctrl, void* data); static void clearPassword(); From b0240320ee4d0f6e4013dea0bab5efb4d4e07c25 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 18 Feb 2012 01:59:02 -0600 Subject: [PATCH 04/32] Inv menus appear now. Still need to update llmenugl and its variants, since our current version is buggy. Also need to look into why inventory postfixes aren't appearing. --- indra/llui/llfloater.cpp | 8 +- indra/llui/llmenugl.cpp | 38 +- indra/llui/llmenugl.h | 31 +- indra/llui/llscrollcontainer.cpp | 1 + indra/llui/llview.h | 5 +- indra/newview/llfolderview.cpp | 332 ++++++++++++----- indra/newview/llfolderview.h | 21 +- indra/newview/llfolderviewitem.cpp | 32 +- indra/newview/llfolderviewitem.h | 4 +- indra/newview/llinventorybridge.cpp | 276 ++++++++++---- indra/newview/llinventorybridge.h | 31 +- indra/newview/llinventorypanel.cpp | 341 ++++++++++++++---- indra/newview/llinventorypanel.h | 61 +++- indra/newview/lllocalinventory.cpp | 2 +- indra/newview/llpanelobjectinventory.cpp | 2 +- indra/newview/llpreviewanim.cpp | 102 +++--- indra/newview/llpreviewanim.h | 5 +- .../default/xui/en-us/menu_inventory.xml | 13 +- 18 files changed, 943 insertions(+), 362 deletions(-) diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 3145c3cf1..560873acc 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2485,8 +2485,12 @@ void LLFloaterView::pushVisibleAll(BOOL visible, const skip_list_t& skip_list) void LLFloaterView::popVisibleAll(const skip_list_t& skip_list) { - for (child_list_const_iter_t child_iter = getChildList()->begin(); - child_iter != getChildList()->end(); ++child_iter) + // make a copy of the list since some floaters change their + // order in the childList when changing visibility. + child_list_t child_list_copy = *getChildList(); + + for (child_list_const_iter_t child_iter = child_list_copy.begin(); + child_iter != child_list_copy.end(); ++child_iter) { LLView *view = *child_iter; if (skip_list.find(view) == skip_list.end()) diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index cd0c2f0c0..4a1368419 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -522,31 +522,15 @@ BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit& // This class represents a separator. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemSeparatorGL : public LLMenuItemGL -{ -public: - LLMenuItemSeparatorGL( const std::string &name = SEPARATOR_NAME ); - - virtual LLXMLNodePtr getXML(bool save_children = true) const; - - virtual std::string getType() const { return "separator"; } - - // doIt() - do the primary funcationality of the menu item. - virtual void doIt( void ) {} - - virtual void draw( void ); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - - virtual U32 getNominalHeight( void ) const { return SEPARATOR_HEIGHT_PIXELS; } -}; LLMenuItemSeparatorGL::LLMenuItemSeparatorGL( const std::string &name ) : - LLMenuItemGL( name, SEPARATOR_LABEL ) + LLMenuItemGL( name.empty() ? SEPARATOR_NAME : name, SEPARATOR_LABEL ) { } - +U32 LLMenuItemSeparatorGL::getNominalHeight( void ) const +{ + return SEPARATOR_HEIGHT_PIXELS; +} LLXMLNodePtr LLMenuItemSeparatorGL::getXML(bool save_children) const { @@ -1694,7 +1678,6 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle< : LLUICtrl( name, LLRect(), FALSE, NULL, NULL ), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), - mParentMenuItem( NULL ), mLabel( label ), mDropShadowed( TRUE ), mHorizontalLayout( FALSE ), @@ -1720,7 +1703,6 @@ LLMenuGL::LLMenuGL( const std::string& label, LLHandle parent_floater : LLUICtrl( label, LLRect(), FALSE, NULL, NULL ), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), - mParentMenuItem( NULL ), mLabel( label ), mDropShadowed( TRUE ), mHorizontalLayout( FALSE ), @@ -2342,6 +2324,16 @@ void LLMenuGL::arrange( void ) } } + +void LLMenuGL::arrangeAndClear( void ) +{ + if (mNeedsArrange) + { + arrange(); + mNeedsArrange = FALSE; + } +} + void LLMenuGL::createSpilloverBranch() { if (!mSpilloverBranch) diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 9f843a3e9..94fab5b16 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -216,6 +216,30 @@ private: KEY mJumpKey; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLMenuItemSeparatorGL +// +// This class represents a separator. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLMenuItemSeparatorGL : public LLMenuItemGL +{ +public: + LLMenuItemSeparatorGL( const std::string &name = std::string() ); + + virtual LLXMLNodePtr getXML(bool save_children = true) const; + + virtual std::string getType() const { return "separator"; } + + // doIt() - do the primary funcationality of the menu item. + virtual void doIt( void ) {} + + virtual void draw( void ); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + + virtual U32 getNominalHeight( void ) const; +}; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemCallGL @@ -483,6 +507,7 @@ public: // when you add items. *FIX: We may need to deal with visibility // arrangement. virtual void arrange( void ); + void arrangeAndClear( void ); // remove all items on the menu void empty( void ); @@ -511,8 +536,8 @@ public: // Whether to drop shadow menu bar void setDropShadowed( const BOOL shadowed ); - void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item; } - LLMenuItemGL* getParentMenuItem() const { return mParentMenuItem; } + void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } + LLMenuItemGL* getParentMenuItem() const { return dynamic_cast(mParentMenuItem.get()); } void setTornOff(BOOL torn_off); BOOL getTornOff() { return mTornOff; } @@ -550,7 +575,7 @@ private: LLColor4 mBackgroundColor; BOOL mBgVisible; - LLMenuItemGL* mParentMenuItem; + LLHandle mParentMenuItem; LLUIString mLabel; BOOL mDropShadowed; // Whether to drop shadow BOOL mHasSelection; diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 7af52ce2a..a6e30581e 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -493,6 +493,7 @@ void LLScrollableContainerView::draw() void LLScrollableContainerView::updateScroll() { + if(!mScrolledView)return; LLRect doc_rect = mScrolledView->getRect(); S32 doc_width = doc_rect.getWidth(); S32 doc_height = doc_rect.getHeight(); diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 6d156464f..4fb1fe605 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -346,8 +346,9 @@ public: virtual void handleVisibilityChange ( BOOL curVisibilityIn ); void pushVisible(BOOL visible) { mLastVisible = mVisible; setVisible(visible); } - void popVisible() { setVisible(mLastVisible); mLastVisible = TRUE; } - + void popVisible() { setVisible(mLastVisible); } + BOOL getLastVisible() const { return mLastVisible; } + LLHandle getHandle() { mHandle.bind(this); return mHandle; } U32 getFollows() const { return mReshapeFlags; } diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index c970cf688..99855aebe 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -41,6 +41,7 @@ #include "llinventoryfilter.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" +#include "llinventorypanel.h" #include "llfoldertype.h" #include "llkeyboard.h" #include "lllineeditor.h" @@ -196,7 +197,7 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) // Default constructor LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, - const LLRect& rect, const LLUUID& source_id, LLView *parent_view, LLFolderViewEventListener* listener ) : + const LLRect& rect, const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener ) : #if LL_WINDOWS #pragma warning( push ) #pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list @@ -205,6 +206,7 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic #if LL_WINDOWS #pragma warning( pop ) #endif + mRunningHeight(0), mScrollContainer( NULL ), mPopupMenuHandle(), mAllowMultiSelect(TRUE), @@ -225,8 +227,10 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic mArrangeGeneration(0), mSignalSelectCallback(0), mMinWidth(0), - mDragAndDropThisFrame(FALSE) + mDragAndDropThisFrame(FALSE), + mParentPanel(parent_view) { + mRoot = this; LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom); setRect( rect ); reshape(rect.getWidth(), rect.getHeight()); @@ -267,6 +271,8 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic mPopupMenuHandle = menu->getHandle(); setTabStop(TRUE); + + mListener->openItem(); } // Destroys the object @@ -282,23 +288,12 @@ LLFolderView::~LLFolderView( void ) mScrollContainer = NULL; mRenameItem = NULL; mRenamer = NULL; - gFocusMgr.releaseFocusIfNeeded( this ); - - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } mAutoOpenItems.removeAllNodes(); gIdleCallbacks.deleteFunction(idle, this); if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); - if(mRenamer == gFocusMgr.getTopCtrl()) - { - gFocusMgr.setTopCtrl(NULL); - } - mAutoOpenItems.removeAllNodes(); clearSelection(); mItems.clear(); @@ -447,6 +442,16 @@ void LLFolderView::openFolder(const std::string& foldername) } } +void LLFolderView::openTopLevelFolders() +{ + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->setOpen(TRUE); + } +} + void LLFolderView::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse) { // call base class to do proper recursion @@ -460,6 +465,18 @@ static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); // This view grows and shinks to enclose all of its children items and folders. S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation ) { + if(!mScrollContainer) + return 1; + if (getListener()->getUUID().notNull()) + { + if (mNeedsSort) + { + mFolders.sort(mSortFunction); + mItems.sort(mSortFunction); + mNeedsSort = false; + } + } + LLFastTimer t2(FTM_ARRANGE); filter_generation = mFilter->getMinRequiredGeneration(); @@ -529,17 +546,21 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen } } - S32 dummy_s32; - BOOL dummy_bool; - S32 min_width; - mScrollContainer->calcVisibleSize( &min_width, &dummy_s32, &dummy_bool, &dummy_bool); - reshape( llmax(min_width, total_width), running_height ); - - S32 new_min_width; - mScrollContainer->calcVisibleSize( &new_min_width, &dummy_s32, &dummy_bool, &dummy_bool); - if (new_min_width != min_width) + /*if(!mHasVisibleChildren)// is there any filtered items ? { - reshape( llmax(min_width, total_width), running_height ); + //Nope. We need to display status textbox, let's reserve some place for it + running_height = mStatusTextBox->getTextPixelHeight(); + target_height = running_height; + }*/ + + mRunningHeight = running_height; + LLRect scroll_rect = mScrollContainer->getContentWindowRect(); + reshape( llmax(scroll_rect.getWidth(), total_width), running_height ); + + LLRect new_scroll_rect = mScrollContainer->getContentWindowRect(); + if (new_scroll_rect.getWidth() != scroll_rect.getWidth()) + { + reshape( llmax(scroll_rect.getWidth(), total_width), running_height ); } // move item renamer text field to item's new position @@ -575,14 +596,14 @@ void LLFolderView::filter( LLInventoryFilter& filter ) void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent) { - S32 min_width = 0; - S32 dummy_height; - BOOL dummy_bool; + LLRect scroll_rect; if (mScrollContainer) { - mScrollContainer->calcVisibleSize( &min_width, &dummy_height, &dummy_bool, &dummy_bool); + LLView::reshape(width, height, called_from_parent); + scroll_rect = mScrollContainer->getContentWindowRect(); } - width = llmax(mMinWidth, min_width); + width = llmax(mMinWidth, scroll_rect.getWidth()); + height = llmax(mRunningHeight, scroll_rect.getHeight()); LLView::reshape(width, height, called_from_parent); mReshapeSignal(mSelectedItems, FALSE); @@ -643,6 +664,8 @@ LLFolderViewItem* LLFolderView::getCurSelectedItem( void ) BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus) { + mSignalSelectCallback = take_keyboard_focus ? SIGNAL_KEYBOARD_FOCUS : SIGNAL_NO_KEYBOARD_FOCUS; + if( selection == this ) { return FALSE; @@ -650,7 +673,7 @@ BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, if( selection && take_keyboard_focus) { - setFocus(TRUE); + mParentPanel->setFocus(TRUE); } // clear selection down here because change of keyboard focus can potentially @@ -670,8 +693,6 @@ BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, llassert(mSelectedItems.size() <= 1); - mSignalSelectCallback = take_keyboard_focus ? SIGNAL_KEYBOARD_FOCUS : SIGNAL_NO_KEYBOARD_FOCUS; - return rv; } @@ -921,10 +942,6 @@ void LLFolderView::draw() { closeAutoOpenedFolders(); } - if(this == gFocusMgr.getKeyboardFocus() && !getVisible()) - { - gFocusMgr.setKeyboardFocus( NULL ); - } // while dragging, update selection rendering to reflect single/multi drag status if (LLToolDragAndDrop::getInstance()->hasMouseCapture()) @@ -996,11 +1013,40 @@ void LLFolderView::closeRenamer( void ) { if (mRenamer && mRenamer->getVisible()) { + if(mRenamer == gFocusMgr.getTopCtrl()) + gFocusMgr.setTopCtrl( NULL ); // Triggers onRenamerLost() that actually closes the renamer. - gFocusMgr.setTopCtrl( NULL ); + //gFocusMgr.setTopCtrl( NULL ); } } +bool isDescendantOfASelectedItem(LLFolderViewItem* item, const std::vector& selectedItems) +{ + LLFolderViewItem* item_parent = dynamic_cast(item->getParent()); + + if (item_parent) + { + for(std::vector::const_iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) + { + const LLFolderViewItem* const selected_item = (*it); + + LLFolderViewItem* parent = item_parent; + + while (parent) + { + if (selected_item == parent) + { + return true; + } + + parent = dynamic_cast(parent->getParent()); + } + } + } + + return false; +} + void LLFolderView::removeSelectedItems( void ) { if(getVisible() && getEnabled()) @@ -1049,11 +1095,11 @@ void LLFolderView::removeSelectedItems( void ) // change selection on successful delete if (new_selection) { - setSelectionFromRoot(new_selection, new_selection->isOpen(), hasFocus()); + setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); } else { - setSelectionFromRoot(NULL, hasFocus()); + setSelectionFromRoot(NULL, mParentPanel->hasFocus()); } } } @@ -1072,18 +1118,18 @@ void LLFolderView::removeSelectedItems( void ) if (!new_selection) { new_selection = last_item->getPreviousOpenNode(FALSE); - while (new_selection && (new_selection->isSelected()/* || isDescendantOfASelectedItem(new_selection, items)*/)) + while (new_selection && (new_selection->isSelected() || isDescendantOfASelectedItem(new_selection, items))) { new_selection = new_selection->getPreviousOpenNode(FALSE); } } if (new_selection) { - setSelectionFromRoot(new_selection, new_selection->isOpen(), hasFocus()); + setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); } else { - setSelectionFromRoot(NULL, hasFocus()); + setSelectionFromRoot(NULL, mParentPanel->hasFocus()); } for(S32 i = 0; i < count; ++i) @@ -1432,19 +1478,6 @@ void LLFolderView::startRenamingSelectedItem( void ) } } -void LLFolderView::setFocus(BOOL focus) -{ - if (focus) - { - if(!hasFocus()) - { - gEditMenuHandler = this; - } - } - - LLFolderViewFolder::setFocus(focus); -} - BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) { BOOL handled = FALSE; @@ -1647,7 +1680,7 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) break; } - if (!handled && hasFocus()) + if (!handled && mParentPanel->hasFocus()) { if (key == KEY_BACKSPACE) { @@ -1679,7 +1712,7 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) } BOOL handled = FALSE; - if (hasFocus()) + if (mParentPanel->hasFocus()) { // SL-51858: Key presses are not being passed to the Popup menu. // A proper fix is non-trivial so instead just close the menu. @@ -1736,20 +1769,13 @@ BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask ) mKeyboardSelection = FALSE; mSearchString.clear(); - setFocus(TRUE); + mParentPanel->setFocus(TRUE); + + LLEditMenuHandler::gEditMenuHandler = this; return LLView::handleMouseDown( x, y, mask ); } -void LLFolderView::onFocusLost( ) -{ - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } - LLUICtrl::onFocusLost(); -} - BOOL LLFolderView::search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward) { // get first selected item @@ -1826,35 +1852,21 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) { // all user operations move keyboard focus to inventory // this way, we know when to stop auto-updating a search - setFocus(TRUE); + mParentPanel->setFocus(TRUE); BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; S32 count = mSelectedItems.size(); LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if(handled && (count > 0) && menu) + if ( handled + && ( count > 0 && (hasVisibleChildren() || mFilter->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS) ) // show menu only if selected items are visible + && menu ) { - //menu->empty(); - const LLView::child_list_t *list = menu->getChildList(); - - LLView::child_list_t::const_iterator menu_itor; - for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) - { - (*menu_itor)->setVisible(TRUE); - (*menu_itor)->setEnabled(TRUE); - } - - // Successively filter out invalid options - selected_items_t::iterator item_itor; - U32 flags = FIRST_SELECTED_ITEM; - for (item_itor = mSelectedItems.begin(); item_itor != mSelectedItems.end(); ++item_itor) - { - (*item_itor)->buildContextMenu(*menu, flags); - flags = 0x0; - } - - menu->arrange(); + updateMenuOptions(menu); + menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); + + menu->needsArrange(); // update menu height if needed } else { @@ -1867,6 +1879,37 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) return handled; } +// Add "--no options--" if the menu is completely blank. +BOOL LLFolderView::addNoOptions(LLMenuGL* menu) const +{ + const std::string nooptions_str = "--no options--"; + LLView *nooptions_item = NULL; + + const LLView::child_list_t *list = menu->getChildList(); + for (LLView::child_list_t::const_iterator itor = list->begin(); + itor != list->end(); + ++itor) + { + LLView *menu_item = (*itor); + if (menu_item->getVisible()) + { + return FALSE; + } + std::string name = menu_item->getName(); + if (menu_item->getName() == nooptions_str) + { + nooptions_item = menu_item; + } + } + if (nooptions_item) + { + nooptions_item->setVisible(TRUE); + nooptions_item->setEnabled(FALSE); + return TRUE; + } + return FALSE; +} + BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask ) { return LLView::handleHover( x, y, mask ); @@ -1901,21 +1944,25 @@ BOOL LLFolderView::handleScrollWheel(S32 x, S32 y, S32 clicks) void LLFolderView::deleteAllChildren() { - if(mRenamer == gFocusMgr.getTopCtrl()) - { - gFocusMgr.setTopCtrl(NULL); - } - LLView::deleteViewByHandle(mPopupMenuHandle); + closeRenamer(); + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); mPopupMenuHandle = LLHandle(); - mRenamer = NULL; + mScrollContainer = NULL; mRenameItem = NULL; + mRenamer = NULL; clearSelection(); LLView::deleteAllChildren(); } void LLFolderView::scrollToShowSelection() { - if (mSelectedItems.size()) + // If items are filtered while background fetch is in progress + // scrollbar resets to the first filtered item. See EXT-3981. + // However we allow scrolling for folder views with mAutoSelectOverride + // (used in Places SP) as an exception because the selection in them + // is not reset during items filtering. See STORM-133. + if ( (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mAutoSelectOverride) + && mSelectedItems.size() ) { mNeedsScroll = TRUE; } @@ -1925,6 +1972,7 @@ void LLFolderView::scrollToShowSelection() // is maximally visible. void LLFolderView::scrollToShowItem(LLFolderViewItem* item) { + if (!mScrollContainer) return; // don't scroll to items when mouse is being used to scroll/drag and drop if (gFocusMgr.childHasMouseCapture(mScrollContainer)) { @@ -2015,7 +2063,7 @@ LLFastTimer::DeclareTimer FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID"); LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id) { LLFastTimer _(FTM_GET_ITEM_BY_ID); - if (id.isNull()) + if (id == getListener()->getUUID()) { return this; } @@ -2030,6 +2078,25 @@ LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id) return NULL; } +LLFolderViewFolder* LLFolderView::getFolderByID(const LLUUID& id) +{ + if (id == getListener()->getUUID()) + { + return this; + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end(); + ++iter) + { + LLFolderViewFolder *folder = (*iter); + if (folder->getListener()->getUUID() == id) + { + return folder; + } + } + return NULL; +} static LLFastTimer::DeclareTimer FTM_AUTO_SELECT("Open and Select"); @@ -2038,6 +2105,14 @@ extern std::set sFolderViewItems; //dumb hack // Main idle routine void LLFolderView::doIdle() { + // If this is associated with the user's inventory, don't do anything + // until that inventory is loaded up. + const LLInventoryPanel *inventory_panel = dynamic_cast(mParentPanel); + if (inventory_panel && !inventory_panel->getIsViewsInitialized()) + { + return; + } + LLFastTimer t2(FTM_INVENTORY); BOOL debug_filters = gSavedSettings.getBOOL("DebugInventoryFilters"); @@ -2078,12 +2153,21 @@ void LLFolderView::doIdle() clearSelection(); requestArrange(); } - else if (!mAutoSelectOverride && (!selected_itemp || !selected_itemp->getFiltered())) + else if ((selected_itemp && !selected_itemp->getFiltered()) && !mAutoSelectOverride) { // select first filtered item LLSelectFirstFilteredItem filter; applyFunctorRecursively(filter); } + + // Open filtered folders for folder views with mAutoSelectOverride=TRUE. + // Used by LLPlacesFolderView. + if (mAutoSelectOverride && !mFilter->getFilterSubString().empty()) + { + LLOpenFilteredFolders filter; + applyFunctorRecursively(filter); + } + scrollToShowSelection(); } @@ -2155,8 +2239,7 @@ void LLFolderView::updateRenamerPosition() LLRect scroller_rect(0, 0, gViewerWindow->getWindowWidthScaled(), 0); if (mScrollContainer) { - BOOL dummy_bool; - mScrollContainer->calcVisibleSize( &scroller_rect.mRight, &scroller_rect.mTop, &dummy_bool, &dummy_bool); + scroller_rect = mScrollContainer->getContentWindowRect(); } S32 width = llmax(llmin(mRenameItem->getRect().getWidth() - x, scroller_rect.getWidth() - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); @@ -2164,13 +2247,64 @@ void LLFolderView::updateRenamerPosition() mRenamer->reshape( width, height, TRUE ); } } + +// Update visibility and availability (i.e. enabled/disabled) of context menu items. +void LLFolderView::updateMenuOptions(LLMenuGL* menu) +{ + const LLView::child_list_t *list = menu->getChildList(); + + LLView::child_list_t::const_iterator menu_itor; + for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) + { + (*menu_itor)->setVisible(FALSE); + (*menu_itor)->pushVisible(TRUE); + (*menu_itor)->setEnabled(TRUE); + } + + // Successively filter out invalid options + + U32 flags = FIRST_SELECTED_ITEM; + for (selected_items_t::iterator item_itor = mSelectedItems.begin(); + item_itor != mSelectedItems.end(); + ++item_itor) + { + LLFolderViewItem* selected_item = (*item_itor); + selected_item->buildContextMenu(*menu, flags); + flags = 0x0; + } + + addNoOptions(menu); +} + +// Refresh the context menu (that is already shown). +void LLFolderView::updateMenu() +{ + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + updateMenuOptions(menu); + menu->needsArrange(); // update menu height if needed + } +} ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- void LLFolderView::onRenamerLost() { + if (mRenamer && mRenamer->getVisible()) + { mRenamer->setVisible(FALSE); + + // will commit current name (which could be same as original name) + mRenamer->setFocus(FALSE); + } + + if( mRenameItem ) + { + setSelectionFromRoot( mRenameItem, TRUE ); + mRenameItem = NULL; + } } LLInventoryFilter* LLFolderView::getFilter() diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 36d250ae1..2031c4f01 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -81,7 +81,7 @@ public: LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, const LLRect& rect, - const LLUUID& source_id, LLView *parent_view, LLFolderViewEventListener* listener ); + const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener ); virtual ~LLFolderView( void ); virtual BOOL canFocusChildren() const; @@ -109,7 +109,7 @@ public: U32 getSortOrder() const; BOOL isFilterModified(); - BOOL getAllowMultiSelect() { return mAllowMultiSelect; } + bool getAllowMultiSelect() { return mAllowMultiSelect; } U32 toggleSearchType(std::string toggle); U32 getSearchType() const; @@ -117,6 +117,7 @@ public: // Close all folders in the view void closeAllFolders(); void openFolder(const std::string& foldername); + void openTopLevelFolders(); virtual void toggleOpen() {}; virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse); @@ -196,9 +197,6 @@ public: //void dragItemIntoFolder( LLFolderViewItem* moving_item, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept ); //void dragFolderIntoFolder( LLFolderViewFolder* moving_folder, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept ); - // LLUICtrl Functionality - /*virtual*/ void setFocus(BOOL focus); - // LLView functionality ///*virtual*/ BOOL handleKey( KEY key, MASK mask, BOOL called_from_parent ); /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); @@ -213,7 +211,6 @@ public: EAcceptance* accept, std::string& tooltip_msg); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void onFocusLost(); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void draw(); virtual void deleteAllChildren(); @@ -233,6 +230,7 @@ public: void addItemID(const LLUUID& id, LLFolderViewItem* itemp); void removeItemID(const LLUUID& id); LLFolderViewItem* getItemByID(const LLUUID& id); + LLFolderViewFolder* getFolderByID(const LLUUID& id); void doIdle(); // Real idle routine static void idle(void* user_data); // static glue to doIdle() @@ -243,10 +241,16 @@ public: BOOL getDebugFilters() { return mDebugFilters; } + LLPanel* getParentPanel() { return mParentPanel; } // DEBUG only void dumpSelectionInformation(); + void updateMenu(); + +private: + void updateMenuOptions(LLMenuGL* menu); void updateRenamerPosition(); + protected: LLScrollableContainerView* mScrollContainer; // NULL if this is not a child of a scroll container. @@ -256,6 +260,8 @@ protected: void finishRenamingItem( void ); void closeRenamer( void ); + + BOOL addNoOptions(LLMenuGL* menu) const; protected: LLHandle mPopupMenuHandle; @@ -295,8 +301,11 @@ protected: signal_t mReshapeSignal; S32 mSignalSelectCallback; S32 mMinWidth; + S32 mRunningHeight; std::map mItemMap; BOOL mDragAndDropThisFrame; + + LLPanel* mParentPanel; /** * Contains item under mouse pointer while dragging diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 4a06d89c9..69d7da876 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -1046,7 +1046,8 @@ LLFolderViewFolder::LLFolderViewFolder( const std::string& name, LLUIImagePtr ic mLastArrangeGeneration( -1 ), mLastCalculatedWidth(0), mCompletedFilterGeneration(-1), - mMostFilteredDescendantGeneration(-1) + mMostFilteredDescendantGeneration(-1), + mNeedsSort(false) { } @@ -1075,6 +1076,14 @@ BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder, LLFolderView* r // makes sure that this view and it's children are the right size. S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) { + // sort before laying out contents + if (mNeedsSort) + { + mFolders.sort(mSortFunction); + mItems.sort(mSortFunction); + mNeedsSort = false; + } + mHasVisibleChildren = hasFilteredDescendants(filter_generation); LLInventoryFilter::EFolderShow show_folder_state = getRoot()->getFilter()->getShowFolderState(); @@ -1219,6 +1228,12 @@ BOOL LLFolderViewFolder::needsArrange() return mLastArrangeGeneration < getRoot()->getArrangeGeneration(); } +void LLFolderViewFolder::requestSort() +{ + mNeedsSort = true; + // whenever item order changes, we need to lay things out again + requestArrange(); +} void LLFolderViewFolder::setCompletedFilterGeneration(S32 generation, BOOL recurse_up) { mMostFilteredDescendantGeneration = llmin(mMostFilteredDescendantGeneration, generation); @@ -1404,6 +1419,11 @@ void LLFolderViewFolder::dirtyFilter() LLFolderViewItem::dirtyFilter(); } +BOOL LLFolderViewFolder::hasFilteredDescendants(S32 filter_generation) +{ + return mMostFilteredDescendantGeneration >= filter_generation; +} + BOOL LLFolderViewFolder::hasFilteredDescendants() { return mMostFilteredDescendantGeneration >= getRoot()->getFilter()->getCurrentGeneration(); @@ -1871,7 +1891,7 @@ void LLFolderViewFolder::destroyView() folderp->destroyView(); // removes entry from mFolders } - deleteAllChildren(); + //deleteAllChildren(); if (mParentFolder) { @@ -2190,12 +2210,16 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r { BOOL was_open = mIsOpen; mIsOpen = openitem; - if(!was_open && openitem) + if (mListener) { - if(mListener) + if(!was_open && openitem) { mListener->openItem(); } + else if(was_open && !openitem) + { + mListener->closeItem(); + } } if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN) diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index cdda18890..a8af1e3b8 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -364,6 +364,7 @@ protected: S32 mLastCalculatedWidth; S32 mCompletedFilterGeneration; S32 mMostFilteredDescendantGeneration; + bool mNeedsSort; public: typedef enum e_recurse_type { @@ -389,6 +390,7 @@ public: virtual S32 arrange( S32* width, S32* height, S32 filter_generation ); BOOL needsArrange(); + void requestSort(); // Returns the sort group (system, trash, folder) for this folder. virtual EInventorySortGroup getSortGroup() const; @@ -396,7 +398,7 @@ public: virtual void setCompletedFilterGeneration(S32 generation, BOOL recurse_up); virtual S32 getCompletedFilterGeneration() { return mCompletedFilterGeneration; } - BOOL hasFilteredDescendants(S32 filter_generation) { return mMostFilteredDescendantGeneration >= filter_generation; } + BOOL hasFilteredDescendants(S32 filter_generation); BOOL hasFilteredDescendants(); // applies filters to control visibility of inventory items diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1b8bc3f60..c23a87bcf 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -213,7 +213,7 @@ LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, mInvType(LLInventoryType::IT_NONE), mIsLink(FALSE) { - mInventoryPanel = inventory; + mInventoryPanel = inventory->getHandle(); const LLInventoryObject* obj = getInventoryObject(); mIsLink = obj && obj->getIsLinkType(); } @@ -592,6 +592,22 @@ void hide_context_entries(LLMenuGL& menu, { const LLView::child_list_t *list = menu.getChildList(); + // For removing double separators or leading separator. Start at true so that + // if the first element is a separator, it will not be shown. + bool is_previous_entry_separator = true; + + for (menuentry_vec_t::const_iterator itor = entries_to_show.begin(); itor != entries_to_show.end(); ++itor) + { + bool found = false; + for (LLView::child_list_t::const_iterator itor2 = list->begin(); itor2 != list->end(); ++itor2) + { + if(*itor == (*itor2)->getName()) + found = true; + } + if(!found) + llinfos << "Failed to find entry '" << *itor << "'" << llendl; + } + for (LLView::child_list_t::const_iterator itor = list->begin(); itor != list->end(); ++itor) @@ -605,8 +621,7 @@ void hide_context_entries(LLMenuGL& menu, { hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries); } - - + bool found = false; menuentry_vec_t::const_iterator itor2; for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2) @@ -614,21 +629,42 @@ void hide_context_entries(LLMenuGL& menu, if (*itor2 == name) { found = true; + break; } } + + // Don't allow multiple separators in a row (e.g. such as if there are no items + // between two separators). + if (found) + { + const bool is_entry_separator = (dynamic_cast(menu_item) != NULL); + found = !(is_entry_separator && is_previous_entry_separator); + is_previous_entry_separator = is_entry_separator; + } + if (!found) { - menu_item->setVisible(FALSE); + if (!menu_item->getLastVisible()) + { + menu_item->setVisible(FALSE); + } + + menu_item->setEnabled(FALSE); } else { - for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2) + menu_item->setVisible(TRUE); + // A bit of a hack so we can remember that some UI element explicitly set this to be visible + // so that some other UI element from multi-select doesn't later set this invisible. + menu_item->pushVisible(TRUE); + + bool enabled = (menu_item->getEnabled() == TRUE); + for (itor2 = disabled_entries.begin(); enabled && (itor2 != disabled_entries.end()); ++itor2) { - if (*itor2 == name) - { - menu_item->setEnabled(FALSE); - } + enabled &= (*itor2 != name); } + llinfos << (enabled ? "Showing" : "hiding") << " " << menu_item->getName() << llendl; + menu_item->setEnabled(enabled); } } } @@ -738,7 +774,8 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // [RLVa:KB] - Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a if (rlv_handler_t::isEnabled()) { - LLInventoryObject* pItem = (mInventoryPanel->getModel()) ? mInventoryPanel->getModel()->getObject(mUUID) : NULL; + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLInventoryObject* pItem = (panel && panel->getModel()) ? panel->getModel()->getObject(mUUID) : NULL; if ( (pItem) && ( ((LLAssetType::AT_NOTECARD == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE))) || ((LLAssetType::AT_LSL_TEXT == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT))) || @@ -855,7 +892,7 @@ LLInventoryObject* LLInvFVBridge::getInventoryObject() const LLInventoryModel* LLInvFVBridge::getInventoryModel() const { - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); return panel ? panel->getModel() : NULL; } @@ -1089,6 +1126,27 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) model->notifyObservers(); } } + +// +=================================================+ +// | InventoryFVBridgeBuilder | +// +=================================================+ +LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, + LLInventoryType::EType inv_type, + LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid, + U32 flags /* = 0x00 */) const +{ + return LLInvFVBridge::createBridge(asset_type, + actual_asset_type, + inv_type, + inventory, + root, + uuid, + flags); +} + // +=================================================+ // | LLItemBridge | // +=================================================+ @@ -1627,7 +1685,7 @@ BOOL LLFolderBridge::isItemRemovable() const return FALSE; } - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); LLFolderViewFolder* folderp = dynamic_cast(panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL); if (folderp) { @@ -1661,16 +1719,58 @@ BOOL LLFolderBridge::isItemCopyable() const return InventoryLinksEnabled(); } - -BOOL LLFolderBridge::isClipboardPasteable() const +BOOL LLFolderBridge::copyToClipboard() const { - if(LLInventoryClipboard::instance().hasContents() && isAgentInventory()) + if(isItemCopyable()) { + LLInventoryClipboard::instance().add(mUUID); return TRUE; } return FALSE; } +BOOL LLFolderBridge::isClipboardPasteable() const +{ + if ( ! LLInvFVBridge::isClipboardPasteable() ) + return FALSE; + +/* TODO + // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 + if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) ) + { + LLInventoryModel* model = getInventoryModel(); + if ( !model ) + { + return FALSE; + } + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + const LLViewerInventoryCategory *current_cat = getCategory(); + + // Search for the direct descendent of current Friends subfolder among all pasted items, + // and return false if is found. + for(S32 i = objects.count() - 1; i >= 0; --i) + { + const LLUUID &obj_id = objects.get(i); + if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) + { + return FALSE; + } + } + } +*/ + return TRUE; + + //Old, less restrictive behavior + /*if(LLInventoryClipboard::instance().hasContents() && isAgentInventory()) + { + return TRUE; + } + return FALSE;*/ + +} + BOOL LLFolderBridge::isClipboardPasteableAsLink() const { @@ -2312,6 +2412,11 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) modifyOutfit(TRUE); return; } + else if ("copy" == action) + { + copyToClipboard(); + return; + } else if ("wearitems" == action) { modifyOutfit(TRUE); @@ -2604,8 +2709,7 @@ void LLFolderBridge::staticFolderOptionsMenu() if (selfp && selfp->mRoot) { - //selfp->mRoot->updateMenu(); - selfp->buildContextMenuFolderOptions(0); + selfp->mRoot->updateMenu(); } } @@ -2623,7 +2727,6 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) { - LLUUID cof_id = LLAppearanceMgr::instance().getCOF(); LLInventoryModel* model = getInventoryModel(); llassert(model != NULL); @@ -2649,13 +2752,7 @@ void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) mDisabledItems.push_back(std::string("New Body Parts")); } - // clear out old menu and folder pointers - mMenu.markDead(); - if (cof_id == mUUID) - { - mItems.push_back(std::string("Take Off Items")); - } - else if(trash_id == mUUID) + if(trash_id == mUUID) { // This is the trash. mItems.push_back(std::string("Empty Trash")); @@ -2792,15 +2889,20 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags) { mItems.push_back(std::string("Add To Outfit")); } - mItems.push_back(std::string("Wear Items")); + else if(!InventoryLinksEnabled()) + mItems.push_back(std::string("Wear Items")); mItems.push_back(std::string("Replace Outfit")); } - mItems.push_back(std::string("Take Off Items")); - } - LLMenuGL* menup = dynamic_cast(mMenu.get()); - if (menup) - { - hide_context_entries(*menup, mItems, mDisabledItems); + mItems.push_back(std::string("Remove From Outfit")); + if (!LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) + { + mDisabledItems.push_back(std::string("Remove From Outfit")); + } + if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) + { + mDisabledItems.push_back(std::string("Replace Outfit")); + } + mItems.push_back(std::string("Outfit Separator")); } } @@ -2827,31 +2929,26 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) uuid_vec_t folders; folders.push_back(category->getUUID()); - mMenu = menu.getHandle(); sSelf = getHandle(); LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); fetch->startFetch(); inc_busy_count(); - if(fetch->isFinished()) + if (fetch->isFinished()) { - //buildContextMenuFolderOptions(flags); - // everything is already here - call done. - fetch->done(); + buildContextMenuFolderOptions(flags); } else { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. + // it's all on its way - add an observer, and the inventory will call done for us when everything is here. gInventory.addObserver(fetch); } } - else - { - mItems.push_back(std::string("--no options--")); - mDisabledItems.push_back(std::string("--no options--")); - } hide_context_entries(menu, mItems, mDisabledItems); + + // Reposition the menu, in case we're adding items to an existing menu. + menu.needsArrange(); + menu.arrangeAndClear(); } BOOL LLFolderBridge::hasChildren() const @@ -2939,7 +3036,7 @@ void LLFolderBridge::createNewCategory(void* user_data) { LLFolderBridge* bridge = (LLFolderBridge*)user_data; if(!bridge) return; - LLInventoryPanel* panel = dynamic_cast(bridge->mInventoryPanel); + LLInventoryPanel* panel = dynamic_cast(bridge->mInventoryPanel.get()); if (!panel) return; LLInventoryModel* model = panel->getModel(); if(!model) return; @@ -3133,7 +3230,7 @@ void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item) // use callback to rearrange favorite landmarks after adding // to have new one placed before target (on which it was dropped). See EXT-4312. LLPointer cb = new AddFavoriteLandmarkCallback(); - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; if (drag_over_item && drag_over_item->getListener()) { @@ -3228,6 +3325,20 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); } +/* TODO + if (is_movable) + { + // Don't allow creating duplicates in the Calling Card/Friends + // subfolders, see bug EXT-1599. Check is item direct descendent + // of target folder and forbid item's movement if it so. + // Note: isItemDirectDescendentOfCategory checks if + // passed category is in the Calling Card/Friends folder + is_movable &= !LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(inv_item, getCategory()); + } +*/ + + // + //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- // Determine if item can be moved & dropped @@ -3264,7 +3375,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); if (active_panel) { - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); if (active_panel && (panel != active_panel)) { active_panel->unSelectAll(); @@ -3297,7 +3408,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, // //-------------------------------------------------------------------------------- - } } else if(LLToolDragAndDrop::SOURCE_WORLD == source) @@ -3490,6 +3600,50 @@ void LLTextureBridge::openItem() } } +// virtual +void LLTextureBridge::performAction(LLInventoryModel* model, std::string action) +{ + // TODO + /*if ("save_as" == action) + { + LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); + LLPreviewTexture* preview_texture = LLFloaterReg::findTypedInstance("preview_texture", mUUID); + if (preview_texture) + { + preview_texture->openToSave(); + } + } + else*/ + LLItemBridge::performAction(model, action); +} + +void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLTextureBridge::buildContextMenu()" << llendl; + menuentry_vec_t items; + menuentry_vec_t disabled_items; + if(isItemInTrash()) + { + addTrashContextMenuOptions(items, disabled_items); + } + else + { + addOpenRightClickMenuOption(items); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + //TODO + /*items.push_back(std::string("Texture Separator")); + items.push_back(std::string("Save As")); + if (!canSaveTexture()) + { + disabled_items.push_back(std::string("Save As")); + }*/ + } + hide_context_entries(menu, items, disabled_items); +} + + // +=================================================+ // | LLSoundBridge | // +=================================================+ @@ -3747,7 +3901,7 @@ LLCallingCardBridge::~LLCallingCardBridge() void LLCallingCardBridge::refreshFolderViewItem() { - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL; if (itemp) { @@ -4216,13 +4370,12 @@ void LLAnimationBridge::performAction(LLInventoryModel* model, std::string actio // See if we can bring an existing preview to the front if(LLPreview::show( mUUID )) return; - - LLViewerInventoryItem *item = getItem(); - if( item ) + + if( getItem() ) { - S32 activate = 0; - if ("playworld" == action) activate = 1; - if ("playlocal" == action) activate = 2; + LLPreviewAnim::e_activation_type activate = LLPreviewAnim::NONE; + if ("playworld" == action) activate = LLPreviewAnim::PLAY; + if ("playlocal" == action) activate = LLPreviewAnim::AUDITION; S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); @@ -4230,7 +4383,7 @@ void LLAnimationBridge::performAction(LLInventoryModel* model, std::string actio rect.translate( left - rect.mLeft, top - rect.mTop ); LLPreviewAnim* preview = new LLPreviewAnim("preview anim", rect, - getPrefix() + item->getName(), + getPrefix() + getItem()->getName(), mUUID, activate); // Force to be entirely onscreen. @@ -4260,7 +4413,7 @@ void LLAnimationBridge::openItem() rect, getPrefix() + item->getName(), mUUID, - 0); + LLPreviewAnim::NONE); preview->setFocus(TRUE); // Force to be entirely onscreen. gFloaterView->adjustToFitScreen(preview, FALSE); @@ -4629,7 +4782,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // [/RLVa:KB] } - LLSimpleListener* callback = mInventoryPanel->getListenerByName("Inventory.AttachObject"); + LLSimpleListener* callback = mInventoryPanel.get()->getListenerByName("Inventory.AttachObject"); if (callback) { @@ -4638,7 +4791,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } LLMenuItemCallGL *new_item = new LLMenuItemCallGL("Custom...", NULL, NULL); attach_menu->append(new_item); - LLSimpleListener* callback = mInventoryPanel->getListenerByName("Inventory.AttachCustom"); + LLSimpleListener* callback = mInventoryPanel.get()->getListenerByName("Inventory.AttachCustom"); new_item->addListener(callback, "on_click", LLSD()); } } @@ -4984,12 +5137,11 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Wearable And Object Separator")); - items.push_back(std::string("Wearable Wear")); items.push_back(std::string("Wearable Edit")); // [RLVa:KB] - Checked: 2011-09-16 (RLVa-1.1.4a) | Added: RLVa-1.1.4a if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) { - disabled_items.push_back(std::string("Wearable Wear")); + disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Edit")); } // [/RLVa:KB] @@ -5294,6 +5446,7 @@ void LLWearableBridge::removeFromAvatar() } } + // +=================================================+ // | LLLinkItemBridge | // +=================================================+ @@ -5400,6 +5553,7 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::string LLLinkFolderBridge::sPrefix("Link: "); LLUIImagePtr LLLinkFolderBridge::getIcon() const { + //For now, all inv links share this icon. There is no 'overlay' mechanism yet. return LLUI::getUIImage("inv_link_folder.tga"); } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3b191498a..eb952262b 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -154,9 +154,8 @@ protected: const LLUUID& new_parent, BOOL restamp); void removeBatchNoCheck(LLDynamicArray& batch); - protected: - LLInventoryPanel* mInventoryPanel; + LLHandle mInventoryPanel; LLFolderView* mRoot; LLUUID mUUID; // item id LLInventoryType::EType mInvType; @@ -165,6 +164,24 @@ protected: }; class AIFilePicker; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInvFVBridgeBuilder +// +// This class intended to build Folder View Bridge via LLInvFVBridge::createBridge. +// It can be overridden with another way of creation necessary Inventory-Folder-View-Bridge. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFVBridgeBuilder +{ +public: + virtual ~LLInventoryFVBridgeBuilder() {} + virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, + LLInventoryType::EType inv_type, + LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid, + U32 flags = 0x00) const; +}; class LLItemBridge : public LLInvFVBridge { @@ -251,9 +268,9 @@ public: virtual BOOL isItemCopyable() const; virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteableAsLink() const; - + virtual BOOL copyToClipboard() const; + static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type); - //static void createWearable(LLUUID parent_folder_id, LLWearableType::EType type); LLViewerInventoryCategory* getCategory() const; LLHandle getHandle() { mHandle.bind(this); return mHandle; } @@ -302,13 +319,11 @@ public: private: BOOL mCallingCards; BOOL mWearables; - LLHandle mMenu; menuentry_vec_t mItems; menuentry_vec_t mDisabledItems; LLRootHandle mHandle; }; - class LLTextureBridge : public LLItemBridge { public: @@ -323,8 +338,8 @@ public: } virtual LLUIImagePtr getIcon() const; virtual void openItem(); - //virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - //virtual void performAction(LLInventoryModel* model, std::string action); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual void performAction(LLInventoryModel* model, std::string action); bool canSaveTexture(void); }; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index f085c7ba2..2b7dba47f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1,32 +1,26 @@ -/** - * @file llinventoryview.cpp - * @brief Implementation of the inventory view and associated stuff. +/* + * @file llinventorypanel.cpp + * @brief Implementation of the inventory panel and associated stuff. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,6 +31,7 @@ #include "llagent.h" #include "llagentwearables.h" +#include "llappearancemgr.h" #include "lluictrlfactory.h" #include "llfloatercustomize.h" #include "llfolderview.h" @@ -58,12 +53,11 @@ static LLRegisterWidget r("inventory_panel"); - - -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - +const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); +const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); +const std::string LLInventoryPanel::WORNITEMS_SORT_ORDER = std::string("WornItemsSortOrder"); +const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); +static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -89,10 +83,50 @@ protected: -const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); -const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); -const std::string LLInventoryPanel::WORNITEMS_SORT_ORDER = std::string("WornItemsSortOrder"); -const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInvPanelComplObserver +// +// Calls specified callback when all specified items become complete. +// +// Usage: +// observer = new LLInvPanelComplObserver(boost::bind(onComplete)); +// inventory->addObserver(observer); +// observer->reset(); // (optional) +// observer->watchItem(incomplete_item1_id); +// observer->watchItem(incomplete_item2_id); +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInvPanelComplObserver : public LLInventoryCompletionObserver +{ +public: + typedef boost::function callback_t; + + LLInvPanelComplObserver(callback_t cb) + : mCallback(cb) + { + } + + void reset(); + +private: + /*virtual*/ void done(); + + /// Called when all the items are complete. + callback_t mCallback; +}; + +void LLInvPanelComplObserver::reset() +{ + mIncomplete.clear(); + mComplete.clear(); +} + +void LLInvPanelComplObserver::done() +{ + mCallback(); +} LLInventoryPanel::LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, @@ -101,56 +135,66 @@ LLInventoryPanel::LLInventoryPanel(const std::string& name, BOOL allow_multi_select, LLView *parent_view) : LLPanel(name, rect, TRUE), - mInventory(inventory), mInventoryObserver(NULL), + mCompletionObserver(NULL), mFolderRoot(NULL), mScroller(NULL), + mSortOrderSetting(sort_order_setting), + mInventory(inventory), mAllowMultiSelect(allow_multi_select), - mSortOrderSetting(sort_order_setting) + mViewsInitialized(false), + mInvFVBridgeBuilder(NULL) { + mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; + setBackgroundColor(gColors.getColor("InventoryBackgroundColor")); setBackgroundVisible(TRUE); setBackgroundOpaque(TRUE); } -BOOL LLInventoryPanel::postBuild() +void LLInventoryPanel::buildFolderView() { - init_inventory_panel_actions(this); - - LLRect folder_rect(0, - 0, - getRect().getWidth(), - 0); - - LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(LLAssetType::AT_CATEGORY, + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY, LLAssetType::AT_CATEGORY, LLInventoryType::IT_CATEGORY, this, NULL, LLUUID::null); - mFolderRoot = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this, new_listener); - mFolderRoot->setAllowMultiSelect(mAllowMultiSelect); + mFolderRoot = createFolderView(new_listener, true/*params.use_label_suffix()*/); +} +BOOL LLInventoryPanel::postBuild() +{ + init_inventory_panel_actions(this); - // scroller - LLRect scroller_view_rect = getRect(); - scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); - mScroller = new LLScrollableContainerView(std::string("Inventory Scroller"), - scroller_view_rect, - mFolderRoot); - mScroller->setFollowsAll(); - mScroller->setReserveScrollCorner(TRUE); - addChild(mScroller); - mFolderRoot->setScrollContainer(mScroller); + buildFolderView(); + { + // scroller + LLRect scroller_view_rect = getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + mScroller = new LLScrollableContainerView(std::string("Inventory Scroller"), + scroller_view_rect, + mFolderRoot); + mScroller->setFollowsAll(); + mScroller->setReserveScrollCorner(TRUE); + addChild(mScroller); + mFolderRoot->setScrollContainer(mScroller); + } - // set up the callbacks from the inventory we're viewing, and then - // build everything. + // Set up the callbacks from the inventory we're viewing, and then build everything. mInventoryObserver = new LLInventoryPanelObserver(this); mInventory->addObserver(mInventoryObserver); - rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); - // bit of a hack to make sure the inventory is open. - mFolderRoot->openFolder(std::string("My Inventory")); + mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this)); + mInventory->addObserver(mCompletionObserver); + + // Build view of inventory if we need default full hierarchy and inventory ready, + // otherwise wait for idle callback. + if (mInventory->isInventoryUsable() && !mViewsInitialized) + { + initializeViews(); + } + gIdleCallbacks.addFunction(onIdle, (void*)this); if (mSortOrderSetting != INHERIT_SORT_ORDER) { @@ -177,9 +221,14 @@ LLInventoryPanel::~LLInventoryPanel() } } + gIdleCallbacks.deleteFunction(onIdle, this); + // LLView destructor will take care of the sub-views. mInventory->removeObserver(mInventoryObserver); + mInventory->removeObserver(mCompletionObserver); delete mInventoryObserver; + delete mCompletionObserver; + mScroller = NULL; } @@ -301,11 +350,9 @@ U32 LLInventoryPanel::getSortOrder() const return mFolderRoot->getSortOrder(); } -// static -LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel() +void LLInventoryPanel::requestSort() { - LLInventoryView *view = LLInventoryView::getActiveInventory(); - return view ? view->getPanel() : NULL; + mFolderRoot->requestSort(); } void LLInventoryPanel::setSinceLogoff(BOOL sl) @@ -335,8 +382,8 @@ void LLInventoryPanel::modelChanged(U32 mask) bool handled = false; - //if (!mViewsInitialized) return; - + if (!mViewsInitialized) return; + const LLInventoryModel* model = getModel(); if (!model) return; @@ -353,7 +400,7 @@ void LLInventoryPanel::modelChanged(U32 mask) // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item // to folder is the fast way to get a folder without searching through folders tree. - //LLFolderViewFolder* view_folder = dynamic_cast(view_item); + LLFolderViewFolder* view_folder = dynamic_cast(view_item); ////////////////////////////// // LABEL Operation @@ -377,7 +424,7 @@ void LLInventoryPanel::modelChanged(U32 mask) ////////////////////////////// // REBUILD Operation // Destroy and regenerate the UI. - /*if (mask & LLInventoryObserver::REBUILD) + if (mask & LLInventoryObserver::REBUILD) { handled = true; if (model_item && view_item) @@ -386,7 +433,7 @@ void LLInventoryPanel::modelChanged(U32 mask) } view_item = buildNewViews(item_id); view_folder = dynamic_cast(view_item); - }*/ + } ////////////////////////////// // INTERNAL Operation @@ -402,13 +449,13 @@ void LLInventoryPanel::modelChanged(U32 mask) ////////////////////////////// // SORT Operation // Sort the folder. - /*if (mask & LLInventoryObserver::SORT) + if (mask & LLInventoryObserver::SORT) { if (view_folder) { view_folder->requestSort(); } - }*/ + } // We don't typically care which of these masks the item is actually flagged with, since the masks // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into @@ -479,11 +526,60 @@ LLFolderView* LLInventoryPanel::getRootFolder() { return mFolderRoot; } + + +// static +void LLInventoryPanel::onIdle(void *userdata) +{ + if (!gInventory.isInventoryUsable()) + return; + + LLInventoryPanel *self = (LLInventoryPanel*)userdata; + // Inventory just initialized, do complete build + if (!self->mViewsInitialized) + { + self->initializeViews(); + } + if (self->mViewsInitialized) + { + gIdleCallbacks.deleteFunction(onIdle, (void*)self); + } +} + const LLUUID& LLInventoryPanel::getRootFolderID() const { return mFolderRoot->getListener()->getUUID(); } -LLFolderViewItem* LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) + +void LLInventoryPanel::initializeViews() +{ + if (!gInventory.isInventoryUsable()) return; + + rebuildViewsFor(getRootFolderID()); + + mViewsInitialized = true; + + openStartFolderOrMyInventory(); + + // Special case for new user login + if (gAgent.isFirstLogin()) + { + // Auto open the user's library + LLFolderViewFolder* lib_folder = mFolderRoot->getFolderByID(gInventory.getLibraryRootFolderID()); + if (lib_folder) + { + lib_folder->setOpen(TRUE); + } + + // Auto close the user's my inventory folder + LLFolderViewFolder* my_inv_folder = mFolderRoot->getFolderByID(gInventory.getRootFolderID()); + if (my_inv_folder) + { + my_inv_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + } + } +} +LLFolderViewItem* LLInventoryPanel::rebuildViewsFor(const LLUUID& id) { // Destroy the old view for this ID so we can rebuild it. LLFolderViewItem* old_view = mFolderRoot->getItemByID(id); @@ -495,6 +591,18 @@ LLFolderViewItem* LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) return buildNewViews(id); } +LLFolderView * LLInventoryPanel::createFolderView(LLInvFVBridge * bridge, bool useLabelSuffix) +{ + LLRect folder_rect(0, + 0, + getRect().getWidth(), + 0); + + LLFolderView* ret = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this, bridge); + ret->setAllowMultiSelect(mAllowMultiSelect); + return ret; +} + LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge) { return new LLFolderViewFolder( @@ -544,7 +652,7 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) if ((objectp->getType() == LLAssetType::AT_CATEGORY) && (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) { - LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(), objectp->getType(), LLInventoryType::IT_CATEGORY, this, @@ -564,7 +672,7 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) { // Build new view for item. LLInventoryItem* item = (LLInventoryItem*)objectp; - LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(item->getType(), + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), item->getActualType(), item->getInventoryType(), this, @@ -622,6 +730,23 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) return itemp; } +// bit of a hack to make sure the inventory is open. +void LLInventoryPanel::openStartFolderOrMyInventory() +{ + // Find My Inventory folder and open it up by name + for (LLView *child = mFolderRoot->getFirstChild(); child; child = mFolderRoot->findNextSibling(child)) + { + LLFolderViewFolder *fchild = dynamic_cast(child); + if (fchild + && fchild->getListener() + && fchild->getListener()->getUUID() == gInventory.getRootFolderID()) + { + fchild->setOpen(TRUE); + break; + } + } +} + struct LLConfirmPurgeData { LLUUID mID; @@ -654,6 +779,10 @@ protected: const LLUUID& mID; }; +void LLInventoryPanel::onItemsCompletion() +{ + if (mFolderRoot) mFolderRoot->updateMenu(); +} void LLInventoryPanel::openSelected() { @@ -707,6 +836,26 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, } + +void LLInventoryPanel::onFocusLost() +{ + // inventory no longer handles cut/copy/paste/delete + if (LLEditMenuHandler::gEditMenuHandler == mFolderRoot) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + + LLPanel::onFocusLost(); +} + +void LLInventoryPanel::onFocusReceived() +{ + // inventory now handles cut/copy/paste/delete + LLEditMenuHandler::gEditMenuHandler = mFolderRoot; + + LLPanel::onFocusReceived(); +} + void LLInventoryPanel::openAllFolders() { mFolderRoot->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); @@ -757,6 +906,19 @@ void LLInventoryPanel::clearSelection() void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) { + // Schedule updating the folder view context menu when all selected items become complete (STORM-373). + mCompletionObserver->reset(); + for (std::deque::const_iterator it = items.begin(); it != items.end(); ++it) + { + LLUUID id = (*it)->getListener()->getUUID(); + LLViewerInventoryItem* inv_item = mInventory->getItem(id); + + if (inv_item && !inv_item->isFinished()) + { + mCompletionObserver->watchItem(id); + } + } + LLFolderView* fv = getRootFolder(); if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename { @@ -808,3 +970,30 @@ void LLInventoryPanel::dumpSelectionInformation(void* user_data) LLInventoryPanel* iv = (LLInventoryPanel*)user_data; iv->mFolderRoot->dumpSelectionInformation(); } +// static +LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) +{ + LLInventoryPanel* res = NULL; + LLInventoryView* floater_inventory = LLInventoryView::getActiveInventory(); + if (!floater_inventory) + { + llwarns << "Could not find My Inventory floater" << llendl; + return FALSE; + } + res = floater_inventory ? floater_inventory->getActivePanel() : NULL; + if (res) + { + // Make sure the floater is not minimized (STORM-438). + if (floater_inventory && floater_inventory->isMinimized()) + { + floater_inventory->setMinimized(FALSE); + } + } + else if (auto_open) + { + floater_inventory->open(); + + res = floater_inventory->getActivePanel(); + } + return res; +} \ No newline at end of file diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index af5888691..883fd4636 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -47,16 +47,13 @@ #include "lluictrlfactory.h" #include -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryView -// -// This is the controller class specific for handling agent -// inventory. It deals with the buttons and views used to navigate as -// well as controls the behavior of the overall object. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - +class LLFolderView; +class LLFolderViewFolder; +class LLFolderViewItem; +class LLInventoryFilter; class LLInventoryModel; class LLInvFVBridge; +class LLInventoryFVBridgeBuilder; class LLMenuBarGL; class LLCheckBoxCtrl; class LLSpinCtrl; @@ -65,19 +62,21 @@ class LLTextBox; class LLIconCtrl; class LLSaveFolderState; class LLSearchEditor; - +class LLInvPanelComplObserver; class LLInventoryPanel : public LLPanel { -public: +protected: LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, LLView *parent_view = NULL); - ~LLInventoryPanel(); +public: + virtual ~LLInventoryPanel(); +public: LLInventoryModel* getModel() { return mInventory; } BOOL postBuild(); @@ -93,6 +92,9 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); + // LLUICtrl methods + /*virtual*/ void onFocusLost(); + /*virtual*/ void onFocusReceived(); // Call this method to set the selection. void openAllFolders(); @@ -130,7 +132,12 @@ public: void openSelected(); void unSelectAll(); + + static void onIdle(void* user_data); + // Find whichever inventory panel is active / on top. + // "Auto_open" determines if we open an inventory panel if none are open. + static LLInventoryPanel *getActiveInventoryPanel(BOOL auto_open = TRUE); public: // TomY TODO: Move this elsewhere? @@ -144,13 +151,27 @@ public: U32 next_owner_perm = 0); protected: + void openStartFolderOrMyInventory(); // open the first level of inventory + void onItemsCompletion(); // called when selected items are complete + LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; - + LLInvPanelComplObserver* mCompletionObserver; BOOL mAllowMultiSelect; LLFolderView* mFolderRoot; LLScrollableContainerView* mScroller; + + /** + * Pointer to LLInventoryFVBridgeBuilder. + * + * It is set in LLInventoryPanel's constructor and can be overridden in derived classes with + * another implementation. + * Take into account it will not be deleted by LLInventoryPanel itself. + */ + const LLInventoryFVBridgeBuilder* mInvFVBridgeBuilder; + + //-------------------------------------------------------------------- // Sorting //-------------------------------------------------------------------- @@ -159,24 +180,30 @@ public: static const std::string RECENTITEMS_SORT_ORDER; static const std::string WORNITEMS_SORT_ORDER; static const std::string INHERIT_SORT_ORDER; - + void setSortOrder(U32 order); U32 getSortOrder() const; + void requestSort(); - static LLInventoryPanel *getActiveInventoryPanel(); private: const std::string mSortOrderSetting; LLUUID mSelectThisID; // if non null, select this item public: + BOOL getIsViewsInitialized() const { return mViewsInitialized; } const LLUUID& getRootFolderID() const; protected: - // Given the id and the parent, build all of the folder views. - LLFolderViewItem* rebuildViewsFor(const LLUUID& id, U32 mask); + // Builds the UI. Call this once the inventory is usable. + void initializeViews(); + LLFolderViewItem* rebuildViewsFor(const LLUUID& id); // Given the id and the parent, build all of the folder views. + + virtual void buildFolderView(); + LLFolderViewItem* buildNewViews(const LLUUID& id); - LLFolderViewItem* buildNewViews(const LLUUID& id); + virtual LLFolderView* createFolderView(LLInvFVBridge * bridge, bool useLabelSuffix); virtual LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge); virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge); + BOOL mViewsInitialized; // Views have been generated }; class LLInventoryView; diff --git a/indra/newview/lllocalinventory.cpp b/indra/newview/lllocalinventory.cpp index 9b1494edf..dbe79684e 100644 --- a/indra/newview/lllocalinventory.cpp +++ b/indra/newview/lllocalinventory.cpp @@ -105,7 +105,7 @@ void LLLocalInventory::open(LLUUID item_id) rect, "", item_id, - 0); + LLPreviewAnim::NONE); floaterp->setFocus(TRUE); gFloaterView->adjustToFitScreen(floaterp, FALSE); } diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 08908b79c..1619d6743 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1434,7 +1434,7 @@ void LLTaskAnimationBridge::openItem() rect, getName(), mUUID, - 0, + LLPreviewAnim::NONE, mPanel->getTaskUUID()); preview->setFocus(TRUE); // take focus if you're looking at one of these diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 0752292ae..4cc0c6914 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -51,55 +51,18 @@ extern LLAgent gAgent; -LLPreviewAnim::LLPreviewAnim(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const S32& activate, const LLUUID& object_uuid ) : +LLPreviewAnim::LLPreviewAnim(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const e_activation_type& _activate, const LLUUID& object_uuid ) : LLPreview( name, rect, title, item_uuid, object_uuid) { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_animation.xml"); - - childSetAction("Anim play btn",playAnim,this); - childSetAction("Anim audition btn",auditionAnim,this); - - const LLInventoryItem* item = getItem(); - - childSetCommitCallback("desc", LLPreview::onText, this); - childSetText("desc", item->getDescription()); - childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); - + mIsCopyable = false; setTitle(title); - + LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_animation.xml"); if (!getHost()) { LLRect curRect = getRect(); translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); } - - mIsCopyable = false; - // preload the animation - if(item) - { - gAgentAvatarp->createMotion(item->getAssetUUID()); - - const LLPermissions& perm = item->getPermissions(); - mIsCopyable = (perm.getCreator() == gAgent.getID()); - } - - switch ( activate ) - { - case 1: - { - playAnim( (void *) this ); - break; - } - case 2: - { - auditionAnim( (void *) this ); - break; - } - default: - { - //do nothing - } - } + activate(_activate); } // static @@ -115,6 +78,50 @@ void LLPreviewAnim::endAnimCallback( void *userdata ) } } +// virtual +BOOL LLPreviewAnim::postBuild() +{ + const LLInventoryItem* item = getItem(); + + // preload the animation + if(item) + { + gAgentAvatarp->createMotion(item->getAssetUUID()); + childSetText("desc", item->getDescription()); + + const LLPermissions& perm = item->getPermissions(); + mIsCopyable = (perm.getCreator() == gAgent.getID()); + } + + childSetAction("Anim play btn",playAnim,this); + childSetAction("Anim audition btn",auditionAnim,this); + + childSetCommitCallback("desc", LLPreview::onText, this); + childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); + + return LLPreview::postBuild(); +} +void LLPreviewAnim::activate(e_activation_type type) +{ + switch ( type ) + { + case PLAY: + { + playAnim( (void *) this ); + break; + } + case AUDITION: + { + auditionAnim( (void *) this ); + break; + } + default: + { + //do nothing + } + } +} + // static void LLPreviewAnim::playAnim( void *userdata ) { @@ -135,10 +142,7 @@ void LLPreviewAnim::playAnim( void *userdata ) { self->mPauseRequest = NULL; gAgent.sendAnimationRequest(itemID, ANIM_REQUEST_START); - - LLVOAvatar* avatar = gAgentAvatarp; - LLMotion* motion = avatar->findMotion(itemID); - + LLMotion* motion = gAgentAvatarp->findMotion(itemID); if (motion) { motion->setDeactivateCallback(&endAnimCallback, (void *)(new LLHandle(self->getHandle()))); @@ -172,9 +176,7 @@ void LLPreviewAnim::auditionAnim( void *userdata ) { self->mPauseRequest = NULL; gAgentAvatarp->startMotion(item->getAssetUUID()); - - LLVOAvatar* avatar = gAgentAvatarp; - LLMotion* motion = avatar->findMotion(itemID); + LLMotion* motion = gAgentAvatarp->findMotion(itemID); if (motion) { @@ -434,9 +436,7 @@ void LLPreviewAnim::onClose(bool app_quitting) { gAgentAvatarp->stopMotion(item->getAssetUUID()); gAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP); - - LLVOAvatar* avatar = gAgentAvatarp; - LLMotion* motion = avatar->findMotion(item->getAssetUUID()); + LLMotion* motion = gAgentAvatarp->findMotion(item->getAssetUUID()); if (motion) { diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index e4ddb65c5..bcc2bc383 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -41,9 +41,10 @@ class AIFilePicker; class LLPreviewAnim : public LLPreview { public: + enum e_activation_type { NONE = 0, PLAY = 1, AUDITION = 2 }; LLPreviewAnim(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, - const S32& activate, + const e_activation_type& activate, const LLUUID& object_uuid = LLUUID::null); static void playAnim( void* userdata ); @@ -65,6 +66,8 @@ public: static void copyAnimID(void* userdata); // static void endAnimCallback( void *userdata ); + /*virtual*/ BOOL postBuild(); + void activate(e_activation_type type); protected: virtual void onClose(bool app_quitting); diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 2cf58f0bf..74e25d0df 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -1,4 +1,4 @@ - + - + + @@ -276,11 +277,11 @@ + name="Object Wear" width="128"> + name="Object Add" width="128"> + name="Wearable And Object Wear" width="128"> Date: Sun, 19 Feb 2012 13:11:52 -0600 Subject: [PATCH 05/32] Added LLView::translateIntoRectWithExclusion utility function. --- indra/llui/llview.cpp | 102 ++++++++++++++++++++++++++++++++---------- indra/llui/llview.h | 1 + 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index b357ebaf2..49974d339 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1822,71 +1822,125 @@ LLView* LLView::findNextSibling(LLView* child) return (next_it != mChildList.end()) ? *next_it : NULL; } -// (Why top and left? That's where the drag bars are for floaters.) -BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside ) + + +LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, BOOL allow_partial_outside) { - S32 delta_x = 0; - S32 delta_y = 0; + LLCoordGL delta; if (allow_partial_outside) { const S32 KEEP_ONSCREEN_PIXELS = 16; - if( getRect().mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft ) + if( input.mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft ) { - delta_x = constraint.mLeft - (getRect().mRight - KEEP_ONSCREEN_PIXELS); + delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS); } else - if( getRect().mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight ) + if( input.mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight ) { - delta_x = constraint.mRight - (getRect().mLeft + KEEP_ONSCREEN_PIXELS); + delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS); } - if( getRect().mTop > constraint.mTop ) + if( input.mTop > constraint.mTop ) { - delta_y = constraint.mTop - getRect().mTop; + delta.mY = constraint.mTop - input.mTop; } else - if( getRect().mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom ) + if( input.mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom ) { - delta_y = constraint.mBottom - (getRect().mTop - KEEP_ONSCREEN_PIXELS); + delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS); } } else { - if( getRect().mLeft < constraint.mLeft ) + if( input.mLeft < constraint.mLeft ) { - delta_x = constraint.mLeft - getRect().mLeft; + delta.mX = constraint.mLeft - input.mLeft; } else - if( getRect().mRight > constraint.mRight ) + if( input.mRight > constraint.mRight ) { - delta_x = constraint.mRight - getRect().mRight; + delta.mX = constraint.mRight - input.mRight; // compensate for left edge possible going off screen - delta_x += llmax( 0, getRect().getWidth() - constraint.getWidth() ); + delta.mX += llmax( 0, input.getWidth() - constraint.getWidth() ); } - if( getRect().mTop > constraint.mTop ) + if( input.mTop > constraint.mTop ) { - delta_y = constraint.mTop - getRect().mTop; + delta.mY = constraint.mTop - input.mTop; } else - if( getRect().mBottom < constraint.mBottom ) + if( input.mBottom < constraint.mBottom ) { - delta_y = constraint.mBottom - getRect().mBottom; + delta.mY = constraint.mBottom - input.mBottom; // compensate for top edge possible going off screen - delta_y -= llmax( 0, getRect().getHeight() - constraint.getHeight() ); + delta.mY -= llmax( 0, input.getHeight() - constraint.getHeight() ); } } - if (delta_x != 0 || delta_y != 0) + return delta; +} + +// Moves the view so that it is entirely inside of constraint. +// If the view will not fit because it's too big, aligns with the top and left. +// (Why top and left? That's where the drag bars are for floaters.) +BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside ) +{ + LLCoordGL translation = getNeededTranslation(getRect(), constraint, allow_partial_outside); + + if (translation.mX != 0 || translation.mY != 0) { - translate(delta_x, delta_y); + translate(translation.mX, translation.mY); return TRUE; } return FALSE; } +// move this view into "inside" but not onto "exclude" +// NOTE: if this view is already contained in "inside", we ignore the "exclude" rect +BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside ) +{ + LLCoordGL translation = getNeededTranslation(getRect(), inside, allow_partial_outside); + + if (translation.mX != 0 || translation.mY != 0) + { + // translate ourselves into constraint rect + translate(translation.mX, translation.mY); + + // do we overlap with exclusion area? + // keep moving in the same direction to the other side of the exclusion rect + if (exclude.overlaps(getRect())) + { + // moving right + if (translation.mX > 0) + { + translate(exclude.mRight - getRect().mLeft, 0); + } + // moving left + else if (translation.mX < 0) + { + translate(exclude.mLeft - getRect().mRight, 0); + } + + // moving up + if (translation.mY > 0) + { + translate(0, exclude.mTop - getRect().mBottom); + } + // moving down + else if (translation.mY < 0) + { + translate(0, exclude.mBottom - getRect().mTop); + } + } + + return TRUE; + } + return FALSE; +} + + void LLView::centerWithin(const LLRect& bounds) { S32 left = bounds.mLeft + (bounds.getWidth() - getRect().getWidth()) / 2; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 4fb1fe605..f376d56c5 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -391,6 +391,7 @@ public: virtual void translate( S32 x, S32 y ); void setOrigin( S32 x, S32 y ) { mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); } BOOL translateIntoRect( const LLRect& constraint, BOOL allow_partial_outside ); + BOOL translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside ); void centerWithin(const LLRect& bounds); void setShape(const LLRect& new_rect, bool by_user = false); From a76105a60de1a9c649f1b22710f173d8870556dc Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sun, 19 Feb 2012 17:28:16 -0600 Subject: [PATCH 06/32] Few things were missing/misnamed in menu_inventory.xml --- .../default/xui/en-us/menu_inventory.xml | 4 +- .../skins/default/xui/fr/menu_inventory.xml | 57 +++++++++---------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 74e25d0df..56233228c 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -277,11 +277,11 @@ + name="Wearable And Object Wear" width="128"> + name="Wearable Add" width="128"> - - + + @@ -20,60 +20,55 @@ - - + + + + + - + - - - - - - - - + + + + + + + - + + + - - - + - + - + - - + + - - + + - - - - - \ No newline at end of file + \ No newline at end of file From e2e65c39bf6b80934ab0dba507ff361c938b946d Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sun, 19 Feb 2012 17:41:54 -0600 Subject: [PATCH 07/32] Fixed up LLMenuGL and variants a bit. --- indra/llui/lllineeditor.cpp | 20 +- indra/llui/llmenugl.cpp | 884 +++++++++++------- indra/llui/llmenugl.h | 158 ++-- indra/llui/lltexteditor.cpp | 21 +- indra/newview/llfloatermessagelog.cpp | 10 +- indra/newview/llinventorybridge.cpp | 20 +- indra/newview/llpanelobjectinventory.cpp | 2 +- indra/newview/llviewermenu.cpp | 676 +++++++------- indra/newview/llvoavatarself.cpp | 28 +- .../default/xui/en-us/floater_inventory.xml | 4 +- 10 files changed, 1047 insertions(+), 776 deletions(-) diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 9caaf70fd..98f2e7311 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -186,12 +186,12 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, { menu = new LLMenuGL(LLStringUtil::null); }*/ - menu->append(new LLMenuItemCallGL("Cut", context_cut, NULL, this)); - menu->append(new LLMenuItemCallGL("Copy", context_copy, NULL, this)); - menu->append(new LLMenuItemCallGL("Paste", context_paste, NULL, this)); - menu->append(new LLMenuItemCallGL("Delete", context_delete, NULL, this)); - menu->append(new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); - menu->appendSeparator("Spelsep"); + menu->addChild(new LLMenuItemCallGL("Cut", context_cut, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Copy", context_copy, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Paste", context_paste, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Delete", context_delete, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); + menu->addSeparator(); //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); menu->setCanTearOff(FALSE); menu->setVisible(FALSE); @@ -668,7 +668,7 @@ BOOL LLLineEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) SpellMenuBind * tempBind = suggestionMenuItems[i]; if(tempBind) { - menu->remove((LLMenuItemCallGL *)tempBind->menuItem); + menu->removeChild((LLMenuItemCallGL *)tempBind->menuItem); ((LLMenuItemCallGL *)tempBind->menuItem)->die(); //delete tempBind->menuItem; //tempBind->menuItem = NULL; @@ -705,7 +705,7 @@ BOOL LLLineEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) //new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); tempStruct->menuItem = suggMenuItem; suggestionMenuItems.push_back(tempStruct); - menu->append(suggMenuItem); + menu->addChild(suggMenuItem); } SpellMenuBind * tempStruct = new SpellMenuBind; tempStruct->origin = this; @@ -716,7 +716,7 @@ BOOL LLLineEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) "Add Word", spell_add, NULL, tempStruct); tempStruct->menuItem = suggMenuItem; suggestionMenuItems.push_back(tempStruct); - menu->append(suggMenuItem); + menu->addChild(suggMenuItem); } } @@ -734,7 +734,7 @@ BOOL LLLineEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) tempStruct->word, spell_show, NULL, tempStruct); tempStruct->menuItem = suggMenuItem; suggestionMenuItems.push_back(tempStruct); - menu->append(suggMenuItem); + menu->addChild(suggMenuItem); } mLastContextMenuX = x; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 4a1368419..048c7c9b2 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -46,20 +46,21 @@ #include "llmenugl.h" +#include "llgl.h" #include "llmath.h" #include "llrender.h" #include "llfocusmgr.h" -#include "llfont.h" #include "llcoord.h" #include "llwindow.h" #include "llcriticaldamp.h" #include "lluictrlfactory.h" +#include "llbutton.h" #include "llfontgl.h" #include "llresmgr.h" +#include "lltrans.h" #include "llui.h" -#include "lltrans.h" #include "llstl.h" #include "v2math.h" @@ -100,10 +101,10 @@ const std::string SEPARATOR_LABEL( "-----------" ); const std::string VERTICAL_SEPARATOR_LABEL( "|" ); const std::string TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" ); -const std::string BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK -const std::string BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE -const std::string ARROW_UP ("^^^^^^^"); -const std::string ARROW_DOWN("vvvvvvv"); +const std::string LLMenuGL::BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK +const std::string LLMenuGL::BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE +const std::string LLMenuGL::ARROW_UP ("^^^^^^^"); +const std::string LLMenuGL::ARROW_DOWN("vvvvvvv"); const F32 MAX_MOUSE_SLOPE_SUB_MENU = 0.9f; @@ -133,21 +134,31 @@ const F32 ACTIVATE_HIGHLIGHT_TIME = 0.3f; // Default constructor LLMenuItemGL::LLMenuItemGL( const std::string& name, const std::string& label, KEY key, MASK mask ) : - LLView( name, TRUE ), + LLUICtrl( name, LLRect(), TRUE, NULL, NULL ), mJumpKey(KEY_NONE), - mAcceleratorKey( key ), - mAcceleratorMask( mask ), mAllowKeyRepeat(FALSE), mHighlight( FALSE ), mGotHover( FALSE ), mBriefItem( FALSE ), - mFont( LLFontGL::getFontSansSerif() ), mStyle(LLFontGL::NORMAL), - mDrawTextDisabled( FALSE ) + mDrawTextDisabled( FALSE ), + mFont( LLFontGL::getFontSansSerif() ), + mAcceleratorKey( key ), + mAcceleratorMask( mask ), + mLabel( label ), + mEnabledColor( sEnabledColor ), + mDisabledColor( sDisabledColor ), + mHighlightBackground( sHighlightBackground ), + mHighlightForeground( sHighlightForeground ) { setLabel( label ); } +LLMenuItemGL::~LLMenuItemGL() +{ + lldebugs << "Menu destroyed:" << this->getName() << llendl; +}; + // virtual LLXMLNodePtr LLMenuItemGL::getXML(bool save_children) const { @@ -190,6 +201,20 @@ LLXMLNodePtr LLMenuItemGL::getXML(bool save_children) const return node; } + +//virtual +void LLMenuItemGL::setValue(const LLSD& value) +{ + setLabel(value.asString()); +} + +//virtual +LLSD LLMenuItemGL::getValue() const +{ + return getLabel(); +} + +//virtual BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) @@ -207,6 +232,26 @@ BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask) return TRUE; } +//virtual +BOOL LLMenuItemGL::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + return LLUICtrl::handleRightMouseDown(x,y,mask); +} + +//virtual +BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + // If this event came from a right-click context menu spawn, + // process as a left-click to allow menu items to be hit + if (LLMenuHolderGL::sContextMenuSpawnPos.mX != S32_MAX + || LLMenuHolderGL::sContextMenuSpawnPos.mY != S32_MAX) + { + BOOL handled = handleMouseUp(x, y, mask); + return handled; + } + return LLUICtrl::handleRightMouseUp(x,y,mask); +} + // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp) @@ -311,9 +356,20 @@ U32 LLMenuItemGL::getNominalHeight( void ) const return llround(mFont->getLineHeight()) + MENU_ITEM_PADDING; } +//virtual +void LLMenuItemGL::setBriefItem(BOOL brief) +{ + mBriefItem = brief; +} + +//virtual +BOOL LLMenuItemGL::isBriefItem() const +{ + return mBriefItem; +} // Get the parent menu for this item -LLMenuGL* LLMenuItemGL::getMenu() +LLMenuGL* LLMenuItemGL::getMenu() const { return (LLMenuGL*) getParent(); } @@ -337,7 +393,7 @@ U32 LLMenuItemGL::getNominalWidth( void ) const if( KEY_NONE != mAcceleratorKey ) { - width += ACCEL_PAD_PIXELS; + width += getMenu()->getShortcutPad(); std::string temp; appendAcceleratorString( temp ); width += mFont->getWidth( temp ); @@ -357,8 +413,10 @@ void LLMenuItemGL::buildDrawLabel( void ) void LLMenuItemGL::doIt( void ) { - // close all open menus by default - // if parent menu is actually visible (and we are not triggering menu item via accelerator) + // Check torn-off status to allow left-arrow keyboard navigation back + // to parent menu. + // Also, don't hide if item triggered by keyboard shortcut (and hence + // parent not visible). if (!getMenu()->getTornOff() && getMenu()->getVisible()) { @@ -373,6 +431,12 @@ void LLMenuItemGL::doIt( void ) { getMenu()->clearHoverItem(); } + + if (mHighlight != highlight) + { + //dirtyRect(); + } + mHighlight = highlight; } @@ -411,25 +475,30 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask ) return FALSE; } -BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK ) +BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK mask) { // switch to mouse navigation mode LLMenuGL::setKeyboardMode(FALSE); doIt(); make_ui_sound("UISndClickRelease"); - return TRUE; + return LLView::handleMouseUp(x, y, mask); } -BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK ) +BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK mask) { // switch to mouse navigation mode LLMenuGL::setKeyboardMode(FALSE); setHighlight(TRUE); - return TRUE; + return LLView::handleMouseDown(x, y, mask); } +BOOL LLMenuItemGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) +{ + // If the menu is scrollable let it handle the wheel event. + return FALSE;//!getMenu()->isScrollable(); +} void LLMenuItemGL::draw( void ) { @@ -440,7 +509,11 @@ void LLMenuItemGL::draw( void ) // let disabled items be highlighted, just don't draw them as such if( getEnabled() && getHighlight() && !mBriefItem) { - gGL.color4fv( sHighlightBackground.mV ); + int debug_count = 0; + if (dynamic_cast(this)) + debug_count++; + gGL.color4fv( mHighlightBackground.mV ); + gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); } @@ -454,15 +527,15 @@ void LLMenuItemGL::draw( void ) if ( getEnabled() && getHighlight() ) { - color = sHighlightForeground; + color = mHighlightForeground; } else if( getEnabled() && !mDrawTextDisabled ) { - color = sEnabledColor; + color = mEnabledColor; } else { - color = sDisabledColor; + color = mDisabledColor; } // Draw the text on top. @@ -516,6 +589,14 @@ BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit& return TRUE; } +void LLMenuItemGL::handleVisibilityChange(BOOL new_visibility) +{ + if (getMenu()) + { + getMenu()->needsArrange(); + } + LLView::handleVisibilityChange(new_visibility); +} //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemSeparatorGL // @@ -543,7 +624,7 @@ LLXMLNodePtr LLMenuItemSeparatorGL::getXML(bool save_children) const void LLMenuItemSeparatorGL::draw( void ) { - gGL.color4fv( getDisabledColor().mV ); + gGL.color4fv( mDisabledColor.mV ); const S32 y = getRect().getHeight() / 2; const S32 PAD = 6; gl_line_2d( PAD, y, getRect().getWidth() - PAD, y ); @@ -554,11 +635,14 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask) LLMenuGL* parent_menu = getMenu(); if (y > getRect().getHeight() / 2) { - return parent_menu->handleMouseDown(x + getRect().mLeft, getRect().mTop + 1, mask); + // the menu items are in the child list in bottom up order + LLView* prev_menu_item = parent_menu->findNextSibling(this); + return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; } else { - return parent_menu->handleMouseDown(x + getRect().mLeft, getRect().mBottom - 1, mask); + LLView* next_menu_item = parent_menu->findPrevSibling(this); + return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE; } } @@ -567,11 +651,13 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask) LLMenuGL* parent_menu = getMenu(); if (y > getRect().getHeight() / 2) { - return parent_menu->handleMouseUp(x + getRect().mLeft, getRect().mTop + 1, mask); + LLView* prev_menu_item = parent_menu->findNextSibling(this); + return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; } else { - return parent_menu->handleMouseUp(x + getRect().mLeft, getRect().mBottom - 1, mask); + LLView* next_menu_item = parent_menu->findPrevSibling(this); + return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE; } } @@ -590,7 +676,6 @@ BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask) } } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemVerticalSeparatorGL // @@ -614,9 +699,8 @@ LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL( void ) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemTearOffGL //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LLMenuItemTearOffGL::LLMenuItemTearOffGL(LLHandle parent_floater_handle) : - LLMenuItemGL(std::string("tear off"), TEAROFF_SEPARATOR_LABEL), - mParentHandle(parent_floater_handle) +LLMenuItemTearOffGL::LLMenuItemTearOffGL() : + LLMenuItemGL(std::string("tear off"), TEAROFF_SEPARATOR_LABEL) { } @@ -630,6 +714,35 @@ LLXMLNodePtr LLMenuItemTearOffGL::getXML(bool save_children) const return node; } +// Returns the first floater ancestor if there is one +LLFloater* LLMenuItemTearOffGL::getParentFloater() +{ + LLView* parent_view = getMenu(); + + while (parent_view) + { + if (dynamic_cast(parent_view)) + { + return dynamic_cast(parent_view); + } + + bool parent_is_menu = dynamic_cast(parent_view) && !dynamic_cast(parent_view); + + if (parent_is_menu) + { + // use menu parent + parent_view = dynamic_cast(parent_view)->getParentMenuItem(); + } + else + { + // just use regular view parent + parent_view = parent_view->getParent(); + } + } + + return NULL; +} + void LLMenuItemTearOffGL::doIt() { if (getMenu()->getTornOff()) @@ -647,7 +760,7 @@ void LLMenuItemTearOffGL::doIt() getMenu()->needsArrange(); - LLFloater* parent_floater = mParentHandle.get(); + LLFloater* parent_floater = getParentFloater(); LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu()); if (tear_off_menu) @@ -662,7 +775,7 @@ void LLMenuItemTearOffGL::doIt() tear_off_menu->setFocus(TRUE); } } - LLMenuItemGL::doIt(); + LLMenuItemGL::onCommit(); } void LLMenuItemTearOffGL::draw() @@ -670,17 +783,17 @@ void LLMenuItemTearOffGL::draw() // disabled items can be highlighted, but shouldn't render as such if( getEnabled() && getHighlight() && !isBriefItem()) { - gGL.color4fv( getHighlightBGColor().mV ); + gGL.color4fv( mHighlightBackground.mV ); gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); } if (getEnabled()) { - gGL.color4fv( getEnabledColor().mV ); + gGL.color4fv( mEnabledColor.mV ); } else { - gGL.color4fv( getDisabledColor().mV ); + gGL.color4fv( mDisabledColor.mV ); } const S32 y = getRect().getHeight() / 3; const S32 PAD = 6; @@ -866,14 +979,21 @@ void LLMenuItemCallGL::doIt( void ) LLMenuItemGL::doIt(); } -void LLMenuItemCallGL::buildDrawLabel( void ) +void LLMenuItemCallGL::updateEnabled( void ) { - LLPointer fired_event = new LLEvent(this); - fireEvent(fired_event, "on_build"); if( mEnabledCallback ) { setEnabled( mEnabledCallback( mUserData ) ); } +} + +void LLMenuItemCallGL::buildDrawLabel( void ) +{ + updateEnabled(); + + LLPointer fired_event = new LLEvent(this); + fireEvent(fired_event, "on_build"); + if(mLabelCallback) { std::string label; @@ -883,16 +1003,18 @@ void LLMenuItemCallGL::buildDrawLabel( void ) LLMenuItemGL::buildDrawLabel(); } +BOOL LLMenuItemCallGL::handleKeyHere( KEY key, MASK mask ) +{ + return LLMenuItemGL::handleKeyHere(key, mask); +} + BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask ) { if( (!gKeyboard->getKeyRepeated(key) || getAllowKeyRepeat()) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) { LLPointer fired_event = new LLEvent(this); fireEvent(fired_event, "on_build"); - if( mEnabledCallback ) - { - setEnabled( mEnabledCallback( mUserData ) ); - } + updateEnabled(); if( !getEnabled() ) { if( mOnDisabledCallback ) @@ -953,7 +1075,7 @@ void LLMenuItemCheckGL::setValue(const LLSD& value) mChecked = value.asBoolean(); if(mChecked) { - mDrawBoolLabel = BOOLEAN_TRUE_PREFIX; + mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX; } else { @@ -993,7 +1115,7 @@ void LLMenuItemCheckGL::buildDrawLabel( void ) { if(mChecked || (mCheckCallback && mCheckCallback( getUserData() ) ) ) { - mDrawBoolLabel = BOOLEAN_TRUE_PREFIX; + mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX; } else { @@ -1027,7 +1149,7 @@ void LLMenuItemToggleGL::buildDrawLabel( void ) { if( *mToggle ) { - mDrawBoolLabel = BOOLEAN_TRUE_PREFIX; + mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX; } else { @@ -1050,47 +1172,51 @@ void LLMenuItemToggleGL::doIt( void ) } -LLMenuItemBranchGL::LLMenuItemBranchGL( const std::string& name, const std::string& label, LLHandle branch, +LLMenuItemBranchGL::LLMenuItemBranchGL( const std::string& name, const std::string& label, LLHandle branch_handle, KEY key, MASK mask ) : - LLMenuItemGL( name, label, key, mask ), - mBranch( branch ) + LLMenuItemGL( name, label, key, mask ) { - if(!dynamic_cast(branch.get())) + LLMenuGL* branch = dynamic_cast(branch_handle.get()); + if(!branch) { llerrs << "Non-menu handle passed as branch reference." << llendl; } - if(getBranch()) + if (branch) { - getBranch()->setVisible( FALSE ); - getBranch()->setParentMenuItem(this); + mBranchHandle = branch->getHandle(); + branch->setVisible(FALSE); + branch->setParentMenuItem(this); } } LLMenuItemBranchGL::~LLMenuItemBranchGL() { - LLView::deleteViewByHandle(mBranch); + if (mBranchHandle.get()) + { + mBranchHandle.get()->die(); + } } // virtual LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const { - // richard: this is redundant with parent, remove - if (getBranch()) + LLMenuGL* branch = getBranch(); + if (branch) { - if(getBranch()->getName() == name) + if (branch->getName() == name) { - return getBranch(); + return branch; } // Always recurse on branches - LLView* child = getBranch()->getChildView(name, recurse, FALSE); + LLView* child = branch->getChildView(name, recurse, FALSE); if(child) { return child; } } - return LLView::getChildView(name, recurse, create_if_missing);; + return LLView::getChildView(name, recurse, create_if_missing); } // virtual @@ -1106,11 +1232,7 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask) { - if(getBranch()) - { - return getBranch()->handleAcceleratorKey(key, mask); - } - return FALSE; + return getBranch() && getBranch()->handleAcceleratorKey(key, mask); } // virtual @@ -1129,19 +1251,21 @@ LLXMLNodePtr LLMenuItemBranchGL::getXML(bool save_children) const // if not, it will be added to the list BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list *listp) { - if(getBranch()) - { - U32 item_count = getBranch()->getItemCount(); - LLMenuItemGL *item; + LLMenuGL* branch = getBranch(); + if (!branch) + return FALSE; - while (item_count--) + U32 item_count = branch->getItemCount(); + LLMenuItemGL *item; + + while (item_count--) + { + if ((item = branch->getItem(item_count))) { - if ((item = getBranch()->getItem(item_count))) - { - return item->addToAcceleratorList(listp); - } + return item->addToAcceleratorList(listp); } } + return FALSE; } @@ -1153,7 +1277,7 @@ void LLMenuItemBranchGL::buildDrawLabel( void ) std::string st = mDrawAccelLabel; appendAcceleratorString( st ); mDrawAccelLabel = st; - mDrawBranchLabel = BRANCH_SUFFIX; + mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX; } // doIt() - do the primary functionality of the menu item. @@ -1163,7 +1287,7 @@ void LLMenuItemBranchGL::doIt( void ) // keyboard navigation automatically propagates highlight to sub-menu // to facilitate fast menu control via jump keys - if (getBranch() && LLMenuGL::getKeyboardMode() && !getBranch()->getHighlightedItem()) + if (LLMenuGL::getKeyboardMode() && getBranch()&& !getBranch()->getHighlightedItem()) { getBranch()->highlightNextItem(NULL); } @@ -1172,7 +1296,7 @@ void LLMenuItemBranchGL::doIt( void ) BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) { BOOL handled = FALSE; - if (called_from_parent && getBranch()) + if (getBranch() && called_from_parent) { handled = getBranch()->handleKey(key, mask, called_from_parent); } @@ -1188,7 +1312,7 @@ BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { BOOL handled = FALSE; - if (called_from_parent && getBranch()) + if (getBranch() && called_from_parent) { handled = getBranch()->handleUnicodeChar(uni_char, TRUE); } @@ -1204,21 +1328,21 @@ BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_pa void LLMenuItemBranchGL::setHighlight( BOOL highlight ) { - if (highlight == getHighlight()) return; - - if(!getBranch()) - { + if (highlight == getHighlight()) return; - } - BOOL auto_open = getEnabled() && (!getBranch()->getVisible() || getBranch()->getTornOff()); + LLMenuGL* branch = getBranch(); + if (!branch) + return; + + BOOL auto_open = getEnabled() && (!branch->getVisible() || branch->getTornOff()); // torn off menus don't open sub menus on hover unless they have focus if (getMenu()->getTornOff() && !((LLFloater*)getMenu()->getParent())->hasFocus()) { auto_open = FALSE; } // don't auto open torn off sub-menus (need to explicitly active menu item to give them focus) - if (getBranch()->getTornOff()) + if (branch->getTornOff()) { auto_open = FALSE; } @@ -1232,14 +1356,14 @@ void LLMenuItemBranchGL::setHighlight( BOOL highlight ) } else { - if (getBranch()->getTornOff()) + if (branch->getTornOff()) { - ((LLFloater*)getBranch()->getParent())->setFocus(FALSE); - getBranch()->clearHoverItem(); + ((LLFloater*)branch->getParent())->setFocus(FALSE); + branch->clearHoverItem(); } else { - getBranch()->setVisible( FALSE ); + branch->setVisible( FALSE ); } } } @@ -1266,6 +1390,7 @@ void LLMenuItemBranchGL::handleVisibilityChange( BOOL new_visibility ) { if (new_visibility == FALSE && getBranch() && !getBranch()->getTornOff()) { + lldebugs << "Forcing branch to visible. Menu: " << getName() << " Branch: " << getBranch()->getName() << llendl; getBranch()->setVisible(FALSE); } LLMenuItemGL::handleVisibilityChange(new_visibility); @@ -1273,40 +1398,60 @@ void LLMenuItemBranchGL::handleVisibilityChange( BOOL new_visibility ) BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask ) { - if (getMenu()->getVisible() && getBranch() && getBranch()->getVisible() && key == KEY_LEFT) + LLMenuGL* branch = getBranch(); + if (!branch) + return LLMenuItemGL::handleKeyHere(key, mask); + + // an item is highlighted, my menu is open, and I have an active sub menu or we are in + // keyboard navigation mode + if (getHighlight() + && getMenu()->isOpen() + && (isActive() || LLMenuGL::getKeyboardMode())) { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - BOOL handled = getBranch()->clearHoverItem(); - if (getBranch()->getTornOff()) + if (branch->getVisible() && key == KEY_LEFT) { - ((LLFloater*)getBranch()->getParent())->setFocus(FALSE); + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + BOOL handled = branch->clearHoverItem(); + if (branch->getTornOff()) + { + ((LLFloater*)branch->getParent())->setFocus(FALSE); + } + if (handled && getMenu()->getTornOff()) + { + ((LLFloater*)getMenu()->getParent())->setFocus(TRUE); + } + return handled; } - if (handled && getMenu()->getTornOff()) - { - ((LLFloater*)getMenu()->getParent())->setFocus(TRUE); - } - return handled; - } - if (getHighlight() && - getMenu()->isOpen() && - key == KEY_RIGHT && getBranch() && !getBranch()->getHighlightedItem()) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - LLMenuItemGL* itemp = getBranch()->highlightNextItem(NULL); - if (itemp) + if (key == KEY_RIGHT && !branch->getHighlightedItem()) { - return TRUE; + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + LLMenuItemGL* itemp = branch->highlightNextItem(NULL); + if (itemp) + { + return TRUE; + } } } - return LLMenuItemGL::handleKeyHere(key, mask); } +//virtual +BOOL LLMenuItemBranchGL::isActive() const +{ + return isOpen() && getBranch() && getBranch()->getHighlightedItem(); +} + +//virtual +BOOL LLMenuItemBranchGL::isOpen() const +{ + return getBranch() && getBranch()->isOpen(); +} + void LLMenuItemBranchGL::openMenu() { LLMenuGL* branch = getBranch(); @@ -1341,18 +1486,20 @@ void LLMenuItemBranchGL::openMenu() branch_rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS); } branch->setRect( branch_rect ); - S32 x = 0; - S32 y = 0; + + // if branch extends outside of menu region change the direction it opens in + S32 x, y; S32 delta_x = 0; S32 delta_y = 0; branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() ); if( y < menu_region_rect.mBottom ) { - delta_y = menu_region_rect.mBottom - y; + // open upwards if menu extends past bottom + // adjust by the height of the menu item branch since it is a submenu + delta_y = branch_rect.getHeight() - getRect().getHeight(); } - S32 menu_region_width = menu_region_rect.getWidth(); - if( x - menu_region_rect.mLeft > menu_region_width - branch_rect.getWidth() ) + if( x + branch_rect.getWidth() > menu_region_rect.mRight ) { // move sub-menu over to left side delta_x = llmax(-x, ( -(branch_rect.getWidth() + getRect().getWidth()))); @@ -1525,6 +1672,7 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask ) LLMenuGL::setKeyboardMode(FALSE); doIt(); make_ui_sound("UISndClick"); + setVisible(TRUE); return TRUE; } @@ -1620,7 +1768,7 @@ void LLMenuItemBranchDownGL::draw( void ) if( getHighlight() ) { - gGL.color4fv( getHighlightBGColor().mV ); + gGL.color4fv( mHighlightBackground.mV ); gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); } @@ -1633,20 +1781,19 @@ void LLMenuItemBranchDownGL::draw( void ) LLColor4 color; if (getHighlight()) { - color = getHighlightFGColor(); + color = mHighlightForeground; } else if( getEnabled() ) { - color = getEnabledColor(); + color = mEnabledColor; } else { - color = getDisabledColor(); + color = mDisabledColor; } getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color, LLFontGL::HCENTER, LLFontGL::BOTTOM, getFontStyle(), font_shadow ); - // underline navigation key only when keyboard navigation has been initiated if (getMenu()->jumpKeysActive() && LLMenuGL::getKeyboardMode()) { @@ -1674,7 +1821,7 @@ void LLMenuItemBranchDownGL::draw( void ) static LLRegisterWidget r1("menu"); // Default constructor -LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle parent_floater_handle ) +LLMenuGL::LLMenuGL( const std::string& name, const std::string& label ) : LLUICtrl( name, LLRect(), FALSE, NULL, NULL ), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), @@ -1689,17 +1836,17 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle< mTornOff(FALSE), mTearOffItem(NULL), mSpilloverBranch(NULL), + mFirstVisibleItem(NULL), mSpilloverMenu(NULL), - mParentFloaterHandle(parent_floater_handle), mJumpKey(KEY_NONE), - mNeedsArrange(FALSE) + mNeedsArrange(FALSE), + mShortcutPad(ACCEL_PAD_PIXELS) { mFadeTimer.stop(); - setCanTearOff(TRUE, parent_floater_handle); setTabStop(FALSE); } -LLMenuGL::LLMenuGL( const std::string& label, LLHandle parent_floater_handle ) +LLMenuGL::LLMenuGL( const std::string& label) : LLUICtrl( label, LLRect(), FALSE, NULL, NULL ), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), @@ -1715,11 +1862,12 @@ LLMenuGL::LLMenuGL( const std::string& label, LLHandle parent_floater mTearOffItem(NULL), mSpilloverBranch(NULL), mSpilloverMenu(NULL), - mParentFloaterHandle(parent_floater_handle), - mJumpKey(KEY_NONE) + mFirstVisibleItem(NULL), + mJumpKey(KEY_NONE), + mNeedsArrange(FALSE), + mShortcutPad(ACCEL_PAD_PIXELS) { mFadeTimer.stop(); - setCanTearOff(TRUE, parent_floater_handle); setTabStop(FALSE); } @@ -1732,14 +1880,12 @@ LLMenuGL::~LLMenuGL( void ) mJumpKeys.clear(); } -void LLMenuGL::setCanTearOff(BOOL tear_off, LLHandle parent_floater_handle ) +void LLMenuGL::setCanTearOff(BOOL tear_off) { if (tear_off && mTearOffItem == NULL) { - mTearOffItem = new LLMenuItemTearOffGL(parent_floater_handle); - mItems.insert(mItems.begin(), mTearOffItem); - addChildAtEnd(mTearOffItem); - needsArrange(); + mTearOffItem = new LLMenuItemTearOffGL(); + addChild(mTearOffItem); } else if (!tear_off && mTearOffItem != NULL) { @@ -1838,7 +1984,7 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory if (child->hasName(LL_MENU_ITEM_SEPARATOR_GL_TAG)) { - appendSeparator(item_name); + addSeparator(); } else { @@ -2074,6 +2220,40 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory } } +bool LLMenuGL::addChild(LLView* view, S32 tab_group) +{ + if (LLMenuGL* menup = dynamic_cast(view)) + { + lldebugs << "Adding menu " << menup->getName() << " to " << getName() << llendl; + appendMenu(menup); + return true; + } + else if (LLMenuItemGL* itemp = dynamic_cast(view)) + { + lldebugs << "Adding " << itemp->getName() << " to " << getName() << llendl; + append(itemp); + return true; + } + lldebugs << "Error adding unknown child '"<<(view ? view->getName() : std::string("NULL")) << "' to " << getName() << llendl; + return false; +} + +void LLMenuGL::removeChild( LLView* ctrl) +{ + // previously a dynamic_cast with if statement to check validity + // unfortunately removeChild is called by ~LLView, and at that point the + // object being deleted is no longer a LLMenuItemGL so a dynamic_cast will fail + LLMenuItemGL* itemp = static_cast(ctrl); + + item_list_t::iterator found_it = std::find(mItems.begin(), mItems.end(), (itemp)); + if (found_it != mItems.end()) + { + mItems.erase(found_it); + } + + return LLUICtrl::removeChild(ctrl); +} + // are we the childmost active menu and hence our jump keys should be enabled? // or are we a free-standing torn-off menu (which uses jump keys too) BOOL LLMenuGL::jumpKeysActive() @@ -2206,39 +2386,59 @@ void LLMenuGL::arrange( void ) // torn off menus are not constrained to the size of the screen U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth(); - U32 max_height = getTornOff() ? U32_MAX : menu_region_rect.getHeight(); + U32 max_height = U32_MAX; + if (!getTornOff()) + { + max_height = getRect().mTop - menu_region_rect.mBottom; + if (menu_region_rect.mTop - getRect().mTop > (S32)max_height) + { + max_height = menu_region_rect.mTop - getRect().mTop; + } + } + // *FIX: create the item first and then ask for its dimensions? - S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); + S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING; + // Scrolling support + item_list_t::iterator first_visible_item_iter; + item_list_t::iterator first_hidden_item_iter = mItems.end(); + //S32 height_before_first_visible_item = -1; + //S32 visible_items_height = 0; + //U32 scrollable_items_cnt = 0; + if (mHorizontalLayout) { item_list_t::iterator item_iter; for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { + // do first so LLMenuGLItemCall can call on_visible to determine if visible + (*item_iter)->buildDrawLabel(); + if ((*item_iter)->getVisible()) { if (!getTornOff() - && item_iter != mItems.begin() // Don't spillover the first item! + && *item_iter != mSpilloverBranch && width + (*item_iter)->getNominalWidth() > max_width - spillover_item_width) { // no room for any more items createSpilloverBranch(); - item_list_t::iterator spillover_iter; - for (spillover_iter = item_iter; spillover_iter != mItems.end(); ++spillover_iter) + std::vector items_to_remove; + std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); + std::vector::iterator spillover_iter; + for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) { LLMenuItemGL* itemp = (*spillover_iter); removeChild(itemp); - mSpilloverMenu->appendNoArrange(itemp); // *NOTE:Mani Favor addChild() in merge with skinning + mSpilloverMenu->addChild(itemp); } - mSpilloverMenu->arrange(); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch - mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch - mItems.erase(item_iter, mItems.end()); - mItems.push_back(mSpilloverBranch); + addChild(mSpilloverBranch); + height = llmax(height, mSpilloverBranch->getNominalHeight()); width += mSpilloverBranch->getNominalWidth(); + break; } else @@ -2255,29 +2455,33 @@ void LLMenuGL::arrange( void ) item_list_t::iterator item_iter; for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { + llassert_always((*item_iter)!=NULL); + // do first so LLMenuGLItemCall can call on_visible to determine if visible + (*item_iter)->buildDrawLabel(); + if ((*item_iter)->getVisible()) { if (!getTornOff() - && item_iter != mItems.begin() // Don't spillover the first item! + && *item_iter != mSpilloverBranch && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height) { // no room for any more items createSpilloverBranch(); - item_list_t::iterator spillover_iter; - for (spillover_iter= item_iter; spillover_iter != mItems.end(); ++spillover_iter) + std::vector items_to_remove; + std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); + std::vector::iterator spillover_iter; + for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) { LLMenuItemGL* itemp = (*spillover_iter); removeChild(itemp); - mSpilloverMenu->appendNoArrange(itemp); // *NOTE:Mani Favor addChild() in merge with skinning + mSpilloverMenu->addChild(itemp); } - mSpilloverMenu->arrange(); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch - mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch - mItems.erase(item_iter, mItems.end()); - mItems.push_back(mSpilloverBranch); addChild(mSpilloverBranch); + height += mSpilloverBranch->getNominalHeight(); width = llmax( width, mSpilloverBranch->getNominalWidth() ); + break; } else @@ -2294,6 +2498,7 @@ void LLMenuGL::arrange( void ) S32 cur_height = (S32)llmin(max_height, height); S32 cur_width = 0; + S32 offset = 0; item_list_t::iterator item_iter; for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { @@ -2308,15 +2513,15 @@ void LLMenuGL::arrange( void ) } else { - rect.setLeftTopAndSize( 0, cur_height, width, (*item_iter)->getNominalHeight()); - cur_height -= (*item_iter)->getNominalHeight(); + rect.setLeftTopAndSize( 0 + offset, cur_height, width, (*item_iter)->getNominalHeight()); + if (offset == 0) + { + cur_height -= (*item_iter)->getNominalHeight(); + } } (*item_iter)->setRect( rect ); - (*item_iter)->buildDrawLabel(); } } - - cleanupSpilloverBranch(); } if (mKeepFixedSize) { @@ -2324,7 +2529,6 @@ void LLMenuGL::arrange( void ) } } - void LLMenuGL::arrangeAndClear( void ) { if (mNeedsArrange) @@ -2342,11 +2546,10 @@ void LLMenuGL::createSpilloverBranch() delete mSpilloverMenu; // technically, you can't tear off spillover menus, but we're passing the handle // along just to be safe - mSpilloverMenu = new LLMenuGL(std::string("More"), std::string("More"), mParentFloaterHandle); + mSpilloverMenu = new LLMenuGL(std::string("More"), std::string("More")); mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); // Inherit colors mSpilloverMenu->setBackgroundColor( mBackgroundColor ); - mSpilloverMenu->setCanTearOff(FALSE); mSpilloverBranch = new LLMenuItemBranchGL(std::string("More"), std::string("More"), mSpilloverMenu->getHandle()); mSpilloverBranch->setFontStyle(LLFontGL::ITALIC); @@ -2360,22 +2563,12 @@ void LLMenuGL::cleanupSpilloverBranch() // head-recursion to propagate items back up to root menu mSpilloverMenu->cleanupSpilloverBranch(); - removeChild(mSpilloverBranch); - - item_list_t::iterator found_iter = std::find(mItems.begin(), mItems.end(), mSpilloverBranch); - if (found_iter != mItems.end()) - { - mItems.erase(found_iter); - } - // pop off spillover items while (mSpilloverMenu->getItemCount()) { LLMenuItemGL* itemp = mSpilloverMenu->getItem(0); mSpilloverMenu->removeChild(itemp); - mSpilloverMenu->mItems.erase(mSpilloverMenu->mItems.begin()); // put them at the end of our own list - mItems.push_back(itemp); addChild(itemp); } @@ -2489,6 +2682,7 @@ void LLMenuGL::empty( void ) cleanupSpilloverBranch(); mItems.clear(); + mFirstVisibleItem = NULL; deleteAllChildren(); @@ -2511,9 +2705,6 @@ BOOL LLMenuGL::handleJumpKey(KEY key) // switch to keyboard navigation mode LLMenuGL::setKeyboardMode(TRUE); - // force highlight to close old menus and any open sub-menus - - //clearHoverItem(); // force highlight to close old menus and open and sub-menus found_it->second->setHighlight(TRUE); found_it->second->doIt(); @@ -2528,40 +2719,18 @@ BOOL LLMenuGL::handleJumpKey(KEY key) // Add the menu item to this menu. BOOL LLMenuGL::append( LLMenuItemGL* item ) { - if (mSpilloverMenu) - { - return mSpilloverMenu->append(item); - } - + if (!item) return FALSE; mItems.push_back( item ); - addChild( item ); + LLUICtrl::addChild(item); needsArrange(); return TRUE; } -// *NOTE:Mani - appendNoArrange() should be removed when merging to skinning/viewer2.0 -// Its added as a fix to a viewer 1.23 bug that has already been address by skinning work. -BOOL LLMenuGL::appendNoArrange( LLMenuItemGL* item ) -{ - if (mSpilloverMenu) - { - return mSpilloverMenu->append(item); - } - - mItems.push_back( item ); - addChild( item ); - return TRUE; -} - // add a separator to this menu -BOOL LLMenuGL::appendSeparator( const std::string &separator_name ) +BOOL LLMenuGL::addSeparator() { - LLMenuItemGL* separator; - if (separator_name.empty()) - separator = new LLMenuItemSeparatorGL(std::string("separator")); - else - separator = new LLMenuItemSeparatorGL(separator_name); - return append( separator ); + LLMenuItemGL* separator = new LLMenuItemSeparatorGL(); + return addChild(separator); } // add a menu - this will create a cascading menu @@ -2581,35 +2750,10 @@ BOOL LLMenuGL::appendMenu( LLMenuGL* menu ) // Inherit colors menu->setBackgroundColor( mBackgroundColor ); - + menu->updateParent(LLMenuGL::sMenuContainer); return success; } -// Remove a menu item from this menu. -BOOL LLMenuGL::remove( LLMenuItemGL* item ) -{ - if (mSpilloverMenu) - { - cleanupSpilloverBranch(); - } - - item_list_t::iterator found_iter = std::find(mItems.begin(), mItems.end(), item); - if (found_iter != mItems.end()) - { - mItems.erase(found_iter); - } - - removeChild( item ); - - // We keep it around in case someone is pointing at it. - // The caller can delete it if it's safe. - // Note that getMenu() will still not work since its parent isn't a menu. - sMenuContainer->addChild( item ); - - needsArrange(); - return TRUE; -} - void LLMenuGL::setEnabledSubMenus(BOOL enable) { setEnabled(enable); @@ -2709,6 +2853,7 @@ LLMenuItemGL* LLMenuGL::getHighlightedItem() LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled) { + if (mItems.empty()) return NULL; // highlighting first item on a torn off menu is the // same as giving focus to it if (!cur_item && getTornOff()) @@ -2716,14 +2861,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa ((LLFloater*)getParent())->setFocus(TRUE); } - item_list_t::iterator cur_item_iter; - for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); ++cur_item_iter) - { - if( (*cur_item_iter) == cur_item) - { - break; - } - } + // Current item position in the items list + item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item); item_list_t::iterator next_item_iter; if (cur_item_iter == mItems.end()) @@ -2734,6 +2873,10 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa { next_item_iter = cur_item_iter; next_item_iter++; + + // First visible item position in the items list + item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem); + if (next_item_iter == mItems.end()) { next_item_iter = mItems.begin(); @@ -2755,7 +2898,7 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa while(1) { // skip separators and disabled/invisible items - if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && (*next_item_iter)->getType() != SEPARATOR_NAME) + if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && !dynamic_cast(*next_item_iter)) { if (cur_item) { @@ -2787,6 +2930,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled) { + if (mItems.empty()) return NULL; + // highlighting first item on a torn off menu is the // same as giving focus to it if (!cur_item && getTornOff()) @@ -2794,14 +2939,8 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa ((LLFloater*)getParent())->setFocus(TRUE); } - item_list_t::reverse_iterator cur_item_iter; - for (cur_item_iter = mItems.rbegin(); cur_item_iter != mItems.rend(); ++cur_item_iter) - { - if( (*cur_item_iter) == cur_item) - { - break; - } - } + // Current item reverse position from the end of the list + item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item); item_list_t::reverse_iterator prev_item_iter; if (cur_item_iter == mItems.rend()) @@ -2812,6 +2951,10 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa { prev_item_iter = cur_item_iter; prev_item_iter++; + + // First visible item reverse position in the items list + item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem); + if (prev_item_iter == mItems.rend()) { prev_item_iter = mItems.rbegin(); @@ -2821,7 +2964,7 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa while(1) { // skip separators and disabled/invisible items - if ((*prev_item_iter)->getEnabled() && (*prev_item_iter)->getVisible() && (*prev_item_iter)->getType() != SEPARATOR_NAME) + if ((*prev_item_iter)->getEnabled() && (*prev_item_iter)->getVisible() && (*prev_item_iter)->getName() != SEPARATOR_NAME) { (*prev_item_iter)->setHighlight(TRUE); return (*prev_item_iter); @@ -2862,17 +3005,15 @@ void LLMenuGL::updateParent(LLView* parentp) { getParent()->removeChild(this); } - parentp->addChild(this); + if (parentp) + { + parentp->addChild(this); + } item_list_t::iterator item_iter; for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { (*item_iter)->updateBranchParent(parentp); } - - if (mSpilloverMenu) - { - mSpilloverMenu->updateParent(parentp); - } } BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask) @@ -2965,14 +3106,25 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask ) ((LLMenuItemGL*)viewp)->setHighlight(TRUE); LLMenuGL::setKeyboardMode(FALSE); } - mHasSelection = TRUE; + mHasSelection = true; } } } getWindow()->setCursor(UI_CURSOR_ARROW); + + // *HACK Release the mouse capture + // This is done to release the mouse after the Navigation Bar "Back" or "Forward" button + // drop-down menu is shown. Otherwise any other view won't be able to handle mouse events + // until the user chooses one of the drop-down menu items. + return TRUE; } +BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) +{ + return blockMouseEvent(x, y); +} + void LLMenuGL::draw( void ) { if (mNeedsArrange) @@ -2993,6 +3145,20 @@ void LLMenuGL::draw( void ) { gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor ); } + + + /*LLRect rootRect = getRootView()->getRect(); + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLMenuItemGL* itemp = static_cast(*child_it); + if(itemp) + { + LLRect screenRect; + localRectToScreen(itemp->getRect(),&screenRect); + lldebugs << itemp->getName() << "Visible:" << itemp->getVisible() << " ValidRect: " << itemp->getRect().isValid() << " Overlaps: " << rootRect.overlaps(screenRect) << llendl; + } + }*/ + LLView::draw(); } @@ -3007,8 +3173,10 @@ void LLMenuGL::setVisible(BOOL visible) { if (visible != getVisible()) { + LLView::setVisible(visible); if (!visible) { + lldebugs << "Hiding " << getName() << llendl; mFadeTimer.start(); clearHoverItem(); // reset last known mouse coordinates so @@ -3017,12 +3185,11 @@ void LLMenuGL::setVisible(BOOL visible) mLastMouseY = 0; } else - { - mHasSelection = FALSE; + { + lldebugs << "Showing " << getName() << llendl; + mHasSelection = true; mFadeTimer.stop(); } - - LLView::setVisible(visible); } } @@ -3067,48 +3234,60 @@ void hide_top_view( LLView* view ) } +// x and y are the desired location for the popup, in the spawning_view's +// coordinate frame, NOT necessarily the mouse location // static void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y) { - const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); + const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size + const S32 CURSOR_WIDTH = 12; + + if(menu->getChildList()->empty()) + { + return; + } + + // Save click point for detecting cursor moves before mouse-up. + // Must be in local coords to compare with mouseUp events. + // If the mouse doesn't move, the menu will stay open ala the Mac. + // See also LLContextMenu::show() + S32 mouse_x, mouse_y; + + // Resetting scrolling position + if (menu->isScrollable() && menu->isScrollPositionOnShowReset()) + { + menu->mFirstVisibleItem = NULL; + } + + menu->setVisible( TRUE ); + + // Fix menu rect if needed. + menu->needsArrange(); + menu->arrangeAndClear(); + + LLUI::getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y); + LLMenuHolderGL::sContextMenuSpawnPos.set(mouse_x,mouse_y); + + const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getRect(); const S32 HPAD = 2; LLRect rect = menu->getRect(); - //LLView* cur_view = spawning_view; S32 left = x + HPAD; S32 top = y; spawning_view->localPointToOtherView(left, top, &left, &top, menu->getParent()); rect.setLeftTopAndSize( left, top, rect.getWidth(), rect.getHeight() ); - - - //rect.setLeftTopAndSize(x + HPAD, y, rect.getWidth(), rect.getHeight()); menu->setRect( rect ); - S32 bottom; - left = rect.mLeft; - bottom = rect.mBottom; - //menu->getParent()->localPointToScreen( rect.mLeft, rect.mBottom, - // &left, &bottom ); - S32 delta_x = 0; - S32 delta_y = 0; - if( bottom < menu_region_rect.mBottom ) - { - // At this point, we need to move the context menu to the - // other side of the mouse. - //delta_y = menu_region_rect.mBottom - bottom; - delta_y = (rect.getHeight() + 2 * HPAD); - } - if( left > menu_region_rect.mRight - rect.getWidth() ) - { - // At this point, we need to move the context menu to the - // other side of the mouse. - //delta_x = (window_width - rect.getWidth()) - x; - delta_x = -(rect.getWidth() + 2 * HPAD); - } - menu->translate( delta_x, delta_y ); - menu->setVisible( TRUE ); + // Adjust context menu to fit onscreen + LLRect mouse_rect; + const S32 MOUSE_CURSOR_PADDING = 5; + mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, + mouse_y + MOUSE_CURSOR_PADDING, + CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, + CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2); + menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect, FALSE ); menu->getParent()->sendChildToFront(menu); } @@ -3218,7 +3397,6 @@ LLPieMenu::LLPieMenu(const std::string& name, const std::string& label) mRightMouseDown(FALSE) { LLMenuGL::setVisible(FALSE); - setCanTearOff(FALSE); } LLPieMenu::LLPieMenu(const std::string& name) @@ -3233,7 +3411,6 @@ LLPieMenu::LLPieMenu(const std::string& name) mRightMouseDown(FALSE) { LLMenuGL::setVisible(FALSE); - setCanTearOff(FALSE); } @@ -3635,7 +3812,7 @@ BOOL LLPieMenu::append(LLMenuItemGL *item) } // virtual -BOOL LLPieMenu::appendSeparator(const std::string &separator_name) +BOOL LLPieMenu::addSeparator() { LLMenuItemGL* separator = new LLMenuItemBlankGL(); separator->setFont( LLFontGL::getFontSansSerifSmall() ); @@ -3916,10 +4093,10 @@ void LLPieMenu::hide(BOOL item_selected) static LLRegisterWidget r2("menu_bar"); // Default constructor -LLMenuBarGL::LLMenuBarGL( const std::string& name ) : LLMenuGL ( name, name ) +LLMenuBarGL::LLMenuBarGL( const std::string& name ) +: LLMenuGL ( name, name ) { mHorizontalLayout = TRUE; - setCanTearOff(FALSE); mKeepFixedSize = TRUE; mAltKeyTrigger = FALSE; } @@ -4004,13 +4181,6 @@ LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory if (child->hasName("menu")) { LLMenuGL *menu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory); - // because of lazy initialization, have to disable tear off functionality - // and then re-enable with proper parent handle - if (menu->getCanTearOff()) - { - menu->setCanTearOff(FALSE); - menu->setCanTearOff(TRUE, parent_handle); - } menubar->appendMenu(menu); if (LLMenuGL::sMenuContainer != NULL) { @@ -4050,7 +4220,9 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask) mAltKeyTrigger = FALSE; } - if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key)) + if(!result + && (key == KEY_F10 && mask == MASK_CONTROL) + && !gKeyboard->getKeyRepeated(key)) { if (getHighlightedItem()) { @@ -4121,19 +4293,22 @@ BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask) return LLMenuGL::handleMouseDown(x, y, mask); } -BOOL LLMenuBarGL::handleRightMouseDown(S32 x, S32 y, MASK mask) +void LLMenuBarGL::setVisible(BOOL visible) { - // clicks on menu bar closes existing menus from other contexts but leave - // own menu open so that we get toggle behavior - if (!getHighlightedItem() || !getHighlightedItem()->isActive()) + if(visible != getVisible()) { - LLMenuGL::sMenuContainer->hideMenus(); + if(!visible) + { + lldebugs << "Hiding " << getName() << llendl; + } + else + { + lldebugs << "Showing " << getName() << llendl; + } } - - return LLMenuGL::handleMouseDown(x, y, mask); + LLUICtrl::setVisible(visible); } - void LLMenuBarGL::draw() { LLMenuItemGL* itemp = getHighlightedItem(); @@ -4227,7 +4402,7 @@ S32 LLMenuBarGL::getRightmostMenuEdge() } // add a vertical separator to this menu -BOOL LLMenuBarGL::appendSeparator( const std::string &separator_name ) +BOOL LLMenuBarGL::addSeparator() { LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL(); return append( separator ); @@ -4249,6 +4424,8 @@ BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu ) success &= branch->addToAcceleratorList(&mAccelerators); success &= append( branch ); branch->setJumpKey(branch->getJumpKey()); + menu->updateParent(LLMenuGL::sMenuContainer); + return success; } @@ -4325,6 +4502,7 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask ) ///============================================================================ /// Class LLMenuHolderGL ///============================================================================ +LLCoordGL LLMenuHolderGL::sContextMenuSpawnPos(S32_MAX, S32_MAX); LLMenuHolderGL::LLMenuHolderGL() : LLPanel(std::string("Menu Holder")) { @@ -4347,7 +4525,7 @@ void LLMenuHolderGL::draw() LLView::draw(); // now draw last selected item as overlay LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get(); - if (selecteditem && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) + if (selecteditem && selecteditem->getVisible() && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) { // make sure toggle items, for example, show the proper state when fading out selecteditem->buildDrawLabel(); @@ -4356,10 +4534,10 @@ void LLMenuHolderGL::draw() selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this); F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME; - F32 alpha = lerp(LLMenuItemGL::getHighlightBGColor().mV[VALPHA], 0.f, interpolant); - LLColor4 bg_color(LLMenuItemGL::getHighlightBGColor().mV[VRED], - LLMenuItemGL::getHighlightBGColor().mV[VGREEN], - LLMenuItemGL::getHighlightBGColor().mV[VBLUE], + F32 alpha = lerp(LLMenuItemGL::sHighlightBackground.mV[VALPHA], 0.f, interpolant); + LLColor4 bg_color(LLMenuItemGL::sHighlightBackground.mV[VRED], + LLMenuItemGL::sHighlightBackground.mV[VGREEN], + LLMenuItemGL::sHighlightBackground.mV[VBLUE], alpha); LLUI::pushMatrix(); @@ -4394,6 +4572,68 @@ BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask ) return handled; } +// This occurs when you mouse-down to spawn a context menu, hold the button +// down, move off the menu, then mouse-up. We want this to close the menu. +BOOL LLMenuHolderGL::handleRightMouseUp( S32 x, S32 y, MASK mask ) +{ + const S32 SLOP = 2; + S32 spawn_dx = (x - sContextMenuSpawnPos.mX); + S32 spawn_dy = (y - sContextMenuSpawnPos.mY); + if (-SLOP <= spawn_dx && spawn_dx <= SLOP + && -SLOP <= spawn_dy && spawn_dy <= SLOP) + { + // we're still inside the slop region from spawning this menu + // so interpret the mouse-up as a single-click to show and leave on + // screen + sContextMenuSpawnPos.set(S32_MAX, S32_MAX); + return TRUE; + } + + BOOL handled = LLView::childrenHandleRightMouseUp(x, y, mask) != NULL; + if (!handled) + { + // clicked off of menu, hide them all + hideMenus(); + } + return handled; +} + +BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + BOOL handled = false; + LLMenuGL* const pMenu = dynamic_cast(getVisibleMenu()); + + if (pMenu) + { + //eat TAB key - EXT-7000 + if (key == KEY_TAB && mask == MASK_NONE) + { + return TRUE; + } + + //handle ESCAPE and RETURN key + handled = LLPanel::handleKey(key, mask, called_from_parent); + if (!handled) + { + if (pMenu->getHighlightedItem()) + { + handled = pMenu->handleKey(key, mask, TRUE); + } + else + { + //highlight first enabled one + if(pMenu->highlightNextItem(NULL)) + { + handled = true; + } + } + } + } + + return handled; + +} + void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent) { if (width != getRect().getWidth() || height != getRect().getHeight()) @@ -4403,17 +4643,17 @@ void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent) LLView::reshape(width, height, called_from_parent); } -BOOL LLMenuHolderGL::hasVisibleMenu() const +LLView* const LLMenuHolderGL::getVisibleMenu() const { for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { LLView* viewp = *child_it; - if (viewp->getVisible() && dynamic_cast(viewp) == NULL) + if (viewp->getVisible() && dynamic_cast(viewp) != NULL) { - return TRUE; + return viewp; } } - return FALSE; + return NULL; } @@ -4434,8 +4674,7 @@ BOOL LLMenuHolderGL::hideMenus() for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { LLView* viewp = *child_it; - // clicks off of menu do not hide menu bar - if (dynamic_cast(viewp) == NULL && viewp->getVisible()) + if (dynamic_cast(viewp) != NULL && viewp->getVisible() && !dynamic_cast(viewp)) { viewp->setVisible(FALSE); } @@ -4461,6 +4700,11 @@ void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item) LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : LLFloater(menup->getName(), LLRect(0, 100, 100, 0), menup->getLabel(), FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, FALSE) { + //S32 floater_header_size = LLFLOATER_HEADER_SIZE; + + setName(menup->getName()); + setTitle(menup->getLabel()); + setCanMinimize(FALSE); // flag menu as being torn off menup->setTornOff(TRUE); // update menu layout as torn off menu (no spillover menus) diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 94fab5b16..b8a5f614d 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -76,32 +76,40 @@ typedef void (*label_callback)(std::string&,void*); // The LLMenuItemGL represents a single menu item in a menu. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemGL : public LLView +class LLMenuItemGL : public LLUICtrl { public: // static functions to control the global color scheme. - static void setEnabledColor( const LLColor4& color ) { sEnabledColor = color; } + /*static void setEnabledColor( const LLColor4& color ) { sEnabledColor = color; } static const LLColor4& getEnabledColor() { return sEnabledColor; } static void setDisabledColor( const LLColor4& color ) { sDisabledColor = color; } static const LLColor4& getDisabledColor() { return sDisabledColor; } static void setHighlightBGColor( const LLColor4& color ) { sHighlightBackground = color; } static const LLColor4& getHighlightBGColor() { return sHighlightBackground; } static void setHighlightFGColor( const LLColor4& color ) { sHighlightForeground = color; } - static const LLColor4& getHighlightFGColor() { return sHighlightForeground; } + static const LLColor4& getHighlightFGColor() { return sHighlightForeground; }*/ LLMenuItemGL( const std::string& name, const std::string& label, KEY key = KEY_NONE, MASK = MASK_NONE ); - virtual ~LLMenuItemGL() {}; + virtual ~LLMenuItemGL(); - virtual void setValue(const LLSD& value) { setLabel(value.asString()); } virtual LLXMLNodePtr getXML(bool save_children = true) const; virtual std::string getType() const { return "item"; } - virtual BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void handleVisibilityChange(BOOL new_visibility); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + + // LLUICtrl overrides + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + LLColor4 getHighlightBgColor() { return mHighlightBackground; } + void setJumpKey(KEY key); KEY getJumpKey() const { return mJumpKey; } @@ -115,8 +123,8 @@ public: virtual U32 getNominalHeight( void ) const; // Marks item as not needing space for check marks or accelerator keys - virtual void setBriefItem(BOOL brief) { mBriefItem = brief; } - virtual BOOL isBriefItem() const { return mBriefItem; } + virtual void setBriefItem(BOOL brief); + virtual BOOL isBriefItem() const; virtual BOOL addToAcceleratorList(std::list *listp); void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } @@ -128,7 +136,7 @@ public: virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); // Get the parent menu for this item - virtual class LLMenuGL* getMenu(); + virtual class LLMenuGL* getMenu() const; // returns the normal width of this control in pixels - this is // used for calculating the widest item, as well as for horizontal @@ -167,6 +175,7 @@ public: virtual BOOL handleKeyHere( KEY key, MASK mask ); virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); virtual void draw( void ); BOOL getHover() const { return mGotHover; } @@ -193,13 +202,19 @@ protected: LLUIString mDrawAccelLabel; LLUIString mDrawBranchLabel; + LLColor4 mEnabledColor; + LLColor4 mDisabledColor; + LLColor4 mHighlightBackground; + LLColor4 mHighlightForeground; + BOOL mHighlight; -private: +public: static LLColor4 sEnabledColor; static LLColor4 sDisabledColor; static LLColor4 sHighlightBackground; static LLColor4 sHighlightForeground; +private: // Keyboard and mouse variables BOOL mAllowKeyRepeat; BOOL mGotHover; @@ -302,6 +317,9 @@ public: void setUserData(void *userdata) { mUserData = userdata; } void* getUserData() const { return mUserData; } +protected: + void updateEnabled( void ); +public: // called to rebuild the draw label virtual void buildDrawLabel( void ); @@ -309,7 +327,8 @@ public: virtual void doIt( void ); virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - + virtual BOOL handleKeyHere(KEY key, MASK mask); + //virtual void draw(); @@ -427,24 +446,35 @@ class LLMenuGL // TODO: The menu and menu item classes share a great deal of functionality and perhaps should be united. // I think it may make the most sense to make LLMenuGL be a subclass of LLMenuItemGL. -MG { +public: + // textual artwork which menugl-imitators may want to match + static const std::string BOOLEAN_TRUE_PREFIX; + static const std::string BRANCH_SUFFIX; + static const std::string ARROW_UP; + static const std::string ARROW_DOWN; + +protected: // let branching menu items use my protected traversal methods friend class LLMenuItemBranchGL; public: - LLMenuGL( const std::string& name, const std::string& label, LLHandle parent_floater = LLHandle()); - LLMenuGL( const std::string& label, LLHandle parent_floater = LLHandle() ); + LLMenuGL( const std::string& name, const std::string& label); + LLMenuGL( const std::string& label); virtual ~LLMenuGL( void ); virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); void parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory *factory); - // LLView Functionality - virtual BOOL handleUnicodeCharHere( llwchar uni_char ); - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - virtual void draw( void ); + /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + /*virtual*/ void draw( void ); virtual void drawBackground(LLMenuItemGL* itemp, LLColor4& color); - virtual void setVisible(BOOL visible); + /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + /*virtual*/ void removeChild( LLView* ctrl); + /*virtual*/ BOOL postBuild(); virtual BOOL handleAcceleratorKey(KEY key, MASK mask); @@ -461,23 +491,10 @@ public: void setBackgroundColor( const LLColor4& color ) { mBackgroundColor = color; } const LLColor4& getBackgroundColor() const { return mBackgroundColor; } void setBackgroundVisible( BOOL b ) { mBgVisible = b; } - void setCanTearOff(BOOL tear_off, LLHandle parent_floater_handle = LLHandle()); - - // Add the menu item to this menu. - virtual BOOL append( LLMenuItemGL* item ); - - // Remove a menu item from this menu. - virtual BOOL remove( LLMenuItemGL* item ); - - // *NOTE:Mani - appendNoArrange() should be removed when merging to skinning/viewer2.0 - // Its added as a fix to a viewer 1.23 bug that has already been address by skinning work. - virtual BOOL appendNoArrange( LLMenuItemGL* item ); + void setCanTearOff(BOOL tear_off); // add a separator to this menu - virtual BOOL appendSeparator( const std::string &separator_name = LLStringUtil::null ); - - // add a menu - this will create a cascading menu - virtual BOOL appendMenu( LLMenuGL* menu ); + virtual BOOL addSeparator(); // for branching menu items, bring sub menus up to root level of menu hierarchy virtual void updateParent( LLView* parentp ); @@ -512,10 +529,6 @@ public: // remove all items on the menu void empty( void ); - // Rearrange the components, and do the right thing if the menu doesn't - // fit in the bounds. - // virtual void arrangeWithBounds(LLRect bounds); - void setItemLastSelected(LLMenuItemGL* item); // must be in menu U32 getItemCount(); // number of menu items LLMenuItemGL* getItem(S32 number); // 0 = first item @@ -550,15 +563,26 @@ public: static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } static BOOL getKeyboardMode() { return sKeyboardMode; } + S32 getShortcutPad() { return mShortcutPad; } + BOOL isScrollable() const { return FALSE; } + static class LLMenuHolderGL* sMenuContainer; + bool isScrollPositionOnShowReset() { return false; } protected: void createSpilloverBranch(); void cleanupSpilloverBranch(); + // Add the menu item to this menu. + virtual BOOL append( LLMenuItemGL* item ); + + // add a menu - this will create a cascading menu + virtual BOOL appendMenu( LLMenuGL* menu ); // TODO: create accessor methods for these? typedef std::list< LLMenuItemGL* > item_list_t; item_list_t mItems; + LLMenuItemGL*mFirstVisibleItem; + typedef std::map navigation_key_map_t; navigation_key_map_t mJumpKeys; S32 mLastMouseX; @@ -578,14 +602,14 @@ private: LLHandle mParentMenuItem; LLUIString mLabel; BOOL mDropShadowed; // Whether to drop shadow - BOOL mHasSelection; + bool mHasSelection; LLFrameTimer mFadeTimer; BOOL mTornOff; class LLMenuItemTearOffGL* mTearOffItem; class LLMenuItemBranchGL* mSpilloverBranch; LLMenuGL* mSpilloverMenu; - LLHandle mParentFloaterHandle; KEY mJumpKey; + S32 mShortcutPad; }; // end class LLMenuGL @@ -631,11 +655,11 @@ public: virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL isActive() const { return isOpen() && getBranch()->getHighlightedItem(); } + virtual BOOL isActive() const; - virtual BOOL isOpen() const { return getBranch() && getBranch()->isOpen(); } + virtual BOOL isOpen() const; - LLMenuGL *getBranch() const { return (LLMenuGL*)(mBranch.get()); } + LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } virtual void updateBranchParent( LLView* parentp ); @@ -651,7 +675,7 @@ public: virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const; private: - LLHandle mBranch; + LLHandle mBranchHandle; }; // end class LLMenuItemBranchGL @@ -684,8 +708,10 @@ public: virtual void draw(); virtual void drawBackground(LLMenuItemGL* itemp, LLColor4& color); +private: virtual BOOL append(LLMenuItemGL* item); - virtual BOOL appendSeparator( const std::string &separator_name = LLStringUtil::null ); +public: + virtual BOOL addSeparator(); BOOL appendPieMenu(LLPieMenu *menu); @@ -730,23 +756,17 @@ public: virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleJumpKey(KEY key); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + void setVisible(BOOL visible); + /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleJumpKey(KEY key); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - // rearrange the child rects so they fit the shape of the menu - // bar. - virtual void arrange( void ); - virtual void draw(); - virtual BOOL jumpKeysActive(); + /*virtual*/ void draw(); + /*virtual*/ BOOL jumpKeysActive(); // add a vertical separator to this menu - virtual BOOL appendSeparator( const std::string &separator_name = LLStringUtil::null ); - - // add a menu - this will create a drop down menu. - virtual BOOL appendMenu( LLMenuGL* menu ); + virtual BOOL addSeparator(); // LLView Functionality virtual BOOL handleHover( S32 x, S32 y, MASK mask ); @@ -757,6 +777,12 @@ public: void resetMenuTrigger() { mAltKeyTrigger = FALSE; } private: + // add a menu - this will create a drop down menu. + virtual BOOL appendMenu( LLMenuGL* menu ); + // rearrange the child rects so they fit the shape of the menu + // bar. + virtual void arrange( void ); + void checkMenuTrigger(); std::list mAccelerators; @@ -784,11 +810,20 @@ public: virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + // Close context menus on right mouse up not handled by menus. + /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); + + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); virtual const LLRect getMenuRect() const { return getLocalRect(); } - virtual BOOL hasVisibleMenu() const; + LLView*const getVisibleMenu() const; + virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} static void setActivatedItem(LLMenuItemGL* item); + // Need to detect if mouse-up after context menu spawn has moved. + // If not, need to keep the menu up. + static LLCoordGL sContextMenuSpawnPos; + private: static LLHandle sItemLastSelectedHandle; static LLFrameTimer sItemActivationTimer; @@ -832,7 +867,7 @@ private: class LLMenuItemTearOffGL : public LLMenuItemGL { public: - LLMenuItemTearOffGL( LLHandle parent_floater_handle = LLHandle()); + LLMenuItemTearOffGL(); virtual LLXMLNodePtr getXML(bool save_children = true) const; virtual std::string getType() const { return "tearoff_menu"; } @@ -841,8 +876,7 @@ public: virtual void draw(void); virtual U32 getNominalHeight() const; -private: - LLHandle mParentHandle; + LLFloater* getParentFloater(); }; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index cd9d06c58..bc6d176c5 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -356,12 +356,12 @@ LLTextEditor::LLTextEditor( { menu = new LLMenuGL(LLStringUtil::null); }*/ - menu->append(new LLMenuItemCallGL("Cut", context_cut, NULL, this)); - menu->append(new LLMenuItemCallGL("Copy", context_copy, NULL, this)); - menu->append(new LLMenuItemCallGL("Paste", context_paste, NULL, this)); - menu->append(new LLMenuItemCallGL("Delete", context_delete, NULL, this)); - menu->append(new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); - menu->appendSeparator("Spelsep"); + menu->addChild(new LLMenuItemCallGL("Cut", context_cut, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Copy", context_copy, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Paste", context_paste, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Delete", context_delete, NULL, this)); + menu->addChild(new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); + menu->addSeparator(); menu->setCanTearOff(FALSE); menu->setVisible(FALSE); mPopupMenuHandle = menu->getHandle(); @@ -1389,7 +1389,7 @@ BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) SpellMenuBind * tempBind = suggestionMenuItems[i]; if(tempBind) { - menu->remove(tempBind->menuItem); + menu->removeChild(tempBind->menuItem); tempBind->menuItem->die(); //delete tempBind->menuItem; //tempBind->menuItem = NULL; @@ -1425,7 +1425,7 @@ BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) tempStruct->word, spell_correct, NULL, tempStruct); tempStruct->menuItem = suggMenuItem; suggestionMenuItems.push_back(tempStruct); - menu->append(suggMenuItem); + menu->addChild(suggMenuItem); } SpellMenuBind * tempStruct = new SpellMenuBind; tempStruct->origin = this; @@ -1437,7 +1437,7 @@ BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) "Add Word", spell_add, NULL, tempStruct); tempStruct->menuItem = suggMenuItem; suggestionMenuItems.push_back(tempStruct); - menu->append(suggMenuItem); + menu->addChild(suggMenuItem); } } @@ -1456,12 +1456,11 @@ BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) tempStruct->word, spell_show, NULL, tempStruct); tempStruct->menuItem = suggMenuItem; suggestionMenuItems.push_back(tempStruct); - menu->append(suggMenuItem); + menu->addChild(suggMenuItem); } mLastContextMenuX = x; mLastContextMenuY = y; menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); } return TRUE; diff --git a/indra/newview/llfloatermessagelog.cpp b/indra/newview/llfloatermessagelog.cpp index 57ffac013..08cfa1200 100644 --- a/indra/newview/llfloatermessagelog.cpp +++ b/indra/newview/llfloatermessagelog.cpp @@ -935,11 +935,11 @@ void LLFloaterMessageLog::onClickClearLog(void* user_data) void LLFloaterMessageLog::onClickFilterChoice(void* user_data) { LLMenuGL* menu = new LLMenuGL(LLStringUtil::null); - menu->append(new LLMenuItemCallGL("No filter", onClickFilterMenu, NULL, (void*)"")); - menu->append(new LLMenuItemCallGL("Fewer spammy messages", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket")); - menu->append(new LLMenuItemCallGL("Fewer spammy messages (minus sound crap)", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket !SoundTrigger !AttachedSound !PreloadSound")); - menu->append(new LLMenuItemCallGL("Object updates", onClickFilterMenu, NULL, (void*)"ObjectUpdateCached ObjectUpdate ObjectUpdateCompressed ImprovedTerseObjectUpdate KillObject RequestMultipleObjects")); - menu->append(new LLMenuItemCallGL("Abnormal", onClickFilterMenu, NULL, (void*)"Invalid TestMessage AddCircuitCode NeighborList AvatarTextureUpdate SimulatorMapUpdate SimulatorSetMap SubscribeLoad UnsubscribeLoad SimulatorReady SimulatorPresentAtLocation SimulatorLoad SimulatorShutdownRequest RegionPresenceRequestByRegionID RegionPresenceRequestByHandle RegionPresenceResponse UpdateSimulator LogDwellTime FeatureDisabled LogFailedMoneyTransaction UserReportInternal SetSimStatusInDatabase SetSimPresenceInDatabase OpenCircuit CloseCircuit DirFindQueryBackend DirPlacesQueryBackend DirClassifiedQueryBackend DirLandQueryBackend DirPopularQueryBackend GroupNoticeAdd DataHomeLocationRequest DataHomeLocationReply DerezContainer ObjectCategory ObjectExportSelected StateSave ReportAutosaveCrash AgentAlertMessage NearestLandingRegionRequest NearestLandingRegionReply NearestLandingRegionUpdated TeleportLandingStatusChanged ConfirmEnableSimulator KickUserAck SystemKickUser AvatarPropertiesRequestBackend UpdateParcel RemoveParcel MergeParcel LogParcelChanges CheckParcelSales ParcelSales StartAuction ConfirmAuctionStart CompleteAuction CancelAuction CheckParcelAuctions ParcelAuctions ChatPass EdgeDataPacket SimStatus ChildAgentUpdate ChildAgentAlive ChildAgentPositionUpdate ChildAgentDying ChildAgentUnknown AtomicPassObject KillChildAgents ScriptSensorRequest ScriptSensorReply DataServerLogout RequestInventoryAsset InventoryAssetResponse TransferInventory TransferInventoryAck EventLocationRequest EventLocationReply MoneyTransferBackend RoutedMoneyBalanceReply SetStartLocation NetTest SetCPURatio SimCrashed NameValuePair RemoveNameValuePair UpdateAttachment RemoveAttachment EmailMessageRequest EmailMessageReply InternalScriptMail ScriptDataRequest ScriptDataReply InviteGroupResponse TallyVotes LiveHelpGroupRequest LiveHelpGroupReply GroupDataUpdate LogTextMessage CreateTrustedCircuit ParcelRename SystemMessage RpcChannelRequest RpcChannelReply RpcScriptRequestInbound RpcScriptRequestInboundForward RpcScriptReplyInbound ScriptMailRegistration Error")); + menu->addChild(new LLMenuItemCallGL("No filter", onClickFilterMenu, NULL, (void*)"")); + menu->addChild(new LLMenuItemCallGL("Fewer spammy messages", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket")); + menu->addChild(new LLMenuItemCallGL("Fewer spammy messages (minus sound crap)", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket !SoundTrigger !AttachedSound !PreloadSound")); + menu->addChild(new LLMenuItemCallGL("Object updates", onClickFilterMenu, NULL, (void*)"ObjectUpdateCached ObjectUpdate ObjectUpdateCompressed ImprovedTerseObjectUpdate KillObject RequestMultipleObjects")); + menu->addChild(new LLMenuItemCallGL("Abnormal", onClickFilterMenu, NULL, (void*)"Invalid TestMessage AddCircuitCode NeighborList AvatarTextureUpdate SimulatorMapUpdate SimulatorSetMap SubscribeLoad UnsubscribeLoad SimulatorReady SimulatorPresentAtLocation SimulatorLoad SimulatorShutdownRequest RegionPresenceRequestByRegionID RegionPresenceRequestByHandle RegionPresenceResponse UpdateSimulator LogDwellTime FeatureDisabled LogFailedMoneyTransaction UserReportInternal SetSimStatusInDatabase SetSimPresenceInDatabase OpenCircuit CloseCircuit DirFindQueryBackend DirPlacesQueryBackend DirClassifiedQueryBackend DirLandQueryBackend DirPopularQueryBackend GroupNoticeAdd DataHomeLocationRequest DataHomeLocationReply DerezContainer ObjectCategory ObjectExportSelected StateSave ReportAutosaveCrash AgentAlertMessage NearestLandingRegionRequest NearestLandingRegionReply NearestLandingRegionUpdated TeleportLandingStatusChanged ConfirmEnableSimulator KickUserAck SystemKickUser AvatarPropertiesRequestBackend UpdateParcel RemoveParcel MergeParcel LogParcelChanges CheckParcelSales ParcelSales StartAuction ConfirmAuctionStart CompleteAuction CancelAuction CheckParcelAuctions ParcelAuctions ChatPass EdgeDataPacket SimStatus ChildAgentUpdate ChildAgentAlive ChildAgentPositionUpdate ChildAgentDying ChildAgentUnknown AtomicPassObject KillChildAgents ScriptSensorRequest ScriptSensorReply DataServerLogout RequestInventoryAsset InventoryAssetResponse TransferInventory TransferInventoryAck EventLocationRequest EventLocationReply MoneyTransferBackend RoutedMoneyBalanceReply SetStartLocation NetTest SetCPURatio SimCrashed NameValuePair RemoveNameValuePair UpdateAttachment RemoveAttachment EmailMessageRequest EmailMessageReply InternalScriptMail ScriptDataRequest ScriptDataReply InviteGroupResponse TallyVotes LiveHelpGroupRequest LiveHelpGroupReply GroupDataUpdate LogTextMessage CreateTrustedCircuit ParcelRename SystemMessage RpcChannelRequest RpcChannelReply RpcScriptRequestInbound RpcScriptRequestInboundForward RpcScriptReplyInbound ScriptMailRegistration Error")); menu->updateParent(LLMenuGL::sMenuContainer); menu->setCanTearOff(FALSE); LLView* buttonp = sInstance->getChild("filter_choice_btn"); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c23a87bcf..736a8a224 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2890,7 +2890,7 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags) mItems.push_back(std::string("Add To Outfit")); } else if(!InventoryLinksEnabled()) - mItems.push_back(std::string("Wear Items")); + mItems.push_back(std::string("Wearable And Object Wear")); mItems.push_back(std::string("Replace Outfit")); } mItems.push_back(std::string("Remove From Outfit")); @@ -4738,7 +4738,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Attach To")); disabled_items.push_back(std::string("Attach To HUD")); } -// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a | OK +/*// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a | OK else if (rlv_handler_t::isEnabled()) { ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(item); @@ -4747,7 +4747,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if ((eWearMask & RLV_WEAR_ADD) == 0) disabled_items.push_back(std::string("Object Add")); } -// [/RLVa:KB] +// [/RLVa:KB]*/ LLMenuGL* attach_menu = menu.getChildMenuByName("Attach To", TRUE); LLMenuGL* attach_hud_menu = menu.getChildMenuByName("Attach To HUD", TRUE); @@ -4766,7 +4766,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if (attachment->getIsHUDAttachment()) { // [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) - attach_hud_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(), + attach_hud_menu->addChild(new_item = new LLMenuItemCallGL(attachment->getName(), NULL, //&LLObjectBridge::attachToAvatar, (rlv_handler_t::isEnabled()) ? &rlvAttachToEnabler : NULL, &attach_label, (void*)attachment)); @@ -4775,7 +4775,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else { // [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) - attach_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(), + attach_menu->addChild(new_item = new LLMenuItemCallGL(attachment->getName(), NULL, //&LLObjectBridge::attachToAvatar, (rlv_handler_t::isEnabled()) ? &rlvAttachToEnabler : NULL, &attach_label, (void*)attachment)); @@ -4790,7 +4790,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } } LLMenuItemCallGL *new_item = new LLMenuItemCallGL("Custom...", NULL, NULL); - attach_menu->append(new_item); + attach_menu->addChild(new_item); LLSimpleListener* callback = mInventoryPanel.get()->getListenerByName("Inventory.AttachCustom"); new_item->addListener(callback, "on_click", LLSD()); } @@ -5138,13 +5138,13 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Wearable Edit")); -// [RLVa:KB] - Checked: 2011-09-16 (RLVa-1.1.4a) | Added: RLVa-1.1.4a +/*// [RLVa:KB] - Checked: 2011-09-16 (RLVa-1.1.4a) | Added: RLVa-1.1.4a if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) { disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Edit")); } -// [/RLVa:KB] +// [/RLVa:KB]*/ if ((flags & FIRST_SELECTED_ITEM) == 0) { @@ -5165,10 +5165,10 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { case LLAssetType::AT_CLOTHING: items.push_back(std::string("Take Off")); -// [RLVa:KB] - Checked: 2011-09-16 (RLVa-1.1.4a) | Added: RLVa-1.1.4a +/*// [RLVa:KB] - Checked: 2011-09-16 (RLVa-1.1.4a) | Added: RLVa-1.1.4a if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) disabled_items.push_back(std::string("Take Off")); -// [/RLVa:KB] +// [/RLVa:KB]*/ // Fallthrough since clothing and bodypart share wear options case LLAssetType::AT_BODYPART: if (get_is_item_worn(item->getUUID())) diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 1619d6743..058afb29d 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1127,7 +1127,7 @@ void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } items.push_back(std::string("Task Play")); - /*menu.appendSeparator(); + /*menu.addSeparator(); menu.append(new LLMenuItemCallGL("Play", &LLTaskSoundBridge::playSound, NULL, diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9ac3ca3cf..77966f665 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -648,17 +648,11 @@ void LLMenuParcelObserver::changed() void pre_init_menus() { // static information - LLColor4 color; - color = gColors.getColor( "MenuDefaultBgColor" ); - LLMenuGL::setDefaultBackgroundColor( color ); - color = gColors.getColor( "MenuItemEnabledColor" ); - LLMenuItemGL::setEnabledColor( color ); - color = gColors.getColor( "MenuItemDisabledColor" ); - LLMenuItemGL::setDisabledColor( color ); - color = gColors.getColor( "MenuItemHighlightBgColor" ); - LLMenuItemGL::setHighlightBGColor( color ); - color = gColors.getColor( "MenuItemHighlightFgColor" ); - LLMenuItemGL::setHighlightFGColor( color ); + LLMenuGL::setDefaultBackgroundColor( gColors.getColor( "MenuDefaultBgColor" ) ); + LLMenuItemGL::sEnabledColor = gColors.getColor( "MenuItemEnabledColor" ); + LLMenuItemGL::sDisabledColor = gColors.getColor( "MenuItemDisabledColor" ); + LLMenuItemGL::sHighlightBackground = gColors.getColor( "MenuItemHighlightBgColor" ); + LLMenuItemGL::sHighlightForeground = gColors.getColor( "MenuItemHighlightFgColor" ); } void initialize_menus(); @@ -766,7 +760,7 @@ void init_menus() gMenuBarView->setBackgroundColor( color ); // gMenuBarView->setItemVisible("Tools", FALSE); - gMenuBarView->arrange(); + gMenuBarView->needsArrange(); gMenuHolder->addChild(gMenuBarView); @@ -799,34 +793,35 @@ void init_menus() LLMenuGL*menu; menu = new LLMenuGL("Singularity"); - menu->append(new LLMenuItemCallGL( "Close All Dialogs", + menu->setCanTearOff(TRUE); + menu->addChild(new LLMenuItemCallGL( "Close All Dialogs", &handle_close_all_notifications, NULL, NULL, 'D', MASK_CONTROL | MASK_ALT | MASK_SHIFT)); - menu->appendSeparator(); - menu->append(new LLMenuItemCallGL( "Fake Away Status", &handle_fake_away_status, NULL)); - menu->append(new LLMenuItemCallGL( "Force Ground Sit", &handle_force_ground_sit, NULL)); - menu->append(new LLMenuItemCallGL( "Phantom Avatar", &handle_phantom_avatar, NULL, NULL, 'P', MASK_CONTROL | MASK_ALT)); - menu->appendSeparator(); - menu->append(new LLMenuItemCallGL( "Animation Override...", + menu->addSeparator(); + menu->addChild(new LLMenuItemCallGL( "Fake Away Status", &handle_fake_away_status, NULL)); + menu->addChild(new LLMenuItemCallGL( "Force Ground Sit", &handle_force_ground_sit, NULL)); + menu->addChild(new LLMenuItemCallGL( "Phantom Avatar", &handle_phantom_avatar, NULL, NULL, 'P', MASK_CONTROL | MASK_ALT)); + menu->addSeparator(); + menu->addChild(new LLMenuItemCallGL( "Animation Override...", &handle_edit_ao, NULL)); - menu->append(new LLMenuItemCheckGL( "Nimble", + menu->addChild(new LLMenuItemCheckGL( "Nimble", &menu_toggle_control, NULL, &menu_check_control, (void*)"Nimble")); - menu->append(new LLMenuItemCheckGL( "ReSit", + menu->addChild(new LLMenuItemCheckGL( "ReSit", &menu_toggle_control, NULL, &menu_check_control, (void*)"ReSit")); - menu->appendSeparator(); - menu->append(new LLMenuItemCallGL( "Object Area Search", &handle_area_search, NULL)); - menu->append(new LLMenuItemCallGL( "Message Log", &handle_open_message_log, NULL)); + menu->addSeparator(); + menu->addChild(new LLMenuItemCallGL( "Object Area Search", &handle_area_search, NULL)); + menu->addChild(new LLMenuItemCallGL( "Message Log", &handle_open_message_log, NULL)); - menu->append(new LLMenuItemCallGL( "Sound Explorer", + menu->addChild(new LLMenuItemCallGL( "Sound Explorer", &handle_sounds_explorer, NULL)); - menu->append(new LLMenuItemCallGL( "Asset Blacklist", + menu->addChild(new LLMenuItemCallGL( "Asset Blacklist", &handle_blacklist, NULL)); - menu->append(new LLMenuItemCheckGL( "Streaming Audio Display", + menu->addChild(new LLMenuItemCheckGL( "Streaming Audio Display", &handle_ticker_toggle, &handle_ticker_enabled, &handle_ticker_check, NULL )); @@ -834,33 +829,32 @@ void init_menus() // // Add in the pose stand ------------------------------------------- /*LLMenuGL* sub = new LLMenuGL("Pose Stand..."); - menu->appendMenu(sub); + menu->addChild(sub); - sub->append(new LLMenuItemCallGL( "Legs Together Arms Out", &handle_pose_stand_ltao, NULL)); - sub->append(new LLMenuItemCallGL( "Legs Together Arms Half", &handle_pose_stand_ltah, NULL)); - sub->append(new LLMenuItemCallGL( "Legs Together Arms Down", &handle_pose_stand_ltad, NULL)); - sub->append(new LLMenuItemCallGL( "Legs Out Arms Up", &handle_pose_stand_loau, NULL)); - sub->append(new LLMenuItemCallGL( "Legs Out Arms Out", &handle_pose_stand_loao, NULL)); - sub->append(new LLMenuItemCallGL( "Legs Half Arms Out", &handle_pose_stand_lhao, NULL)); - sub->append(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Out", &handle_pose_stand_ltao, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Half", &handle_pose_stand_ltah, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Down", &handle_pose_stand_ltad, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Up", &handle_pose_stand_loau, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Out", &handle_pose_stand_loao, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Half Arms Out", &handle_pose_stand_lhao, NULL)); + sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, NULL)); // ------------------------------------------------------*/ - menu->append(new LLMenuItemCheckGL("Pose Stand",&handle_toggle_pose, NULL, &handle_check_pose, NULL)); + menu->addChild(new LLMenuItemCheckGL("Pose Stand",&handle_toggle_pose, NULL, &handle_check_pose, NULL)); //these should always be last in a sub menu menu->createJumpKeys(); - gMenuBarView->appendMenu( menu ); - menu->updateParent(LLMenuGL::sMenuContainer); + gMenuBarView->addChild( menu ); menu = new LLMenuGL(CLIENT_MENU_NAME); + menu->setCanTearOff(TRUE); init_client_menu(menu); - gMenuBarView->appendMenu( menu ); - menu->updateParent(LLMenuGL::sMenuContainer); + gMenuBarView->addChild( menu ); menu = new LLMenuGL(SERVER_MENU_NAME); + menu->setCanTearOff(TRUE); init_server_menu(menu); - gMenuBarView->appendMenu( menu ); - menu->updateParent(LLMenuGL::sMenuContainer); + gMenuBarView->addChild( menu ); gMenuBarView->createJumpKeys(); @@ -877,8 +871,8 @@ void init_menus() menu = new LLMenuGL(CLIENT_MENU_NAME); menu->setCanTearOff(FALSE); - menu->append(new LLMenuItemCallGL("Debug Settings...", LLFloaterSettingsDebug::show, NULL, NULL)); - gLoginMenuBarView->appendMenu(menu); + menu->addChild(new LLMenuItemCallGL("Debug Settings...", LLFloaterSettingsDebug::show, NULL, NULL)); + gLoginMenuBarView->addChild(menu); menu->updateParent(LLMenuGL::sMenuContainer); gLoginMenuBarView->setRect(LLRect(menuBarRect.mLeft, menuBarRect.mTop, @@ -897,27 +891,27 @@ void init_client_menu(LLMenuGL* menu) { LLMenuGL* sub_menu = NULL; - //menu->append(new LLMenuItemCallGL("Permissions Control", &show_permissions_control)); + //menu->addChild(new LLMenuItemCallGL("Permissions Control", &show_permissions_control)); // this is now in the view menu so we don't need it here! { // *TODO: Translate LLMenuGL* sub = new LLMenuGL("Consoles"); - menu->appendMenu(sub); - sub->append(new LLMenuItemCheckGL("Frame Console", + menu->addChild(sub); + sub->addChild(new LLMenuItemCheckGL("Frame Console", &toggle_visibility, NULL, &get_visibility, (void*)gDebugView->mFrameStatView, '2', MASK_CONTROL|MASK_SHIFT ) ); - sub->append(new LLMenuItemCheckGL("Texture Console", + sub->addChild(new LLMenuItemCheckGL("Texture Console", &toggle_visibility, NULL, &get_visibility, (void*)gTextureView, '3', MASK_CONTROL|MASK_SHIFT ) ); LLView* debugview = gDebugView->mDebugConsolep; - sub->append(new LLMenuItemCheckGL("Debug Console", + sub->addChild(new LLMenuItemCheckGL("Debug Console", &toggle_visibility, NULL, &get_visibility, @@ -926,13 +920,13 @@ void init_client_menu(LLMenuGL* menu) if(gAuditTexture) { - sub->append(new LLMenuItemCheckGL("Texture Size Console", + sub->addChild(new LLMenuItemCheckGL("Texture Size Console", &toggle_visibility, NULL, &get_visibility, (void*)gTextureSizeView, '5', MASK_CONTROL|MASK_SHIFT ) ); - sub->append(new LLMenuItemCheckGL("Texture Category Console", + sub->addChild(new LLMenuItemCheckGL("Texture Category Console", &toggle_visibility, NULL, &get_visibility, @@ -940,14 +934,14 @@ void init_client_menu(LLMenuGL* menu) '6', MASK_CONTROL|MASK_SHIFT ) ); } - sub->append(new LLMenuItemCheckGL("Fast Timers", + sub->addChild(new LLMenuItemCheckGL("Fast Timers", &toggle_visibility, NULL, &get_visibility, (void*)gDebugView->mFastTimerView, '9', MASK_CONTROL|MASK_SHIFT ) ); //#if MEM_TRACK_MEM - sub->append(new LLMenuItemCheckGL("Memory", + sub->addChild(new LLMenuItemCheckGL("Memory", &toggle_visibility, NULL, &get_visibility, @@ -955,68 +949,68 @@ void init_client_menu(LLMenuGL* menu) '0', MASK_CONTROL|MASK_SHIFT ) ); //#endif - sub->appendSeparator(); + sub->addSeparator(); // Debugging view for unified notifications - sub->append(new LLMenuItemCallGL("Notifications Console...", + sub->addChild(new LLMenuItemCallGL("Notifications Console...", &handle_show_notifications_console, NULL, NULL, '5', MASK_CONTROL|MASK_SHIFT )); - sub->appendSeparator(); + sub->addSeparator(); - sub->append(new LLMenuItemCallGL("Region Info to Debug Console", + sub->addChild(new LLMenuItemCallGL("Region Info to Debug Console", &handle_region_dump_settings, NULL)); - sub->append(new LLMenuItemCallGL("Group Info to Debug Console", + sub->addChild(new LLMenuItemCallGL("Group Info to Debug Console", &handle_dump_group_info, NULL, NULL)); - sub->append(new LLMenuItemCallGL("Capabilities Info to Debug Console", + sub->addChild(new LLMenuItemCallGL("Capabilities Info to Debug Console", &handle_dump_capabilities_info, NULL, NULL)); sub->createJumpKeys(); } // neither of these works particularly well at the moment - /*menu->append(new LLMenuItemCallGL( "Reload UI XML", &reload_ui, + /*menu->addChild(new LLMenuItemCallGL( "Reload UI XML", &reload_ui, NULL, NULL) );*/ - /*menu->append(new LLMenuItemCallGL("Reload settings/colors", + /*menu->addChild(new LLMenuItemCallGL("Reload settings/colors", &handle_reload_settings, NULL, NULL));*/ - menu->append(new LLMenuItemCallGL("Reload personal setting overrides", + menu->addChild(new LLMenuItemCallGL("Reload personal setting overrides", &reload_personal_settings_overrides, NULL, NULL, KEY_F2, MASK_CONTROL|MASK_SHIFT)); sub_menu = new LLMenuGL("HUD Info"); { - sub_menu->append(new LLMenuItemCheckGL("Velocity", + sub_menu->addChild(new LLMenuItemCheckGL("Velocity", &toggle_visibility, NULL, &get_visibility, (void*)gVelocityBar)); - sub_menu->append(new LLMenuItemToggleGL("Camera", &gDisplayCameraPos ) ); - sub_menu->append(new LLMenuItemToggleGL("Wind", &gDisplayWindInfo) ); - sub_menu->append(new LLMenuItemToggleGL("FOV", &gDisplayFOV ) ); + sub_menu->addChild(new LLMenuItemToggleGL("Camera", &gDisplayCameraPos ) ); + sub_menu->addChild(new LLMenuItemToggleGL("Wind", &gDisplayWindInfo) ); + sub_menu->addChild(new LLMenuItemToggleGL("FOV", &gDisplayFOV ) ); sub_menu->createJumpKeys(); } - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); - menu->appendSeparator(); + menu->addSeparator(); - menu->append(new LLMenuItemCheckGL( "High-res Snapshot", + menu->addChild(new LLMenuItemCheckGL( "High-res Snapshot", &menu_toggle_control, NULL, &menu_check_control, (void*)"HighResSnapshot")); - menu->append(new LLMenuItemCheckGL( "Quiet Snapshots to Disk", + menu->addChild(new LLMenuItemCheckGL( "Quiet Snapshots to Disk", &menu_toggle_control, NULL, &menu_check_control, (void*)"QuietSnapshotsToDisk")); - menu->append(new LLMenuItemCheckGL("Show Mouselook Crosshairs", + menu->addChild(new LLMenuItemCheckGL("Show Mouselook Crosshairs", &menu_toggle_control, NULL, &menu_check_control, (void*)"ShowCrosshairs")); - menu->append(new LLMenuItemCheckGL("Debug Permissions", + menu->addChild(new LLMenuItemCheckGL("Debug Permissions", &menu_toggle_control, NULL, &menu_check_control, @@ -1028,7 +1022,7 @@ void init_client_menu(LLMenuGL* menu) #ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid()) { - menu->append(new LLMenuItemCheckGL("Hacked Godmode", + menu->addChild(new LLMenuItemCheckGL("Hacked Godmode", &handle_toggle_hacked_godmode, NULL, &check_toggle_hacked_godmode, @@ -1036,20 +1030,20 @@ void init_client_menu(LLMenuGL* menu) } #endif // - menu->append(new LLMenuItemCallGL("Clear Group Cache", + menu->addChild(new LLMenuItemCallGL("Clear Group Cache", LLGroupMgr::debugClearAllGroups)); - menu->append(new LLMenuItemCheckGL("Use Web Map Tiles", menu_toggle_control, NULL, menu_check_control, (void*)"UseWebMapTiles")); + menu->addChild(new LLMenuItemCheckGL("Use Web Map Tiles", menu_toggle_control, NULL, menu_check_control, (void*)"UseWebMapTiles")); - menu->appendSeparator(); + menu->addSeparator(); sub_menu = new LLMenuGL("Rendering"); init_debug_rendering_menu(sub_menu); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); sub_menu = new LLMenuGL("World"); init_debug_world_menu(sub_menu); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1b | OK #ifdef RLV_ADVANCED_MENU @@ -1057,7 +1051,7 @@ void init_client_menu(LLMenuGL* menu) { sub_menu = new LLMenuGL("RLVa"); init_debug_rlva_menu(sub_menu); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); sub_menu->setVisible(rlv_handler_t::isEnabled()); sub_menu->setEnabled(rlv_handler_t::isEnabled()); } @@ -1066,107 +1060,107 @@ void init_client_menu(LLMenuGL* menu) sub_menu = new LLMenuGL("UI"); init_debug_ui_menu(sub_menu); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); sub_menu = new LLMenuGL("XUI"); init_debug_xui_menu(sub_menu); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); sub_menu = new LLMenuGL("Character"); init_debug_avatar_menu(sub_menu); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); { LLMenuGL* sub = NULL; sub = new LLMenuGL("Network"); - sub->append(new LLMenuItemCallGL("Enable Message Log", + sub->addChild(new LLMenuItemCallGL("Enable Message Log", &handle_viewer_enable_message_log, NULL)); - sub->append(new LLMenuItemCallGL("Disable Message Log", + sub->addChild(new LLMenuItemCallGL("Disable Message Log", &handle_viewer_disable_message_log, NULL)); - sub->appendSeparator(); + sub->addSeparator(); - sub->append(new LLMenuItemCheckGL("Velocity Interpolate Objects", + sub->addChild(new LLMenuItemCheckGL("Velocity Interpolate Objects", &velocity_interpolate, NULL, &menu_check_control, (void*)"VelocityInterpolate")); - sub->append(new LLMenuItemCheckGL("Ping Interpolate Object Positions", + sub->addChild(new LLMenuItemCheckGL("Ping Interpolate Object Positions", &menu_toggle_control, NULL, &menu_check_control, (void*)"PingInterpolate")); - sub->appendSeparator(); + sub->addSeparator(); - sub->append(new LLMenuItemCallGL("Drop a Packet", + sub->addChild(new LLMenuItemCallGL("Drop a Packet", &drop_packet, NULL, NULL, 'L', MASK_ALT | MASK_CONTROL)); - menu->appendMenu( sub ); + menu->addChild( sub ); sub->createJumpKeys(); } { LLMenuGL* sub = NULL; sub = new LLMenuGL("Recorder"); - sub->append(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, NULL, &menu_check_control, (void*)"StatsSessionTrackFrameStats")); + sub->addChild(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, NULL, &menu_check_control, (void*)"StatsSessionTrackFrameStats")); - sub->append(new LLMenuItemCallGL("Start Logging", &LLFrameStats::startLogging, NULL)); - sub->append(new LLMenuItemCallGL("Stop Logging", &LLFrameStats::stopLogging, NULL)); - sub->append(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, NULL)); - sub->append(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, NULL)); - sub->append(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, NULL)); - sub->appendSeparator(); - sub->append(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, NULL)); - sub->append(new LLMenuItemCallGL("Stop Playback", &LLAgentPilot::stopPlayback, NULL)); - sub->append(new LLMenuItemToggleGL("Loop Playback", &LLAgentPilot::sLoop) ); - sub->append(new LLMenuItemCallGL("Start Record", &LLAgentPilot::startRecord, NULL)); - sub->append(new LLMenuItemCallGL("Stop Record", &LLAgentPilot::saveRecord, NULL)); + sub->addChild(new LLMenuItemCallGL("Start Logging", &LLFrameStats::startLogging, NULL)); + sub->addChild(new LLMenuItemCallGL("Stop Logging", &LLFrameStats::stopLogging, NULL)); + sub->addChild(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, NULL)); + sub->addChild(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, NULL)); + sub->addChild(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, NULL)); + sub->addSeparator(); + sub->addChild(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, NULL)); + sub->addChild(new LLMenuItemCallGL("Stop Playback", &LLAgentPilot::stopPlayback, NULL)); + sub->addChild(new LLMenuItemToggleGL("Loop Playback", &LLAgentPilot::sLoop) ); + sub->addChild(new LLMenuItemCallGL("Start Record", &LLAgentPilot::startRecord, NULL)); + sub->addChild(new LLMenuItemCallGL("Stop Record", &LLAgentPilot::saveRecord, NULL)); - menu->appendMenu( sub ); + menu->addChild( sub ); sub->createJumpKeys(); } { LLMenuGL* sub = NULL; sub = new LLMenuGL("Media"); - sub->append(new LLMenuItemCallGL("Reload MIME types", &LLMIMETypes::reload)); - sub->append(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test)); - menu->appendMenu( sub ); + sub->addChild(new LLMenuItemCallGL("Reload MIME types", &LLMIMETypes::reload)); + sub->addChild(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test)); + menu->addChild( sub ); sub->createJumpKeys(); } - menu->appendSeparator(); + menu->addSeparator(); - menu->append(new LLMenuItemToggleGL("Show Updates", + menu->addChild(new LLMenuItemToggleGL("Show Updates", &gShowObjectUpdates)); - menu->appendSeparator(); + menu->addSeparator(); - menu->append(new LLMenuItemCallGL("Compress Images...", + menu->addChild(new LLMenuItemCallGL("Compress Images...", &handle_compress_image, NULL, NULL)); - menu->append(new LLMenuItemCheckGL("Limit Select Distance", + menu->addChild(new LLMenuItemCheckGL("Limit Select Distance", &menu_toggle_control, NULL, &menu_check_control, (void*)"LimitSelectDistance")); - menu->append(new LLMenuItemCheckGL("Disable Camera Constraints", + menu->addChild(new LLMenuItemCheckGL("Disable Camera Constraints", &menu_toggle_control, NULL, &menu_check_control, (void*)"DisableCameraConstraints")); - menu->append(new LLMenuItemCheckGL("Mouse Smoothing", + menu->addChild(new LLMenuItemCheckGL("Mouse Smoothing", &menu_toggle_control, NULL, &menu_check_control, (void*) "MouseSmooth")); - menu->appendSeparator(); + menu->addSeparator(); - menu->append(new LLMenuItemCheckGL( "Console Window", + menu->addChild(new LLMenuItemCheckGL( "Console Window", &menu_toggle_control, NULL, &menu_check_control, @@ -1175,7 +1169,7 @@ void init_client_menu(LLMenuGL* menu) // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-1.0.0e | OK #ifdef RLV_ADVANCED_TOGGLE_RLVA if (gSavedSettings.controlExists(RLV_SETTING_MAIN)) - menu->append(new LLMenuItemCheckGL("RestrainedLove API", &rlvToggleEnabled, NULL, &rlvGetEnabled, NULL)); + menu->addChild(new LLMenuItemCheckGL("RestrainedLove API", &rlvToggleEnabled, NULL, &rlvGetEnabled, NULL)); #endif // RLV_ADVANCED_TOGGLE_RLVA // [/RLVa:KB] @@ -1184,31 +1178,31 @@ void init_client_menu(LLMenuGL* menu) LLMenuGL* sub = NULL; sub = new LLMenuGL("Debugging"); #if LL_WINDOWS - sub->append(new LLMenuItemCallGL("Force Breakpoint", &force_error_breakpoint, NULL, NULL, 'B', MASK_CONTROL | MASK_ALT)); + sub->addChild(new LLMenuItemCallGL("Force Breakpoint", &force_error_breakpoint, NULL, NULL, 'B', MASK_CONTROL | MASK_ALT)); #endif - sub->append(new LLMenuItemCallGL("Force LLError And Crash", &force_error_llerror)); - sub->append(new LLMenuItemCallGL("Force Bad Memory Access", &force_error_bad_memory_access)); - sub->append(new LLMenuItemCallGL("Force Infinite Loop", &force_error_infinite_loop)); - sub->append(new LLMenuItemCallGL("Force Driver Crash", &force_error_driver_crash)); - sub->append(new LLMenuItemCallGL("Force Disconnect Viewer", &handle_disconnect_viewer)); - // *NOTE:Mani this isn't handled yet... sub->append(new LLMenuItemCallGL("Force Software Exception", &force_error_unhandled_exception)); + sub->addChild(new LLMenuItemCallGL("Force LLError And Crash", &force_error_llerror)); + sub->addChild(new LLMenuItemCallGL("Force Bad Memory Access", &force_error_bad_memory_access)); + sub->addChild(new LLMenuItemCallGL("Force Infinite Loop", &force_error_infinite_loop)); + sub->addChild(new LLMenuItemCallGL("Force Driver Crash", &force_error_driver_crash)); + sub->addChild(new LLMenuItemCallGL("Force Disconnect Viewer", &handle_disconnect_viewer)); + // *NOTE:Mani this isn't handled yet... sub->addChild(new LLMenuItemCallGL("Force Software Exception", &force_error_unhandled_exception)); sub->createJumpKeys(); - menu->appendMenu(sub); + menu->addChild(sub); } - menu->append(new LLMenuItemCheckGL( "Output Debug Minidump", + menu->addChild(new LLMenuItemCheckGL( "Output Debug Minidump", &menu_toggle_control, NULL, &menu_check_control, (void*)"SaveMinidump")); - menu->append(new LLMenuItemCallGL("Debug Settings...", LLFloaterSettingsDebug::show, NULL, NULL)); - menu->append(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, NULL, &check_admin_override, NULL, 'V', MASK_CONTROL | MASK_ALT)); + menu->addChild(new LLMenuItemCallGL("Debug Settings...", LLFloaterSettingsDebug::show, NULL, NULL)); + menu->addChild(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, NULL, &check_admin_override, NULL, 'V', MASK_CONTROL | MASK_ALT)); - menu->append(new LLMenuItemCallGL("Request Admin Status", + menu->addChild(new LLMenuItemCallGL("Request Admin Status", &handle_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_CONTROL)); - menu->append(new LLMenuItemCallGL("Leave Admin Status", + menu->addChild(new LLMenuItemCallGL("Leave Admin Status", &handle_leave_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL)); menu->createJumpKeys(); @@ -1217,26 +1211,26 @@ void init_client_menu(LLMenuGL* menu) void init_debug_world_menu(LLMenuGL* menu) { /* REMOVE mouse move sun from menu options - menu->append(new LLMenuItemCheckGL("Mouse Moves Sun", + menu->addChild(new LLMenuItemCheckGL("Mouse Moves Sun", &menu_toggle_control, NULL, &menu_check_control, (void*)"MouseSun", 'M', MASK_CONTROL|MASK_ALT)); */ - menu->append(new LLMenuItemCheckGL("Sim Sun Override", + menu->addChild(new LLMenuItemCheckGL("Sim Sun Override", &menu_toggle_control, NULL, &menu_check_control, (void*)"SkyOverrideSimSunPosition")); - menu->append(new LLMenuItemCallGL("Dump Scripted Camera", + menu->addChild(new LLMenuItemCallGL("Dump Scripted Camera", &handle_dump_followcam, NULL, NULL)); - menu->append(new LLMenuItemCheckGL("Fixed Weather", + menu->addChild(new LLMenuItemCheckGL("Fixed Weather", &menu_toggle_control, NULL, &menu_check_control, (void*)"FixedWeather")); - menu->append(new LLMenuItemCallGL("Dump Region Object Cache", + menu->addChild(new LLMenuItemCallGL("Dump Region Object Cache", &handle_dump_region_object_cache, NULL, NULL)); menu->createJumpKeys(); } @@ -1263,60 +1257,60 @@ static void handle_export_menus_to_xml_continued(AIFilePicker* filepicker) void init_debug_ui_menu(LLMenuGL* menu) { - menu->append(new LLMenuItemCheckGL("Rotate Mini-Map", menu_toggle_control, NULL, menu_check_control, (void*)"MiniMapRotate")); - menu->append(new LLMenuItemCheckGL("Use default system color picker", menu_toggle_control, NULL, menu_check_control, (void*)"UseDefaultColorPicker")); - menu->append(new LLMenuItemCheckGL("Show search panel in overlay bar", menu_toggle_control, NULL, menu_check_control, (void*)"ShowSearchBar")); - menu->appendSeparator(); + menu->addChild(new LLMenuItemCheckGL("Rotate Mini-Map", menu_toggle_control, NULL, menu_check_control, (void*)"MiniMapRotate")); + menu->addChild(new LLMenuItemCheckGL("Use default system color picker", menu_toggle_control, NULL, menu_check_control, (void*)"UseDefaultColorPicker")); + menu->addChild(new LLMenuItemCheckGL("Show search panel in overlay bar", menu_toggle_control, NULL, menu_check_control, (void*)"ShowSearchBar")); + menu->addSeparator(); // commented out until work is complete: DEV-32268 - // menu->append(new LLMenuItemCallGL("Buy Currency Test", &handle_buy_currency_test)); - menu->append(new LLMenuItemCallGL("Editable UI", &edit_ui)); - menu->append(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr)); - menu->append(new LLMenuItemCallGL( "Dump Inventory", &dump_inventory)); - menu->append(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, NULL, NULL, 'F', MASK_ALT | MASK_CONTROL)); - menu->append(new LLMenuItemCallGL( "Print Selected Object Info", &print_object_info, NULL, NULL, 'P', MASK_CONTROL|MASK_SHIFT )); - menu->append(new LLMenuItemCallGL( "Print Agent Info", &print_agent_nvpairs, NULL, NULL, 'P', MASK_SHIFT )); - menu->append(new LLMenuItemCallGL( "Memory Stats", &output_statistics, NULL, NULL, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - menu->append(new LLMenuItemCheckGL("Double-Click Auto-Pilot", + // menu->addChild(new LLMenuItemCallGL("Buy Currency Test", &handle_buy_currency_test)); + menu->addChild(new LLMenuItemCallGL("Editable UI", &edit_ui)); + menu->addChild(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr)); + menu->addChild(new LLMenuItemCallGL( "Dump Inventory", &dump_inventory)); + menu->addChild(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, NULL, NULL, 'F', MASK_ALT | MASK_CONTROL)); + menu->addChild(new LLMenuItemCallGL( "Print Selected Object Info", &print_object_info, NULL, NULL, 'P', MASK_CONTROL|MASK_SHIFT )); + menu->addChild(new LLMenuItemCallGL( "Print Agent Info", &print_agent_nvpairs, NULL, NULL, 'P', MASK_SHIFT )); + menu->addChild(new LLMenuItemCallGL( "Memory Stats", &output_statistics, NULL, NULL, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + menu->addChild(new LLMenuItemCheckGL("Double-Click Auto-Pilot", menu_toggle_control, NULL, menu_check_control, (void*)"DoubleClickAutoPilot")); // add for double click teleport support - menu->append(new LLMenuItemCheckGL("Double-Click Teleport", + menu->addChild(new LLMenuItemCheckGL("Double-Click Teleport", menu_toggle_control, NULL, menu_check_control, (void*)"DoubleClickTeleport")); - menu->appendSeparator(); -// menu->append(new LLMenuItemCallGL( "Print Packets Lost", &print_packets_lost, NULL, NULL, 'L', MASK_SHIFT )); - menu->append(new LLMenuItemCheckGL("Debug SelectMgr", menu_toggle_control, NULL, menu_check_control, (void*)"DebugSelectMgr")); - menu->append(new LLMenuItemToggleGL("Debug Clicks", &gDebugClicks)); - menu->append(new LLMenuItemToggleGL("Debug Views", &LLView::sDebugRects)); - menu->append(new LLMenuItemCheckGL("Show Name Tooltips", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); - menu->append(new LLMenuItemToggleGL("Debug Mouse Events", &LLView::sDebugMouseHandling)); - menu->append(new LLMenuItemToggleGL("Debug Keys", &LLView::sDebugKeys)); - menu->append(new LLMenuItemToggleGL("Debug WindowProc", &gDebugWindowProc)); - menu->append(new LLMenuItemToggleGL("Debug Text Editor Tips", &gDebugTextEditorTips)); - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime")); - menu->append(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo")); - menu->append(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderMatrices")); - menu->append(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor")); + menu->addSeparator(); +// menu->addChild(new LLMenuItemCallGL( "Print Packets Lost", &print_packets_lost, NULL, NULL, 'L', MASK_SHIFT )); + menu->addChild(new LLMenuItemCheckGL("Debug SelectMgr", menu_toggle_control, NULL, menu_check_control, (void*)"DebugSelectMgr")); + menu->addChild(new LLMenuItemToggleGL("Debug Clicks", &gDebugClicks)); + menu->addChild(new LLMenuItemToggleGL("Debug Views", &LLView::sDebugRects)); + menu->addChild(new LLMenuItemCheckGL("Show Name Tooltips", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); + menu->addChild(new LLMenuItemToggleGL("Debug Mouse Events", &LLView::sDebugMouseHandling)); + menu->addChild(new LLMenuItemToggleGL("Debug Keys", &LLView::sDebugKeys)); + menu->addChild(new LLMenuItemToggleGL("Debug WindowProc", &gDebugWindowProc)); + menu->addChild(new LLMenuItemToggleGL("Debug Text Editor Tips", &gDebugTextEditorTips)); + menu->addSeparator(); + menu->addChild(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime")); + menu->addChild(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo")); + menu->addChild(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderMatrices")); + menu->addChild(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor")); menu->createJumpKeys(); } void init_debug_xui_menu(LLMenuGL* menu) { - menu->append(new LLMenuItemCallGL("Floater Test...", LLFloaterTest::show)); - menu->append(new LLMenuItemCallGL("Font Test...", LLFloaterFontTest::show)); - menu->append(new LLMenuItemCallGL("Export Menus to XML...", handle_export_menus_to_xml)); - menu->append(new LLMenuItemCallGL("Edit UI...", LLFloaterEditUI::show)); - menu->append(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml)); + menu->addChild(new LLMenuItemCallGL("Floater Test...", LLFloaterTest::show)); + menu->addChild(new LLMenuItemCallGL("Font Test...", LLFloaterFontTest::show)); + menu->addChild(new LLMenuItemCallGL("Export Menus to XML...", handle_export_menus_to_xml)); + menu->addChild(new LLMenuItemCallGL("Edit UI...", LLFloaterEditUI::show)); + menu->addChild(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml)); // - //menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml)); - menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, NULL, NULL, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT)); + //menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml)); + menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, NULL, NULL, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT)); // - menu->append(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); + menu->addChild(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); - //menu->append(new LLMenuItemCallGL("Buy Currency...", handle_buy_currency)); + //menu->addChild(new LLMenuItemCallGL("Buy Currency...", handle_buy_currency)); menu->createJumpKeys(); } @@ -1329,94 +1323,94 @@ void init_debug_rendering_menu(LLMenuGL* menu) // Debug menu for types/pools // sub_menu = new LLMenuGL("Types"); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); - sub_menu->append(new LLMenuItemCheckGL("Simple", + sub_menu->addChild(new LLMenuItemCheckGL("Simple", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SIMPLE, '1', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Alpha", + sub_menu->addChild(new LLMenuItemCheckGL("Alpha", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_ALPHA, '2', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Tree", + sub_menu->addChild(new LLMenuItemCheckGL("Tree", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TREE, '3', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Character", + sub_menu->addChild(new LLMenuItemCheckGL("Character", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_AVATAR, '4', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("SurfacePatch", + sub_menu->addChild(new LLMenuItemCheckGL("SurfacePatch", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TERRAIN, '5', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Sky", + sub_menu->addChild(new LLMenuItemCheckGL("Sky", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SKY, '6', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Water", + sub_menu->addChild(new LLMenuItemCheckGL("Water", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_WATER, '7', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Ground", + sub_menu->addChild(new LLMenuItemCheckGL("Ground", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GROUND, '8', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Volume", + sub_menu->addChild(new LLMenuItemCheckGL("Volume", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_VOLUME, '9', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Grass", + sub_menu->addChild(new LLMenuItemCheckGL("Grass", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GRASS, '0', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); //NOTE: Using a static variable, as an unsigned long long cannot fit in the space of a pointer. Pass pointer to callbacks static U64 cloud_flags = (1ULL<append(new LLMenuItemCheckGL("Clouds", //This clobbers skyuseclassicclouds, but.. big deal. + sub_menu->addChild(new LLMenuItemCheckGL("Clouds", //This clobbers skyuseclassicclouds, but.. big deal. &LLPipeline::toggleRenderPairedTypeControl, NULL, &LLPipeline::hasRenderPairedTypeControl, (void*)&cloud_flags, '-', MASK_CONTROL|MASK_ALT| MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Particles", + sub_menu->addChild(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_PARTICLES, '=', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Bump", + sub_menu->addChild(new LLMenuItemCheckGL("Bump", &LLPipeline::toggleRenderTypeControl, NULL, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_BUMP, '\\', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->createJumpKeys(); sub_menu = new LLMenuGL("Features"); - menu->appendMenu(sub_menu); - sub_menu->append(new LLMenuItemCheckGL("UI", + menu->addChild(sub_menu); + sub_menu->addChild(new LLMenuItemCheckGL("UI", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_UI, KEY_F1, MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL("Selected", + sub_menu->addChild(new LLMenuItemCheckGL("Selected", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_SELECTED, KEY_F2, MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL("Highlighted", + sub_menu->addChild(new LLMenuItemCheckGL("Highlighted", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED, KEY_F3, MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL("Dynamic Textures", + sub_menu->addChild(new LLMenuItemCheckGL("Dynamic Textures", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES, KEY_F4, MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL( "Foot Shadows", + sub_menu->addChild(new LLMenuItemCheckGL( "Foot Shadows", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS, KEY_F5, MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL("Fog", + sub_menu->addChild(new LLMenuItemCheckGL("Fog", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOG, KEY_F6, MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL("Test FRInfo", + sub_menu->addChild(new LLMenuItemCheckGL("Test FRInfo", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO, KEY_F8, MASK_ALT|MASK_CONTROL)); - sub_menu->append(new LLMenuItemCheckGL( "Flexible Objects", + sub_menu->addChild(new LLMenuItemCheckGL( "Flexible Objects", &LLPipeline::toggleRenderDebugFeature, NULL, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE, KEY_F9, MASK_ALT|MASK_CONTROL)); @@ -1427,165 +1421,165 @@ void init_debug_rendering_menu(LLMenuGL* menu) // Debug menu for info displays // sub_menu = new LLMenuGL("Info Displays"); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); - sub_menu->append(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_VERIFY)); - sub_menu->append(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BBOXES)); - sub_menu->append(new LLMenuItemCheckGL("Points", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Points", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_POINTS)); - sub_menu->append(new LLMenuItemCheckGL("Octree", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Octree", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_OCTREE)); - sub_menu->append(new LLMenuItemCheckGL("Shadow Frusta", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Shadow Frusta", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)); - sub_menu->append(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_OCCLUSION)); - sub_menu->append(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BATCH_SIZE)); - sub_menu->append(new LLMenuItemCheckGL("Animated Textures", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Animated Textures", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_ANIM)); - sub_menu->append(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)); - sub_menu->append(new LLMenuItemCheckGL("Avatar Rendering Cost", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Avatar Rendering Cost", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SHAME)); - sub_menu->append(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_AREA)); - sub_menu->append(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_FACE_AREA)); - sub_menu->append(new LLMenuItemCheckGL("Lights", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Lights", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_LIGHTS)); - sub_menu->append(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_PARTICLES)); - sub_menu->append(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_COMPOSITION)); - sub_menu->append(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_GLOW)); - sub_menu->append(new LLMenuItemCheckGL("Raycasting", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Raycasting", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_RAYCAST)); - sub_menu->append(new LLMenuItemCheckGL("Sculpt", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Sculpt", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SCULPTED)); - sub_menu->append(new LLMenuItemCheckGL("Build Queue", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Build Queue", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BUILD_QUEUE)); - sub_menu->append(new LLMenuItemCheckGL("Update Types", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Update Types", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_UPDATE_TYPE)); - sub_menu->append(new LLMenuItemCheckGL("Physics Shapes", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Physics Shapes", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)); - sub_menu->append(new LLMenuItemCheckGL("Normals", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Normals", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_NORMALS)); - sub_menu->append(new LLMenuItemCheckGL("LOD Info", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("LOD Info", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_LOD_INFO)); - sub_menu->append(new LLMenuItemCheckGL("Wind Vectors", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Wind Vectors", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_WIND_VECTORS)); - sub_menu->append(new LLMenuItemCheckGL("Complexity", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Complexity", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)); ; sub_menu = new LLMenuGL("Render Tests"); - sub_menu->append(new LLMenuItemCheckGL("Camera Offset", + sub_menu->addChild(new LLMenuItemCheckGL("Camera Offset", &menu_toggle_control, NULL, &menu_check_control, (void*)"CameraOffset")); - sub_menu->append(new LLMenuItemToggleGL("Randomize Framerate", &gRandomizeFramerate)); + sub_menu->addChild(new LLMenuItemToggleGL("Randomize Framerate", &gRandomizeFramerate)); - sub_menu->append(new LLMenuItemToggleGL("Periodic Slow Frame", &gPeriodicSlowFrame)); + sub_menu->addChild(new LLMenuItemToggleGL("Periodic Slow Frame", &gPeriodicSlowFrame)); - sub_menu->append(new LLMenuItemToggleGL("Frame Test", &LLPipeline::sRenderFrameTest)); + sub_menu->addChild(new LLMenuItemToggleGL("Frame Test", &LLPipeline::sRenderFrameTest)); sub_menu->createJumpKeys(); - menu->appendMenu( sub_menu ); + menu->addChild( sub_menu ); - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL("Axes", menu_toggle_control, NULL, menu_check_control, (void*)"ShowAxes")); - //menu->append(new LLMenuItemCheckGL("Cull Small Objects", toggle_cull_small, NULL, menu_check_control, (void*)"RenderCullBySize")); + menu->addSeparator(); + menu->addChild(new LLMenuItemCheckGL("Axes", menu_toggle_control, NULL, menu_check_control, (void*)"ShowAxes")); + //menu->addChild(new LLMenuItemCheckGL("Cull Small Objects", toggle_cull_small, NULL, menu_check_control, (void*)"RenderCullBySize")); - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL("Hide Selected", menu_toggle_control, NULL, menu_check_control, (void*)"HideSelectedObjects")); - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, NULL, menu_check_control, (void*)"ShowTangentBasis")); - menu->append(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, NULL, NULL, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT)); - //menu->append(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, NULL, NULL, 'I', MASK_CONTROL|MASK_SHIFT)); + menu->addSeparator(); + menu->addChild(new LLMenuItemCheckGL("Hide Selected", menu_toggle_control, NULL, menu_check_control, (void*)"HideSelectedObjects")); + menu->addSeparator(); + menu->addChild(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, NULL, menu_check_control, (void*)"ShowTangentBasis")); + menu->addChild(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, NULL, NULL, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT)); + //menu->addChild(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, NULL, NULL, 'I', MASK_CONTROL|MASK_SHIFT)); - menu->append(new LLMenuItemToggleGL("Wireframe", &gUseWireframe, + menu->addChild(new LLMenuItemToggleGL("Wireframe", &gUseWireframe, 'R', MASK_CONTROL|MASK_SHIFT)); LLMenuItemCheckGL* item; item = new LLMenuItemCheckGL("Object-Object Occlusion", menu_toggle_control, NULL, menu_check_control, (void*)"UseOcclusion", 'O', MASK_CONTROL|MASK_SHIFT); item->setEnabled(gGLManager.mHasOcclusionQuery && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Debug GL", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugGL"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Debug Pipeline", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugPipeline"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Automatic Alpha Masks (non-deferred)", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAutoMaskAlphaNonDeferred"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Automatic Alpha Masks (deferred)", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAutoMaskAlphaDeferred"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_control, NULL, menu_check_control, (void*)"TextureDisable"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("HTTP Get Textures", menu_toggle_control, NULL, menu_check_control, (void*)"ImagePipelineUseHTTP"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Run Multiple Threads", menu_toggle_control, NULL, menu_check_control, (void*)"RunMultipleThreads"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, NULL, menu_check_control, (void*)"CheesyBeacon"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Attached Lights", menu_toggle_attached_lights, NULL, menu_check_control, (void*)"RenderAttachedLights"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Attached Particles", menu_toggle_attached_particles, NULL, menu_check_control, (void*)"RenderAttachedParticles"); - menu->append(item); + menu->addChild(item); item = new LLMenuItemCheckGL("Audit Texture", menu_toggle_control, NULL, menu_check_control, (void*)"AuditTexture"); - menu->append(item); + menu->addChild(item); #ifndef LL_RELEASE_FOR_DOWNLOAD - menu->appendSeparator(); - menu->append(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); + menu->addSeparator(); + menu->addChild(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); #else if(gSavedSettings.getBOOL("QAMode")) { - menu->appendSeparator(); - menu->append(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); + menu->addSeparator(); + menu->addChild(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); } #endif @@ -1595,74 +1589,74 @@ void init_debug_rendering_menu(LLMenuGL* menu) void init_debug_avatar_menu(LLMenuGL* menu) { LLMenuGL* sub_menu = new LLMenuGL("Character Tests"); - menu->appendMenu(sub_menu); - sub_menu->append(new LLMenuItemToggleGL("Go Away/AFK When Idle", + menu->addChild(sub_menu); + sub_menu->addChild(new LLMenuItemToggleGL("Go Away/AFK When Idle", &gAllowIdleAFK)); - sub_menu->append(new LLMenuItemCallGL("Appearance To XML", + sub_menu->addChild(new LLMenuItemCallGL("Appearance To XML", &LLVOAvatar::dumpArchetypeXML)); // HACK for easy testing of avatar geometry - sub_menu->append(new LLMenuItemCallGL( "Toggle Character Geometry", + sub_menu->addChild(new LLMenuItemCallGL( "Toggle Character Geometry", &handle_god_request_avatar_geometry, &enable_god_customer_service, NULL)); - sub_menu->append(new LLMenuItemCallGL("Test Male", + sub_menu->addChild(new LLMenuItemCallGL("Test Male", handle_test_male)); - sub_menu->append(new LLMenuItemCallGL("Test Female", + sub_menu->addChild(new LLMenuItemCallGL("Test Female", handle_test_female)); - sub_menu->append(new LLMenuItemCallGL("Toggle PG", handle_toggle_pg)); + sub_menu->addChild(new LLMenuItemCallGL("Toggle PG", handle_toggle_pg)); - sub_menu->append(new LLMenuItemCheckGL("Allow Select Avatar", menu_toggle_control, NULL, menu_check_control, (void*)"AllowSelectAvatar")); + sub_menu->addChild(new LLMenuItemCheckGL("Allow Select Avatar", menu_toggle_control, NULL, menu_check_control, (void*)"AllowSelectAvatar")); sub_menu->createJumpKeys(); - menu->appendMenu(sub_menu); + menu->addChild(sub_menu); - menu->append(new LLMenuItemToggleGL("Tap-Tap-Hold To Run", &gAllowTapTapHoldRun)); - menu->append(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, NULL)); - menu->append(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, NULL)); - menu->append(new LLMenuItemToggleGL("Animation Info", &LLVOAvatar::sShowAnimationDebug)); - menu->append(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, NULL)); + menu->addChild(new LLMenuItemToggleGL("Tap-Tap-Hold To Run", &gAllowTapTapHoldRun)); + menu->addChild(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, NULL)); + menu->addChild(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, NULL)); + menu->addChild(new LLMenuItemToggleGL("Animation Info", &LLVOAvatar::sShowAnimationDebug)); + menu->addChild(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, NULL)); LLMenuItemCheckGL* item; item = new LLMenuItemCheckGL("Show Look At", menu_toggle_control, NULL, menu_check_control, (void*)"AscentShowLookAt"); - menu->append(item); + menu->addChild(item); - menu->append(new LLMenuItemToggleGL("Show Point At", &LLHUDEffectPointAt::sDebugPointAt)); - menu->append(new LLMenuItemToggleGL("Debug Joint Updates", &LLVOAvatar::sJointDebug)); - menu->append(new LLMenuItemToggleGL("Disable LOD", &LLViewerJoint::sDisableLOD)); - menu->append(new LLMenuItemToggleGL("Debug Character Vis", &LLVOAvatar::sDebugInvisible)); - //menu->append(new LLMenuItemToggleGL("Show Attachment Points", &LLVOAvatar::sShowAttachmentPoints)); + menu->addChild(new LLMenuItemToggleGL("Show Point At", &LLHUDEffectPointAt::sDebugPointAt)); + menu->addChild(new LLMenuItemToggleGL("Debug Joint Updates", &LLVOAvatar::sJointDebug)); + menu->addChild(new LLMenuItemToggleGL("Disable LOD", &LLViewerJoint::sDisableLOD)); + menu->addChild(new LLMenuItemToggleGL("Debug Character Vis", &LLVOAvatar::sDebugInvisible)); + //menu->addChild(new LLMenuItemToggleGL("Show Attachment Points", &LLVOAvatar::sShowAttachmentPoints)); //diabling collision plane due to DEV-14477 -brad - //menu->append(new LLMenuItemToggleGL("Show Collision Plane", &LLVOAvatar::sShowFootPlane)); - menu->append(new LLMenuItemCheckGL("Show Collision Skeleton", + //menu->addChild(new LLMenuItemToggleGL("Show Collision Plane", &LLVOAvatar::sShowFootPlane)); + menu->addChild(new LLMenuItemCheckGL("Show Collision Skeleton", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_AVATAR_VOLUME)); - menu->append(new LLMenuItemCheckGL("Display Agent Target", + menu->addChild(new LLMenuItemCheckGL("Display Agent Target", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_AGENT_TARGET)); - menu->append(new LLMenuItemCheckGL("Attachment Bytes", + menu->addChild(new LLMenuItemCheckGL("Attachment Bytes", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES)); - menu->append(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation)); - menu->append(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments)); - menu->append(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures, NULL, NULL, 'R', MASK_ALT | MASK_CONTROL )); + menu->addChild(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation)); + menu->addChild(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments)); + menu->addChild(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures, NULL, NULL, 'R', MASK_ALT | MASK_CONTROL )); // //#ifndef LL_RELEASE_FOR_DOWNLOAD // - menu->append(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT)); - menu->append(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT )); + menu->addChild(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT)); + menu->addChild(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT )); // //#endif // LLMenuItemCallGL* mesh_item = new LLMenuItemCallGL("Meshes And Morphs...", handle_meshes_and_morphs); mesh_item->setUserData((void*)mesh_item); // So we can remove it later - menu->append(mesh_item); + menu->addChild(mesh_item); menu->createJumpKeys(); } @@ -1675,41 +1669,41 @@ void init_debug_rlva_menu(LLMenuGL* menu) LLMenuGL* pDbgMenu = new LLMenuGL("Debug"); if (gSavedSettings.controlExists(RLV_SETTING_DEBUG)) - pDbgMenu->append(new LLMenuItemCheckGL("Show Debug Messages", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_DEBUG)); - pDbgMenu->appendSeparator(); + pDbgMenu->addChild(new LLMenuItemCheckGL("Show Debug Messages", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_DEBUG)); + pDbgMenu->addSeparator(); if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) - pDbgMenu->append(new LLMenuItemCheckGL("Enable Legacy Naming", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLELEGACYNAMING)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Enable Legacy Naming", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLELEGACYNAMING)); if (gSavedSettings.controlExists(RLV_SETTING_SHAREDINVAUTORENAME)) - pDbgMenu->append(new LLMenuItemCheckGL("Rename Shared Items on Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHAREDINVAUTORENAME)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Rename Shared Items on Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHAREDINVAUTORENAME)); - menu->appendMenu(pDbgMenu); - menu->appendSeparator(); + menu->addChild(pDbgMenu); + menu->addSeparator(); } if (gSavedSettings.controlExists(RLV_SETTING_ENABLESHAREDWEAR)) - menu->append(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); - menu->appendSeparator(); + menu->addChild(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); + menu->addSeparator(); #ifdef RLV_EXTENSION_HIDELOCKED if ( (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDLAYER)) && (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDATTACH)) ) { - menu->append(new LLMenuItemCheckGL("Hide Locked Layers", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDLAYER)); - menu->append(new LLMenuItemCheckGL("Hide Locked Attachments", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDATTACH)); - //sub_menu->append(new LLMenuItemToggleGL("Hide locked inventory", &rlv_handler_t::fHideLockedInventory)); - menu->appendSeparator(); + menu->addChild(new LLMenuItemCheckGL("Hide Locked Layers", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDLAYER)); + menu->addChild(new LLMenuItemCheckGL("Hide Locked Attachments", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDATTACH)); + //sub_menu->addChild(new LLMenuItemToggleGL("Hide locked inventory", &rlv_handler_t::fHideLockedInventory)); + menu->addSeparator(); } #endif // RLV_EXTENSION_HIDELOCKED if (gSavedSettings.controlExists(RLV_SETTING_FORBIDGIVETORLV)) - menu->append(new LLMenuItemCheckGL("Forbid Give to #RLV", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_FORBIDGIVETORLV)); + menu->addChild(new LLMenuItemCheckGL("Forbid Give to #RLV", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_FORBIDGIVETORLV)); if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) - menu->append(new LLMenuItemCheckGL("Show Name Tags", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHOWNAMETAGS)); - menu->appendSeparator(); + menu->addChild(new LLMenuItemCheckGL("Show Name Tags", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHOWNAMETAGS)); + menu->addSeparator(); #ifdef RLV_EXTENSION_FLOATER_RESTRICTIONS // TODO-RLVa: figure out a way to tell if floater_rlv_behaviour.xml exists - menu->append(new LLMenuItemCallGL("Restrictions...", RlvFloaterBehaviour::show, NULL, NULL)); + menu->addChild(new LLMenuItemCallGL("Restrictions...", RlvFloaterBehaviour::show, NULL, NULL)); #endif // RLV_EXTENSION_FLOATER_RESTRICTIONS } // [/RLVa:KB] @@ -1718,73 +1712,73 @@ void init_server_menu(LLMenuGL* menu) { { LLMenuGL* sub = new LLMenuGL("Object"); - menu->appendMenu(sub); + menu->addChild(sub); - sub->append(new LLMenuItemCallGL( "Take Copy", + sub->addChild(new LLMenuItemCallGL( "Take Copy", &force_take_copy, &enable_god_customer_service, NULL, 'O', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); #ifdef _CORY_TESTING - sub->append(new LLMenuItemCallGL( "Export Copy", + sub->addChild(new LLMenuItemCallGL( "Export Copy", &force_export_copy, NULL, NULL)); - sub->append(new LLMenuItemCallGL( "Import Geometry", + sub->addChild(new LLMenuItemCallGL( "Import Geometry", &force_import_geometry, NULL, NULL)); #endif - //sub->append(new LLMenuItemCallGL( "Force Public", + //sub->addChild(new LLMenuItemCallGL( "Force Public", // &handle_object_owner_none, NULL, NULL)); - //sub->append(new LLMenuItemCallGL( "Force Ownership/Permissive", + //sub->addChild(new LLMenuItemCallGL( "Force Ownership/Permissive", // &handle_object_owner_self_and_permissive, NULL, NULL, 'K', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->append(new LLMenuItemCallGL( "Force Owner To Me", + sub->addChild(new LLMenuItemCallGL( "Force Owner To Me", &handle_object_owner_self, &enable_god_customer_service)); - sub->append(new LLMenuItemCallGL( "Force Owner Permissive", + sub->addChild(new LLMenuItemCallGL( "Force Owner Permissive", &handle_object_owner_permissive, &enable_god_customer_service)); - //sub->append(new LLMenuItemCallGL( "Force Totally Permissive", + //sub->addChild(new LLMenuItemCallGL( "Force Totally Permissive", // &handle_object_permissive)); - sub->append(new LLMenuItemCallGL( "Delete", + sub->addChild(new LLMenuItemCallGL( "Delete", &handle_force_delete, &enable_god_customer_service, NULL, KEY_DELETE, MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->append(new LLMenuItemCallGL( "Lock", + sub->addChild(new LLMenuItemCallGL( "Lock", &handle_object_lock, &enable_god_customer_service, NULL, 'L', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->append(new LLMenuItemCallGL( "Get Asset IDs", + sub->addChild(new LLMenuItemCallGL( "Get Asset IDs", &handle_object_asset_ids, &enable_god_customer_service, NULL, 'I', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->createJumpKeys(); } { LLMenuGL* sub = new LLMenuGL("Parcel"); - menu->appendMenu(sub); + menu->addChild(sub); - sub->append(new LLMenuItemCallGL("Owner To Me", + sub->addChild(new LLMenuItemCallGL("Owner To Me", &handle_force_parcel_owner_to_me, &enable_god_customer_service, NULL)); - sub->append(new LLMenuItemCallGL("Set to Linden Content", + sub->addChild(new LLMenuItemCallGL("Set to Linden Content", &handle_force_parcel_to_content, &enable_god_customer_service, NULL, 'C', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->appendSeparator(); - sub->append(new LLMenuItemCallGL("Claim Public Land", + sub->addSeparator(); + sub->addChild(new LLMenuItemCallGL("Claim Public Land", &handle_claim_public_land, &enable_god_customer_service)); sub->createJumpKeys(); } { LLMenuGL* sub = new LLMenuGL("Region"); - menu->appendMenu(sub); - sub->append(new LLMenuItemCallGL("Dump Temp Asset Data", + menu->addChild(sub); + sub->addChild(new LLMenuItemCallGL("Dump Temp Asset Data", &handle_region_dump_temp_asset_data, &enable_god_customer_service, NULL)); sub->createJumpKeys(); } - menu->append(new LLMenuItemCallGL( "God Tools...", + menu->addChild(new LLMenuItemCallGL( "God Tools...", &LLFloaterGodTools::show, &enable_god_basic, NULL)); - menu->appendSeparator(); + menu->addSeparator(); - menu->append(new LLMenuItemCallGL("Save Region State", + menu->addChild(new LLMenuItemCallGL("Save Region State", &LLPanelRegionTools::onSaveState, &enable_god_customer_service, NULL)); -// menu->append(new LLMenuItemCallGL("Force Join Group", handle_force_join_group)); +// menu->addChild(new LLMenuItemCallGL("Force Join Group", handle_force_join_group)); // -// menu->appendSeparator(); +// menu->addSeparator(); // -// menu->append(new LLMenuItemCallGL( "OverlayTitle", +// menu->addChild(new LLMenuItemCallGL( "OverlayTitle", // &handle_show_overlay_title, &enable_god_customer_service, NULL)); menu->createJumpKeys(); } @@ -5792,7 +5786,7 @@ void show_debug_menus() //gMenuBarView->setItemVisible("DebugOptions", visible); //gMenuBarView->setItemVisible(std::string(AVI_TOOLS), visible); - gMenuBarView->arrange(); // clean-up positioning + gMenuBarView->needsArrange(); // clean-up positioning }; } @@ -8293,11 +8287,11 @@ void handle_meshes_and_morphs(void* menu_item) { LLMenuItemCallGL* item = (LLMenuItemCallGL*) menu_item; LLMenuGL* parent_menu = (LLMenuGL*) item->getParent(); - parent_menu->remove(item); + parent_menu->removeChild(item); LLMenuGL* menu = new LLMenuGL("Meshes And Morphs"); - menu->append(new LLMenuItemCallGL("Dump Avatar Mesh Info", &LLPolyMesh::dumpDiagInfo)); - menu->appendSeparator(); + menu->addChild(new LLMenuItemCallGL("Dump Avatar Mesh Info", &LLPolyMesh::dumpDiagInfo)); + menu->addSeparator(); LLVOAvatar::mesh_info_t mesh_info; LLVOAvatar::getMeshInfo(&mesh_info); @@ -8329,30 +8323,30 @@ void handle_meshes_and_morphs(void* menu_item) LLPolyMesh::getMorphList(mesh, &morph_list); LLMenuGL* lod_menu = new LLMenuGL(caption); - lod_menu->append(new LLMenuItemCallGL("Save LLM", handle_mesh_save_llm, NULL, (void*) mesh_shared)); + lod_menu->addChild(new LLMenuItemCallGL("Save LLM", handle_mesh_save_llm, NULL, (void*) mesh_shared)); LLMenuGL* action_menu = new LLMenuGL("Base Mesh"); - action_menu->append(new LLMenuItemCallGL("Save OBJ", handle_mesh_save_obj, NULL, (void*) mesh_shared)); + action_menu->addChild(new LLMenuItemCallGL("Save OBJ", handle_mesh_save_obj, NULL, (void*) mesh_shared)); if (lod == 0) { // Since an LOD mesh has only faces, we won't enable this for // LOD meshes until we add code for processing the face commands. - action_menu->append(new LLMenuItemCallGL("Load OBJ", handle_mesh_load_obj, NULL, (void*) mesh_shared)); + action_menu->addChild(new LLMenuItemCallGL("Load OBJ", handle_mesh_load_obj, NULL, (void*) mesh_shared)); } action_menu->createJumpKeys(); - lod_menu->appendMenu(action_menu); + lod_menu->addChild(action_menu); action_menu = new LLMenuGL("Current Mesh"); - action_menu->append(new LLMenuItemCallGL("Save OBJ", handle_mesh_save_current_obj, NULL, (void*) mesh_shared)); + action_menu->addChild(new LLMenuItemCallGL("Save OBJ", handle_mesh_save_current_obj, NULL, (void*) mesh_shared)); action_menu->createJumpKeys(); - lod_menu->appendMenu(action_menu); + lod_menu->addChild(action_menu); - lod_menu->appendSeparator(); + lod_menu->addSeparator(); for(LLPolyMesh::morph_list_t::iterator morph_iter = morph_list.begin(); morph_iter != morph_list.end(); ++morph_iter) @@ -8362,23 +8356,23 @@ void handle_meshes_and_morphs(void* menu_item) action_menu = new LLMenuGL(morph_name); - action_menu->append(new LLMenuItemCallGL("Save OBJ", handle_morph_save_obj, NULL, (void*) morph_data)); - action_menu->append(new LLMenuItemCallGL("Load OBJ", handle_morph_load_obj, NULL, (void*) morph_data)); + action_menu->addChild(new LLMenuItemCallGL("Save OBJ", handle_morph_save_obj, NULL, (void*) morph_data)); + action_menu->addChild(new LLMenuItemCallGL("Load OBJ", handle_morph_load_obj, NULL, (void*) morph_data)); action_menu->createJumpKeys(); - lod_menu->appendMenu(action_menu); + lod_menu->addChild(action_menu); } lod_menu->createJumpKeys(); - type_menu->appendMenu(lod_menu); + type_menu->addChild(lod_menu); } type_menu->createJumpKeys(); - menu->appendMenu(type_menu); + menu->addChild(type_menu); } menu->createJumpKeys(); menu->updateParent(LLMenuGL::sMenuContainer); - parent_menu->appendMenu(menu); + parent_menu->addChild(menu); LLMenuGL::sMenuContainer->hideMenus(); LLFloater* tear_off_menu = LLTearOffMenu::create(menu); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 15aac7dd5..471f5c371 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -290,7 +290,7 @@ BOOL LLVOAvatarSelf::buildMenus() // object_selected_and_point_valid); item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first); - gAttachPieMenu->append(item); + gAttachPieMenu->addChild(item); attachment_found = TRUE; break; @@ -306,7 +306,7 @@ BOOL LLVOAvatarSelf::buildMenus() if (!attachment_found) { - gAttachPieMenu->appendSeparator(); + gAttachPieMenu->addSeparator(); } } @@ -324,7 +324,7 @@ BOOL LLVOAvatarSelf::buildMenus() LLViewerJointAttachment* attachment = iter->second; if (attachment->getGroup() == i) { - gDetachPieMenu->append(new LLMenuItemCallGL(attachment->getName(), + gDetachPieMenu->addChild(new LLMenuItemCallGL(attachment->getName(), &handle_detach_from_avatar, object_attached, attachment)); attachment_found = TRUE; @@ -334,7 +334,7 @@ BOOL LLVOAvatarSelf::buildMenus() if (!attachment_found) { - gDetachPieMenu->appendSeparator(); + gDetachPieMenu->addSeparator(); } } } @@ -358,8 +358,8 @@ BOOL LLVOAvatarSelf::buildMenus() // NULL, // object_selected_and_point_valid); item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first); - gAttachScreenPieMenu->append(item); - gDetachScreenPieMenu->append(new LLMenuItemCallGL(attachment->getName(), + gAttachScreenPieMenu->addChild(item); + gDetachScreenPieMenu->addChild(new LLMenuItemCallGL(attachment->getName(), &handle_detach_from_avatar, object_attached, attachment)); } } @@ -387,17 +387,17 @@ BOOL LLVOAvatarSelf::buildMenus() NULL, &object_selected_and_point_valid, &attach_label, attachment); item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first); - gAttachSubMenu->append(item); + gAttachSubMenu->addChild(item); - gDetachSubMenu->append(new LLMenuItemCallGL(attachment->getName(), + gDetachSubMenu->addChild(new LLMenuItemCallGL(attachment->getName(), &handle_detach_from_avatar, object_attached, &detach_label, attachment)); } if (pass == 0) { // put separator between non-hud and hud attachments - gAttachSubMenu->appendSeparator(); - gDetachSubMenu->appendSeparator(); + gAttachSubMenu->addSeparator(); + gDetachSubMenu->addSeparator(); } } @@ -434,8 +434,8 @@ BOOL LLVOAvatarSelf::buildMenus() S32 attach_index = attach_it->second; while (cur_pie_slice < requested_pie_slice) { - gAttachBodyPartPieMenus[group]->appendSeparator(); - gDetachBodyPartPieMenus[group]->appendSeparator(); + gAttachBodyPartPieMenus[group]->addSeparator(); + gDetachBodyPartPieMenus[group]->addSeparator(); cur_pie_slice++; } @@ -449,9 +449,9 @@ BOOL LLVOAvatarSelf::buildMenus() // [/RLVa:KB] // LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(), // NULL, object_selected_and_point_valid); - gAttachBodyPartPieMenus[group]->append(item); + gAttachBodyPartPieMenus[group]->addChild(item); item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index); - gDetachBodyPartPieMenus[group]->append(new LLMenuItemCallGL(attachment->getName(), + gDetachBodyPartPieMenus[group]->addChild(new LLMenuItemCallGL(attachment->getName(), &handle_detach_from_avatar, object_attached, attachment)); cur_pie_slice++; diff --git a/indra/newview/skins/default/xui/en-us/floater_inventory.xml b/indra/newview/skins/default/xui/en-us/floater_inventory.xml index 4c56c695b..0571d8518 100644 --- a/indra/newview/skins/default/xui/en-us/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/floater_inventory.xml @@ -58,8 +58,8 @@ left_delta="0" mouse_opaque="true" name="Worn Items" sort_order="WornItemsSortOrder" width="461" /> - + From bdeead6f8e1281f93248c0faeca3091af50a8624 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 21 Feb 2012 21:59:22 -0600 Subject: [PATCH 08/32] Updated LLView: -Removed a few extra unneeded virtuals -Pulled tabgroups out of llpanel and into LLView -removeChild doesn't support delete. Delete manually. -addChildAtEnd renamed to addChildInBack -getScreenRect renamed to calcScreenRect -added calcScreenBoundingRect and calcBoundingRect(which updateBoundingRect calls -General cleanup. Someone at LL figured out that dynamic_cast actually exists. Fixed PieMenu not reliably centering on cursor. Fixed context menu crash in line and text editors. Classes with LLEditMenuHandler as a base do not need to set gEditMenuHandler to NULL, since LLEditMenuHandler's dtor does that already! --- indra/llui/llfloater.cpp | 6 +- indra/llui/lllineeditor.cpp | 247 ++++++++++--------- indra/llui/lllineeditor.h | 11 +- indra/llui/llmenugl.cpp | 89 +++---- indra/llui/llpanel.cpp | 27 +-- indra/llui/llpanel.h | 9 +- indra/llui/llscrollingpanellist.cpp | 2 +- indra/llui/llscrolllistctrl.cpp | 5 - indra/llui/lltexteditor.cpp | 11 +- indra/llui/llview.cpp | 301 +++++++++++++----------- indra/llui/llview.h | 35 ++- indra/newview/dohexeditor.cpp | 4 - indra/newview/floatersculptpreview.cpp | 2 +- indra/newview/llcolorswatch.cpp | 4 +- indra/newview/llfloatercustomize.cpp | 3 +- indra/newview/llfloaterimagepreview.cpp | 2 +- indra/newview/llfloaterstats.cpp | 2 +- indra/newview/llgroupnotify.cpp | 2 +- indra/newview/llpanelavatar.cpp | 2 +- indra/newview/llpanelgroupgeneral.cpp | 3 +- indra/newview/llpanelgroupnotices.cpp | 3 +- indra/newview/llpanelgrouproles.cpp | 9 +- indra/newview/llpanellogin.cpp | 2 +- indra/newview/llpreviewtexture.cpp | 2 +- indra/newview/llstatview.cpp | 4 +- indra/newview/lltexturectrl.cpp | 4 +- indra/newview/lltoolbar.cpp | 2 +- indra/newview/llviewermedia.cpp | 5 - indra/newview/llviewerwindow.cpp | 2 +- 29 files changed, 404 insertions(+), 396 deletions(-) diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 560873acc..b5b8e1df8 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1568,10 +1568,12 @@ void LLFloater::setCanResize(BOOL can_resize) { for (S32 i = 0; i < 4; i++) { - removeChild(mResizeBar[i], TRUE); + removeChild(mResizeBar[i]); + delete mResizeBar[i]; mResizeBar[i] = NULL; - removeChild(mResizeHandle[i], TRUE); + removeChild(mResizeHandle[i]); + delete mResizeHandle[i]; mResizeHandle[i] = NULL; } } diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 98f2e7311..f54d2c761 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -104,7 +104,6 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, : LLUICtrl( name, rect, TRUE, commit_callback, userdata, FOLLOWS_TOP | FOLLOWS_LEFT ), mMaxLengthBytes(max_length_bytes), - mPopupMenuHandle(), mCursorPos( 0 ), mScrollHPos( 0 ), mTextPadLeft(0), @@ -140,7 +139,8 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, mHaveHistory(FALSE), mImage( sImage ), mReplaceNewlinesWithSpaces( TRUE ), - mSpellCheckable( FALSE ) + mSpellCheckable( FALSE ), + mContextMenuHandle() { llassert( max_length_bytes > 0 ); @@ -195,26 +195,21 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); menu->setCanTearOff(FALSE); menu->setVisible(FALSE); - mPopupMenuHandle = menu->getHandle(); + setContextMenu(menu); } - - + LLLineEditor::~LLLineEditor() { mCommitOnFocusLost = FALSE; + // calls onCommit() while LLLineEditor still valid gFocusMgr.releaseFocusIfNeeded( this ); - - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } - LLView::deleteViewByHandle(mPopupMenuHandle); } void LLLineEditor::onFocusReceived() { + gEditMenuHandler = this; LLUICtrl::onFocusReceived(); updateAllowingLanguageInput(); } @@ -646,105 +641,6 @@ BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask) return TRUE; } - -BOOL LLLineEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) -{ - setFocus(TRUE); - - //setCursorAtLocalPos( x); - S32 wordStart = 0; - S32 wordLen = 0; - S32 pos = calculateCursorFromMouse(x); - - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if (menu) - { - if(menu->isOpen()) - { - menu->setVisible(FALSE); - } - for (int i = 0;i<(int)suggestionMenuItems.size();i++) - { - SpellMenuBind * tempBind = suggestionMenuItems[i]; - if(tempBind) - { - menu->removeChild((LLMenuItemCallGL *)tempBind->menuItem); - ((LLMenuItemCallGL *)tempBind->menuItem)->die(); - //delete tempBind->menuItem; - //tempBind->menuItem = NULL; - delete tempBind; - } - } - suggestionMenuItems.clear(); - - // spell_check="true" in xui - menu->setItemVisible("Spelsep", !mReadOnly && mSpellCheckable); - if (!mReadOnly && mSpellCheckable) - { - // search for word matches - bool is_word_part = getWordBoundriesAt(pos, &wordStart, &wordLen); - if (is_word_part) - { - const LLWString& text = mText.getWString(); - std::string selectedWord(std::string(text.begin(), text.end()).substr(wordStart,wordLen)); - - if (!glggHunSpell->isSpelledRight(selectedWord)) - { - //misspelled word here, and you have just right clicked on it! - std::vector suggs = glggHunSpell->getSuggestionList(selectedWord); - - for (int i = 0; i<(int)suggs.size() ;i++) - { - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - tempStruct->word = suggs[i]; - tempStruct->wordPositionEnd = wordStart + wordLen; - tempStruct->wordPositionStart=wordStart; - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - tempStruct->word, spell_correct, NULL, tempStruct); - //new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); - } - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - tempStruct->word = selectedWord; - tempStruct->wordPositionEnd = wordStart + wordLen; - tempStruct->wordPositionStart=wordStart; - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - "Add Word", spell_add, NULL, tempStruct); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); - } - } - - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - if (glggHunSpell->getSpellCheckHighlight()) - { - tempStruct->word = "Hide Misspellings"; - } - else - { - tempStruct->word = "Show Misspellings"; - } - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - tempStruct->word, spell_show, NULL, tempStruct); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); - } - - mLastContextMenuX = x; - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); - } - return TRUE; -} - BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask) { // Check first whether the "clear search" button wants to deal with this. @@ -836,6 +732,16 @@ BOOL LLLineEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) return TRUE; } +BOOL LLLineEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + setFocus(TRUE); + if (!LLUICtrl::handleRightMouseDown(x, y, mask)) + { + showContextMenu(x, y); + } + return TRUE; +} + BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; @@ -1616,7 +1522,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) // SL-51858: Key presses are not being passed to the Popup menu. // A proper fix is non-trivial so instead just close the menu. - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); if (menu && menu->isOpen()) { LLMenuGL::sMenuContainer->hideMenus(); @@ -1698,7 +1604,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) { // SL-51858: Key presses are not being passed to the Popup menu. // A proper fix is non-trivial so instead just close the menu. - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); if (menu && menu->isOpen()) { LLMenuGL::sMenuContainer->hideMenus(); @@ -2061,7 +1967,7 @@ void LLLineEditor::draw() // Make sure the IME is in the right place S32 pixels_after_scroll = findPixelNearestPos(); // RCalculcate for IME position - LLRect screen_pos = getScreenRect(); + LLRect screen_pos = calcScreenRect(); LLCoordGL ime_pos( screen_pos.mLeft + pixels_after_scroll, screen_pos.mTop - UI_LINEEDITOR_V_PAD ); ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]); @@ -3070,6 +2976,121 @@ LLWString LLLineEditor::getConvertedText() const return text; } +void LLLineEditor::showContextMenu(S32 x, S32 y) +{ + LLMenuGL* menu = static_cast(mContextMenuHandle.get()); + + if (menu) + { + gEditMenuHandler = this; + + /*S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + menu->show(screen_x, screen_y);*/ + + + //setCursorAtLocalPos( x); + S32 wordStart = 0; + S32 wordLen = 0; + S32 pos = calculateCursorFromMouse(x); + + LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); + if (menu) + { + if(menu->isOpen()) + { + menu->setVisible(FALSE); + } + for (int i = 0;i<(int)suggestionMenuItems.size();i++) + { + SpellMenuBind * tempBind = suggestionMenuItems[i]; + if(tempBind) + { + menu->removeChild((LLMenuItemCallGL *)tempBind->menuItem); + ((LLMenuItemCallGL *)tempBind->menuItem)->die(); + //delete tempBind->menuItem; + //tempBind->menuItem = NULL; + delete tempBind; + } + } + suggestionMenuItems.clear(); + + // spell_check="true" in xui + menu->setItemVisible("Spelsep", !mReadOnly && mSpellCheckable); + if (!mReadOnly && mSpellCheckable) + { + // search for word matches + bool is_word_part = getWordBoundriesAt(pos, &wordStart, &wordLen); + if (is_word_part) + { + const LLWString& text = mText.getWString(); + std::string selectedWord(std::string(text.begin(), text.end()).substr(wordStart,wordLen)); + + if (!glggHunSpell->isSpelledRight(selectedWord)) + { + //misspelled word here, and you have just right clicked on it! + std::vector suggs = glggHunSpell->getSuggestionList(selectedWord); + + for (int i = 0; i<(int)suggs.size() ;i++) + { + SpellMenuBind * tempStruct = new SpellMenuBind; + tempStruct->origin = this; + tempStruct->word = suggs[i]; + tempStruct->wordPositionEnd = wordStart + wordLen; + tempStruct->wordPositionStart=wordStart; + LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( + tempStruct->word, spell_correct, NULL, tempStruct); + //new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); + tempStruct->menuItem = suggMenuItem; + suggestionMenuItems.push_back(tempStruct); + menu->addChild(suggMenuItem); + } + SpellMenuBind * tempStruct = new SpellMenuBind; + tempStruct->origin = this; + tempStruct->word = selectedWord; + tempStruct->wordPositionEnd = wordStart + wordLen; + tempStruct->wordPositionStart=wordStart; + LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( + "Add Word", spell_add, NULL, tempStruct); + tempStruct->menuItem = suggMenuItem; + suggestionMenuItems.push_back(tempStruct); + menu->addChild(suggMenuItem); + } + } + + SpellMenuBind * tempStruct = new SpellMenuBind; + tempStruct->origin = this; + if (glggHunSpell->getSpellCheckHighlight()) + { + tempStruct->word = "Hide Misspellings"; + } + else + { + tempStruct->word = "Show Misspellings"; + } + LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( + tempStruct->word, spell_show, NULL, tempStruct); + tempStruct->menuItem = suggMenuItem; + suggestionMenuItems.push_back(tempStruct); + menu->addChild(suggMenuItem); + } + + mLastContextMenuX = x; + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); + } + } +} + +void LLLineEditor::setContextMenu(LLMenuGL* new_context_menu) +{ + if (new_context_menu) + mContextMenuHandle = new_context_menu->getHandle(); + else + mContextMenuHandle.markDead(); +} + static LLRegisterWidget r2("search_editor"); diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 6c6ca2884..280fafbca 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -56,6 +56,7 @@ class LLFontGL; class LLLineEditorRollback; class LLButton; +class LLMenuGL; typedef BOOL (*LLLinePrevalidateFunc)(const LLWString &wstr); @@ -79,6 +80,9 @@ public: LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE, S32 border_thickness = 1); +protected: + void showContextMenu(S32 x, S32 y); +public: virtual ~LLLineEditor(); virtual LLXMLNodePtr getXML(bool save_children = true) const; @@ -252,7 +256,9 @@ public: void updateHistory(); // stores current line in history void setReplaceNewlinesWithSpaces(BOOL replace); - + + void setContextMenu(LLMenuGL* new_context_menu); + private: // private helper methods @@ -285,7 +291,6 @@ private: virtual S32 getPreeditFontSize() const; protected: - LLHandle mPopupMenuHandle; LLUIString mText; // The string being edited. std::string mPrevText; // Saved string for 'ESC' revert LLUIString mLabel; // text label that is visible when no user text provided @@ -359,6 +364,8 @@ protected: std::vector mPreeditPositions; LLPreeditor::standouts_t mPreeditStandouts; + LLHandle mContextMenuHandle; + private: // Utility on top of LLUI::getUIImage, looks up a named image in a given XML node and returns it if possible // or returns a given default image if anything in the process fails. diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 048c7c9b2..6b04cb91c 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1699,7 +1699,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask) { BOOL menu_open = getBranch()->getVisible(); // don't do keyboard navigation of top-level menus unless in keyboard mode, or menu expanded - if (getHighlight() && getMenu()->getVisible() && (isActive() || LLMenuGL::getKeyboardMode())) + if (getHighlight() && getMenu()->isOpen() && (isActive() || LLMenuGL::getKeyboardMode())) { if (key == KEY_LEFT) { @@ -3314,6 +3314,9 @@ protected: LLPieMenu* mBranch; }; +const F32 PIE_MENU_WIDTH = 190; +const F32 PIE_MENU_HEIGHT = 190; + LLPieMenuBranch::LLPieMenuBranch(const std::string& name, const std::string& label, LLPieMenu* branch) @@ -3396,6 +3399,7 @@ LLPieMenu::LLPieMenu(const std::string& name, const std::string& label) mCurRadius(0.f), mRightMouseDown(FALSE) { + setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0)); LLMenuGL::setVisible(FALSE); } @@ -3410,6 +3414,7 @@ LLPieMenu::LLPieMenu(const std::string& name) mCurRadius(0.f), mRightMouseDown(FALSE) { + setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0)); LLMenuGL::setVisible(FALSE); } @@ -3836,9 +3841,6 @@ BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu) // virtual void LLPieMenu::arrange() { - const S32 rect_height = 190; - const S32 rect_width = 190; - // all divide by 6 const S32 CARD_X = 60; const S32 DIAG_X = 48; @@ -3848,8 +3850,6 @@ void LLPieMenu::arrange() const S32 ITEM_CENTER_X[] = { CARD_X, DIAG_X, 0, -DIAG_X, -CARD_X, -DIAG_X, 0, DIAG_X }; const S32 ITEM_CENTER_Y[] = { 0, DIAG_Y, CARD_Y, DIAG_Y, 0, -DIAG_Y, -CARD_Y, -DIAG_Y }; - LLRect rect; - S32 font_height = 0; if( mItems.size() ) { @@ -3862,8 +3862,7 @@ void LLPieMenu::arrange() // TODO: Compute actual bounding rect for menu - // HACK: casting away const. Should use setRect or some helper function instead. - const_cast(getRect()).setOriginAndSize(getRect().mLeft, getRect().mBottom, rect_width, rect_height ); + LLRect rect = getRect(); // place items around a circle, with item 0 at positive X, // rotating counter-clockwise @@ -3881,7 +3880,7 @@ void LLPieMenu::arrange() item_width, font_height ); // Correct for the actual rectangle size - rect.translate( rect_width/2, rect_height/2 ); + rect.translate( getRect().getWidth()/2, getRect().getHeight()/2 ); item->setRect( rect ); @@ -3979,62 +3978,38 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down) const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); LLView* parent_view = getParent(); - BOOL moved = FALSE; S32 local_x, local_y; parent_view->screenPointToLocal(x, y, &local_x, &local_y); - // HACK: casting away const. Should use setRect or some helper function instead. - const_cast(getRect()).setCenterAndSize(local_x, local_y, width, height); + LLRect rect; + rect.setCenterAndSize(local_x, local_y, width, height); + setRect(rect); + arrange(); // Adjust the pie rectangle to keep it on screen - if (getRect().mLeft < menu_region_rect.mLeft) + if(!menu_region_rect.contains(rect)) { - //mShiftHoriz = menu_region_rect.mLeft - getRect().mLeft; - //getRect().translate( mShiftHoriz, 0 ); - // HACK: casting away const. Should use setRect or some helper function instead. - const_cast(getRect()).translate( menu_region_rect.mLeft - getRect().mLeft, 0 ); - moved = TRUE; - } - - if (getRect().mRight > menu_region_rect.mRight) - { - //mShiftHoriz = menu_region_rect.mRight - getRect().mRight; - //getRect().translate( mShiftHoriz, 0); - // HACK: casting away const. Should use setRect or some helper function instead. - const_cast(getRect()).translate( menu_region_rect.mRight - getRect().mRight, 0 ); - moved = TRUE; - } - - if (getRect().mBottom < menu_region_rect.mBottom) - { - //mShiftVert = menu_region_rect.mBottom - getRect().mBottom; - //getRect().translate( 0, mShiftVert ); - // HACK: casting away const. Should use setRect or some helper function instead. - const_cast(getRect()).translate( 0, menu_region_rect.mBottom - getRect().mBottom ); - moved = TRUE; - } - - - if (getRect().mTop > menu_region_rect.mTop) - { - //mShiftVert = menu_region_rect.mTop - getRect().mTop; - //getRect().translate( 0, mShiftVert ); - // HACK: casting away const. Should use setRect or some helper function instead. - const_cast(getRect()).translate( 0, menu_region_rect.mTop - getRect().mTop ); - moved = TRUE; - } - - // If we had to relocate the pie menu, put the cursor in the - // center of its rectangle - if (moved) - { - LLCoordGL center; - center.mX = (getRect().mLeft + getRect().mRight) / 2; - center.mY = (getRect().mTop + getRect().mBottom) / 2; - - LLUI::setMousePositionLocal(getParent(), center.mX, center.mY); + S32 trans[2]={0,0}; + if (rect.mLeft < menu_region_rect.mLeft) + { + trans[0] = menu_region_rect.mLeft - rect.mLeft; + } + else if (rect.mRight > menu_region_rect.mRight) + { + trans[0] = menu_region_rect.mRight - rect.mRight; + } + if (rect.mBottom < menu_region_rect.mBottom) + { + trans[1] = menu_region_rect.mBottom - rect.mBottom; + } + else if (rect.mTop > menu_region_rect.mTop) + { + trans[1] = menu_region_rect.mTop - rect.mTop; + } + setRect(rect.translate(trans[0],trans[1])); + LLUI::setMousePositionLocal(getParent(),rect.getCenterX(), rect.getCenterY()); } // *FIX: what happens when mouse buttons reversed? diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index ea8b72ba9..af0dc47c1 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -79,7 +79,6 @@ void LLPanel::init() mBorder = NULL; mDefaultBtn = NULL; setIsChrome(FALSE); //is this a decorator to a live window or a form? - mLastTabGroup = 0; mPanelHandle.bind(this); setTabStop(FALSE); @@ -269,20 +268,6 @@ void LLPanel::setDefaultBtn(const std::string& id) } } -void LLPanel::addCtrl( LLUICtrl* ctrl, S32 tab_group) -{ - mLastTabGroup = tab_group; - - LLView::addCtrl(ctrl, tab_group); -} - -void LLPanel::addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group) -{ - mLastTabGroup = tab_group; - - LLView::addCtrlAtEnd(ctrl, tab_group); -} - BOOL LLPanel::handleKeyHere( KEY key, MASK mask ) { BOOL handled = FALSE; @@ -1189,9 +1174,13 @@ void LLLayoutStack::draw() } } -void LLLayoutStack::removeCtrl(LLUICtrl* ctrl) +void LLLayoutStack::removeChild(LLView* ctrl) { - LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel((LLPanel*)ctrl); + LLView::removeChild(ctrl); + LLPanel* panel = dynamic_cast(ctrl); + if(!panel) + return; + LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel(panel); if (embedded_panelp) { @@ -1200,10 +1189,8 @@ void LLLayoutStack::removeCtrl(LLUICtrl* ctrl) } // need to update resizebars - + calcMinExtents(); - - LLView::removeCtrl(ctrl); } LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 317efbc40..bb16b6e02 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -138,8 +138,6 @@ public: LLHandle getHandle() const { return mPanelHandle; } - S32 getLastTabGroup() const { return mLastTabGroup; } - const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; } BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); @@ -235,10 +233,6 @@ private: // common construction logic void init(); - // From LLView - virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group ); - virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group); - // Unified error reporting for the child* functions typedef std::set expected_members_list_t; mutable expected_members_list_t mExpectedMembers; @@ -253,7 +247,6 @@ private: LLViewBorder* mBorder; LLButton* mDefaultBtn; std::string mLabel; - S32 mLastTabGroup; LLRootHandle mPanelHandle; typedef std::map ui_string_map_t; @@ -278,7 +271,7 @@ public: /*virtual*/ void draw(); /*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const; - /*virtual*/ void removeCtrl(LLUICtrl* ctrl); + /*virtual*/ void removeChild(LLView* ctrl); static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp index c2afb78f7..8aa8b9fe3 100644 --- a/indra/llui/llscrollingpanellist.cpp +++ b/indra/llui/llscrollingpanellist.cpp @@ -52,7 +52,7 @@ void LLScrollingPanelList::clearPanels() void LLScrollingPanelList::addPanel( LLScrollingPanel* panel ) { - addChildAtEnd( panel ); + addChildInBack( panel ); mPanelList.push_front( panel ); const S32 GAP_BETWEEN_PANELS = 6; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 01c3a4731..bf480990f 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -745,11 +745,6 @@ S32 LLScrollListCtrl::getSearchColumn() LLScrollListCtrl::~LLScrollListCtrl() { std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); - - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } } diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index bc6d176c5..fc877ba59 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -372,18 +372,12 @@ LLTextEditor::~LLTextEditor() { gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } - // Scrollbar is deleted by LLView mHoverSegment = NULL; std::for_each(mSegments.begin(), mSegments.end(), DeletePointer()); std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - LLView::deleteViewByHandle(mPopupMenuHandle); + //LLView::deleteViewByHandle(mPopupMenuHandle); } void LLTextEditor::context_cut(void* data) { @@ -1461,6 +1455,7 @@ BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) mLastContextMenuX = x; mLastContextMenuY = y; menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); } return TRUE; @@ -3245,7 +3240,7 @@ void LLTextEditor::drawCursor() } // Make sure the IME is in the right place - LLRect screen_pos = getScreenRect(); + LLRect screen_pos = calcScreenRect(); LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_left), screen_pos.mBottom + llfloor(cursor_top) ); ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 49974d339..b1a730c73 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -81,7 +81,9 @@ S32 LLView::sLastBottomXML = S32_MIN; BOOL LLView::sIsDrawing = FALSE; #endif -LLView::LLView() : +LLView::LLView() +: mVisible(TRUE), + mInDraw(false), mParentView(NULL), mReshapeFlags(FOLLOWS_NONE), mDefaultTabGroup(0), @@ -92,18 +94,20 @@ LLView::LLView() : mIsFocusRoot(FALSE), mLastVisible(TRUE), mUseBoundingRect(FALSE), - mVisible(TRUE), mNextInsertionOrdinal(0), mHoverCursor(UI_CURSOR_ARROW), + mLastTabGroup(0), // mDelayedDelete(FALSE) // { } -LLView::LLView(const std::string& name, BOOL mouse_opaque) : - mParentView(NULL), +LLView::LLView(const std::string& name, BOOL mouse_opaque) +: mVisible(TRUE), + mInDraw(false), mName(name), + mParentView(NULL), mReshapeFlags(FOLLOWS_NONE), mDefaultTabGroup(0), mEnabled(TRUE), @@ -113,9 +117,9 @@ LLView::LLView(const std::string& name, BOOL mouse_opaque) : mIsFocusRoot(FALSE), mLastVisible(TRUE), mUseBoundingRect(FALSE), - mVisible(TRUE), mNextInsertionOrdinal(0), mHoverCursor(UI_CURSOR_ARROW), + mLastTabGroup(0), // mDelayedDelete(FALSE) // @@ -124,9 +128,11 @@ LLView::LLView(const std::string& name, BOOL mouse_opaque) : LLView::LLView( - const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) : - mParentView(NULL), + const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) +: mVisible(TRUE), + mInDraw(false), mName(name), + mParentView(NULL), mRect(rect), mBoundingRect(rect), mReshapeFlags(reshape), @@ -138,9 +144,9 @@ LLView::LLView( mIsFocusRoot(FALSE), mLastVisible(TRUE), mUseBoundingRect(FALSE), - mVisible(TRUE), mNextInsertionOrdinal(0), mHoverCursor(UI_CURSOR_ARROW), + mLastTabGroup(0), // mDelayedDelete(FALSE) // @@ -234,7 +240,7 @@ void LLView::setUseBoundingRect( BOOL use_bounding_rect ) } } -BOOL LLView::getUseBoundingRect() +BOOL LLView::getUseBoundingRect() const { return mUseBoundingRect; } @@ -263,6 +269,7 @@ void LLView::sendChildToFront(LLView* child) void LLView::sendChildToBack(LLView* child) { +// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs if (child && child->getParent() == this) { // minor optimization, but more importantly, @@ -291,16 +298,18 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child) } } -void LLView::addChild(LLView* child, S32 tab_group) +// virtual +bool LLView::addChild(LLView* child, S32 tab_group) { if (!child) { - return; + return false; } if (mParentView == child) { llerrs << "Adding view " << child->getName() << " as child of itself" << llendl; } + // remove from current parent if (child->mParentView) { @@ -313,86 +322,57 @@ void LLView::addChild(LLView* child, S32 tab_group) // add to ctrl list if is LLUICtrl if (child->isCtrl()) { - // controls are stored in reverse order from render order - addCtrlAtEnd((LLUICtrl*) child, tab_group); + LLUICtrl* ctrl = static_cast(child); + mCtrlOrder.insert(tab_order_pair_t(ctrl, + tab_order_t(tab_group, mNextInsertionOrdinal))); + + mNextInsertionOrdinal++; } child->mParentView = this; updateBoundingRect(); + mLastTabGroup = tab_group; + return true; } -void LLView::addChildAtEnd(LLView* child, S32 tab_group) +bool LLView::addChildInBack(LLView* child, S32 tab_group) { - if (mParentView == child) + if(addChild(child, tab_group)) { - llerrs << "Adding view " << child->getName() << " as child of itself" << llendl; - } - // remove from current parent - if (child->mParentView) - { - child->mParentView->removeChild(child); + sendChildToBack(child); + return true; } - // add to back of child list - mChildList.push_back(child); - - // add to ctrl list if is LLUICtrl - if (child->isCtrl()) - { - // controls are stored in reverse order from render order - addCtrl((LLUICtrl*) child, tab_group); - } - - child->mParentView = this; - updateBoundingRect(); + return false; } // remove the specified child from the view, and set it's parent to NULL. -void LLView::removeChild(LLView* child, BOOL deleteIt) +void LLView::removeChild(LLView* child) { + //llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs if (child->mParentView == this) { + // if we are removing an item we are currently iterating over, that would be bad + llassert(child->mInDraw == false); mChildList.remove( child ); child->mParentView = NULL; if (child->isCtrl()) { - removeCtrl((LLUICtrl*)child); - } - if (deleteIt) - { - delete child; + child_tab_order_t::iterator found = mCtrlOrder.find(static_cast(child)); + if(found != mCtrlOrder.end()) + { + mCtrlOrder.erase(found); + } } } else { - llerrs << "LLView::removeChild called with non-child" << llendl; + llwarns << child->getName() << "is not a child of " << getName() << llendl; } updateBoundingRect(); } -void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group) -{ - mCtrlOrder.insert(tab_order_pair_t(ctrl, - tab_order_t(tab_group, mNextInsertionOrdinal++))); -} - -void LLView::addCtrl( LLUICtrl* ctrl, S32 tab_group) -{ - // add to front of list by using negative ordinal, which monotonically increases - mCtrlOrder.insert(tab_order_pair_t(ctrl, - tab_order_t(tab_group, -1 * mNextInsertionOrdinal++))); -} - -void LLView::removeCtrl(LLUICtrl* ctrl) -{ - child_tab_order_t::iterator found = mCtrlOrder.find(ctrl); - if(found != mCtrlOrder.end()) - { - mCtrlOrder.erase(found); - } -} - LLView::ctrl_list_t LLView::getCtrlList() const { ctrl_list_t controls; @@ -1325,56 +1305,72 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask) void LLView::draw() { - if (sDebugRects) - { - drawDebugRect(); + drawChildren(); +} - // Check for bogus rectangle - if (getRect().mRight <= getRect().mLeft - || getRect().mTop <= getRect().mBottom) - { - llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl; - } - } - - LLRect rootRect = getRootView()->getRect(); - LLRect screenRect; +void LLView::drawChildren() +{ // draw focused control on top of everything else - LLUICtrl* focus_view = dynamic_cast(gFocusMgr.getKeyboardFocus()); + /*LLUICtrl* focus_view = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (focus_view && focus_view->getParent() != this) { focus_view = NULL; - } - - ++sDepth; - for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) + }*/ + if (!mChildList.empty()) { - LLView *viewp = *child_iter; + LLView* rootp = getRootView(); + ++sDepth; - if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid()) + for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) { - // Only draw views that are within the root view - localRectToScreen(viewp->getRect(),&screenRect); - if ( rootRect.overlaps(screenRect) ) - { - gGL.matrixMode(LLRender::MM_MODELVIEW); - LLUI::pushMatrix(); + child_list_reverse_iter_t child = child_iter++; + LLView *viewp = *child; + + if (viewp == NULL) { - LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); - viewp->draw(); + continue; + } + + + if (viewp->getVisible() && /*viewp != focus_view && */viewp->getRect().isValid()) + { + // Only draw views that are within the root view + LLRect screen_rect = viewp->calcScreenRect(); + if ( rootp->getLocalRect().overlaps(screen_rect) ) + { + //gGL.matrixMode(LLRender::MM_MODELVIEW); + LLUI::pushMatrix(); + { + LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); + // flag the fact we are in draw here, in case overridden draw() method attempts to remove this widget + viewp->mInDraw = true; + viewp->draw(); + viewp->mInDraw = false; + + if (sDebugRects) + { + viewp->drawDebugRect(); + + // Check for bogus rectangle + if (!getRect().isValid()) + { + llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl; + } + } + } + LLUI::popMatrix(); } - LLUI::popMatrix(); } + } - + --sDepth; } - --sDepth; - if (focus_view && focus_view->getVisible()) + /*if (focus_view && focus_view->getVisible()) { drawChild(focus_view); - } + }*/ // HACK if (sEditingUI && this == sEditingUIView) @@ -1391,12 +1387,12 @@ void LLView::drawDebugRect() // drawing solids requires texturing be disabled gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (mUseBoundingRect) + if (getUseBoundingRect()) { LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f); } - LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect; + LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect; // draw red rectangle for the border LLColor4 border_color(0.f, 0.f, 0.f, 1.f); @@ -1539,43 +1535,51 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent) updateBoundingRect(); } -void LLView::updateBoundingRect() +LLRect LLView::calcBoundingRect() { - if (isDead()) return; - - if (mUseBoundingRect) - { - LLRect local_bounding_rect = LLRect::null; + LLRect local_bounding_rect = LLRect::null; BOOST_FOREACH(LLView* childp, mChildList) { // ignore invisible and "top" children when calculating bounding rect - // such as combobox popups - if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl()) - { - continue; - } - - LLRect child_bounding_rect = childp->getBoundingRect(); - - if (local_bounding_rect.isEmpty()) - { - // start out with bounding rect equal to first visible child's bounding rect - local_bounding_rect = child_bounding_rect; - } - else - { - // accumulate non-null children rectangles - if (child_bounding_rect.notEmpty()) - { - local_bounding_rect.unionWith(child_bounding_rect); - } - } + // such as combobox popups + if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl()) + { + continue; } - mBoundingRect = local_bounding_rect; - // translate into parent-relative coordinates - mBoundingRect.translate(mRect.mLeft, mRect.mBottom); + LLRect child_bounding_rect = childp->getBoundingRect(); + + if (local_bounding_rect.isEmpty()) + { + // start out with bounding rect equal to first visible child's bounding rect + local_bounding_rect = child_bounding_rect; + } + else + { + // accumulate non-null children rectangles + if (!child_bounding_rect.isEmpty()) + { + local_bounding_rect.unionWith(child_bounding_rect); + } + } + } + + // convert to parent-relative coordinates + local_bounding_rect.translate(mRect.mLeft, mRect.mBottom); + return local_bounding_rect; +} + + +void LLView::updateBoundingRect() +{ + if (isDead()) return; + + LLRect cur_rect = mBoundingRect; + + if (getUseBoundingRect()) + { + mBoundingRect = calcBoundingRect(); } else { @@ -1583,21 +1587,40 @@ void LLView::updateBoundingRect() } // give parent view a chance to resize, in case we just moved, for example - if (getParent() && getParent()->mUseBoundingRect) + if (getParent() && getParent()->getUseBoundingRect()) { getParent()->updateBoundingRect(); } + + /*if (mBoundingRect != cur_rect) + { + dirtyRect(); + }*/ + } -LLRect LLView::getScreenRect() const +LLRect LLView::calcScreenRect() const { - // *FIX: check for one-off error LLRect screen_rect; localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom); localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop); return screen_rect; } +LLRect LLView::calcScreenBoundingRect() const +{ + LLRect screen_rect; + // get bounding rect, if used + LLRect bounding_rect = getUseBoundingRect() ? mBoundingRect : mRect; + + // convert to local coordinates, as defined by mRect + bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); + + localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom); + localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop); + return screen_rect; +} + LLRect LLView::getLocalBoundingRect() const { LLRect local_bounding_rect = getBoundingRect(); @@ -1644,15 +1667,19 @@ BOOL LLView::hasAncestor(const LLView* parentp) const BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const { - LLView *child = getChildView(childname, TRUE, FALSE); - if (child) + LLView *focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + + while (focus != NULL) { - return gFocusMgr.childHasKeyboardFocus(child); - } - else - { - return FALSE; + if (focus->getName() == childname) + { + return TRUE; + } + + focus = focus->getParent(); } + + return FALSE; } //----------------------------------------------------------------------------- diff --git a/indra/llui/llview.h b/indra/llui/llview.h index f376d56c5..acde9bf22 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -294,7 +294,7 @@ public: void setSoundFlags(U8 flags) { mSoundFlags = flags; } void setName(std::string name) { mName = name; } void setUseBoundingRect( BOOL use_bounding_rect ); - BOOL getUseBoundingRect(); + BOOL getUseBoundingRect() const; const std::string& getToolTip() const { return mToolTipMsg.getString(); } @@ -302,15 +302,14 @@ public: void sendChildToBack(LLView* child); void moveChildToFrontOfTabGroup(LLUICtrl* child); void moveChildToBackOfTabGroup(LLUICtrl* child); + + virtual bool addChild(LLView* view, S32 tab_group = 0); + + // implemented in terms of addChild() + bool addChildInBack(LLView* view, S32 tab_group = 0); - void addChild(LLView* view, S32 tab_group = 0); - void addChildAtEnd(LLView* view, S32 tab_group = 0); // remove the specified child from the view, and set it's parent to NULL. - void removeChild(LLView* view, BOOL deleteIt = FALSE); - - virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group); - virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group); - virtual void removeCtrl( LLUICtrl* ctrl); + virtual void removeChild(LLView* view); child_tab_order_t getCtrlOrder() const { return mCtrlOrder; } ctrl_list_t getCtrlList() const; @@ -318,6 +317,7 @@ public: void setDefaultTabGroup(S32 d) { mDefaultTabGroup = d; } S32 getDefaultTabGroup() const { return mDefaultTabGroup; } + S32 getLastTabGroup() { return mLastTabGroup; } BOOL isInVisibleChain() const; BOOL isInEnabledChain() const; @@ -336,14 +336,14 @@ public: void setAllChildrenEnabled(BOOL b); virtual void setVisible(BOOL visible); - BOOL getVisible() const { return mVisible; } + const BOOL& getVisible() const { return mVisible; } virtual void setEnabled(BOOL enabled); BOOL getEnabled() const { return mEnabled; } U8 getSoundFlags() const { return mSoundFlags; } virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - virtual void handleVisibilityChange ( BOOL curVisibilityIn ); + virtual void handleVisibilityChange ( BOOL new_visibility ); void pushVisible(BOOL visible) { mLastVisible = mVisible; setVisible(visible); } void popVisible() { setVisible(mLastVisible); } @@ -361,13 +361,15 @@ public: const LLRect& getRect() const { return mRect; } const LLRect& getBoundingRect() const { return mBoundingRect; } LLRect getLocalBoundingRect() const; - LLRect getScreenRect() const; + LLRect calcScreenRect() const; + LLRect calcScreenBoundingRect() const; LLRect getLocalRect() const; virtual LLRect getSnapRect() const; LLRect getLocalSnapRect() const; // Override and return required size for this object. 0 for width/height means don't care. virtual LLRect getRequiredRect(); + LLRect calcBoundingRect(); void updateBoundingRect(); LLView* getRootView(); @@ -469,6 +471,8 @@ public: virtual LLSD getValue() const; const child_list_t* getChildList() const { return &mChildList; } + child_list_const_iter_t beginChild() const { return mChildList.begin(); } + child_list_const_iter_t endChild() const { return mChildList.end(); } // LLMouseHandler functions // Default behavior is to pass events to children @@ -602,6 +606,7 @@ protected: void drawDebugRect(); void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE); + void drawChildren(); LLView* childrenHandleKey(KEY key, MASK mask); LLView* childrenHandleUnicodeChar(llwchar uni_char); @@ -631,15 +636,18 @@ private: LLView* mParentView; child_list_t mChildList; - std::string mName; // location in pixels, relative to surrounding structure, bottom,left=0,0 + BOOL mVisible; LLRect mRect; LLRect mBoundingRect; + + std::string mName; U32 mReshapeFlags; child_tab_order_t mCtrlOrder; S32 mDefaultTabGroup; + S32 mLastTabGroup; BOOL mEnabled; // Enabled means "accepts input that has an effect on the state of the application." // A disabled view, for example, may still have a scrollbar that responds to mouse events. @@ -655,10 +663,11 @@ private: LLRootHandle mHandle; BOOL mLastVisible; - BOOL mVisible; + S32 mNextInsertionOrdinal; + bool mInDraw; // public: BOOL mDelayedDelete; diff --git a/indra/newview/dohexeditor.cpp b/indra/newview/dohexeditor.cpp index 071ff7d88..ce0b91bdd 100644 --- a/indra/newview/dohexeditor.cpp +++ b/indra/newview/dohexeditor.cpp @@ -81,10 +81,6 @@ DOHexEditor::DOHexEditor(const std::string& name, const LLRect& rect) DOHexEditor::~DOHexEditor() { gFocusMgr.releaseFocusIfNeeded(this); - if(gEditMenuHandler == this) - { - gEditMenuHandler = NULL; - } } LLView* DOHexEditor::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory) diff --git a/indra/newview/floatersculptpreview.cpp b/indra/newview/floatersculptpreview.cpp index 09356154d..cc8706e5c 100644 --- a/indra/newview/floatersculptpreview.cpp +++ b/indra/newview/floatersculptpreview.cpp @@ -259,7 +259,7 @@ void LLFloaterSculptPreview::draw() if (selected <= 0) { - gl_rect_2d_checkerboard(getScreenRect(),mPreviewRect); + gl_rect_2d_checkerboard(calcScreenRect(),mPreviewRect); LLGLDisable gls_alpha(GL_ALPHA_TEST); if(mImagep.notNull()) diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp index 2ba89a29a..8b349c9cc 100644 --- a/indra/newview/llcolorswatch.cpp +++ b/indra/newview/llcolorswatch.cpp @@ -218,7 +218,7 @@ void LLColorSwatchCtrl::draw() if ( mValid ) { // Draw the color swatch - gl_rect_2d_checkerboard( getScreenRect(), interior ); + gl_rect_2d_checkerboard( calcScreenRect(), interior ); gl_rect_2d(interior, mColor, TRUE); LLColor4 opaque_color = mColor; opaque_color.mV[VALPHA] = 1.f; @@ -239,7 +239,7 @@ void LLColorSwatchCtrl::draw() LLPointer fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName); if( fallback_image->getComponents() == 4 ) { - gl_rect_2d_checkerboard( getScreenRect(), interior ); + gl_rect_2d_checkerboard( calcScreenRect(), interior ); } gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), fallback_image); fallback_image->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 35c2a902e..93afcea06 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -1398,7 +1398,8 @@ LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, } for (it = to_remove.begin(); it != to_remove.end(); it++) { - removeChild(*it, TRUE); + removeChild(*it); + delete (*it); } slider->translate(0,PARAM_HINT_HEIGHT); reshape(getRect().getWidth(),getRect().getHeight()-PARAM_HINT_HEIGHT); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 67c20c91d..9ac2f29ba 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -264,7 +264,7 @@ void LLFloaterImagePreview::draw() if (selected <= 0) { - gl_rect_2d_checkerboard( getScreenRect(), mPreviewRect); + gl_rect_2d_checkerboard( calcScreenRect(), mPreviewRect); LLGLDisable gls_alpha(GL_ALPHA_TEST); if(mImagep.notNull()) diff --git a/indra/newview/llfloaterstats.cpp b/indra/newview/llfloaterstats.cpp index 4d8fd7099..459aa3585 100644 --- a/indra/newview/llfloaterstats.cpp +++ b/indra/newview/llfloaterstats.cpp @@ -602,7 +602,7 @@ void LLFloaterStats::reshape(S32 width, S32 height, BOOL called_from_parent) void LLFloaterStats::addStatView(LLStatView* stat) { - mStatsContainer->addChildAtEnd(stat); + mStatsContainer->addChildInBack(stat); } // virtual diff --git a/indra/newview/llgroupnotify.cpp b/indra/newview/llgroupnotify.cpp index 3eabf6df1..24ff0408e 100644 --- a/indra/newview/llgroupnotify.cpp +++ b/indra/newview/llgroupnotify.cpp @@ -417,7 +417,7 @@ void LLGroupNotifyBox::moveToBack() { // Move this dialog to the back. gNotifyBoxView->removeChild(this); - gNotifyBoxView->addChildAtEnd(this); + gNotifyBoxView->addChildInBack(this); mNextBtn->setVisible(FALSE); // And enable the next button on the frontmost one, if there is one diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index dd3e21c85..69857de55 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -587,7 +587,7 @@ void LLPanelAvatarSecondLife::onClickPartnerInfo(void *data) if (self->mPartnerID.notNull()) { LLFloaterAvatarInfo::showFromProfile(self->mPartnerID, - self->getScreenRect()); + self->calcScreenRect()); } } diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 6aa23b24e..11d7b80bb 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -150,7 +150,8 @@ BOOL LLPanelGroupGeneral::postBuild() if (founder) { mFounderName = new LLNameBox(founder->getName(),founder->getRect(),LLUUID::null,FALSE,founder->getFont(),founder->getMouseOpaque()); - removeChild(founder, TRUE); + removeChild(founder); + delete founder; addChild(mFounderName); } diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index bde9aa848..83a4c1a75 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -278,7 +278,8 @@ BOOL LLPanelGroupNotices::postBuild() target->setToolTip(dtv->getToolTip()); mPanelCreateNotice->addChild(target); - mPanelCreateNotice->removeChild(dtv, TRUE); + mPanelCreateNotice->removeChild(dtv); + delete dtv; arrangeNoticeView(VIEW_PAST_NOTICE); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index e044a163d..5f5e8c9ec 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -521,21 +521,24 @@ BOOL LLPanelGroupSubTab::postBuild() if (icon && !icon->getImageName().empty()) { mActionIcons["folder"] = icon->getImageName(); - removeChild(icon, TRUE); + removeChild(icon); + delete icon; } icon = getChild("power_all_have_icon",no_recurse); if (icon && !icon->getImageName().empty()) { mActionIcons["full"] = icon->getImageName(); - removeChild(icon, TRUE); + removeChild(icon); + delete icon; } icon = getChild("power_partial_icon",no_recurse); if (icon && !icon->getImageName().empty()) { mActionIcons["partial"] = icon->getImageName(); - removeChild(icon, TRUE); + removeChild(icon); + delete icon; } return LLPanelGroupTab::postBuild(); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index dcb5d75f3..949cbe9b8 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -247,7 +247,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLPanelLogin::sInstance = this; // add to front so we are the bottom-most child - gViewerWindow->getRootView()->addChildAtEnd(this); + gViewerWindow->getRootView()->addChildInBack(this); // Logo mLogoImage = LLUI::getUIImage("startup_logo.j2c"); diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index d714b7444..97c929956 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -269,7 +269,7 @@ void LLPreviewTexture::draw() // ...border gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f)); - gl_rect_2d_checkerboard( getScreenRect(), interior ); + gl_rect_2d_checkerboard( calcScreenRect(), interior ); if ( mImage.notNull() ) { diff --git a/indra/newview/llstatview.cpp b/indra/newview/llstatview.cpp index 9a3fcffff..17c4dcca2 100644 --- a/indra/newview/llstatview.cpp +++ b/indra/newview/llstatview.cpp @@ -86,7 +86,7 @@ LLStatBar *LLStatView::addStat(const std::string& name, LLStat *statp, stat_barp->mStatp = statp; stat_barp->setVisible(mDisplayChildren); - addChildAtEnd(stat_barp); + addChildInBack(stat_barp); mStatBars.push_back(stat_barp); // Rearrange all child bars. @@ -98,7 +98,7 @@ LLStatView *LLStatView::addStatView(const std::string& name, const std::string& { LLStatView *statview = new LLStatView(name, label, setting, rect); statview->setVisible(mDisplayChildren); - addChildAtEnd(statview); + addChildInBack(statview); return statview; } diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 1662af54e..61e045361 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -650,7 +650,7 @@ void LLFloaterTexturePicker::draw() { if( mTexturep->getComponents() == 4 ) { - gl_rect_2d_checkerboard( getScreenRect(), interior ); + gl_rect_2d_checkerboard( calcScreenRect(), interior ); } gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep ); @@ -1528,7 +1528,7 @@ void LLTextureCtrl::draw() { if( mTexturep->getComponents() == 4 ) { - gl_rect_2d_checkerboard( getScreenRect(), interior ); + gl_rect_2d_checkerboard( calcScreenRect(), interior ); } gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep); diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp index becb8baf4..93d39fe5a 100644 --- a/indra/newview/lltoolbar.cpp +++ b/indra/newview/lltoolbar.cpp @@ -176,7 +176,7 @@ BOOL LLToolBar::postBuild() { LLRect rect(0, 0, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT); mResizeHandle = new LLFakeResizeHandle(std::string(""), rect, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT); - this->addChildAtEnd(mResizeHandle); + this->addChildInBack(mResizeHandle); LLLayoutStack* toolbar_stack = getChild("toolbar_stack"); toolbar_stack->reshape(toolbar_stack->getRect().getWidth() - RESIZE_HANDLE_WIDTH, toolbar_stack->getRect().getHeight()); } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 911813104..727e19578 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -317,11 +317,6 @@ LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, ////////////////////////////////////////////////////////////////////////////////////////// LLViewerMediaImpl::~LLViewerMediaImpl() { - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } - destroyMediaSource(); LLViewerMedia::removeMedia(this); } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5267c32e8..1c93eefae 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1945,7 +1945,7 @@ void LLViewerWindow::initWorldUI() } gHUDView = new LLHUDView(hud_rect); // put behind everything else in the UI - mRootView->addChildAtEnd(gHUDView); + mRootView->addChildInBack(gHUDView); } } From c2da7f4570ab6e9d8b34d4f73a02b54b571a0180 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 22 Feb 2012 00:09:52 -0600 Subject: [PATCH 09/32] Fixed translations failing attachment text. (support 'value' attribute for strings starting with a space) --- indra/llui/lltrans.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index 8fb40e5d6..780d204bf 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -72,7 +72,11 @@ bool LLTrans::parseStrings(const std::string& xml_filename, const std::setgetTextContents()); + std::string contents; + //value is used for strings with preceeding spaces. If not present, fall back to getTextContents() + if(!string->getAttributeString("value",contents)) + contents=string->getTextContents(); + LLTransTemplate xml_template(string_name, contents); sStringTemplates[xml_template.mName] = xml_template; std::set::const_iterator iter = default_args.find(xml_template.mName); From 3d39e443fe626051db5dc4b5d87f2b6f20e9d8e5 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 22 Feb 2012 17:51:06 -0600 Subject: [PATCH 10/32] Append username to window title upon connecting to grid. --- indra/llwindow/llwindow.h | 2 ++ indra/llwindow/llwindowmacosx.cpp | 9 +++++++++ indra/llwindow/llwindowmacosx.h | 2 ++ indra/llwindow/llwindowsdl.cpp | 5 +++++ indra/llwindow/llwindowsdl.h | 2 ++ indra/llwindow/llwindowwin32.cpp | 8 ++++++++ indra/llwindow/llwindowwin32.h | 2 ++ indra/newview/llstartup.cpp | 6 ++++++ 8 files changed, 36 insertions(+) diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index a15332e2f..48264ef47 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -171,6 +171,8 @@ public: // Provide native key event data virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } + virtual void setTitle(const std::string &title){}; + protected: LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); virtual ~LLWindow(); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 34f52701a..e83425a79 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -3272,6 +3272,15 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) } } +void LLWindowMacOSX::setTitle(const std::string &title) +{ + /*strncpy((char*)mWindowTitle + 1, title.c_str(), 253); + mWindowTitle[0] = title.length();*/ + + CFStringRef title_str = CFStringCreateWithCString(NULL, title.c_str(), kCFStringEncodingUTF8); + SetWindowTitleWithCFString(mWindow, title_str); +} + LLSD LLWindowMacOSX::getNativeKeyData() { LLSD result = LLSD::emptyMap(); diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 504b446d1..3096a0aec 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -118,6 +118,8 @@ public: /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + /*virtual*/ void setTitle(const std::string &title); + static std::vector getDynamicFallbackFontList(); // Provide native key event data diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index d600df17f..b87cb21a7 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -2514,6 +2514,11 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) llinfos << "spawn_web_browser returning." << llendl; } +void LLWindowSDL::setTitle(const std::string &title) +{ + mWindowTitle = title; + SDL_WM_SetCaption(mWindowTitle.c_str(),mWindowTitle.c_str()); +} void *LLWindowSDL::getPlatformWindow() { diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index a6b9ff4f9..4fbe89b5e 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -127,6 +127,8 @@ public: /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + /*virtual*/ void setTitle(const std::string &title); + static std::vector getDynamicFallbackFontList(); // Not great that these are public, but they have to be accessible diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index d73fb3a0a..8fecd08d3 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3140,6 +3140,14 @@ void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) ShellExecuteEx( &sei ); } +void LLWindowWin32::setTitle(const std::string &title) +{ + mbstowcs(mWindowTitle, title.c_str(), 255); + mWindowTitle[255] = 0; + + SetWindowText(mWindowHandle, mWindowTitle); +} + /* Make the raw keyboard data available - used to poke through to LLQtWebKit so that Qt/Webkit has access to the virtual keycodes etc. that it needs diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 9343593f6..fefe5d308 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -117,6 +117,8 @@ public: void ShellEx(const std::string& command); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + /*virtual*/ void setTitle(const std::string &title); + LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); static std::vector getDynamicFallbackFontList(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 7372023e0..9ebce0906 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1886,6 +1886,12 @@ bool idle_startup() // OGPX : Inventory root might be null in OGP. // && gAgent.mInventoryRootID.notNull()) { + std::string name = firstname; + std::string last_name = lastname; + LLStringUtil::toLower(last_name); + if(last_name != "resident") + name += " " + lastname; + gViewerWindow->getWindow()->setTitle(LLAppViewer::instance()->getWindowTitle() + "- " + name); LLStartUp::setStartupState( STATE_WORLD_INIT ); } else From 323ec8cf59ede9db6eda688e9d578fd78f37f7e8 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 23 Feb 2012 04:00:09 -0600 Subject: [PATCH 11/32] Updated customize floater to work with layer 0 wearable, for now. --- indra/newview/llfloatercolorpicker.cpp | 6 + indra/newview/llfloatercustomize.cpp | 511 ++++++++++--------------- indra/newview/llfolderview.cpp | 3 +- indra/newview/lltexlayer.cpp | 1 + 4 files changed, 219 insertions(+), 302 deletions(-) diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index 717922394..f9d782cc2 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -645,6 +645,12 @@ void LLFloaterColorPicker::draw() startX + mLumMarkerSize, startY + mLumMarkerSize, LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ), TRUE ); + // draw a white marker inside the black marker to be visible with dark or bright ui. + gl_triangle_2d ( startX+2, startY, + startX + mLumMarkerSize - 1, startY - mLumMarkerSize + 2, + startX + mLumMarkerSize - 1, startY + mLumMarkerSize - 2, + LLColor4 ( 1.0f, 1.0f, 1.0f, 1.0f ), TRUE ); + // draw luminance slider outline gl_rect_2d ( mLumRegionLeft, mLumRegionTop - mLumRegionHeight + 1, diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 93afcea06..a66037db8 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -421,8 +421,12 @@ enum ESubpart { struct LLSubpart { - LLSubpart() : mSex( SEX_BOTH ), mVisualHint(true) {} - + LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, const ESex sex=SEX_BOTH, bool visual_hint=true ) + : mSex( sex ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) + {} + LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, bool visual_hint) + : mSex( SEX_BOTH ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) + {} std::string mButtonName; std::string mTargetJoint; std::string mEditGroup; @@ -741,14 +745,11 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) { - if (gAgentWearables.getWearable(mType, 0)) // TODO: MULTI-WEARABLE + const LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE + if(wearable) { - LLVOAvatar *avatar = gAgentAvatarp; - if (avatar) - { - const LLTextureEntry* current_te = avatar->getTE(te); - return (current_te && current_te->getID() == IMG_INVISIBLE); - } + const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); + return (lto && lto->getID() == IMG_INVISIBLE); } return false; } @@ -775,14 +776,24 @@ void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) bool new_invis_state = checkbox_ctrl->get(); if (new_invis_state) { - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); - const LLTextureEntry* current_te = gAgentAvatarp->getTE(te); - if (current_te) + + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); + + LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE + const LLLocalTextureObject* lto = wearable ? wearable->getLocalTextureObject(te) : NULL; + + if(lto) { - self->mPreviousTextureList[(S32)te] = current_te->getID(); + self->mPreviousTextureList[(S32)te] = lto->getID(); } - gAgentAvatarp->setLocalTextureTE(te,image, 0); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); + if(wearable) + { + LLLocalTextureObject new_lto(image, IMG_INVISIBLE); + wearable->setLocalTextureObject(te, new_lto); + wearable->writeToAvatar(); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); + } + } else { @@ -794,9 +805,15 @@ void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) } if (prev_id.notNull()) { - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); - gAgentAvatarp->setLocalTextureTE(te, image, 0); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); + LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE + if(wearable) + { + LLLocalTextureObject new_lto(image, prev_id); + wearable->setLocalTextureObject(te, new_lto); + wearable->writeToAvatar(); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); + } } } @@ -821,15 +838,19 @@ void LLPanelEditWearable::onColorCommit( LLUICtrl* ctrl, void* userdata ) { ETextureIndex te = (ETextureIndex)cl_itr->second; - LLColor4 old_color = gAgentAvatarp->getClothesColor( te ); + LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE + if(!wearable) + return; + + LLColor4 old_color = wearable->getClothesColor( te ); const LLColor4& new_color = color_ctrl->get(); if( old_color != new_color ) { // Set the new version - gAgentAvatarp->setClothesColor( te, new_color, TRUE ); - - LLVisualParamHint::requestHintUpdates(); + wearable->setClothesColor(te, new_color, TRUE); + wearable->writeToAvatar(); gAgentAvatarp->wearableUpdated(self->mType, FALSE); + LLVisualParamHint::requestHintUpdates(); } } } @@ -851,10 +872,15 @@ void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te) { return; } - const LLTextureEntry* current_te = avatar->getTE(te); - if (current_te) + + LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE + if(!wearable) + return; + + const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); + if (lto) { - mPreviousTextureList[te] = current_te->getID(); + mPreviousTextureList[te] = lto->getID(); } } @@ -878,10 +904,10 @@ void LLPanelEditWearable::addTextureDropTarget( ETextureIndex te, const std::str LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE if (wearable && mType == LLWearableType::WT_ALPHA) { - const LLTextureEntry* current_te = avatar->getTE(te); - if (current_te) + const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); + if (lto) { - mPreviousTextureList[te] = current_te->getID(); + mPreviousTextureList[te] = lto->getID(); } } } @@ -898,15 +924,19 @@ void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) ETextureIndex te = (ETextureIndex)(self->mTextureList[ctrl->getName()]); // Set the new version - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( texture_ctrl->getImageAssetID() ); + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( texture_ctrl->getImageAssetID() ); if (image->getID().isNull()) { image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); } self->mTextureList[ctrl->getName()] = te; - if (gAgentWearables.getWearable(self->mType, 0)) // TODO: MULTI-WEARABLE + + LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE + if (wearable) { - gAgentAvatarp->setLocalTextureTE(te, image, 0); + LLLocalTextureObject lto(image, texture_ctrl->getImageAssetID()); + wearable->setLocalTextureObject(te, lto); + wearable->writeToAvatar(); gAgentAvatarp->wearableUpdated(self->mType, FALSE); } if (self->mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) @@ -1066,13 +1096,14 @@ void LLPanelEditWearable::draw() childSetVisible(name, is_copyable && is_modifiable && is_complete ); if (texture_ctrl) { - const LLTextureEntry* te = avatar->getTE(te_index); + + const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te_index); LLUUID new_id; - if( te && (te->getID() != IMG_DEFAULT_AVATAR) ) + if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) { - new_id = te->getID(); + new_id = lto->getID(); } else { @@ -1091,17 +1122,22 @@ void LLPanelEditWearable::draw() } } - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) + LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE + + if(wearable) { - std::string name = iter->first; - S32 te_index = iter->second; - childSetVisible(name, is_modifiable && is_complete ); - childSetEnabled(name, is_modifiable && is_complete ); - LLColorSwatchCtrl* ctrl = getChild(name); - if (ctrl) + for( std::map::iterator iter = mColorList.begin(); + iter != mColorList.end(); ++iter ) { - ctrl->set(avatar->getClothesColor( (ETextureIndex)te_index ) ); + std::string name = iter->first; + S32 te_index = iter->second; + childSetVisible(name, is_modifiable && is_complete ); + childSetEnabled(name, is_modifiable && is_complete ); + LLColorSwatchCtrl* ctrl = getChild(name); + if (ctrl) + { + ctrl->set( wearable->getClothesColor(te_index ) ); + } } } @@ -1229,19 +1265,29 @@ void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata ) return; } + LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE + if(!wearable) + { + return; + } + ESex new_sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE; - LLViewerVisualParam* param = (LLViewerVisualParam*)avatar->getVisualParam( "male" ); + LLVisualParam* param = avatar->getVisualParam( "male" ); if( !param ) { return; } - param->setWeight( (new_sex == SEX_MALE), TRUE ); + wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); + wearable->writeToAvatar(); + avatar->updateVisualParams(); + + /*param->setWeight( (new_sex == SEX_MALE), TRUE ); avatar->updateSexDependentLayerSets( TRUE ); - avatar->updateVisualParams(); + avatar->updateVisualParams();*/ gFloaterCustomize->clearScrollingPanelList(); @@ -1525,12 +1571,21 @@ void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata) LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; LLViewerVisualParam* param = self->mParam; - F32 current_weight = gAgentAvatarp->getVisualParamWeight( param ); + if(!param) + return; + + LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)param->getWearableType(), 0 ); // TODO: MULTI-WEARABLE + + if(!wearable) + return; + + F32 current_weight = wearable->getVisualParamWeight(param->getID()); F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); if (current_weight != new_weight ) { updateAvatarHeightDisplay(); - gAgentAvatarp->setVisualParamWeight( param, new_weight, FALSE); + wearable->setVisualParamWeight( param->getID(), new_weight, FALSE); + wearable->writeToAvatar(); gAgentAvatarp->updateVisualParams(); } } @@ -1592,7 +1647,14 @@ void LLScrollingPanelParam::onHintMaxHeldDown( void* userdata ) void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) { - F32 current_weight = gAgentAvatarp->getVisualParamWeight( hint->getVisualParam() ); + LLViewerVisualParam* param = hint->getVisualParam(); + + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE + + if(!wearable) + return; + + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); if (current_weight != hint->getVisualParamWeight() ) { @@ -1619,7 +1681,8 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - gAgentAvatarp->setVisualParamWeight( hint->getVisualParam(), new_weight, TRUE); + wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); + wearable->writeToAvatar(); gAgentAvatarp->updateVisualParams(); slider->setValue( weightToPercent( new_weight ) ); @@ -1642,20 +1705,27 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata ) if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) { - // step in direction - F32 current_weight = gAgentAvatarp->getVisualParamWeight( hint->getVisualParam() ); - F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); - // step a fraction in the negative directiona - F32 new_weight = current_weight - (range / 10.f); - F32 new_percent = self->weightToPercent(new_weight); - LLSliderCtrl* slider = self->getChild("param slider"); - if (slider) + LLViewerVisualParam* param = hint->getVisualParam(); + + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE + if(wearable) { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) + // step in direction + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); + // step a fraction in the negative direction + F32 new_weight = current_weight - (range / 10.f); + F32 new_percent = self->weightToPercent(new_weight); + LLSliderCtrl* slider = self->getChild("param slider"); + if (slider) { - avatar->setVisualParamWeight(hint->getVisualParam(), new_weight, TRUE); - slider->setValue( self->weightToPercent( new_weight ) ); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); + wearable->writeToAvatar(); + slider->setValue( self->weightToPercent( new_weight ) ); + } } } } @@ -1677,20 +1747,27 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata ) if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) { - // step in direction - F32 current_weight = gAgentAvatarp->getVisualParamWeight( hint->getVisualParam() ); - F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); - // step a fraction in the negative direction - F32 new_weight = current_weight + (range / 10.f); - F32 new_percent = self->weightToPercent(new_weight); - LLSliderCtrl* slider = self->getChild("param slider"); - if (slider) + LLViewerVisualParam* param = hint->getVisualParam(); + + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); + if(wearable) { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) + // step in direction + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); + // step a fraction in the negative direction + F32 new_weight = current_weight + (range / 10.f); + F32 new_percent = self->weightToPercent(new_weight); + LLSliderCtrl* slider = self->getChild("param slider"); + if (slider) { - avatar->setVisualParamWeight(hint->getVisualParam(), new_weight, TRUE); - slider->setValue( self->weightToPercent( new_weight ) ); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); + wearable->writeToAvatar(); + slider->setValue( self->weightToPercent( new_weight ) ); + } } } } @@ -1748,22 +1825,16 @@ LLFloaterCustomize::LLFloaterCustomize() gInventory.addObserver(mInventoryObserver); LLCallbackMap::map_t factory_map; - factory_map["Shape"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_SHAPE) ) ); - factory_map["Skin"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_SKIN) ) ); - factory_map["Hair"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_HAIR) ) ); - factory_map["Eyes"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_EYES) ) ); - factory_map["Shirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_SHIRT) ) ); - factory_map["Pants"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_PANTS) ) ); - factory_map["Shoes"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_SHOES) ) ); - factory_map["Socks"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_SOCKS) ) ); - factory_map["Jacket"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_JACKET) ) ); - factory_map["Gloves"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_GLOVES) ) ); - factory_map["Undershirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_UNDERSHIRT) ) ); - factory_map["Underpants"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_UNDERPANTS) ) ); - factory_map["Skirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_SKIRT) ) ); - factory_map["Alpha"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_ALPHA))); - factory_map["Tattoo"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_TATTOO))); - factory_map["Physics"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, LLWearableType::WT_PHYSICS))); + const std::string &invalid_name = LLWearableType::getTypeName(LLWearableType::WT_INVALID); + for(U32 type=LLWearableType::WT_SHAPE;typebuildFloater(this, "floater_customize.xml", &factory_map); } @@ -1782,22 +1853,16 @@ BOOL LLFloaterCustomize::postBuild() initWearablePanels(); // Tab container - childSetTabChangeCallback("customize tab container", "Shape", onTabChanged, (void*)LLWearableType::WT_SHAPE, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Skin", onTabChanged, (void*)LLWearableType::WT_SKIN, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Hair", onTabChanged, (void*)LLWearableType::WT_HAIR, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Eyes", onTabChanged, (void*)LLWearableType::WT_EYES, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Shirt", onTabChanged, (void*)LLWearableType::WT_SHIRT, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Pants", onTabChanged, (void*)LLWearableType::WT_PANTS, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Shoes", onTabChanged, (void*)LLWearableType::WT_SHOES, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Socks", onTabChanged, (void*)LLWearableType::WT_SOCKS, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Jacket", onTabChanged, (void*)LLWearableType::WT_JACKET, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Gloves", onTabChanged, (void*)LLWearableType::WT_GLOVES, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Undershirt", onTabChanged, (void*)LLWearableType::WT_UNDERSHIRT, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Underpants", onTabChanged, (void*)LLWearableType::WT_UNDERPANTS, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Skirt", onTabChanged, (void*)LLWearableType::WT_SKIRT, onTabPrecommit ); - childSetTabChangeCallback("customize tab container", "Alpha", onTabChanged, (void*)LLWearableType::WT_ALPHA, onTabPrecommit); - childSetTabChangeCallback("customize tab container", "Tattoo", onTabChanged, (void*)LLWearableType::WT_TATTOO, onTabPrecommit); - childSetTabChangeCallback("customize tab container", "Physics", onTabChanged, (void*)LLWearableType::WT_PHYSICS, onTabPrecommit); + const std::string &invalid_name = LLWearableType::getTypeName(LLWearableType::WT_INVALID); + for(U32 type=LLWearableType::WT_SHAPE;typemTargetJoint = "mPelvis"; - part->mEditGroup = "shape_body"; - part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f); + LLSubpart* part = new LLSubpart("mPelvis", "shape_body", LLVector3d(0.f,0.f,0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); panel->addSubpart( "Body", SUBPART_SHAPE_WHOLE, part ); // head supparts - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "shape_head"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f ); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f ); + const LLVector3d head_target(0.f, 0.f, 0.05f); + const LLVector3d head_camera(-0.5f, 0.05f, 0.07f); + + part = new LLSubpart("mHead", "shape_head", head_target, head_camera); panel->addSubpart( "Head", SUBPART_SHAPE_HEAD, part ); - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "shape_eyes"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f ); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f ); + part = new LLSubpart("mHead", "shape_eyes", head_target, head_camera); panel->addSubpart( "Eyes", SUBPART_SHAPE_EYES, part ); - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "shape_ears"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f ); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f ); + part = new LLSubpart("mHead", "shape_ears", head_target, head_camera); panel->addSubpart( "Ears", SUBPART_SHAPE_EARS, part ); - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "shape_nose"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f ); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f ); + part = new LLSubpart("mHead", "shape_nose", head_target, head_camera); panel->addSubpart( "Nose", SUBPART_SHAPE_NOSE, part ); - - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "shape_mouth"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f ); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f ); + part = new LLSubpart("mHead", "shape_mouth", head_target, head_camera); panel->addSubpart( "Mouth", SUBPART_SHAPE_MOUTH, part ); - - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "shape_chin"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f ); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f ); + part = new LLSubpart("mHead", "shape_chin", head_target, head_camera); panel->addSubpart( "Chin", SUBPART_SHAPE_CHIN, part ); // torso - part = new LLSubpart(); - part->mTargetJoint = "mTorso"; - part->mEditGroup = "shape_torso"; - part->mTargetOffset.setVec(0.f, 0.f, 0.3f); - part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f); + part = new LLSubpart("mTorso", "shape_torso", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); panel->addSubpart( "Torso", SUBPART_SHAPE_TORSO, part ); // legs - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "shape_legs"; - part->mTargetOffset.setVec(0.f, 0.f, -0.5f); - part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f); + part = new LLSubpart("mPelvis", "shape_legs", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); panel->addSubpart( "Legs", SUBPART_SHAPE_LEGS, part ); panel->childSetCommitCallback("sex radio", LLPanelEditWearable::onCommitSexChange, panel); @@ -2147,32 +2175,16 @@ void LLFloaterCustomize::initWearablePanels() // Skin panel = mWearablePanelList[ LLWearableType::WT_SKIN ]; - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "skin_color"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f); + part = new LLSubpart("mHead", "skin_color", head_target, head_camera); panel->addSubpart( "Skin Color", SUBPART_SKIN_COLOR, part ); - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "skin_facedetail"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f); + part = new LLSubpart("mHead", "skin_facedetail", head_target, head_camera); panel->addSubpart( "Face Detail", SUBPART_SKIN_FACEDETAIL, part ); - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "skin_makeup"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f); + part = new LLSubpart("mHead", "skin_makeup", head_target, head_camera); panel->addSubpart( "Makeup", SUBPART_SKIN_MAKEUP, part ); - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "skin_bodydetail"; - part->mTargetOffset.setVec(0.f, 0.f, -0.2f); - part->mCameraOffset.setVec(-2.5f, 0.5f, 0.5f); + part = new LLSubpart("mPelvis", "skin_bodydetail", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f)); panel->addSubpart( "Body Detail", SUBPART_SKIN_BODYDETAIL, part ); panel->addTextureDropTarget( TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE ); @@ -2183,33 +2195,16 @@ void LLFloaterCustomize::initWearablePanels() // Hair panel = mWearablePanelList[ LLWearableType::WT_HAIR ]; - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "hair_color"; - part->mTargetOffset.setVec(0.f, 0.f, 0.10f); - part->mCameraOffset.setVec(-0.4f, 0.05f, 0.10f); + part = new LLSubpart("mHead", "hair_color", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f)); panel->addSubpart( "Color", SUBPART_HAIR_COLOR, part ); - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "hair_style"; - part->mTargetOffset.setVec(0.f, 0.f, 0.10f); - part->mCameraOffset.setVec(-0.4f, 0.05f, 0.10f); + part = new LLSubpart("mHead", "hair_style", head_target, head_camera); panel->addSubpart( "Style", SUBPART_HAIR_STYLE, part ); - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "hair_eyebrows"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f); + part = new LLSubpart("mHead", "hair_eyebrows", head_target, head_camera); panel->addSubpart( "Eyebrows", SUBPART_HAIR_EYEBROWS, part ); - part = new LLSubpart(); - part->mSex = SEX_MALE; - part->mTargetJoint = "mHead"; - part->mEditGroup = "hair_facial"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f); + part = new LLSubpart("mHead", "hair_facial", head_target, head_camera, SEX_MALE); panel->addSubpart( "Facial", SUBPART_HAIR_FACIAL, part ); panel->addTextureDropTarget(TEX_HAIR, "Texture", @@ -2220,11 +2215,7 @@ void LLFloaterCustomize::initWearablePanels() // Eyes panel = mWearablePanelList[ LLWearableType::WT_EYES ]; - part = new LLSubpart(); - part->mTargetJoint = "mHead"; - part->mEditGroup = "eyes"; - part->mTargetOffset.setVec(0.f, 0.f, 0.05f); - part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f); + part = new LLSubpart("mHead", "eyes", head_target, head_camera); panel->addSubpart( LLStringUtil::null, SUBPART_EYES, part ); panel->addTextureDropTarget(TEX_EYES_IRIS, "Iris", @@ -2235,11 +2226,7 @@ void LLFloaterCustomize::initWearablePanels() // Shirt panel = mWearablePanelList[ LLWearableType::WT_SHIRT ]; - part = new LLSubpart(); - part->mTargetJoint = "mTorso"; - part->mEditGroup = "shirt"; - part->mTargetOffset.setVec(0.f, 0.f, 0.3f); - part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f); + part = new LLSubpart("mTorso", "shirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); panel->addSubpart( LLStringUtil::null, SUBPART_SHIRT, part ); panel->addTextureDropTarget( TEX_UPPER_SHIRT, "Fabric", @@ -2253,11 +2240,7 @@ void LLFloaterCustomize::initWearablePanels() // Pants panel = mWearablePanelList[ LLWearableType::WT_PANTS ]; - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "pants"; - part->mTargetOffset.setVec(0.f, 0.f, -0.5f); - part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f); + part = new LLSubpart("mPelvis", "pants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); panel->addSubpart( LLStringUtil::null, SUBPART_PANTS, part ); panel->addTextureDropTarget(TEX_LOWER_PANTS, "Fabric", @@ -2273,11 +2256,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "shoes"; - part->mTargetOffset.setVec(0.f, 0.f, -0.5f); - part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f); + part = new LLSubpart("mPelvis", "shoes", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); panel->addSubpart( LLStringUtil::null, SUBPART_SHOES, part ); panel->addTextureDropTarget( TEX_LOWER_SHOES, "Fabric", @@ -2294,11 +2273,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "socks"; - part->mTargetOffset.setVec(0.f, 0.f, -0.5f); - part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f); + part = new LLSubpart("mPelvis", "socks", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); panel->addSubpart( LLStringUtil::null, SUBPART_SOCKS, part ); panel->addTextureDropTarget( TEX_LOWER_SOCKS, "Fabric", @@ -2314,11 +2289,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mTorso"; - part->mEditGroup = "jacket"; - part->mTargetOffset.setVec(0.f, 0.f, 0.f); - part->mCameraOffset.setVec(-2.f, 0.1f, 0.3f); + part = new LLSubpart("mTorso", "jacket", LLVector3d(), LLVector3d(-2.f, 0.1f, 0.3f)); panel->addSubpart( LLStringUtil::null, SUBPART_JACKET, part ); panel->addTextureDropTarget( TEX_UPPER_JACKET, "Upper Fabric", @@ -2337,11 +2308,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "skirt"; - part->mTargetOffset.setVec(0.f, 0.f, -0.5f); - part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f); + part = new LLSubpart("mPelvis", "skirt", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); panel->addSubpart( LLStringUtil::null, SUBPART_SKIRT, part ); panel->addTextureDropTarget( TEX_SKIRT, "Fabric", @@ -2358,11 +2325,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mTorso"; - part->mEditGroup = "gloves"; - part->mTargetOffset.setVec(0.f, 0.f, 0.f); - part->mCameraOffset.setVec(-1.f, 0.15f, 0.f); + part = new LLSubpart("mTorso", "gloves", LLVector3d(), LLVector3d(-1.f, 0.15f, 0.f)); panel->addSubpart( LLStringUtil::null, SUBPART_GLOVES, part ); panel->addTextureDropTarget( TEX_UPPER_GLOVES, "Fabric", @@ -2379,11 +2342,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mTorso"; - part->mEditGroup = "undershirt"; - part->mTargetOffset.setVec(0.f, 0.f, 0.3f); - part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f); + part = new LLSubpart("mTorso", "undershirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); panel->addSubpart( LLStringUtil::null, SUBPART_UNDERSHIRT, part ); panel->addTextureDropTarget( TEX_UPPER_UNDERSHIRT, "Fabric", @@ -2399,11 +2358,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "underpants"; - part->mTargetOffset.setVec(0.f, 0.f, -0.5f); - part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f); + part = new LLSubpart("mPelvis", "underpants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); panel->addSubpart( LLStringUtil::null, SUBPART_UNDERPANTS, part ); panel->addTextureDropTarget( TEX_LOWER_UNDERPANTS, "Fabric", @@ -2419,11 +2374,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "alpha"; - part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f); + part = new LLSubpart("mPelvis", "alpha", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); panel->addSubpart(LLStringUtil::null, SUBPART_ALPHA, part); panel->addTextureDropTarget(TEX_LOWER_ALPHA, "Lower Alpha", @@ -2455,11 +2406,7 @@ void LLFloaterCustomize::initWearablePanels() if (panel) { - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "tattoo"; - part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f); + part = new LLSubpart("mPelvis", "tattoo", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); panel->addSubpart(LLStringUtil::null, SUBPART_TATTOO, part); panel->addTextureDropTarget(TEX_LOWER_TATTOO, "Lower Tattoo", @@ -2481,63 +2428,25 @@ void LLFloaterCustomize::initWearablePanels() if(panel) { - part = new LLSubpart(); - part->mSex = SEX_FEMALE; - part->mTargetJoint = "mTorso"; - part->mEditGroup = "physics_breasts_updown"; - part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); - part->mVisualHint = false; + part = new LLSubpart("mTorso", "physics_breasts_updown", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); panel->addSubpart("Breast Bounce", SUBPART_PHYSICS_BREASTS_UPDOWN, part); - part = new LLSubpart(); - part->mSex = SEX_FEMALE; - part->mTargetJoint = "mTorso"; - part->mEditGroup = "physics_breasts_inout"; - part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); - part->mVisualHint = false; + part = new LLSubpart("mTorso", "physics_breasts_inout", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); panel->addSubpart("Breast Cleavage", SUBPART_PHYSICS_BREASTS_INOUT, part); - part = new LLSubpart(); - part->mSex = SEX_FEMALE; - part->mTargetJoint = "mTorso"; - part->mEditGroup = "physics_breasts_leftright"; - part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); - part->mVisualHint = false; + part = new LLSubpart("mTorso", "physics_breasts_leftright", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); panel->addSubpart("Breast Sway", SUBPART_PHYSICS_BREASTS_LEFTRIGHT, part); - part = new LLSubpart(); - part->mTargetJoint = "mTorso"; - part->mEditGroup = "physics_belly_updown"; - part->mTargetOffset.setVec(0.f, 0.f, -.05f); - part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); - part->mVisualHint = false; + part = new LLSubpart("mTorso", "physics_belly_updown", LLVector3d(0.f, 0.f, -.05f), LLVector3d(-0.8f, 0.15f, 0.38f), false); panel->addSubpart("Belly Bounce", SUBPART_PHYSICS_BELLY_UPDOWN, part); - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "physics_butt_updown"; - part->mTargetOffset.setVec(0.f, 0.f, -0.1f); - part->mCameraOffset.setVec(0.3f, 0.8f, -0.1f); - part->mVisualHint = false; + part = new LLSubpart("mPelvis", "physics_butt_updown", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); panel->addSubpart("Butt Bounce", SUBPART_PHYSICS_BUTT_UPDOWN, part); - part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "physics_butt_leftright"; - part->mTargetOffset.setVec(0.f, 0.f, -0.1f); - part->mCameraOffset.setVec(0.3f, 0.8f, -0.1f); - part->mVisualHint = false; + part = new LLSubpart("mPelvis", "physics_butt_leftright", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); panel->addSubpart("Butt Sway", SUBPART_PHYSICS_BUTT_LEFTRIGHT, part); - part = new LLSubpart(); - part->mTargetJoint = "mTorso"; - part->mEditGroup = "physics_advanced"; - part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f); - part->mVisualHint = false; + part = new LLSubpart("mTorso", "physics_advanced", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), false); panel->addSubpart("Advanced Parameters", SUBPART_PHYSICS_ADVANCED, part); } diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 99855aebe..4c0a8b694 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -2392,7 +2392,8 @@ void LLFolderViewEventListener::arrangeAndSet(LLFolderViewItem* focus, { if(!focus) return; LLFolderView* root = focus->getRoot(); - focus->getParentFolder()->requestArrange(); + if(focus->getParentFolder()) + focus->getParentFolder()->requestArrange(); if(set_selection) { focus->setSelectionFromRoot(focus, TRUE, take_keyboard_focus); diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index b55346c02..911e0f336 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -201,6 +201,7 @@ void LLTexLayerSetBuffer::conditionalRestartUploadTimer() } else { + mNeedsUploadTimer.unpause(); //Isn't always unpaused before this, although it should be.. mNeedsUploadTimer.reset(); mNeedsUploadTimer.start(); } From 5c66c705462c54ee6fd5deb0328671c15d057dc9 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 23 Feb 2012 14:31:43 -0600 Subject: [PATCH 12/32] Display an arrow overlay on item links. --- indra/newview/llbuildnewviewsscheduler.cpp | 2 ++ indra/newview/llfolderview.cpp | 4 ++-- indra/newview/llfolderviewitem.cpp | 15 ++++++++++++++- indra/newview/llfolderviewitem.h | 4 +++- indra/newview/llinventorypanel.cpp | 11 ++++++++++- indra/newview/llpanelobjectinventory.cpp | 3 +++ .../skins/default/textures/inv_link_overlay.tga | Bin 0 -> 231 bytes 7 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 indra/newview/skins/default/textures/inv_link_overlay.tga diff --git a/indra/newview/llbuildnewviewsscheduler.cpp b/indra/newview/llbuildnewviewsscheduler.cpp index aee02f803..541c792e2 100644 --- a/indra/newview/llbuildnewviewsscheduler.cpp +++ b/indra/newview/llbuildnewviewsscheduler.cpp @@ -72,6 +72,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento { LLFolderViewFolder* folderp = new LLFolderViewFolder(new_listener->getDisplayName(), new_listener->getIcon(), + NULL, panelp->getRootFolder(), new_listener); @@ -94,6 +95,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento { itemp = new LLFolderViewItem(new_listener->getDisplayName(), new_listener->getIcon(), + NULL, new_listener->getCreationDate(), panelp->getRootFolder(), new_listener); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 4c0a8b694..52ac8f009 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -196,13 +196,13 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) ///---------------------------------------------------------------------------- // Default constructor -LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, +LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, const LLRect& rect, const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener ) : #if LL_WINDOWS #pragma warning( push ) #pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list #endif - LLFolderViewFolder( name, root_folder_icon, this, listener ), + LLFolderViewFolder( name, root_folder_icon, NULL, this, listener ), #if LL_WINDOWS #pragma warning( pop ) #endif diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 69d7da876..cc280df73 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -75,6 +75,7 @@ void LLFolderViewItem::cleanupClass() // Default constructor // NOTE: Optimize this, we call it a *lot* when opening a large inventory LLFolderViewItem::LLFolderViewItem( const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_overlay, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener ) : @@ -100,6 +101,7 @@ LLFolderViewItem::LLFolderViewItem( const std::string& name, LLUIImagePtr icon, mRoot( root ), mCreationDate(creation_date), mIcon(icon), + mIconOverlay(icon_overlay), mListener(listener) { sFolderViewItems.insert(this); @@ -917,12 +919,22 @@ void LLFolderViewItem::draw() mDragAndDropTarget = FALSE; } + const LLViewerInventoryItem *item = getInventoryItem(); + const BOOL highlight_link = mIconOverlay && item && item->getIsLinkType(); + //--------------------------------------------------------------------------------// + // Draw open icon + // const S32 icon_x = mIndentation + ARROW_SIZE + TEXT_PAD; if (mIcon) { mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); } + if (highlight_link) + { + mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + } + //--------------------------------------------------------------------------------// // Exit if no label to draw // @@ -1032,9 +1044,10 @@ void LLFolderViewItem::draw() // Default constructor LLFolderViewFolder::LLFolderViewFolder( const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_link, LLFolderView* root, LLFolderViewEventListener* listener ): - LLFolderViewItem( name, icon, 0, root, listener ), // 0 = no create time + LLFolderViewItem( name, icon, icon_link, 0, root, listener ), // 0 = no create time mNumDescendantsSelected(0), mIsOpen(FALSE), mExpanderHighlighted(FALSE), diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index a8af1e3b8..657cfda54 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -125,6 +125,7 @@ protected: std::string mLabelSuffix; LLUIImagePtr mIcon; std::string mStatusText; + LLUIImagePtr mIconOverlay; BOOL mHasVisibleChildren; S32 mIndentation; BOOL mPassedFilter; @@ -166,7 +167,7 @@ public: void filterFromRoot( void ); // creation_date is in UTC seconds - LLFolderViewItem( const std::string& name, LLUIImagePtr icon, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener ); + LLFolderViewItem( const std::string& name, LLUIImagePtr icon, LLUIImagePtr icon_overlay, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener ); virtual ~LLFolderViewItem( void ); // addToFolder() returns TRUE if it succeeds. FALSE otherwise @@ -325,6 +326,7 @@ class LLFolderViewFolder : public LLFolderViewItem { protected: LLFolderViewFolder( const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_link, LLFolderView* root, LLFolderViewEventListener* listener ); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 2b7dba47f..7ee2c5714 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -598,7 +598,14 @@ LLFolderView * LLInventoryPanel::createFolderView(LLInvFVBridge * bridge, bool u getRect().getWidth(), 0); - LLFolderView* ret = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this, bridge); + LLFolderView* ret = new LLFolderView( + + getName(), + NULL, + folder_rect, + LLUUID::null, + this, + bridge); ret->setAllowMultiSelect(mAllowMultiSelect); return ret; } @@ -608,6 +615,7 @@ LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * br return new LLFolderViewFolder( bridge->getDisplayName(), bridge->getIcon(), + LLUI::getUIImage("inv_link_overlay.tga"), mFolderRoot, bridge); } @@ -617,6 +625,7 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge return new LLFolderViewItem( bridge->getDisplayName(), bridge->getIcon(), + LLUI::getUIImage("inv_link_overlay.tga"), bridge->getCreationDate(), mFolderRoot, bridge); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 058afb29d..5883d7b60 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1760,6 +1760,7 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root LLFolderViewFolder* new_folder = NULL; new_folder = new LLFolderViewFolder(inventory_root->getName(), bridge->getIcon(), + NULL, mFolders, bridge); new_folder->addToFolder(mFolders, mFolders); @@ -1797,6 +1798,7 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li { view = new LLFolderViewFolder(obj->getName(), bridge->getIcon(), + NULL, mFolders, bridge); child_categories.put(new obj_folder_pair(obj, @@ -1806,6 +1808,7 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li { view = new LLFolderViewItem(obj->getName(), bridge->getIcon(), + NULL, bridge->getCreationDate(), mFolders, bridge); diff --git a/indra/newview/skins/default/textures/inv_link_overlay.tga b/indra/newview/skins/default/textures/inv_link_overlay.tga new file mode 100644 index 0000000000000000000000000000000000000000..4d76eb0613a14a6bd1dec7915aad00c79676fd3c GIT binary patch literal 231 zcmZvW!3uyd3`3(Jh^KvmpSmgP^x~&_^jMqfD55#6?IX Date: Fri, 24 Feb 2012 20:16:33 -0600 Subject: [PATCH 13/32] Added LLInitParam. Not yet plugged into xml parsing. --- indra/CMakeLists.txt | 1 + indra/cmake/LLXUIXML.cmake | 7 + indra/llui/CMakeLists.txt | 5 + indra/llui/lluictrlfactory.h | 1 + indra/llui/llview.cpp | 154 +- indra/llui/llview.h | 155 +- indra/llxuixml/CMakeLists.txt | 40 + indra/llxuixml/llinitparam.cpp | 469 ++++ indra/llxuixml/llinitparam.h | 2294 ++++++++++++++++++++ indra/llxuixml/lluicolor.cpp | 87 + indra/llxuixml/lluicolor.h | 71 + indra/newview/CMakeLists.txt | 3 + indra/newview/llbuildnewviewsscheduler.cpp | 2 +- indra/newview/statemachine/CMakeLists.txt | 2 + 14 files changed, 3128 insertions(+), 163 deletions(-) create mode 100644 indra/cmake/LLXUIXML.cmake create mode 100644 indra/llxuixml/CMakeLists.txt create mode 100644 indra/llxuixml/llinitparam.cpp create mode 100644 indra/llxuixml/llinitparam.h create mode 100644 indra/llxuixml/lluicolor.cpp create mode 100644 indra/llxuixml/lluicolor.h diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 09eade34f..8ba3b5367 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -77,6 +77,7 @@ if (VIEWER) add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) + add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml) # viewer plugins directory add_subdirectory(${LIBS_OPEN_PREFIX}plugins) diff --git a/indra/cmake/LLXUIXML.cmake b/indra/cmake/LLXUIXML.cmake new file mode 100644 index 000000000..b8bfe48c7 --- /dev/null +++ b/indra/cmake/LLXUIXML.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- + +set(LLXUIXML_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/llxuixml + ) + +set(LLXUIXML_LIBRARIES llxuixml) diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 42fa88495..b144f9c3d 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -5,22 +5,26 @@ project(llui) include(00-Common) include(LLCommon) include(LLImage) +include(LLInventory) include(LLMath) include(LLMessage) include(LLRender) include(LLWindow) include(LLVFS) include(LLXML) +include(LLXUIXML) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} + ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LLXUIXML_INCLUDE_DIRS} ) set(llui_SOURCE_FILES @@ -159,6 +163,7 @@ target_link_libraries(llui llwindow llimage llvfs # ugh, just for LLDir + llxuixml llxml llcommon # must be after llimage, llwindow, llrender llmath diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index ef3a97be5..c51778917 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -38,6 +38,7 @@ #include "llcallbackmap.h" #include "llfloater.h" +#include "llinitparam.h" class LLView; class LLPanel; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index a427346ed..abb2cb75a 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -83,76 +83,94 @@ S32 LLView::sLastBottomXML = S32_MIN; BOOL LLView::sIsDrawing = FALSE; #endif -LLView::LLView() -: mVisible(TRUE), - mInDraw(false), - mParentView(NULL), - mReshapeFlags(FOLLOWS_NONE), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(TRUE), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), - mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW), - mLastTabGroup(0), - // - mDelayedDelete(FALSE) - // +LLView::Follows::Follows() +: string(""), + flags("flags", FOLLOWS_NONE) +{} + +LLView::Params::Params() +: name("name", std::string("unnamed")), + enabled("enabled", true), + visible("visible", true), + mouse_opaque("mouse_opaque", true), + follows("follows"), + hover_cursor("hover_cursor", "UI_CURSOR_ARROW"), + use_bounding_rect("use_bounding_rect", false), + tab_group("tab_group", 0), + default_tab_group("default_tab_group"), + //tool_tip("tool_tip"), + sound_flags("sound_flags", MOUSE_UP), + layout("layout"), + rect("rect"), + bottom_delta("bottom_delta", S32_MAX), + top_pad("top_pad"), + top_delta("top_delta", S32_MAX), + left_pad("left_pad"), + left_delta("left_delta", S32_MAX), + from_xui("from_xui", true), + focus_root("focus_root", false), + needs_translate("translate"), + xmlns("xmlns"), + xmlns_xsi("xmlns:xsi"), + xsi_schemaLocation("xsi:schemaLocation"), + xsi_type("xsi:type") + { + addSynonym(rect, ""); +} + +LLView::LLView(const LLView::Params& p) +{ + init(p); +} + +void LLView::init(const LLView::Params& p) +{ + mVisible = p.visible; + mInDraw = false; + mName = p.name; + mParentView = NULL; + mReshapeFlags = FOLLOWS_NONE; + mSaveToXML = p.from_xui; + mIsFocusRoot = p.focus_root; + mLastVisible = FALSE; + mNextInsertionOrdinal = 0; + mHoverCursor = getCursorFromString(p.hover_cursor); + mEnabled = p.enabled; + mMouseOpaque = p.mouse_opaque; + mSoundFlags = p.sound_flags; + mUseBoundingRect = p.use_bounding_rect; + mDefaultTabGroup = p.default_tab_group; + mLastTabGroup = 0; + //mToolTipMsg((LLStringExplicit)p.tool_tip()), + //mDefaultWidgets(NULL) + + // create rect first, as this will supply initial follows flags + setShape(p.rect); + mReshapeFlags = p.follows.flags; +} + +LLView::LLView() +{ + init(LLView::Params()); } LLView::LLView(const std::string& name, BOOL mouse_opaque) -: mVisible(TRUE), - mInDraw(false), - mName(name), - mParentView(NULL), - mReshapeFlags(FOLLOWS_NONE), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(mouse_opaque), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), - mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW), - mLastTabGroup(0), - // - mDelayedDelete(FALSE) - // { + LLView::Params p; + p.name = name; + p.mouse_opaque = mouse_opaque; + init(p); } - -LLView::LLView( - const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) -: mVisible(TRUE), - mInDraw(false), - mName(name), - mParentView(NULL), - mRect(rect), - mBoundingRect(rect), - mReshapeFlags(reshape), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(mouse_opaque), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), - mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW), - mLastTabGroup(0), - // - mDelayedDelete(FALSE) - // +LLView::LLView( const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) { + LLView::Params p; + p.name = name; + p.mouse_opaque = mouse_opaque; + p.rect = rect; + p.follows.flags = reshape; + init(p); } @@ -160,15 +178,10 @@ LLView::~LLView() { //llinfos << "Deleting view " << mName << ":" << (void*) this << llendl; // llassert(LLView::sIsDrawing == FALSE); - if( gFocusMgr.getKeyboardFocus() == this ) - { - llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl; - gFocusMgr.removeKeyboardFocusWithoutCallback( this ); - } if( hasMouseCapture() ) { - llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; + //llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; gFocusMgr.removeMouseCaptureWithoutCallback( this ); } @@ -616,11 +629,6 @@ void LLView::setVisible(BOOL visible) { if ( mVisible != visible ) { - if( !visible && (gFocusMgr.getTopCtrl() == this) ) - { - gFocusMgr.setTopCtrl( NULL ); - } - mVisible = visible; // notify children of visibility change if root, or part of visible hierarchy diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 676e21a2a..194c7fc64 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -54,6 +54,7 @@ #include "stdenums.h" #include "lluistring.h" #include "llcursortypes.h" +#include "llinitparam.h" #include "llfocusmgr.h" const U32 FOLLOWS_NONE = 0x00; @@ -68,88 +69,6 @@ const BOOL NOT_MOUSE_OPAQUE = FALSE; const U32 GL_NAME_UI_RESERVED = 2; -/* -// virtual functions defined in LLView: - -virtual BOOL isCtrl() const; - LLUICtrl -virtual BOOL isPanel(); - LLPanel -virtual void setRect(const LLRect &rect); - LLLineEditor -virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group); -virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group); -virtual void removeCtrl( LLUICtrl* ctrl); - LLPanel -virtual BOOL canFocusChildren() const { return TRUE; } - LLFolderView -virtual void deleteAllChildren(); - LLFolderView, LLPanelObjectInventory -virtual void setTentative(BOOL b) {} - LLUICtrl, LLSliderCtrl, LLSpinCtrl -virtual BOOL getTentative() const { return FALSE; } - LLUICtrl, LLCheckBoxCtrl -virtual void setVisible(BOOL visible); - LLFloater, LLAlertDialog, LLMenuItemGL, LLModalDialog -virtual void setEnabled(BOOL enabled) { mEnabled = enabled; } - LLCheckBoxCtrl, LLComboBox, LLLineEditor, LLMenuGL, LLRadioGroup, etc -virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ) { return FALSE; } - LLUICtrl, LLButton, LLCheckBoxCtrl, LLLineEditor, LLMenuGL, LLSliderCtrl -virtual void handleVisibilityChange ( BOOL curVisibilityIn ); - LLMenuGL -virtual LLRect getSnapRect() const { return mRect; } *TODO: Make non virtual - LLFloater -virtual LLRect getRequiredRect() { return mRect; } - LLScrolllistCtrl -virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - LLUICtrl, et. al. -virtual void translate( S32 x, S32 y ); - LLMenuGL -virtual void handleReshape(const LLRect& new_rect, bool by_user = false); - LLFloater, LLScrollLIstVtrl -virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0); -virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0); - LLScrollListCtrl -virtual BOOL canSnapTo(const LLView* other_view) { return other_view != this && other_view->getVisible(); } - LLFloater -virtual void setSnappedTo(const LLView* snap_view) {} - LLFloater -virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - * -virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - * -virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,EDragAndDropType cargo_type,void* cargo_data,EAcceptance* accept,std::string& tooltip_msg); - * -virtual void draw(); - * - - * -virtual LLXMLNodePtr getXML(bool save_children = true) const; - * -virtual void initFromXML(LLXMLNodePtr node, LLView* parent); - * -virtual void onFocusLost() {} - LLUICtrl, LLScrollListCtrl, LLMenuGL, LLLineEditor, LLComboBox -virtual void onFocusReceived() {} - LLUICtrl, LLTextEditor, LLScrollListVtrl, LLMenuGL, LLLineEditor -virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const; - LLTabContainer, LLPanel, LLMenuGL -virtual void setControlName(const std::string& control, LLView *context); - LLSliderCtrl, LLCheckBoxCtrl -virtual std::string getControlName() const { return mControlName; } - LLSliderCtrl, LLCheckBoxCtrl -virtual bool handleEvent(LLPointer event, const LLSD& userdata); - LLMenuItem -virtual void setValue(const LLSD& value); - * - -protected: -virtual BOOL handleKeyHere(KEY key, MASK mask); - * -virtual BOOL handleUnicodeCharHere(llwchar uni_char); - * -*/ - class LLUICtrlFactory; // maps xml strings to widget classes @@ -209,9 +128,73 @@ public: } }; -class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElement +class LLView +: public LLMouseHandler, // handles mouse events + public LLFocusableElement, // handles keyboard events + public LLMortician // lazy deletion + //public LLHandleProvider // passes out weak references to self { +public: + struct Follows : public LLInitParam::ChoiceBlock + { + Alternative string; + Alternative flags; + Follows(); + }; + + struct Params : public LLInitParam::Block + { + Mandatory name; + + Optional enabled, + visible, + mouse_opaque, + use_bounding_rect, + from_xui, + focus_root; + + Optional tab_group, + default_tab_group; + Optional tool_tip; + + Optional sound_flags; + Optional follows; + Optional hover_cursor; + + Optional layout; + Optional rect; + + // Historical bottom-left layout used bottom_delta and left_delta + // for relative positioning. New layout "topleft" prefers specifying + // based on top edge. + Optional bottom_delta, // from last bottom to my bottom + top_pad, // from last bottom to my top + top_delta, // from last top to my top + left_pad, // from last right to my left + left_delta; // from last left to my left + + //FIXME: get parent context involved in parsing traversal + Ignored needs_translate, // cue for translation tools + xmlns, // xml namespace + xmlns_xsi, // xml namespace + xsi_schemaLocation, // xml schema + xsi_type; // xml schema type + + Params(); + }; + + void initFromParams(const LLView::Params&); + +protected: + LLView(const LLView::Params&); + //friend class LLUICtrlFactory; +private: + void init(const LLView::Params&); + +private: + // widgets in general are not copyable + LLView(const LLView& other) {}; public: #if LL_DEBUG static BOOL sIsDrawing; @@ -663,15 +646,9 @@ private: LLRootHandle mHandle; BOOL mLastVisible; - - S32 mNextInsertionOrdinal; bool mInDraw; - // -public: - BOOL mDelayedDelete; - // private: static LLWindow* sWindow; // All root views must know about their window. diff --git a/indra/llxuixml/CMakeLists.txt b/indra/llxuixml/CMakeLists.txt new file mode 100644 index 000000000..bc98a43bd --- /dev/null +++ b/indra/llxuixml/CMakeLists.txt @@ -0,0 +1,40 @@ +# -*- cmake -*- + +project(llxuixml) + +include(00-Common) +include(LLCommon) +include(LLMath) +include(LLXML) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ) + +set(llxuixml_SOURCE_FILES + llinitparam.cpp + lluicolor.cpp + ) + +set(llxuixml_HEADER_FILES + CMakeLists.txt + + llinitparam.h + lluicolor.h + ) + +set_source_files_properties(${llxuixml_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llxuixml_SOURCE_FILES ${llxuixml_HEADER_FILES}) + +add_library (llxuixml ${llxuixml_SOURCE_FILES}) +# Libraries on which this library depends, needed for Linux builds +# Sort by high-level to low-level +target_link_libraries(llxuixml + llxml + llcommon + llmath + ) diff --git a/indra/llxuixml/llinitparam.cpp b/indra/llxuixml/llinitparam.cpp new file mode 100644 index 000000000..db72aa19b --- /dev/null +++ b/indra/llxuixml/llinitparam.cpp @@ -0,0 +1,469 @@ +/** + * @file llinitparam.cpp + * @brief parameter block abstraction for creating complex objects and + * parsing construction parameters from xml and LLSD + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llinitparam.h" + + +namespace LLInitParam +{ + // + // Param + // + Param::Param(BaseBlock* enclosing_block) + : mIsProvided(false) + { + const U8* my_addr = reinterpret_cast(this); + const U8* block_addr = reinterpret_cast(enclosing_block); + mEnclosingBlockOffset = 0x7FFFffff & (U32)(my_addr - block_addr); + } + + // + // ParamDescriptor + // + ParamDescriptor::ParamDescriptor(param_handle_t p, + merge_func_t merge_func, + deserialize_func_t deserialize_func, + serialize_func_t serialize_func, + validation_func_t validation_func, + inspect_func_t inspect_func, + S32 min_count, + S32 max_count) + : mParamHandle(p), + mMergeFunc(merge_func), + mDeserializeFunc(deserialize_func), + mSerializeFunc(serialize_func), + mValidationFunc(validation_func), + mInspectFunc(inspect_func), + mMinCount(min_count), + mMaxCount(max_count), + mUserData(NULL) + {} + + ParamDescriptor::ParamDescriptor() + : mParamHandle(0), + mMergeFunc(NULL), + mDeserializeFunc(NULL), + mSerializeFunc(NULL), + mValidationFunc(NULL), + mInspectFunc(NULL), + mMinCount(0), + mMaxCount(0), + mUserData(NULL) + {} + + ParamDescriptor::~ParamDescriptor() + { + delete mUserData; + } + + // + // Parser + // + Parser::~Parser() + {} + + void Parser::parserWarning(const std::string& message) + { + if (mParseSilently) return; + llwarns << message << llendl; + } + + void Parser::parserError(const std::string& message) + { + if (mParseSilently) return; + llerrs << message << llendl; + } + + + // + // BlockDescriptor + // + void BlockDescriptor::aggregateBlockData(BlockDescriptor& src_block_data) + { + mNamedParams.insert(src_block_data.mNamedParams.begin(), src_block_data.mNamedParams.end()); + std::copy(src_block_data.mUnnamedParams.begin(), src_block_data.mUnnamedParams.end(), std::back_inserter(mUnnamedParams)); + std::copy(src_block_data.mValidationList.begin(), src_block_data.mValidationList.end(), std::back_inserter(mValidationList)); + std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams)); + } + + BlockDescriptor::BlockDescriptor() + : mMaxParamOffset(0), + mInitializationState(UNINITIALIZED), + mCurrentBlockPtr(NULL) + {} + + // called by each derived class in least to most derived order + void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) + { + descriptor.mCurrentBlockPtr = this; + descriptor.mMaxParamOffset = block_size; + + switch(descriptor.mInitializationState) + { + case BlockDescriptor::UNINITIALIZED: + // copy params from base class here + descriptor.aggregateBlockData(base_descriptor); + + descriptor.mInitializationState = BlockDescriptor::INITIALIZING; + break; + case BlockDescriptor::INITIALIZING: + descriptor.mInitializationState = BlockDescriptor::INITIALIZED; + break; + case BlockDescriptor::INITIALIZED: + // nothing to do + break; + } + } + + param_handle_t BaseBlock::getHandleFromParam(const Param* param) const + { + const U8* param_address = reinterpret_cast(param); + const U8* baseblock_address = reinterpret_cast(this); + return (param_address - baseblock_address); + } + + bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent) + { + if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), true)) + { + if (!silent) + { + p.parserWarning(llformat("Failed to parse parameter \"%s\"", p.getCurrentElementName().c_str())); + } + return false; + } + return true; + } + + + bool BaseBlock::validateBlock(bool emit_errors) const + { + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it) + { + const Param* param = getParamFromHandle(it->first); + if (!it->second(param)) + { + if (emit_errors) + { + llwarns << "Invalid param \"" << getParamName(block_data, param) << "\"" << llendl; + } + return false; + } + } + return true; + } + + void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const + { + // named param is one like LLView::Params::follows + // unnamed param is like LLView::Params::rect - implicit + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + + for (BlockDescriptor::param_list_t::const_iterator it = block_data.mUnnamedParams.begin(); + it != block_data.mUnnamedParams.end(); + ++it) + { + param_handle_t param_handle = (*it)->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::serialize_func_t serialize_func = (*it)->mSerializeFunc; + if (serialize_func) + { + const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; + // each param descriptor remembers its serial number + // so we can inspect the same param under different names + // and see that it has the same number + name_stack.push_back(std::make_pair("", true)); + serialize_func(*param, parser, name_stack, diff_param); + name_stack.pop_back(); + } + } + + for(BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); + it != block_data.mNamedParams.end(); + ++it) + { + param_handle_t param_handle = it->second->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc; + if (serialize_func && param->anyProvided()) + { + // Ensure this param has not already been serialized + // Prevents from being serialized as its own tag. + bool duplicate = false; + for (BlockDescriptor::param_list_t::const_iterator it2 = block_data.mUnnamedParams.begin(); + it2 != block_data.mUnnamedParams.end(); + ++it2) + { + if (param_handle == (*it2)->mParamHandle) + { + duplicate = true; + break; + } + } + + //FIXME: for now, don't attempt to serialize values under synonyms, as current parsers + // don't know how to detect them + if (duplicate) + { + continue; + } + + name_stack.push_back(std::make_pair(it->first, !duplicate)); + const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; + serialize_func(*param, parser, name_stack, diff_param); + name_stack.pop_back(); + } + } + } + + bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const + { + // named param is one like LLView::Params::follows + // unnamed param is like LLView::Params::rect - implicit + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + + for (BlockDescriptor::param_list_t::const_iterator it = block_data.mUnnamedParams.begin(); + it != block_data.mUnnamedParams.end(); + ++it) + { + param_handle_t param_handle = (*it)->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::inspect_func_t inspect_func = (*it)->mInspectFunc; + if (inspect_func) + { + name_stack.push_back(std::make_pair("", true)); + inspect_func(*param, parser, name_stack, (*it)->mMinCount, (*it)->mMaxCount); + name_stack.pop_back(); + } + } + + for(BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); + it != block_data.mNamedParams.end(); + ++it) + { + param_handle_t param_handle = it->second->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::inspect_func_t inspect_func = it->second->mInspectFunc; + if (inspect_func) + { + // Ensure this param has not already been inspected + bool duplicate = false; + for (BlockDescriptor::param_list_t::const_iterator it2 = block_data.mUnnamedParams.begin(); + it2 != block_data.mUnnamedParams.end(); + ++it2) + { + if (param_handle == (*it2)->mParamHandle) + { + duplicate = true; + break; + } + } + + name_stack.push_back(std::make_pair(it->first, !duplicate)); + inspect_func(*param, parser, name_stack, it->second->mMinCount, it->second->mMaxCount); + name_stack.pop_back(); + } + } + + return true; + } + + bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool ignored) + { + BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + bool names_left = name_stack_range.first != name_stack_range.second; + + bool new_name = names_left + ? name_stack_range.first->second + : true; + + if (names_left) + { + const std::string& top_name = name_stack_range.first->first; + + ParamDescriptor::deserialize_func_t deserialize_func = NULL; + Param* paramp = NULL; + + BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name); + if (found_it != block_data.mNamedParams.end()) + { + // find pointer to member parameter from offset table + paramp = getParamFromHandle(found_it->second->mParamHandle); + deserialize_func = found_it->second->mDeserializeFunc; + + Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second); + ++new_name_stack.first; + if (deserialize_func(*paramp, p, new_name_stack, new_name)) + { + // value is no longer new, we know about it now + name_stack_range.first->second = false; + return true; + } + else + { + return false; + } + } + } + + // try to parse unnamed parameters, in declaration order + for ( BlockDescriptor::param_list_t::iterator it = block_data.mUnnamedParams.begin(); + it != block_data.mUnnamedParams.end(); + ++it) + { + Param* paramp = getParamFromHandle((*it)->mParamHandle); + ParamDescriptor::deserialize_func_t deserialize_func = (*it)->mDeserializeFunc; + + if (deserialize_func && deserialize_func(*paramp, p, name_stack_range, new_name)) + { + return true; + } + } + + // if no match, and no names left on stack, this is just an existence assertion of this block + // verify by calling readValue with NoParamValue type, an inherently unparseable type + if (!names_left) + { + Flag no_value; + return p.readValue(no_value); + } + + return false; + } + + //static + void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name) + { + // create a copy of the param descriptor in mAllParams + // so other data structures can store a pointer to it + block_data.mAllParams.push_back(in_param); + ParamDescriptorPtr param(block_data.mAllParams.back()); + + std::string name(char_name); + if ((size_t)param->mParamHandle > block_data.mMaxParamOffset) + { + llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << llendl; + } + + if (name.empty()) + { + block_data.mUnnamedParams.push_back(param); + } + else + { + // don't use insert, since we want to overwrite existing entries + block_data.mNamedParams[name] = param; + } + + if (param->mValidationFunc) + { + block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); + } + } + + void BaseBlock::addSynonym(Param& param, const std::string& synonym) + { + BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + if (block_data.mInitializationState == BlockDescriptor::INITIALIZING) + { + param_handle_t handle = getHandleFromParam(¶m); + + // check for invalid derivation from a paramblock (i.e. without using + // Block + if ((size_t)handle > block_data.mMaxParamOffset) + { + llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << llendl; + } + + ParamDescriptorPtr param_descriptor = findParamDescriptor(param); + if (param_descriptor) + { + if (synonym.empty()) + { + block_data.mUnnamedParams.push_back(param_descriptor); + } + else + { + block_data.mNamedParams[synonym] = param_descriptor; + } + } + } + } + + const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const + { + param_handle_t handle = getHandleFromParam(paramp); + for (BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); it != block_data.mNamedParams.end(); ++it) + { + if (it->second->mParamHandle == handle) + { + return it->first; + } + } + + return LLStringUtil::null; + } + + ParamDescriptorPtr BaseBlock::findParamDescriptor(const Param& param) + { + param_handle_t handle = getHandleFromParam(¶m); + BlockDescriptor& descriptor = mostDerivedBlockDescriptor(); + BlockDescriptor::all_params_list_t::iterator end_it = descriptor.mAllParams.end(); + for (BlockDescriptor::all_params_list_t::iterator it = descriptor.mAllParams.begin(); + it != end_it; + ++it) + { + if ((*it)->mParamHandle == handle) return *it; + } + return ParamDescriptorPtr(); + } + + // take all provided params from other and apply to self + // NOTE: this requires that "other" is of the same derived type as this + bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) + { + bool some_param_changed = false; + BlockDescriptor::all_params_list_t::const_iterator end_it = block_data.mAllParams.end(); + for (BlockDescriptor::all_params_list_t::const_iterator it = block_data.mAllParams.begin(); + it != end_it; + ++it) + { + const Param* other_paramp = other.getParamFromHandle((*it)->mParamHandle); + ParamDescriptor::merge_func_t merge_func = (*it)->mMergeFunc; + if (merge_func) + { + Param* paramp = getParamFromHandle((*it)->mParamHandle); + llassert(paramp->mEnclosingBlockOffset == (*it)->mParamHandle); + some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); + } + } + return some_param_changed; + } +} diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h new file mode 100644 index 000000000..ab2095776 --- /dev/null +++ b/indra/llxuixml/llinitparam.h @@ -0,0 +1,2294 @@ +/** + * @file llinitparam.h + * @brief parameter block abstraction for creating complex objects and + * parsing construction parameters from xml and LLSD + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPARAM_H +#define LL_LLPARAM_H + +#include +#include +#include +#include +#include + +#include "llerror.h" + +namespace LLInitParam +{ + // used to indicate no matching value to a given name when parsing + struct Flag{}; + + template const T& defaultValue() { static T value; return value; } + + template ::value > + struct ParamCompare + { + static bool equals(const T &a, const T &b) + { + return a == b; + } + }; + + // boost function types are not comparable + template + struct ParamCompare + { + static bool equals(const T&a, const T &b) + { + return false; + } + }; + + template<> + struct ParamCompare + { + static bool equals(const LLSD &a, const LLSD &b) { return false; } + }; + + template<> + struct ParamCompare + { + static bool equals(const Flag& a, const Flag& b) { return false; } + }; + + + // helper functions and classes + typedef ptrdiff_t param_handle_t; + + // empty default implementation of key cache + // leverages empty base class optimization + template + class TypeValues + { + private: + struct Inaccessable{}; + public: + typedef std::map value_name_map_t; + typedef Inaccessable name_t; + + void setValueName(const std::string& key) {} + std::string getValueName() const { return ""; } + std::string calcValueName(const T& value) const { return ""; } + void clearValueName() const {} + + static bool getValueFromName(const std::string& name, T& value) + { + return false; + } + + static bool valueNamesExist() + { + return false; + } + + static std::vector* getPossibleValues() + { + return NULL; + } + + static value_name_map_t* getValueNames() {return NULL;} + }; + + template > + class TypeValuesHelper + { + public: + typedef typename std::map value_name_map_t; + typedef std::string name_t; + + //TODO: cache key by index to save on param block size + void setValueName(const std::string& value_name) + { + mValueName = value_name; + } + + std::string getValueName() const + { + return mValueName; + } + + std::string calcValueName(const T& value) const + { + value_name_map_t* map = getValueNames(); + for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end(); + it != end_it; + ++it) + { + if (ParamCompare::equals(it->second, value)) + { + return it->first; + } + } + + return ""; + } + + void clearValueName() const + { + mValueName.clear(); + } + + static bool getValueFromName(const std::string& name, T& value) + { + value_name_map_t* map = getValueNames(); + typename value_name_map_t::iterator found_it = map->find(name); + if (found_it == map->end()) return false; + + value = found_it->second; + return true; + } + + static bool valueNamesExist() + { + return !getValueNames()->empty(); + } + + static value_name_map_t* getValueNames() + { + static value_name_map_t sMap; + static bool sInitialized = false; + + if (!sInitialized) + { + sInitialized = true; + DERIVED_TYPE::declareValues(); + } + return &sMap; + } + + static std::vector* getPossibleValues() + { + static std::vector sValues; + + value_name_map_t* map = getValueNames(); + for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end(); + it != end_it; + ++it) + { + sValues.push_back(it->first); + } + return &sValues; + } + + static void declare(const std::string& name, const T& value) + { + (*getValueNames())[name] = value; + } + + protected: + static void getName(const std::string& name, const T& value) + {} + + mutable std::string mValueName; + }; + + class Parser + { + LOG_CLASS(Parser); + + public: + + struct CompareTypeID + { + bool operator()(const std::type_info* lhs, const std::type_info* rhs) const + { + return lhs->before(*rhs); + } + }; + + typedef std::vector > name_stack_t; + typedef std::pair name_stack_range_t; + typedef std::vector possible_values_t; + + typedef bool (*parser_read_func_t)(Parser& parser, void* output); + typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&); + typedef boost::function parser_inspect_func_t; + + typedef std::map parser_read_func_map_t; + typedef std::map parser_write_func_map_t; + typedef std::map parser_inspect_func_map_t; + + Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) + : mParseSilently(false), + mParserReadFuncs(&read_map), + mParserWriteFuncs(&write_map), + mParserInspectFuncs(&inspect_map) + {} + virtual ~Parser(); + + template bool readValue(T& param) + { + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + return false; + } + + template bool writeValue(const T& param, name_stack_t& name_stack) + { + parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); + if (found_it != mParserWriteFuncs->end()) + { + return found_it->second(*this, (const void*)¶m, name_stack); + } + return false; + } + + // dispatch inspection to registered inspection functions, for each parameter in a param block + template bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) + { + parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T)); + if (found_it != mParserInspectFuncs->end()) + { + found_it->second(name_stack, min_count, max_count, possible_values); + return true; + } + return false; + } + + virtual std::string getCurrentElementName() = 0; + virtual void parserWarning(const std::string& message); + virtual void parserError(const std::string& message); + void setParseSilently(bool silent) { mParseSilently = silent; } + + protected: + template + void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL) + { + mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func)); + mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func)); + } + + template + void registerInspectFunc(parser_inspect_func_t inspect_func) + { + mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func)); + } + + bool mParseSilently; + + private: + parser_read_func_map_t* mParserReadFuncs; + parser_write_func_map_t* mParserWriteFuncs; + parser_inspect_func_map_t* mParserInspectFuncs; + }; + + class Param; + + // various callbacks and constraints associated with an individual param + struct ParamDescriptor + { + struct UserData + { + virtual ~UserData() {} + }; + + typedef bool(*merge_func_t)(Param&, const Param&, bool); + typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool); + typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param); + typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); + typedef bool(*validation_func_t)(const Param*); + + ParamDescriptor(param_handle_t p, + merge_func_t merge_func, + deserialize_func_t deserialize_func, + serialize_func_t serialize_func, + validation_func_t validation_func, + inspect_func_t inspect_func, + S32 min_count, + S32 max_count); + + ParamDescriptor(); + ~ParamDescriptor(); + + param_handle_t mParamHandle; + merge_func_t mMergeFunc; + deserialize_func_t mDeserializeFunc; + serialize_func_t mSerializeFunc; + inspect_func_t mInspectFunc; + validation_func_t mValidationFunc; + S32 mMinCount; + S32 mMaxCount; + S32 mNumRefs; + UserData* mUserData; + }; + + typedef boost::shared_ptr ParamDescriptorPtr; + + // each derived Block class keeps a static data structure maintaining offsets to various params + class BlockDescriptor + { + public: + BlockDescriptor(); + + typedef enum e_initialization_state + { + UNINITIALIZED, + INITIALIZING, + INITIALIZED + } EInitializationState; + + void aggregateBlockData(BlockDescriptor& src_block_data); + + typedef boost::unordered_map param_map_t; + typedef std::vector param_list_t; + typedef std::list all_params_list_t; + typedef std::vector > param_validation_list_t; + + param_map_t mNamedParams; // parameters with associated names + param_list_t mUnnamedParams; // parameters with_out_ associated names + param_validation_list_t mValidationList; // parameters that must be validated + all_params_list_t mAllParams; // all parameters, owns descriptors + size_t mMaxParamOffset; + EInitializationState mInitializationState; // whether or not static block data has been initialized + class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed + }; + + class BaseBlock + { + public: + //TODO: implement in terms of owned_ptr + template + class Lazy + { + public: + Lazy() + : mPtr(NULL) + {} + + ~Lazy() + { + delete mPtr; + } + + Lazy(const Lazy& other) + { + if (other.mPtr) + { + mPtr = new T(*other.mPtr); + } + else + { + mPtr = NULL; + } + } + + Lazy& operator = (const Lazy& other) + { + if (other.mPtr) + { + mPtr = new T(*other.mPtr); + } + else + { + mPtr = NULL; + } + return *this; + } + + bool empty() const + { + return mPtr == NULL; + } + + void set(const T& other) + { + delete mPtr; + mPtr = new T(other); + } + + const T& get() const + { + return ensureInstance(); + } + + T& get() + { + return ensureInstance(); + } + + private: + // lazily allocate an instance of T + T* ensureInstance() const + { + if (mPtr == NULL) + { + mPtr = new T(); + } + return mPtr; + } + + private: + // if you get a compilation error with this, that means you are using a forward declared struct for T + // unfortunately, the type traits we rely on don't work with forward declared typed + //static const int dummy = sizeof(T); + + mutable T* mPtr; + }; + + // "Multiple" constraint types, put here in root class to avoid ambiguity during use + struct AnyAmount + { + enum { minCount = 0 }; + enum { maxCount = U32_MAX }; + }; + + template + struct AtLeast + { + enum { minCount = MIN_AMOUNT }; + enum { maxCount = U32_MAX }; + }; + + template + struct AtMost + { + enum { minCount = 0 }; + enum { maxCount = MAX_AMOUNT }; + }; + + template + struct Between + { + enum { minCount = MIN_AMOUNT }; + enum { maxCount = MAX_AMOUNT }; + }; + + template + struct Exactly + { + enum { minCount = EXACT_COUNT }; + enum { maxCount = EXACT_COUNT }; + }; + + // this typedef identifies derived classes as being blocks + typedef void baseblock_base_class_t; + LOG_CLASS(BaseBlock); + friend class Param; + + virtual ~BaseBlock() {} + bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); + + param_handle_t getHandleFromParam(const Param* param) const; + bool validateBlock(bool emit_errors = true) const; + + Param* getParamFromHandle(const param_handle_t param_handle) + { + if (param_handle == 0) return NULL; + + U8* baseblock_address = reinterpret_cast(this); + return reinterpret_cast(baseblock_address + param_handle); + } + + const Param* getParamFromHandle(const param_handle_t param_handle) const + { + const U8* baseblock_address = reinterpret_cast(this); + return reinterpret_cast(baseblock_address + param_handle); + } + + void addSynonym(Param& param, const std::string& synonym); + + // Blocks can override this to do custom tracking of changes + virtual void paramChanged(const Param& changed_param, bool user_provided) {} + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); + void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + + // take all provided params from other and apply to self + bool overwriteFrom(const BaseBlock& other) + { + return false; + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const BaseBlock& other) + { + return false; + } + + static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name); + + ParamDescriptorPtr findParamDescriptor(const Param& param); + + protected: + void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); + + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + return mergeBlock(block_data, source, overwrite); + } + // take all provided params from other and apply to self + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); + + static BlockDescriptor& selfBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + private: + const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; + }; + + template + struct ParamCompare, false > + { + static bool equals(const BaseBlock::Lazy& a, const BaseBlock::Lazy& b) { return !a.empty() || !b.empty(); } + }; + + class Param + { + public: + void setProvided(bool is_provided = true) + { + mIsProvided = is_provided; + enclosingBlock().paramChanged(*this, is_provided); + } + + Param& operator =(const Param& other) + { + mIsProvided = other.mIsProvided; + // don't change mEnclosingblockoffset + return *this; + } + protected: + + bool anyProvided() const { return mIsProvided; } + + Param(BaseBlock* enclosing_block); + + // store pointer to enclosing block as offset to reduce space and allow for quick copying + BaseBlock& enclosingBlock() const + { + const U8* my_addr = reinterpret_cast(this); + // get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class + return *const_cast + (reinterpret_cast + (my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset)); + } + + private: + friend class BaseBlock; + + U32 mEnclosingBlockOffset:31; + U32 mIsProvided:1; + + }; + + // these templates allow us to distinguish between template parameters + // that derive from BaseBlock and those that don't + template + struct IsBlock + { + static const bool value = false; + struct EmptyBase {}; + typedef EmptyBase base_class_t; + }; + + template + struct IsBlock + { + static const bool value = true; + typedef BaseBlock base_class_t; + }; + + template + struct IsBlock, typename T::baseblock_base_class_t > + { + static const bool value = true; + typedef BaseBlock base_class_t; + }; + + template::value> + class ParamValue : public NAME_VALUE_LOOKUP + { + public: + typedef const T& value_assignment_t; + typedef T value_t; + typedef ParamValue self_t; + + ParamValue(): mValue() {} + ParamValue(value_assignment_t other) : mValue(other) {} + + void setValue(value_assignment_t val) + { + mValue = val; + } + + value_assignment_t getValue() const + { + return mValue; + } + + T& getValue() + { + return mValue; + } + + operator value_assignment_t() const + { + return mValue; + } + + value_assignment_t operator()() const + { + return mValue; + } + + void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) + { + *this = name; + } + + self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + { + if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue)) + { + setValueName(name); + } + + return *this; + } + + protected: + T mValue; + }; + + template + class ParamValue + : public T, + public NAME_VALUE_LOOKUP + { + public: + typedef const T& value_assignment_t; + typedef T value_t; + typedef ParamValue self_t; + + ParamValue() + : T(), + mValidated(false) + {} + + ParamValue(value_assignment_t other) + : T(other), + mValidated(false) + {} + + void setValue(value_assignment_t val) + { + *this = val; + } + + value_assignment_t getValue() const + { + return *this; + } + + T& getValue() + { + return *this; + } + + operator value_assignment_t() const + { + return *this; + } + + value_assignment_t operator()() const + { + return *this; + } + + void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) + { + *this = name; + } + + self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + { + if (NAME_VALUE_LOOKUP::getValueFromName(name, *this)) + { + setValueName(name); + } + + return *this; + } + + protected: + mutable bool mValidated; // lazy validation flag + }; + + template + class ParamValue + : public NAME_VALUE_LOOKUP + { + public: + typedef const std::string& value_assignment_t; + typedef std::string value_t; + typedef ParamValue self_t; + + ParamValue(): mValue() {} + ParamValue(value_assignment_t other) : mValue(other) {} + + void setValue(value_assignment_t val) + { + if (NAME_VALUE_LOOKUP::getValueFromName(val, mValue)) + { + NAME_VALUE_LOOKUP::setValueName(val); + } + else + { + mValue = val; + } + } + + value_assignment_t getValue() const + { + return mValue; + } + + std::string& getValue() + { + return mValue; + } + + operator value_assignment_t() const + { + return mValue; + } + + value_assignment_t operator()() const + { + return mValue; + } + + protected: + std::string mValue; + }; + + + template > + struct ParamIterator + { + typedef typename std::vector >::const_iterator const_iterator; + typedef typename std::vector >::iterator iterator; + }; + + // specialize for custom parsing/decomposition of specific classes + // e.g. TypedParam has left, top, right, bottom, etc... + template, + bool HAS_MULTIPLE_VALUES = false, + bool VALUE_IS_BLOCK = IsBlock >::value> + class TypedParam + : public Param, + public ParamValue + { + public: + typedef TypedParam self_t; + typedef ParamValue param_value_t; + typedef typename param_value_t::value_assignment_t value_assignment_t; + typedef NAME_VALUE_LOOKUP name_value_lookup_t; + + using param_value_t::operator(); + + TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr) + { + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + BaseBlock::addParam(block_descriptor, param_descriptor, name); + } + + setValue(value); + } + + bool isProvided() const { return Param::anyProvided(); } + + static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast(param); + // no further names in stack, attempt to parse value now + if (name_stack_range.first == name_stack_range.second) + { + if (parser.readValue(typed_param.getValue())) + { + typed_param.clearValueName(); + typed_param.setProvided(); + return true; + } + + // try to parse a known named value + if(name_value_lookup_t::valueNamesExist()) + { + // try to parse a known named value + std::string name; + if (parser.readValue(name)) + { + // try to parse a per type named value + if (name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + + } + } + } + return false; + } + + static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + { + const self_t& typed_param = static_cast(param); + if (!typed_param.isProvided()) return; + + if (!name_stack.empty()) + { + name_stack.back().second = true; + } + + std::string key = typed_param.getValueName(); + + // first try to write out name of name/value pair + + if (!key.empty()) + { + if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), key)) + { + parser.writeValue(key, name_stack); + } + } + // then try to serialize value directly + else if (!diff_param || !ParamCompare::equals(typed_param.getValue(), static_cast(diff_param)->getValue())) + { + if (!parser.writeValue(typed_param.getValue(), name_stack)) + { + std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); + if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), calculated_key)) + { + parser.writeValue(calculated_key, name_stack); + } + } + } + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (name_value_lookup_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); + } + } + + void set(value_assignment_t val, bool flag_as_provided = true) + { + param_value_t::clearValueName(); + setValue(val); + setProvided(flag_as_provided); + } + + self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + { + return static_cast(param_value_t::operator =(name)); + } + + protected: + + self_t& operator =(const self_t& other) + { + param_value_t::operator =(other); + Param::operator =(other); + return *this; + } + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (src_typed_param.isProvided() + && (overwrite || !dst_typed_param.isProvided())) + { + dst_typed_param.set(src_typed_param.getValue()); + return true; + } + return false; + } + }; + + // parameter that is a block + template + class TypedParam + : public Param, + public ParamValue + { + public: + typedef ParamValue param_value_t; + typedef typename param_value_t::value_assignment_t value_assignment_t; + typedef TypedParam self_t; + typedef NAME_VALUE_LOOKUP name_value_lookup_t; + + using param_value_t::operator(); + + TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + param_value_t(value) + { + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + BaseBlock::addParam(block_descriptor, param_descriptor, name); + } + } + + static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast(param); + // attempt to parse block... + if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) + { + typed_param.clearValueName(); + typed_param.setProvided(); + return true; + } + + if(name_value_lookup_t::valueNamesExist()) + { + // try to parse a known named value + std::string name; + if (parser.readValue(name)) + { + // try to parse a per type named value + if (name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + + } + } + return false; + } + + static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + { + const self_t& typed_param = static_cast(param); + if (!typed_param.isProvided()) return; + + if (!name_stack.empty()) + { + name_stack.back().second = true; + } + + std::string key = typed_param.getValueName(); + if (!key.empty()) + { + if (!parser.writeValue(key, name_stack)) + { + return; + } + } + else + { + typed_param.serializeBlock(parser, name_stack, static_cast(diff_param)); + } + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + // I am a param that is also a block, so just recurse into my contents + const self_t& typed_param = static_cast(param); + typed_param.inspectBlock(parser, name_stack, min_count, max_count); + } + + // a param-that-is-a-block is provided when the user has set one of its child params + // *and* the block as a whole validates + bool isProvided() const + { + // only validate block when it hasn't already passed validation with current data + if (Param::anyProvided() && !param_value_t::mValidated) + { + // a sub-block is "provided" when it has been filled in enough to be valid + param_value_t::mValidated = param_value_t::validateBlock(false); + } + return Param::anyProvided() && param_value_t::mValidated; + } + + // assign block contents to this param-that-is-a-block + void set(value_assignment_t val, bool flag_as_provided = true) + { + setValue(val); + param_value_t::clearValueName(); + // force revalidation of block + // next call to isProvided() will update provision status based on validity + param_value_t::mValidated = false; + setProvided(flag_as_provided); + } + + self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + { + return static_cast(param_value_t::operator =(name)); + } + + // propagate changed status up to enclosing block + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + param_value_t::paramChanged(changed_param, user_provided); + if (user_provided) + { + // a child param has been explicitly changed + // so *some* aspect of this block is now provided + param_value_t::mValidated = false; + setProvided(); + param_value_t::clearValueName(); + } + else + { + Param::enclosingBlock().paramChanged(*this, user_provided); + } + } + + protected: + + self_t& operator =(const self_t& other) + { + param_value_t::operator =(other); + Param::operator =(other); + return *this; + } + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (src_typed_param.anyProvided()) + { + if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::selfBlockDescriptor(), src_typed_param, overwrite)) + { + dst_typed_param.clearValueName(); + dst_typed_param.setProvided(true); + return true; + } + } + return false; + } + }; + + // container of non-block parameters + template + class TypedParam + : public Param + { + public: + typedef TypedParam self_t; + typedef ParamValue param_value_t; + typedef typename std::vector container_t; + typedef const container_t& value_assignment_t; + + typedef typename param_value_t::value_t value_t; + typedef NAME_VALUE_LOOKUP name_value_lookup_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr) + { + std::copy(value.begin(), value.end(), std::back_inserter(mValues)); + + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + BaseBlock::addParam(block_descriptor, param_descriptor, name); + } + } + + bool isProvided() const { return Param::anyProvided(); } + + static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast(param); + value_t value; + // no further names in stack, attempt to parse value now + if (name_stack_range.first == name_stack_range.second) + { + // attempt to read value directly + if (parser.readValue(value)) + { + typed_param.add(value); + return true; + } + + // try to parse a known named value + if(name_value_lookup_t::valueNamesExist()) + { + // try to parse a known named value + std::string name; + if (parser.readValue(name)) + { + // try to parse a per type named value + if (name_value_lookup_t::getValueFromName(name, value)) + { + typed_param.add(value); + typed_param.mValues.back().setValueName(name); + return true; + } + + } + } + } + return false; + } + + static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + { + const self_t& typed_param = static_cast(param); + if (!typed_param.isProvided() || name_stack.empty()) return; + + for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); + it != end_it; + ++it) + { + std::string key = it->getValueName(); + name_stack.back().second = true; + + if(key.empty()) + // not parsed via name values, write out value directly + { + bool value_written = parser.writeValue(*it, name_stack); + if (!value_written) + { + std::string calculated_key = it->calcValueName(it->getValue()); + if (!parser.writeValue(calculated_key, name_stack)) + { + break; + } + } + } + else + { + if(!parser.writeValue(key, name_stack)) + { + break; + } + } + } + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + parser.inspectValue(name_stack, min_count, max_count, NULL); + if (name_value_lookup_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); + } + } + + void set(value_assignment_t val, bool flag_as_provided = true) + { + mValues = val; + setProvided(flag_as_provided); + } + + param_value_t& add() + { + mValues.push_back(param_value_t(value_t())); + Param::setProvided(); + return mValues.back(); + } + + void add(const value_t& item) + { + param_value_t param_value; + param_value.setValue(item); + mValues.push_back(param_value); + setProvided(); + } + + void add(const typename name_value_lookup_t::name_t& name) + { + value_t value; + + // try to parse a per type named value + if (name_value_lookup_t::getValueFromName(name, value)) + { + add(value); + mValues.back().setValueName(name); + } + } + + // implicit conversion + operator value_assignment_t() const { return mValues; } + // explicit conversion + value_assignment_t operator()() const { return mValues; } + + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; + iterator begin() { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator begin() const { return mValues.begin(); } + const_iterator end() const { return mValues.end(); } + bool empty() const { return mValues.empty(); } + size_t size() const { return mValues.size(); } + + U32 numValidElements() const + { + return mValues.size(); + } + + protected: + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (overwrite) + { + std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); + } + else + { + container_t new_values(src_typed_param.mValues); + std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); + std::swap(dst_typed_param.mValues, new_values); + } + + if (src_typed_param.begin() != src_typed_param.end()) + { + dst_typed_param.setProvided(); + } + return true; + } + + container_t mValues; + }; + + // container of block parameters + template + class TypedParam + : public Param + { + public: + typedef TypedParam self_t; + typedef ParamValue param_value_t; + typedef typename std::vector container_t; + typedef const container_t& value_assignment_t; + typedef typename param_value_t::value_t value_t; + typedef NAME_VALUE_LOOKUP name_value_lookup_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr) + { + std::copy(value.begin(), value.end(), back_inserter(mValues)); + + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + BaseBlock::addParam(block_descriptor, param_descriptor, name); + } + } + + bool isProvided() const { return Param::anyProvided(); } + + static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast(param); + bool new_value = false; + + if (new_name || typed_param.mValues.empty()) + { + new_value = true; + typed_param.mValues.push_back(value_t()); + } + + param_value_t& value = typed_param.mValues.back(); + + // attempt to parse block... + if(value.deserializeBlock(parser, name_stack_range, new_name)) + { + typed_param.setProvided(); + return true; + } + else if(name_value_lookup_t::valueNamesExist()) + { + // try to parse a known named value + std::string name; + if (parser.readValue(name)) + { + // try to parse a per type named value + if (name_value_lookup_t::getValueFromName(name, value.getValue())) + { + typed_param.mValues.back().setValueName(name); + typed_param.setProvided(); + return true; + } + + } + } + + if (new_value) + { // failed to parse new value, pop it off + typed_param.mValues.pop_back(); + } + + return false; + } + + static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + { + const self_t& typed_param = static_cast(param); + if (!typed_param.isProvided() || name_stack.empty()) return; + + for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); + it != end_it; + ++it) + { + name_stack.back().second = true; + + std::string key = it->getValueName(); + if (!key.empty()) + { + parser.writeValue(key, name_stack); + } + // Not parsed via named values, write out value directly + // NOTE: currently we don't worry about removing default values in Multiple + else + { + it->serializeBlock(parser, name_stack, NULL); + } + } + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + // I am a vector of blocks, so describe my contents recursively + param_value_t(value_t()).inspectBlock(parser, name_stack, min_count, max_count); + } + + void set(value_assignment_t val, bool flag_as_provided = true) + { + mValues = val; + setProvided(flag_as_provided); + } + + param_value_t& add() + { + mValues.push_back(value_t()); + setProvided(); + return mValues.back(); + } + + void add(const value_t& item) + { + mValues.push_back(item); + setProvided(); + } + + void add(const typename name_value_lookup_t::name_t& name) + { + value_t value; + + // try to parse a per type named value + if (name_value_lookup_t::getValueFromName(name, value)) + { + add(value); + mValues.back().setValueName(name); + } + } + + // implicit conversion + operator value_assignment_t() const { return mValues; } + // explicit conversion + value_assignment_t operator()() const { return mValues; } + + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; + iterator begin() { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator begin() const { return mValues.begin(); } + const_iterator end() const { return mValues.end(); } + bool empty() const { return mValues.empty(); } + size_t size() const { return mValues.size(); } + + U32 numValidElements() const + { + U32 count = 0; + for (const_iterator it = mValues.begin(), end_it = mValues.end(); + it != end_it; + ++it) + { + if(it->validateBlock(false)) count++; + } + return count; + } + + protected: + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (overwrite) + { + std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); + } + else + { + container_t new_values(src_typed_param.mValues); + std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); + std::swap(dst_typed_param.mValues, new_values); + } + + if (src_typed_param.begin() != src_typed_param.end()) + { + dst_typed_param.setProvided(); + } + + return true; + } + + container_t mValues; + }; + + template + class ChoiceBlock : public BASE_BLOCK + { + typedef ChoiceBlock self_t; + typedef ChoiceBlock enclosing_block_t; + typedef BASE_BLOCK base_block_t; + + LOG_CLASS(self_t); + public: + // take all provided params from other and apply to self + bool overwriteFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, true); + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, false); + } + + bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + bool source_override = source_provided && (overwrite || !dest_provided); + + if (source_override || source.mCurChoice == mCurChoice) + { + return mergeBlock(block_data, source, overwrite); + } + return false; + } + + // merge with other block + bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite) + { + mCurChoice = other.mCurChoice; + return base_block_t::mergeBlock(selfBlockDescriptor(), other, overwrite); + } + + // clear out old choice when param has changed + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param); + // if we have a new choice... + if (changed_param_handle != mCurChoice) + { + // clear provided flag on previous choice + Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice); + if (previous_choice) + { + previous_choice->setProvided(false); + } + mCurChoice = changed_param_handle; + } + base_block_t::paramChanged(changed_param, user_provided); + } + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + + protected: + ChoiceBlock() + : mCurChoice(0) + { + BaseBlock::init(selfBlockDescriptor(), base_block_t::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); + } + + // Alternatives are mutually exclusive wrt other Alternatives in the same block. + // One alternative in a block will always have isChosen() == true. + // At most one alternative in a block will have isProvided() == true. + template > + class Alternative : public TypedParam + { + public: + friend class ChoiceBlock; + + typedef Alternative self_t; + typedef TypedParam >::value> super_t; + typedef typename super_t::value_assignment_t value_assignment_t; + + using super_t::operator =; + + explicit Alternative(const char* name = "", value_assignment_t val = defaultValue()) + : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1), + mOriginalValue(val) + { + // assign initial choice to first declared option + DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr); + if (LL_UNLIKELY(DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) + { + if(blockp->mCurChoice == 0) + { + blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this); + } + } + } + + void choose() + { + static_cast(Param::enclosingBlock()).paramChanged(*this, true); + } + + void chooseAs(value_assignment_t val) + { + super_t::set(val); + } + + void operator =(value_assignment_t val) + { + super_t::set(val); + } + + void operator()(typename super_t::value_assignment_t val) + { + super_t::set(val); + } + + operator value_assignment_t() const + { + return (*this)(); + } + + value_assignment_t operator()() const + { + if (static_cast(Param::enclosingBlock()).getCurrentChoice() == this) + { + return super_t::getValue(); + } + return mOriginalValue; + } + + bool isChosen() const + { + return static_cast(Param::enclosingBlock()).getCurrentChoice() == this; + } + + private: + T mOriginalValue; + }; + + protected: + static BlockDescriptor& selfBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + private: + param_handle_t mCurChoice; + + const Param* getCurrentChoice() const + { + return base_block_t::getParamFromHandle(mCurChoice); + } + }; + + template + class Block + : public BASE_BLOCK + { + typedef Block self_t; + typedef Block block_t; + + public: + typedef BASE_BLOCK base_block_t; + + // take all provided params from other and apply to self + bool overwriteFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, true); + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, false); + } + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + + protected: + Block() + { + //#pragma message("Parsing LLInitParam::Block") + BaseBlock::init(selfBlockDescriptor(), BASE_BLOCK::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); + } + + // + // Nested classes for declaring parameters + // + template > + class Optional : public TypedParam + { + public: + typedef TypedParam >::value> super_t; + typedef typename super_t::value_assignment_t value_assignment_t; + + using super_t::operator(); + using super_t::operator =; + + explicit Optional(const char* name = "", value_assignment_t val = defaultValue()) + : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1) + { + //#pragma message("Parsing LLInitParam::Block::Optional") + } + + Optional& operator =(value_assignment_t val) + { + set(val); + return *this; + } + + DERIVED_BLOCK& operator()(value_assignment_t val) + { + super_t::set(val); + return static_cast(Param::enclosingBlock()); + } + }; + + template > + class Mandatory : public TypedParam + { + public: + typedef TypedParam >::value> super_t; + typedef Mandatory self_t; + typedef typename super_t::value_assignment_t value_assignment_t; + + using super_t::operator(); + using super_t::operator =; + + // mandatory parameters require a name to be parseable + explicit Mandatory(const char* name = "", value_assignment_t val = defaultValue()) + : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1) + {} + + Mandatory& operator =(value_assignment_t val) + { + set(val); + return *this; + } + + DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) + { + super_t::set(val); + return static_cast(Param::enclosingBlock()); + } + + static bool validate(const Param* p) + { + // valid only if provided + return static_cast(p)->isProvided(); + } + + }; + + template > + class Multiple : public TypedParam + { + public: + typedef TypedParam >::value> super_t; + typedef Multiple self_t; + typedef typename super_t::container_t container_t; + typedef typename super_t::value_assignment_t value_assignment_t; + typedef typename super_t::iterator iterator; + typedef typename super_t::const_iterator const_iterator; + + explicit Multiple(const char* name = "") + : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) + {} + + Multiple& operator =(value_assignment_t val) + { + set(val); + return *this; + } + + DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) + { + super_t::set(val); + return static_cast(Param::enclosingBlock()); + } + + static bool validate(const Param* paramp) + { + U32 num_valid = ((super_t*)paramp)->numValidElements(); + return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; + } + }; + + class Deprecated : public Param + { + public: + explicit Deprecated(const char* name) + : Param(DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr) + { + BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor(); + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + NULL, + &deserializeParam, + NULL, + NULL, + NULL, + 0, S32_MAX)); + BaseBlock::addParam(block_descriptor, param_descriptor, name); + } + } + + static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (name_stack_range.first == name_stack_range.second) + { + //std::string message = llformat("Deprecated value %s ignored", getName().c_str()); + //parser.parserWarning(message); + return true; + } + + return false; + } + }; + + // different semantics for documentation purposes, but functionally identical + typedef Deprecated Ignored; + + protected: + static BlockDescriptor& selfBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + template + void changeDefault(TypedParam& param, + typename TypedParam::value_assignment_t value) + { + if (!param.isProvided()) + { + param.set(value, false); + } + } + + }; + + template + class BatchBlock + : public Block + { + public: + typedef BatchBlock self_t; + typedef Block super_t; + + BatchBlock() + {} + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) + { + if (new_name) + { + // reset block + *static_cast(this) = defaultBatchValue(); + } + return super_t::deserializeBlock(p, name_stack_range, new_name); + } + + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) + { + if (overwrite) + { + *static_cast(this) = defaultBatchValue(); + // merge individual parameters into destination + return super_t::mergeBlock(super_t::selfBlockDescriptor(), other, overwrite); + } + return false; + } + protected: + static const DERIVED_BLOCK& defaultBatchValue() + { + static DERIVED_BLOCK default_value; + return default_value; + } + }; + + // FIXME: this specialization is not currently used, as it only matches against the BatchBlock base class + // and not the derived class with the actual params + template + class ParamValue , + NAME_VALUE_LOOKUP, + true> + : public NAME_VALUE_LOOKUP, + protected BatchBlock + { + public: + typedef BatchBlock block_t; + typedef const BatchBlock& value_assignment_t; + typedef block_t value_t; + + ParamValue() + : block_t(), + mValidated(false) + {} + + ParamValue(value_assignment_t other) + : block_t(other), + mValidated(false) + { + } + + void setValue(value_assignment_t val) + { + *this = val; + } + + value_assignment_t getValue() const + { + return *this; + } + + BatchBlock& getValue() + { + return *this; + } + + operator value_assignment_t() const + { + return *this; + } + + value_assignment_t operator()() const + { + return *this; + } + + protected: + mutable bool mValidated; // lazy validation flag + }; + + template + class ParamValue , + TypeValues, + IS_BLOCK> + : public IsBlock::base_class_t + { + public: + typedef ParamValue , TypeValues, false> self_t; + typedef const T& value_assignment_t; + typedef T value_t; + + ParamValue() + : mValue(), + mValidated(false) + {} + + ParamValue(value_assignment_t other) + : mValue(other), + mValidated(false) + {} + + void setValue(value_assignment_t val) + { + mValue.set(val); + } + + value_assignment_t getValue() const + { + return mValue.get(); + } + + T& getValue() + { + return mValue.get(); + } + + operator value_assignment_t() const + { + return mValue.get(); + } + + value_assignment_t operator()() const + { + return mValue.get(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) + { + return mValue.get().deserializeBlock(p, name_stack_range, new_name); + } + + void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const + { + if (mValue.empty()) return; + + mValue.get().serializeBlock(p, name_stack, diff_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + if (mValue.empty()) return false; + + return mValue.get().inspectBlock(p, name_stack, min_count, max_count); + } + + protected: + mutable bool mValidated; // lazy validation flag + + private: + BaseBlock::Lazy mValue; + }; + + template <> + class ParamValue , + false> + : public TypeValues, + public BaseBlock + { + public: + typedef ParamValue, false> self_t; + typedef const LLSD& value_assignment_t; + + ParamValue() + : mValidated(false) + {} + + ParamValue(value_assignment_t other) + : mValue(other), + mValidated(false) + {} + + void setValue(value_assignment_t val) { mValue = val; } + + value_assignment_t getValue() const { return mValue; } + LLSD& getValue() { return mValue; } + + operator value_assignment_t() const { return mValue; } + value_assignment_t operator()() const { return mValue; } + + + // block param interface + bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); + void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + //TODO: implement LLSD params as schema type Any + return true; + } + + protected: + mutable bool mValidated; // lazy validation flag + + private: + static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); + + LLSD mValue; + }; + + template + class CustomParamValue + : public Block > >, + public TypeValues + { + public: + typedef enum e_value_age + { + VALUE_NEEDS_UPDATE, // mValue needs to be refreshed from the block parameters + VALUE_AUTHORITATIVE, // mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue) + BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative + } EValueAge; + + typedef ParamValue > derived_t; + typedef CustomParamValue self_t; + typedef Block block_t; + typedef const T& value_assignment_t; + typedef T value_t; + + + CustomParamValue(const T& value = T()) + : mValue(value), + mValueAge(VALUE_AUTHORITATIVE), + mValidated(false) + {} + + bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name) + { + derived_t& typed_param = static_cast(*this); + // try to parse direct value T + if (name_stack_range.first == name_stack_range.second) + { + if(parser.readValue(typed_param.mValue)) + { + typed_param.mValueAge = VALUE_AUTHORITATIVE; + typed_param.updateBlockFromValue(false); + + typed_param.clearValueName(); + + return true; + } + } + + // fall back on parsing block components for T + return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); + } + + void serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const + { + const derived_t& typed_param = static_cast(*this); + const derived_t* diff_param = static_cast(diff_block); + + std::string key = typed_param.getValueName(); + + // first try to write out name of name/value pair + if (!key.empty()) + { + if (!diff_param || !ParamCompare::equals(diff_param->getValueName(), key)) + { + parser.writeValue(key, name_stack); + } + } + // then try to serialize value directly + else if (!diff_param || !ParamCompare::equals(typed_param.getValue(), diff_param->getValue())) + { + + if (!parser.writeValue(typed_param.getValue(), name_stack)) + { + //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), + // since these tend to be viewed as the constructor arguments for the value T. It seems + // cleaner to treat the uniqueness of a BlockValue according to the generated value, and + // not the individual components. This way will not + // be exported as , since it was probably the intent of the user to + // be specific about the RGB color values. This also fixes an issue where we distinguish + // between rect.left not being provided and rect.left being explicitly set to 0 (same as default) + + if (typed_param.mValueAge == VALUE_AUTHORITATIVE) + { + // if the value is authoritative but the parser doesn't accept the value type + // go ahead and make a copy, and splat the value out to its component params + // and serialize those params + derived_t copy(typed_param); + copy.updateBlockFromValue(true); + copy.block_t::serializeBlock(parser, name_stack, NULL); + } + else + { + block_t::serializeBlock(parser, name_stack, NULL); + } + } + } + } + + bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + // first, inspect with actual type... + parser.inspectValue(name_stack, min_count, max_count, NULL); + if (TypeValues::getPossibleValues()) + { + //...then inspect with possible string values... + parser.inspectValue(name_stack, min_count, max_count, TypeValues::getPossibleValues()); + } + // then recursively inspect contents... + return block_t::inspectBlock(parser, name_stack, min_count, max_count); + } + + bool validateBlock(bool emit_errors = true) const + { + if (mValueAge == VALUE_NEEDS_UPDATE) + { + if (block_t::validateBlock(emit_errors)) + { + // clear stale keyword associated with old value + TypeValues::clearValueName(); + mValueAge = BLOCK_AUTHORITATIVE; + static_cast(const_cast(this))->updateValueFromBlock(); + return true; + } + else + { + //block value incomplete, so not considered provided + // will attempt to revalidate on next call to isProvided() + return false; + } + } + else + { + // we have a valid value in hand + return true; + } + } + + // propagate change status up to enclosing block + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + BaseBlock::paramChanged(changed_param, user_provided); + if (user_provided) + { + // a parameter changed, so our value is out of date + mValueAge = VALUE_NEEDS_UPDATE; + } + } + + void setValue(value_assignment_t val) + { + derived_t& typed_param = static_cast(*this); + // set param version number to be up to date, so we ignore block contents + mValueAge = VALUE_AUTHORITATIVE; + mValue = val; + typed_param.clearValueName(); + static_cast(this)->updateBlockFromValue(false); + } + + value_assignment_t getValue() const + { + validateBlock(true); + return mValue; + } + + T& getValue() + { + validateBlock(true); + return mValue; + } + + operator value_assignment_t() const + { + return getValue(); + } + + value_assignment_t operator()() const + { + return getValue(); + } + + protected: + + // use this from within updateValueFromBlock() to set the value without making it authoritative + void updateValue(value_assignment_t value) + { + mValue = value; + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + bool source_override = source_provided && (overwrite || !dst_provided); + + const derived_t& src_typed_param = static_cast(source); + + if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE) + { + // copy value over + setValue(src_typed_param.getValue()); + return true; + } + // merge individual parameters into destination + if (mValueAge == VALUE_AUTHORITATIVE) + { + static_cast(this)->updateBlockFromValue(dst_provided); + } + return mergeBlock(block_data, source, overwrite); + } + + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + return block_t::mergeBlock(block_data, source, overwrite); + } + + mutable bool mValidated; // lazy validation flag + + private: + mutable T mValue; + mutable EValueAge mValueAge; + }; +} + + +#endif // LL_LLPARAM_H diff --git a/indra/llxuixml/lluicolor.cpp b/indra/llxuixml/lluicolor.cpp new file mode 100644 index 000000000..f9bb80f8c --- /dev/null +++ b/indra/llxuixml/lluicolor.cpp @@ -0,0 +1,87 @@ +/** + * @file lluicolor.cpp + * @brief brief LLUIColor class implementation file + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lluicolor.h" + +LLUIColor::LLUIColor() + :mColorPtr(NULL) +{ +} + + +LLUIColor::LLUIColor(const LLColor4& color) +: mColor(color), + mColorPtr(NULL) +{ +} + +LLUIColor::LLUIColor(const LLUIColor* color) +: mColorPtr(color) +{ +} + +void LLUIColor::set(const LLColor4& color) +{ + mColor = color; + mColorPtr = NULL; +} + +void LLUIColor::set(const LLUIColor* color) +{ + mColorPtr = color; +} + +const LLColor4& LLUIColor::get() const +{ + return (mColorPtr == NULL ? mColor : mColorPtr->get()); +} + +LLUIColor::operator const LLColor4& () const +{ + return get(); +} + +const LLColor4& LLUIColor::operator()() const +{ + return get(); +} + +bool LLUIColor::isReference() const +{ + return mColorPtr != NULL; +} + +namespace LLInitParam +{ + // used to detect equivalence with default values on export + bool ParamCompare::equals(const LLUIColor &a, const LLUIColor &b) + { + // do not detect value equivalence, treat pointers to colors as distinct from color values + return (a.mColorPtr == NULL && b.mColorPtr == NULL ? a.mColor == b.mColor : a.mColorPtr == b.mColorPtr); + } +} diff --git a/indra/llxuixml/lluicolor.h b/indra/llxuixml/lluicolor.h new file mode 100644 index 000000000..97ebea854 --- /dev/null +++ b/indra/llxuixml/lluicolor.h @@ -0,0 +1,71 @@ +/** + * @file lluicolor.h + * @brief brief LLUIColor class header file + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLUICOLOR_H_ +#define LL_LLUICOLOR_H_ + +#include "v4color.h" + +namespace LLInitParam +{ + template + struct ParamCompare; +} + +class LLUIColor +{ +public: + LLUIColor(); + LLUIColor(const LLColor4& color); + LLUIColor(const LLUIColor* color); + + void set(const LLColor4& color); + void set(const LLUIColor* color); + + const LLColor4& get() const; + + operator const LLColor4& () const; + const LLColor4& operator()() const; + + bool isReference() const; + +private: + friend struct LLInitParam::ParamCompare; + + const LLUIColor* mColorPtr; + LLColor4 mColor; +}; + +namespace LLInitParam +{ + template<> + struct ParamCompare + { + static bool equals(const LLUIColor& a, const LLUIColor& b); + }; +} + +#endif diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cf3f2a06f..d8d68a706 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -37,6 +37,7 @@ include(LLUI) include(LLVFS) include(LLWindow) include(LLXML) +include(LLXUIXML) include(LScript) include(Linking) include(NDOF) @@ -71,6 +72,7 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LLXUIXML_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS}/lscript_compile ) @@ -1535,6 +1537,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLVFS_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLXML_LIBRARIES} + ${LLXUIXML_LIBRARIES} ${LSCRIPT_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} diff --git a/indra/newview/llbuildnewviewsscheduler.cpp b/indra/newview/llbuildnewviewsscheduler.cpp index 541c792e2..23ac8eaf0 100644 --- a/indra/newview/llbuildnewviewsscheduler.cpp +++ b/indra/newview/llbuildnewviewsscheduler.cpp @@ -106,7 +106,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento if (itemp) { - itemp->mDelayedDelete = TRUE; + //itemp->mDelayedDelete = TRUE; if (parent_folder) { itemp->addToFolder(parent_folder, panelp->getRootFolder()); diff --git a/indra/newview/statemachine/CMakeLists.txt b/indra/newview/statemachine/CMakeLists.txt index 86f19107e..d36caca38 100644 --- a/indra/newview/statemachine/CMakeLists.txt +++ b/indra/newview/statemachine/CMakeLists.txt @@ -9,6 +9,7 @@ include(LLMessage) # This is needed by LLPlugin. include(LLMath) include(LLVFS) include(LLXML) +include(LLXUIXML) include(LLWindow) include(LLUI) include(LLRender) @@ -25,6 +26,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LLXUIXML_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLUI_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} From dcec1cb5f20f5924610ab5826571cfd5058388e9 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 24 Feb 2012 20:18:46 -0600 Subject: [PATCH 14/32] LLViewerWindow::handlePerFrameHover renamed to LLViewerWindow::updateUI. Migrated some code to LLViewerWindow::updateMouseDelta, but made no functional change. Use LLSelectMgr to look up selected textures for texture view (opposed to soon-to-be-removed llhoverview) --- indra/newview/llappviewer.cpp | 2 +- indra/newview/llstartup.cpp | 2 +- indra/newview/lltextureview.cpp | 64 +++++++++++----------- indra/newview/llviewerdisplay.cpp | 2 +- indra/newview/llviewerwindow.cpp | 90 ++++++++++++++++--------------- indra/newview/llviewerwindow.h | 3 +- 6 files changed, 87 insertions(+), 76 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3c4cbd97f..f92fa1d56 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3912,7 +3912,7 @@ void LLAppViewer::idle() return; } - gViewerWindow->handlePerFrameHover(); + gViewerWindow->updateUI(); /////////////////////////////////////// // Agent and camera movement diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index bd584bc6c..8a880d1bd 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -399,7 +399,7 @@ bool idle_startup() // until initialization is complete, but need to be done here for things // to work. gIdleCallbacks.callFunctions(); - gViewerWindow->handlePerFrameHover(); + gViewerWindow->updateUI(); LLMortician::updateClass(); if (gNoRender) diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index a264e30b5..ab55f6988 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -747,52 +747,56 @@ void LLTextureView::draw() if (!mOrderFetch) { #if 1 - if (pri < HIGH_PRIORITY && LLSelectMgr::getInstance()) - { - struct f : public LLSelectedTEFunctor + if (pri < HIGH_PRIORITY && LLSelectMgr::getInstance()) { - LLViewerFetchedTexture* mImage; - f(LLViewerFetchedTexture* image) : mImage(image) {} - virtual bool apply(LLViewerObject* object, S32 te) + struct f : public LLSelectedTEFunctor { - return (mImage == object->getTEImage(te)); + LLViewerFetchedTexture* mImage; + f(LLViewerFetchedTexture* image) : mImage(image) {} + virtual bool apply(LLViewerObject* object, S32 te) + { + return (mImage == object->getTEImage(te)); + } + } func(imagep); + const bool firstonly = true; + bool match = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, firstonly); + if (match) + { + pri += 3*HIGH_PRIORITY; } - } func(imagep); - const bool firstonly = true; - bool match = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, firstonly); - if (match) - { - pri += 3*HIGH_PRIORITY; } - } #endif #if 1 - if (pri < HIGH_PRIORITY && (cur_discard< 0 || desired_discard < cur_discard)) - { - LLViewerObject *objectp = gHoverView->getLastHoverObject(); - if (objectp) + if (pri < HIGH_PRIORITY && (cur_discard< 0 || desired_discard < cur_discard)) { - S32 tex_count = objectp->getNumTEs(); - for (S32 i = 0; i < tex_count; i++) + LLSelectNode* hover_node = LLSelectMgr::instance().getHoverNode(); + if (hover_node) { - if (imagep == objectp->getTEImage(i)) + LLViewerObject *objectp = hover_node->getObject(); + if (objectp) { - pri += 2*HIGH_PRIORITY; - break; + S32 tex_count = objectp->getNumTEs(); + for (S32 i = 0; i < tex_count; i++) + { + if (imagep == objectp->getTEImage(i)) + { + pri += 2*HIGH_PRIORITY; + break; + } + } } } } - } #endif #if 1 - if (pri > 0.f && pri < HIGH_PRIORITY) - { - if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f || - imagep->mFetchDeltaTime < 0.25f) + if (pri > 0.f && pri < HIGH_PRIORITY) { - pri += 1*HIGH_PRIORITY; + if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f || + imagep->mFetchDeltaTime < 0.25f) + { + pri += 1*HIGH_PRIORITY; + } } - } #endif } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index bc297bcb0..30d00b6c6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -152,7 +152,7 @@ void display_startup() LLGLState::checkStates(); LLGLState::checkTextureChannels(); - gViewerWindow->handlePerFrameHover(); // Fix ui flicker. + gViewerWindow->updateUI(); // Fix ui flicker. glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); LLGLSUIDefault gls_ui; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f06fce3e4..130ecfe74 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2793,7 +2793,7 @@ void LLViewerWindow::moveCursorToCenter() // Update UI based on stored mouse position from mouse-move // event processing. -BOOL LLViewerWindow::handlePerFrameHover() +void LLViewerWindow::updateUI() { static LLFastTimer::DeclareTimer ftm("Update UI"); LLFastTimer t(ftm); @@ -2819,51 +2819,13 @@ BOOL LLViewerWindow::handlePerFrameHover() &gDebugRaycastStart, &gDebugRaycastEnd); } - //RN: fix for asynchronous notification of mouse leaving window not working - LLCoordWindow mouse_pos; - mWindow->getCursorPosition(&mouse_pos); - if (mouse_pos.mX < 0 || - mouse_pos.mY < 0 || - mouse_pos.mX > mWindowRectRaw.getWidth() || - mouse_pos.mY > mWindowRectRaw.getHeight()) - { - mMouseInWindow = FALSE; - } - else - { - mMouseInWindow = TRUE; - } + updateMouseDelta(); - S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); - S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); - - LLVector2 mouse_vel; - - static const LLCachedControl mouse_smooth("MouseSmooth",false); - if (mouse_smooth) - { - static F32 fdx = 0.f; - static F32 fdy = 0.f; - - F32 amount = 16.f; - fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); - fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); - - mCurrentMouseDelta.set(llround(fdx), llround(fdy)); - mouse_vel.setVec(fdx,fdy); - } - else - { - mCurrentMouseDelta.set(dx, dy); - mouse_vel.setVec((F32) dx, (F32) dy); - } - - mMouseVelocityStat.addValue(mouse_vel.magVec()); if (gNoRender) { - return TRUE; + return; } // clean up current focus @@ -3239,7 +3201,7 @@ BOOL LLViewerWindow::handlePerFrameHover() previous_x = x; previous_y = y; - return handled; + return; } @@ -3250,6 +3212,50 @@ void LLViewerWindow::hoverPickCallback(const LLPickInfo& pick_info) } +void LLViewerWindow::updateMouseDelta() +{ + S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); + S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); + + //RN: fix for asynchronous notification of mouse leaving window not working + LLCoordWindow mouse_pos; + mWindow->getCursorPosition(&mouse_pos); + if (mouse_pos.mX < 0 || + mouse_pos.mY < 0 || + mouse_pos.mX > mWindowRectRaw.getWidth() || + mouse_pos.mY > mWindowRectRaw.getHeight()) + { + mMouseInWindow = FALSE; + } + else + { + mMouseInWindow = TRUE; + } + + LLVector2 mouse_vel; + + static const LLCachedControl mouse_smooth("MouseSmooth",false); + if (mouse_smooth) + { + static F32 fdx = 0.f; + static F32 fdy = 0.f; + + F32 amount = 16.f; + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + + mCurrentMouseDelta.set(llround(fdx), llround(fdy)); + mouse_vel.setVec(fdx,fdy); + } + else + { + mCurrentMouseDelta.set(dx, dy); + mouse_vel.setVec((F32) dx, (F32) dy); + } + + mMouseVelocityStat.addValue(mouse_vel.magVec()); +} + void LLViewerWindow::saveLastMouse(const LLCoordGL &point) { // Store last mouse location. diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 86ca05fb4..30848b386 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -282,7 +282,8 @@ public: void updateObjectUnderCursor(); - BOOL handlePerFrameHover(); // Once per frame, update UI based on mouse position + void updateUI(); // Once per frame, update UI based on mouse position + void updateMouseDelta(); BOOL handleKey(KEY key, MASK mask); void handleScrollWheel (S32 clicks); From 2bf940e15d24b5b1014b15aa761efecf3aadd502 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 27 Feb 2012 02:53:12 -0600 Subject: [PATCH 15/32] Fixed up inventory filter. Basic folders now have an 'open' icon. Tweaked the indent size for inventory (looks a little nicer imo) --- indra/llui/llscrollbar.cpp | 80 +-- indra/llui/llscrollbar.h | 5 +- indra/llui/llscrollcontainer.cpp | 541 ++++++++-------- indra/llui/llscrollcontainer.h | 26 +- indra/llui/llview.cpp | 7 + indra/llui/llview.h | 6 +- indra/newview/llbuildnewviewsscheduler.cpp | 2 + indra/newview/llfolderview.cpp | 371 +++++++---- indra/newview/llfolderview.h | 43 +- indra/newview/llfoldervieweventlistener.h | 6 +- indra/newview/llfolderviewitem.cpp | 701 +++++++++++---------- indra/newview/llfolderviewitem.h | 108 ++-- indra/newview/llinventoryactions.cpp | 11 +- indra/newview/llinventorybackup.cpp | 3 +- indra/newview/llinventorybridge.cpp | 19 +- indra/newview/llinventoryfilter.cpp | 371 +++++++++-- indra/newview/llinventoryfilter.h | 83 ++- indra/newview/llinventorypanel.cpp | 92 ++- indra/newview/llinventorypanel.h | 18 +- indra/newview/lllocalinventory.cpp | 3 +- indra/newview/llpanelmaininventory.cpp | 153 ++--- indra/newview/llpanelmaininventory.h | 5 +- indra/newview/llpanelobjectinventory.cpp | 42 +- indra/newview/llpanelobjectinventory.h | 4 +- indra/newview/llviewerfoldertype.cpp | 24 +- indra/newview/llviewermessage.cpp | 9 +- 26 files changed, 1656 insertions(+), 1077 deletions(-) diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index 825a411c4..dad9b3d55 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -73,7 +73,8 @@ LLScrollbar::LLScrollbar( mHighlightColor ( LLUI::sColorsGroup->getColor("DefaultHighlightLight") ), mShadowColor ( LLUI::sColorsGroup->getColor("DefaultShadowLight") ), mOnScrollEndCallback( NULL ), - mOnScrollEndData( NULL ) + mOnScrollEndData( NULL ), + mThickness( SCROLLBAR_SIZE ) { //llassert( 0 <= mDocSize ); //llassert( 0 <= mDocPos && mDocPos <= mDocSize ); @@ -92,22 +93,22 @@ LLScrollbar::LLScrollbar( if( LLScrollbar::VERTICAL == mOrientation ) { - line_up_rect.setLeftTopAndSize( 0, getRect().getHeight(), SCROLLBAR_SIZE, SCROLLBAR_SIZE ); + line_up_rect.setLeftTopAndSize( 0, getRect().getHeight(), mThickness, mThickness ); line_up_img="UIImgBtnScrollUpOutUUID"; line_up_selected_img="UIImgBtnScrollUpInUUID"; - line_down_rect.setOriginAndSize( 0, 0, SCROLLBAR_SIZE, SCROLLBAR_SIZE ); + line_down_rect.setOriginAndSize( 0, 0, mThickness, mThickness ); line_down_img="UIImgBtnScrollDownOutUUID"; line_down_selected_img="UIImgBtnScrollDownInUUID"; } else { // Horizontal - line_up_rect.setOriginAndSize( 0, 0, SCROLLBAR_SIZE, SCROLLBAR_SIZE ); + line_up_rect.setOriginAndSize( 0, 0, mThickness, mThickness ); line_up_img="UIImgBtnScrollLeftOutUUID"; line_up_selected_img="UIImgBtnScrollLeftInUUID"; - line_down_rect.setOriginAndSize( getRect().getWidth() - SCROLLBAR_SIZE, 0, SCROLLBAR_SIZE, SCROLLBAR_SIZE ); + line_down_rect.setOriginAndSize( getRect().getWidth() - mThickness, 0, mThickness, mThickness ); line_down_img="UIImgBtnScrollRightOutUUID"; line_down_selected_img="UIImgBtnScrollRightInUUID"; } @@ -158,7 +159,8 @@ void LLScrollbar::setDocParams( S32 size, S32 pos ) updateThumbRect(); } -void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb) +// returns true if document position really changed +bool LLScrollbar::setDocPos(S32 pos, BOOL update_thumb) { pos = llclamp(pos, 0, getDocPosMax()); if (pos != mDocPos) @@ -175,7 +177,9 @@ void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb) { updateThumbRect(); } + return true; } + return false; } void LLScrollbar::setDocSize(S32 size) @@ -221,7 +225,7 @@ void LLScrollbar::updateThumbRect() const S32 THUMB_MIN_LENGTH = 16; S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight(); - S32 thumb_bg_length = llmax(0, window_length - 2 * SCROLLBAR_SIZE); + S32 thumb_bg_length = llmax(0, window_length - 2 * mThickness); S32 visible_lines = llmin( mDocSize, mPageSize ); S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length; @@ -229,24 +233,24 @@ void LLScrollbar::updateThumbRect() if( mOrientation == LLScrollbar::VERTICAL ) { - S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE; - S32 thumb_start_min = SCROLLBAR_SIZE + THUMB_MIN_LENGTH; + S32 thumb_start_max = thumb_bg_length + mThickness; + S32 thumb_start_min = mThickness + THUMB_MIN_LENGTH; S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max; mThumbRect.mLeft = 0; mThumbRect.mTop = thumb_start; - mThumbRect.mRight = SCROLLBAR_SIZE; + mThumbRect.mRight = mThickness; mThumbRect.mBottom = thumb_start - thumb_length; } else { // Horizontal - S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE - thumb_length; - S32 thumb_start_min = SCROLLBAR_SIZE; + S32 thumb_start_max = thumb_bg_length + mThickness - thumb_length; + S32 thumb_start_min = mThickness; S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min; mThumbRect.mLeft = thumb_start; - mThumbRect.mTop = SCROLLBAR_SIZE; + mThumbRect.mTop = mThickness; mThumbRect.mRight = thumb_start + thumb_length; mThumbRect.mBottom = 0; } @@ -318,21 +322,21 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) // S32 old_pos = mThumbRect.mTop; S32 delta_pixels = y - mDragStartY; - if( mOrigRect.mBottom + delta_pixels < SCROLLBAR_SIZE ) + if( mOrigRect.mBottom + delta_pixels < mThickness ) { - delta_pixels = SCROLLBAR_SIZE - mOrigRect.mBottom - 1; + delta_pixels = mThickness - mOrigRect.mBottom - 1; } else - if( mOrigRect.mTop + delta_pixels > height - SCROLLBAR_SIZE ) + if( mOrigRect.mTop + delta_pixels > height - mThickness ) { - delta_pixels = height - SCROLLBAR_SIZE - mOrigRect.mTop + 1; + delta_pixels = height - mThickness - mOrigRect.mTop + 1; } mThumbRect.mTop = mOrigRect.mTop + delta_pixels; mThumbRect.mBottom = mOrigRect.mBottom + delta_pixels; S32 thumb_length = mThumbRect.getHeight(); - S32 thumb_track_length = height - 2 * SCROLLBAR_SIZE; + S32 thumb_track_length = height - 2 * mThickness; if( delta_pixels != mLastDelta || mDocChanged) @@ -343,7 +347,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) { S32 variable_lines = getDocPosMax(); S32 pos = mThumbRect.mTop; - F32 ratio = F32(pos - SCROLLBAR_SIZE - thumb_length) / usable_track_length; + F32 ratio = F32(pos - mThickness - thumb_length) / usable_track_length; S32 new_pos = llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines ); // Note: we do not call updateThumbRect() here. Instead we let the thumb and the document go slightly @@ -362,21 +366,21 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) S32 delta_pixels = x - mDragStartX; - if( mOrigRect.mLeft + delta_pixels < SCROLLBAR_SIZE ) + if( mOrigRect.mLeft + delta_pixels < mThickness ) { - delta_pixels = SCROLLBAR_SIZE - mOrigRect.mLeft - 1; + delta_pixels = mThickness - mOrigRect.mLeft - 1; } else - if( mOrigRect.mRight + delta_pixels > width - SCROLLBAR_SIZE ) + if( mOrigRect.mRight + delta_pixels > width - mThickness ) { - delta_pixels = width - SCROLLBAR_SIZE - mOrigRect.mRight + 1; + delta_pixels = width - mThickness - mOrigRect.mRight + 1; } mThumbRect.mLeft = mOrigRect.mLeft + delta_pixels; mThumbRect.mRight = mOrigRect.mRight + delta_pixels; S32 thumb_length = mThumbRect.getWidth(); - S32 thumb_track_length = width - 2 * SCROLLBAR_SIZE; + S32 thumb_track_length = width - 2 * mThickness; if( delta_pixels != mLastDelta || mDocChanged) { @@ -386,7 +390,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) { S32 variable_lines = getDocPosMax(); S32 pos = mThumbRect.mLeft; - F32 ratio = F32(pos - SCROLLBAR_SIZE) / usable_track_length; + F32 ratio = F32(pos - mThickness) / usable_track_length; S32 new_pos = llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines); @@ -405,7 +409,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) } else { - handled = childrenHandleMouseUp( x, y, mask ) != NULL; + handled = childrenHandleHover( x, y, mask ) != NULL; } // Opaque @@ -423,8 +427,8 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks) { - changeLine( clicks * mStepSize, TRUE ); - return TRUE; + BOOL handled = changeLine( clicks * mStepSize, TRUE ); + return handled; } BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -475,14 +479,14 @@ void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent) if (mOrientation == VERTICAL) { - up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE)); - down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE)); + up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); + down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); up_button->setOrigin(up_button->getRect().mLeft, getRect().getHeight() - up_button->getRect().getHeight()); } else { - up_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), up_button->getRect().getHeight()); - down_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), down_button->getRect().getHeight()); + up_button->reshape(llmin(getRect().getWidth() / 2, mThickness), up_button->getRect().getHeight()); + down_button->reshape(llmin(getRect().getWidth() / 2, mThickness), down_button->getRect().getHeight()); down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), down_button->getRect().mBottom); } updateThumbRect(); @@ -513,10 +517,10 @@ void LLScrollbar::draw() if (!rounded_rect_imagep) { - gl_rect_2d(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0, - mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(), - mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * SCROLLBAR_SIZE : getRect().getWidth(), - mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0, mTrackColor, TRUE); + gl_rect_2d(mOrientation == HORIZONTAL ? mThickness : 0, + mOrientation == VERTICAL ? getRect().getHeight() - 2 * mThickness : getRect().getHeight(), + mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * mThickness : getRect().getWidth(), + mOrientation == VERTICAL ? mThickness : 0, mTrackColor, TRUE); gl_rect_2d(mThumbRect, mThumbColor, TRUE); @@ -560,9 +564,9 @@ void LLScrollbar::draw() } // end draw -void LLScrollbar::changeLine( S32 delta, BOOL update_thumb ) +bool LLScrollbar::changeLine( S32 delta, BOOL update_thumb ) { - setDocPos(mDocPos + delta, update_thumb); + return setDocPos(mDocPos + delta, update_thumb); } void LLScrollbar::setValue(const LLSD& value) diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index 0bbf8662a..da13ff2af 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -82,7 +82,7 @@ public: // How many "lines" the "document" has scrolled. // 0 <= DocPos <= DocSize - DocVisibile - void setDocPos( S32 pos, BOOL update_thumb = TRUE ); + bool setDocPos( S32 pos, BOOL update_thumb = TRUE ); S32 getDocPos() const { return mDocPos; } BOOL isAtBeginning(); @@ -113,7 +113,7 @@ public: private: void updateThumbRect(); - void changeLine(S32 delta, BOOL update_thumb ); + bool changeLine(S32 delta, BOOL update_thumb ); void (*mChangeCallback)( S32 new_pos, LLScrollbar* self, void* userdata ); void* mCallbackUserData; @@ -142,6 +142,7 @@ private: void (*mOnScrollEndCallback)(void*); void *mOnScrollEndData; + S32 mThickness; }; diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index a6e30581e..8e740384a 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -69,52 +69,31 @@ LLScrollableContainerView::LLScrollableContainerView( const std::string& name, BOOL is_opaque, const LLColor4& bg_color ) : LLUICtrl( name, rect, FALSE, NULL, NULL ), - mScrolledView( scrolled_view ), - mIsOpaque( is_opaque ), - mBackgroundColor( bg_color ), - mReserveScrollCorner( FALSE ), mAutoScrolling( FALSE ), - mAutoScrollRate( 0.f ) + mAutoScrollRate( 0.f ), + mBackgroundColor( bg_color ), + mIsOpaque( is_opaque ), + mHideScrollbar( FALSE ), + mReserveScrollCorner( FALSE ), + mMinAutoScrollRate( MIN_AUTO_SCROLL_RATE ), + mMaxAutoScrollRate( MAX_AUTO_SCROLL_RATE ), + mScrolledView( scrolled_view ) { if( mScrolledView ) { - addChild( mScrolledView ); + LLView::addChild( mScrolledView ); } - init(); -} - -// LLUICtrl constructor -LLScrollableContainerView::LLScrollableContainerView( const std::string& name, const LLRect& rect, - LLUICtrl* scrolled_ctrl, BOOL is_opaque, - const LLColor4& bg_color) : - LLUICtrl( name, rect, FALSE, NULL, NULL ), - mScrolledView( scrolled_ctrl ), - mIsOpaque( is_opaque ), - mBackgroundColor( bg_color ), - mReserveScrollCorner( FALSE ), - mAutoScrolling( FALSE ), - mAutoScrollRate( 0.f ) -{ - if( scrolled_ctrl ) - { - addChild( scrolled_ctrl ); - } - - init(); -} - -void LLScrollableContainerView::init() -{ + S32 scrollbar_size = SCROLLBAR_SIZE; LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 ); mBorder = new LLViewBorder( std::string("scroll border"), border_rect, LLViewBorder::BEVEL_IN ); - addChild( mBorder ); + LLView::addChild( mBorder ); mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - mInnerRect.stretch( -mBorder->getBorderWidth() ); + mInnerRect.stretch( -getBorderWidth() ); LLRect vertical_scroll_rect = mInnerRect; - vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - SCROLLBAR_SIZE; + vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size; mScrollbar[VERTICAL] = new LLScrollbar( std::string("scrollable vertical"), vertical_scroll_rect, LLScrollbar::VERTICAL, @@ -123,14 +102,14 @@ void LLScrollableContainerView::init() mInnerRect.getHeight(), NULL, this, VERTICAL_MULTIPLE); - addChild( mScrollbar[VERTICAL] ); + LLView::addChild( mScrollbar[VERTICAL] ); mScrollbar[VERTICAL]->setVisible( FALSE ); mScrollbar[VERTICAL]->setFollowsRight(); mScrollbar[VERTICAL]->setFollowsTop(); mScrollbar[VERTICAL]->setFollowsBottom(); LLRect horizontal_scroll_rect = mInnerRect; - horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + SCROLLBAR_SIZE; + horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + scrollbar_size; mScrollbar[HORIZONTAL] = new LLScrollbar( std::string("scrollable horizontal"), horizontal_scroll_rect, LLScrollbar::HORIZONTAL, @@ -139,7 +118,7 @@ void LLScrollableContainerView::init() mInnerRect.getWidth(), NULL, this, HORIZONTAL_MULTIPLE); - addChild( mScrollbar[HORIZONTAL] ); + LLView::addChild( mScrollbar[HORIZONTAL] ); mScrollbar[HORIZONTAL]->setVisible( FALSE ); mScrollbar[HORIZONTAL]->setFollowsLeft(); mScrollbar[HORIZONTAL]->setFollowsRight(); @@ -190,8 +169,8 @@ void LLScrollableContainerView::reshape(S32 width, S32 height, { LLUICtrl::reshape( width, height, called_from_parent ); - mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - mInnerRect.stretch( -mBorder->getBorderWidth() ); + mInnerRect = getLocalRect(); + mInnerRect.stretch( -getBorderWidth() ); if (mScrolledView) { @@ -201,22 +180,33 @@ void LLScrollableContainerView::reshape(S32 width, S32 height, S32 visible_height = 0; BOOL show_v_scrollbar = FALSE; BOOL show_h_scrollbar = FALSE; - calcVisibleSize( scrolled_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); mScrollbar[VERTICAL]->setPageSize( visible_height ); mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); mScrollbar[HORIZONTAL]->setPageSize( visible_width ); + updateScroll(); } } BOOL LLScrollableContainerView::handleKeyHere(KEY key, MASK mask) { + // allow scrolled view to handle keystrokes in case it delegated keyboard focus + // to the scroll container. + // NOTE: this should not recurse indefinitely as handleKeyHere + // should not propagate to parent controls, so mScrolledView should *not* + // call LLScrollContainer::handleKeyHere in turn + if (mScrolledView && mScrolledView->handleKeyHere(key, mask)) + { + return TRUE; + } for( S32 i = 0; i < SCROLLBAR_COUNT; i++ ) { if( mScrollbar[i]->handleKeyHere(key, mask) ) { + updateScroll(); return TRUE; } } @@ -226,38 +216,37 @@ BOOL LLScrollableContainerView::handleKeyHere(KEY key, MASK mask) BOOL LLScrollableContainerView::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - for( S32 i = 0; i < SCROLLBAR_COUNT; i++ ) - { - // Note: tries vertical and then horizontal + // Give event to my child views - they may have scroll bars + // (Bad UI design, but technically possible.) + if (LLUICtrl::handleScrollWheel(x,y,clicks)) + return TRUE; + // When the vertical scrollbar is visible, scroll wheel + // only affects vertical scrolling. It's confusing to have + // scroll wheel perform both vertical and horizontal in a + // single container. + LLScrollbar* vertical = mScrollbar[VERTICAL]; + if (vertical->getVisible() + && vertical->getEnabled()) + { // Pretend the mouse is over the scrollbar - if( mScrollbar[i]->handleScrollWheel( 0, 0, clicks ) ) + if (vertical->handleScrollWheel( 0, 0, clicks ) ) { - return TRUE; + updateScroll(); } + // Always eat the event + return TRUE; } - // Eat scroll wheel event (to avoid scrolling nested containers?) - return TRUE; -} - -BOOL LLScrollableContainerView::needsToScroll(S32 x, S32 y, LLScrollableContainerView::SCROLL_ORIENTATION axis) const -{ - if(mScrollbar[axis]->getVisible()) + LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; + // Test enablement and visibility for consistency with + // LLView::childrenHandleScrollWheel(). + if (horizontal->getVisible() + && horizontal->getEnabled() + && horizontal->handleScrollWheel( 0, 0, clicks ) ) { - LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 ); - const S32 AUTOSCROLL_SIZE = 10; - if(mScrollbar[axis]->getVisible()) - { - inner_rect_local.mRight -= SCROLLBAR_SIZE; - inner_rect_local.mTop += AUTOSCROLL_SIZE; - inner_rect_local.mBottom = inner_rect_local.mTop - AUTOSCROLL_SIZE; - } - if( inner_rect_local.pointInRect( x, y ) && (mScrollbar[axis]->getDocPos() > 0) ) - { - return TRUE; - } - + updateScroll(); + return TRUE; } return FALSE; } @@ -269,65 +258,10 @@ BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask, EAcceptance* accept, std::string& tooltip_msg) { + //S32 scrollbar_size = SCROLLBAR_SIZE; // Scroll folder view if needed. Never accepts a drag or drop. *accept = ACCEPT_NO; - BOOL handled = FALSE; - if( mScrollbar[HORIZONTAL]->getVisible() || mScrollbar[VERTICAL]->getVisible() ) - { - const S32 AUTOSCROLL_SIZE = 10; - S32 auto_scroll_speed = llround(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); - - LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 ); - if( mScrollbar[HORIZONTAL]->getVisible() ) - { - inner_rect_local.mBottom += SCROLLBAR_SIZE; - } - if( mScrollbar[VERTICAL]->getVisible() ) - { - inner_rect_local.mRight -= SCROLLBAR_SIZE; - } - - if( mScrollbar[HORIZONTAL]->getVisible() ) - { - LLRect left_scroll_rect = inner_rect_local; - left_scroll_rect.mRight = AUTOSCROLL_SIZE; - if( left_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() > 0) ) - { - mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() - auto_scroll_speed ); - mAutoScrolling = TRUE; - handled = TRUE; - } - - LLRect right_scroll_rect = inner_rect_local; - right_scroll_rect.mLeft = inner_rect_local.mRight - AUTOSCROLL_SIZE; - if( right_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() < mScrollbar[HORIZONTAL]->getDocPosMax()) ) - { - mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() + auto_scroll_speed ); - mAutoScrolling = TRUE; - handled = TRUE; - } - } - if( mScrollbar[VERTICAL]->getVisible() ) - { - LLRect bottom_scroll_rect = inner_rect_local; - bottom_scroll_rect.mTop = AUTOSCROLL_SIZE + bottom_scroll_rect.mBottom; - if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() < mScrollbar[VERTICAL]->getDocPosMax()) ) - { - mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() + auto_scroll_speed ); - mAutoScrolling = TRUE; - handled = TRUE; - } - - LLRect top_scroll_rect = inner_rect_local; - top_scroll_rect.mBottom = inner_rect_local.mTop - AUTOSCROLL_SIZE; - if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() > 0) ) - { - mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() - auto_scroll_speed ); - mAutoScrolling = TRUE; - handled = TRUE; - } - } - } + BOOL handled = autoScroll(x, y); if( !handled ) { @@ -338,6 +272,78 @@ BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask, return TRUE; } +bool LLScrollableContainerView::autoScroll(S32 x, S32 y) +{ + S32 scrollbar_size = SCROLLBAR_SIZE; + + bool scrolling = false; + if( mScrollbar[HORIZONTAL]->getVisible() || mScrollbar[VERTICAL]->getVisible() ) + { + LLRect screen_local_extents; + screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents); + + LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 ); + if( mScrollbar[HORIZONTAL]->getVisible() ) + { + inner_rect_local.mBottom += scrollbar_size; + } + if( mScrollbar[VERTICAL]->getVisible() ) + { + inner_rect_local.mRight -= scrollbar_size; + } + + // clip rect against root view + inner_rect_local.intersectWith(screen_local_extents); + + S32 auto_scroll_speed = llround(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); + // autoscroll region should take up no more than one third of visible scroller area + S32 auto_scroll_region_width = llmin(inner_rect_local.getWidth() / 3, 10); + S32 auto_scroll_region_height = llmin(inner_rect_local.getHeight() / 3, 10); + + if( mScrollbar[HORIZONTAL]->getVisible() ) + { + LLRect left_scroll_rect = screen_local_extents; + left_scroll_rect.mRight = inner_rect_local.mLeft + auto_scroll_region_width; + if( left_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() > 0) ) + { + mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() - auto_scroll_speed ); + mAutoScrolling = TRUE; + scrolling = true; + } + + LLRect right_scroll_rect = screen_local_extents; + right_scroll_rect.mLeft = inner_rect_local.mRight - auto_scroll_region_width; + if( right_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() < mScrollbar[HORIZONTAL]->getDocPosMax()) ) + { + mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() + auto_scroll_speed ); + mAutoScrolling = TRUE; + scrolling = true; + } + } + if( mScrollbar[VERTICAL]->getVisible() ) + { + LLRect bottom_scroll_rect = screen_local_extents; + bottom_scroll_rect.mTop = inner_rect_local.mBottom + auto_scroll_region_height; + if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() < mScrollbar[VERTICAL]->getDocPosMax()) ) + { + mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() + auto_scroll_speed ); + mAutoScrolling = TRUE; + scrolling = true; + } + + LLRect top_scroll_rect = screen_local_extents; + top_scroll_rect.mBottom = inner_rect_local.mTop - auto_scroll_region_height; + if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() > 0) ) + { + mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() - auto_scroll_speed ); + mAutoScrolling = TRUE; + scrolling = true; + } + } + } + return scrolling; +} + BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) { @@ -368,42 +374,44 @@ BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, std::string& msg, LL void LLScrollableContainerView::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const { - const LLRect& rect = mScrolledView->getRect(); - calcVisibleSize(rect, visible_width, visible_height, show_h_scrollbar, show_v_scrollbar); -} - -void LLScrollableContainerView::calcVisibleSize( const LLRect& doc_rect, S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const -{ + const LLRect& doc_rect = getScrolledViewRect(); + S32 scrollbar_size = SCROLLBAR_SIZE; S32 doc_width = doc_rect.getWidth(); S32 doc_height = doc_rect.getHeight(); - *visible_width = getRect().getWidth() - 2 * mBorder->getBorderWidth(); - *visible_height = getRect().getHeight() - 2 * mBorder->getBorderWidth(); + S32 border_width = getBorderWidth(); + *visible_width = getRect().getWidth() - 2 * border_width; + *visible_height = getRect().getHeight() - 2 * border_width; *show_v_scrollbar = FALSE; - if( *visible_height < doc_height ) - { - *show_v_scrollbar = TRUE; - *visible_width -= SCROLLBAR_SIZE; - } - *show_h_scrollbar = FALSE; - if( *visible_width < doc_width ) - { - *show_h_scrollbar = TRUE; - *visible_height -= SCROLLBAR_SIZE; - // Must retest now that visible_height has changed - if( !*show_v_scrollbar && (*visible_height < doc_height) ) + if (!mHideScrollbar) + { + if( *visible_height < doc_height ) { *show_v_scrollbar = TRUE; - *visible_width -= SCROLLBAR_SIZE; + *visible_width -= scrollbar_size; + } + + if( *visible_width < doc_width ) + { + *show_h_scrollbar = TRUE; + *visible_height -= scrollbar_size; + + // Must retest now that visible_height has changed + if( !*show_v_scrollbar && (*visible_height < doc_height) ) + { + *show_v_scrollbar = TRUE; + *visible_width -= scrollbar_size; + } } } } void LLScrollableContainerView::draw() { + S32 scrollbar_size = SCROLLBAR_SIZE; if (mAutoScrolling) { // add acceleration to autoscroll @@ -411,76 +419,79 @@ void LLScrollableContainerView::draw() } else { - // reset to minimum - mAutoScrollRate = MIN_AUTO_SCROLL_RATE; + // reset to minimum for next time + mAutoScrollRate = mMinAutoScrollRate; } - // clear this flag to be set on next call to handleDragAndDrop + // clear this flag to be set on next call to autoScroll mAutoScrolling = FALSE; // auto-focus when scrollbar active // this allows us to capture user intent (i.e. stop automatically scrolling the view/etc) - if (!gFocusMgr.childHasKeyboardFocus(this) && - (mScrollbar[VERTICAL]->hasMouseCapture() || mScrollbar[HORIZONTAL]->hasMouseCapture())) + if (!hasFocus() + && (mScrollbar[VERTICAL]->hasMouseCapture() || mScrollbar[HORIZONTAL]->hasMouseCapture())) { focusFirstItem(); } - // Draw background - if( mIsOpaque ) + if (getRect().isValid()) { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( mBackgroundColor.mV ); - gl_rect_2d( mInnerRect ); - } + // Draw background + if( mIsOpaque ) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4fv( mBackgroundColor.mV ); + gl_rect_2d( mInnerRect ); + } - // Draw mScrolledViews and update scroll bars. - // get a scissor region ready, and draw the scrolling view. The - // scissor region ensures that we don't draw outside of the bounds - // of the rectangle. - if( mScrolledView ) - { - updateScroll(); - - // Draw the scrolled area. + // Draw mScrolledViews and update scroll bars. + // get a scissor region ready, and draw the scrolling view. The + // scissor region ensures that we don't draw outside of the bounds + // of the rectangle. + if( mScrolledView ) { - S32 visible_width = 0; - S32 visible_height = 0; - BOOL show_v_scrollbar = FALSE; - BOOL show_h_scrollbar = FALSE; - calcVisibleSize( mScrolledView->getRect(), &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + updateScroll(); - LLLocalClipRect clip(LLRect(mInnerRect.mLeft, - mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) + visible_height, - visible_width, - mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) - )); - drawChild(mScrolledView); + // Draw the scrolled area. + { + S32 visible_width = 0; + S32 visible_height = 0; + BOOL show_v_scrollbar = FALSE; + BOOL show_h_scrollbar = FALSE; + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + + LLLocalClipRect clip(LLRect(mInnerRect.mLeft, + mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, + mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), + mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + )); + drawChild(mScrolledView); + } } - } - // Highlight border if a child of this container has keyboard focus - if( mBorder->getVisible() ) - { - mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); - } + // Highlight border if a child of this container has keyboard focus + if( mBorder->getVisible() ) + { + mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); + } - // Draw all children except mScrolledView - // Note: scrollbars have been adjusted by above drawing code - for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); - child_iter != getChildList()->rend(); ++child_iter) - { - LLView *viewp = *child_iter; - if( sDebugRects ) + // Draw all children except mScrolledView + // Note: scrollbars have been adjusted by above drawing code + for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); + child_iter != getChildList()->rend(); ++child_iter) { - sDepth++; - } - if( (viewp != mScrolledView) && viewp->getVisible() ) - { - drawChild(viewp); - } - if( sDebugRects ) - { - sDepth--; + LLView *viewp = *child_iter; + if( sDebugRects ) + { + sDepth++; + } + if( (viewp != mScrolledView) && viewp->getVisible() ) + { + drawChild(viewp); + } + if( sDebugRects ) + { + sDepth--; + } } } @@ -491,9 +502,30 @@ void LLScrollableContainerView::draw() } // end draw +bool LLScrollableContainerView::addChild(LLView* view, S32 tab_group) +{ + if (!mScrolledView) + { + // Use the first panel or container as the scrollable view (bit of a hack) + mScrolledView = view; + } + + bool ret_val = LLView::addChild(view, tab_group); + + //bring the scrollbars to the front + sendChildToFront( mScrollbar[HORIZONTAL] ); + sendChildToFront( mScrollbar[VERTICAL] ); + + return ret_val; +} + void LLScrollableContainerView::updateScroll() { - if(!mScrolledView)return; + if (!mScrolledView) + { + return; + } + S32 scrollbar_size = SCROLLBAR_SIZE; LLRect doc_rect = mScrolledView->getRect(); S32 doc_width = doc_rect.getWidth(); S32 doc_height = doc_rect.getHeight(); @@ -501,9 +533,9 @@ void LLScrollableContainerView::updateScroll() S32 visible_height = 0; BOOL show_v_scrollbar = FALSE; BOOL show_h_scrollbar = FALSE; - calcVisibleSize( doc_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - S32 border_width = mBorder->getBorderWidth(); + S32 border_width = getBorderWidth(); if( show_v_scrollbar ) { if( doc_rect.mTop < getRect().getHeight() - border_width ) @@ -517,15 +549,15 @@ void LLScrollableContainerView::updateScroll() S32 v_scrollbar_height = visible_height; if( !show_h_scrollbar && mReserveScrollCorner ) { - v_scrollbar_height -= SCROLLBAR_SIZE; + v_scrollbar_height -= scrollbar_size; } - mScrollbar[VERTICAL]->reshape( SCROLLBAR_SIZE, v_scrollbar_height, TRUE ); + mScrollbar[VERTICAL]->reshape( scrollbar_size, v_scrollbar_height, TRUE ); // Make room for the horizontal scrollbar (or not) S32 v_scrollbar_offset = 0; if( show_h_scrollbar || mReserveScrollCorner ) { - v_scrollbar_offset = SCROLLBAR_SIZE; + v_scrollbar_offset = scrollbar_size; } LLRect r = mScrollbar[VERTICAL]->getRect(); r.translate( 0, mInnerRect.mBottom - r.mBottom + v_scrollbar_offset ); @@ -555,9 +587,9 @@ void LLScrollableContainerView::updateScroll() S32 h_scrollbar_width = visible_width; if( !show_v_scrollbar && mReserveScrollCorner ) { - h_scrollbar_width -= SCROLLBAR_SIZE; + h_scrollbar_width -= scrollbar_size; } - mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, SCROLLBAR_SIZE, TRUE ); + mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, scrollbar_size, TRUE ); } else { @@ -577,8 +609,19 @@ void LLScrollableContainerView::updateScroll() void LLScrollableContainerView::setBorderVisible(BOOL b) { mBorder->setVisible( b ); + // Recompute inner rect, as border visibility changes it + mInnerRect = getLocalRect(); + mInnerRect.stretch( -getBorderWidth() ); } +LLRect LLScrollableContainerView::getVisibleContentRect() +{ + updateScroll(); + LLRect visible_rect = getContentWindowRect(); + LLRect contents_rect = mScrolledView->getRect(); + visible_rect.translate(-contents_rect.mLeft, -contents_rect.mBottom); + return visible_rect; +} LLRect LLScrollableContainerView::getContentWindowRect() { updateScroll(); @@ -588,7 +631,7 @@ LLRect LLScrollableContainerView::getContentWindowRect() BOOL show_h_scrollbar = FALSE; BOOL show_v_scrollbar = FALSE; calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - S32 border_width = mBorder->getBorderWidth(); + S32 border_width = getBorderWidth(); scroller_view_rect.setOriginAndSize(border_width, show_h_scrollbar ? mScrollbar[HORIZONTAL]->getRect().mTop : border_width, visible_width, @@ -596,99 +639,85 @@ LLRect LLScrollableContainerView::getContentWindowRect() return scroller_view_rect; } -// Scroll so that as much of rect as possible is showing (where rect is defined in the space of scroller view, not scrolled) -void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLCoordGL& desired_offset) +// rect is in document coordinates, constraint is in display coordinates relative to content window rect +void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLRect& constraint) { if (!mScrolledView) { - llwarns << "LLScrollableContainerView::scrollToShowRect with no view!" << llendl; + llwarns << "LLScrollContainer::scrollToShowRect with no view!" << llendl; return; } - S32 visible_width = 0; - S32 visible_height = 0; - BOOL show_v_scrollbar = FALSE; - BOOL show_h_scrollbar = FALSE; - const LLRect& scrolled_rect = mScrolledView->getRect(); - calcVisibleSize( scrolled_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + LLRect content_window_rect = getContentWindowRect(); + // get document rect + LLRect scrolled_rect = mScrolledView->getRect(); - // can't be so far left that right side of rect goes off screen, or so far right that left side does - S32 horiz_offset = llclamp(desired_offset.mX, llmin(0, -visible_width + rect.getWidth()), 0); - // can't be so high that bottom of rect goes off screen, or so low that top does - S32 vert_offset = llclamp(desired_offset.mY, 0, llmax(0, visible_height - rect.getHeight())); + // shrink target rect to fit within constraint region, biasing towards top left + LLRect rect_to_constrain = rect; + rect_to_constrain.mBottom = llmax(rect_to_constrain.mBottom, rect_to_constrain.mTop - constraint.getHeight()); + rect_to_constrain.mRight = llmin(rect_to_constrain.mRight, rect_to_constrain.mLeft + constraint.getWidth()); - // Vertical - // 1. First make sure the top is visible - // 2. Then, if possible without hiding the top, make the bottom visible. - S32 vert_pos = mScrollbar[VERTICAL]->getDocPos(); + // calculate allowable positions for scroller window in document coordinates + LLRect allowable_scroll_rect(rect_to_constrain.mRight - constraint.mRight, + rect_to_constrain.mBottom - constraint.mBottom, + rect_to_constrain.mLeft - constraint.mLeft, + rect_to_constrain.mTop - constraint.mTop); - // find scrollbar position to get top of rect on screen (scrolling up) - S32 top_offset = scrolled_rect.mTop - rect.mTop - vert_offset; - // find scrollbar position to get bottom of rect on screen (scrolling down) - S32 bottom_offset = vert_offset == 0 ? scrolled_rect.mTop - rect.mBottom - visible_height : top_offset; - // scroll up far enough to see top or scroll down just enough if item is bigger than visual area - if( vert_pos >= top_offset || visible_height < rect.getHeight()) - { - vert_pos = top_offset; - } - // else scroll down far enough to see bottom - else - if( vert_pos <= bottom_offset ) - { - vert_pos = bottom_offset; - } + // translate from allowable region for lower left corner to upper left corner + allowable_scroll_rect.translate(0, content_window_rect.getHeight()); + + S32 vert_pos = llclamp(mScrollbar[VERTICAL]->getDocPos(), + mScrollbar[VERTICAL]->getDocSize() - allowable_scroll_rect.mTop, // min vertical scroll + mScrollbar[VERTICAL]->getDocSize() - allowable_scroll_rect.mBottom); // max vertical scroll mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); - mScrollbar[VERTICAL]->setPageSize( visible_height ); + mScrollbar[VERTICAL]->setPageSize( content_window_rect.getHeight() ); mScrollbar[VERTICAL]->setDocPos( vert_pos ); - // Horizontal - // 1. First make sure left side is visible - // 2. Then, if possible without hiding the left side, make the right side visible. - S32 horiz_pos = mScrollbar[HORIZONTAL]->getDocPos(); - S32 left_offset = rect.mLeft - scrolled_rect.mLeft + horiz_offset; - S32 right_offset = horiz_offset == 0 ? rect.mRight - scrolled_rect.mLeft - visible_width : left_offset; + S32 horizontal_pos = llclamp(mScrollbar[HORIZONTAL]->getDocPos(), + allowable_scroll_rect.mLeft, + allowable_scroll_rect.mRight); - if( horiz_pos >= left_offset || visible_width < rect.getWidth() ) - { - horiz_pos = left_offset; - } - else if( horiz_pos <= right_offset ) - { - horiz_pos = right_offset; - } - mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); - mScrollbar[HORIZONTAL]->setPageSize( visible_width ); - mScrollbar[HORIZONTAL]->setDocPos( horiz_pos ); + mScrollbar[HORIZONTAL]->setPageSize( content_window_rect.getWidth() ); + mScrollbar[HORIZONTAL]->setDocPos( horizontal_pos ); // propagate scroll to document updateScroll(); + + // In case we are in accordion tab notify parent to show selected rectangle + LLRect screen_rc; + localRectToScreen(rect_to_constrain, &screen_rc); + notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); } void LLScrollableContainerView::pageUp(S32 overlap) { mScrollbar[VERTICAL]->pageUp(overlap); + updateScroll(); } void LLScrollableContainerView::pageDown(S32 overlap) { mScrollbar[VERTICAL]->pageDown(overlap); + updateScroll(); } void LLScrollableContainerView::goToTop() { mScrollbar[VERTICAL]->setDocPos(0); + updateScroll(); } void LLScrollableContainerView::goToBottom() { mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocSize()); + updateScroll(); } S32 LLScrollableContainerView::getBorderWidth() const { - if (mBorder) + if (mBorder && mBorder->getVisible()) { return mBorder->getBorderWidth(); } diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 7aa08ce06..a5002a341 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -63,31 +63,29 @@ public: LLScrollableContainerView( const std::string& name, const LLRect& rect, LLView* scrolled_view, BOOL is_opaque = FALSE, const LLColor4& bg_color = LLColor4(0,0,0,0) ); - LLScrollableContainerView( const std::string& name, const LLRect& rect, - LLUICtrl* scrolled_ctrl, BOOL is_opaque = FALSE, - const LLColor4& bg_color = LLColor4(0,0,0,0) ); virtual ~LLScrollableContainerView( void ); void setScrolledView(LLView* view) { mScrolledView = view; } virtual void setValue(const LLSD& value) { mInnerRect.setValue(value); } - void calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const; - void calcVisibleSize( const LLRect& doc_rect, S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const; void setBorderVisible( BOOL b ); - void scrollToShowRect( const LLRect& rect, const LLCoordGL& desired_offset ); + void scrollToShowRect( const LLRect& rect, const LLRect& constraint); + void scrollToShowRect( const LLRect& rect) { scrollToShowRect(rect, LLRect(0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0)); } + void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; } + LLRect getVisibleContentRect(); LLRect getContentWindowRect(); const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } void pageUp(S32 overlap = 0); void pageDown(S32 overlap = 0); void goToTop(); void goToBottom(); + bool isAtTop() { return mScrollbar[VERTICAL]->isAtBeginning(); } + bool isAtBottom() { return mScrollbar[VERTICAL]->isAtEnd(); } S32 getBorderWidth() const; - BOOL needsToScroll(S32 x, S32 y, SCROLL_ORIENTATION axis) const; - // LLView functionality virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); virtual BOOL handleKeyHere(KEY key, MASK mask); @@ -100,8 +98,10 @@ public: virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect); virtual void draw(); - - virtual LLXMLNodePtr getXML(bool save_children = true) const; + virtual bool addChild(LLView* view, S32 tab_group = 0); + + bool autoScroll(S32 x, S32 y); + virtual LLXMLNodePtr getXML(bool save_children) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); private: @@ -111,6 +111,9 @@ private: virtual void scrollHorizontal( S32 new_pos ); virtual void scrollVertical( S32 new_pos ); void updateScroll(); +public: + void calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const; +private: LLScrollbar* mScrollbar[SCROLLBAR_COUNT]; LLView* mScrolledView; @@ -122,6 +125,9 @@ private: BOOL mReserveScrollCorner; BOOL mAutoScrolling; F32 mAutoScrollRate; + F32 mMinAutoScrollRate; + F32 mMaxAutoScrollRate; + bool mHideScrollbar; }; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index abb2cb75a..b63d6e609 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -3024,6 +3024,13 @@ LLSD LLView::getValue() const return LLSD(); } +S32 LLView::notifyParent(const LLSD& info) +{ + LLView* parent = getParent(); + if(parent) + return parent->notifyParent(info); + return 0; +} LLView* LLView::createWidget(LLXMLNodePtr xml_node) const { // forward requests to ui ctrl factory diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 194c7fc64..b937fb216 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -583,10 +583,14 @@ public: static LLWindow* getWindow(void) { return LLUI::sWindow; } virtual void handleReshape(const LLRect& rect, bool by_user); -protected: + virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleUnicodeCharHere(llwchar uni_char); + + //send custom notification to LLView parent + virtual S32 notifyParent(const LLSD& info); +protected: void drawDebugRect(); void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE); void drawChildren(); diff --git a/indra/newview/llbuildnewviewsscheduler.cpp b/indra/newview/llbuildnewviewsscheduler.cpp index 23ac8eaf0..16d2900ed 100644 --- a/indra/newview/llbuildnewviewsscheduler.cpp +++ b/indra/newview/llbuildnewviewsscheduler.cpp @@ -71,6 +71,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento if (new_listener) { LLFolderViewFolder* folderp = new LLFolderViewFolder(new_listener->getDisplayName(), + new_listener->getIcon(), new_listener->getIcon(), NULL, panelp->getRootFolder(), @@ -96,6 +97,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento itemp = new LLFolderViewItem(new_listener->getDisplayName(), new_listener->getIcon(), NULL, + NULL, new_listener->getCreationDate(), panelp->getRootFolder(), new_listener); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 52ac8f009..527e3f0f0 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -35,7 +35,6 @@ #include "llfolderview.h" #include "llcallbacklist.h" -#include "llfloaterinventory.h" #include "llinventorybridge.h" #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryfilter.h" @@ -43,6 +42,7 @@ #include "llinventorymodelbackgroundfetch.h" #include "llinventorypanel.h" #include "llfoldertype.h" +#include "llfloaterinventory.h"// hacked in for the bonus context menu items. #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" @@ -196,13 +196,13 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) ///---------------------------------------------------------------------------- // Default constructor -LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, +LLFolderView::LLFolderView( const std::string& name, const LLRect& rect, const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener ) : #if LL_WINDOWS #pragma warning( push ) #pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list #endif - LLFolderViewFolder( name, root_folder_icon, NULL, this, listener ), + LLFolderViewFolder( name, NULL, NULL, NULL, this, listener ), #if LL_WINDOWS #pragma warning( pop ) #endif @@ -210,17 +210,18 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic mScrollContainer( NULL ), mPopupMenuHandle(), mAllowMultiSelect(TRUE), + mShowEmptyMessage(TRUE), mShowFolderHierarchy(FALSE), mSourceID(source_id), mRenameItem( NULL ), mNeedsScroll( FALSE ), - mLastScrollItem( NULL ), + mUseLabelSuffix( TRUE ), + mPinningSelectedItem(FALSE), mNeedsAutoSelect( FALSE ), mAutoSelectOverride(FALSE), mNeedsAutoRename(FALSE), mDebugFilters(FALSE), mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME), // This gets overridden by a pref immediately - mSearchType(1), mFilter( new LLInventoryFilter(name) ), mShowSelectionContext(FALSE), mShowSingleSelection(FALSE), @@ -228,9 +229,14 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic mSignalSelectCallback(0), mMinWidth(0), mDragAndDropThisFrame(FALSE), - mParentPanel(parent_view) + mParentPanel(parent_view), + mUseEllipses(FALSE), + mSearchType(1) + { mRoot = this; + + mShowLoadStatus = TRUE; LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom); setRect( rect ); reshape(rect.getWidth(), rect.getHeight()); @@ -310,18 +316,6 @@ BOOL LLFolderView::canFocusChildren() const return FALSE; } -void LLFolderView::checkTreeResortForModelChanged() -{ - if (mSortOrder & LLInventoryFilter::SO_DATE && !(mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME)) - { - // This is the case where something got added or removed. If we are date sorting - // everything including folders, then we need to rebuild the whole tree. - // Just set to something not SO_DATE to force the folder most resent date resort. - mSortOrder = mSortOrder & ~LLInventoryFilter::SO_DATE; - setSortOrder(mSortOrder | LLInventoryFilter::SO_DATE); - } -} - static LLFastTimer::DeclareTimer FTM_SORT("Sort Inventory"); void LLFolderView::setSortOrder(U32 order) @@ -329,15 +323,10 @@ void LLFolderView::setSortOrder(U32 order) if (order != mSortOrder) { LLFastTimer t(FTM_SORT); + mSortOrder = order; - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->sortBy(order); - } - + sortBy(order); arrangeAll(); } } @@ -412,10 +401,7 @@ BOOL LLFolderView::addFolder( LLFolderViewFolder* folder) { mFolders.insert(mFolders.begin(), folder); } - if (folder->numSelected()) - { - recursiveIncrementNumDescendantsSelected(folder->numSelected()); - } + folder->setShowLoadStatus(mShowLoadStatus); folder->setOrigin(0, 0); folder->reshape(getRect().getWidth(), 0); folder->setVisible(FALSE); @@ -432,16 +418,6 @@ void LLFolderView::closeAllFolders() arrangeAll(); } -void LLFolderView::openFolder(const std::string& foldername) -{ - LLFolderViewFolder* inv = getChild(foldername); - if (inv) - { - setSelection(inv, FALSE, FALSE); - inv->setOpen(TRUE); - } -} - void LLFolderView::openTopLevelFolders() { for (folders_t::iterator iter = mFolders.begin(); @@ -508,6 +484,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen folderp->setVisible(show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter } + if (folderp->getVisible()) { S32 child_height = 0; @@ -604,6 +581,11 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent) } width = llmax(mMinWidth, scroll_rect.getWidth()); height = llmax(mRunningHeight, scroll_rect.getHeight()); + + // restrict width with scroll container's width + if (mUseEllipses) + width = scroll_rect.getWidth(); + LLView::reshape(width, height, called_from_parent); mReshapeSignal(mSelectedItems, FALSE); @@ -696,6 +678,30 @@ BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, return rv; } +void LLFolderView::setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + LLFolderViewItem* itemp = getItemByID(obj_id); + if(itemp && itemp->getListener()) + { + itemp->arrangeAndSet(TRUE, take_keyboard_focus); + mSelectThisID.setNull(); + return; + } + else + { + // save the desired item to be selected later (if/when ready) + mSelectThisID = obj_id; + } +} + +void LLFolderView::updateSelection() +{ + if (mSelectThisID.notNull()) + { + setSelectionByID(mSelectThisID, false); + } +} + BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) { BOOL rv = FALSE; @@ -738,26 +744,6 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) return rv; } -void LLFolderView::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items) -{ - // now store resulting selection - if (mAllowMultiSelect) - { - LLFolderViewItem *cur_selection = getCurSelectedItem(); - LLFolderViewFolder::extendSelection(selection, cur_selection, items); - for (S32 i = 0; i < items.count(); i++) - { - addToSelectionList(items[i]); - } - } - else - { - setSelection(selection, FALSE, FALSE); - } - - mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS; -} - static LLFastTimer::DeclareTimer FTM_SANITIZE_SELECTION("Sanitize Selection"); void LLFolderView::sanitizeSelection() { @@ -874,23 +860,27 @@ void LLFolderView::sanitizeSelection() void LLFolderView::clearSelection() { - if (mSelectedItems.size() > 0) + for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); + item_it != mSelectedItems.end(); + ++item_it) { - recursiveDeselect(FALSE); - mSelectedItems.clear(); + (*item_it)->setUnselected(); } + + mSelectedItems.clear(); + mSelectThisID.setNull(); } -BOOL LLFolderView::getSelectionList(std::set &selection) +std::set LLFolderView::getSelectionList() const { + std::set selection; for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) { selection.insert((*item_it)->getListener()->getUUID()); } - - return (selection.size() != 0); + return selection; } BOOL LLFolderView::startDrag(LLToolDragAndDrop::ESource source) @@ -972,7 +962,7 @@ void LLFolderView::draw() { mStatusText.clear(); } - else + else if (mShowEmptyMessage) { static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) @@ -987,7 +977,7 @@ void LLFolderView::draw() } } - LLFolderViewFolder::draw(); + LLView::draw(); mDragAndDropThisFrame = FALSE; } @@ -1013,10 +1003,8 @@ void LLFolderView::closeRenamer( void ) { if (mRenamer && mRenamer->getVisible()) { - if(mRenamer == gFocusMgr.getTopCtrl()) - gFocusMgr.setTopCtrl( NULL ); // Triggers onRenamerLost() that actually closes the renamer. - //gFocusMgr.setTopCtrl( NULL ); + gFocusMgr.setTopCtrl( NULL ); } } @@ -1255,7 +1243,9 @@ void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) mAutoOpenItems.push(item); item->setOpen(TRUE); - scrollToShowItem(item); + LLRect content_rect = mScrollContainer->getContentWindowRect(); + LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0); + scrollToShowItem(item, constraint_rect); } void LLFolderView::closeAutoOpenedFolders() @@ -1865,8 +1855,7 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); - - menu->needsArrange(); // update menu height if needed + //menu->needsArrange(); // update menu height if needed } else { @@ -1922,9 +1911,28 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, std::string& tooltip_msg) { mDragAndDropThisFrame = TRUE; + // have children handle it first BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + // when drop is not handled by child, it should be handled + // by the folder which is the hierarchy root. + if (!handled) + { + if (getListener()->getUUID().notNull()) + { + handled = LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + else + { + if (!mFolders.empty()) + { + // dispatch to last folder as a hack to support "Contents" folder in object inventory + handled = mFolders.back()->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + } + } + } + if (handled) { lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderView" << llendl; @@ -1970,50 +1978,41 @@ void LLFolderView::scrollToShowSelection() // If the parent is scroll containter, scroll it to make the selection // is maximally visible. -void LLFolderView::scrollToShowItem(LLFolderViewItem* item) +void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect) { if (!mScrollContainer) return; + // don't scroll to items when mouse is being used to scroll/drag and drop if (gFocusMgr.childHasMouseCapture(mScrollContainer)) { mNeedsScroll = FALSE; return; } - if(item && mScrollContainer) + + // if item exists and is in visible portion of parent folder... + if(item) { - LLRect local_rect = item->getRect(); + LLRect local_rect = item->getLocalRect(); LLRect item_scrolled_rect; // item position relative to display area of scroller + LLRect visible_doc_rect = mScrollContainer->getVisibleContentRect(); S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); S32 label_height = llround(sFont->getLineHeight()); - // when navigating with keyboard, only move top of folders on screen, otherwise show whole folder - S32 max_height_to_show = gFocusMgr.childHasKeyboardFocus(this) ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); - item->localPointToOtherView(item->getIndentation(), llmax(0, local_rect.getHeight() - max_height_to_show), &item_scrolled_rect.mLeft, &item_scrolled_rect.mBottom, mScrollContainer); - item->localPointToOtherView(local_rect.getWidth(), local_rect.getHeight(), &item_scrolled_rect.mRight, &item_scrolled_rect.mTop, mScrollContainer); + // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder + S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); + + // get portion of item that we want to see... + LLRect item_local_rect = LLRect(item->getIndentation(), + local_rect.getHeight(), + llmin(MIN_ITEM_WIDTH_VISIBLE, local_rect.getWidth()), + llmax(0, local_rect.getHeight() - max_height_to_show)); - item_scrolled_rect.mRight = llmin(item_scrolled_rect.mLeft + MIN_ITEM_WIDTH_VISIBLE, item_scrolled_rect.mRight); - LLCoordGL scroll_offset(-mScrollContainer->getBorderWidth() - item_scrolled_rect.mLeft, - mScrollContainer->getRect().getHeight() - item_scrolled_rect.mTop - 1); + LLRect item_doc_rect; - S32 max_scroll_offset = getVisibleRect().getHeight() - item_scrolled_rect.getHeight(); - if (item != mLastScrollItem || // if we're scrolling to focus on a new item - // or the item has just appeared on screen and it wasn't onscreen before - (scroll_offset.mY > 0 && scroll_offset.mY < max_scroll_offset && - (mLastScrollOffset.mY < 0 || mLastScrollOffset.mY > max_scroll_offset))) - { - // we now have a position on screen that we want to keep stable - // offset of selection relative to top of visible area - mLastScrollOffset = scroll_offset; - mLastScrollItem = item; - } + item->localRectToOtherView(item_local_rect, &item_doc_rect, this); - mScrollContainer->scrollToShowRect( item_scrolled_rect, mLastScrollOffset ); + mScrollContainer->scrollToShowRect( item_doc_rect, constraint_rect ); - // after scrolling, store new offset - // in case we don't have room to maintain the original position - LLCoordGL new_item_left_top; - item->localPointToOtherView(item->getIndentation(), item->getRect().getHeight(), &new_item_left_top.mX, &new_item_left_top.mY, mScrollContainer); - mLastScrollOffset.set(-mScrollContainer->getBorderWidth() - new_item_left_top.mX, mScrollContainer->getRect().getHeight() - new_item_left_top.mY - 1); } } @@ -2141,7 +2140,7 @@ void LLFolderView::doIdle() LLFastTimer t3(FTM_AUTO_SELECT); // select new item only if a filtered item not currently selected LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); - if (selected_itemp != NULL && sFolderViewItems.count(selected_itemp) == 0) + /*if (selected_itemp != NULL && sFolderViewItems.count(selected_itemp) == 0) { // There is a crash bug due to a race condition: when a folder view item is // destroyed, its address may still appear in mSelectedItems a couple of doIdle() @@ -2153,7 +2152,7 @@ void LLFolderView::doIdle() clearSelection(); requestArrange(); } - else if ((selected_itemp && !selected_itemp->getFiltered()) && !mAutoSelectOverride) + else */if ((selected_itemp && !selected_itemp->getFiltered()) && !mAutoSelectOverride) { // select first filtered item LLSelectFirstFilteredItem filter; @@ -2171,6 +2170,59 @@ void LLFolderView::doIdle() scrollToShowSelection(); } + // during filtering process, try to pin selected item's location on screen + // this will happen when searching your inventory and when new items arrive + if (filter_modified_and_active) + { + // calculate rectangle to pin item to at start of animated rearrange + if (!mPinningSelectedItem && !mSelectedItems.empty()) + { + // lets pin it! + mPinningSelectedItem = TRUE; + + LLRect visible_content_rect = mScrollContainer->getVisibleContentRect(); + LLFolderViewItem* selected_item = mSelectedItems.back(); + + LLRect item_rect; + selected_item->localRectToOtherView(selected_item->getLocalRect(), &item_rect, this); + // if item is visible in scrolled region + if (visible_content_rect.overlaps(item_rect)) + { + // then attempt to keep it in same place on screen + mScrollConstraintRect = item_rect; + mScrollConstraintRect.translate(-visible_content_rect.mLeft, -visible_content_rect.mBottom); + } + else + { + // otherwise we just want it onscreen somewhere + LLRect content_rect = mScrollContainer->getContentWindowRect(); + mScrollConstraintRect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + } + } + else + { + // stop pinning selected item after folders stop rearranging + if (!needsArrange()) + { + mPinningSelectedItem = FALSE; + } + } + + LLRect constraint_rect; + if (mPinningSelectedItem) + { + // use last known constraint rect for pinned item + constraint_rect = mScrollConstraintRect; + } + else + { + // during normal use (page up/page down, etc), just try to fit item on screen + LLRect content_rect = mScrollContainer->getContentWindowRect(); + constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + + BOOL is_visible = isInVisibleChain(); if ( is_visible ) @@ -2184,10 +2236,10 @@ void LLFolderView::doIdle() if (mSelectedItems.size() && mNeedsScroll) { - scrollToShowItem(mSelectedItems.back()); + scrollToShowItem(mSelectedItems.back(), constraint_rect); // continue scrolling until animated layout change is done - if (getCompletedFilterGeneration() >= mFilter->getMinRequiredGeneration() && - (!needsArrange() || !is_visible)) + if (!filter_modified_and_active + && (!needsArrange() || !is_visible)) { mNeedsScroll = FALSE; } @@ -2286,6 +2338,87 @@ void LLFolderView::updateMenu() menu->needsArrange(); // update menu height if needed } } + +bool LLFolderView::selectFirstItem() +{ + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();++iter) + { + LLFolderViewFolder* folder = (*iter ); + if (folder->getVisible()) + { + LLFolderViewItem* itemp = folder->getNextFromChild(0,true); + if(itemp) + setSelection(itemp,FALSE,TRUE); + return true; + } + + } + for(items_t::iterator iit = mItems.begin(); + iit != mItems.end(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + if (itemp->getVisible()) + { + setSelection(itemp,FALSE,TRUE); + return true; + } + } + return false; +} +bool LLFolderView::selectLastItem() +{ + for(items_t::reverse_iterator iit = mItems.rbegin(); + iit != mItems.rend(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + if (itemp->getVisible()) + { + setSelection(itemp,FALSE,TRUE); + return true; + } + } + for (folders_t::reverse_iterator iter = mFolders.rbegin(); + iter != mFolders.rend();++iter) + { + LLFolderViewFolder* folder = (*iter); + if (folder->getVisible()) + { + LLFolderViewItem* itemp = folder->getPreviousFromChild(0,true); + if(itemp) + setSelection(itemp,FALSE,TRUE); + return true; + } + } + return false; +} + + +S32 LLFolderView::notify(const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "select_first") + { + setFocus(true); + selectFirstItem(); + scrollToShowSelection(); + return 1; + + } + else if(str_action == "select_last") + { + setFocus(true); + selectLastItem(); + scrollToShowSelection(); + return 1; + } + } + return 0; +} + + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- @@ -2322,9 +2455,9 @@ bool LLFolderView::getFilterWorn() const return mFilter->getFilterWorn(); } -U32 LLFolderView::getFilterTypes() const +U32 LLFolderView::getFilterObjectTypes() const { - return mFilter->getFilterTypes(); + return mFilter->getFilterObjectTypes(); } PermissionMask LLFolderView::getFilterPermissions() const @@ -2381,27 +2514,3 @@ void properties_selected_items(void* user_data) fv->propertiesSelectedItems(); } } - -///---------------------------------------------------------------------------- -/// Class LLFolderViewEventListener -///---------------------------------------------------------------------------- - -void LLFolderViewEventListener::arrangeAndSet(LLFolderViewItem* focus, - BOOL set_selection, - BOOL take_keyboard_focus) -{ - if(!focus) return; - LLFolderView* root = focus->getRoot(); - if(focus->getParentFolder()) - focus->getParentFolder()->requestArrange(); - if(set_selection) - { - focus->setSelectionFromRoot(focus, TRUE, take_keyboard_focus); - if(root) - { - root->scrollToShowSelection(); - } - } -} - - diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 2031c4f01..c6ee590df 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -71,16 +71,13 @@ class LLTextBox; // manages the screen region of the folder view. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLUICtrl; -class LLLineEditor; - class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler { public: typedef void (*SelectCallback)(const std::deque &items, BOOL user_action, void* data); - LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, const LLRect& rect, + LLFolderView( const std::string& name, const LLRect& rect, const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener ); virtual ~LLFolderView( void ); @@ -91,7 +88,6 @@ public: // FolderViews default to sort by name. This will change that, // and resort the items if necessary. void setSortOrder(U32 order); - void checkTreeResortForModelChanged(); void setFilterPermMask(PermissionMask filter_perm_mask); typedef boost::signals2::signal& items, BOOL user_action)> signal_t; @@ -102,7 +98,7 @@ public: LLInventoryFilter* getFilter(); const std::string getFilterSubString(BOOL trim = FALSE); bool getFilterWorn() const; - U32 getFilterTypes() const; + U32 getFilterObjectTypes() const; PermissionMask getFilterPermissions() const; // *NOTE: use getFilter()->getShowFolderState(); //LLInventoryFilter::EFolderShow getShowFolderState(); @@ -116,7 +112,6 @@ public: // Close all folders in the view void closeAllFolders(); - void openFolder(const std::string& foldername); void openTopLevelFolders(); virtual void toggleOpen() {}; @@ -140,13 +135,17 @@ public: virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus); + // Used by menu callbacks + void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus); + + // Called once a frame to update the selection if mSelectThisID has been set + void updateSelection(); + // This method is used to toggle the selection of an item. Walks // children, and keeps track of selected objects. virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - virtual void extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items); - - virtual BOOL getSelectionList(std::set &selection); + virtual std::set getSelectionList() const; // make sure if ancestor is selected, descendents are not void sanitizeSelection(); @@ -216,7 +215,7 @@ public: virtual void deleteAllChildren(); void scrollToShowSelection(); - void scrollToShowItem(LLFolderViewItem* item); + void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect); void setScrollContainer( LLScrollableContainerView* parent ) { mScrollContainer = parent; } LLRect getVisibleRect(); @@ -226,6 +225,7 @@ public: void setShowSingleSelection(BOOL show); BOOL getShowSingleSelection() { return mShowSingleSelection; } F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); } + bool getUseEllipses() { return mUseEllipses; } void addItemID(const LLUUID& id, LLFolderViewItem* itemp); void removeItemID(const LLUUID& id); @@ -238,6 +238,8 @@ public: BOOL needsAutoSelect() { return mNeedsAutoSelect && !mAutoSelectOverride; } BOOL needsAutoRename() { return mNeedsAutoRename; } void setNeedsAutoRename(BOOL val) { mNeedsAutoRename = val; } + void setPinningSelectedItem(BOOL val) { mPinningSelectedItem = val; } + void setAutoSelectOverride(BOOL val) { mAutoSelectOverride = val; } BOOL getDebugFilters() { return mDebugFilters; } @@ -245,6 +247,9 @@ public: // DEBUG only void dumpSelectionInformation(); + virtual S32 notify(const LLSD& info) ; + + bool useLabelSuffix() { return mUseLabelSuffix; } void updateMenu(); private: @@ -260,6 +265,8 @@ protected: void finishRenamingItem( void ); void closeRenamer( void ); + bool selectFirstItem(); + bool selectLastItem(); BOOL addNoOptions(LLMenuGL* menu) const; protected: @@ -269,6 +276,7 @@ protected: selected_items_t mSelectedItems; BOOL mKeyboardSelection; BOOL mAllowMultiSelect; + BOOL mShowEmptyMessage; BOOL mShowFolderHierarchy; LLUUID mSourceID; @@ -277,11 +285,12 @@ protected: LLLineEditor* mRenamer; BOOL mNeedsScroll; - LLFolderViewItem* mLastScrollItem; - LLCoordGL mLastScrollOffset; + BOOL mPinningSelectedItem; + LLRect mScrollConstraintRect; BOOL mNeedsAutoSelect; BOOL mAutoSelectOverride; BOOL mNeedsAutoRename; + bool mUseLabelSuffix; BOOL mDebugFilters; U32 mSortOrder; @@ -305,8 +314,16 @@ protected: std::map mItemMap; BOOL mDragAndDropThisFrame; + LLUUID mSelectThisID; // if non null, select this item + LLPanel* mParentPanel; + /** + * Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll. + * NOTE: For now it uses only to cut LLFolderViewItem::mLabel text to be used for Landmarks in Places Panel. + */ + bool mUseEllipses; // See EXT-719 + /** * Contains item under mouse pointer while dragging */ diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index 7640d5878..73983931b 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -57,6 +57,7 @@ public: virtual PermissionMask getPermissionMask() const = 0; virtual LLFolderType::EType getPreferredType() const = 0; virtual LLPointer getIcon() const = 0; + virtual LLPointer getOpenIcon() const { return getIcon(); } virtual LLFontGL::StyleFlags getLabelStyle() const = 0; virtual std::string getLabelSuffix() const = 0; virtual void openItem( void ) = 0; @@ -101,11 +102,6 @@ public: // bridge is actually dropped. This allows for cleanup of the old // view, reference counting, etc. // virtual void dropped() = 0; - - // this method accesses the parent and arranges and sets it as - // specified. - void arrangeAndSet(LLFolderViewItem* focus, BOOL set_selection, - BOOL take_keyboard_focus = TRUE); }; diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index cc280df73..71453494f 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -75,21 +75,22 @@ void LLFolderViewItem::cleanupClass() // Default constructor // NOTE: Optimize this, we call it a *lot* when opening a large inventory LLFolderViewItem::LLFolderViewItem( const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_open, LLUIImagePtr icon_overlay, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener ) : LLUICtrl( name, LLRect(0, 0, 0, 0), TRUE, NULL, NULL, FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_RIGHT), mLabelWidth(0), - + mLabelWidthDirty(false), mParentFolder( NULL ), mIsSelected( FALSE ), mIsCurSelection( FALSE ), mSelectPending(FALSE), mLabelStyle( LLFontGL::NORMAL ), - mHasVisibleChildren(FALSE), mIndentation(0), + mItemHeight(16 + ICON_PAD), mPassedFilter(FALSE), mLastFilterGeneration(-1), mStringMatchOffset(std::string::npos), @@ -101,10 +102,19 @@ LLFolderViewItem::LLFolderViewItem( const std::string& name, LLUIImagePtr icon, mRoot( root ), mCreationDate(creation_date), mIcon(icon), + mIconOpen(icon_open), mIconOverlay(icon_overlay), - mListener(listener) + mListener(listener), + mShowLoadStatus(true), + + mSearchType(0) { sFolderViewItems.insert(this); + + /*S32 icon_height = mIcon.notNull() ? mIcon->getHeight() : 0; + S32 label_height = llround(sFont->getLineHeight());*/ + + postBuild();//Not parsing xml file yet. } BOOL LLFolderViewItem::postBuild() @@ -227,40 +237,52 @@ void LLFolderViewItem::refreshFromListener() mLabel = mListener->getDisplayName(); setIcon(mListener->getIcon()); time_t creation_date = mListener->getCreationDate(); - if (mCreationDate != creation_date) + if ((creation_date > 0) && (mCreationDate != creation_date)) { - mCreationDate = mListener->getCreationDate(); + setCreationDate(creation_date); dirtyFilter(); } - mLabelStyle = mListener->getLabelStyle(); - mLabelSuffix = mListener->getLabelSuffix(); - - LLInventoryItem* item = gInventory.getItem(mListener->getUUID()); - - std::string desc; - if (item) + if (mRoot->useLabelSuffix()) { - if (!item->getDescription().empty()) - { - desc = item->getDescription(); - LLStringUtil::toUpper(desc); - } + mLabelStyle = mListener->getLabelStyle(); + mLabelSuffix = mListener->getLabelSuffix(); } - mSearchableLabelDesc = desc; - - std::string creator_name; - if (item) - { - if (item->getCreatorUUID().notNull()) - { - gCacheName->getFullName(item->getCreatorUUID(), creator_name); - LLStringUtil::toUpper(creator_name); - } - } - mSearchableLabelCreator = creator_name; + + updateExtraSearchCriteria(); } } +void LLFolderViewItem::updateExtraSearchCriteria() +{ + if(!mListener) + return; + LLInventoryItem* item = gInventory.getItem(mListener->getUUID()); + + std::string desc; + if (item) + { + if (!item->getDescription().empty()) + { + desc = item->getDescription(); + LLStringUtil::toUpper(desc); + } + } + mSearchableLabelDesc = desc; + + std::string creator_name; + if (item) + { + if (item->getCreatorUUID().notNull()) + { + gCacheName->getFullName(item->getCreatorUUID(), creator_name); + LLStringUtil::toUpper(creator_name); + } + } + mSearchableLabelCreator = creator_name; + + updateSearchLabelType(); +} + void LLFolderViewItem::refresh() { refreshFromListener(); @@ -272,21 +294,17 @@ void LLFolderViewItem::refresh() if (mSearchableLabel.compare(searchable_label)) { mSearchableLabel.assign(searchable_label); + updateSearchLabelType(); dirtyFilter(); - // some part of label has changed, so overall width has potentially changed + // some part of label has changed, so overall width has potentially changed, and sort order too if (mParentFolder) { + mParentFolder->requestSort(); mParentFolder->requestArrange(); } } - S32 label_width = sFont->getWidth(mLabel); - if( mLabelSuffix.size() ) - { - label_width += sFont->getWidth( mLabelSuffix ); - } - - mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + label_width; + mLabelWidthDirty = true; } void LLFolderViewItem::applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor) @@ -313,7 +331,31 @@ void LLFolderViewItem::arrangeFromRoot() S32 height = 0; S32 width = 0; - root->arrange( &width, &height, 0 ); + S32 total_height = root->arrange( &width, &height, 0 ); + + LLSD params; + params["action"] = "size_changes"; + params["height"] = total_height; + getParent()->notifyParent(params); +} + +// Utility function for LLFolderView +void LLFolderViewItem::arrangeAndSet(BOOL set_selection, + BOOL take_keyboard_focus) +{ + LLFolderView* root = getRoot(); + if (getParentFolder()) + { + getParentFolder()->requestArrange(); + } + if(set_selection) + { + setSelectionFromRoot(this, TRUE, take_keyboard_focus); + if(root) + { + root->scrollToShowSelection(); + } + } } // This function clears the currently selected item, and records the @@ -333,11 +375,10 @@ void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, BOOL getRoot()->changeSelection(selection, selected); } -void LLFolderViewItem::extendSelectionFromRoot(LLFolderViewItem* selection) +std::set LLFolderViewItem::getSelectionList() const { - LLDynamicArray selected_items; - - getRoot()->extendSelection(selection, NULL, selected_items); + std::set selection; + return selection; } EInventorySortGroup LLFolderViewItem::getSortGroup() const @@ -362,34 +403,51 @@ BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder, LLFolderView* roo // makes sure that this view and it's children are the right size. S32 LLFolderViewItem::arrange( S32* width, S32* height, S32 filter_generation) { - mIndentation = mParentFolder ? mParentFolder->getIndentation() + LEFT_INDENTATION : 0; + S32 indentation = LEFT_INDENTATION; + // Only indent deeper items in hierarchy + mIndentation = (getParentFolder() + && getParentFolder()->getParentFolder() ) + ? mParentFolder->getIndentation() + indentation + : 0; + if (mLabelWidthDirty) + { + mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + sFont->getWidth(mSearchableLabel); + mLabelWidthDirty = false; + } + *width = llmax(*width, mLabelWidth + mIndentation); + + // determine if we need to use ellipses to avoid horizontal scroll. EXT-719 + bool use_ellipses = getRoot()->getUseEllipses(); + if (use_ellipses) + { + // limit to set rect to avoid horizontal scrollbar + *width = llmin(*width, getRoot()->getRect().getWidth()); + } *height = getItemHeight(); return *height; } S32 LLFolderViewItem::getItemHeight() { - S32 icon_height = mIcon.notNull() ? mIcon->getHeight() : 0; - S32 label_height = llround(sFont->getLineHeight()); - return llmax( icon_height, label_height ) + ICON_PAD; + return mItemHeight; } void LLFolderViewItem::filter( LLInventoryFilter& filter) { - BOOL filtered = mListener && filter.check(this); - - // if our visibility will change as a result of this filter, then + const BOOL previous_passed_filter = mPassedFilter; + const BOOL passed_filter = filter.check(this); + + // If our visibility will change as a result of this filter, then // we need to be rearranged in our parent folder - if (getVisible() != filtered) + if (mParentFolder) { - if (mParentFolder) - { + if (getVisible() != passed_filter + || previous_passed_filter != passed_filter ) mParentFolder->requestArrange(); - } } - setFiltered(filtered, filter.getCurrentGeneration()); + setFiltered(passed_filter, filter.getCurrentGeneration()); mStringMatchOffset = filter.getStringMatchOffset(); filter.decrementFilterCount(); @@ -419,10 +477,6 @@ BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL openitem, if (selection == this && !mIsSelected) { selectItem(); - if(mListener) - { - mListener->selectItem(); - } } else if (mIsSelected) // Deselect everything else. { @@ -433,9 +487,9 @@ BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selected) { - if (selection == this && mIsSelected != selected) + if (selection == this) { - if (mIsSelected) + if (mIsSelected) { deselectItem(); } @@ -443,10 +497,6 @@ BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selecte { selectItem(); } - if(mListener) - { - mListener->selectItem(); - } return TRUE; } return FALSE; @@ -454,29 +504,18 @@ BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selecte void LLFolderViewItem::deselectItem(void) { - llassert(mIsSelected); - mIsSelected = FALSE; - - // Update ancestors' count of selected descendents. - LLFolderViewFolder* parent_folder = getParentFolder(); - if (parent_folder) - { - parent_folder->recursiveIncrementNumDescendantsSelected(-1); - } } void LLFolderViewItem::selectItem(void) { - llassert(!mIsSelected); - - mIsSelected = TRUE; - - // Update ancestors' count of selected descendents. - LLFolderViewFolder* parent_folder = getParentFolder(); - if (parent_folder) + if (mIsSelected == FALSE) { - parent_folder->recursiveIncrementNumDescendantsSelected(1); + if (mListener) + { + mListener->selectItem(); + } + mIsSelected = TRUE; } } @@ -567,21 +606,19 @@ void LLFolderViewItem::rename(const std::string& new_name) if(mParentFolder) { - mParentFolder->resort(this); + mParentFolder->requestSort(); } } } } -std::string& LLFolderViewItem::getSearchableLabel() +void LLFolderViewItem::updateSearchLabelType() { - mSearchable = ""; - U32 flags = mRoot->getSearchType(); - if (flags == 0 || (flags & 1)) - { + mSearchType = mRoot->getSearchType(); + mSearchable.erase(); + if (!mSearchType || mSearchType & 1) mSearchable = mSearchableLabel; - } - if (flags & 2) + if (mSearchType & 2) { if (mSearchable.length()) { @@ -589,7 +626,7 @@ std::string& LLFolderViewItem::getSearchableLabel() } mSearchable += mSearchableLabelDesc; } - if (flags & 4) + if (mSearchType & 4) { if (mSearchable.length()) { @@ -597,6 +634,12 @@ std::string& LLFolderViewItem::getSearchableLabel() } mSearchable += mSearchableLabelCreator; } +} + +const std::string& LLFolderViewItem::getSearchableLabel() +{ + if(mSearchType != mRoot->getSearchType()) + updateSearchLabelType(); return mSearchable; } @@ -628,6 +671,11 @@ BOOL LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask ) BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) { + if (LLView::childrenHandleMouseDown(x, y, mask)) + { + return TRUE; + } + // No handler needed for focus lost since this class has no // state that depends on it. gFocusMgr.setMouseCapture( this ); @@ -640,7 +688,7 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) } else if (mask & MASK_SHIFT) { - extendSelectionFromRoot(this); + getParentFolder()->extendSelectionTo(this); } else { @@ -747,6 +795,11 @@ BOOL LLFolderViewItem::handleScrollWheel(S32 x, S32 y, S32 clicks) BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) { + if (LLView::childrenHandleMouseUp(x, y, mask)) + { + return TRUE; + } + // if mouse hasn't moved since mouse down... if ( pointInView(x, y) && mSelectPending ) { @@ -757,7 +810,7 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) } else if (mask & MASK_SHIFT) { - extendSelectionFromRoot(this); + getParentFolder()->extendSelectionTo(this); } else { @@ -847,10 +900,10 @@ void LLFolderViewItem::draw() // Draw highlight for selected items // const BOOL show_context = getRoot()->getShowSelectionContext(); - const BOOL filled = show_context || (getRoot()->getParent()->hasFocus()); // If we have keyboard focus, draw selection filled + const BOOL filled = show_context || (getRoot()->getParentPanel()->hasFocus()); // If we have keyboard focus, draw selection filled const S32 focus_top = getRect().getHeight(); - const S32 focus_bottom = getRect().getHeight() - getItemHeight(); - const bool folder_open = (getRect().getHeight() > getItemHeight() + 4); + const S32 focus_bottom = getRect().getHeight() - mItemHeight; + const bool folder_open = (getRect().getHeight() > mItemHeight + 4); if (mIsSelected) // always render "current" item. Only render other selected items if mShowSingleSelection is FALSE { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -925,7 +978,11 @@ void LLFolderViewItem::draw() // Draw open icon // const S32 icon_x = mIndentation + ARROW_SIZE + TEXT_PAD; - if (mIcon) + if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders + { + mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1); + } + else if (mIcon) { mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); } @@ -986,7 +1043,8 @@ void LLFolderViewItem::draw() if ((mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime")) || (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() - && root_is_loading)) + && root_is_loading + && mShowLoadStatus)) { std::string load_string = " ( Loading... ) "; font->renderUTF8(load_string, 0, right_x, y, sSearchStatusColor, @@ -1007,13 +1065,10 @@ void LLFolderViewItem::draw() if (sBoxImage.notNull() && mStringMatchOffset != std::string::npos) { // don't draw backgrounds for zero-length strings - std::string combined_string = mLabel + mLabelSuffix; S32 filter_string_length = getRoot()->getFilterSubString().size(); - std::string combined_string_upper = combined_string; - LLStringUtil::toUpper(combined_string_upper); - if (filter_string_length > 0 && (mRoot->getSearchType() & 1) && - combined_string_upper.find(mRoot->getFilterSubString()) == mStringMatchOffset) + if (filter_string_length > 0 && (mRoot->getSearchType() & 1)) { + std::string combined_string = mLabel + mLabelSuffix; S32 left = llround(text_left) + font->getWidth(combined_string, 0, mStringMatchOffset) - 1; S32 right = left + font->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD); @@ -1044,11 +1099,11 @@ void LLFolderViewItem::draw() // Default constructor LLFolderViewFolder::LLFolderViewFolder( const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_open, LLUIImagePtr icon_link, LLFolderView* root, LLFolderViewEventListener* listener ): - LLFolderViewItem( name, icon, icon_link, 0, root, listener ), // 0 = no create time - mNumDescendantsSelected(0), + LLFolderViewItem( name, icon, icon_open, icon_link, 0, root, listener ), // 0 = no create time mIsOpen(FALSE), mExpanderHighlighted(FALSE), mCurHeight(0.f), @@ -1060,11 +1115,11 @@ LLFolderViewFolder::LLFolderViewFolder( const std::string& name, LLUIImagePtr ic mLastCalculatedWidth(0), mCompletedFilterGeneration(-1), mMostFilteredDescendantGeneration(-1), - mNeedsSort(false) + mNeedsSort(false), + mPassedFolderFilter(FALSE) { } - // Destroys the object LLFolderViewFolder::~LLFolderViewFolder( void ) { @@ -1073,6 +1128,17 @@ LLFolderViewFolder::~LLFolderViewFolder( void ) gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() } +void LLFolderViewFolder::setFilteredFolder(bool filtered, S32 filter_generation) +{ + mPassedFolderFilter = filtered; + mLastFilterGeneration = filter_generation; +} + +bool LLFolderViewFolder::getFilteredFolder(S32 filter_generation) +{ + return mPassedFolderFilter && mLastFilterGeneration >= getRoot()->getFilter()->getMinRequiredGeneration(); +} + // addToFolder() returns TRUE if it succeeds. FALSE otherwise BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) { @@ -1098,8 +1164,6 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) } mHasVisibleChildren = hasFilteredDescendants(filter_generation); - - LLInventoryFilter::EFolderShow show_folder_state = getRoot()->getFilter()->getShowFolderState(); // calculate height as a single item (without any children), and reshapes rectangle to match LLFolderViewItem::arrange( width, height, filter_generation ); @@ -1132,8 +1196,10 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) } else { - folderp->setVisible(show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? - (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter + folderp->setVisible( folderp->getListener() + && (folderp->getFiltered(filter_generation) + || (folderp->getFilteredFolder(filter_generation) + && folderp->hasFilteredDescendants(filter_generation)))); // passed filter or has descendants that passed filter } if (folderp->getVisible()) @@ -1267,6 +1333,8 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) // you will automatically fail this time, so we only // check against items that have passed the filter S32 must_pass_generation = filter.getMustPassGeneration(); + + bool autoopen_folders = (filter.hasFilterString()); // if we have already been filtered against this generation, skip out if (getCompletedFilterGeneration() >= filter_generation) @@ -1285,7 +1353,9 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) } else { - // filter self only on first pass through + // filter against folder rules + filterFolder(filter); + // and then item rules LLFolderViewItem::filter( filter ); } } @@ -1343,10 +1413,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) if (folder->getFiltered() || folder->hasFilteredDescendants(filter.getMinRequiredGeneration())) { mMostFilteredDescendantGeneration = filter_generation; - if (mRoot->needsAutoSelect()) - { - folder->setOpenArrangeRecursively(TRUE); - } + requestArrange(); } // just skip it, it has already been filtered continue; @@ -1359,7 +1426,8 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) if (folder->getFiltered() || folder->hasFilteredDescendants(filter_generation)) { mMostFilteredDescendantGeneration = filter_generation; - if (getRoot()->needsAutoSelect()) + requestArrange(); + if (getRoot()->needsAutoSelect() && autoopen_folders) { folder->setOpenArrangeRecursively(TRUE); } @@ -1380,6 +1448,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) if (item->getFiltered()) { mMostFilteredDescendantGeneration = filter_generation; + requestArrange(); } continue; } @@ -1398,6 +1467,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) if (item->getFiltered(filter.getMinRequiredGeneration())) { mMostFilteredDescendantGeneration = filter_generation; + requestArrange(); } } @@ -1411,6 +1481,31 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) } } +void LLFolderViewFolder::filterFolder(LLInventoryFilter& filter) +{ + const BOOL previous_passed_filter = mPassedFolderFilter; + const BOOL passed_filter = filter.checkFolder(this); + + // If our visibility will change as a result of this filter, then + // we need to be rearranged in our parent folder + if (mParentFolder) + { + if (getVisible() != passed_filter + || previous_passed_filter != passed_filter ) + { + mParentFolder->requestArrange(); + } + } + + setFilteredFolder(passed_filter, filter.getCurrentGeneration()); + filter.decrementFilterCount(); + + if (getRoot()->getDebugFilters()) + { + mStatusText = llformat("%d", mLastFilterGeneration); + } +} + void LLFolderViewFolder::setFiltered(BOOL filtered, S32 filter_generation) { // if this folder is now filtered, but wasn't before @@ -1432,31 +1527,27 @@ void LLFolderViewFolder::dirtyFilter() LLFolderViewItem::dirtyFilter(); } +BOOL LLFolderViewFolder::getFiltered() +{ + return getFilteredFolder(getRoot()->getFilter()->getMinRequiredGeneration()) + && LLFolderViewItem::getFiltered(); +} + +BOOL LLFolderViewFolder::getFiltered(S32 filter_generation) +{ + return getFilteredFolder(filter_generation) && LLFolderViewItem::getFiltered(filter_generation); +} BOOL LLFolderViewFolder::hasFilteredDescendants(S32 filter_generation) { return mMostFilteredDescendantGeneration >= filter_generation; } + BOOL LLFolderViewFolder::hasFilteredDescendants() { return mMostFilteredDescendantGeneration >= getRoot()->getFilter()->getCurrentGeneration(); } -void LLFolderViewFolder::recursiveIncrementNumDescendantsSelected(S32 increment) -{ - LLFolderViewFolder* parent_folder = this; - do - { - parent_folder->mNumDescendantsSelected += increment; - - // Make sure we don't have negative values. - llassert(parent_folder->mNumDescendantsSelected >= 0); - - parent_folder = parent_folder->getParentFolder(); - } - while(parent_folder); -} - // Passes selection information on to children and record selection // information if necessary. BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem, @@ -1469,10 +1560,6 @@ BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem { selectItem(); } - if(mListener) - { - mListener->selectItem(); - } rv = TRUE; } else @@ -1530,13 +1617,9 @@ BOOL LLFolderViewFolder::changeSelection(LLFolderViewItem* selection, BOOL selec } else { - deselectItem(); + deselectItem(); } } - if(mListener && selected) - { - mListener->selectItem(); - } } for (folders_t::iterator iter = mFolders.begin(); @@ -1737,158 +1820,89 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo } } -void LLFolderViewFolder::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& selected_items) +void LLFolderViewFolder::extendSelectionTo(LLFolderViewItem* new_selection) { - // pass on to child folders first - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) + if (getRoot()->getAllowMultiSelect() == FALSE) return; + + LLFolderViewItem* cur_selected_item = getRoot()->getCurSelectedItem(); + if (cur_selected_item == NULL) { - folders_t::iterator fit = iter++; - (*fit)->extendSelection(selection, last_selected, selected_items); + cur_selected_item = new_selection; } - // handle selection of our immediate children... - BOOL reverse_select = FALSE; - BOOL found_last_selected = FALSE; - BOOL found_selection = FALSE; - LLDynamicArray items_to_select; - LLFolderViewItem* item; - //...folders first... - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) + bool reverse = false; + LLFolderViewFolder* common_ancestor = getCommonAncestor(cur_selected_item, new_selection, reverse); + if (!common_ancestor) return; + + LLFolderViewItem* last_selected_item_from_cur = cur_selected_item; + LLFolderViewFolder* cur_folder = cur_selected_item->getParentFolder(); + + std::vector items_to_select_forward; + + while(cur_folder != common_ancestor) { - folders_t::iterator fit = iter++; - item = (*fit); - if(item == selection) - { - found_selection = TRUE; - } - else if (item == last_selected) - { - found_last_selected = TRUE; - if (found_selection) - { - reverse_select = TRUE; - } - } - - if (found_selection || found_last_selected) - { - // deselect currently selected items so they can be pushed back on queue - if (item->isSelected()) - { - item->changeSelection(item, FALSE); - } - items_to_select.put(item); - } - - if (found_selection && found_last_selected) - { - break; - } + cur_folder->gatherChildRangeExclusive(last_selected_item_from_cur, NULL, reverse, items_to_select_forward); + + last_selected_item_from_cur = cur_folder; + cur_folder = cur_folder->getParentFolder(); } - if (!(found_selection && found_last_selected)) + std::vector items_to_select_reverse; + + LLFolderViewItem* last_selected_item_from_new = new_selection; + cur_folder = new_selection->getParentFolder(); + while(cur_folder != common_ancestor) { - //,,,then items - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - item = (*iit); - if(item == selection) - { - found_selection = TRUE; - } - else if (item == last_selected) - { - found_last_selected = TRUE; - if (found_selection) - { - reverse_select = TRUE; - } - } + cur_folder->gatherChildRangeExclusive(last_selected_item_from_new, NULL, !reverse, items_to_select_reverse); - if (found_selection || found_last_selected) - { - // deselect currently selected items so they can be pushed back on queue - if (item->isSelected()) - { - item->changeSelection(item, FALSE); - } - items_to_select.put(item); - } - - if (found_selection && found_last_selected) - { - break; - } - } + last_selected_item_from_new = cur_folder; + cur_folder = cur_folder->getParentFolder(); } - if (found_last_selected && found_selection) - { - // we have a complete selection inside this folder - for (S32 index = reverse_select ? items_to_select.getLength() - 1 : 0; - reverse_select ? index >= 0 : index < items_to_select.getLength(); reverse_select ? index-- : index++) - { - LLFolderViewItem* item = items_to_select[index]; - if (item->changeSelection(item, TRUE)) - { - selected_items.put(item); - } - } - } - else if (found_selection) - { - // last selection was not in this folder....go ahead and select just the new item - if (selection->changeSelection(selection, TRUE)) - { - selected_items.put(selection); - } - } -} + common_ancestor->gatherChildRangeExclusive(last_selected_item_from_cur, last_selected_item_from_new, reverse, items_to_select_forward); -void LLFolderViewFolder::recursiveDeselect(BOOL deselect_self) -{ - if (isSelected() && deselect_self) + for (std::vector::reverse_iterator it = items_to_select_reverse.rbegin(), end_it = items_to_select_reverse.rend(); + it != end_it; + ++it) { - deselectItem(); + items_to_select_forward.push_back(*it); } - if (0 == mNumDescendantsSelected) - { - return; - } + LLFolderView* root = getRoot(); - // Deselect all items in this folder. - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) + for (std::vector::iterator it = items_to_select_forward.begin(), end_it = items_to_select_forward.end(); + it != end_it; + ++it) { - items_t::iterator iit = iter++; - LLFolderViewItem* item = (*iit); + LLFolderViewItem* item = *it; if (item->isSelected()) { - item->deselectItem(); + root->removeFromSelectionList(item); } + else + { + item->selectItem(); + } + root->addToSelectionList(item); } - // Recursively deselect all folders in this folder. - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) + if (new_selection->isSelected()) { - folders_t::iterator fit = iter++; - LLFolderViewFolder* folder = (*fit); - folder->recursiveDeselect(TRUE); + root->removeFromSelectionList(new_selection); } - + else + { + new_selection->selectItem(); + } + root->addToSelectionList(new_selection); } + void LLFolderViewFolder::destroyView() { for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) + iter != mItems.end();) { items_t::iterator iit = iter++; LLFolderViewItem* item = (*iit); @@ -1918,8 +1932,6 @@ BOOL LLFolderViewFolder::removeItem(LLFolderViewItem* item) { if(item->remove()) { - //RN: this seem unneccessary as remove() moves to trash - //removeView(item); return TRUE; } return FALSE; @@ -1956,21 +1968,13 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) LLFolderViewFolder* f = static_cast(item); folders_t::iterator ft; ft = std::find(mFolders.begin(), mFolders.end(), f); - if(ft != mFolders.end()) + if (ft != mFolders.end()) { - if ((*ft)->numSelected()) - { - recursiveIncrementNumDescendantsSelected(-(*ft)->numSelected()); - } mFolders.erase(ft); } } else { - if ((*it)->isSelected()) - { - recursiveIncrementNumDescendantsSelected(-1); - } mItems.erase(it); } //item has been removed, need to update filter @@ -1981,14 +1985,6 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) removeChild(item); } -// This function is called by a child that needs to be resorted. -// This is only called for renaming an object because it won't work for date -void LLFolderViewFolder::resort(LLFolderViewItem* item) -{ - mItems.sort(mSortFunction); - mFolders.sort(mSortFunction); -} - bool LLFolderViewFolder::isTrash() const { if (mAmTrash == LLFolderViewFolder::UNKNOWN) @@ -2066,15 +2062,14 @@ EInventorySortGroup LLFolderViewFolder::getSortGroup() const return SG_TRASH_FOLDER; } - // Folders that can't be moved are 'system' folders. if( mListener ) { - if( !(mListener->isItemMovable()) ) + if(LLFolderType::lookupIsProtectedType(mListener->getPreferredType())) { return SG_SYSTEM_FOLDER; } } - + return SG_NORMAL_FOLDER; } @@ -2146,38 +2141,54 @@ BOOL LLFolderViewFolder::isRemovable() // this is an internal method used for adding items to folders. BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) { - - items_t::iterator it = std::lower_bound( - mItems.begin(), - mItems.end(), - item, - mSortFunction); - mItems.insert(it,item); - if (item->isSelected()) - { - recursiveIncrementNumDescendantsSelected(1); - } + mItems.push_back(item); + item->setRect(LLRect(0, 0, getRect().getWidth(), 0)); item->setVisible(FALSE); - addChild( item ); + + addChild(item); + item->dirtyFilter(); + + // Update the folder creation date if the folder has no creation date + bool setting_date = false; + const time_t item_creation_date = item->getCreationDate(); + if ((item_creation_date > 0) && (mCreationDate == 0)) + { + setCreationDate(item_creation_date); + setting_date = true; + } + + // Handle sorting requestArrange(); + requestSort(); + + // Traverse parent folders and update creation date and resort, if necessary + LLFolderViewFolder* parentp = getParentFolder(); + while (parentp) + { + // Update the parent folder creation date + if (setting_date && (parentp->mCreationDate == 0)) + { + parentp->setCreationDate(item_creation_date); + } + + if (parentp->mSortFunction.isByDate()) + { + // parent folder doesn't have a time stamp yet, so get it from us + parentp->requestSort(); + } + + parentp = parentp->getParentFolder(); + } + return TRUE; } // this is an internal method used for adding items to folders. BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) { - folders_t::iterator it = std::lower_bound( - mFolders.begin(), - mFolders.end(), - folder, - mSortFunction); - mFolders.insert(it,folder); - if (folder->numSelected()) - { - recursiveIncrementNumDescendantsSelected(folder->numSelected()); - } + mFolders.push_back(folder); folder->setOrigin(0, 0); folder->reshape(getRect().getWidth(), 0); folder->setVisible(FALSE); @@ -2185,6 +2196,14 @@ BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) folder->dirtyFilter(); // rearrange all descendants too, as our indentation level might have changed folder->requestArrange(TRUE); + requestSort(); + LLFolderViewFolder* parentp = getParentFolder(); + while (parentp && !parentp->mSortFunction.isByDate()) + { + // parent folder doesn't have a time stamp yet, so get it from us + parentp->requestSort(); + parentp = parentp->getParentFolder(); + } return TRUE; } @@ -2345,20 +2364,33 @@ BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, EAcceptance* accept, std::string& tooltip_msg) { - LLFolderView* root_view = getRoot(); - BOOL handled = FALSE; - if(mIsOpen) + + if (mIsOpen) { - handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, - cargo_data, accept, tooltip_msg) != NULL; + handled = (childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL); } if (!handled) { - BOOL accepted = mListener && mListener->dragOrDrop(mask, drop,cargo_type,cargo_data); + handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - if (accepted) + lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewFolder" << llendl; + } + + return TRUE; +} + +BOOL LLFolderViewFolder::handleDragAndDropToThisFolder(MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL accepted = mListener && mListener->dragOrDrop(mask, drop, cargo_type, cargo_data); + + if (accepted) { mDragAndDropTarget = TRUE; *accept = ACCEPT_YES_MULTI; @@ -2369,13 +2401,10 @@ BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, } if (!drop && accepted) - { - root_view->autoOpenTest(this); - } - - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewFolder" << llendl; + { + getRoot()->autoOpenTest(this); } - + return TRUE; } @@ -2478,7 +2507,9 @@ void LLFolderViewFolder::draw() bool possibly_has_children = false; bool up_to_date = mListener && mListener->isUpToDate(); - if(!up_to_date && mListener && mListener->hasChildren()) // we know we have children but haven't fetched them (doesn't obey filter) + if(!up_to_date + && mListener + && mListener->hasChildren()) // we know we have children but haven't fetched them (doesn't obey filter) { possibly_has_children = true; } @@ -2750,10 +2781,38 @@ bool LLInventorySort::updateSort(U32 order) bool LLInventorySort::operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b) { + /* TO-DO + // ignore sort order for landmarks in the Favorites folder. + // they should be always sorted as in Favorites bar. See EXT-719 + if (a->getSortGroup() == SG_ITEM + && b->getSortGroup() == SG_ITEM + && a->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK + && b->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + + static const LLUUID& favorites_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + + LLUUID a_uuid = a->getParentFolder()->getListener()->getUUID(); + LLUUID b_uuid = b->getParentFolder()->getListener()->getUUID(); + + if ((a_uuid == favorites_folder_id && b_uuid == favorites_folder_id)) + { + // *TODO: mantipov: probably it is better to add an appropriate method to LLFolderViewItem + // or to LLInvFVBridge + LLViewerInventoryItem* aitem = (static_cast(a->getListener()))->getItem(); + LLViewerInventoryItem* bitem = (static_cast(b->getListener()))->getItem(); + if (!aitem || !bitem) + return false; + S32 a_sort = aitem->getSortField(); + S32 b_sort = bitem->getSortField(); + return a_sort < b_sort; + } + }*/ + // We sort by name if we aren't sorting by date // OR if these are folders and we are sorting folders by name. bool by_name = (!mByDate - || (mFoldersByName + || (mFoldersByName && (a->getSortGroup() != SG_ITEM))); if (a->getSortGroup() != b->getSortGroup()) diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 657cfda54..65fa2fda7 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -60,10 +60,10 @@ class LLInventorySort public: LLInventorySort() : mSortOrder(0), - mByDate(false), - mSystemToTop(false), - mFoldersByName(false) { } - + mByDate(false), + mSystemToTop(false), + mFoldersByName(false) { } + // Returns true if order has changed bool updateSort(U32 order); U32 getSort() { return mSortOrder; } @@ -92,7 +92,7 @@ public: friend class LLFolderViewEventListener; static const S32 LEFT_PAD = 5; - static const S32 LEFT_INDENTATION = 13; + static const S32 LEFT_INDENTATION = 6; static const S32 ICON_PAD = 2; static const S32 ICON_WIDTH = 16; static const S32 TEXT_PAD = 1; @@ -101,6 +101,9 @@ public: // animation parameters static const F32 FOLDER_CLOSE_TIME_CONSTANT; static const F32 FOLDER_OPEN_TIME_CONSTANT; + + BOOL isLoading() const { return mIsLoading; } + private: BOOL mIsSelected; @@ -114,9 +117,9 @@ protected: std::string mSearchableLabel; std::string mSearchableLabelDesc; std::string mSearchableLabelCreator; - std::string mSearchable; S32 mLabelWidth; - U32 mCreationDate; + bool mLabelWidthDirty; + time_t mCreationDate; LLFolderViewFolder* mParentFolder; LLFolderViewEventListener* mListener; BOOL mIsCurSelection; @@ -125,9 +128,11 @@ protected: std::string mLabelSuffix; LLUIImagePtr mIcon; std::string mStatusText; + LLUIImagePtr mIconOpen; LLUIImagePtr mIconOverlay; BOOL mHasVisibleChildren; S32 mIndentation; + S32 mItemHeight; BOOL mPassedFilter; S32 mLastFilterGeneration; std::string::size_type mStringMatchOffset; @@ -136,18 +141,26 @@ protected: BOOL mDragAndDropTarget; BOOL mIsLoading; LLTimer mTimeSinceRequestStart; + bool mShowLoadStatus; + + std::string mSearchable; + U32 mSearchType; // helper function to change the selection from the root. void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected); - // helper function to change the selection from the root. - void extendSelectionFromRoot(LLFolderViewItem* selection); + //Sets extra search criteria 'labels' to be compared against by filter. + void updateExtraSearchCriteria(); + //Update mSearchable string based on roots search flags. (Name, creator, desc) + void updateSearchLabelType(); // this is an internal method used for adding items to folders. A - // no-op at this leve, but reimplemented in derived classes. + // no-op at this level, but reimplemented in derived classes. virtual BOOL addItem(LLFolderViewItem*) { return FALSE; } virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } + virtual void setCreationDate(time_t creation_date_utc) { mCreationDate = creation_date_utc; } + public: BOOL postBuild(); @@ -158,16 +171,16 @@ public: void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus = TRUE); - - // This function is called when the folder view is dirty. It's // implemented here but called by derived classes when folding the // views. void arrangeFromRoot(); void filterFromRoot( void ); + + void arrangeAndSet(BOOL set_selection, BOOL take_keyboard_focus); // creation_date is in UTC seconds - LLFolderViewItem( const std::string& name, LLUIImagePtr icon, LLUIImagePtr icon_overlay, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener ); + LLFolderViewItem( const std::string& name, LLUIImagePtr icon, LLUIImagePtr icon_open, LLUIImagePtr icon_overlay, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener ); virtual ~LLFolderViewItem( void ); // addToFolder() returns TRUE if it succeeds. FALSE otherwise @@ -198,9 +211,6 @@ public: // Returns TRUE if the selection state of this item was changed. virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - // this method is used to group select items - virtual void extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items) { } - // this method is used to deselect this element void deselectItem(); @@ -208,7 +218,7 @@ public: virtual void selectItem(); // gets multiple-element selection - virtual BOOL getSelectionList(std::set &selection){return TRUE;} + virtual std::set getSelectionList() const; // Returns true is this object and all of its children can be removed (deleted by user) virtual BOOL isRemovable(); @@ -221,12 +231,16 @@ public: BOOL isSelected() const { return mIsSelected; } + void setUnselected() { mIsSelected = FALSE; } + void setIsCurSelection(BOOL select) { mIsCurSelection = select; } BOOL getIsCurSelection() { return mIsCurSelection; } BOOL hasVisibleChildren() { return mHasVisibleChildren; } + void setShowLoadStatus(bool status) { mShowLoadStatus = status; } + // Call through to the viewed object and return true if it can be // removed. Returns true if it's removed. //virtual BOOL removeRecursively(BOOL single_item); @@ -239,7 +253,7 @@ public: // viewed. This method will ask the viewed object itself. const std::string& getName( void ) const; - std::string& getSearchableLabel( void ); + const std::string& getSearchableLabel( void ); // This method returns the label displayed on the view. This // method was primarily added to allow sorting on the folder @@ -248,10 +262,10 @@ public: // Used for sorting, like getLabel() above. virtual time_t getCreationDate() const { return mCreationDate; } - + LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; } const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; } - + LLFolderViewItem* getNextOpenNode( BOOL include_children = TRUE ); LLFolderViewItem* getPreviousOpenNode( BOOL include_children = TRUE ); @@ -271,7 +285,7 @@ public: // Show children (unfortunate that this is called "open") virtual void setOpen(BOOL open = TRUE) {}; - virtual BOOL isOpen() { return FALSE; } + virtual BOOL isOpen() const { return FALSE; } virtual LLFolderView* getRoot(); BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor ); @@ -300,13 +314,21 @@ public: virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual LLView* getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const + { + if(create_if_missing) + return LLView::getChildView(name, recurse, TRUE); + else + return NULL; + } + // virtual void handleDropped(); virtual void draw(); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); }; @@ -326,6 +348,7 @@ class LLFolderViewFolder : public LLFolderViewItem { protected: LLFolderViewFolder( const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_open, LLUIImagePtr icon_link, LLFolderView* root, LLFolderViewEventListener* listener ); @@ -343,13 +366,6 @@ public: typedef std::list items_t; typedef std::list folders_t; -private: - S32 mNumDescendantsSelected; - -public: // Accessed needed by LLFolderViewItem - void recursiveIncrementNumDescendantsSelected(S32 increment); - S32 numSelected(void) const { return mNumDescendantsSelected + (isSelected() ? 1 : 0); } - protected: items_t mItems; folders_t mFolders; @@ -367,6 +383,8 @@ protected: S32 mCompletedFilterGeneration; S32 mMostFilteredDescendantGeneration; bool mNeedsSort; + bool mPassedFolderFilter; + public: typedef enum e_recurse_type { @@ -406,7 +424,15 @@ public: // applies filters to control visibility of inventory items virtual void filter( LLInventoryFilter& filter); virtual void setFiltered(BOOL filtered, S32 filter_generation); + virtual BOOL getFiltered(); + virtual BOOL getFiltered(S32 filter_generation); + virtual void dirtyFilter(); + + // folder-specific filtering (filter status propagates top down instead of bottom up) + void filterFolder(LLInventoryFilter& filter); + void setFilteredFolder(bool filtered, S32 filter_generation); + bool getFilteredFolder(S32 filter_generation); // Passes selection information on to children and record // selection information if necessary. @@ -421,10 +447,7 @@ public: virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); // this method is used to group select items - virtual void extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items); - - // Deselect this folder and all folder/items it contains recursively. - void recursiveDeselect(BOOL deselect_self); + void extendSelectionTo(LLFolderViewItem* selection); // Returns true is this object and all of its children can be removed. virtual BOOL isRemovable(); @@ -480,15 +503,15 @@ public: virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse = RECURSE_NO); // Get the current state of the folder. - virtual BOOL isOpen() { return mIsOpen; } + virtual BOOL isOpen() const { return mIsOpen; } // special case if an object is dropped on the child. BOOL handleDragAndDropFromChild(MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); void applyFunctorRecursively(LLFolderViewFunctor& functor); virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor); @@ -519,7 +542,6 @@ public: time_t getCreationDate() const; bool isTrash() const; - S32 getNumSelectedDescendants(void) const { return mNumDescendantsSelected; } folders_t::const_iterator getFoldersBegin() const { return mFolders.begin(); } folders_t::const_iterator getFoldersEnd() const { return mFolders.end(); } diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index a4cdfde10..0cb51a4bb 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -129,8 +129,7 @@ bool doToSelected(LLFolderView* folder, std::string action) LLInventoryClipboard::instance().reset(); } - std::set selected_items; - folder->getSelectionList(selected_items); + std::set selected_items = folder->getSelectionList(); LLMultiPreview* multi_previewp = NULL; LLMultiProperties* multi_propertiesp = NULL; @@ -232,7 +231,7 @@ class LLNewWindow : public inventory_listener_t LLInventoryView* iv = new LLInventoryView(std::string("Inventory"), rect, mPtr->getActivePanel()->getModel()); - iv->getActivePanel()->setFilterTypes(mPtr->getActivePanel()->getFilterTypes()); + iv->getActivePanel()->setFilterTypes(mPtr->getActivePanel()->getFilterObjectTypes()); iv->getActivePanel()->setFilterSubString(mPtr->getActivePanel()->getFilterSubString()); iv->open(); /*Flawfinder: ignore*/ @@ -537,8 +536,7 @@ class LLBeginIMSession : public inventory_panel_listener_t LLInventoryPanel *panel = mPtr; LLInventoryModel* model = panel->getModel(); if(!model) return true; - std::set selected_items; - panel->getRootFolder()->getSelectionList(selected_items); + std::set selected_items = panel->getRootFolder()->getSelectionList(); std::string name; static int session_num = 1; @@ -643,8 +641,7 @@ class LLAttachObject : public inventory_panel_listener_t LLFolderView* folder = panel->getRootFolder(); if(!folder) return true; - std::set selected_items; - folder->getSelectionList(selected_items); + std::set selected_items = folder->getSelectionList(); LLUUID id = *selected_items.begin(); std::string joint_name = userdata.asString(); diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp index 45a1b68bf..b3caf401f 100644 --- a/indra/newview/llinventorybackup.cpp +++ b/indra/newview/llinventorybackup.cpp @@ -489,8 +489,7 @@ void LLInventoryBackup::save(LLFolderView* folder) { LLInventoryModel* model = &gInventory; - std::set selected_items; - folder->getSelectionList(selected_items); + std::set selected_items = folder->getSelectionList(); if(selected_items.size() < 1) { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e8c78fd7a..23a9375c7 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5548,6 +5548,7 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } + // +=================================================+ // | LLLinkBridge | // +=================================================+ @@ -5555,8 +5556,22 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::string LLLinkFolderBridge::sPrefix("Link: "); LLUIImagePtr LLLinkFolderBridge::getIcon() const { - //For now, all inv links share this icon. There is no 'overlay' mechanism yet. - return LLUI::getUIImage("inv_link_folder.tga"); + LLFolderType::EType folder_type = LLFolderType::FT_NONE; + const LLInventoryObject *obj = getInventoryObject(); + if (obj) + { + LLViewerInventoryCategory* cat = NULL; + LLInventoryModel* model = getInventoryModel(); + if(model) + { + cat = (LLViewerInventoryCategory*)model->getCategory(obj->getLinkedUUID()); + if (cat) + { + folder_type = cat->getPreferredType(); + } + } + } + return LLFolderBridge::getIcon(folder_type); } void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 3849286cd..c73d9995c 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -30,7 +30,7 @@ // viewer includes #include "llfoldervieweventlistener.h" -#include "llfolderview.h" +#include "llfolderviewitem.h" #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" #include "llviewercontrol.h" @@ -44,12 +44,21 @@ #include "lltrans.h" LLInventoryFilter::FilterOps::FilterOps() : - mFilterTypes(0xffffffff), + mFilterObjectTypes(0xffffffffffffffffULL), + mFilterCategoryTypes(0xffffffffffffffffULL), + mFilterWearableTypes(0xffffffffffffffffULL), mMinDate(time_min()), mMaxDate(time_max()), mHoursAgo(0), mShowFolderState(SHOW_NON_EMPTY_FOLDERS), - mPermissions(PERM_NONE) {} + mPermissions(PERM_NONE), + mFilterTypes(FILTERTYPE_OBJECT), + mFilterWorn(false), + mFilterUUID(LLUUID::null), + mFilterLinks(FILTERLINK_INCLUDE_LINKS) +{ +} + ///---------------------------------------------------------------------------- /// Class LLInventoryFilter ///---------------------------------------------------------------------------- @@ -62,7 +71,6 @@ LLInventoryFilter::LLInventoryFilter(const std::string& name) mSubStringMatchOffset = 0; mFilterSubString.clear(); - mFilterWorn = false; mFilterGeneration = 0; mMustPassGeneration = S32_MAX; mMinRequiredGeneration = 0; @@ -82,36 +90,184 @@ LLInventoryFilter::~LLInventoryFilter() BOOL LLInventoryFilter::check(LLFolderViewItem* item) { - LLFolderViewEventListener* listener = item->getListener(); - const LLUUID& item_id = listener->getUUID(); - const LLInventoryObject *obj = gInventory.getObject(item_id); - if (isActive() && obj && obj->getIsLinkType()) + // If it's a folder and we're showing all folders, return TRUE automatically. + const BOOL is_folder = (dynamic_cast(item) != NULL); + if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)) { - // When filtering is active, omit links. - return FALSE; + return TRUE; } - time_t earliest; + const LLFolderViewEventListener* listener = item->getListener(); + const LLUUID item_id = listener ? listener->getUUID() : LLUUID::null; - earliest = time_corrected() - mFilterOps.mHoursAgo * 3600; - if (mFilterOps.mMinDate > time_min() && mFilterOps.mMinDate < earliest) - { - earliest = mFilterOps.mMinDate; - } - else if (!mFilterOps.mHoursAgo) - { - earliest = 0; - } mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; - BOOL passed = (0x1 << listener->getInventoryType() & mFilterOps.mFilterTypes || listener->getInventoryType() == LLInventoryType::IT_NONE) - && (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos) - && (mFilterWorn == false || gAgentWearables.isWearingItem(item_id) || - (gAgentAvatarp && gAgentAvatarp->isWearingAttachment(item_id))) - && ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions) - && (listener->getCreationDate() >= earliest && listener->getCreationDate() <= mFilterOps.mMaxDate); + + const BOOL passed_filtertype = checkAgainstFilterType(item); + const BOOL passed_permissions = checkAgainstPermissions(item); + const BOOL passed_filterlink = checkAgainstFilterLinks(item); + const BOOL passed_wearable = !mFilterOps.mFilterWorn || (gAgentWearables.isWearingItem(item_id) || (gAgentAvatarp && gAgentAvatarp->isWearingAttachment(item_id))); + const BOOL passed = (passed_filtertype && + passed_permissions && + passed_filterlink && + passed_wearable && + (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos)); + return passed; } +bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) +{ + // we're showing all folders, overriding filter + if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS) + { + return true; + } + + const LLFolderViewEventListener* listener = folder->getListener(); + const LLUUID folder_id = listener->getUUID(); + + if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY) + { + // Can only filter categories for items in your inventory + // (e.g. versus in-world object contents). + const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); + if (!cat) + return false; + LLFolderType::EType cat_type = cat->getPreferredType(); + if (cat_type != LLFolderType::FT_NONE && (1LL << cat_type & mFilterOps.mFilterCategoryTypes) == U64(0)) + return false; + } + + return true; +} + +BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const +{ + const LLFolderViewEventListener* listener = item->getListener(); + if (!listener) return FALSE; + + LLInventoryType::EType object_type = listener->getInventoryType(); + const LLUUID object_id = listener->getUUID(); + const LLInventoryObject *object = gInventory.getObject(object_id); + + const U32 filterTypes = mFilterOps.mFilterTypes; + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_OBJECT + // Pass if this item's type is of the correct filter type + if (filterTypes & FILTERTYPE_OBJECT) + { + // If it has no type, pass it, unless it's a link. + if (object_type == LLInventoryType::IT_NONE) + { + if (object && object->getIsLinkType()) + { + return FALSE; + } + } + else if ((1LL << object_type & mFilterOps.mFilterObjectTypes) == U64(0)) + { + return FALSE; + } + } + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_UUID + // Pass if this item is the target UUID or if it links to the target UUID + if (filterTypes & FILTERTYPE_UUID) + { + if (!object) return FALSE; + + if (object->getLinkedUUID() != mFilterOps.mFilterUUID) + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_DATE + // Pass if this item is within the date range. + if (filterTypes & FILTERTYPE_DATE) + { + const U16 HOURS_TO_SECONDS = 3600; + time_t earliest = time_corrected() - mFilterOps.mHoursAgo * HOURS_TO_SECONDS; + if (mFilterOps.mMinDate > time_min() && mFilterOps.mMinDate < earliest) + { + earliest = mFilterOps.mMinDate; + } + else if (!mFilterOps.mHoursAgo) + { + earliest = 0; + } + if (listener->getCreationDate() < earliest || + listener->getCreationDate() > mFilterOps.mMaxDate) + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_WEARABLE + // Pass if this item is a wearable of the appropriate type + if (filterTypes & FILTERTYPE_WEARABLE) + { + LLWearableType::EType type = listener->getWearableType(); + if ((0x1LL << type & mFilterOps.mFilterWearableTypes) == 0) + { + return FALSE; + } + } + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_EMPTYFOLDERS + // Pass if this item is a folder and is not a system folder that should be hidden + if (filterTypes & FILTERTYPE_EMPTYFOLDERS) + { + if (object_type == LLInventoryType::IT_CATEGORY) + { + bool is_hidden_if_empty = LLViewerFolderType::lookupIsHiddenIfEmpty(listener->getPreferredType()); + if (is_hidden_if_empty) + { + // Force the fetching of those folders so they are hidden iff they really are empty... + gInventory.fetchDescendentsOf(object_id); + return FALSE; + } + } + } + + return TRUE; +} + +BOOL LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const +{ + const LLFolderViewEventListener* listener = item->getListener(); + if (!listener) return FALSE; + + PermissionMask perm = listener->getPermissionMask(); + const LLInvFVBridge *bridge = dynamic_cast(item->getListener()); + if (bridge && bridge->isLink()) + { + const LLUUID& linked_uuid = gInventory.getLinkedItemID(bridge->getUUID()); + const LLViewerInventoryItem *linked_item = gInventory.getItem(linked_uuid); + if (linked_item) + perm = linked_item->getPermissionMask(); + } + return (perm & mFilterOps.mPermissions) == mFilterOps.mPermissions; +} + +BOOL LLInventoryFilter::checkAgainstFilterLinks(const LLFolderViewItem* item) const +{ + const LLFolderViewEventListener* listener = item->getListener(); + if (!listener) return TRUE; + + const LLUUID object_id = listener->getUUID(); + const LLInventoryObject *object = gInventory.getObject(object_id); + if (!object) return TRUE; + + const BOOL is_link = object->getIsLinkType(); + if (is_link && (mFilterOps.mFilterLinks == FILTERLINK_EXCLUDE_LINKS)) + return FALSE; + if (!is_link && (mFilterOps.mFilterLinks == FILTERLINK_ONLY_LINKS)) + return FALSE; + return TRUE; +} + const std::string& LLInventoryFilter::getFilterSubString(BOOL trim) const { return mFilterSubString; @@ -125,20 +281,32 @@ std::string::size_type LLInventoryFilter::getStringMatchOffset() const // has user modified default filter params? BOOL LLInventoryFilter::isNotDefault() const { - return mFilterOps.mFilterTypes != mDefaultFilterOps.mFilterTypes - || mFilterSubString.size() - || mFilterWorn - || mFilterOps.mPermissions != mDefaultFilterOps.mPermissions - || mFilterOps.mMinDate != mDefaultFilterOps.mMinDate - || mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate - || mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo; + BOOL not_default = FALSE; + + not_default |= (mFilterOps.mFilterObjectTypes != mDefaultFilterOps.mFilterObjectTypes); + not_default |= (mFilterOps.mFilterCategoryTypes != mDefaultFilterOps.mFilterCategoryTypes); + not_default |= (mFilterOps.mFilterWearableTypes != mDefaultFilterOps.mFilterWearableTypes); + not_default |= (mFilterOps.mFilterTypes != mDefaultFilterOps.mFilterTypes); + not_default |= (mFilterOps.mFilterLinks != mDefaultFilterOps.mFilterLinks); + not_default |= (mFilterSubString.size()); + not_default |= (mFilterOps.mFilterWorn != mDefaultFilterOps.mFilterWorn); + not_default |= (mFilterOps.mPermissions != mDefaultFilterOps.mPermissions); + not_default |= (mFilterOps.mMinDate != mDefaultFilterOps.mMinDate); + not_default |= (mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate); + not_default |= (mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo); + + return not_default; } BOOL LLInventoryFilter::isActive() const { - return mFilterOps.mFilterTypes != 0xffffffff + return mFilterOps.mFilterObjectTypes != 0xffffffffffffffffULL + || mFilterOps.mFilterCategoryTypes != 0xffffffffffffffffULL + || mFilterOps.mFilterWearableTypes != 0xffffffffffffffffULL + || mFilterOps.mFilterTypes != FILTERTYPE_OBJECT + || mFilterOps.mFilterLinks != FILTERLINK_INCLUDE_LINKS || mFilterSubString.size() - || mFilterWorn + || mFilterOps.mFilterWorn != false || mFilterOps.mPermissions != PERM_NONE || mFilterOps.mMinDate != time_min() || mFilterOps.mMaxDate != time_max() @@ -157,15 +325,15 @@ BOOL LLInventoryFilter::isModifiedAndClear() return ret; } -void LLInventoryFilter::setFilterTypes(U32 types) +void LLInventoryFilter::updateFilterTypes(U64 types, U64& current_types) { - if (mFilterOps.mFilterTypes != types) + if (current_types != types) { // keep current items only if no type bits getting turned off - BOOL fewer_bits_set = (mFilterOps.mFilterTypes & ~types); - BOOL more_bits_set = (~mFilterOps.mFilterTypes & types); - - mFilterOps.mFilterTypes = types; + bool fewer_bits_set = (current_types & ~types) != 0; + bool more_bits_set = (~current_types & types) != 0; + + current_types = types; if (more_bits_set && fewer_bits_set) { // neither less or more restrive, both simultaneously @@ -181,10 +349,46 @@ void LLInventoryFilter::setFilterTypes(U32 types) { setModified(FILTER_MORE_RESTRICTIVE); } - } } +void LLInventoryFilter::setFilterObjectTypes(U64 types) +{ + updateFilterTypes(types, mFilterOps.mFilterObjectTypes); + mFilterOps.mFilterTypes |= FILTERTYPE_OBJECT; +} + +void LLInventoryFilter::setFilterCategoryTypes(U64 types) +{ + updateFilterTypes(types, mFilterOps.mFilterCategoryTypes); + mFilterOps.mFilterTypes |= FILTERTYPE_CATEGORY; +} + +void LLInventoryFilter::setFilterWearableTypes(U64 types) +{ + updateFilterTypes(types, mFilterOps.mFilterWearableTypes); + mFilterOps.mFilterTypes |= FILTERTYPE_WEARABLE; +} + +void LLInventoryFilter::setFilterEmptySystemFolders() +{ + mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS; +} + +void LLInventoryFilter::setFilterUUID(const LLUUID& object_id) +{ + if (mFilterOps.mFilterUUID == LLUUID::null) + { + setModified(FILTER_MORE_RESTRICTIVE); + } + else + { + setModified(FILTER_RESTART); + } + mFilterOps.mFilterUUID = object_id; + mFilterOps.mFilterTypes = FILTERTYPE_UUID; +} + void LLInventoryFilter::setFilterSubString(const std::string& string) { std::string filter_sub_string_new = string; @@ -215,6 +419,19 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) { setModified(FILTER_RESTART); } + + // Cancel out UUID once the search string is modified + if (mFilterOps.mFilterTypes == FILTERTYPE_UUID) + { + mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID; + mFilterOps.mFilterUUID == LLUUID::null; + setModified(FILTER_RESTART); + } + + // Cancel out filter links once the search string is modified + { + mFilterOps.mFilterLinks = FILTERLINK_INCLUDE_LINKS; + } } } @@ -256,6 +473,7 @@ void LLInventoryFilter::setDateRange(time_t min_date, time_t max_date) mFilterOps.mMaxDate = llmax(mFilterOps.mMinDate, max_date); setModified(); } + mFilterOps.mFilterTypes |= FILTERTYPE_DATE; } void LLInventoryFilter::setDateRangeLastLogoff(BOOL sl) @@ -270,12 +488,18 @@ void LLInventoryFilter::setDateRangeLastLogoff(BOOL sl) setDateRange(0, time_max()); setModified(); } + mFilterOps.mFilterTypes |= FILTERTYPE_DATE; } BOOL LLInventoryFilter::isSinceLogoff() const { - return (mFilterOps.mMinDate == (time_t)mLastLogoff) && - (mFilterOps.mMaxDate == time_max()); + bool min_date = (mFilterOps.mMinDate == (time_t)mLastLogoff); + bool max_date = (mFilterOps.mMaxDate == time_max()); + bool is_filter = (mFilterOps.mFilterTypes & FILTERTYPE_DATE); + return min_date && max_date && is_filter; + //return (mFilterOps.mMinDate == (time_t)mLastLogoff) && + // (mFilterOps.mMaxDate == time_max()) && + // (mFilterOps.mFilterTypes & FILTERTYPE_DATE); } void LLInventoryFilter::clearModified() @@ -313,7 +537,22 @@ void LLInventoryFilter::setHoursAgo(U32 hours) setModified(FILTER_RESTART); } } + mFilterOps.mFilterTypes |= FILTERTYPE_DATE; } + +void LLInventoryFilter::setFilterLinks(U64 filter_links) +{ + if (mFilterOps.mFilterLinks != filter_links) + { + if (mFilterOps.mFilterLinks == FILTERLINK_EXCLUDE_LINKS || + mFilterOps.mFilterLinks == FILTERLINK_ONLY_LINKS) + setModified(FILTER_MORE_RESTRICTIVE); + else + setModified(FILTER_LESS_RESTRICTIVE); + } + mFilterOps.mFilterLinks = filter_links; +} + void LLInventoryFilter::setShowFolderState(EFolderShow state) { if (mFilterOps.mShowFolderState != state) @@ -403,9 +642,9 @@ void LLInventoryFilter::setModified(EFilterBehavior behavior) } } -BOOL LLInventoryFilter::isFilterWith(LLInventoryType::EType t) const +BOOL LLInventoryFilter::isFilterObjectTypesWith(LLInventoryType::EType t) const { - return mFilterOps.mFilterTypes & (0x01 << t); + return mFilterOps.mFilterObjectTypes & (1LL << t); } const std::string& LLInventoryFilter::getFilterText() @@ -423,7 +662,7 @@ const std::string& LLInventoryFilter::getFilterText() S32 num_filter_types = 0; mFilterText.clear(); - if (isFilterWith(LLInventoryType::IT_ANIMATION)) + if (isFilterObjectTypesWith(LLInventoryType::IT_ANIMATION)) { filtered_types += " Animations,"; filtered_by_type = TRUE; @@ -435,7 +674,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_CALLINGCARD)) + if (isFilterObjectTypesWith(LLInventoryType::IT_CALLINGCARD)) { filtered_types += " Calling Cards,"; filtered_by_type = TRUE; @@ -447,7 +686,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_WEARABLE)) + if (isFilterObjectTypesWith(LLInventoryType::IT_WEARABLE)) { filtered_types += " Clothing,"; filtered_by_type = TRUE; @@ -459,7 +698,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_GESTURE)) + if (isFilterObjectTypesWith(LLInventoryType::IT_GESTURE)) { filtered_types += " Gestures,"; filtered_by_type = TRUE; @@ -471,7 +710,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_LANDMARK)) + if (isFilterObjectTypesWith(LLInventoryType::IT_LANDMARK)) { filtered_types += " Landmarks,"; filtered_by_type = TRUE; @@ -483,7 +722,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_NOTECARD)) + if (isFilterObjectTypesWith(LLInventoryType::IT_NOTECARD)) { filtered_types += " Notecards,"; filtered_by_type = TRUE; @@ -495,7 +734,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_OBJECT) && isFilterWith(LLInventoryType::IT_ATTACHMENT)) + if (isFilterObjectTypesWith(LLInventoryType::IT_OBJECT) && isFilterObjectTypesWith(LLInventoryType::IT_ATTACHMENT)) { filtered_types += " Objects,"; filtered_by_type = TRUE; @@ -507,7 +746,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_LSL)) + if (isFilterObjectTypesWith(LLInventoryType::IT_LSL)) { filtered_types += " Scripts,"; filtered_by_type = TRUE; @@ -519,7 +758,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_SOUND)) + if (isFilterObjectTypesWith(LLInventoryType::IT_SOUND)) { filtered_types += " Sounds,"; filtered_by_type = TRUE; @@ -531,7 +770,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_TEXTURE)) + if (isFilterObjectTypesWith(LLInventoryType::IT_TEXTURE)) { filtered_types += " Textures,"; filtered_by_type = TRUE; @@ -543,7 +782,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (isFilterWith(LLInventoryType::IT_SNAPSHOT)) + if (isFilterObjectTypesWith(LLInventoryType::IT_SNAPSHOT)) { filtered_types += " Snapshots,"; filtered_by_type = TRUE; @@ -588,7 +827,7 @@ const std::string& LLInventoryFilter::getFilterText() void LLInventoryFilter::toLLSD(LLSD& data) const { - data["filter_types"] = (LLSD::Integer)getFilterTypes(); + data["filter_types"] = (LLSD::Integer)getFilterObjectTypes(); data["min_date"] = (LLSD::Integer)getMinDate(); data["max_date"] = (LLSD::Integer)getMaxDate(); data["hours_ago"] = (LLSD::Integer)getHoursAgo(); @@ -603,7 +842,7 @@ void LLInventoryFilter::fromLLSD(LLSD& data) { if(data.has("filter_types")) { - setFilterTypes((U32)data["filter_types"].asInteger()); + setFilterObjectTypes((U32)data["filter_types"].asInteger()); } if(data.has("min_date") && data.has("max_date")) @@ -642,6 +881,16 @@ void LLInventoryFilter::fromLLSD(LLSD& data) } } +U64 LLInventoryFilter::getFilterObjectTypes() const +{ + return mFilterOps.mFilterObjectTypes; +} + +U64 LLInventoryFilter::getFilterCategoryTypes() const +{ + return mFilterOps.mFilterCategoryTypes; +} + BOOL LLInventoryFilter::hasFilterString() const { return mFilterSubString.size() > 0; @@ -665,6 +914,10 @@ U32 LLInventoryFilter::getHoursAgo() const { return mFilterOps.mHoursAgo; } +U64 LLInventoryFilter::getFilterLinks() const +{ + return mFilterOps.mFilterLinks; +} LLInventoryFilter::EFolderShow LLInventoryFilter::getShowFolderState() const { return mFilterOps.mShowFolderState; diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 2d6ef39e1..b999843b5 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -51,8 +51,26 @@ public: FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one }; + enum EFilterType { + FILTERTYPE_NONE = 0, + FILTERTYPE_OBJECT = 0x1 << 0, // normal default search-by-object-type + FILTERTYPE_CATEGORY = 0x1 << 1, // search by folder type + FILTERTYPE_UUID = 0x1 << 2, // find the object with UUID and any links to it + FILTERTYPE_DATE = 0x1 << 3, // search by date range + FILTERTYPE_WEARABLE = 0x1 << 4, // search by wearable type + FILTERTYPE_EMPTYFOLDERS = 0x1 << 5 // pass if folder is not a system folder to be hidden if empty + }; + + enum EFilterLink + { + FILTERLINK_INCLUDE_LINKS, // show links too + FILTERLINK_EXCLUDE_LINKS, // don't show links + FILTERLINK_ONLY_LINKS // only show links + }; + enum ESortOrderType { + SO_NAME = 0, // Sort inventory by name SO_DATE = 0x1, // Sort inventory by date SO_FOLDERS_BY_NAME = 0x1 << 1, // Force folder sort by name SO_SYSTEM_FOLDERS_TO_TOP = 0x1 << 2 // Force system folders to be on top @@ -61,17 +79,26 @@ public: LLInventoryFilter(const std::string& name); virtual ~LLInventoryFilter(); - void setFilterTypes(U32 types); - BOOL isFilterWith(LLInventoryType::EType t) const; - U32 getFilterTypes() const { return mFilterOps.mFilterTypes; } - + // +-------------------------------------------------------------------+ + // + Parameters + // +-------------------------------------------------------------------+ + void setFilterObjectTypes(U64 types); + U64 getFilterObjectTypes() const; + U64 getFilterCategoryTypes() const; + BOOL isFilterObjectTypesWith(LLInventoryType::EType t) const; + void setFilterCategoryTypes(U64 types); + void setFilterUUID(const LLUUID &object_id); + void setFilterWearableTypes(U64 types); + void setFilterEmptySystemFolders(); + void updateFilterTypes(U64 types, U64& current_types); + void setFilterSubString(const std::string& string); const std::string& getFilterSubString(BOOL trim = FALSE) const; const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; } BOOL hasFilterString() const; - void setFilterWorn(bool worn) { mFilterWorn = worn; } - bool getFilterWorn() const { return mFilterWorn; } + void setFilterWorn(bool worn) { mFilterOps.mFilterWorn = worn; } + bool getFilterWorn() const { return mFilterOps.mFilterWorn; } void setFilterPermissions(PermissionMask perms); PermissionMask getFilterPermissions() const; @@ -84,10 +111,18 @@ public: void setHoursAgo(U32 hours); U32 getHoursAgo() const; + void setFilterLinks(U64 filter_link); + U64 getFilterLinks() const; + // +-------------------------------------------------------------------+ // + Execution And Results // +-------------------------------------------------------------------+ - BOOL check(LLFolderViewItem* item); + BOOL check(LLFolderViewItem* item); + bool checkFolder(const LLFolderViewFolder* folder); + BOOL checkAgainstFilterType(const LLFolderViewItem* item) const; + BOOL checkAgainstPermissions(const LLFolderViewItem* item) const; + BOOL checkAgainstFilterLinks(const LLFolderViewItem* item) const; + std::string::size_type getStringMatchOffset() const; // +-------------------------------------------------------------------+ @@ -146,12 +181,20 @@ private: struct FilterOps { FilterOps(); - U32 mFilterTypes; + U32 mFilterTypes; + + U64 mFilterObjectTypes; // For _OBJECT + U64 mFilterWearableTypes; + U64 mFilterCategoryTypes; // For _CATEGORY + LLUUID mFilterUUID; // for UUID + time_t mMinDate; time_t mMaxDate; U32 mHoursAgo; EFolderShow mShowFolderState; PermissionMask mPermissions; + U64 mFilterLinks; + bool mFilterWorn; }; U32 mOrder; @@ -163,21 +206,19 @@ private: std::string::size_type mSubStringMatchOffset; std::string mFilterSubString; std::string mFilterSubStringOrig; - bool mFilterWorn; - - const std::string mName; - S32 mFilterGeneration; - S32 mMustPassGeneration; - S32 mMinRequiredGeneration; - S32 mNextFilterGeneration; + const std::string mName; - S32 mFilterCount; - EFilterBehavior mFilterBehavior; + S32 mFilterGeneration; + S32 mMustPassGeneration; + S32 mMinRequiredGeneration; + S32 mNextFilterGeneration; - BOOL mModified; - BOOL mNeedTextRebuild; - std::string mFilterText; + S32 mFilterCount; + EFilterBehavior mFilterBehavior; + + BOOL mModified; + BOOL mNeedTextRebuild; + std::string mFilterText; }; - #endif diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 7ee2c5714..15601478b 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -204,10 +204,8 @@ BOOL LLInventoryPanel::postBuild() { setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); } - mFolderRoot->setSortOrder(mFolderRoot->getFilter()->getSortOrder()); - - - return TRUE; + getFilter()->setFilterEmptySystemFolders(); + return LLPanel::postBuild(); } LLInventoryPanel::~LLInventoryPanel() @@ -273,11 +271,8 @@ LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac void LLInventoryPanel::draw() { - // select the desired item (in case it wasn't loaded when the selection was requested) - if (mSelectThisID.notNull()) - { - setSelection(mSelectThisID, false); - } + // Select the desired item (in case it wasn't loaded when the selection was requested) + mFolderRoot->updateSelection(); LLPanel::draw(); } @@ -299,14 +294,17 @@ const LLInventoryFilter* LLInventoryPanel::getFilter() const return NULL; } -void LLInventoryPanel::setFilterTypes(U32 filter_types) +void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type) { - getFilter()->setFilterTypes(filter_types); -} + if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT) + getFilter()->setFilterObjectTypes(types); + if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY) + getFilter()->setFilterCategoryTypes(types); +} -U32 LLInventoryPanel::getFilterTypes() const +U32 LLInventoryPanel::getFilterObjectTypes() const { - return mFolderRoot->getFilterTypes(); + return mFolderRoot->getFilterObjectTypes(); } U32 LLInventoryPanel::getFilterPermMask() const @@ -314,11 +312,17 @@ U32 LLInventoryPanel::getFilterPermMask() const return mFolderRoot->getFilterPermissions(); } + void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) { getFilter()->setFilterPermissions(filter_perm_mask); } +void LLInventoryPanel::setFilterWearableTypes(U64 types) +{ + getFilter()->setFilterWearableTypes(types); +} + void LLInventoryPanel::setFilterWorn(bool worn) { getFilter()->setFilterWorn(worn); @@ -334,6 +338,7 @@ const std::string LLInventoryPanel::getFilterSubString() return mFolderRoot->getFilterSubString(); } + void LLInventoryPanel::setSortOrder(U32 order) { getFilter()->setSortOrder(order); @@ -365,6 +370,11 @@ void LLInventoryPanel::setHoursAgo(U32 hours) getFilter()->setHoursAgo(hours); } +void LLInventoryPanel::setFilterLinks(U64 filter_links) +{ + getFilter()->setFilterLinks(filter_links); +} + void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) { getFilter()->setShowFolderState(show); @@ -599,9 +609,7 @@ LLFolderView * LLInventoryPanel::createFolderView(LLInvFVBridge * bridge, bool u 0); LLFolderView* ret = new LLFolderView( - getName(), - NULL, folder_rect, LLUUID::null, this, @@ -615,6 +623,7 @@ LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * br return new LLFolderViewFolder( bridge->getDisplayName(), bridge->getIcon(), + bridge->getOpenIcon(), LLUI::getUIImage("inv_link_overlay.tga"), mFolderRoot, bridge); @@ -625,6 +634,7 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge return new LLFolderViewItem( bridge->getDisplayName(), bridge->getIcon(), + bridge->getOpenIcon(), LLUI::getUIImage("inv_link_overlay.tga"), bridge->getCreationDate(), mFolderRoot, @@ -833,19 +843,29 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* accept, std::string& tooltip_msg) { + BOOL handled = FALSE; - BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - - if (handled) + //if (mAcceptsDragAndDrop) { - mFolderRoot->setDragAndDropThisFrame(); + handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + + // If folder view is empty the (x, y) point won't be in its rect + // so the handler must be called explicitly. + // but only if was not handled before. See EXT-6746. + if (!handled && !mFolderRoot->hasVisibleChildren()) + { + handled = mFolderRoot->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + + if (handled) + { + mFolderRoot->setDragAndDropThisFrame(); + } } return handled; } - - void LLInventoryPanel::onFocusLost() { // inventory no longer handles cut/copy/paste/delete @@ -886,22 +906,18 @@ void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) { - LLFolderViewItem* itemp = mFolderRoot->getItemByID(obj_id); - if(itemp && itemp->getListener()) + // Don't select objects in COF (e.g. to prevent refocus when items are worn). + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF()) { - itemp->getListener()->arrangeAndSet(itemp, TRUE, take_keyboard_focus); - mSelectThisID.setNull(); return; } - else - { - // save the desired item to be selected later (if/when ready) - mSelectThisID = obj_id; - } + mFolderRoot->setSelectionByID(obj_id, take_keyboard_focus); } + void LLInventoryPanel::setSelectCallback(const boost::function& items, BOOL user_action)>& cb) { - if (mFolderRoot) + if (mFolderRoot) { mFolderRoot->setSelectCallback(cb); } @@ -910,7 +926,6 @@ void LLInventoryPanel::setSelectCallback(const boost::functionclearSelection(); - mSelectThisID.setNull(); } void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) @@ -1005,4 +1020,13 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) res = floater_inventory->getActivePanel(); } return res; -} \ No newline at end of file +} +void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type) +{ + getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << folder_type)); +} + +BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const +{ + return !(getFilter()->getFilterCategoryTypes() & (1ULL << folder_type)); +} diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 883fd4636..4a2953f7f 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -105,10 +105,11 @@ public: void clearSelection(); LLInventoryFilter* getFilter(); const LLInventoryFilter* getFilter() const; - void setFilterTypes(U32 filter); - U32 getFilterTypes() const; + void setFilterTypes(U64 filter, LLInventoryFilter::EFilterType = LLInventoryFilter::FILTERTYPE_OBJECT); + U32 getFilterObjectTypes() const; void setFilterPermMask(PermissionMask filter_perm_mask); U32 getFilterPermMask() const; + void setFilterWearableTypes(U64 filter); void setFilterSubString(const std::string& string); const std::string getFilterSubString(); void setFilterWorn(bool worn); @@ -117,7 +118,8 @@ public: void setSinceLogoff(BOOL sl); void setHoursAgo(U32 hours); BOOL getSinceLogoff(); - + void setFilterLinks(U64 filter_links); + void setShowFolderState(LLInventoryFilter::EFolderShow show); LLInventoryFilter::EFolderShow getShowFolderState(); void setAllowMultiSelect(BOOL allow) { mFolderRoot->setAllowMultiSelect(allow); } @@ -187,8 +189,13 @@ public: private: const std::string mSortOrderSetting; - LLUUID mSelectThisID; // if non null, select this item - + + //-------------------------------------------------------------------- + // Hidden folders + //-------------------------------------------------------------------- +public: + void addHideFolderType(LLFolderType::EType folder_type); + public: BOOL getIsViewsInitialized() const { return mViewsInitialized; } const LLUUID& getRootFolderID() const; @@ -199,6 +206,7 @@ protected: virtual void buildFolderView(); LLFolderViewItem* buildNewViews(const LLUUID& id); + BOOL getIsHiddenFolderType(LLFolderType::EType folder_type) const; virtual LLFolderView* createFolderView(LLInvFVBridge * bridge, bool useLabelSuffix); virtual LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge); diff --git a/indra/newview/lllocalinventory.cpp b/indra/newview/lllocalinventory.cpp index dbe79684e..c6578ed8c 100644 --- a/indra/newview/lllocalinventory.cpp +++ b/indra/newview/lllocalinventory.cpp @@ -333,8 +333,7 @@ void LLLocalInventory::loadInvCache(std::string filename) void LLLocalInventory::saveInvCache(std::string filename, LLFolderView* folder) { LLInventoryModel* model = &gInventory; - std::set selected_items; - folder->getSelectionList(selected_items); + std::set selected_items = folder->getSelectionList(); if(selected_items.size() < 1) { // No items selected? Wtfboom diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 3743a49b8..edd3dc458 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -71,7 +71,6 @@ public: BOOL getCheckSinceLogoff(); static void onTimeAgo(LLUICtrl*, void *); - static void onCheckSinceLogoff(LLUICtrl*, void *); static void onCloseBtn(void* user_data); static void selectAllTypes(void* user_data); static void selectNoTypes(void* user_data); @@ -153,6 +152,7 @@ BOOL LLInventoryView::postBuild() mActivePanel->getFilter()->markDefault(); mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); mActivePanel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, mActivePanel, _1, _2)); + mResortActivePanel = true; } LLInventoryPanel* recent_items_panel = getChild("Recent Items"); if (recent_items_panel) @@ -221,8 +221,6 @@ BOOL LLInventoryView::postBuild() childSetAction("Inventory.ResetAll",onResetAll,this); childSetAction("Inventory.ExpandAll",onExpandAll,this); childSetAction("collapse_btn", onCollapseAll, this); - - //panel->getFilter()->markDefault(); return TRUE; } @@ -349,12 +347,12 @@ BOOL LLInventoryView::handleKeyHere(KEY key, MASK mask) && mask == MASK_NONE) { // move focus to inventory proper - root_folder->setFocus(TRUE); + mActivePanel->setFocus(TRUE); root_folder->scrollToShowSelection(); return TRUE; } - if (root_folder->hasFocus() && key == KEY_UP) + if (mActivePanel->hasFocus() && key == KEY_UP) { startSearch(); } @@ -528,6 +526,7 @@ void LLInventoryView::onClearSearch(void* user_data) { self->mActivePanel->setFilterSubString(LLStringUtil::null); self->mActivePanel->setFilterTypes(0xffffffff); + self->mActivePanel->setFilterLinks(LLInventoryFilter::FILTERLINK_INCLUDE_LINKS); } if (finder) @@ -544,6 +543,7 @@ void LLInventoryView::onClearSearch(void* user_data) self->mActivePanel->getRootFolder()->applyFunctorRecursively(opener); self->mActivePanel->getRootFolder()->scrollToShowSelection(); } + self->mFilterSubString = ""; } //static @@ -561,10 +561,8 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ LLInventoryModelBackgroundFetch::instance().start(); - std::string filter_text = search_string; - std::string uppercase_search_string = filter_text; - LLStringUtil::toUpper(uppercase_search_string); - if (self->mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty()) + self->mFilterSubString = search_string; + if (self->mActivePanel->getFilterSubString().empty() && self->mFilterSubString.empty()) { // current filter and new filter empty, do nothing return; @@ -578,7 +576,7 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ } // set new filter string - self->mActivePanel->setFilterSubString(uppercase_search_string); + self->setFilterSubString(self->mFilterSubString); } struct FilterEntry : public LLDictionaryEntry @@ -677,7 +675,7 @@ void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) return; } - U32 filter_type = view->mActivePanel->getFilterTypes(); + U32 filter_type = view->mActivePanel->getFilterObjectTypes(); if(!LLFilterDictionary::instanceExists()) LLFilterDictionary::instance().init(view); @@ -688,12 +686,12 @@ void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) for (LLFilterDictionary::const_iterator_t dictionary_iter = LLFilterDictionary::instance().map_t::begin(); dictionary_iter != LLFilterDictionary::instance().map_t::end(); dictionary_iter++) { - if(filter_mask != 0xffffffff) + if(dictionary_iter->first != 0xffffffff) filter_mask |= dictionary_iter->first; } filter_type &= filter_mask; - + //llinfos << "filter_type: " << filter_type << llendl; std::string selection; @@ -705,7 +703,7 @@ void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) { const FilterEntry *entry = LLFilterDictionary::instance().lookup(filter_type); if(entry) - selection = view->getString(entry->mName); + selection = entry->mName; else selection = view->getString("filter_type_custom"); } @@ -767,9 +765,6 @@ void LLInventoryView::onCollapseAll(void* userdata) void LLInventoryView::onFilterSelected(void* userdata, bool from_click) { LLInventoryView* self = (LLInventoryView*) userdata; - LLInventoryFilter* filter; - - LLFloaterInventoryFinder *finder = self->getFinder(); // Find my index self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs"); @@ -777,7 +772,10 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) { return; } - filter = self->mActivePanel->getFilter(); + + self->setFilterSubString(self->mFilterSubString); + LLInventoryFilter* filter = self->mActivePanel->getFilter(); + LLFloaterInventoryFinder *finder = self->getFinder(); if (finder) { finder->changeFilter(filter); @@ -810,7 +808,7 @@ BOOL LLInventoryView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, { // Check to see if we are auto scrolling from the last frame LLInventoryPanel* panel = (LLInventoryPanel*)this->getActivePanel(); - BOOL needsToScroll = panel->getScrollableContainer()->needsToScroll(x, y, LLScrollableContainerView::VERTICAL); + BOOL needsToScroll = panel->getScrollableContainer()->autoScroll(x, y); if(mFilterTabs) { if(needsToScroll) @@ -825,6 +823,39 @@ BOOL LLInventoryView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, } void LLInventoryView::changed(U32 mask) +{ + updateItemcountText(); +} + +void LLInventoryView::draw() +{ + if (mActivePanel && mSearchEditor) + { + mSearchEditor->setText(mActivePanel->getFilterSubString()); + } + + if (mActivePanel && mQuickFilterCombo) + { + refreshQuickFilter( mQuickFilterCombo ); + } + + if (mActivePanel && mResortActivePanel) + { + // EXP-756: Force resorting of the list the first time we draw the list: + // In the case of date sorting, we don't have enough information at initialization time + // to correctly sort the folders. Later manual resort doesn't do anything as the order value is + // set correctly. The workaround is to reset the order to alphabetical (or anything) then to the correct order. + U32 order = mActivePanel->getSortOrder(); + mActivePanel->setSortOrder(LLInventoryFilter::SO_NAME); + mActivePanel->setSortOrder(order); + mResortActivePanel = false; + } + + updateItemcountText(); + LLFloater::draw(); +} + +void LLInventoryView::updateItemcountText() { std::ostringstream title; title << "Inventory"; @@ -839,33 +870,6 @@ void LLInventoryView::changed(U32 mask) setTitle(title.str()); } - -void LLInventoryView::draw() -{ - if (LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { - LLLocale locale(LLLocale::USER_LOCALE); - std::ostringstream title; - title << "Inventory"; - std::string item_count_string; - LLResMgr::getInstance()->getIntegerString(item_count_string, gInventory.getItemCount()); - title << " (" << item_count_string << " items)"; - title << mFilterText; - setTitle(title.str()); - } - if (mActivePanel && mSearchEditor) - { - mSearchEditor->setText(mActivePanel->getFilterSubString()); - } - - if (mActivePanel && mQuickFilterCombo) - { - refreshQuickFilter( mQuickFilterCombo ); - } - - LLFloater::draw(); -} - void LLInventoryView::setFilterTextFromFilter() { mFilterText = mActivePanel->getFilter()->getFilterText(); @@ -935,6 +939,9 @@ LLFloaterInventoryFinder::LLFloaterInventoryFinder(const std::string& name, BOOL LLFloaterInventoryFinder::postBuild() { + const LLRect& viewrect = mInventoryView->getRect(); + setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); + childSetAction("All", selectAllTypes, this); childSetAction("None", selectNoTypes, this); @@ -944,30 +951,12 @@ BOOL LLFloaterInventoryFinder::postBuild() mSpinSinceDays = getChild("spin_days_ago"); childSetCommitCallback("spin_days_ago", onTimeAgo, this); -// mCheckSinceLogoff = getChild("check_since_logoff"); - childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this); - childSetAction("Close", onCloseBtn, this); updateElementsFromFilter(); return TRUE; } - -void LLFloaterInventoryFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data) -{ - LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; - if (!self) return; - - bool since_logoff= self->childGetValue("check_since_logoff"); - - if (!since_logoff && - !( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) ) - { - self->mSpinSinceHours->set(1.0f); - } -} - void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) { LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; @@ -993,7 +982,7 @@ void LLFloaterInventoryFinder::updateElementsFromFilter() return; // Get data needed for filter display - U32 filter_types = mFilter->getFilterTypes(); + U32 filter_types = mFilter->getFilterObjectTypes(); std::string filter_string = mFilter->getFilterSubString(); LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); U32 hours = mFilter->getHoursAgo(); @@ -1101,9 +1090,9 @@ void LLFloaterInventoryFinder::draw() } // update the panel, panel will update the filter - mInventoryView->mActivePanel->setShowFolderState(getCheckShowEmpty() ? + mInventoryView->getPanel()->setShowFolderState(getCheckShowEmpty() ? LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mInventoryView->mActivePanel->setFilterTypes(filter); + mInventoryView->getPanel()->setFilterTypes(filter); if (getCheckSinceLogoff()) { mSpinSinceDays->set(0); @@ -1119,8 +1108,8 @@ void LLFloaterInventoryFinder::draw() mSpinSinceHours->set((F32)hours); } hours += days * 24; - mInventoryView->mActivePanel->setHoursAgo(hours); - mInventoryView->mActivePanel->setSinceLogoff(getCheckSinceLogoff()); + mInventoryView->getPanel()->setHoursAgo(hours); + mInventoryView->getPanel()->setSinceLogoff(getCheckSinceLogoff()); mInventoryView->setFilterTextFromFilter(); LLFloater::draw(); @@ -1174,18 +1163,6 @@ void LLFloaterInventoryFinder::selectAllTypes(void* user_data) self->childSetValue("check_sound", TRUE); self->childSetValue("check_texture", TRUE); self->childSetValue("check_snapshot", TRUE); - -/* - self->mCheckCallingCard->set(TRUE); - self->mCheckClothing->set(TRUE); - self->mCheckGesture->set(TRUE); - self->mCheckLandmark->set(TRUE); - self->mCheckNotecard->set(TRUE); - self->mCheckObject->set(TRUE); - self->mCheckScript->set(TRUE); - self->mCheckSound->set(TRUE); - self->mCheckTexture->set(TRUE); - self->mCheckSnapshot->set(TRUE);*/ } //static @@ -1194,20 +1171,6 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data) LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; if(!self) return; - /* - self->childSetValue("check_animation", FALSE); - self->mCheckCallingCard->set(FALSE); - self->mCheckClothing->set(FALSE); - self->mCheckGesture->set(FALSE); - self->mCheckLandmark->set(FALSE); - self->mCheckNotecard->set(FALSE); - self->mCheckObject->set(FALSE); - self->mCheckScript->set(FALSE); - self->mCheckSound->set(FALSE); - self->mCheckTexture->set(FALSE); - self->mCheckSnapshot->set(FALSE);*/ - - self->childSetValue("check_animation", FALSE); self->childSetValue("check_calling_card", FALSE); self->childSetValue("check_clothing", FALSE); diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 60d7d73b9..6b2ca33b4 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -124,7 +124,7 @@ public: void updateSortControls(); void resetFilters(); - + void updateItemcountText(); // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) static void closeAll() @@ -166,9 +166,10 @@ protected: LLTabContainer* mFilterTabs; LLHandle mFinderHandle; LLInventoryPanel* mActivePanel; + bool mResortActivePanel; LLSaveFolderState* mSavedFolderState; - std::string mFilterText; + std::string mFilterSubString; // This container is used to hold all active inventory views. This diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 5883d7b60..3a3b61264 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -328,15 +328,15 @@ const std::string& LLTaskInvFVBridge::getDisplayName() const if(!copy) { - mDisplayName.append(" (no copy)"); + mDisplayName.append(LLTrans::getString("no_copy")); } if(!mod) { - mDisplayName.append(" (no modify)"); + mDisplayName.append(LLTrans::getString("no_modify")); } if(!xfer) { - mDisplayName.append(" (no transfer)"); + mDisplayName.append(LLTrans::getString("no_transfer")); } } @@ -852,7 +852,7 @@ void LLTaskCategoryBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { std::vector items; std::vector disabled_items; - items.push_back(std::string("Task Open")); // *TODO: Translate + //items.push_back(std::string("Task Open")); // *TODO: Translate hide_context_entries(menu, items, disabled_items); } @@ -1108,9 +1108,9 @@ void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } } } - else + else if (canOpenItem()) { - items.push_back(std::string("Task Open")); + //items.push_back(std::string("Task Open")); if (!isItemCopyable()) { disabled_items.push_back(std::string("Task Open")); @@ -1618,7 +1618,7 @@ void LLPanelObjectInventory::reset() setBorderVisible(FALSE); LLRect dummy_rect(0, 1, 1, 0); - mFolders = new LLFolderView(std::string("task inventory"), NULL, dummy_rect, getTaskUUID(), this, LLTaskInvFVBridge::createObjectBridge(this, NULL)); + mFolders = new LLFolderView(std::string("task inventory"), dummy_rect, getTaskUUID(), this, LLTaskInvFVBridge::createObjectBridge(this, NULL)); // this ensures that we never say "searching..." or "no items found" mFolders->getFilter()->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); @@ -1681,9 +1681,9 @@ void LLPanelObjectInventory::updateInventory() // We're still interested in this task's inventory. std::set selected_items; BOOL inventory_has_focus = FALSE; - if (mHaveInventory && mFolders->getNumSelectedDescendants()) + if (mHaveInventory) { - mFolders->getSelectionList(selected_items); + selected_items = mFolders->getSelectionList(); inventory_has_focus = gFocusMgr.childHasKeyboardFocus(mFolders); } @@ -1737,7 +1737,7 @@ void LLPanelObjectInventory::updateInventory() } } - mFolders->arrangeFromRoot(); + mFolders->requestArrange(); mInventoryNeedsUpdate = FALSE; } @@ -1760,6 +1760,7 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root LLFolderViewFolder* new_folder = NULL; new_folder = new LLFolderViewFolder(inventory_root->getName(), bridge->getIcon(), + bridge->getOpenIcon(), NULL, mFolders, bridge); @@ -1798,6 +1799,7 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li { view = new LLFolderViewFolder(obj->getName(), bridge->getIcon(), + bridge->getOpenIcon(), NULL, mFolders, bridge); @@ -1808,6 +1810,7 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li { view = new LLFolderViewItem(obj->getName(), bridge->getIcon(), + bridge->getOpenIcon(), NULL, bridge->getCreationDate(), mFolders, @@ -1975,3 +1978,22 @@ void LLPanelObjectInventory::idle(void* user_data) self->updateInventory(); } } + +void LLPanelObjectInventory::onFocusLost() +{ + // inventory no longer handles cut/copy/paste/delete + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + + LLPanel::onFocusLost(); +} + +void LLPanelObjectInventory::onFocusReceived() +{ + // inventory now handles cut/copy/paste/delete + LLEditMenuHandler::gEditMenuHandler = mFolders; + + LLPanel::onFocusReceived(); +} diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index 3a2fc59cb..74a8ff7d3 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -61,7 +61,9 @@ public: virtual void deleteAllChildren(); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); - + /*virtual*/ void onFocusLost(); + /*virtual*/ void onFocusReceived(); + static void idle(void* user_data); protected: diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index b005857b1..8c7184ede 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -66,7 +66,7 @@ struct ViewerFolderEntry : public LLDictionaryEntry mIconNameOpen(icon_name), mIconNameClosed(icon_name), */ - mIconNameOpen("inv_folder_plain_closed.tga"), mIconNameClosed("inv_folder_plain_closed.tga"), + mIconNameOpen("inv_folder_plain_open.tga"), mIconNameClosed("inv_folder_plain_closed.tga"), mNewCategoryName(new_category_name), mIsQuiet(FALSE), mHideIfEmpty(false) @@ -117,7 +117,7 @@ LLViewerFolderDictionary::LLViewerFolderDictionary() addEntry(LLFolderType::FT_CLOTHING, new ViewerFolderEntry("Clothing", "inv_folder_clothing.tga", "inv_folder_clothing.tga", FALSE, false)); addEntry(LLFolderType::FT_OBJECT, new ViewerFolderEntry("Objects", "inv_folder_object.tga", "inv_folder_object.tga", FALSE, false)); addEntry(LLFolderType::FT_NOTECARD, new ViewerFolderEntry("Notecards", "inv_folder_notecard.tga", "inv_folder_notecard.tga", FALSE, false)); - addEntry(LLFolderType::FT_ROOT_INVENTORY, new ViewerFolderEntry("My Inventory", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_ROOT_INVENTORY, new ViewerFolderEntry("My Inventory", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); addEntry(LLFolderType::FT_LSL_TEXT, new ViewerFolderEntry("Scripts", "inv_folder_script.tga", "inv_folder_script.tga", FALSE, false)); addEntry(LLFolderType::FT_BODYPART, new ViewerFolderEntry("Body Parts", "inv_folder_bodypart.tga", "inv_folder_bodypart.tga", FALSE, false)); addEntry(LLFolderType::FT_TRASH, new ViewerFolderEntry("Trash", "inv_folder_trash.tga", "inv_folder_trash.tga", TRUE, false)); @@ -125,26 +125,26 @@ LLViewerFolderDictionary::LLViewerFolderDictionary() addEntry(LLFolderType::FT_LOST_AND_FOUND, new ViewerFolderEntry("Lost And Found", "inv_folder_lostandfound.tga", "inv_folder_lostandfound.tga", TRUE, false)); addEntry(LLFolderType::FT_ANIMATION, new ViewerFolderEntry("Animations", "inv_folder_animation.tga", "inv_folder_animation.tga", FALSE, false)); addEntry(LLFolderType::FT_GESTURE, new ViewerFolderEntry("Gestures", "inv_folder_gesture.tga", "inv_folder_gesture.tga", FALSE, false)); - addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE, false)); - addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE, false)); - addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE, false)); - addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", TRUE, false)); + addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", TRUE, false)); + addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", TRUE, false)); + addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Outbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Outbox", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); - addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false, "default")); + addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false, "default")); #if SUPPORT_ENSEMBLES initEnsemblesFromFile(); #else for (U32 type = (U32)LLFolderType::FT_ENSEMBLE_START; type <= (U32)LLFolderType::FT_ENSEMBLE_END; ++type) { - addEntry((LLFolderType::EType)type, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry((LLFolderType::EType)type, new ViewerFolderEntry("New Folder", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); } #endif } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5c5e6de60..d6be37009 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -308,7 +308,7 @@ template<> bool SH_SpamHandler::isAgent(const std::string &owner) bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLMessageSystem* msg = gMessageSystem; const LLSD& payload = notification["payload"]; switch(option) @@ -730,7 +730,7 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) bool join_group_response(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); BOOL delete_context_data = TRUE; bool accept_invite = false; @@ -919,7 +919,7 @@ private: mSelectedItems.clear(); if (LLInventoryPanel::getActiveInventoryPanel()) { - LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(mSelectedItems); + mSelectedItems = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); } mSelectedItems.erase(mMoveIntoFolderID); } @@ -954,8 +954,7 @@ private: } // get selected items (without destination folder) - selected_items_t selected_items; - active_panel->getRootFolder()->getSelectionList(selected_items); + selected_items_t selected_items = active_panel->getRootFolder()->getSelectionList(); selected_items.erase(mMoveIntoFolderID); // compare stored & current sets of selected items From 2f632d3324398cfef129390dd20319ed2bb8747e Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 27 Feb 2012 19:04:47 -0600 Subject: [PATCH 16/32] Worn items have bold text in inventory. Also made label text for worn items more legible. --- indra/newview/llfolderview.cpp | 15 +++++------ indra/newview/llfolderviewitem.cpp | 40 +++++++++++++++++++++--------- indra/newview/llfolderviewitem.h | 7 ++++-- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 527e3f0f0..7b01cee85 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -253,7 +253,7 @@ LLFolderView::LLFolderView( const std::string& name, // just make sure the label ("Inventory Folder") never shows up mLabel = LLStringUtil::null; - mRenamer = new LLLineEditor(std::string("ren"), getRect(), LLStringUtil::null, sFont, + mRenamer = new LLLineEditor(std::string("ren"), getRect(), LLStringUtil::null, getLabelFontForStyle(LLFontGL::NORMAL), DB_INV_ITEM_NAME_STR_LEN, &LLFolderView::commitRename, NULL, @@ -466,7 +466,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen getRoot()->getFilter()->getShowFolderState(); S32 total_width = LEFT_PAD; - S32 running_height = mDebugFilters ? llceil(sSmallFont->getLineHeight()) : 0; + S32 running_height = mDebugFilters ? llceil(LLFontGL::getFontMonospace()->getLineHeight()) : 0; S32 target_height = running_height; S32 parent_item_height = getRect().getHeight(); @@ -921,8 +921,8 @@ void LLFolderView::draw() { std::string current_filter_string = llformat("Current Filter: %d, Least Filter: %d, Auto-accept Filter: %d", mFilter->getCurrentGeneration(), mFilter->getMinRequiredGeneration(), mFilter->getMustPassGeneration()); - sSmallFont->renderUTF8(current_filter_string, 0, 2, - getRect().getHeight() - sSmallFont->getLineHeight(), LLColor4(0.5f, 0.5f, 0.8f, 1.f), + LLFontGL::getFontMonospace()->renderUTF8(current_filter_string, 0, 2, + getRect().getHeight() - LLFontGL::getFontMonospace()->getLineHeight(), LLColor4(0.5f, 0.5f, 0.8f, 1.f), LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); } @@ -964,16 +964,17 @@ void LLFolderView::draw() } else if (mShowEmptyMessage) { + const LLFontGL* font = getLabelFontForStyle(mLabelStyle); static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) { mStatusText = std::string("Searching..."); // *TODO:translate - sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); + font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); } else { mStatusText = std::string("No matching items found in inventory."); // *TODO:translate - sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); + font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); } } @@ -1997,7 +1998,7 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr LLRect visible_doc_rect = mScrollContainer->getVisibleContentRect(); S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); - S32 label_height = llround(sFont->getLineHeight()); + S32 label_height = llround(getLabelFontForStyle(mLabelStyle)->getLineHeight()); // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 71453494f..7f860023e 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -44,9 +44,9 @@ #include "llfocusmgr.h" // gFocusMgr #include "lltrans.h" // statics -const LLFontGL* LLFolderViewItem::sFont = NULL; -const LLFontGL* LLFolderViewItem::sSmallFont = NULL; +std::map LLFolderViewItem::sFonts; // map of styles to fonts +// only integers can be initialized in header const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f; const F32 LLFolderViewItem::FOLDER_OPEN_TIME_CONSTANT = 0.03f; @@ -57,11 +57,26 @@ LLUIImagePtr LLFolderViewItem::sBoxImage; // avoid a crash bug due to a race condition (see in doIdle()). std::set sFolderViewItems; +//static +LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style) +{ + LLFontGL* rtn = sFonts[style]; + if (!rtn) // grab label font with this style, lazily + { + LLFontDescriptor labelfontdesc("SansSerif", "Small", style); + rtn = LLFontGL::getFont(labelfontdesc); + if (!rtn) + { + rtn = LLFontGL::getFontMonospace(); + } + sFonts[style] = rtn; + } + return rtn; +} + //static void LLFolderViewItem::initClass() { - sFont = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); - sSmallFont = LLResMgr::getInstance()->getRes( LLFONT_SMALL ); sArrowImage = LLUI::getUIImage("folder_arrow.tga"); sBoxImage = LLUI::getUIImage("rounded_square.tga"); } @@ -69,6 +84,7 @@ void LLFolderViewItem::initClass() //static void LLFolderViewItem::cleanupClass() { + sFonts.clear(); sArrowImage = NULL; sBoxImage = NULL; } @@ -411,7 +427,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height, S32 filter_generation) : 0; if (mLabelWidthDirty) { - mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + sFont->getWidth(mSearchableLabel); + mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + getLabelFontForStyle(mLabelStyle)->getWidth(mSearchableLabel); mLabelWidthDirty = false; } @@ -876,9 +892,9 @@ void LLFolderViewItem::draw() static LLCachedControl sSuffixColor(gColors, "InventoryItemSuffixColor", LLColor4::white ); static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); - const S32 TOP_PAD = 0; - const S32 FOCUS_LEFT = 0; - const LLFontGL* font = sFont; + const S32 TOP_PAD = 4; + const S32 FOCUS_LEFT = 1; + const LLFontGL* font = getLabelFontForStyle(mLabelStyle); const BOOL in_inventory = getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(), gInventory.getRootFolderID()); const BOOL in_library = getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(), gInventory.getLibraryRootFolderID()); @@ -1016,7 +1032,7 @@ void LLFolderViewItem::draw() LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? LLColor4(0.5f, 0.8f, 0.5f, 1.f) : LLColor4(0.8f, 0.5f, 0.5f, 1.f); - sSmallFont->renderUTF8(mStatusText, 0, text_left, y, filter_color, + LLFontGL::getFontMonospace()->renderUTF8(mStatusText, 0, text_left, y, filter_color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE ); text_left = right_x; @@ -1048,7 +1064,7 @@ void LLFolderViewItem::draw() { std::string load_string = " ( Loading... ) "; font->renderUTF8(load_string, 0, right_x, y, sSearchStatusColor, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE); } @@ -1058,7 +1074,7 @@ void LLFolderViewItem::draw() if (!mLabelSuffix.empty()) { font->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE ); } @@ -1081,7 +1097,7 @@ void LLFolderViewItem::draw() F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; font->renderUTF8( combined_string, mStringMatchOffset, match_string_left, yy, - sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, filter_string_length, S32_MAX, &right_x, FALSE ); } } diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 65fa2fda7..ca9da12ea 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -108,8 +108,6 @@ private: BOOL mIsSelected; protected: - static const LLFontGL* sFont; - static const LLFontGL* sSmallFont; static LLUIImagePtr sArrowImage; static LLUIImagePtr sBoxImage; @@ -159,6 +157,8 @@ protected: virtual BOOL addItem(LLFolderViewItem*) { return FALSE; } virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } + static LLFontGL* getLabelFontForStyle(U8 style); + virtual void setCreationDate(time_t creation_date_utc) { mCreationDate = creation_date_utc; } public: @@ -329,6 +329,9 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); + +private: + static std::map sFonts; // map of styles to fonts }; From fb10af2723c97a6c0f1c8e5067b4fae725b62333 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 28 Feb 2012 18:46:54 -0600 Subject: [PATCH 17/32] Reverted inventory search behavor to pre v2. (search is per-panel, not global to the inventory floater) --- indra/newview/llinventorybridge.cpp | 7 +++++++ indra/newview/llinventoryfilter.cpp | 3 ++- indra/newview/llpanelmaininventory.cpp | 15 +++++++++------ indra/newview/llpanelmaininventory.h | 2 +- indra/newview/llwearable.cpp | 13 ++++++------- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 23a9375c7..3ed9560d5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5245,6 +5245,13 @@ void LLWearableBridge::wearOnAvatar() void LLWearableBridge::wearAddOnAvatar() { // TODO: investigate wearables may not be loaded at this point EXT-8231 + // Don't wear anything until initial wearables are loaded, can + // destroy clothing items. + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); + return; + } LLViewerInventoryItem* item = getItem(); if(item) diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index c73d9995c..a5bd75877 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -429,8 +429,9 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) } // Cancel out filter links once the search string is modified + // Singu Note: No, don't do this... { - mFilterOps.mFilterLinks = FILTERLINK_INCLUDE_LINKS; + //mFilterOps.mFilterLinks = FILTERLINK_INCLUDE_LINKS; } } } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index edd3dc458..ac746097b 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -170,6 +170,7 @@ BOOL LLInventoryView::postBuild() worn_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); worn_items_panel->getFilter()->markDefault(); worn_items_panel->setFilterWorn(true); + worn_items_panel->setFilterLinks(LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS); worn_items_panel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, worn_items_panel, _1, _2)); } @@ -526,7 +527,6 @@ void LLInventoryView::onClearSearch(void* user_data) { self->mActivePanel->setFilterSubString(LLStringUtil::null); self->mActivePanel->setFilterTypes(0xffffffff); - self->mActivePanel->setFilterLinks(LLInventoryFilter::FILTERLINK_INCLUDE_LINKS); } if (finder) @@ -543,7 +543,7 @@ void LLInventoryView::onClearSearch(void* user_data) self->mActivePanel->getRootFolder()->applyFunctorRecursively(opener); self->mActivePanel->getRootFolder()->scrollToShowSelection(); } - self->mFilterSubString = ""; + //self->mFilterSubString = ""; } //static @@ -561,8 +561,11 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ LLInventoryModelBackgroundFetch::instance().start(); - self->mFilterSubString = search_string; - if (self->mActivePanel->getFilterSubString().empty() && self->mFilterSubString.empty()) + //self->mFilterSubString = search_string; + std::string filter_text = search_string; + std::string uppercase_search_string = filter_text; + LLStringUtil::toUpper(uppercase_search_string); + if (self->mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty() /*self->mFilterSubString.empty()*/) { // current filter and new filter empty, do nothing return; @@ -576,7 +579,7 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ } // set new filter string - self->setFilterSubString(self->mFilterSubString); + self->mActivePanel->setFilterSubString(uppercase_search_string/*self->mFilterSubString*/); } struct FilterEntry : public LLDictionaryEntry @@ -773,7 +776,7 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) return; } - self->setFilterSubString(self->mFilterSubString); + //self->setFilterSubString(self->mFilterSubString); LLInventoryFilter* filter = self->mActivePanel->getFilter(); LLFloaterInventoryFinder *finder = self->getFinder(); if (finder) diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 6b2ca33b4..44f6c7f09 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -169,7 +169,7 @@ protected: bool mResortActivePanel; LLSaveFolderState* mSavedFolderState; std::string mFilterText; - std::string mFilterSubString; + //std::string mFilterSubString; // This container is used to hold all active inventory views. This diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 82917326c..cda83f523 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -161,8 +161,7 @@ BOOL LLWearable::FileExportTextures( FILE* file ) iter != mTEMap.end(); ++iter) { S32 te = iter->first; - LLUUID& image_id = iter->second->getID(); - fprintf( file, "%d %s\n", te, image_id.asString().c_str() ); + fprintf( file, "%d %s\n", te, iter->second->getID().asString().c_str() ); } return TRUE; @@ -1243,11 +1242,11 @@ void LLWearable::pullCrossWearableValues() //pretty sure is right if(param->getID() == 507) avatar->setActualBoobGrav(param->getWeight()); - /*if(param->getID() == 151) - avatar->setActualButtGrav(param->getWeight()); - if(param->getID() == 157) - avatar->setActualFatGrav(param->getWeight()); - *//* + //if(param->getID() == 151) + // avatar->setActualButtGrav(param->getWeight()); + //if(param->getID() == 157) + // avatar->setActualFatGrav(param->getWeight()); + //if(param->getID() == 507) //{ // llwarns << "current = " << avatar->getActualBoobGrav() << llendl; From 500135941a434984c39d0427ec617851ee32167d Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 2 Mar 2012 16:57:33 -0600 Subject: [PATCH 18/32] Modernized lluictrl. Added LLViewModel. Fixed focus callbacks being called excessively. Updated LLButton, and implemented boost::signals2 to replace old callback handling. --- indra/llui/CMakeLists.txt | 2 + indra/llui/llbutton.cpp | 900 ++++++++++++++---------- indra/llui/llbutton.h | 238 ++++--- indra/llui/llcheckboxctrl.cpp | 101 ++- indra/llui/llcheckboxctrl.h | 13 +- indra/llui/llcombobox.cpp | 16 +- indra/llui/llfloater.cpp | 6 +- indra/llui/llscrollbar.cpp | 4 +- indra/llui/llscrolllistctrl.cpp | 10 +- indra/llui/llspinctrl.cpp | 4 +- indra/llui/lltabcontainer.cpp | 12 +- indra/llui/lluictrl.cpp | 59 +- indra/llui/lluictrl.h | 17 +- indra/llui/llview.cpp | 10 - indra/llui/llview.h | 4 - indra/llui/llviewmodel.cpp | 157 +++++ indra/llui/llviewmodel.h | 214 ++++++ indra/newview/hippofloaterxml.cpp | 27 +- indra/newview/llfloateranimpreview.cpp | 14 +- indra/newview/llfloatercolorpicker.cpp | 9 +- indra/newview/llfloatercustomize.cpp | 12 +- indra/newview/llfloaterlagmeter.cpp | 24 +- indra/newview/llfloatertools.cpp | 92 ++- indra/newview/llfloatertools.h | 4 +- indra/newview/lljoystickbutton.cpp | 5 +- indra/newview/lljoystickbutton.h | 2 +- indra/newview/llmoveview.cpp | 8 +- indra/newview/llpanelclassified.cpp | 14 +- indra/newview/llpanelevent.cpp | 12 +- indra/newview/llpanelgroup.cpp | 14 +- indra/newview/llpanelgroupgeneral.cpp | 10 +- indra/newview/llpanelgroupinvite.cpp | 14 +- indra/newview/llpanelgrouplandmoney.cpp | 2 +- indra/newview/llpanelgroupnotices.cpp | 15 +- indra/newview/llpanelgrouproles.cpp | 88 +-- indra/newview/llpanelgrouproles.h | 15 +- indra/newview/llpanelgroupvoting.cpp | 30 +- indra/newview/llpanelmediahud.cpp | 16 +- indra/newview/llpanelpick.cpp | 9 +- indra/newview/llpanelplace.cpp | 12 +- indra/newview/llpanelskins.cpp | 6 +- indra/newview/llpreviewgesture.cpp | 16 +- indra/newview/llprogressview.cpp | 4 +- indra/newview/llprogressview.h | 2 +- indra/newview/lltoolplacer.cpp | 33 - indra/newview/lltoolplacer.h | 16 - indra/newview/llvoiceremotectrl.cpp | 20 +- indra/newview/llvoiceremotectrl.h | 8 +- 48 files changed, 1359 insertions(+), 961 deletions(-) create mode 100644 indra/llui/llviewmodel.cpp create mode 100644 indra/llui/llviewmodel.h diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index b144f9c3d..92a54d021 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -79,6 +79,7 @@ set(llui_SOURCE_FILES lluistring.cpp llundo.cpp llviewborder.cpp + llviewmodel.cpp llview.cpp llviewquery.cpp ) @@ -146,6 +147,7 @@ set(llui_HEADER_FILES lluixmltags.h llundo.h llviewborder.h + llviewmodel.h llview.h llviewquery.h ) diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index c4bdbfc4a..fa371cf1e 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -63,47 +63,64 @@ S32 BORDER_SIZE = 1; LLButton::LLButton( const std::string& name, const LLRect& rect, const std::string& control_name, void (*click_callback)(void*), void *callback_data) : LLUICtrl(name, rect, TRUE, NULL, NULL), - mClickedCallback( click_callback ), - mMouseDownCallback( NULL ), - mMouseUpCallback( NULL ), - mHeldDownCallback( NULL ), - mGLFont( NULL ), + mMouseDownFrame( 0 ), - mHeldDownDelay( 0.5f ), // seconds until held-down callback is called - mHeldDownFrameDelay( 0 ), - mImageUnselected( NULL ), - mImageSelected( NULL ), - mImageHoverSelected( NULL ), - mImageHoverUnselected( NULL ), - mImageDisabled( NULL ), - mImageDisabledSelected( NULL ), - mToggleState( FALSE ), - mIsToggle( FALSE ), - mScaleImage( TRUE ), - mDropShadowedText( TRUE ), + mMouseHeldDownCount(0), mBorderEnabled( FALSE ), mFlashing( FALSE ), + mCurGlowStrength(0.f), + mNeedsHighlight(FALSE), + mUnselectedLabel(name), + mSelectedLabel(name), + mGLFont( LLFontGL::getFontSansSerif() ), + mHeldDownDelay( 0.5f ), // seconds until held-down callback is called + mHeldDownFrameDelay( 0 ), + mImageUnselected(LLUI::getUIImage("button_enabled_32x128.tga")), + mImageSelected(LLUI::getUIImage("button_enabled_selected_32x128.tga")), + mImageDisabled(LLUI::getUIImage("button_disabled_32x128.tga")), + mImageDisabledSelected(LLUI::getUIImage("button_disabled_32x128.tga")), + mImagePressed(LLUI::getUIImage("button_enabled_selected_32x128.tga")), + mImagePressedSelected(LLUI::getUIImage("button_enabled_32x128.tga")), + mImageFlash(NULL), + mImageHoverSelected( NULL ), + mImageHoverUnselected( NULL ), + mUnselectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelColor" )), + mSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedColor")), + mDisabledLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelDisabledColor")), + mDisabledSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedDisabledColor")), + mImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), + mFlashBgColor(LLUI::sColorsGroup->getColor("ButtonFlashBgColor")), + mDisabledImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), + mImageOverlay(NULL), + mImageOverlayColor(LLColor4::white), + mImageOverlayDisabledColor(LLColor4(1.f,1.f,1.f,.5f)), + mImageOverlaySelectedColor(LLColor4::white), + mImageOverlayAlignment(LLFontGL::HCENTER), + mImageOverlayTopPad(0), + mImageOverlayBottomPad(0), + mImgOverlayLabelSpace(1), + mIsToggle( FALSE ), + mScaleImage( TRUE ), + mDropShadowedText( TRUE ), + mAutoResize( FALSE ), mHAlign( LLFontGL::HCENTER ), mLeftHPad( LLBUTTON_H_PAD ), mRightHPad( LLBUTTON_H_PAD ), - mHoverGlowStrength(0.15f), - mCurGlowStrength(0.f), - mNeedsHighlight(FALSE), + mBottomVPad( LLBUTTON_V_PAD ), + mHoverGlowStrength(0.25f), mCommitOnReturn(TRUE), - mImagep( NULL ) + mFadeWhenDisabled(FALSE), + mForcePressedState(false), + mDisplayPressedState(TRUE), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL), + mHeldDownSignal(NULL), + mHandleRightMouse(false), + mButtonFlashCount(LLUI::sConfigGroup->getS32("ButtonFlashCount")), + mButtonFlashRate(LLUI::sConfigGroup->getF32("ButtonFlashRate")), + mAlpha(1.f) { - mUnselectedLabel = name; - mSelectedLabel = name; - - setImageUnselected(std::string("button_enabled_32x128.tga")); - setImageSelected(std::string("button_enabled_selected_32x128.tga")); - setImageDisabled(std::string("button_disabled_32x128.tga")); - setImageDisabledSelected(std::string("button_disabled_32x128.tga")); - - mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - - init(click_callback, callback_data, NULL, control_name); + init(click_callback, callback_data, control_name); } @@ -117,79 +134,92 @@ LLButton::LLButton(const std::string& name, const LLRect& rect, const std::string& unselected_label, const std::string& selected_label ) : LLUICtrl(name, rect, TRUE, NULL, NULL), - mClickedCallback( click_callback ), - mMouseDownCallback( NULL ), - mMouseUpCallback( NULL ), - mHeldDownCallback( NULL ), - mGLFont( NULL ), mMouseDownFrame( 0 ), + mMouseHeldDownCount(0), + mBorderEnabled( FALSE ), + mFlashing( FALSE ), + mCurGlowStrength(0.f), + mNeedsHighlight(FALSE), + mUnselectedLabel(unselected_label), + mSelectedLabel(selected_label), + mGLFont( font ? font : LLFontGL::getFontSansSerif() ), mHeldDownDelay( 0.5f ), // seconds until held-down callback is called mHeldDownFrameDelay( 0 ), - mImageUnselected( NULL ), - mImageSelected( NULL ), + mImageUnselected(LLUI::getUIImage("button_enabled_32x128.tga")), + mImageSelected(LLUI::getUIImage("button_enabled_selected_32x128.tga")), + mImageDisabled(LLUI::getUIImage("button_disabled_32x128.tga")), + mImageDisabledSelected(LLUI::getUIImage("button_disabled_32x128.tga")), + mImagePressed(LLUI::getUIImage("button_enabled_selected_32x128.tga")), + mImagePressedSelected(LLUI::getUIImage("button_enabled_32x128.tga")), + mImageFlash(NULL), mImageHoverSelected( NULL ), mImageHoverUnselected( NULL ), - mImageDisabled( NULL ), - mImageDisabledSelected( NULL ), - mToggleState( FALSE ), + mUnselectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelColor" )), + mSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedColor")), + mDisabledLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelDisabledColor")), + mDisabledSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedDisabledColor")), + mImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), + mFlashBgColor(LLUI::sColorsGroup->getColor("ButtonFlashBgColor")), + mDisabledImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), + mImageOverlay(NULL), + mImageOverlayColor(LLColor4::white), + mImageOverlayDisabledColor(LLColor4(1.f,1.f,1.f,.5f)), + mImageOverlaySelectedColor(LLColor4::white), + mImageOverlayAlignment(LLFontGL::HCENTER), + mImageOverlayTopPad(0), + mImageOverlayBottomPad(0), + mImgOverlayLabelSpace(1), mIsToggle( FALSE ), mScaleImage( TRUE ), mDropShadowedText( TRUE ), - mBorderEnabled( FALSE ), - mFlashing( FALSE ), + mAutoResize( FALSE ), mHAlign( LLFontGL::HCENTER ), mLeftHPad( LLBUTTON_H_PAD ), mRightHPad( LLBUTTON_H_PAD ), + mBottomVPad( LLBUTTON_V_PAD ), mHoverGlowStrength(0.25f), - mCurGlowStrength(0.f), - mNeedsHighlight(FALSE), mCommitOnReturn(TRUE), - mImagep( NULL ) + mFadeWhenDisabled(FALSE), + mForcePressedState(false), + mDisplayPressedState(TRUE), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL), + mHeldDownSignal(NULL), + mHandleRightMouse(false), + mButtonFlashCount(LLUI::sConfigGroup->getS32("ButtonFlashCount")), + mButtonFlashRate(LLUI::sConfigGroup->getF32("ButtonFlashRate")), + mAlpha(1.f) { - mUnselectedLabel = unselected_label; - mSelectedLabel = selected_label; - - // by default, disabled color is same as enabled - mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); if( unselected_image_name != "" ) { // user-specified image - don't use fixed borders unless requested - setImageUnselected(unselected_image_name); - setImageDisabled(unselected_image_name); + mImageUnselected = LLUI::getUIImage(unselected_image_name); + mImageDisabled = mImageUnselected; - mDisabledImageColor.mV[VALPHA] = 0.5f; - mScaleImage = FALSE; - } - else - { - setImageUnselected(std::string("button_enabled_32x128.tga")); - setImageDisabled(std::string("button_disabled_32x128.tga")); + mFadeWhenDisabled = TRUE; + //mScaleImage = FALSE; + + mImagePressedSelected = mImageUnselected; } if( selected_image_name != "" ) { // user-specified image - don't use fixed borders unless requested - setImageSelected(selected_image_name); - setImageDisabledSelected(selected_image_name); + mImageSelected = LLUI::getUIImage(selected_image_name); + mImageDisabled = mImageSelected; - mDisabledImageColor.mV[VALPHA] = 0.5f; - mScaleImage = FALSE; - } - else - { - setImageSelected(std::string("button_enabled_selected_32x128.tga")); - setImageDisabledSelected(std::string("button_disabled_32x128.tga")); + mFadeWhenDisabled = TRUE; + //mScaleImage = FALSE; + + mImagePressed = mImageSelected; } - init(click_callback, callback_data, font, control_name); + init(click_callback, callback_data, control_name); } -void LLButton::init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name) +void LLButton::init(void (*click_callback)(void*), void *callback_data, const std::string& control_name) { - mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); - // Hack to make sure there is space for at least one character if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) { @@ -198,30 +228,22 @@ void LLButton::init(void (*click_callback)(void*), void *callback_data, const LL mRightHPad = LLBUTTON_ORIG_H_PAD; } - mCallbackUserData = callback_data; mMouseDownTimer.stop(); - + + if(click_callback) + setClickedCallback(click_callback, callback_data); + setControlName(control_name, NULL); - mUnselectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelColor" ) ); - mSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedColor" ) ); - mDisabledLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelDisabledColor" ) ); - mDisabledSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedDisabledColor" ) ); - mHighlightColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) ); - mUnselectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) ); - mSelectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) ); - mFlashBgColor = ( LLUI::sColorsGroup->getColor( "ButtonFlashBgColor" ) ); - - mImageOverlayAlignment = LLFontGL::HCENTER; - mImageOverlayColor = LLColor4::white; } + +// virtual LLButton::~LLButton() { - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - } + delete mMouseDownSignal; + delete mMouseUpSignal; + delete mHeldDownSignal; } // HACK: Committing a button is the same as instantly clicking it. @@ -229,19 +251,12 @@ LLButton::~LLButton() void LLButton::onCommit() { // WARNING: Sometimes clicking a button destroys the floater or - // panel containing it. Therefore we need to call mClickedCallback + // panel containing it. Therefore we need to call LLUICtrl::onCommit() // LAST, otherwise this becomes deleted memory. - LLUICtrl::onCommit(); - if (mMouseDownCallback) - { - (*mMouseDownCallback)(mCallbackUserData); - } + if (mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); - if (mMouseUpCallback) - { - (*mMouseUpCallback)(mCallbackUserData); - } + if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); if (getSoundFlags() & MOUSE_DOWN) { @@ -259,13 +274,66 @@ void LLButton::onCommit() } // do this last, as it can result in destroying this button - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); +} + +/*boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) +{ + return setClickedCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setMouseDownCallback(const CommitCallbackParam& cb) +{ + return setMouseDownCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackParam& cb) +{ + return setMouseUpCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb) +{ + return setHeldDownCallback(initCommitCallback(cb)); +}*/ + + +boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mCommitSignal) mCommitSignal = new commit_signal_t(); + return mCommitSignal->connect(cb); +} +boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); + return mMouseDownSignal->connect(cb); +} +boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); + return mMouseUpSignal->connect(cb); +} +boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mHeldDownSignal) mHeldDownSignal = new commit_signal_t(); + return mHeldDownSignal->connect(cb); } +// *TODO: Deprecate (for backwards compatibility only) +boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data ) +{ + return setClickedCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data ) +{ + return setMouseDownCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data ) +{ + return setMouseUpCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data ) +{ + return setHeldDownCallback(boost::bind(cb, data)); +} BOOL LLButton::handleUnicodeCharHere(llwchar uni_char) { @@ -278,10 +346,8 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char) toggleState(); } - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); + handled = TRUE; } return handled; @@ -299,10 +365,7 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask ) handled = TRUE; - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); } return handled; } @@ -310,27 +373,35 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask ) BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) { - // Route future Mouse messages here preemptively. (Release on mouse up.) - gFocusMgr.setMouseCapture( this ); - - if (hasTabStop() && !getIsChrome()) + if (!childrenHandleMouseDown(x, y, mask)) { - setFocus(TRUE); - } + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); - if (mMouseDownCallback) - { - (*mMouseDownCallback)(mCallbackUserData); - } + if (hasTabStop() && !getIsChrome()) + { + setFocus(TRUE); + } + + /* + * ATTENTION! This call fires another mouse down callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseDownSignal(x, y, mask); + */ + LLUICtrl::handleMouseDown(x, y, mask); + + if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); mMouseDownTimer.start(); - mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); - - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } + mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); + mMouseHeldDownCount = 0; + + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + } return TRUE; } @@ -343,14 +414,17 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) // Always release the mouse gFocusMgr.setMouseCapture( NULL ); - // Regardless of where mouseup occurs, handle callback - if (mMouseUpCallback) - { - (*mMouseUpCallback)(mCallbackUserData); - } + /* + * ATTENTION! This call fires another mouse up callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseUpSignal(x, y, mask); + */ + LLUICtrl::handleMouseUp(x, y, mask); - mMouseDownTimer.stop(); - mMouseDownTimer.reset(); + // Regardless of where mouseup occurs, handle callback + if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); + + resetMouseDownTimer(); // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. // If mouseup in the widget, it's been clicked @@ -366,83 +440,167 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) toggleState(); } - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); } } + else + { + childrenHandleMouseUp(x, y, mask); + } return TRUE; } +BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mHandleRightMouse && !childrenHandleRightMouseDown(x, y, mask)) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + + if (hasTabStop() && !getIsChrome()) + { + setFocus(TRUE); + } + +// if (pointInView(x, y)) +// { +// } + // send the mouse down signal + LLUICtrl::handleRightMouseDown(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way + // if they are not mouse opaque. + } + + return TRUE; +} + +BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + if (mHandleRightMouse) + { + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + // Always release the mouse + gFocusMgr.setMouseCapture( NULL ); + + // if (pointInView(x, y)) + // { + // mRightMouseUpSignal(this, x,y,mask); + // } + } + else + { + childrenHandleRightMouseUp(x, y, mask); + } + + // send the mouse up signal + LLUICtrl::handleRightMouseUp(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way. + // if they are not mouse opaque. + } + return TRUE; +} + +void LLButton::setHighlight(bool b) +{ + mNeedsHighlight = b; +} BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) { - LLMouseHandler* other_captor = gFocusMgr.getMouseCapture(); - mNeedsHighlight = other_captor == NULL || - other_captor == this || - // this following bit is to support modal dialogs - (other_captor->isView() && hasAncestor((LLView*)other_captor)); + if (isInEnabledChain() + && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this)) + mNeedsHighlight = TRUE; - if (mMouseDownTimer.getStarted() && NULL != mHeldDownCallback) + if (!childrenHandleHover(x, y, mask)) { - F32 elapsed = getHeldDownTime(); - if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) + if (mMouseDownTimer.getStarted()) { - mHeldDownCallback( mCallbackUserData ); + F32 elapsed = getHeldDownTime(); + if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) + { + LLSD param; + param["count"] = mMouseHeldDownCount++; + if (mHeldDownSignal) (*mHeldDownSignal)(this, param); + } } + + // We only handle the click if the click both started and ended within us + getWindow()->setCursor(UI_CURSOR_ARROW); + lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; } - - // We only handle the click if the click both started and ended within us - getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; - return TRUE; } +void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height) +{ + overlay_width = mImageOverlay->getWidth(); + overlay_height = mImageOverlay->getHeight(); + + F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); + overlay_width = llround((F32)overlay_width * scale_factor); + overlay_height = llround((F32)overlay_height * scale_factor); +} + // virtual void LLButton::draw() { - BOOL flash = FALSE; + F32 alpha = mAlpha; + bool flash = FALSE; if( mFlashing ) { F32 elapsed = mFlashingTimer.getElapsedTimeF32(); - S32 flash_count = S32(elapsed * LLUI::sConfigGroup->getF32("ButtonFlashRate") * 2.f); + S32 flash_count = S32(elapsed * mButtonFlashRate * 2.f); // flash on or off? - flash = (flash_count % 2 == 0) || flash_count > S32((F32)LLUI::sConfigGroup->getS32("ButtonFlashCount") * 2.f); + flash = (flash_count % 2 == 0) || flash_count > S32((F32)mButtonFlashCount * 2.f); } - BOOL pressed_by_keyboard = FALSE; + bool pressed_by_keyboard = FALSE; if (hasFocus()) { pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN)); } - // Unselected image assignments - S32 local_mouse_x; - S32 local_mouse_y; - LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + bool mouse_pressed_and_over = false; + if (hasMouseCapture()) + { + S32 local_mouse_x ; + S32 local_mouse_y; + LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y); + } - BOOL pressed = pressed_by_keyboard - || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y)) - || mToggleState; + bool enabled = isInEnabledChain(); - BOOL use_glow_effect = FALSE; + bool pressed = pressed_by_keyboard + || mouse_pressed_and_over + || mForcePressedState; + bool selected = getToggleState(); + + bool use_glow_effect = FALSE; LLColor4 glow_color = LLColor4::white; LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA; - if ( mNeedsHighlight ) + LLUIImage* imagep = NULL; + if (pressed && mDisplayPressedState) { - if (pressed) + imagep = selected ? mImagePressedSelected : mImagePressed; + } + else if ( mNeedsHighlight ) + { + if (selected) { if (mImageHoverSelected) { - mImagep = mImageHoverSelected; + imagep = mImageHoverSelected; } else { - mImagep = mImageSelected; + imagep = mImageSelected; use_glow_effect = TRUE; } } @@ -450,32 +608,18 @@ void LLButton::draw() { if (mImageHoverUnselected) { - mImagep = mImageHoverUnselected; + imagep = mImageHoverUnselected; } else { - mImagep = mImageUnselected; + imagep = mImageUnselected; use_glow_effect = TRUE; } } } - else if ( pressed ) + else { - mImagep = mImageSelected; - } - else - { - mImagep = mImageUnselected; - } - - if (mFlashing) - { - use_glow_effect = TRUE; - glow_type = LLRender::BT_ALPHA; // blend the glow - if (mNeedsHighlight) // highlighted AND flashing - glow_color = (glow_color*0.5f + mFlashBgColor*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity - else - glow_color = mFlashBgColor; + imagep = selected ? mImageSelected : mImageUnselected; } // Override if more data is available @@ -485,19 +629,41 @@ void LLButton::draw() // disabled but checked if (!mImageDisabledSelected.isNull() && - ( (getEnabled() && getTentative()) - || (!getEnabled() && pressed ) ) ) + ( (enabled && getTentative()) + || (!enabled && selected ) ) ) { - mImagep = mImageDisabledSelected; + imagep = mImageDisabledSelected; } else if (!mImageDisabled.isNull() - && !getEnabled() - && !pressed) + && !enabled + && !selected) { - mImagep = mImageDisabled; + imagep = mImageDisabled; } - if (mNeedsHighlight && !mImagep) + if (mFlashing) + { + // if button should flash and we have icon for flashing, use it as image for button + if(flash && mImageFlash) + { + // setting flash to false to avoid its further influence on glow + flash = false; + imagep = mImageFlash; + } + // else use usual flashing via flash_color + else + { + LLColor4 flash_color = mFlashBgColor.get(); + use_glow_effect = TRUE; + glow_type = LLRender::BT_ALPHA; // blend the glow + if (mNeedsHighlight) // highlighted AND flashing + glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity + else + glow_color = flash_color; + } + } + + if (mNeedsHighlight && !imagep) { use_glow_effect = TRUE; } @@ -506,60 +672,37 @@ void LLButton::draw() LLColor4 label_color; // label changes when button state changes, not when pressed - if ( getEnabled() ) + if ( enabled ) { - if ( mToggleState ) + if ( getToggleState() ) { - label_color = mSelectedLabelColor; + label_color = mSelectedLabelColor.get(); } else { - label_color = mUnselectedLabelColor; + label_color = mUnselectedLabelColor.get(); } } else { - if ( mToggleState ) + if ( getToggleState() ) { - label_color = mDisabledSelectedLabelColor; + label_color = mDisabledSelectedLabelColor.get(); } else { - label_color = mDisabledLabelColor; + label_color = mDisabledLabelColor.get(); } } // Unselected label assignments - LLWString label; - - if( mToggleState ) - { - if( getEnabled() || mDisabledSelectedLabel.empty() ) - { - label = mSelectedLabel; - } - else - { - label = mDisabledSelectedLabel; - } - } - else - { - if( getEnabled() || mDisabledLabel.empty() ) - { - label = mUnselectedLabel; - } - else - { - label = mDisabledLabel; - } - } + LLWString label = getCurrentLabel(); // overlay with keyboard focus border if (hasFocus()) { F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); - drawBorder(gFocusMgr.getFocusColor(), llround(lerp(1.f, 3.f, lerp_amt))); + drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, llround(lerp(1.f, 3.f, lerp_amt))); } if (use_glow_effect) @@ -576,25 +719,27 @@ void LLButton::draw() // Draw button image, if available. // Otherwise draw basic rectangular button. - if (mImagep.notNull()) + if (imagep != NULL) { + // apply automatic 50% alpha fade to disabled image + LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get(); if ( mScaleImage) { - mImagep->draw(getLocalRect(), getEnabled() ? mImageColor : mDisabledImageColor ); + imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha ); if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - mImagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % mCurGlowStrength); + imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } else { - mImagep->draw(0, 0, getEnabled() ? mImageColor : mDisabledImageColor ); + imagep->draw(0, 0, (enabled ? mImageColor.get() : disabled_color) % alpha ); if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - mImagep->drawSolid(0, 0, glow_color % mCurGlowStrength); + imagep->drawSolid(0, 0, glow_color % (mCurGlowStrength * alpha)); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } @@ -602,9 +747,9 @@ void LLButton::draw() else { // no image - llwarns << "No image for button " << getName() << llendl; + lldebugs << "No image for button " << getName() << llendl; // draw it in pink so we can find it - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1, FALSE); + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, FALSE); } // let overlay image and text play well together @@ -616,37 +761,41 @@ void LLButton::draw() if (mImageOverlay.notNull() && mImageOverlay->getWidth() > 1) { // get max width and height (discard level 0) - S32 overlay_width = mImageOverlay->getWidth(); - S32 overlay_height = mImageOverlay->getHeight(); + S32 overlay_width; + S32 overlay_height; - F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); - overlay_width = llround((F32)overlay_width * scale_factor); - overlay_height = llround((F32)overlay_height * scale_factor); + getOverlayImageSize(overlay_width, overlay_height); S32 center_x = getLocalRect().getCenterX(); S32 center_y = getLocalRect().getCenterY(); //FUGLY HACK FOR "DEPRESSED" BUTTONS - if (pressed) + if (pressed && mDisplayPressedState) { center_y--; center_x++; } + center_y += (mImageOverlayBottomPad - mImageOverlayTopPad); // fade out overlay images on disabled buttons - LLColor4 overlay_color = mImageOverlayColor; - if (!getEnabled()) + LLColor4 overlay_color = mImageOverlayColor.get(); + if (!enabled) { - overlay_color.mV[VALPHA] = 0.5f; + overlay_color = mImageOverlayDisabledColor.get(); } + else if (getToggleState()) + { + overlay_color = mImageOverlaySelectedColor.get(); + } + overlay_color.mV[VALPHA] *= alpha; switch(mImageOverlayAlignment) { case LLFontGL::LEFT: - text_left += overlay_width + 1; - text_width -= overlay_width + 1; + text_left += overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; mImageOverlay->draw( - mLeftHPad, + mLeftHPad, center_y - (overlay_height / 2), overlay_width, overlay_height, @@ -661,10 +810,10 @@ void LLButton::draw() overlay_color); break; case LLFontGL::RIGHT: - text_right -= overlay_width + 1; - text_width -= overlay_width + 1; + text_right -= overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; mImageOverlay->draw( - getRect().getWidth() - mRightHPad - overlay_width, + getRect().getWidth() - mRightHPad - overlay_width, center_y - (overlay_height / 2), overlay_width, overlay_height, @@ -698,7 +847,7 @@ void LLButton::draw() S32 y_offset = 2 + (getRect().getHeight() - 20)/2; - if (pressed) + if (pressed && mDisplayPressedState) { y_offset--; x++; @@ -706,8 +855,8 @@ void LLButton::draw() mGLFont->render(label, 0, (F32)x, - (F32)(LLBUTTON_V_PAD + y_offset), - label_color, + (F32)(mBottomVPad + y_offset), + label_color % alpha, mHAlign, LLFontGL::BOTTOM, LLFontGL::NORMAL, mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW, @@ -720,45 +869,45 @@ void LLButton::draw() { drawDebugRect(); } - + // reset hover status for next frame mNeedsHighlight = FALSE; + + LLUICtrl::draw(); } -void LLButton::drawBorder(const LLColor4& color, S32 size) +void LLButton::drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size) { + if (imagep == NULL) return; if (mScaleImage) { - mImagep->drawBorder(getLocalRect(), color, size); + imagep->drawBorder(getLocalRect(), color, size); } else { - mImagep->drawBorder(0, 0, color, size); + imagep->drawBorder(0, 0, color, size); } } -void LLButton::setClickedCallback(void (*cb)(void*), void* userdata) +BOOL LLButton::getToggleState() const { - mClickedCallback = cb; - if (userdata) - { - mCallbackUserData = userdata; - } + return getValue().asBoolean(); } - void LLButton::setToggleState(BOOL b) { - if( b != mToggleState ) + if( b != getToggleState() ) { setControlValue(b); // will fire LLControlVariable callbacks (if any) - mToggleState = b; // may or may not be redundant + setValue(b); // may or may not be redundant + // Unselected label assignments + autoResize(); } } void LLButton::setFlashing( BOOL b ) { - if (b != mFlashing) + if ((bool)b != mFlashing) { mFlashing = b; mFlashingTimer.reset(); @@ -768,18 +917,10 @@ void LLButton::setFlashing( BOOL b ) BOOL LLButton::toggleState() { - setToggleState( !mToggleState ); - return mToggleState; -} + bool flipped = ! getToggleState(); + setToggleState(flipped); -void LLButton::setValue(const LLSD& value ) -{ - mToggleState = value.asBoolean(); -} - -LLSD LLButton::getValue() const -{ - return mToggleState == TRUE; + return flipped; } void LLButton::setLabel( const LLStringExplicit& label ) @@ -806,26 +947,72 @@ void LLButton::setLabelSelected( const LLStringExplicit& label ) mSelectedLabel = label; } -void LLButton::setDisabledLabel( const LLStringExplicit& label ) +const LLUIString& LLButton::getCurrentLabel() const { - mDisabledLabel = label; -} - -void LLButton::setDisabledSelectedLabel( const LLStringExplicit& label ) -{ - mDisabledSelectedLabel = label; + if( getToggleState() ) + { + return mSelectedLabel; + } + else + { + return mUnselectedLabel; + } } void LLButton::setImageUnselected(LLPointer image) { mImageUnselected = image; + if (mImageUnselected.isNull()) + { + llwarns << "Setting default button image for: " << getName() << " to NULL" << llendl; + } } +void LLButton::autoResize() +{ + resize(getCurrentLabel()); +} + +void LLButton::resize(LLUIString label) +{ + // get label length + S32 label_width = mGLFont->getWidth(label.getString()); + // get current btn length + S32 btn_width =getRect().getWidth(); + // check if it need resize + if (mAutoResize) + { + S32 min_width = label_width + mLeftHPad + mRightHPad; + if (mImageOverlay) + { + S32 overlay_width = mImageOverlay->getWidth(); + F32 scale_factor = (getRect().getHeight() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (F32)mImageOverlay->getHeight(); + overlay_width = llround((F32)overlay_width * scale_factor); + + switch(mImageOverlayAlignment) + { + case LLFontGL::LEFT: + case LLFontGL::RIGHT: + min_width += overlay_width + mImgOverlayLabelSpace; + break; + case LLFontGL::HCENTER: + min_width = llmax(min_width, overlay_width + mLeftHPad + mRightHPad); + break; + default: + // draw nothing + break; + } + } + if (btn_width < min_width) + { + reshape(min_width, getRect().getHeight()); + } + } +} void LLButton::setImages( const std::string &image_name, const std::string &selected_name ) { - setImageUnselected(image_name); - setImageSelected(selected_name); - + setImageUnselected(LLUI::getUIImage(image_name)); + setImageSelected(LLUI::getUIImage(selected_name)); } void LLButton::setImageSelected(LLPointer image) @@ -843,31 +1030,18 @@ void LLButton::setColor(const LLColor4& color) setImageColor(color); } -void LLButton::setAlpha(F32 alpha) -{ - mImageColor.setAlpha(alpha); - mDisabledImageColor.setAlpha(alpha * 0.5f); -} - void LLButton::setImageDisabled(LLPointer image) { mImageDisabled = image; mDisabledImageColor = mImageColor; - mDisabledImageColor.mV[VALPHA] *= 0.5f; + mFadeWhenDisabled = TRUE; } void LLButton::setImageDisabledSelected(LLPointer image) { mImageDisabledSelected = image; mDisabledImageColor = mImageColor; - mDisabledImageColor.mV[VALPHA] *= 0.5f; -} - -void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name, const LLColor4& c ) -{ - setImageDisabled(image_name); - setImageDisabledSelected(selected_name); - mDisabledImageColor = c; + mFadeWhenDisabled = TRUE; } void LLButton::setImageHoverSelected(LLPointer image) @@ -875,22 +1049,14 @@ void LLButton::setImageHoverSelected(LLPointer image) mImageHoverSelected = image; } -void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name) -{ - LLColor4 clr = mImageColor; - clr.mV[VALPHA] *= .5f; - setDisabledImages( image_name, selected_name, clr ); -} - void LLButton::setImageHoverUnselected(LLPointer image) { mImageHoverUnselected = image; } -void LLButton::setHoverImages( const std::string& image_name, const std::string& selected_name ) +void LLButton::setImageFlash(LLPointer image) { - setImageHoverUnselected(image_name); - setImageHoverSelected(selected_name); + mImageFlash = image; } void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment, const LLColor4& color) @@ -907,11 +1073,23 @@ void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign a } } +void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment, const LLColor4& color) +{ + if (image_id.isNull()) + { + mImageOverlay = NULL; + } + else + { + mImageOverlay = LLUI::getUIImageByID(image_id); + mImageOverlayAlignment = alignment; + mImageOverlayColor = color; + } +} void LLButton::onMouseCaptureLost() { - mMouseDownTimer.stop(); - mMouseDownTimer.reset(); + resetMouseDownTimer(); } //------------------------------------------------------------------------- @@ -932,55 +1110,23 @@ S32 round_up(S32 grid, S32 value) } } -void LLButton::setImageUnselected(const std::string &image_name) -{ - setImageUnselected(LLUI::getUIImage(image_name)); - mImageUnselectedName = image_name; -} - -void LLButton::setImageSelected(const std::string &image_name) -{ - setImageSelected(LLUI::getUIImage(image_name)); - mImageSelectedName = image_name; -} - -void LLButton::setImageHoverSelected(const std::string &image_name) -{ - setImageHoverSelected(LLUI::getUIImage(image_name)); - mImageHoverSelectedName = image_name; -} - -void LLButton::setImageHoverUnselected(const std::string &image_name) -{ - setImageHoverUnselected(LLUI::getUIImage(image_name)); - mImageHoverUnselectedName = image_name; -} - -void LLButton::setImageDisabled(const std::string &image_name) -{ - setImageDisabled(LLUI::getUIImage(image_name)); - mImageDisabledName = image_name; -} - -void LLButton::setImageDisabledSelected(const std::string &image_name) -{ - setImageDisabledSelected(LLUI::getUIImage(image_name)); - mImageDisabledSelectedName = image_name; -} - void LLButton::addImageAttributeToXML(LLXMLNodePtr node, - const std::string& image_name, - const LLUUID& image_id, + const LLPointer image, const std::string& xml_tag_name) const { - if( !image_name.empty() ) - { + if(!image) + return; + + const std::string image_name = image->getName(); + + if(image_name.empty()) + return; + + LLUUID id; + if(!id.set(image_name, false)) node->createChild(xml_tag_name.c_str(), TRUE)->setStringValue(image_name); - } - else if( image_id != LLUUID::null ) - { - node->createChild((xml_tag_name + "_id").c_str(), TRUE)->setUUIDValue(image_id); - } + else + node->createChild((xml_tag_name + "_id").c_str(), TRUE)->setUUIDValue(id); } // virtual @@ -995,12 +1141,12 @@ LLXMLNodePtr LLButton::getXML(bool save_children) const node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont)); node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign)); - addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,std::string("image_unselected")); - addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,std::string("image_selected")); - addImageAttributeToXML(node,mImageHoverSelectedName,mImageHoverSelectedID,std::string("image_hover_selected")); - addImageAttributeToXML(node,mImageHoverUnselectedName,mImageHoverUnselectedID,std::string("image_hover_unselected")); - addImageAttributeToXML(node,mImageDisabledName,mImageDisabledID,std::string("image_disabled")); - addImageAttributeToXML(node,mImageDisabledSelectedName,mImageDisabledSelectedID,std::string("image_disabled_selected")); + addImageAttributeToXML(node,mImageUnselected,std::string("image_unselected")); + addImageAttributeToXML(node,mImageSelected,std::string("image_selected")); + addImageAttributeToXML(node,mImageHoverSelected,std::string("image_hover_selected")); + addImageAttributeToXML(node,mImageHoverUnselected,std::string("image_hover_unselected")); + addImageAttributeToXML(node,mImageDisabled,std::string("image_disabled")); + addImageAttributeToXML(node,mImageDisabledSelected,std::string("image_disabled_selected")); node->createChild("scale_image", TRUE)->setBoolValue(mScaleImage); @@ -1082,13 +1228,13 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa node->getAttributeBOOL("toggle", is_toggle); button->setIsToggle(is_toggle); - if(image_hover_selected != LLStringUtil::null) button->setImageHoverSelected(image_hover_selected); + if(image_hover_selected != LLStringUtil::null) button->setImageHoverSelected(LLUI::getUIImage(image_hover_selected)); - if(image_hover_unselected != LLStringUtil::null) button->setImageHoverUnselected(image_hover_unselected); + if(image_hover_unselected != LLStringUtil::null) button->setImageHoverUnselected(LLUI::getUIImage(image_hover_unselected)); - if(image_disabled_selected != LLStringUtil::null) button->setImageDisabledSelected(image_disabled_selected ); + if(image_disabled_selected != LLStringUtil::null) button->setImageDisabledSelected(LLUI::getUIImage(image_disabled_selected)); - if(image_disabled != LLStringUtil::null) button->setImageDisabled(image_disabled); + if(image_disabled != LLStringUtil::null) button->setImageDisabled(LLUI::getUIImage(image_disabled)); if(image_overlay != LLStringUtil::null) button->setImageOverlay(image_overlay, image_overlay_alignment); @@ -1126,6 +1272,18 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa return button; } +void LLButton::resetMouseDownTimer() +{ + mMouseDownTimer.stop(); + mMouseDownTimer.reset(); +} + +BOOL LLButton::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + // just treat a double click as a second click + return handleMouseDown(x, y, mask); +} + void LLButton::setHelpURLCallback(const std::string &help_url) { mHelpURL = help_url; diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index d9fde0ea8..039ee034b 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -41,6 +41,8 @@ #include "llfontgl.h" #include "lluiimage.h" #include "lluistring.h" +#include "llinitparam.h" +#include "lluicolor.h" // // Constants @@ -85,21 +87,26 @@ public: const LLFontGL* mGLFont = NULL, const std::string& unselected_label = LLStringUtil::null, const std::string& selected_label = LLStringUtil::null ); +public: - virtual ~LLButton(); - void init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name); + ~LLButton(); + // For backward compatability only + typedef boost::function button_callback_t; - - void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName, - const LLUUID& imageID,const std::string& xmlTagName) const; + void addImageAttributeToXML(LLXMLNodePtr node, const LLPointer, const std::string& xmlTagName) const; + void init(void (*click_callback)(void*), void *callback_data, const std::string& control_name); virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + virtual void setAlpha( F32 alpha ) { mAlpha = alpha; } virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual void draw(); virtual void onMouseCaptureLost(); @@ -109,29 +116,48 @@ public: void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; } void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } - void setClickedCallback( void (*cb)(void *data), void* data = NULL ); // mouse down and up within button - void setMouseDownCallback( void (*cb)(void *data) ) { mMouseDownCallback = cb; } // mouse down within button - void setMouseUpCallback( void (*cb)(void *data) ) { mMouseUpCallback = cb; } // mouse up, EVEN IF NOT IN BUTTON - void setHeldDownCallback( void (*cb)(void *data) ) { mHeldDownCallback = cb; } // Mouse button held down and in button + + /*boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); + boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb); + boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb); + boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb);*/ + + boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button + boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON + // Passes a 'count' parameter in the commit param payload, i.e. param["count"]) + boost::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button + + + // *TODO: Deprecate (for backwards compatability only) + boost::signals2::connection setClickedCallback( button_callback_t cb, void* data ); + boost::signals2::connection setMouseDownCallback( button_callback_t cb, void* data ); + boost::signals2::connection setMouseUpCallback( button_callback_t cb, void* data ); + boost::signals2::connection setHeldDownCallback( button_callback_t cb, void* data ); + void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; } F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); } - BOOL getIsToggle() const { return mIsToggle; } - void setIsToggle(BOOL is_toggle) { mIsToggle = is_toggle; } BOOL toggleState(); - BOOL getToggleState() const { return mToggleState; } + BOOL getToggleState() const; void setToggleState(BOOL b); + void setHighlight(bool b); void setFlashing( BOOL b ); BOOL getFlashing() const { return mFlashing; } void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } LLFontGL::HAlign getHAlign() const { return mHAlign; } void setLeftHPad( S32 pad ) { mLeftHPad = pad; } - S32 getLeftHPad() const { return mLeftHPad; } + S32 getLeftHPad() const { return mLeftHPad; } void setRightHPad( S32 pad ) { mRightHPad = pad; } - S32 getRightHPad() const { return mRightHPad; } + S32 getRightHPad() const { return mRightHPad; } + + void setImageOverlayTopPad( S32 pad ) { mImageOverlayTopPad = pad; } + S32 getImageOverlayTopPad() const { return mImageOverlayTopPad; } + void setImageOverlayBottomPad( S32 pad ) { mImageOverlayBottomPad = pad; } + S32 getImageOverlayBottomPad() const { return mImageOverlayBottomPad; } const std::string getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); } const std::string getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); } @@ -139,35 +165,31 @@ public: void setImageColor(const std::string& color_control); void setImageColor(const LLColor4& c); /*virtual*/ void setColor(const LLColor4& c); - /*virtual*/ void setAlpha(F32 alpha); void setImages(const std::string &image_name, const std::string &selected_name); - void setDisabledImages(const std::string &image_name, const std::string &selected_name); - void setDisabledImages(const std::string &image_name, const std::string &selected_name, const LLColor4& c); - - void setHoverImages(const std::string &image_name, const std::string &selected_name); void setDisabledImageColor(const LLColor4& c) { mDisabledImageColor = c; } void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } void setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); + void setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); LLPointer getImageOverlay() { return mImageOverlay; } + LLFontGL::HAlign getImageOverlayHAlign() const { return mImageOverlayAlignment; } - - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - + void autoResize(); // resize with label of current btn state + void resize(LLUIString label); // resize with label input void setLabel( const LLStringExplicit& label); virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); void setLabelUnselected(const LLStringExplicit& label); void setLabelSelected(const LLStringExplicit& label); - void setDisabledLabel(const LLStringExplicit& disabled_label); - void setDisabledSelectedLabel(const LLStringExplicit& disabled_label); void setDisabledLabelColor( const LLColor4& c ) { mDisabledLabelColor = c; } void setFont(const LLFontGL *font) { mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); } + const LLFontGL* getFont() const { return mGLFont; } + const LLUIString& getCurrentLabel() const; + void setScaleImage(BOOL scale) { mScaleImage = scale; } BOOL getScaleImage() const { return mScaleImage; } @@ -175,132 +197,130 @@ public: void setBorderEnabled(BOOL b) { mBorderEnabled = b; } - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks - void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; } - void setImageUnselected(const std::string &image_name); - const std::string& getImageUnselectedName() const { return mImageUnselectedName; } - void setImageSelected(const std::string &image_name); - const std::string& getImageSelectedName() const { return mImageSelectedName; } - void setImageHoverSelected(const std::string &image_name); - void setImageHoverUnselected(const std::string &image_name); - void setImageDisabled(const std::string &image_name); - void setImageDisabledSelected(const std::string &image_name); - void setImageUnselected(LLPointer image); void setImageSelected(LLPointer image); void setImageHoverSelected(LLPointer image); void setImageHoverUnselected(LLPointer image); void setImageDisabled(LLPointer image); void setImageDisabledSelected(LLPointer image); - + void setImageFlash(LLPointer image); + void setImagePressed(LLPointer image); + void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } BOOL getCommitOnReturn() const { return mCommitOnReturn; } + static void onHeldDown(void *userdata); // to be called by gIdleCallbacks void setHelpURLCallback(const std::string &help_url); const std::string& getHelpURL() const { return mHelpURL; } + void setForcePressedState(bool b) { mForcePressedState = b; } + + void setAutoResize(bool auto_resize) { mAutoResize = auto_resize; } + + bool getIsToggle() const { return mIsToggle; } + bool setIsToggle(bool toggle) { return mIsToggle = toggle; } + protected: - - virtual void drawBorder(const LLColor4& color, S32 size); - - void setImageUnselectedID(const LLUUID &image_id); - const LLUUID& getImageUnselectedID() const { return mImageUnselectedID; } - void setImageSelectedID(const LLUUID &image_id); - const LLUUID& getImageSelectedID() const { return mImageSelectedID; } - void setImageHoverSelectedID(const LLUUID &image_id); - void setImageHoverUnselectedID(const LLUUID &image_id); - void setImageDisabledID(const LLUUID &image_id); - void setImageDisabledSelectedID(const LLUUID &image_id); const LLPointer& getImageUnselected() const { return mImageUnselected; } const LLPointer& getImageSelected() const { return mImageSelected; } - + void getOverlayImageSize(S32& overlay_width, S32& overlay_height); + LLFrameTimer mMouseDownTimer; + bool mNeedsHighlight; + S32 mButtonFlashCount; + F32 mButtonFlashRate; -private: - - void (*mClickedCallback)(void* data ); - void (*mMouseDownCallback)(void *data); - void (*mMouseUpCallback)(void *data); - void (*mHeldDownCallback)(void *data); + void drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size); + void resetMouseDownTimer(); + commit_signal_t* mMouseDownSignal; + commit_signal_t* mMouseUpSignal; + commit_signal_t* mHeldDownSignal; + const LLFontGL *mGLFont; - S32 mMouseDownFrame; - F32 mHeldDownDelay; // seconds, after which held-down callbacks get called - S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called + S32 mMouseDownFrame; + S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback + F32 mHeldDownDelay; // seconds, after which held-down callbacks get called + S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called LLPointer mImageOverlay; - LLFontGL::HAlign mImageOverlayAlignment; - LLColor4 mImageOverlayColor; + LLFontGL::HAlign mImageOverlayAlignment; + LLUIColor mImageOverlayColor; + LLUIColor mImageOverlaySelectedColor; + LLUIColor mImageOverlayDisabledColor; - LLPointer mImageUnselected; - LLUIString mUnselectedLabel; - LLColor4 mUnselectedLabelColor; + LLPointer mImageUnselected; + LLUIString mUnselectedLabel; + LLUIColor mUnselectedLabelColor; - LLPointer mImageSelected; - LLUIString mSelectedLabel; - LLColor4 mSelectedLabelColor; + LLPointer mImageSelected; + LLUIString mSelectedLabel; + LLUIColor mSelectedLabelColor; - LLPointer mImageHoverSelected; + LLPointer mImageHoverSelected; - LLPointer mImageHoverUnselected; + LLPointer mImageHoverUnselected; - LLPointer mImageDisabled; - LLUIString mDisabledLabel; - LLColor4 mDisabledLabelColor; + LLPointer mImageDisabled; + LLUIColor mDisabledLabelColor; - LLPointer mImageDisabledSelected; - LLUIString mDisabledSelectedLabel; - LLColor4 mDisabledSelectedLabelColor; + LLPointer mImageDisabledSelected; + LLUIString mDisabledSelectedLabel; + LLUIColor mDisabledSelectedLabelColor; - LLUUID mImageUnselectedID; - LLUUID mImageSelectedID; - LLUUID mImageHoverSelectedID; - LLUUID mImageHoverUnselectedID; - LLUUID mImageDisabledID; - LLUUID mImageDisabledSelectedID; - std::string mImageUnselectedName; - std::string mImageSelectedName; - std::string mImageHoverSelectedName; - std::string mImageHoverUnselectedName; - std::string mImageDisabledName; - std::string mImageDisabledSelectedName; + LLPointer mImagePressed; + LLPointer mImagePressedSelected; - LLColor4 mHighlightColor; - LLColor4 mUnselectedBgColor; - LLColor4 mSelectedBgColor; - LLColor4 mFlashBgColor; + /* There are two ways an image can flash- by making changes in color according to flash_color attribute + or by changing icon from current to the one specified in image_flash. Second way is used only if + flash icon name is set in attributes(by default it isn't). First way is used otherwise. */ + LLPointer mImageFlash; - LLColor4 mImageColor; - LLColor4 mDisabledImageColor; + LLUIColor mFlashBgColor; - BOOL mIsToggle; - BOOL mToggleState; - BOOL mScaleImage; + LLUIColor mImageColor; + LLUIColor mDisabledImageColor; - BOOL mDropShadowedText; + bool mIsToggle; + bool mScaleImage; - BOOL mBorderEnabled; + bool mDropShadowedText; + bool mAutoResize; + bool mBorderEnabled; + bool mFlashing; - BOOL mFlashing; + LLFontGL::HAlign mHAlign; + S32 mLeftHPad; + S32 mRightHPad; + S32 mBottomVPad; // under text label - LLFontGL::HAlign mHAlign; - S32 mLeftHPad; - S32 mRightHPad; + S32 mImageOverlayTopPad; + S32 mImageOverlayBottomPad; - F32 mHoverGlowStrength; - F32 mCurGlowStrength; + /* + * Space between image_overlay and label + */ + S32 mImgOverlayLabelSpace; - BOOL mNeedsHighlight; - BOOL mCommitOnReturn; + F32 mHoverGlowStrength; + F32 mCurGlowStrength; - std::string mHelpURL; + bool mCommitOnReturn; + bool mFadeWhenDisabled; - LLPointer mImagep; + bool mForcePressedState; + bool mDisplayPressedState; - LLFrameTimer mFlashingTimer; + std::string mHelpURL; + + LLFrameTimer mFlashingTimer; + + bool mHandleRightMouse; + + F32 mAlpha; }; #endif // LL_LLBUTTON_H diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index c1daee798..c7ed9ba34 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -113,37 +113,27 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect, LLCHECKBOXCTRL_VPAD, LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING + text_width + LLCHECKBOXCTRL_HPAD, llmax( text_height, LLCHECKBOXCTRL_BTN_SIZE ) + LLCHECKBOXCTRL_VPAD); - std::string active_true_id, active_false_id; - std::string inactive_true_id, inactive_false_id; - if (mRadioStyle) - { - active_true_id = "UIImgRadioActiveSelectedUUID"; - active_false_id = "UIImgRadioActiveUUID"; - inactive_true_id = "UIImgRadioInactiveSelectedUUID"; - inactive_false_id = "UIImgRadioInactiveUUID"; - mButton = new LLButton(std::string("Radio control button"), btn_rect, - active_false_id, active_true_id, control_which, - &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() ); - mButton->setDisabledImages( inactive_false_id, inactive_true_id ); - mButton->setHoverGlowStrength(0.35f); - } - else - { - active_false_id = "UIImgCheckboxActiveUUID"; - active_true_id = "UIImgCheckboxActiveSelectedUUID"; - inactive_true_id = "UIImgCheckboxInactiveSelectedUUID"; - inactive_false_id = "UIImgCheckboxInactiveUUID"; - mButton = new LLButton(std::string("Checkbox control button"), btn_rect, - active_false_id, active_true_id, control_which, - &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() ); - mButton->setDisabledImages( inactive_false_id, inactive_true_id ); - mButton->setHoverGlowStrength(0.35f); - } + + std::string active_true_id = mRadioStyle ? "UIImgRadioActiveSelectedUUID" : "UIImgCheckboxActiveSelectedUUID"; + std::string active_false_id = mRadioStyle ? "UIImgRadioActiveUUID" : "UIImgCheckboxActiveUUID"; + std::string inactive_true_id = mRadioStyle ? "UIImgRadioInactiveSelectedUUID" : "UIImgCheckboxInactiveSelectedUUID"; + std::string inactive_false_id = mRadioStyle ? "UIImgRadioInactiveUUID" : "UIImgCheckboxInactiveUUID"; + std::string button_name = mRadioStyle ? "Radio control button" : "Checkbox control button"; + + mButton = new LLButton( button_name, btn_rect, + active_false_id, active_true_id, control_which, + &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() ); + + mButton->setImageDisabledSelected(LLUI::getUIImage(inactive_true_id)); + mButton->setImageDisabled(LLUI::getUIImage(inactive_false_id)); + mButton->setHoverGlowStrength(0.35f); + mButton->setIsToggle(TRUE); mButton->setToggleState( initial_value ); mButton->setFollowsLeft(); mButton->setFollowsBottom(); mButton->setCommitOnReturn(FALSE); + mButton->setScaleImage(FALSE); addChild(mButton); } @@ -156,22 +146,8 @@ LLCheckBoxCtrl::~LLCheckBoxCtrl() // static void LLCheckBoxCtrl::onButtonPress( void *userdata ) { - LLCheckBoxCtrl* self = (LLCheckBoxCtrl*) userdata; - - if (self->mRadioStyle) - { - self->setValue(TRUE); - } - - self->setControlValue(self->getValue()); - // HACK: because buttons don't normally commit + LLCheckBoxCtrl* self = (LLCheckBoxCtrl*)userdata; self->onCommit(); - - if (self->mKeyboardFocusOnClick) - { - self->setFocus( TRUE ); - self->onFocusReceived(); - } } void LLCheckBoxCtrl::onCommit() @@ -179,6 +155,7 @@ void LLCheckBoxCtrl::onCommit() if( getEnabled() ) { setTentative(FALSE); + setControlValue(getValue()); LLUICtrl::onCommit(); } } @@ -186,7 +163,15 @@ void LLCheckBoxCtrl::onCommit() void LLCheckBoxCtrl::setEnabled(BOOL b) { LLView::setEnabled(b); - mButton->setEnabled(b); + + if (b) + { + mLabel->setColor( mTextEnabledColor.get() ); + } + else + { + mLabel->setColor( mTextDisabledColor.get() ); + } } void LLCheckBoxCtrl::clear() @@ -219,21 +204,6 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) LLUICtrl::reshape(width, height, called_from_parent); } -void LLCheckBoxCtrl::draw() -{ - if (getEnabled()) - { - mLabel->setColor( mTextEnabledColor ); - } - else - { - mLabel->setColor( mTextDisabledColor ); - } - - // Draw children - LLUICtrl::draw(); -} - //virtual void LLCheckBoxCtrl::setValue(const LLSD& value ) { @@ -246,6 +216,18 @@ LLSD LLCheckBoxCtrl::getValue() const return mButton->getValue(); } +//virtual +void LLCheckBoxCtrl::setTentative(BOOL b) +{ + mButton->setTentative(b); +} + +//virtual +BOOL LLCheckBoxCtrl::getTentative() const +{ + return mButton->getTentative(); +} + void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label ) { mLabel->setText( label ); @@ -282,7 +264,7 @@ BOOL LLCheckBoxCtrl::isDirty() const { if ( mButton ) { - return (mSetValue != mButton->getToggleState()); + return mButton->isDirty(); } return FALSE; // Shouldn't get here } @@ -293,11 +275,12 @@ void LLCheckBoxCtrl::resetDirty() { if ( mButton ) { - mSetValue = mButton->getToggleState(); + mButton->resetDirty(); } } + // virtual LLXMLNodePtr LLCheckBoxCtrl::getXML(bool save_children) const { diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index ff867f519..b9f8bec6f 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -82,7 +82,6 @@ public: virtual void setEnabled( BOOL b ); - virtual void draw(); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); // LLUICtrl interface @@ -91,8 +90,8 @@ public: BOOL get() { return (BOOL)getValue().asBoolean(); } void set(BOOL value) { setValue(value); } - virtual void setTentative(BOOL b) { mButton->setTentative(b); } - virtual BOOL getTentative() const { return mButton->getTentative(); } + virtual void setTentative(BOOL b); + virtual BOOL getTentative() const; virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); @@ -108,6 +107,9 @@ public: void setLabel( const LLStringExplicit& label ); std::string getLabel() const; + void setFont( const LLFontGL* font ) { mFont = font; } + const LLFontGL* getFont() { return mFont; } + virtual void setControlName(const std::string& control_name, LLView* context); virtual std::string getControlName() const; @@ -121,8 +123,9 @@ protected: LLButton* mButton; LLTextBox* mLabel; const LLFontGL* mFont; - LLColor4 mTextEnabledColor; - LLColor4 mTextDisabledColor; + + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; BOOL mRadioStyle; BOOL mInitialValue; // Value set in constructor BOOL mSetValue; // Value set programmatically diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index a54b8deed..c4f6d0042 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -85,13 +85,13 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std:: LLRect(), LLStringUtil::null, NULL, this); - mButton->setImageUnselected(std::string("square_btn_32x128.tga")); - mButton->setImageSelected(std::string("square_btn_selected_32x128.tga")); - mButton->setImageDisabled(std::string("square_btn_32x128.tga")); - mButton->setImageDisabledSelected(std::string("square_btn_selected_32x128.tga")); + mButton->setImageUnselected(LLUI::getUIImage("square_btn_32x128.tga")); + mButton->setImageSelected(LLUI::getUIImage("square_btn_selected_32x128.tga")); + mButton->setImageDisabled(LLUI::getUIImage("square_btn_32x128.tga")); + mButton->setImageDisabledSelected(LLUI::getUIImage("square_btn_selected_32x128.tga")); mButton->setScaleImage(TRUE); - mButton->setMouseDownCallback(onButtonDown); + mButton->setMouseDownCallback(boost::bind(&LLComboBox::onButtonDown,this)); mButton->setFont(LLFontGL::getFontSansSerifSmall()); mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); mButton->setHAlign( LLFontGL::LEFT ); @@ -244,8 +244,6 @@ void LLComboBox::clear() } mButton->setLabelSelected(LLStringUtil::null); mButton->setLabelUnselected(LLStringUtil::null); - mButton->setDisabledLabel(LLStringUtil::null); - mButton->setDisabledSelectedLabel(LLStringUtil::null); mList->deselectAllItems(); } @@ -445,8 +443,6 @@ void LLComboBox::setLabel(const LLStringExplicit& name) { mButton->setLabelUnselected(name); mButton->setLabelSelected(name); - mButton->setDisabledLabel(name); - mButton->setDisabledSelectedLabel(name); } } @@ -1218,7 +1214,7 @@ LLFlyoutButton::LLFlyoutButton( LLRect(), LLStringUtil::null, NULL, this); mActionButton->setScaleImage(TRUE); - mActionButton->setClickedCallback(onActionButtonClick); + mActionButton->setClickedCallback(boost::bind(&LLFlyoutButton::onActionButtonClick, this)); mActionButton->setFollowsAll(); mActionButton->setHAlign( LLFontGL::HCENTER ); mActionButton->setLabel(label); diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index b5b8e1df8..e35c1cbc0 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -707,6 +707,8 @@ const std::string& LLFloater::getCurrentTitle() const void LLFloater::setTitle( const std::string& title ) { + if(mTitle == title) + return; mTitle = title; applyTitle(); } @@ -1742,8 +1744,8 @@ void LLFloater::buildButtons() buttonp->setFollowsRight(); buttonp->setToolTip( sButtonToolTips[i] ); buttonp->setImageColor(LLUI::sColorsGroup->getColor("FloaterButtonImageColor")); - buttonp->setHoverImages(sButtonPressedImageNames[i], - sButtonPressedImageNames[i]); + buttonp->setImageHoverSelected(LLUI::getUIImage(sButtonPressedImageNames[i])); + buttonp->setImageHoverUnselected(LLUI::getUIImage(sButtonPressedImageNames[i])); buttonp->setScaleImage(TRUE); buttonp->setSaveToXML(false); addChild(buttonp); diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index dad9b3d55..d41606636 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -127,7 +127,7 @@ LLScrollbar::LLScrollbar( line_up_btn->setFollowsLeft(); line_up_btn->setFollowsBottom(); } - line_up_btn->setHeldDownCallback( &LLScrollbar::onLineUpBtnPressed ); + line_up_btn->setHeldDownCallback( boost::bind(&LLScrollbar::onLineUpBtnPressed, (void*)this) ); line_up_btn->setTabStop(FALSE); line_up_btn->setScaleImage(TRUE); @@ -138,7 +138,7 @@ LLScrollbar::LLScrollbar( &LLScrollbar::onLineDownBtnPressed, this, LLFontGL::getFontSansSerif() ); line_down_btn->setFollowsRight(); line_down_btn->setFollowsBottom(); - line_down_btn->setHeldDownCallback( &LLScrollbar::onLineDownBtnPressed ); + line_down_btn->setHeldDownCallback( boost::bind(&LLScrollbar::onLineDownBtnPressed, this) ); line_down_btn->setTabStop(FALSE); line_down_btn->setScaleImage(TRUE); addChild(line_down_btn); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index bf480990f..4b8358106 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -3679,9 +3679,9 @@ LLColumnHeader::LLColumnHeader(const std::string& label, const LLRect &rect, LLS mButton->setTabStop(FALSE); // require at least two frames between mouse down and mouse up event to capture intentional "hold" not just bad framerate mButton->setHeldDownDelay(LLUI::sConfigGroup->getF32("ColumnHeaderDropDownDelay"), 2); - mButton->setHeldDownCallback(onHeldDown); - mButton->setClickedCallback(onClick); - mButton->setMouseDownCallback(onMouseDown); + mButton->setHeldDownCallback(boost::bind(&LLColumnHeader::onHeldDown, this)); + mButton->setClickedCallback(boost::bind(&LLColumnHeader::onClick, this)); + mButton->setMouseDownCallback(boost::bind(&LLColumnHeader::onMouseDown, this)); mButton->setCallbackUserData(this); mButton->setToolTip(label); @@ -3843,8 +3843,8 @@ void LLColumnHeader::setImage(const std::string &image_name) { if (mButton) { - mButton->setImageSelected(image_name); - mButton->setImageUnselected(image_name); + mButton->setImageSelected(LLUI::getUIImage(image_name)); + mButton->setImageUnselected(LLUI::getUIImage(image_name)); } } diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index e3a659e86..4db05f0cc 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -101,7 +101,7 @@ LLSpinCtrl::LLSpinCtrl( const std::string& name, const LLRect& rect, const std:: &LLSpinCtrl::onUpBtn, this, LLFontGL::getFontSansSerif() ); mUpBtn->setFollowsLeft(); mUpBtn->setFollowsBottom(); - mUpBtn->setHeldDownCallback( &LLSpinCtrl::onUpBtn ); + mUpBtn->setHeldDownCallback(boost::bind(&LLSpinCtrl::onUpBtn,this)); mUpBtn->setTabStop(FALSE); addChild(mUpBtn); @@ -115,7 +115,7 @@ LLSpinCtrl::LLSpinCtrl( const std::string& name, const LLRect& rect, const std:: &LLSpinCtrl::onDownBtn, this, LLFontGL::getFontSansSerif() ); mDownBtn->setFollowsLeft(); mDownBtn->setFollowsBottom(); - mDownBtn->setHeldDownCallback( &LLSpinCtrl::onDownBtn ); + mDownBtn->setHeldDownCallback(boost::bind(&LLSpinCtrl::onDownBtn,this)); mDownBtn->setTabStop(FALSE); addChild(mDownBtn); diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index eeff21cdf..0f08f2c58 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -803,7 +803,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, LLStringUtil::null, LLStringUtil::null, LLStringUtil::null, - &LLTabContainer::onTabBtn, NULL, + NULL, NULL, font, trimmed_label, trimmed_label); btn->setImages(std::string("tab_left.tga"), std::string("tab_left_selected.tga")); @@ -825,7 +825,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, btn = new LLButton(std::string(child->getName()) + " tab", btn_rect, LLStringUtil::null, LLStringUtil::null, LLStringUtil::null, - &LLTabContainer::onTabBtn, NULL, // set userdata below + NULL, NULL, // set userdata below font, trimmed_label, trimmed_label ); btn->setVisible( FALSE ); @@ -865,7 +865,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, if (btn) { btn->setSaveToXML(false); - btn->setCallbackUserData( tuple ); + btn->setClickedCallback(&LLTabContainer::onTabBtn, tuple); addChild( btn, 0 ); } if (child) @@ -1682,7 +1682,7 @@ void LLTabContainer::initButtons() mPrevArrowBtn = new LLButton(std::string("Left Arrow"), left_arrow_btn_rect, out_id, in_id, LLStringUtil::null, &LLTabContainer::onPrevBtn, this, LLFontGL::getFontSansSerif() ); - mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld); + mPrevArrowBtn->setHeldDownCallback(boost::bind(LLTabContainer::onPrevBtnHeld, this)); mPrevArrowBtn->setFollowsLeft(); out_id = "UIImgBtnJumpRightOutUUID"; @@ -1717,12 +1717,12 @@ void LLTabContainer::initButtons() } } - mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld); + mPrevArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onPrevBtnHeld, this)); mPrevArrowBtn->setSaveToXML(false); mPrevArrowBtn->setTabStop(FALSE); addChild(mPrevArrowBtn); - mNextArrowBtn->setHeldDownCallback(onNextBtnHeld); + mNextArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onNextBtnHeld, this)); mNextArrowBtn->setSaveToXML(false); mNextArrowBtn->setTabStop(FALSE); addChild(mNextArrowBtn); diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 0fd4c908f..4e4a1418f 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -42,6 +42,7 @@ static LLRegisterWidget r("ui_ctrl"); // NOTE: the LLFocusableElement implementation has been moved to llfocusmgr.cpp, to mirror the header where the class is defined. LLUICtrl::LLUICtrl() : + mViewModel(LLViewModelPtr(new LLViewModel)), mCommitSignal(NULL), mValidateSignal(NULL), mCommitCallback(NULL), @@ -62,6 +63,7 @@ LLUICtrl::LLUICtrl(const std::string& name, const LLRect& rect, BOOL mouse_opaqu LLView( name, rect, mouse_opaque, reshape ), mCommitSignal(NULL), mValidateSignal(NULL), + mViewModel(LLViewModelPtr(new LLViewModel)), mCommitCallback( on_commit_callback), mValidateCallback( NULL ), mCallbackUserData( callback_userdata ), @@ -101,12 +103,33 @@ BOOL LLUICtrl::isCtrl() const return TRUE; } +//virtual +void LLUICtrl::setValue(const LLSD& value) +{ + mViewModel->setValue(value); +} + //virtual LLSD LLUICtrl::getValue() const { - return LLSD(); + return mViewModel->getValue(); } +/// When two widgets are displaying the same data (e.g. during a skin +/// change), share their ViewModel. +void LLUICtrl::shareViewModelFrom(const LLUICtrl& other) +{ + // Because mViewModel is an LLViewModelPtr, this assignment will quietly + // dispose of the previous LLViewModel -- unless it's already shared by + // somebody else. + mViewModel = other.mViewModel; +} + +//virtual +LLViewModel* LLUICtrl::getViewModel() const +{ + return mViewModel; +} // virtual BOOL LLUICtrl::setTextArg( const std::string& key, const LLStringExplicit& text ) { @@ -169,43 +192,12 @@ void LLUICtrl::onFocusReceived() { // trigger callbacks LLFocusableElement::onFocusReceived(); - - // find first view in hierarchy above new focus that is a LLUICtrl - LLView* viewp = getParent(); - LLUICtrl* last_focus = dynamic_cast(gFocusMgr.getLastKeyboardFocus()); - - while (viewp && !viewp->isCtrl()) - { - viewp = viewp->getParent(); - } - - // and if it has newly gained focus, call onFocusReceived() - LLUICtrl* ctrlp = static_cast(viewp); - if (ctrlp && (!last_focus || !last_focus->hasAncestor(ctrlp))) - { - ctrlp->onFocusReceived(); - } } void LLUICtrl::onFocusLost() { // trigger callbacks LLFocusableElement::onFocusLost(); - - // find first view in hierarchy above old focus that is a LLUICtrl - LLView* viewp = getParent(); - while (viewp && !viewp->isCtrl()) - { - viewp = viewp->getParent(); - } - - // and if it has just lost focus, call onFocusReceived() - LLUICtrl* ctrlp = static_cast(viewp); - // hasFocus() includes any descendants - if (ctrlp && !ctrlp->hasFocus()) - { - ctrlp->onFocusLost(); - } } // virtual @@ -229,12 +221,13 @@ BOOL LLUICtrl::acceptsTextInput() const //virtual BOOL LLUICtrl::isDirty() const { - return FALSE; + return mViewModel->isDirty(); }; //virtual void LLUICtrl::resetDirty() { + mViewModel->resetDirty(); } // virtual diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 66dc12637..bbdca3091 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -38,11 +38,13 @@ #include "llrect.h" #include "llsd.h" +#include "llviewmodel.h" // *TODO move dependency to .cpp file class LLUICtrl : public LLView { public: + typedef boost::function commit_callback_t; typedef boost::signals2::signal commit_signal_t; typedef boost::signals2::signal enable_signal_t; @@ -56,6 +58,10 @@ public: U32 reshape=FOLLOWS_NONE); /*virtual*/ ~LLUICtrl(); + // We need this virtual so we can override it with derived versions + virtual LLViewModel* getViewModel() const; + // We shouldn't ever need to set this directly + //virtual void setViewModel(const LLViewModelPtr&); // LLView interface /*virtual*/ void initFromXML(LLXMLNodePtr node, LLView* parent); /*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const; @@ -63,8 +69,6 @@ public: /*virtual*/ void onFocusReceived(); /*virtual*/ void onFocusLost(); /*virtual*/ BOOL isCtrl() const; - /*virtual*/ void setTentative(BOOL b); - /*virtual*/ BOOL getTentative() const; // From LLFocusableElement /*virtual*/ void setFocus( BOOL b ); @@ -77,7 +81,14 @@ public: virtual class LLCtrlListInterface* getListInterface(); virtual class LLCtrlScrollInterface* getScrollInterface(); + virtual void setTentative(BOOL b); + virtual BOOL getTentative() const; + virtual void setValue(const LLSD& value); virtual LLSD getValue() const; + /// When two widgets are displaying the same data (e.g. during a skin + /// change), share their ViewModel. + virtual void shareViewModelFrom(const LLUICtrl& other); + virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); virtual void setIsChrome(BOOL is_chrome); @@ -141,6 +152,8 @@ protected: commit_signal_t* mCommitSignal; enable_signal_t* mValidateSignal; + + LLViewModelPtr mViewModel; void (*mCommitCallback)( LLUICtrl* ctrl, void* userdata ); BOOL (*mValidateCallback)( LLUICtrl* ctrl, void* userdata ); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index b63d6e609..ceff14d93 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -504,16 +504,6 @@ LLRect LLView::getRequiredRect() return mRect; } -//virtual -void LLView::onFocusLost() -{ -} - -//virtual -void LLView::onFocusReceived() -{ -} - BOOL LLView::focusNextRoot() { LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); diff --git a/indra/llui/llview.h b/indra/llui/llview.h index b937fb216..c5eaf1614 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -411,10 +411,6 @@ public: BOOL getSaveToXML() const { return mSaveToXML; } void setSaveToXML(BOOL b) { mSaveToXML = b; } - // inherited from LLFocusableElement - /* virtual */ void onFocusLost(); - /* virtual */ void onFocusReceived(); - typedef enum e_hit_test_type { HIT_TEST_USE_BOUNDING_RECT, diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp new file mode 100644 index 000000000..a9f8acc44 --- /dev/null +++ b/indra/llui/llviewmodel.cpp @@ -0,0 +1,157 @@ +/** + * @file llviewmodel.cpp + * @author Nat Goodspeed + * @date 2008-08-08 + * @brief Implementation for llviewmodel. + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llviewmodel.h" +// STL headers +// std headers +// external library headers +// other Linden headers + +/// +LLViewModel::LLViewModel() + : mDirty(false) +{ +} + +/// Instantiate an LLViewModel with an existing data value +LLViewModel::LLViewModel(const LLSD& value) + : mDirty(false) +{ + setValue(value); +} + +/// Update the stored value +void LLViewModel::setValue(const LLSD& value) +{ + mValue = value; + mDirty = true; +} + +LLSD LLViewModel::getValue() const +{ + return mValue; +} + +//////////////////////////////////////////////////////////////////////////// + +/// +LLTextViewModel::LLTextViewModel() + : LLViewModel(false), + mUpdateFromDisplay(false) +{ +} + +/// Instantiate an LLViewModel with an existing data value +LLTextViewModel::LLTextViewModel(const LLSD& value) + : LLViewModel(value), + mUpdateFromDisplay(false) +{ +} + +/// Update the stored value +void LLTextViewModel::setValue(const LLSD& value) +{ + LLViewModel::setValue(value); + mDisplay = utf8str_to_wstring(value.asString()); + // mDisplay and mValue agree + mUpdateFromDisplay = false; +} + +void LLTextViewModel::setDisplay(const LLWString& value) +{ + // This is the strange way to alter the value. Normally we'd setValue() + // and do the utf8str_to_wstring() to get the corresponding mDisplay + // value. But a text editor might want to edit the display string + // directly, then convert back to UTF8 on commit. + mDisplay = value; + mDirty = true; + // Don't immediately convert to UTF8 -- do it lazily -- we expect many + // more setDisplay() calls than getValue() calls. Just flag that it needs + // doing. + mUpdateFromDisplay = true; +} + +LLSD LLTextViewModel::getValue() const +{ + // Has anyone called setDisplay() since the last setValue()? If so, have + // to convert mDisplay back to UTF8. + if (mUpdateFromDisplay) + { + // The fact that we're lazily updating fields in this object should be + // transparent to clients, which is why this method is left + // conventionally const. Nor do we particularly want to make these + // members mutable. Just cast away constness in this one place. + LLTextViewModel* nthis = const_cast(this); + nthis->mUpdateFromDisplay = false; + nthis->mValue = wstring_to_utf8str(mDisplay); + } + return LLViewModel::getValue(); +} + + +//////////////////////////////////////////////////////////////////////////// + +LLListViewModel::LLListViewModel(const LLSD& values) + : LLViewModel() +{ +} + +void LLListViewModel::addColumn(const LLSD& column, EAddPosition pos) +{ +} + +void LLListViewModel::clearColumns() +{ +} + +void LLListViewModel::setColumnLabel(const std::string& column, const std::string& label) +{ +} + +LLScrollListItem* LLListViewModel::addElement(const LLSD& value, EAddPosition pos, + void* userdata) +{ + return NULL; +} + +LLScrollListItem* LLListViewModel::addSimpleElement(const std::string& value, EAddPosition pos, + const LLSD& id) +{ + return NULL; +} + +void LLListViewModel::clearRows() +{ +} + +void LLListViewModel::sortByColumn(const std::string& name, bool ascending) +{ +} diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h new file mode 100644 index 000000000..763af5d8a --- /dev/null +++ b/indra/llui/llviewmodel.h @@ -0,0 +1,214 @@ +/** + * @file llviewmodel.h + * @author Nat Goodspeed + * @date 2008-08-08 + * @brief Define "View Model" classes intended to store data values for use + * by LLUICtrl subclasses. The phrase is borrowed from Microsoft + * terminology, in which "View Model" means the storage object + * underlying a specific widget object -- as in our case -- rather + * than the business "model" object underlying the overall "view" + * presented by the collection of widgets. + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLVIEWMODEL_H) +#define LL_LLVIEWMODEL_H + +#include "llpointer.h" +#include "llsd.h" +#include "llrefcount.h" +#include "stdenums.h" +#include "llstring.h" +#include + +class LLScrollListItem; + +class LLViewModel; +class LLTextViewModel; +class LLListViewModel; +// Because LLViewModel is derived from LLRefCount, always pass, store +// and return LLViewModelPtr rather than plain LLViewModel*. +typedef LLPointer LLViewModelPtr; +typedef LLPointer LLTextViewModelPtr; +typedef LLPointer LLListViewModelPtr; + +/** + * LLViewModel stores a scalar LLSD data item, the current display value of a + * scalar LLUICtrl widget. LLViewModel subclasses are used to store data + * collections used for aggregate widgets. LLViewModel is ref-counted because + * -- for multiple skins -- we may have distinct widgets sharing the same + * LLViewModel data. This way, the LLViewModel is quietly deleted when the + * last referencing widget is destroyed. + */ +class LLViewModel: public LLRefCount +{ +public: + LLViewModel(); + /// Instantiate an LLViewModel with an existing data value + LLViewModel(const LLSD& value); + + /// Update the stored value + virtual void setValue(const LLSD& value); + /// Get the stored value, in appropriate type. + virtual LLSD getValue() const; + + /// Has the value been changed since last time we checked? + bool isDirty() const { return mDirty; } + /// Once the value has been saved to a file, or otherwise consumed by the + /// app, we no longer need to enable the Save button + void resetDirty() { mDirty = false; } + // + void setDirty() { mDirty = true; } + +protected: + LLSD mValue; + bool mDirty; +}; + +/** + * LLTextViewModel stores a value displayed as text. + */ +class LLTextViewModel: public LLViewModel +{ +public: + LLTextViewModel(); + /// Instantiate an LLViewModel with an existing data value + LLTextViewModel(const LLSD& value); + + // LLViewModel functions + virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; + + // New functions + /// Get the stored value in string form + const LLWString& getDisplay() const { return mDisplay; } + + /** + * Set the display string directly (see LLTextEditor). What the user is + * editing is actually the LLWString value rather than the underlying + * UTF-8 value. + */ + void setDisplay(const LLWString& value); + +private: + /// To avoid converting every widget's stored value from LLSD to LLWString + /// every frame, cache the converted value + LLWString mDisplay; + /// As the user edits individual characters (setDisplay()), defer + /// LLWString-to-UTF8 conversions until s/he's done. + bool mUpdateFromDisplay; +}; + +/** + * LLListViewModel stores a list of data items. The semantics are borrowed + * from LLScrollListCtrl. + */ +class LLListViewModel: public LLViewModel +{ +public: + LLListViewModel() {} + LLListViewModel(const LLSD& values); + + virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM); + virtual void clearColumns(); + virtual void setColumnLabel(const std::string& column, const std::string& label); + virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, + void* userdata = NULL); + virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos, + const LLSD& id); + virtual void clearRows(); + virtual void sortByColumn(const std::string& name, bool ascending); +}; + +//namespace LLViewModel +//{ +// class Value +// { +// public: +// Value(const LLSD& value = LLSD()); +// +// LLSD getValue() const { return mValue; } +// void setValue(const LLSD& value) { mValue = value; } +// +// bool isAvailable() const { return false; } +// bool isReadOnly() const { return false; } +// +// bool undo() { return false; } +// bool redo() { return false; } +// +// /// Has the value been changed since last time we checked? +// bool isDirty() const { return mDirty; } +// /// Once the value has been saved to a file, or otherwise consumed by the +// /// app, we no longer need to enable the Save button +// void resetDirty() { mDirty = false; } +// // +// void setDirty() { mDirty = true; } +// +// protected: +// LLSD mValue; +// bool mDirty; +// }; +// +// class Numeric : public Value +// { +// public: +// Numeric(S32 value = 0); +// Numeric(F32 value); +// +// F32 getPrecision(); +// F32 getMin(); +// F32 getMax(); +// +// void increment(); +// void decrement(); +// }; +// +// class MultipleValues : public Value +// { +// class Selector +// {}; +// +// MultipleValues(); +// virtual S32 numElements(); +// }; +// +// class Tuple : public MultipleValues +// { +// Tuple(S32 size); +// LLSD getValue(S32 which) const; +// void setValue(S32 which, const LLSD& value); +// }; +// +// class List : public MultipleValues +// { +// List(); +// +// void add(const ValueModel& value); +// bool remove(const Selector& item); +// +// void setSortElement(const Selector& element); +// void sort(); +// }; +// +//}; +#endif /* ! defined(LL_LLVIEWMODEL_H) */ diff --git a/indra/newview/hippofloaterxml.cpp b/indra/newview/hippofloaterxml.cpp index 477f0d7bb..c49788692 100644 --- a/indra/newview/hippofloaterxml.cpp +++ b/indra/newview/hippofloaterxml.cpp @@ -65,6 +65,11 @@ class HippoFloaterXmlImpl : public LLFloater private: std::string mName; bool mIsNotifyOnClose; + //Must retain handles to unregister notices. + typedef boost::signals2::scoped_connection notice_connection_t; + typedef boost::shared_ptr notice_ptr_t; + + std::map mNotices; }; @@ -260,7 +265,7 @@ void HippoFloaterXml::execute(const std::string &cmds) // ******************************************************************** // generic notification callbacks -static void notify(LLUICtrl *ctrl, void *data) +static void notifyCallback(LLUICtrl *ctrl) { std::string msg = "NOTIFY:"; msg += ctrl->getName(); @@ -269,11 +274,6 @@ static void notify(LLUICtrl *ctrl, void *data) send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL); } -static void notify(void *data) -{ - notify(static_cast(data), 0); -} - void HippoFloaterXmlImpl::onClose(bool quitting) { if (mIsNotifyOnClose) @@ -324,16 +324,19 @@ bool HippoFloaterXmlImpl::execute(LLUICtrl *ctrl, bool set = (value != "0"); if (HippoFloaterXmlImpl *floater = dynamic_cast(ctrl)) { floater->mIsNotifyOnClose = set; - } else if (LLButton *button = dynamic_cast(ctrl)) { + } else if (LLButton *button = dynamic_cast(ctrl)) + { if (set) - button->setClickedCallback(notify, ctrl); + floater->mNotices[button] = notice_ptr_t(new notice_connection_t(button->setClickedCallback(boost::bind(¬ifyCallback, ctrl)))); else - button->setClickedCallback(0, 0); - } else { + floater->mNotices.erase(button); + } + else + { if (set) - ctrl->setCommitCallback(notify); + floater->mNotices[ctrl] = notice_ptr_t(new notice_connection_t(ctrl->setCommitCallback(boost::bind(¬ifyCallback, ctrl)))); else - ctrl->setCommitCallback(0); + floater->mNotices.erase(ctrl); } } } diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp index 13f9d5524..95ba4a08f 100644 --- a/indra/newview/llfloateranimpreview.cpp +++ b/indra/newview/llfloateranimpreview.cpp @@ -267,12 +267,13 @@ BOOL LLFloaterAnimPreview::postBuild() { mPlayButton = new LLButton(std::string("play_btn"), LLRect(0,0,0,0)); } - mPlayButton->setClickedCallback(onBtnPlay); - mPlayButton->setCallbackUserData(this); + mPlayButton->setClickedCallback(boost::bind(&LLFloaterAnimPreview::onBtnPlay,this)); mPlayButton->setImages(std::string("button_anim_play.tga"), std::string("button_anim_play_selected.tga")); - mPlayButton->setDisabledImages(LLStringUtil::null,LLStringUtil::null); + + mPlayButton->setImageDisabled(NULL); + mPlayButton->setImageDisabledSelected(NULL); mPlayButton->setScaleImage(TRUE); @@ -281,12 +282,13 @@ BOOL LLFloaterAnimPreview::postBuild() { mStopButton = new LLButton(std::string("stop_btn"), LLRect(0,0,0,0)); } - mStopButton->setClickedCallback(onBtnStop); - mStopButton->setCallbackUserData(this); + mStopButton->setClickedCallback(boost::bind(&LLFloaterAnimPreview::onBtnStop, this)); mStopButton->setImages(std::string("button_anim_stop.tga"), std::string("button_anim_stop_selected.tga")); - mStopButton->setDisabledImages(LLStringUtil::null,LLStringUtil::null); + + mStopButton->setImageDisabled(NULL); + mStopButton->setImageDisabledSelected(NULL); mStopButton->setScaleImage(TRUE); diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index f9d782cc2..474e4d874 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -224,20 +224,17 @@ LLFloaterColorPicker:: postBuild() { mCancelBtn = getChild( "cancel_btn" ); - mCancelBtn->setClickedCallback ( onClickCancel ); - mCancelBtn->setCallbackUserData ( this ); + mCancelBtn->setClickedCallback ( boost::bind(&LLFloaterColorPicker::onClickCancel,this) ); mSelectBtn = getChild( "select_btn"); - mSelectBtn->setClickedCallback ( onClickSelect ); - mSelectBtn->setCallbackUserData ( this ); + mSelectBtn->setClickedCallback ( boost::bind(&LLFloaterColorPicker::onClickSelect,this) ); mSelectBtn->setFocus ( TRUE ); mPipetteBtn = getChild("color_pipette" ); mPipetteBtn->setImages(std::string("eye_button_inactive.tga"), std::string("eye_button_active.tga")); - mPipetteBtn->setClickedCallback( onClickPipette ); - mPipetteBtn->setCallbackUserData ( this ); + mPipetteBtn->setClickedCallback( boost::bind(&LLFloaterColorPicker::onClickPipette,this) ); mApplyImmediateCheck = getChild("apply_immediate"); mApplyImmediateCheck->set(gSavedSettings.getBOOL("ApplyColorImmediately")); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index a66037db8..e9ec8c6aa 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -1419,15 +1419,15 @@ LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, childSetValue("min param text", min_name); childSetValue("max param text", max_name); mLess = getChild("less"); - mLess->setMouseDownCallback( LLScrollingPanelParam::onHintMinMouseDown ); - mLess->setMouseUpCallback( LLScrollingPanelParam::onHintMinMouseUp ); - mLess->setHeldDownCallback( LLScrollingPanelParam::onHintMinHeldDown ); + mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMinMouseDown, this) ); + mLess->setMouseUpCallback( boost::bind(LLScrollingPanelParam::onHintMinMouseUp, this) ); + mLess->setHeldDownCallback( boost::bind(LLScrollingPanelParam::onHintMinHeldDown, this) ); mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); mMore = getChild("more"); - mMore->setMouseDownCallback( LLScrollingPanelParam::onHintMaxMouseDown ); - mMore->setMouseUpCallback( LLScrollingPanelParam::onHintMaxMouseUp ); - mMore->setHeldDownCallback( LLScrollingPanelParam::onHintMaxHeldDown ); + mMore->setMouseDownCallback( boost::bind(LLScrollingPanelParam::onHintMaxMouseDown, this) ); + mMore->setMouseUpCallback( boost::bind(LLScrollingPanelParam::onHintMaxMouseUp, this) ); + mMore->setHeldDownCallback( boost::bind(LLScrollingPanelParam::onHintMaxHeldDown, this) ); mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); } else diff --git a/indra/newview/llfloaterlagmeter.cpp b/indra/newview/llfloaterlagmeter.cpp index a2d120ad8..d1445cdbb 100644 --- a/indra/newview/llfloaterlagmeter.cpp +++ b/indra/newview/llfloaterlagmeter.cpp @@ -147,25 +147,25 @@ void LLFloaterLagMeter::determineClient() if (!gFocusMgr.getAppHasFocus()) { - mClientButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_window_bg_msg", mStringArgs) ); mClientCause->setText( LLStringUtil::null ); } else if(client_frame_time >= mClientFrameTimeCritical) { - mClientButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_critical_msg", mStringArgs) ); find_cause = true; } else if(client_frame_time >= mClientFrameTimeWarning) { - mClientButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_warning_msg", mStringArgs) ); find_cause = true; } else { - mClientButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_normal_msg", mStringArgs) ); mClientCause->setText( LLStringUtil::null ); } @@ -206,13 +206,13 @@ void LLFloaterLagMeter::determineNetwork() if(packet_loss >= mNetworkPacketLossCritical) { - mNetworkButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); mNetworkText->setText( getString("network_packet_loss_critical_msg", mStringArgs) ); find_cause_loss = true; } else if(ping_time >= mNetworkPingCritical) { - mNetworkButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); if (client_frame_time_ms < mNetworkPingCritical) { mNetworkText->setText( getString("network_ping_critical_msg", mStringArgs) ); @@ -221,13 +221,13 @@ void LLFloaterLagMeter::determineNetwork() } else if(packet_loss >= mNetworkPacketLossWarning) { - mNetworkButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); mNetworkText->setText( getString("network_packet_loss_warning_msg", mStringArgs) ); find_cause_loss = true; } else if(ping_time >= mNetworkPingWarning) { - mNetworkButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); if (client_frame_time_ms < mNetworkPingWarning) { mNetworkText->setText( getString("network_ping_warning_msg", mStringArgs) ); @@ -236,7 +236,7 @@ void LLFloaterLagMeter::determineNetwork() } else { - mNetworkButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mNetworkText->setText( getString("network_performance_normal_msg", mStringArgs) ); } @@ -261,19 +261,19 @@ void LLFloaterLagMeter::determineServer() if(sim_frame_time >= mServerFrameTimeCritical) { - mServerButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mServerButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); mServerText->setText( getString("server_frame_time_critical_msg", mStringArgs) ); find_cause = true; } else if(sim_frame_time >= mServerFrameTimeWarning) { - mServerButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mServerButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); mServerText->setText( getString("server_frame_time_warning_msg", mStringArgs) ); find_cause = true; } else { - mServerButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mServerButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mServerText->setText( getString("server_frame_time_normal_msg", mStringArgs) ); mServerCause->setText( LLStringUtil::null ); } diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 821cd03fb..913051f61 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -180,8 +180,41 @@ void* LLFloaterTools::createPanelLandInfo(void* data) return floater->mPanelLandInfo; } +static const std::string toolNames[]={ + "ToolCube", + "ToolPrism", + "ToolPyramid", + "ToolTetrahedron", + "ToolCylinder", + "ToolHemiCylinder", + "ToolCone", + "ToolHemiCone", + "ToolSphere", + "ToolHemiSphere", + "ToolTorus", + "ToolTube", + "ToolRing", + "ToolTree", + "ToolGrass"}; +LLPCode toolData[]={ + LL_PCODE_CUBE, + LL_PCODE_PRISM, + LL_PCODE_PYRAMID, + LL_PCODE_TETRAHEDRON, + LL_PCODE_CYLINDER, + LL_PCODE_CYLINDER_HEMI, + LL_PCODE_CONE, + LL_PCODE_CONE_HEMI, + LL_PCODE_SPHERE, + LL_PCODE_SPHERE_HEMI, + LL_PCODE_TORUS, + LLViewerObject::LL_VO_SQUARE_TORUS, + LLViewerObject::LL_VO_TRIANGLE_TORUS, + LL_PCODE_LEGACY_TREE, + LL_PCODE_LEGACY_GRASS}; + BOOL LLFloaterTools::postBuild() -{ +{ // Hide until tool selected setVisible(FALSE); @@ -250,44 +283,12 @@ BOOL LLFloaterTools::postBuild() // Create Buttons // - static const std::string toolNames[]={ - "ToolCube", - "ToolPrism", - "ToolPyramid", - "ToolTetrahedron", - "ToolCylinder", - "ToolHemiCylinder", - "ToolCone", - "ToolHemiCone", - "ToolSphere", - "ToolHemiSphere", - "ToolTorus", - "ToolTube", - "ToolRing", - "ToolTree", - "ToolGrass"}; - void* toolData[]={ - &LLToolPlacerPanel::sCube, - &LLToolPlacerPanel::sPrism, - &LLToolPlacerPanel::sPyramid, - &LLToolPlacerPanel::sTetrahedron, - &LLToolPlacerPanel::sCylinder, - &LLToolPlacerPanel::sCylinderHemi, - &LLToolPlacerPanel::sCone, - &LLToolPlacerPanel::sConeHemi, - &LLToolPlacerPanel::sSphere, - &LLToolPlacerPanel::sSphereHemi, - &LLToolPlacerPanel::sTorus, - &LLToolPlacerPanel::sSquareTorus, - &LLToolPlacerPanel::sTriangleTorus, - &LLToolPlacerPanel::sTree, - &LLToolPlacerPanel::sGrass}; for(size_t t=0; t(toolNames[t]); if(found) { - found->setClickedCallback(setObjectType,toolData[t]); + found->setClickedCallback(boost::bind(&LLFloaterTools::setObjectType, toolData[t])); mButtons.push_back( found ); } else @@ -737,15 +738,13 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) else { // Highlight the correct placer button - for( std::vector::size_type i = 0; i < mButtons.size(); i++ ) + for( S32 t = 0; t < (S32)mButtons.size(); t++ ) { LLPCode pcode = LLToolPlacer::getObjectType(); - void *userdata = mButtons[i]->getCallbackUserData(); - LLPCode *cur = (LLPCode*) userdata; - - BOOL state = (pcode == *cur); - mButtons[i]->setToggleState( state ); - mButtons[i]->setVisible( create_visible ); + LLPCode button_pcode = toolData[t]; + BOOL state = (pcode == button_pcode); + mButtons[t]->setToggleState( state ); + mButtons[t]->setVisible( create_visible ); } } @@ -1034,9 +1033,8 @@ void commit_grid_mode(LLUICtrl *ctrl, void *data) } // static -void LLFloaterTools::setObjectType( void* data ) +void LLFloaterTools::setObjectType( LLPCode pcode ) { - LLPCode pcode = *(LLPCode*) data; LLToolPlacer::setObjectType( pcode ); gSavedSettings.setBOOL("CreateToolCopySelection", FALSE); gFocusMgr.setMouseCapture(NULL); @@ -1067,11 +1065,11 @@ void LLFloaterTools::onSelectTreesGrass(LLUICtrl*, void*) { const std::string &selected = gFloaterTools->mComboTreesGrass->getValue(); LLPCode pcode = LLToolPlacer::getObjectType(); - if (pcode == LLToolPlacerPanel::sTree) + if (pcode == LL_PCODE_LEGACY_TREE) { gSavedSettings.setString("LastTree", selected); } - else if (pcode == LLToolPlacerPanel::sGrass) + else if (pcode == LL_PCODE_LEGACY_GRASS) { gSavedSettings.setString("LastGrass", selected); } @@ -1085,7 +1083,7 @@ void LLFloaterTools::updateTreeGrassCombo(bool visible) LLPCode pcode = LLToolPlacer::getObjectType(); std::map::iterator it, end; std::string selected; - if (pcode == LLToolPlacerPanel::sTree) + if (pcode == LL_PCODE_LEGACY_TREE) { tree_grass_label->setVisible(visible); LLButton* button = getChild("ToolTree"); @@ -1095,7 +1093,7 @@ void LLFloaterTools::updateTreeGrassCombo(bool visible) it = LLVOTree::sSpeciesNames.begin(); end = LLVOTree::sSpeciesNames.end(); } - else if (pcode == LLToolPlacerPanel::sGrass) + else if (pcode == LL_PCODE_LEGACY_GRASS) { tree_grass_label->setVisible(visible); LLButton* button = getChild("ToolGrass"); diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index a06e2728c..4a8078a44 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -103,10 +103,10 @@ public: static void setEditTool(void* data); void saveLastTool(); private: - static void setObjectType( void* data ); - + void refresh(); + static void setObjectType( LLPCode pcode ); static void onClickGridOptions(void* data); public: diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp index 4cfc2eaac..5e6f3e1b0 100644 --- a/indra/newview/lljoystickbutton.cpp +++ b/indra/newview/lljoystickbutton.cpp @@ -78,8 +78,7 @@ LLJoystick::LLJoystick( mHeldDown(FALSE), mHeldDownTimer() { - setHeldDownCallback(&LLJoystick::onHeldDown); - setCallbackUserData(this); + setHeldDownCallback(boost::bind(&LLJoystick::onHeldDownCallback,this)); } @@ -178,7 +177,7 @@ F32 LLJoystick::getElapsedHeldDownTime() } // static -void LLJoystick::onHeldDown(void *userdata) +void LLJoystick::onHeldDownCallback(void *userdata) { LLJoystick *self = (LLJoystick *)userdata; diff --git a/indra/newview/lljoystickbutton.h b/indra/newview/lljoystickbutton.h index 2d0492a11..74430f1c1 100644 --- a/indra/newview/lljoystickbutton.h +++ b/indra/newview/lljoystickbutton.h @@ -60,7 +60,7 @@ public: virtual void onHeldDown() = 0; F32 getElapsedHeldDownTime(); - static void onHeldDown(void *userdata); // called by llbutton callback handler + static void onHeldDownCallback(void *userdata); // called by llbutton callback handler void setInitialQuadrant(EJoystickQuadrant initial) { mInitialQuadrant = initial; }; virtual LLXMLNodePtr getXML(bool save_children = true) const; diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 59996ca64..14b5fa13a 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -81,21 +81,21 @@ LLFloaterMove::LLFloaterMove(const LLSD& key) mTurnLeftButton = getChild("turn left btn"); mTurnLeftButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mTurnLeftButton->setHeldDownCallback( turnLeft ); + mTurnLeftButton->setHeldDownCallback( boost::bind(&LLFloaterMove::turnLeft, this) ); mTurnRightButton = getChild("turn right btn"); mTurnRightButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mTurnRightButton->setHeldDownCallback( turnRight ); + mTurnRightButton->setHeldDownCallback( boost::bind(&LLFloaterMove::turnRight, this) ); mMoveUpButton = getChild("move up btn"); childSetAction("move up btn",moveUp,NULL); mMoveUpButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mMoveUpButton->setHeldDownCallback( moveUp ); + mMoveUpButton->setHeldDownCallback( boost::bind(&LLFloaterMove::moveUp, this) ); mMoveDownButton = getChild("move down btn"); childSetAction("move down btn",moveDown,NULL); mMoveDownButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mMoveDownButton->setHeldDownCallback( moveDown ); + mMoveDownButton->setHeldDownCallback( boost::bind(&LLFloaterMove::moveDown, this) ); } // virtual diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 9751c2d7a..5fe634eed 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -270,22 +270,18 @@ BOOL LLPanelClassified::postBuild() mLocationEditor = getChild("location_editor"); mSetBtn = getChild( "set_location_btn"); - mSetBtn->setClickedCallback(onClickSet); - mSetBtn->setCallbackUserData(this); + mSetBtn->setClickedCallback(boost::bind(&LLPanelClassified::onClickSet, this)); mTeleportBtn = getChild( "classified_teleport_btn"); - mTeleportBtn->setClickedCallback(onClickTeleport); - mTeleportBtn->setCallbackUserData(this); + mTeleportBtn->setClickedCallback(boost::bind(&LLPanelClassified::onClickTeleport, this)); mMapBtn = getChild( "classified_map_btn"); - mMapBtn->setClickedCallback(onClickMap); - mMapBtn->setCallbackUserData(this); + mMapBtn->setClickedCallback(boost::bind(&LLPanelClassified::onClickMap, this)); if(mInFinder) { mProfileBtn = getChild( "classified_profile_btn"); - mProfileBtn->setClickedCallback(onClickProfile); - mProfileBtn->setCallbackUserData(this); + mProfileBtn->setClickedCallback(boost::bind(&LLPanelClassified::onClickProfile, this)); } mCategoryCombo = getChild( "classified_category_combo"); @@ -319,7 +315,7 @@ BOOL LLPanelClassified::postBuild() } mUpdateBtn = getChild("classified_update_btn"); - mUpdateBtn->setClickedCallback(onClickUpdate); + mUpdateBtn->setClickedCallback(boost::bind(&LLPanelClassified::onClickUpdate, this)); mUpdateBtn->setCallbackUserData(this); if (!mInFinder) diff --git a/indra/newview/llpanelevent.cpp b/indra/newview/llpanelevent.cpp index 0105180a4..9b453fbeb 100644 --- a/indra/newview/llpanelevent.cpp +++ b/indra/newview/llpanelevent.cpp @@ -89,20 +89,16 @@ BOOL LLPanelEvent::postBuild() mTBCover = getChild("event_cover"); mTeleportBtn = getChild( "teleport_btn"); - mTeleportBtn->setClickedCallback(onClickTeleport); - mTeleportBtn->setCallbackUserData(this); + mTeleportBtn->setClickedCallback(boost::bind(&LLPanelEvent::onClickTeleport,this)); mMapBtn = getChild( "map_btn"); - mMapBtn->setClickedCallback(onClickMap); - mMapBtn->setCallbackUserData(this); + mMapBtn->setClickedCallback(boost::bind(&LLPanelEvent::onClickMap,this)); mNotifyBtn = getChild( "notify_btn"); - mNotifyBtn->setClickedCallback(onClickNotify); - mNotifyBtn->setCallbackUserData(this); + mNotifyBtn->setClickedCallback(boost::bind(&LLPanelEvent::onClickNotify,this)); mCreateEventBtn = getChild( "create_event_btn"); - mCreateEventBtn->setClickedCallback(onClickCreateEvent); - mCreateEventBtn->setCallbackUserData(this); + mCreateEventBtn->setClickedCallback(boost::bind(&LLPanelEvent::onClickCreateEvent,this)); return TRUE; } diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 835d8e514..b1e55d30c 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -72,8 +72,7 @@ BOOL LLPanelGroupTab::postBuild() LLButton* button = getChild("help_button"); if (button) { - button->setClickedCallback(onClickHelp); - button->setCallbackUserData(this); + button->setClickedCallback(boost::bind(&LLPanelGroupTab::onClickHelp,this)); } mHelpText = getString("help_text"); @@ -267,23 +266,21 @@ BOOL LLPanelGroup::postBuild() LLButton* button = getChild("btn_ok"); if (button) { - button->setClickedCallback(onBtnOK); - button->setCallbackUserData(this); + button->setClickedCallback(boost::bind(&LLPanelGroup::onBtnOK,this)); button->setVisible(mAllowEdit); } button = getChild("btn_cancel"); if (button) { - button->setClickedCallback(onBtnCancel); - button->setCallbackUserData(this); + button->setClickedCallback(boost::bind(&LLPanelGroup::onBtnCancel,this)); button->setVisible(mAllowEdit); } button = getChild("btn_apply"); if (button) { - button->setClickedCallback(onBtnApply); + button->setClickedCallback(boost::bind(&LLPanelGroup::onBtnApply,this)); button->setVisible(mAllowEdit); button->setEnabled(FALSE); @@ -293,8 +290,7 @@ BOOL LLPanelGroup::postBuild() button = getChild("btn_refresh"); if (button) { - button->setClickedCallback(onBtnRefresh); - button->setCallbackUserData(this); + button->setClickedCallback(boost::bind(&LLPanelGroup::onBtnRefresh,this)); button->setVisible(mAllowEdit); } diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 11d7b80bb..5aecdce57 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -135,15 +135,13 @@ BOOL LLPanelGroupGeneral::postBuild() mBtnJoinGroup = getChild("join_button", recurse); if ( mBtnJoinGroup ) { - mBtnJoinGroup->setClickedCallback(onClickJoin); - mBtnJoinGroup->setCallbackUserData(this); + mBtnJoinGroup->setClickedCallback(boost::bind(&LLPanelGroupGeneral::onClickJoin, this)); } mBtnInfo = getChild("info_button", recurse); if ( mBtnInfo ) { - mBtnInfo->setClickedCallback(onClickInfo); - mBtnInfo->setCallbackUserData(this); + mBtnInfo->setClickedCallback(boost::bind(&LLPanelGroupGeneral::onClickInfo, this)); } LLTextBox* founder = getChild("founder_name"); @@ -158,7 +156,7 @@ BOOL LLPanelGroupGeneral::postBuild() mListVisibleMembers = getChild("visible_members", recurse); if (mListVisibleMembers) { - mListVisibleMembers->setDoubleClickCallback(openProfile); + mListVisibleMembers->setDoubleClickCallback(&LLPanelGroupGeneral::openProfile); mListVisibleMembers->setCallbackUserData(this); } @@ -166,7 +164,7 @@ BOOL LLPanelGroupGeneral::postBuild() mCtrlShowInGroupList = getChild("show_in_group_list", recurse); if (mCtrlShowInGroupList) { - mCtrlShowInGroupList->setCommitCallback(onCommitAny); + mCtrlShowInGroupList->setCommitCallback(&LLPanelGroupGeneral::onCommitAny); mCtrlShowInGroupList->setCallbackUserData(this); } diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index cff4637bd..bd8cf5551 100644 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -527,17 +527,14 @@ BOOL LLPanelGroupInvite::postBuild() { // default to opening avatarpicker automatically // (*impl::callbackClickAdd)((void*)this); - button->setClickedCallback(impl::callbackClickAdd); - button->setCallbackUserData(this); + button->setClickedCallback(boost::bind(&impl::callbackClickAdd, this)); } mImplementation->mRemoveButton = getChild("remove_button", recurse); if ( mImplementation->mRemoveButton ) { - mImplementation->mRemoveButton-> - setClickedCallback(impl::callbackClickRemove); - mImplementation->mRemoveButton->setCallbackUserData(mImplementation); + mImplementation->mRemoveButton->setClickedCallback(boost::bind(&impl::callbackClickRemove, mImplementation)); mImplementation->mRemoveButton->setEnabled(FALSE); } @@ -545,17 +542,14 @@ BOOL LLPanelGroupInvite::postBuild() getChild("ok_button", recurse); if ( mImplementation->mOKButton ) { - mImplementation->mOKButton-> - setClickedCallback(impl::callbackClickOK); - mImplementation->mOKButton->setCallbackUserData(mImplementation); + mImplementation->mOKButton->setClickedCallback(boost::bind(&impl::callbackClickOK, mImplementation)); mImplementation->mOKButton->setEnabled(FALSE); } button = getChild("cancel_button", recurse); if ( button ) { - button->setClickedCallback(impl::callbackClickCancel); - button->setCallbackUserData(mImplementation); + button->setClickedCallback(boost::bind(&impl::callbackClickCancel,mImplementation)); } mImplementation->mOwnerWarning = getString("confirm_invite_owner_str"); diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp index 474c98ec2..fa0432b6c 100644 --- a/indra/newview/llpanelgrouplandmoney.cpp +++ b/indra/newview/llpanelgrouplandmoney.cpp @@ -654,7 +654,7 @@ BOOL LLPanelGroupLandMoney::postBuild() if ( mImplementationp->mMapButtonp ) { - mImplementationp->mMapButtonp->setClickedCallback(LLPanelGroupLandMoney::impl::mapCallback, mImplementationp); + mImplementationp->mMapButtonp->setClickedCallback(boost::bind(&LLPanelGroupLandMoney::impl::mapCallback, mImplementationp)); } if ( mImplementationp->mGroupOverLimitTextp ) diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 83a4c1a75..13786d9e4 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -220,13 +220,11 @@ BOOL LLPanelGroupNotices::postBuild() mNoticesList->setCallbackUserData(this); mBtnNewMessage = getChild("create_new_notice",recurse); - mBtnNewMessage->setClickedCallback(onClickNewMessage); - mBtnNewMessage->setCallbackUserData(this); + mBtnNewMessage->setClickedCallback(boost::bind(&LLPanelGroupNotices::onClickNewMessage,this)); mBtnNewMessage->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_NOTICES_SEND)); mBtnGetPastNotices = getChild("refresh_notices",recurse); - mBtnGetPastNotices->setClickedCallback(onClickRefreshNotices); - mBtnGetPastNotices->setCallbackUserData(this); + mBtnGetPastNotices->setClickedCallback(boost::bind(&LLPanelGroupNotices::onClickRefreshNotices,this)); // Create mCreateSubject = getChild("create_subject",recurse); @@ -240,12 +238,10 @@ BOOL LLPanelGroupNotices::postBuild() mCreateInventoryIcon->setVisible(FALSE); mBtnSendMessage = getChild("send_notice",recurse); - mBtnSendMessage->setClickedCallback(onClickSendMessage); - mBtnSendMessage->setCallbackUserData(this); + mBtnSendMessage->setClickedCallback(boost::bind(&LLPanelGroupNotices::onClickSendMessage,this)); mBtnRemoveAttachment = getChild("remove_attachment",recurse); - mBtnRemoveAttachment->setClickedCallback(onClickRemoveAttachment); - mBtnRemoveAttachment->setCallbackUserData(this); + mBtnRemoveAttachment->setClickedCallback(boost::bind(&LLPanelGroupNotices::onClickRemoveAttachment,this)); mBtnRemoveAttachment->setEnabled(FALSE); // View @@ -261,8 +257,7 @@ BOOL LLPanelGroupNotices::postBuild() mViewInventoryIcon->setVisible(FALSE); mBtnOpenAttachment = getChild("open_attachment",recurse); - mBtnOpenAttachment->setClickedCallback(onClickOpenAttachment); - mBtnOpenAttachment->setCallbackUserData(this); + mBtnOpenAttachment->setClickedCallback(boost::bind(&LLPanelGroupNotices::onClickOpenAttachment,this)); mNoNoticesStr = getString("no_notices_text"); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 5f5e8c9ec..cf07b5edb 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -501,15 +501,13 @@ BOOL LLPanelGroupSubTab::postBuild() mSearchButton = getChild("search_button", recurse); if (!mSearchButton) return FALSE; - mSearchButton->setClickedCallback(onClickSearch); - mSearchButton->setCallbackUserData(this); + mSearchButton->setClickedCallback(boost::bind(&LLPanelGroupSubTab::onClickSearch,this)); mSearchButton->setEnabled(FALSE); mShowAllButton = getChild("show_all_button", recurse); if (!mShowAllButton) return FALSE; - mShowAllButton->setClickedCallback(onClickShowAll); - mShowAllButton->setCallbackUserData(this); + mShowAllButton->setClickedCallback(boost::bind(&LLPanelGroupSubTab::onClickShowAll,this)); mShowAllButton->setEnabled(FALSE); // Get icons for later use. @@ -665,8 +663,7 @@ bool LLPanelGroupSubTab::matchesActionSearchFilter(std::string action) void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl, U64 allowed_by_some, U64 allowed_by_all, - icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role) @@ -686,7 +683,6 @@ void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl, allowed_by_some, allowed_by_all, (*ras_it), - icons, commit_callback, show_all, filter, @@ -698,8 +694,7 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, U64 allowed_by_some, U64 allowed_by_all, LLRoleActionSet* action_set, - icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role) @@ -712,10 +707,11 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, LLSD row; row["columns"][0]["column"] = "icon"; - icon_map_t::iterator iter = icons.find("folder"); - if (iter != icons.end()) + row["columns"][0]["type"] = "icon"; + + icon_map_t::iterator iter = mActionIcons.find("folder"); + if (iter != mActionIcons.end()) { - row["columns"][0]["type"] = "icon"; row["columns"][0]["value"] = (*iter).second; } @@ -777,8 +773,8 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, { if (show_full_strength) { - icon_map_t::iterator iter = icons.find("full"); - if (iter != icons.end()) + icon_map_t::iterator iter = mActionIcons.find("full"); + if (iter != mActionIcons.end()) { row["columns"][column_index]["column"] = "checkbox"; row["columns"][column_index]["type"] = "icon"; @@ -788,8 +784,8 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, } else { - icon_map_t::iterator iter = icons.find("partial"); - if (iter != icons.end()) + icon_map_t::iterator iter = mActionIcons.find("partial"); + if (iter != mActionIcons.end()) { row["columns"][column_index]["column"] = "checkbox"; row["columns"][column_index]["type"] = "icon"; @@ -813,7 +809,6 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, LLCheckBoxCtrl* check = check_cell->getCheckBox(); check->setEnabled(can_change_actions); check->setCommitCallback(commit_callback); - check->setCallbackUserData(ctrl->getCallbackUserData()); check->setToolTip( check->getLabel() ); if (show_all) @@ -912,16 +907,14 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) LLButton* button = parent->getChild("member_invite", recurse); if ( button ) { - button->setClickedCallback(onInviteMember); - button->setCallbackUserData(this); + button->setClickedCallback(boost::bind(&LLPanelGroupMembersSubTab::onInviteMember,this)); button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); } mEjectBtn = parent->getChild("member_eject", recurse); if ( mEjectBtn ) { - mEjectBtn->setClickedCallback(onEjectMembers); - mEjectBtn->setCallbackUserData(this); + mEjectBtn->setClickedCallback(boost::bind(&LLPanelGroupMembersSubTab::onEjectMembers,this)); mEjectBtn->setEnabled(FALSE); } @@ -956,7 +949,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() if (selection.empty()) return; // Build a vector of all selected members, and gather allowed actions. - std::vector selected_members; + uuid_vec_t selected_members; U64 allowed_by_all = 0xffffffffffffLL; U64 allowed_by_some = 0; @@ -964,10 +957,12 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() for (itor = selection.begin(); itor != selection.end(); ++itor) { - selected_members.push_back( (*itor)->getUUID() ); + LLUUID member_id = (*itor)->getUUID(); + + selected_members.push_back( member_id ); // Get this member's power mask including any unsaved changes - U64 powers = getAgentPowersBasedOnRoleChanges((*itor)->getUUID()); + U64 powers = getAgentPowersBasedOnRoleChanges( member_id ); allowed_by_all &= powers; allowed_by_some |= powers; @@ -980,7 +975,6 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() buildActionsList(mAllowedActionsList, allowed_by_some, allowed_by_all, - mActionIcons, NULL, FALSE, FALSE, @@ -1021,8 +1015,8 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() if (cb_enable && (count > 0) && role_id == gdatap->mOwnerRole) { // Check if any owners besides this agent are selected. - std::vector::const_iterator member_iter; - std::vector::const_iterator member_end = + uuid_vec_t::const_iterator member_iter; + uuid_vec_t::const_iterator member_end = selected_members.end(); for (member_iter = selected_members.begin(); member_iter != member_end; @@ -1048,7 +1042,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() //now see if there are any role changes for the selected //members and remember to include them - std::vector::iterator sel_mem_iter = selected_members.begin(); + uuid_vec_t::iterator sel_mem_iter = selected_members.begin(); for (; sel_mem_iter != selected_members.end(); sel_mem_iter++) { LLRoleMemberChangeType type; @@ -1106,7 +1100,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() check->setTentative( (0 != count) && (selected_members.size() != - (std::vector::size_type)count)); + (uuid_vec_t::size_type)count)); //NOTE: as of right now a user can break the group //by removing himself from a role if he is the @@ -1281,7 +1275,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, buildActionsList(mAllowedActionsList, powers_some_have, powers_all_have, - mActionIcons, NULL, FALSE, FALSE, @@ -1778,8 +1771,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) parent->getChild("role_create", recurse); if ( mCreateRoleButton ) { - mCreateRoleButton->setCallbackUserData(this); - mCreateRoleButton->setClickedCallback(onCreateRole); + mCreateRoleButton->setClickedCallback(boost::bind(&LLPanelGroupRolesSubTab::onCreateRole,this)); mCreateRoleButton->setEnabled(FALSE); } @@ -1787,8 +1779,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) parent->getChild("role_delete", recurse); if ( mDeleteRoleButton ) { - mDeleteRoleButton->setCallbackUserData(this); - mDeleteRoleButton->setClickedCallback(onDeleteRole); + mDeleteRoleButton->setClickedCallback(boost::bind(&LLPanelGroupRolesSubTab::onDeleteRole,this)); mDeleteRoleButton->setEnabled(FALSE); } @@ -2062,8 +2053,7 @@ void LLPanelGroupRolesSubTab::handleRoleSelect() buildActionsList(mAllowedActionsList, rd.mRolePowers, 0LL, - mActionIcons, - onActionCheck, + boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false), TRUE, FALSE, is_owner_role); @@ -2160,24 +2150,18 @@ void LLPanelGroupRolesSubTab::buildMembersList() } } -// static -void LLPanelGroupRolesSubTab::onActionCheck(LLUICtrl* ctrl, void* user_data) -{ - LLPanelGroupRolesSubTab* self = static_cast(user_data); - LLCheckBoxCtrl* check = static_cast(ctrl); - if (!check || !self) return; - - self->handleActionCheck(check); -} - struct ActionCBData { LLPanelGroupRolesSubTab* mSelf; LLCheckBoxCtrl* mCheck; }; -void LLPanelGroupRolesSubTab::handleActionCheck(LLCheckBoxCtrl* check, bool force) +void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) { + LLCheckBoxCtrl* check = dynamic_cast(ctrl); + if (!check) + return; + lldebugs << "LLPanelGroupRolesSubTab::handleActionSelect()" << llendl; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); @@ -2473,7 +2457,7 @@ BOOL LLPanelGroupActionsSubTab::postBuildSubTab(LLView* root) mActionList->setCallbackUserData(this); mActionList->setCommitOnSelectionChange(TRUE); - mActionList->setCommitCallback(onActionSelect); + mActionList->setCommitCallback(boost::bind(&LLPanelGroupActionsSubTab::handleActionSelect, this)); mActionMembers->setCallbackUserData(this); mActionRoles->setCallbackUserData(this); @@ -2529,20 +2513,12 @@ void LLPanelGroupActionsSubTab::update(LLGroupChange gc) buildActionsList(mActionList, GP_ALL_POWERS, GP_ALL_POWERS, - mActionIcons, NULL, FALSE, TRUE, FALSE); } -// static -void LLPanelGroupActionsSubTab::onActionSelect(LLUICtrl* scroll, void* data) -{ - LLPanelGroupActionsSubTab* self = static_cast(data); - self->handleActionSelect(); -} - void LLPanelGroupActionsSubTab::handleActionSelect() { mActionMembers->deleteAllItems(); diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 5b51fa03f..3083c2d56 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -130,8 +130,7 @@ public: void buildActionsList(LLScrollListCtrl* ctrl, U64 allowed_by_some, U64 allowed_by_all, - icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role); @@ -139,8 +138,7 @@ public: U64 allowed_by_some, U64 allowed_by_all, LLRoleActionSet* action_set, - icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role); @@ -248,8 +246,6 @@ public: void handleRoleSelect(); void buildMembersList(); - static void onActionCheck(LLUICtrl*, void*); - void handleActionCheck(LLCheckBoxCtrl*, bool force=false); bool addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check); static void onPropertiesKey(LLLineEditor*, void*); @@ -268,10 +264,8 @@ public: void saveRoleChanges(); protected: - LLSD createRoleItem(const LLUUID& role_id, - std::string name, - std::string title, - S32 members); + void handleActionCheck(LLUICtrl* ctrl, bool force); + LLSD createRoleItem(const LLUUID& role_id, std::string name, std::string title, S32 members); LLScrollListCtrl* mRolesList; LLNameListCtrl* mAssignedMembersList; @@ -306,7 +300,6 @@ public: virtual bool apply(std::string& mesg); virtual void update(LLGroupChange gc); - static void onActionSelect(LLUICtrl*, void*); void handleActionSelect(); protected: LLScrollListCtrl* mActionList; diff --git a/indra/newview/llpanelgroupvoting.cpp b/indra/newview/llpanelgroupvoting.cpp index d3d24b7d0..b4bee1522 100644 --- a/indra/newview/llpanelgroupvoting.cpp +++ b/indra/newview/llpanelgroupvoting.cpp @@ -1575,35 +1575,25 @@ BOOL LLPanelGroupVoting::postBuild() mImpl->mVotesHistory->setDoubleClickCallback(impl::onDoubleClickHistoryItem); mImpl->mVotesHistory->setCallbackUserData(mImpl); - mImpl->mBtnAbstain->setClickedCallback(impl::onClickAbstain); - mImpl->mBtnAbstain->setCallbackUserData(mImpl); + mImpl->mBtnAbstain->setClickedCallback(boost::bind(&impl::onClickAbstain,mImpl)); - mImpl->mBtnNo->setClickedCallback(impl::onClickNo); - mImpl->mBtnNo->setCallbackUserData(mImpl); + mImpl->mBtnNo->setClickedCallback(boost::bind(&impl::onClickNo,mImpl)); - mImpl->mBtnYes->setClickedCallback(impl::onClickYes); - mImpl->mBtnYes->setCallbackUserData(mImpl); + mImpl->mBtnYes->setClickedCallback(boost::bind(&impl::onClickYes,mImpl)); - mImpl->mBtnCreateProposal->setClickedCallback(impl::onClickCreateProposal); - mImpl->mBtnCreateProposal->setCallbackUserData(mImpl); + mImpl->mBtnCreateProposal->setClickedCallback(boost::bind(&impl::onClickCreateProposal,mImpl)); - mImpl->mBtnSubmitProposal->setClickedCallback(impl::onClickSubmitProposal); - mImpl->mBtnSubmitProposal->setCallbackUserData(mImpl); + mImpl->mBtnSubmitProposal->setClickedCallback(boost::bind(&impl::onClickSubmitProposal,mImpl)); - mImpl->mBtnCancelProposal->setClickedCallback(impl::onClickCancelProposal); - mImpl->mBtnCancelProposal->setCallbackUserData(mImpl); + mImpl->mBtnCancelProposal->setClickedCallback(boost::bind(&impl::onClickCancelProposal,mImpl)); - mImpl->mBtnViewProposalList->setClickedCallback(impl::onClickViewProposalList); - mImpl->mBtnViewProposalList->setCallbackUserData(mImpl); + mImpl->mBtnViewProposalList->setClickedCallback(boost::bind(&impl::onClickViewProposalList,mImpl)); - mImpl->mBtnViewProposalItem->setClickedCallback(impl::onClickViewProposalItem); - mImpl->mBtnViewProposalItem->setCallbackUserData(mImpl); + mImpl->mBtnViewProposalItem->setClickedCallback(boost::bind(&impl::onClickViewProposalItem,mImpl)); - mImpl->mBtnViewHistoryList->setClickedCallback(impl::onClickViewHistoryList); - mImpl->mBtnViewHistoryList->setCallbackUserData(mImpl); + mImpl->mBtnViewHistoryList->setClickedCallback(boost::bind(&impl::onClickViewHistoryList,mImpl)); - mImpl->mBtnViewHistoryItem->setClickedCallback(impl::onClickViewHistoryItem); - mImpl->mBtnViewHistoryItem->setCallbackUserData(mImpl); + mImpl->mBtnViewHistoryItem->setClickedCallback(boost::bind(&impl::onClickViewHistoryItem,mImpl)); gMessageSystem->setHandlerFuncFast(_PREHASH_GroupActiveProposalItemReply, impl::processGroupActiveProposalItemReply); diff --git a/indra/newview/llpanelmediahud.cpp b/indra/newview/llpanelmediahud.cpp index 2d0aa931c..2fcee26c6 100644 --- a/indra/newview/llpanelmediahud.cpp +++ b/indra/newview/llpanelmediahud.cpp @@ -129,20 +129,20 @@ BOOL LLPanelMediaHUD::postBuild() LLButton* scroll_up_btn = getChild("scrollup"); scroll_up_btn->setClickedCallback(onScrollUp, this); - scroll_up_btn->setHeldDownCallback(onScrollUpHeld); - scroll_up_btn->setMouseUpCallback(onScrollStop); + scroll_up_btn->setHeldDownCallback(onScrollUpHeld, this); + scroll_up_btn->setMouseUpCallback(onScrollStop, this); LLButton* scroll_left_btn = getChild("scrollleft"); scroll_left_btn->setClickedCallback(onScrollLeft, this); - scroll_left_btn->setHeldDownCallback(onScrollLeftHeld); - scroll_left_btn->setMouseUpCallback(onScrollStop); + scroll_left_btn->setHeldDownCallback(onScrollLeftHeld, this); + scroll_left_btn->setMouseUpCallback(onScrollStop, this); LLButton* scroll_right_btn = getChild("scrollright"); scroll_right_btn->setClickedCallback(onScrollRight, this); - scroll_right_btn->setHeldDownCallback(onScrollLeftHeld); - scroll_right_btn->setMouseUpCallback(onScrollStop); + scroll_right_btn->setHeldDownCallback(onScrollLeftHeld, this); + scroll_right_btn->setMouseUpCallback(onScrollStop, this); LLButton* scroll_down_btn = getChild("scrolldown"); scroll_down_btn->setClickedCallback(onScrollDown, this); - scroll_down_btn->setHeldDownCallback(onScrollDownHeld); - scroll_down_btn->setMouseUpCallback(onScrollStop); + scroll_down_btn->setHeldDownCallback(onScrollDownHeld, this); + scroll_down_btn->setMouseUpCallback(onScrollStop, this); mMouseInactiveTime = gSavedSettings.getF32("MediaControlTimeout"); mControlFadeTime = gSavedSettings.getF32("MediaControlFadeTime"); diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index 812ec22a0..7bcb0eb31 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -160,16 +160,13 @@ BOOL LLPanelPick::postBuild() mLocationEditor = getChild("location_editor"); mSetBtn = getChild( "set_location_btn"); - mSetBtn->setClickedCallback(onClickSet); - mSetBtn->setCallbackUserData(this); + mSetBtn->setClickedCallback(boost::bind(&LLPanelPick::onClickSet,this)); mTeleportBtn = getChild( "pick_teleport_btn"); - mTeleportBtn->setClickedCallback(onClickTeleport); - mTeleportBtn->setCallbackUserData(this); + mTeleportBtn->setClickedCallback(boost::bind(&LLPanelPick::onClickTeleport,this)); mMapBtn = getChild( "pick_map_btn"); - mMapBtn->setClickedCallback(onClickMap); - mMapBtn->setCallbackUserData(this); + mMapBtn->setClickedCallback(boost::bind(&LLPanelPick::onClickMap,this)); mSortOrderText = getChild("sort_order_text"); diff --git a/indra/newview/llpanelplace.cpp b/indra/newview/llpanelplace.cpp index 38b75572a..4f687099f 100644 --- a/indra/newview/llpanelplace.cpp +++ b/indra/newview/llpanelplace.cpp @@ -106,20 +106,16 @@ BOOL LLPanelPlace::postBuild() mLocationDisplay = getChild("location_editor"); mTeleportBtn = getChild( "teleport_btn"); - mTeleportBtn->setClickedCallback(onClickTeleport); - mTeleportBtn->setCallbackUserData(this); + mTeleportBtn->setClickedCallback(boost::bind(&LLPanelPlace::onClickTeleport,this)); mMapBtn = getChild( "map_btn"); - mMapBtn->setClickedCallback(onClickMap); - mMapBtn->setCallbackUserData(this); + mMapBtn->setClickedCallback(boost::bind(&LLPanelPlace::onClickMap,this)); //mLandmarkBtn = getChild( "landmark_btn"); - //mLandmarkBtn->setClickedCallback(onClickLandmark); - //mLandmarkBtn->setCallbackUserData(this); + //mLandmarkBtn->setClickedCallback(boost::bind(&LLPanelPlace::onClickLandmark,this)); mAuctionBtn = getChild( "auction_btn"); - mAuctionBtn->setClickedCallback(onClickAuction); - mAuctionBtn->setCallbackUserData(this); + mAuctionBtn->setClickedCallback(boost::bind(&LLPanelPlace::onClickAuction,this)); // Default to no auction button. We'll show it if we get an auction id mAuctionBtn->setVisible(FALSE); diff --git a/indra/newview/llpanelskins.cpp b/indra/newview/llpanelskins.cpp index 828598c3d..3d5958a5f 100644 --- a/indra/newview/llpanelskins.cpp +++ b/indra/newview/llpanelskins.cpp @@ -126,9 +126,9 @@ void LLPanelSkins::refresh() "textures"+gDirUtilp->getDirDelimiter()+ imagename); b->setImages(imageprev,imageprev); - b->setHoverImages(imageprev,imageprev); - b->setScaleImage(TRUE); - + b->setImageHoverSelected(LLUI::getUIImage(imageprev)); + b->setImageHoverUnselected(LLUI::getUIImage(imageprev)); + //