diff options
Diffstat (limited to 'indra')
28 files changed, 2048 insertions, 110 deletions
| diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 0429749e11..c550b81094 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -480,30 +480,61 @@ void LLFloaterTools::refresh()  	else  #endif  	{ -		F32 link_cost  = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost(); -		S32 link_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount(); +        LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); +        F32 link_cost = selection->getSelectedLinksetCost(); +        S32 link_count = selection->getRootObjectCount(); +        S32 object_count = selection->getObjectCount(); -		LLCrossParcelFunctor func; -		if (LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true)) -		{ -			// Selection crosses parcel bounds. -			// We don't display remaining land capacity in this case. -			const LLStringExplicit empty_str(""); -			childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", empty_str); -		} -		else -		{ -			LLViewerObject* selected_object = mObjectSelection->getFirstObject(); -			if (selected_object) -			{ -				// Select a parcel at the currently selected object's position. -				LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal()); -			} -			else -			{ -				LL_WARNS() << "Failed to get selected object" << LL_ENDL; -			} -		} +        LLCrossParcelFunctor func; +        if (!LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true)) +        { +            // Unless multiple parcels selected, higlight parcel object is at. +            LLViewerObject* selected_object = mObjectSelection->getFirstObject(); +            if (selected_object) +            { +                // Select a parcel at the currently selected object's position. +                LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal()); +            } +            else +            { +                LL_WARNS() << "Failed to get selected object" << LL_ENDL; +            } +        } + +        if (object_count == 1) +        { +            // "selection_faces" shouldn't be visible if not LLToolFace::getInstance() +            // But still need to be populated in case user switches + +            std::string faces_str = ""; + +            for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end();) +            { +                LLObjectSelection::iterator nextiter = iter++; // not strictly needed, we have only one object +                LLSelectNode* node = *nextiter; +                LLViewerObject* object = (*nextiter)->getObject(); +                if (!object) +                    continue; +                S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); +                for (S32 te = 0; te < num_tes; ++te) +                { +                    if (node->isTESelected(te)) +                    { +                        if (!faces_str.empty()) +                        { +                            faces_str += ", "; +                        } +                        faces_str += llformat("%d", te); +                    } +                } +            } + +            childSetTextArg("selection_faces", "[FACES_STRING]", faces_str); +        } + +        bool show_faces = (object_count == 1) +                          && LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); +        getChildView("selection_faces")->setVisible(show_faces);  		LLStringUtil::format_map_t selection_args;  		selection_args["OBJ_COUNT"] = llformat("%.1d", link_count); @@ -824,7 +855,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)  	bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();  	getChildView("selection_count")->setVisible(!land_visible && have_selection); -	getChildView("remaining_capacity")->setVisible(!land_visible && have_selection); +    getChildView("selection_faces")->setVisible(LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool() +                                                && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1);  	getChildView("selection_empty")->setVisible(!land_visible && !have_selection);  	mTab->setVisible(!land_visible); @@ -1181,26 +1213,6 @@ void LLFloaterTools::updateLandImpacts()  		return;  	} -	S32 rezzed_prims = parcel->getSimWidePrimCount(); -	S32 total_capacity = parcel->getSimWideMaxPrimCapacity(); -	LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); -	if (region) -	{ -		S32 max_tasks_per_region = (S32)region->getMaxTasks(); -		total_capacity = llmin(total_capacity, max_tasks_per_region); -	} -	std::string remaining_capacity_str = ""; - -	bool show_mesh_cost = gMeshRepo.meshRezEnabled(); -	if (show_mesh_cost) -	{ -		LLStringUtil::format_map_t remaining_capacity_args; -		remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims); -		remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args); -	} - -	childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", remaining_capacity_str); -  	// Update land impacts info in the weights floater  	LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance<LLFloaterObjectWeights>("object_weights");  	if(object_weights_floater) diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index d5ee7efdc6..def5a6bd6e 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -122,7 +122,7 @@ public:  	LLUUID       getWorldID(LLUUID tracking_id);      bool         isLocal(LLUUID world_id);  	std::string  getFilename(LLUUID tracking_id); - +      	void         feedScrollList(LLScrollListCtrl* ctrl);  	void         doUpdates();  	void         setNeedsRebake(); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 23394b26f2..e03533c029 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -38,6 +38,7 @@  #include "llfontgl.h"  // project includes +#include "llagent.h"  #include "llagentdata.h"  #include "llbutton.h"  #include "llcheckboxctrl.h" @@ -45,9 +46,13 @@  #include "llcombobox.h"  #include "lldrawpoolbump.h"  #include "llface.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" // gInventory +#include "llinventorymodelbackgroundfetch.h"  #include "lllineeditor.h"  #include "llmaterialmgr.h"  #include "llmediaentry.h" +#include "llmenubutton.h"  #include "llnotificationsutil.h"  #include "llradiogroup.h"  #include "llresmgr.h" @@ -57,6 +62,8 @@  #include "lltexturectrl.h"  #include "lltextureentry.h"  #include "lltooldraganddrop.h" +#include "lltoolface.h" +#include "lltoolmgr.h"  #include "lltrans.h"  #include "llui.h"  #include "llviewercontrol.h" @@ -298,7 +305,9 @@ BOOL	LLPanelFace::postBuild()  	{  		mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this);  	} -	 + +    mMenuClipboardColor = getChild<LLMenuButton>("clipboard_color_params_btn"); +    mMenuClipboardTexture = getChild<LLMenuButton>("clipboard_texture_params_btn");  	clearCtrls(); @@ -309,7 +318,9 @@ LLPanelFace::LLPanelFace()  :	LLPanel(),  	mIsAlpha(false)  { -	USE_TEXTURE = LLTrans::getString("use_texture"); +    USE_TEXTURE = LLTrans::getString("use_texture"); +    mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2)); +    mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2));  } @@ -1508,6 +1519,10 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  				}  			}  		} +        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); +        BOOL single_volume = (selected_count == 1); +        mMenuClipboardColor->setEnabled(editable && single_volume); +        mMenuClipboardTexture->setEnabled(editable && single_volume);  		// Set variable values for numeric expressions  		LLCalc* calcp = LLCalc::getInstance(); @@ -2538,6 +2553,804 @@ void LLPanelFace::onAlignTexture(void* userdata)      self->alignTestureLayer();  } +enum EPasteMode +{ +    PASTE_COLOR, +    PASTE_TEXTURE +}; + +struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor +{ +    LLPanelFacePasteTexFunctor(LLPanelFace* panel, EPasteMode mode) : +        mPanelFace(panel), mMode(mode) {} + +    virtual bool apply(LLViewerObject* objectp, S32 te) +    { +        switch (mMode) +        { +        case PASTE_COLOR: +            mPanelFace->onPasteColor(objectp, te); +            break; +        case PASTE_TEXTURE: +            mPanelFace->onPasteTexture(objectp, te); +            break; +        } +        return true; +    } +private: +    LLPanelFace *mPanelFace; +    EPasteMode mMode; +}; + +struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor +{ +    LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {} +    virtual bool apply(LLViewerObject* object) +    { +        object->sendTEUpdate(); +        if (mUpdateMedia) +        { +            LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object); +            if (vo && vo->hasMedia()) +            { +                vo->sendMediaDataUpdate(); +            } +        } +        return true; +    } +private: +    bool mUpdateMedia; +}; + +struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor +{ +    virtual bool apply(LLViewerObject* objectp, S32 te) +    { +        if (objectp && objectp->getTE(te)) +        { +            LLTextureEntry* tep = objectp->getTE(te); +            const LLMediaEntry *media_data = tep->getMediaData(); +            if (media_data) +            { +                if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) +                { +                    viewer_media_t media_impl = +                        LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); +                    if (media_impl) +                    { +                        media_impl->navigateHome(); +                    } +                } +            } +        } +        return true; +    } +}; + +void LLPanelFace::onCopyColor() +{ +    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); +    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); +    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); +    if (!objectp || !node +        || objectp->getPCode() != LL_PCODE_VOLUME +        || !objectp->permModify() +        || objectp->isPermanentEnforced() +        || selected_count > 1) +    { +        return; +    } + +    if (mClipboardParams.has("color")) +    { +        mClipboardParams["color"].clear(); +    } +    else +    { +        mClipboardParams["color"] = LLSD::emptyArray(); +    } + +    std::map<LLUUID, LLUUID> asset_item_map; + +    // a way to resolve situations where source and target have different amount of faces +    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); +    mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); +    for (S32 te = 0; te < num_tes; ++te) +    { +        if (node->isTESelected(te)) +        { +            LLTextureEntry* tep = objectp->getTE(te); +            if (tep) +            { +                LLSD te_data; + +                // asLLSD() includes media +                te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow + +                mClipboardParams["color"].append(te_data); +            } +        } +    } +} + +void LLPanelFace::onPasteColor() +{ +    if (!mClipboardParams.has("color")) +    { +        return; +    } + +    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); +    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); +    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); +    if (!objectp || !node +        || objectp->getPCode() != LL_PCODE_VOLUME +        || !objectp->permModify() +        || objectp->isPermanentEnforced() +        || selected_count > 1) +    { +        // not supposed to happen +        LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL; +        return; +    } + +    bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); +    LLSD &clipboard = mClipboardParams["color"]; // array +    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); +    S32 compare_tes = num_tes; + +    if (face_selection_mode) +    { +        compare_tes = 0; +        for (S32 te = 0; te < num_tes; ++te) +        { +            if (node->isTESelected(te)) +            { +                compare_tes++; +            } +        } +    } + +    // we can copy if single face was copied in edit face mode or if face count matches +    if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) +        && compare_tes != clipboard.size()) +    { +        LLSD notif_args; +        if (face_selection_mode) +        { +            static std::string reason = getString("paste_error_face_selection_mismatch"); +            notif_args["REASON"] = reason; +        } +        else +        { +            static std::string reason = getString("paste_error_object_face_count_mismatch"); +            notif_args["REASON"] = reason; +        } +        LLNotificationsUtil::add("FacePasteFailed", notif_args); +        return; +    } + +    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + +    LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); +    selected_objects->applyToTEs(&paste_func); + +    LLPanelFaceUpdateFunctor sendfunc(false); +    selected_objects->applyToObjects(&sendfunc); +} + +void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) +{ +    LLSD te_data; +    LLSD &clipboard = mClipboardParams["color"]; // array +    if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) +    { +        te_data = *(clipboard.beginArray()); +    } +    else if (clipboard[te]) +    { +        te_data = clipboard[te]; +    } +    else +    { +        return; +    } + +    LLTextureEntry* tep = objectp->getTE(te); +    if (tep) +    { +        if (te_data.has("te")) +        { +            // Color / Alpha +            if (te_data["te"].has("colors")) +            { +                LLColor4 color = tep->getColor(); + +                LLColor4 clip_color; +                clip_color.setValue(te_data["te"]["colors"]); + +                // Color +                color.mV[VRED] = clip_color.mV[VRED]; +                color.mV[VGREEN] = clip_color.mV[VGREEN]; +                color.mV[VBLUE] = clip_color.mV[VBLUE]; + +                // Alpha +                color.mV[VALPHA] = clip_color.mV[VALPHA]; + +                objectp->setTEColor(te, color); +            } + +            // Color/fullbright +            if (te_data["te"].has("fullbright")) +            { +                objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger()); +            } + +            // Glow +            if (te_data["te"].has("glow")) +            { +                objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal()); +            } +        } +    } +} + +void LLPanelFace::onCopyTexture() +{ +    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); +    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); +    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); +    if (!objectp || !node +        || objectp->getPCode() != LL_PCODE_VOLUME +        || !objectp->permModify() +        || objectp->isPermanentEnforced() +        || selected_count > 1) +    { +        return; +    } + +    if (mClipboardParams.has("texture")) +    { +        mClipboardParams["texture"].clear(); +    } +    else +    { +        mClipboardParams["texture"] = LLSD::emptyArray(); +    } + +    std::map<LLUUID, LLUUID> asset_item_map; + +    // a way to resolve situations where source and target have different amount of faces +    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); +    mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); +    for (S32 te = 0; te < num_tes; ++te) +    { +        if (node->isTESelected(te)) +        { +            LLTextureEntry* tep = objectp->getTE(te); +            if (tep) +            { +                LLSD te_data; + +                // asLLSD() includes media +                te_data["te"] = tep->asLLSD(); +                te_data["te"]["shiny"] = tep->getShiny(); +                te_data["te"]["bumpmap"] = tep->getBumpmap(); +                te_data["te"]["bumpshiny"] = tep->getBumpShiny(); +                te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); + +                if (te_data["te"].has("imageid")) +                { +                    LLUUID item_id; +                    LLUUID id = te_data["te"]["imageid"].asUUID(); +                    bool from_library = get_is_predefined_texture(id); +                    bool full_perm = from_library; + +                    if (!full_perm +                        && objectp->permCopy() +                        && objectp->permTransfer() +                        && objectp->permModify()) +                    { +                        // If agent created this object and nothing is limiting permissions, mark as full perm +                        // If agent was granted permission to edit objects owned and created by somebody else, mark full perm +                        // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive +                        std::string creator_app_link; +                        LLUUID creator_id; +                        LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link); +                        full_perm = objectp->mOwnerID == creator_id; +                    } + +                    if (id.notNull() && !full_perm) +                    { +                        std::map<LLUUID, LLUUID>::iterator iter = asset_item_map.find(id); +                        if (iter != asset_item_map.end()) +                        { +                            item_id = iter->second; +                        } +                        else +                        { +                            // What this does is simply searches inventory for item with same asset id, +                            // as result it is Hightly unreliable, leaves little control to user, borderline hack +                            // but there are little options to preserve permissions - multiple inventory +                            // items might reference same asset and inventory search is expensive. +                            item_id = get_copy_free_item_by_asset_id(id); +                            // record value to avoid repeating inventory search when possible +                            asset_item_map[id] = item_id; +                        } +                    } + +                    if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) +                    { +                        full_perm = true; +                        from_library = true; +                    } + +                    { +                        te_data["te"]["itemfullperm"] = full_perm; +                        te_data["te"]["fromlibrary"] = from_library;  + +                        // If full permission object, texture is free to copy, +                        // but otherwise we need to check inventory and extract permissions +                        // +                        // Normally we care only about restrictions for current user and objects +                        // don't inherit any 'next owner' permissions from texture, so there is +                        // no need to record item id if full_perm==true +                        if (!full_perm && !from_library && item_id.notNull()) +                        { +                            LLViewerInventoryItem* itemp = gInventory.getItem(item_id); +                            if (itemp) +                            { +                                LLPermissions item_permissions = itemp->getPermissions(); +                                if (item_permissions.allowOperationBy(PERM_COPY, +                                    gAgent.getID(), +                                    gAgent.getGroupID())) +                                { +                                    te_data["te"]["imageitemid"] = item_id; +                                    te_data["te"]["itemfullperm"] = itemp->getIsFullPerm(); +                                    if (!itemp->isFinished()) +                                    { +                                        // needed for dropTextureAllFaces +                                        LLInventoryModelBackgroundFetch::instance().start(item_id, false); +                                    } +                                } +                            } +                        } +                    } +                } + +                LLMaterialPtr material_ptr = tep->getMaterialParams(); +                if (!material_ptr.isNull()) +                { +                    LLSD mat_data; + +                    mat_data["NormMap"] = material_ptr->getNormalID(); +                    mat_data["SpecMap"] = material_ptr->getSpecularID(); + +                    mat_data["NormRepX"] = material_ptr->getNormalRepeatX(); +                    mat_data["NormRepY"] = material_ptr->getNormalRepeatY(); +                    mat_data["NormOffX"] = material_ptr->getNormalOffsetX(); +                    mat_data["NormOffY"] = material_ptr->getNormalOffsetY(); +                    mat_data["NormRot"] = material_ptr->getNormalRotation(); + +                    mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX(); +                    mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY(); +                    mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX(); +                    mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY(); +                    mat_data["SpecRot"] = material_ptr->getSpecularRotation(); + +                    mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue(); +                    mat_data["SpecExp"] = material_ptr->getSpecularLightExponent(); +                    mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity(); +                    mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff(); +                    mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode(); + +                    // Replace no-copy textures, destination texture will get used instead if available +                    if (mat_data.has("NormMap")) +                    { +                        LLUUID id = mat_data["NormMap"].asUUID(); +                        if (id.notNull() && !get_can_copy_texture(id)) +                        { +                            mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); +                            mat_data["NormMapNoCopy"] = true; +                        } + +                    } +                    if (mat_data.has("SpecMap")) +                    { +                        LLUUID id = mat_data["SpecMap"].asUUID(); +                        if (id.notNull() && !get_can_copy_texture(id)) +                        { +                            mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); +                            mat_data["SpecMapNoCopy"] = true; +                        } + +                    } + +                    te_data["material"] = mat_data; +                } + +                mClipboardParams["texture"].append(te_data); +            } +        } +    } +} + +void LLPanelFace::onPasteTexture() +{ +    if (!mClipboardParams.has("texture")) +    { +        return; +    } + +    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); +    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); +    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); +    if (!objectp || !node +        || objectp->getPCode() != LL_PCODE_VOLUME +        || !objectp->permModify() +        || objectp->isPermanentEnforced() +        || selected_count > 1) +    { +        // not supposed to happen +        LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL; +        return; +    } + +    bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); +    LLSD &clipboard = mClipboardParams["texture"]; // array +    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); +    S32 compare_tes = num_tes; + +    if (face_selection_mode) +    { +        compare_tes = 0; +        for (S32 te = 0; te < num_tes; ++te) +        { +            if (node->isTESelected(te)) +            { +                compare_tes++; +            } +        } +    } + +    // we can copy if single face was copied in edit face mode or if face count matches +    if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean())  +        && compare_tes != clipboard.size()) +    { +        LLSD notif_args; +        if (face_selection_mode) +        { +            static std::string reason = getString("paste_error_face_selection_mismatch"); +            notif_args["REASON"] = reason; +        } +        else +        { +            static std::string reason = getString("paste_error_object_face_count_mismatch"); +            notif_args["REASON"] = reason; +        } +        LLNotificationsUtil::add("FacePasteFailed", notif_args); +        return; +    } + +    bool full_perm_object = true; +    LLSD::array_const_iterator iter = clipboard.beginArray(); +    LLSD::array_const_iterator end = clipboard.endArray(); +    for (; iter != end; ++iter) +    { +        const LLSD& te_data = *iter; +        if (te_data.has("te") && te_data["te"].has("imageid")) +        { +            bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); +            full_perm_object &= full_perm; +            if (!full_perm) +            { +                if (te_data["te"].has("imageitemid")) +                { +                    LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); +                    if (item_id.notNull()) +                    { +                        LLViewerInventoryItem* itemp = gInventory.getItem(item_id); +                        if (!itemp) +                        { +                            // image might be in object's inventory, but it can be not up to date +                            LLSD notif_args; +                            static std::string reason = getString("paste_error_inventory_not_found"); +                            notif_args["REASON"] = reason; +                            LLNotificationsUtil::add("FacePasteFailed", notif_args); +                            return; +                        } +                    } +                } +                else +                { +                    // Item was not found on 'copy' stage +                    // Since this happened at copy, might be better to either show this +                    // at copy stage or to drop clipboard here +                    LLSD notif_args; +                    static std::string reason = getString("paste_error_inventory_not_found"); +                    notif_args["REASON"] = reason; +                    LLNotificationsUtil::add("FacePasteFailed", notif_args); +                    return; +                } +            } +        } +    } + +    if (!full_perm_object) +    { +        LLNotificationsUtil::add("FacePasteTexturePermissions"); +    } + +    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + +    LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); +    selected_objects->applyToTEs(&paste_func); + +    LLPanelFaceUpdateFunctor sendfunc(true); +    selected_objects->applyToObjects(&sendfunc); + +    LLPanelFaceNavigateHomeFunctor navigate_home_func; +    selected_objects->applyToTEs(&navigate_home_func); +} + +void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) +{ +    LLSD te_data; +    LLSD &clipboard = mClipboardParams["texture"]; // array +    if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) +    { +        te_data = *(clipboard.beginArray()); +    } +    else if (clipboard[te]) +    { +        te_data = clipboard[te]; +    } +    else +    { +        return; +    } + +    LLTextureEntry* tep = objectp->getTE(te); +    if (tep) +    { +        if (te_data.has("te")) +        { +            // Texture +            bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); +            bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean(); +            if (te_data["te"].has("imageid")) +            { +                const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id +                LLViewerInventoryItem* itemp_res = NULL; + +                if (te_data["te"].has("imageitemid")) +                { +                    LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); +                    if (item_id.notNull()) +                    { +                        LLViewerInventoryItem* itemp = gInventory.getItem(item_id); +                        if (itemp && itemp->isFinished()) +                        { +                            // dropTextureAllFaces will fail if incomplete +                            itemp_res = itemp; +                        } +                        else +                        { +                            // Theoretically shouldn't happend, but if it does happen, we +                            // might need to add a notification to user that paste will fail +                            // since inventory isn't fully loaded +                            LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL; +                        } +                    } +                } +                // for case when item got removed from inventory after we pressed 'copy' +                // or texture got pasted into previous object +                if (!itemp_res && !full_perm) +                { +                    // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable. +                    LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL; +                    // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) +                    // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work +                    LLViewerInventoryCategory::cat_array_t cats; +                    LLViewerInventoryItem::item_array_t items; +                    LLAssetIDMatches asset_id_matches(imageid); +                    gInventory.collectDescendentsIf(LLUUID::null, +                        cats, +                        items, +                        LLInventoryModel::INCLUDE_TRASH, +                        asset_id_matches); + +                    // Extremely unreliable and perfomance unfriendly. +                    // But we need this to check permissions and it is how texture control finds items +                    for (S32 i = 0; i < items.size(); i++) +                    { +                        LLViewerInventoryItem* itemp = items[i]; +                        if (itemp && itemp->isFinished()) +                        { +                            // dropTextureAllFaces will fail if incomplete +                            LLPermissions item_permissions = itemp->getPermissions(); +                            if (item_permissions.allowOperationBy(PERM_COPY, +                                gAgent.getID(), +                                gAgent.getGroupID())) +                            { +                                itemp_res = itemp; +                                break; // first match +                            } +                        } +                    } +                } + +                if (itemp_res) +                { +                    if (te == -1) // all faces +                    { +                        LLToolDragAndDrop::dropTextureAllFaces(objectp, +                            itemp_res, +                            from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, +                            LLUUID::null); +                    } +                    else // one face +                    { +                        LLToolDragAndDrop::dropTextureOneFace(objectp, +                            te, +                            itemp_res, +                            from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, +                            LLUUID::null); +                    } +                } +                // not an inventory item or no complete items +                else if (full_perm) +                { +                    // Either library, local or existed as fullperm when user made a copy +                    LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); +                    objectp->setTEImage(U8(te), image); +                } +            } + +            if (te_data["te"].has("bumpmap")) +            { +                objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger()); +            } +            if (te_data["te"].has("bumpshiny")) +            { +                objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger()); +            } +            if (te_data["te"].has("bumpfullbright")) +            { +                objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger()); +            } + +            // Texture map +            if (te_data["te"].has("scales") && te_data["te"].has("scalet")) +            { +                objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal()); +            } +            if (te_data["te"].has("offsets") && te_data["te"].has("offsett")) +            { +                objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal()); +            } +            if (te_data["te"].has("imagerot")) +            { +                objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal()); +            } + +            // Media +            if (te_data["te"].has("media_flags")) +            { +                U8 media_flags = te_data["te"]["media_flags"].asInteger(); +                objectp->setTEMediaFlags(te, media_flags); +                LLVOVolume *vo = dynamic_cast<LLVOVolume*>(objectp); +                if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY)) +                { +                    vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/); +                } +            } +            else +            { +                // Keep media flags on destination unchanged +            } +        } + +        if (te_data.has("material")) +        { +            LLUUID object_id = objectp->getID(); + +            LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); + +            // Normal +            // Replace placeholders with target's +            if (te_data["material"].has("NormMapNoCopy")) +            { +                LLMaterialPtr material = tep->getMaterialParams(); +                if (material.notNull()) +                { +                    LLUUID id = material->getNormalID(); +                    if (id.notNull()) +                    { +                        te_data["material"]["NormMap"] = id; +                    } +                } +            } +            LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id); +            LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id); +            LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id); +            LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id); +            LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id); +            LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id); + +            // Specular +                // Replace placeholders with target's +            if (te_data["material"].has("SpecMapNoCopy")) +            { +                LLMaterialPtr material = tep->getMaterialParams(); +                if (material.notNull()) +                { +                    LLUUID id = material->getSpecularID(); +                    if (id.notNull()) +                    { +                        te_data["material"]["SpecMap"] = id; +                    } +                } +            } +            LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id); +            LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id); +            LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id); +            LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id); +            LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id); +            LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id); +            LLColor4 spec_color(te_data["material"]["SpecColor"]); +            LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); +            LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); +            LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); +            LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); +            if (te_data.has("te") && te_data["te"].has("shiny")) +            { +                objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); +            } +        } +    } +} + +void LLPanelFace::menuDoToSelected(const LLSD& userdata) +{ +    std::string command = userdata.asString(); + +    // paste +    if (command == "color_paste") +    { +        onPasteColor(); +    } +    else if (command == "texture_paste") +    { +        onPasteTexture(); +    } +    // copy +    else if (command == "color_copy") +    { +        onCopyColor(); +    } +    else if (command == "texture_copy") +    { +        onCopyTexture(); +    } +} + +bool LLPanelFace::menuEnableItem(const LLSD& userdata) +{ +    std::string command = userdata.asString(); + +    // paste options +    if (command == "color_paste") +    { +        return mClipboardParams.has("color"); +    } +    else if (command == "texture_paste") +    { +        return mClipboardParams.has("texture"); +    } +    return false; +} +  // TODO: I don't know who put these in or what these are for???  void LLPanelFace::setMediaURL(const std::string& url) diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 2d57d89a44..948d33c2c1 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -47,6 +47,7 @@ class LLUICtrl;  class LLViewerObject;  class LLFloater;  class LLMaterialID; +class LLMenuButton;  // Represents an edit for use in replicating the op across one or more materials in the selection set.  // @@ -205,6 +206,18 @@ protected:  	static void		onClickAutoFix(void*);      static void		onAlignTexture(void*); +public: // needs to be accessible to selection manager +    void            onCopyColor(); // records all selected faces +    void            onPasteColor(); // to specific face +    void            onPasteColor(LLViewerObject* objectp, S32 te); // to specific face +    void            onCopyTexture(); +    void            onPasteTexture(); +    void            onPasteTexture(LLViewerObject* objectp, S32 te); + +protected: +    void            menuDoToSelected(const LLSD& userdata); +    bool            menuEnableItem(const LLSD& userdata); +  	static F32     valueGlow(LLViewerObject* object, S32 face); @@ -400,7 +413,10 @@ private:  	 * If agent selects texture which is not allowed to be applied for the currently selected object,  	 * all controls of the floater texture picker which allow to apply the texture will be disabled.  	 */ -	void onTextureSelectionChanged(LLInventoryItem* itemp); +    void onTextureSelectionChanged(LLInventoryItem* itemp); + +    LLMenuButton*   mMenuClipboardColor; +    LLMenuButton*   mMenuClipboardTexture;  	bool mIsAlpha; @@ -415,7 +431,9 @@ private:  	 * up-arrow on a spinner, and avoids running afoul of its throttle.  	 */  	bool mUpdateInFlight; -	bool mUpdatePending; +    bool mUpdatePending; + +    LLSD            mClipboardParams;  public:  	#if defined(DEF_GET_MAT_STATE) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 6bff95ab36..9bdc68b86a 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -46,6 +46,7 @@  #include "llcombobox.h"  #include "llfocusmgr.h"  #include "llmanipscale.h" +#include "llmenubutton.h"  #include "llpreviewscript.h"  #include "llresmgr.h"  #include "llselectmgr.h" @@ -117,8 +118,9 @@ BOOL	LLPanelObject::postBuild()  	// Phantom checkbox  	mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");  	childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); -        +  	// Position +	mMenuClipboardPos = getChild<LLMenuButton>("clipboard_pos_btn");  	mLabelPosition = getChild<LLTextBox>("label position");  	mCtrlPosX = getChild<LLSpinCtrl>("Pos X");  	childSetCommitCallback("Pos X",onCommitPosition,this); @@ -128,6 +130,7 @@ BOOL	LLPanelObject::postBuild()  	childSetCommitCallback("Pos Z",onCommitPosition,this);  	// Scale +	mMenuClipboardSize = getChild<LLMenuButton>("clipboard_size_btn");  	mLabelSize = getChild<LLTextBox>("label size");  	mCtrlScaleX = getChild<LLSpinCtrl>("Scale X");  	childSetCommitCallback("Scale X",onCommitScale,this); @@ -141,6 +144,7 @@ BOOL	LLPanelObject::postBuild()  	childSetCommitCallback("Scale Z",onCommitScale,this);  	// Rotation +	mMenuClipboardRot = getChild<LLMenuButton>("clipboard_rot_btn");  	mLabelRotation = getChild<LLTextBox>("label rotation");  	mCtrlRotX = getChild<LLSpinCtrl>("Rot X");  	childSetCommitCallback("Rot X",onCommitRotation,this); @@ -155,6 +159,8 @@ BOOL	LLPanelObject::postBuild()  	mComboBaseType = getChild<LLComboBox>("comboBaseType");  	childSetCommitCallback("comboBaseType",onCommitParametric,this); +	mMenuClipboardParams = getChild<LLMenuButton>("clipboard_obj_params_btn"); +  	// Cut  	mLabelCut = getChild<LLTextBox>("text cut");  	mSpinCutBegin = getChild<LLSpinCtrl>("cut begin"); @@ -285,8 +291,13 @@ LLPanelObject::LLPanelObject()  	mSelectedType(MI_BOX),  	mSculptTextureRevert(LLUUID::null),  	mSculptTypeRevert(0), +    mHasClipboardPos(false), +    mHasClipboardSize(false), +    mHasClipboardRot(false),  	mSizeChanged(FALSE)  { +    mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2)); +    mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2));  } @@ -373,7 +384,7 @@ void LLPanelObject::getState( )  		calcp->clearVar(LLCalc::Z_POS);  	} - +	mMenuClipboardPos->setEnabled(enable_move);  	mLabelPosition->setEnabled( enable_move );  	mCtrlPosX->setEnabled(enable_move);  	mCtrlPosY->setEnabled(enable_move); @@ -399,6 +410,7 @@ void LLPanelObject::getState( )  		calcp->setVar(LLCalc::Z_SCALE, 0.f);  	} +	mMenuClipboardSize->setEnabled(enable_scale);  	mLabelSize->setEnabled( enable_scale );  	mCtrlScaleX->setEnabled( enable_scale );  	mCtrlScaleY->setEnabled( enable_scale ); @@ -430,6 +442,7 @@ void LLPanelObject::getState( )  		calcp->clearVar(LLCalc::Z_ROT);  	} +	mMenuClipboardRot->setEnabled(enable_rotate);  	mLabelRotation->setEnabled( enable_rotate );  	mCtrlRotX->setEnabled( enable_rotate );  	mCtrlRotY->setEnabled( enable_rotate ); @@ -607,7 +620,7 @@ void LLPanelObject::getState( )  		}  		else  		{ -			LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL; +			LL_INFOS("FloaterTools") << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;  			selected_item = MI_BOX;  		} @@ -933,6 +946,7 @@ void LLPanelObject::getState( )  	// Update field enablement  	mComboBaseType	->setEnabled( enabled ); +	mMenuClipboardParams->setEnabled(enabled);  	mLabelCut		->setEnabled( enabled );  	mSpinCutBegin	->setEnabled( enabled ); @@ -1093,7 +1107,8 @@ void LLPanelObject::getState( )  			}  			mComboBaseType->setEnabled(!isMesh); -			 +			mMenuClipboardParams->setEnabled(!isMesh); +  			if (mCtrlSculptType)  			{  				if (sculpt_stitching == LL_SCULPT_TYPE_NONE) @@ -1157,11 +1172,11 @@ void LLPanelObject::sendIsPhysical()  		LLSelectMgr::getInstance()->selectionUpdatePhysics(value);  		mIsPhysical = value; -		LL_INFOS() << "update physics sent" << LL_ENDL; +		LL_INFOS("FloaterTools") << "update physics sent" << LL_ENDL;  	}  	else  	{ -		LL_INFOS() << "update physics not changed" << LL_ENDL; +		LL_INFOS("FloaterTools") << "update physics not changed" << LL_ENDL;  	}  } @@ -1173,11 +1188,11 @@ void LLPanelObject::sendIsTemporary()  		LLSelectMgr::getInstance()->selectionUpdateTemporary(value);  		mIsTemporary = value; -		LL_INFOS() << "update temporary sent" << LL_ENDL; +		LL_INFOS("FloaterTools") << "update temporary sent" << LL_ENDL;  	}  	else  	{ -		LL_INFOS() << "update temporary not changed" << LL_ENDL; +		LL_INFOS("FloaterTools") << "update temporary not changed" << LL_ENDL;  	}  } @@ -1190,11 +1205,11 @@ void LLPanelObject::sendIsPhantom()  		LLSelectMgr::getInstance()->selectionUpdatePhantom(value);  		mIsPhantom = value; -		LL_INFOS() << "update phantom sent" << LL_ENDL; +		LL_INFOS("FloaterTools") << "update phantom sent" << LL_ENDL;  	}  	else  	{ -		LL_INFOS() << "update phantom not changed" << LL_ENDL; +		LL_INFOS("FloaterTools") << "update phantom not changed" << LL_ENDL;  	}  } @@ -1304,7 +1319,7 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)  		break;  	default: -		LL_WARNS() << "Unknown base type " << selected_type  +		LL_WARNS("FloaterTools") << "Unknown base type " << selected_type   			<< " in getVolumeParams()" << LL_ENDL;  		// assume a box  		selected_type = MI_BOX; @@ -1644,6 +1659,8 @@ void LLPanelObject::sendPosition(BOOL btn_down)  	LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());  	LLViewerRegion* regionp = mObject->getRegion(); +	if (!regionp) return; +  	// Clamp the Z height  	const F32 height = newpos.mV[VZ];  	const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal()); @@ -2000,3 +2017,283 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata)  	self->sendSculpt();  } + +void LLPanelObject::menuDoToSelected(const LLSD& userdata) +{ +    std::string command = userdata.asString(); + +    // paste +    if (command == "psr_paste") +    { +        onPastePos(); +        onPasteSize(); +        onPasteRot(); +    } +    else if (command == "pos_paste") +    { +        onPastePos(); +    } +    else if (command == "size_paste") +    { +        onPasteSize(); +    } +    else if (command == "rot_paste") +    { +        onPasteRot(); +    } +    else if (command == "params_paste") +    { +        onPasteParams(); +    } +    // copy +    else if (command == "psr_copy") +    { +        onCopyPos(); +        onCopySize(); +        onCopyRot(); +    } +    else if (command == "pos_copy") +    { +        onCopyPos(); +    } +    else if (command == "size_copy") +    { +        onCopySize(); +    } +    else if (command == "rot_copy") +    { +        onCopyRot(); +    } +    else if (command == "params_copy") +    { +        onCopyParams(); +    } +} + +bool LLPanelObject::menuEnableItem(const LLSD& userdata) +{ +    std::string command = userdata.asString(); + +    // paste options +    if (command == "psr_paste") +    { +        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); +        BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME)) +            && (selected_count == 1); + +        if (!single_volume) +        { +            return false; +        } + +        bool enable_move; +        bool enable_modify; + +        LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify); + +        return enable_move && enable_modify && mHasClipboardPos && mHasClipboardSize && mHasClipboardRot; +    } +    else if (command == "pos_paste") +    { +        // assumes that menu won't be active if there is no move permission +        return mHasClipboardPos; +    } +    else if (command == "size_paste") +    { +        return mHasClipboardSize; +    } +    else if (command == "rot_paste") +    { +        return mHasClipboardRot; +    } +    else if (command == "params_paste") +    { +        return mClipboardParams.isMap() && !mClipboardParams.emptyMap(); +    } +    // copy options +    else if (command == "psr_copy") +    { +        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); +        BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME)) +            && (selected_count == 1); + +        if (!single_volume) +        { +            return false; +        } + +        bool enable_move; +        bool enable_modify; + +        LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify); + +        // since we forbid seeing values we also should forbid copying them +        return enable_move && enable_modify; +    } +    return false; +} + +void LLPanelObject::onCopyPos() +{ +    mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); + +    std::string stringVec = llformat("<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ]); +    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); + +    mHasClipboardPos = true; +} + +void LLPanelObject::onCopySize() +{ +    mClipboardSize = LLVector3(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); + +    std::string stringVec = llformat("<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ]); +    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); + +    mHasClipboardSize = true; +} + +void LLPanelObject::onCopyRot() +{ +    mClipboardRot = LLVector3(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); + +    std::string stringVec = llformat("<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ]); +    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); + +    mHasClipboardRot = true; +} + +void LLPanelObject::onPastePos() +{ +    if (!mHasClipboardPos) return; +    if (mObject.isNull()) return; + +    LLViewerRegion* regionp = mObject->getRegion(); +    if (!regionp) return; + + +    // Clamp pos on non-attachments, just keep the prims within the region +    if (!mObject->isAttachment()) +    { +        F32 max_width = regionp->getWidth(); // meters +        mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], 0.f, max_width); +        mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], 0.f, max_width); +        //height will get properly clamped by sendPosition +    } + +    mCtrlPosX->set( mClipboardPos.mV[VX] ); +    mCtrlPosY->set( mClipboardPos.mV[VY] ); +    mCtrlPosZ->set( mClipboardPos.mV[VZ] ); + +    sendPosition(FALSE); +} + +void LLPanelObject::onPasteSize() +{ +    if (!mHasClipboardSize) return; + +    mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); +    mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); +    mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); + +    mCtrlScaleX->set(mClipboardSize.mV[VX]); +    mCtrlScaleY->set(mClipboardSize.mV[VY]); +    mCtrlScaleZ->set(mClipboardSize.mV[VZ]); + +    sendScale(FALSE); +} + +void LLPanelObject::onPasteRot() +{ +    if (!mHasClipboardRot) return; + +    mCtrlRotX->set(mClipboardRot.mV[VX]); +    mCtrlRotY->set(mClipboardRot.mV[VY]); +    mCtrlRotZ->set(mClipboardRot.mV[VZ]); + +    sendRotation(FALSE); +} + +void LLPanelObject::onCopyParams() +{ +    LLViewerObject* objectp = mObject; +    if (!objectp || objectp->isMesh()) +    { +        return; +    } + +    mClipboardParams.clear(); + +    // Parametrics +    LLVolumeParams params; +    getVolumeParams(params); +    mClipboardParams["volume_params"] = params.asLLSD(); + +    // Sculpted Prim +    if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) +    { +        LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + +        LLUUID texture_id = sculpt_params->getSculptTexture(); +        if (get_can_copy_texture(texture_id)) +        { +            LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL; +            mClipboardParams["sculpt"]["id"] = texture_id; +        } +        else +        { +            mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); +        } + +        mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); +    } +} + +void LLPanelObject::onPasteParams() +{ +    LLViewerObject* objectp = mObject; +    if (!objectp) +    { +        return; +    } + +    // Sculpted Prim +    if (mClipboardParams.has("sculpt")) +    { +        LLSculptParams sculpt_params; +        LLUUID sculpt_id = mClipboardParams["sculpt"]["id"].asUUID(); +        U8 sculpt_type = (U8)mClipboardParams["sculpt"]["type"].asInteger(); +        sculpt_params.setSculptTexture(sculpt_id, sculpt_type); +        objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); +    } +    else +    { +        LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); +        if (sculpt_params) +        { +            objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); +        } +    } + +    // volume params +    // make sure updateVolume() won't affect flexible +    if (mClipboardParams.has("volume_params")) +    { +        LLVolumeParams params; +        params.fromLLSD(mClipboardParams["volume_params"]); +        LLVOVolume *volobjp = (LLVOVolume *)objectp; +        if (volobjp->isFlexible()) +        { +            if (params.getPathParams().getCurveType() == LL_PCODE_PATH_LINE) +            { +                params.getPathParams().setCurveType(LL_PCODE_PATH_FLEXIBLE); +            } +        } +        else if (params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) +        { +            params.getPathParams().setCurveType(LL_PCODE_PATH_LINE); +        } + +        objectp->updateVolume(params); +    } +} diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 8829f493fa..515dd27c0a 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -37,6 +37,7 @@ class LLCheckBoxCtrl;  class LLTextBox;  class LLUICtrl;  class LLButton; +class LLMenuButton;  class LLViewerObject;  class LLComboBox;  class LLColorSwatchCtrl; @@ -66,6 +67,14 @@ public:  	static void 	onCommitPhantom(		LLUICtrl* ctrl, void* userdata);  	static void 	onCommitPhysics(		LLUICtrl* ctrl, void* userdata); +    void            onCopyPos(); +    void            onPastePos(); +    void            onCopySize(); +    void            onPasteSize(); +    void            onCopyRot(); +    void            onPasteRot(); +    void            onCopyParams(); +    void            onPasteParams();  	static void 	onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -75,6 +84,9 @@ public:  	BOOL     		onDropSculpt(LLInventoryItem* item);  	static void     onCommitSculptType(    LLUICtrl *ctrl, void* userdata); +    void            menuDoToSelected(const LLSD& userdata); +    bool            menuEnableItem(const LLSD& userdata); +  protected:  	void			getState(); @@ -92,6 +104,7 @@ protected:  protected:  	// Per-object options  	LLComboBox*		mComboBaseType; +	LLMenuButton*	mMenuClipboardParams;  	LLTextBox*		mLabelCut;  	LLSpinCtrl*		mSpinCutBegin; @@ -131,17 +144,20 @@ protected:  	LLTextBox*		mLabelRevolutions;  	LLSpinCtrl*		mSpinRevolutions; +	LLMenuButton*   mMenuClipboardPos;  	LLTextBox*		mLabelPosition;  	LLSpinCtrl*		mCtrlPosX;  	LLSpinCtrl*		mCtrlPosY;  	LLSpinCtrl*		mCtrlPosZ; +	LLMenuButton*   mMenuClipboardSize;  	LLTextBox*		mLabelSize;  	LLSpinCtrl*		mCtrlScaleX;  	LLSpinCtrl*		mCtrlScaleY;  	LLSpinCtrl*		mCtrlScaleZ;  	BOOL			mSizeChanged; +	LLMenuButton*   mMenuClipboardRot;  	LLTextBox*		mLabelRotation;  	LLSpinCtrl*		mCtrlRotX;  	LLSpinCtrl*		mCtrlRotY; @@ -157,7 +173,7 @@ protected:  	LLComboBox      *mCtrlSculptType;  	LLCheckBoxCtrl  *mCtrlSculptMirror;  	LLCheckBoxCtrl  *mCtrlSculptInvert; -	 +  	LLVector3		mCurEulerDegrees;		// to avoid sending rotation when not changed  	BOOL			mIsPhysical;			// to avoid sending "physical" when not changed  	BOOL			mIsTemporary;			// to avoid sending "temporary" when not changed @@ -167,6 +183,15 @@ protected:  	LLUUID          mSculptTextureRevert;   // so we can revert the sculpt texture on cancel  	U8              mSculptTypeRevert;      // so we can revert the sculpt type on cancel +    LLVector3       mClipboardPos; +    LLVector3       mClipboardSize; +    LLVector3       mClipboardRot; +    LLSD            mClipboardParams; + +    bool            mHasClipboardPos; +    bool            mHasClipboardSize; +    bool            mHasClipboardRot; +  	LLPointer<LLViewerObject> mObject;  	LLPointer<LLViewerObject> mRootObject;  }; diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 05d9346f89..cd6ea97243 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -50,6 +50,7 @@  //#include "llfirstuse.h"  #include "llfocusmgr.h"  #include "llmanipscale.h" +#include "llmenubutton.h"  #include "llpreviewscript.h"  #include "llresmgr.h"  #include "llselectmgr.h" @@ -166,6 +167,9 @@ BOOL	LLPanelVolume::postBuild()  		mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution));  	} +    mMenuClipboardFeatures = getChild<LLMenuButton>("clipboard_features_params_btn"); +    mMenuClipboardLight = getChild<LLMenuButton>("clipboard_light_params_btn"); +  	std::map<std::string, std::string> material_name_map;  	material_name_map["Stone"]= LLTrans::getString("Stone");  	material_name_map["Metal"]= LLTrans::getString("Metal");	 @@ -206,6 +210,8 @@ LLPanelVolume::LLPanelVolume()  {  	setMouseOpaque(FALSE); +    mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2)); +    mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2));  } @@ -407,7 +413,6 @@ void LLPanelVolume::getState( )  			gAgentAvatarp->updateMeshVisibility();  		}  	} -	  	// Flexible properties  	BOOL is_flexible = volobjp && volobjp->isFlexible(); @@ -562,6 +567,9 @@ void LLPanelVolume::getState( )  	mObject = objectp;  	mRootObject = root_objectp; + +    mMenuClipboardFeatures->setEnabled(editable && single_volume && volobjp); // Note: physics doesn't need to be limited by single volume +    mMenuClipboardLight->setEnabled(editable && single_volume && volobjp);  }  // static @@ -829,6 +837,290 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data)  	}  } +void LLPanelVolume::onCopyFeatures() +{ +    LLViewerObject* objectp = mObject; +    if (!objectp) +    { +        return; +    } + +    LLSD clipboard; + +    LLVOVolume *volobjp = NULL; +    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) +    { +        volobjp = (LLVOVolume *)objectp; +    } + +    // Flexi Prim +    if (volobjp && volobjp->isFlexible()) +    { +        LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); +        if (attributes) +        { +            clipboard["flex"]["lod"] = attributes->getSimulateLOD(); +            clipboard["flex"]["gav"] = attributes->getGravity(); +            clipboard["flex"]["ten"] = attributes->getTension(); +            clipboard["flex"]["fri"] = attributes->getAirFriction(); +            clipboard["flex"]["sen"] = attributes->getWindSensitivity(); +            LLVector3 force = attributes->getUserForce(); +            clipboard["flex"]["forx"] = force.mV[0]; +            clipboard["flex"]["fory"] = force.mV[1]; +            clipboard["flex"]["forz"] = force.mV[2]; +        } +    } + +    // Physics +    { +        clipboard["physics"]["shape"] = objectp->getPhysicsShapeType(); +        clipboard["physics"]["gravity"] = objectp->getPhysicsGravity(); +        clipboard["physics"]["friction"] = objectp->getPhysicsFriction(); +        clipboard["physics"]["density"] = objectp->getPhysicsDensity(); +        clipboard["physics"]["restitution"] = objectp->getPhysicsRestitution(); + +        U8 material_code = 0; +        struct f : public LLSelectedTEGetFunctor<U8> +        { +            U8 get(LLViewerObject* object, S32 te) +            { +                return object->getMaterial(); +            } +        } func; +        bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, material_code); +        // This should always be true since material should be per object. +        if (material_same) +        { +            clipboard["physics"]["material"] = material_code; +        } +    } + +    mClipboardParams["features"] = clipboard; +} + +void LLPanelVolume::onPasteFeatures() +{ +    LLViewerObject* objectp = mObject; +    if (!objectp && mClipboardParams.has("features")) +    { +        return; +    } + +    LLSD &clipboard = mClipboardParams["features"]; + +    LLVOVolume *volobjp = NULL; +    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) +    { +        volobjp = (LLVOVolume *)objectp; +    } + +    // Physics +    bool is_root = objectp->isRoot(); + +    // Not sure if phantom should go under physics, but doesn't fit elsewhere +    BOOL is_phantom = clipboard["is_phantom"].asBoolean() && is_root; +    LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom); + +    BOOL is_physical = clipboard["is_physical"].asBoolean() && is_root; +    LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical); + +    if (clipboard.has("physics")) +    { +        objectp->setPhysicsShapeType((U8)clipboard["physics"]["shape"].asInteger()); +        U8 cur_material = objectp->getMaterial(); +        U8 material = (U8)clipboard["physics"]["material"].asInteger() | (cur_material & ~LL_MCODE_MASK); + +        objectp->setMaterial(material); +        objectp->sendMaterialUpdate(); +        objectp->setPhysicsGravity(clipboard["physics"]["gravity"].asReal()); +        objectp->setPhysicsFriction(clipboard["physics"]["friction"].asReal()); +        objectp->setPhysicsDensity(clipboard["physics"]["density"].asReal()); +        objectp->setPhysicsRestitution(clipboard["physics"]["restitution"].asReal()); +        objectp->updateFlags(TRUE); +    } + +    // Flexible +    bool is_flexible = clipboard.has("flex"); +    if (is_flexible && volobjp->canBeFlexible()) +    { +        LLVOVolume *volobjp = (LLVOVolume *)objectp; +        BOOL update_shape = FALSE; + +        // do before setParameterEntry or it will think that it is already flexi +        update_shape = volobjp->setIsFlexible(is_flexible); + +        if (objectp->getClickAction() == CLICK_ACTION_SIT) +        { +            objectp->setClickAction(CLICK_ACTION_NONE); +        } + +        LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); +        if (attributes) +        { +            LLFlexibleObjectData new_attributes; +            new_attributes = *attributes; +            new_attributes.setSimulateLOD(clipboard["flex"]["lod"].asInteger()); +            new_attributes.setGravity(clipboard["flex"]["gav"].asReal()); +            new_attributes.setTension(clipboard["flex"]["ten"].asReal()); +            new_attributes.setAirFriction(clipboard["flex"]["fri"].asReal()); +            new_attributes.setWindSensitivity(clipboard["flex"]["sen"].asReal()); +            F32 fx = (F32)clipboard["flex"]["forx"].asReal(); +            F32 fy = (F32)clipboard["flex"]["fory"].asReal(); +            F32 fz = (F32)clipboard["flex"]["forz"].asReal(); +            LLVector3 force(fx, fy, fz); +            new_attributes.setUserForce(force); +            objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true); +        } + +        if (update_shape) +        { +            mObject->sendShapeUpdate(); +            LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); +        } +    } +    else +    { +        LLVOVolume *volobjp = (LLVOVolume *)objectp; +        if (volobjp->setIsFlexible(false)) +        { +            mObject->sendShapeUpdate(); +            LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); +        } +    } +} + +void LLPanelVolume::onCopyLight() +{ +    LLViewerObject* objectp = mObject; +    if (!objectp) +    { +        return; +    } + +    LLSD clipboard; + +    LLVOVolume *volobjp = NULL; +    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) +    { +        volobjp = (LLVOVolume *)objectp; +    } + +    // Light Source +    if (volobjp && volobjp->getIsLight()) +    { +        clipboard["light"]["intensity"] = volobjp->getLightIntensity(); +        clipboard["light"]["radius"] = volobjp->getLightRadius(); +        clipboard["light"]["falloff"] = volobjp->getLightFalloff(); +        LLColor3 color = volobjp->getLightSRGBColor(); +        clipboard["light"]["r"] = color.mV[0]; +        clipboard["light"]["g"] = color.mV[1]; +        clipboard["light"]["b"] = color.mV[2]; + +        // Spotlight +        if (volobjp->isLightSpotlight()) +        { +            LLUUID id = volobjp->getLightTextureID(); +            if (id.notNull() && get_can_copy_texture(id)) +            { +                clipboard["spot"]["id"] = id; +                LLVector3 spot_params = volobjp->getSpotLightParams(); +                clipboard["spot"]["fov"] = spot_params.mV[0]; +                clipboard["spot"]["focus"] = spot_params.mV[1]; +                clipboard["spot"]["ambiance"] = spot_params.mV[2]; +            } +        } +    } + +    mClipboardParams["light"] = clipboard; +} + +void LLPanelVolume::onPasteLight() +{ +    LLViewerObject* objectp = mObject; +    if (!objectp && mClipboardParams.has("light")) +    { +        return; +    } + +    LLSD &clipboard = mClipboardParams["light"]; + +    LLVOVolume *volobjp = NULL; +    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) +    { +        volobjp = (LLVOVolume *)objectp; +    } + +    // Light Source +    if (volobjp) +    { +        if (clipboard.has("light")) +        { +            volobjp->setIsLight(TRUE); +            volobjp->setLightIntensity((F32)clipboard["light"]["intensity"].asReal()); +            volobjp->setLightRadius((F32)clipboard["light"]["radius"].asReal()); +            volobjp->setLightFalloff((F32)clipboard["light"]["falloff"].asReal()); +            F32 r = (F32)clipboard["light"]["r"].asReal(); +            F32 g = (F32)clipboard["light"]["g"].asReal(); +            F32 b = (F32)clipboard["light"]["b"].asReal(); +            volobjp->setLightSRGBColor(LLColor3(r, g, b)); +        } +        else +        { +            volobjp->setIsLight(FALSE); +        } + +        if (clipboard.has("spot")) +        { +            volobjp->setLightTextureID(clipboard["spot"]["id"].asUUID()); +            LLVector3 spot_params; +            spot_params.mV[0] = (F32)clipboard["spot"]["fov"].asReal(); +            spot_params.mV[1] = (F32)clipboard["spot"]["focus"].asReal(); +            spot_params.mV[2] = (F32)clipboard["spot"]["ambiance"].asReal(); +            volobjp->setSpotLightParams(spot_params); +        } +    } +} + +void LLPanelVolume::menuDoToSelected(const LLSD& userdata) +{ +    std::string command = userdata.asString(); + +    // paste +    if (command == "features_paste") +    { +        onPasteFeatures(); +    } +    else if (command == "light_paste") +    { +        onPasteLight(); +    } +    // copy +    else if (command == "features_copy") +    { +        onCopyFeatures(); +    } +    else if (command == "light_copy") +    { +        onCopyLight(); +    } +} + +bool LLPanelVolume::menuEnableItem(const LLSD& userdata) +{ +    std::string command = userdata.asString(); + +    // paste options +    if (command == "features_paste") +    { +        return mClipboardParams.has("features"); +    } +    else if (command == "light_paste") +    { +        return mClipboardParams.has("light"); +    } +    return false; +} +  // static  void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata )  { diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 66117316cf..1651108093 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -37,6 +37,7 @@ class LLCheckBoxCtrl;  class LLTextBox;  class LLUICtrl;  class LLButton; +class LLMenuButton;  class LLViewerObject;  class LLComboBox;  class LLColorSwatchCtrl; @@ -73,6 +74,13 @@ public:  	void		onLightCancelTexture(const LLSD& data);   	void		onLightSelectTexture(const LLSD& data); +    void            onCopyFeatures(); +    void            onPasteFeatures(); +    void            onCopyLight(); +    void            onPasteLight(); +  +    void        menuDoToSelected(const LLSD& userdata); +    bool        menuEnableItem(const LLSD& userdata);  protected:  	void			getState(); @@ -120,6 +128,11 @@ protected:  	LLSpinCtrl*     mSpinPhysicsFriction;  	LLSpinCtrl*     mSpinPhysicsDensity;  	LLSpinCtrl*     mSpinPhysicsRestitution; + +    LLMenuButton*   mMenuClipboardFeatures; +    LLMenuButton*   mMenuClipboardLight; + +    LLSD            mClipboardParams;  };  #endif diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 6ccb2f68e5..cd6f48b7e4 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -79,6 +79,60 @@ static const S32 LOCAL_TRACKING_ID_COLUMN = 1;  //static const char WHITE_IMAGE_NAME[] = "Blank Texture";  //static const char NO_IMAGE_NAME[] = "None"; + + +//static +bool get_is_predefined_texture(LLUUID asset_id) +{ +    if (asset_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture")) +        || asset_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID")) +        || asset_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")) +        || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) +    { +        return true; +    } +    return false; +} + +LLUUID get_copy_free_item_by_asset_id(LLUUID asset_id) +{ +    LLViewerInventoryCategory::cat_array_t cats; +    LLViewerInventoryItem::item_array_t items; +    LLAssetIDMatches asset_id_matches(asset_id); +    gInventory.collectDescendentsIf(LLUUID::null, +        cats, +        items, +        LLInventoryModel::INCLUDE_TRASH, +        asset_id_matches); +    if (items.size()) +    { +        for (S32 i = 0; i < items.size(); i++) +        { +            LLViewerInventoryItem* itemp = items[i]; +            if (itemp) +            { +                LLPermissions item_permissions = itemp->getPermissions(); +                if (item_permissions.allowOperationBy(PERM_COPY, +                    gAgent.getID(), +                    gAgent.getGroupID())) +                { +                    return itemp->getUUID(); +                } +            } +        } +    } +    return LLUUID::null; +} + +bool get_can_copy_texture(LLUUID asset_id) +{ +    // User is allowed to copy a texture if: +    // library asset or default texture, +    // or copy perm asset exists in user's inventory + +    return get_is_predefined_texture(asset_id) || get_copy_free_item_by_asset_id(asset_id).notNull(); +} +  LLFloaterTexturePicker::LLFloaterTexturePicker(	  	LLView* owner,  	LLUUID image_asset_id, diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 92f6f89af6..4250cf86b8 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -52,6 +52,16 @@ class LLViewerFetchedTexture;  typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback;  typedef boost::function<void (LLInventoryItem*)> texture_selected_callback; +// Helper functions for UI that work with picker +bool get_is_predefined_texture(LLUUID asset_id); + +// texture picker works by asset ids since objects normaly do +// not retain inventory ids as result these functions are looking +// for textures in inventory by asset ids +// This search can be performance unfriendly and doesn't warranty +// that the texture is original source of asset +LLUUID get_copy_free_item_by_asset_id(LLUUID image_id); +bool get_can_copy_texture(LLUUID image_id);  //////////////////////////////////////////////////////////////////////////////////////////  // LLTextureCtrl diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.pngBinary files differ new file mode 100644 index 0000000000..9a81c5f94b --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.pngBinary files differ new file mode 100644 index 0000000000..88012cf8d1 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.pngBinary files differ new file mode 100644 index 0000000000..ab02e7d42d --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.pngBinary files differ new file mode 100644 index 0000000000..63b4bd2127 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.pngBinary files differ new file mode 100644 index 0000000000..4200182b0c --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.pngBinary files differ new file mode 100644 index 0000000000..e12887f489 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index a875c4e848..eb725a5cab 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -438,6 +438,13 @@ with the same filename but different name    <texture name="OptionsMenu_Off" file_name="icons/OptionsMenu_Off.png" preload="false" />    <texture name="OptionsMenu_Press" file_name="icons/OptionsMenu_Press.png" preload="false" /> +  <texture name="ClipboardSmallMenu_Disabled" file_name="icons/ClipboardSmallMenu_Disabled.png" preload="false" /> +  <texture name="ClipboardSmallMenu_Off" file_name="icons/ClipboardSmallMenu_Off.png" preload="false" /> +  <texture name="ClipboardSmallMenu_Press" file_name="icons/ClipboardSmallMenu_Press.png" preload="false" /> +  <texture name="ClipboardMenu_Disabled" file_name="icons/ClipboardMenu_Disabled.png" preload="false" /> +  <texture name="ClipboardMenu_Off" file_name="icons/ClipboardMenu_Off.png" preload="false" /> +  <texture name="ClipboardMenu_Press" file_name="icons/ClipboardMenu_Press.png" preload="false" /> +    <texture name="OutboxStatus_Success" file_name="green_checkmark.png" preload="false" />    <texture name="OutboxStatus_Warning" file_name="icons/pop_up_caution.png" preload="false" />    <texture name="OutboxStatus_Error" file_name="red_x.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 0abee2ff80..f5214420b4 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2,7 +2,7 @@  <floater   positioning="cascading"   legacy_header_height="18" - height="600" + height="609"   layout="topleft"   bg_opaque_image="Window_NoTitle_Foreground"   bg_alpha_image="Window_NoTitle_Background" @@ -68,7 +68,7 @@      </floater.string>      <floater.string       name="status_selectcount"> -        [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] +        [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] [secondlife:///app/openfloater/object_weights More info]      </floater.string>      <floater.string       name="status_remaining_capacity"> @@ -763,11 +763,12 @@  	  font="SansSerifSmall"  	  layout="topleft"  	  left="10" -	  name="selection_count" +	  name="selection_faces"  	  top_delta="0"  	  visible="false"  	  width="280"> -	</text> +    Faces selected: [FACES_STRING] +  </text>  	<text  	 text_color="LtGray_50"  	  type="string" @@ -777,11 +778,10 @@  	  font="SansSerifSmall"  	  layout="topleft"  	  left="10" -	  name="remaining_capacity" +	  name="selection_count"  	  top_pad="0"  	  visible="false"  	  width="280"> -	  [CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info]  	</text>      <!-- <text -->      <!-- text_color="LtGray_50" --> @@ -820,7 +820,7 @@      width="282"/>      <tab_container       follows="left|top" -     height="410" +     height="426"       halign="center"       left="0"       name="Object Info Tabs" @@ -1430,16 +1430,40 @@ even though the user gets a free copy.               tool_tip="Causes object to not collide with other objects or avatars"               top_pad="0"               width="123" /> -        <text +            <view_border +             bevel_style="none" +             follows="top|left" +             height="0" +             layout="topleft" +             left_delta="0" +             name="object_horizontal" +             top_pad="10" +             width="95" /> +            <menu_button +             menu_filename="menu_copy_paste_pos.xml" +             follows="top|left" +             height="11" +             image_disabled="ClipboardSmallMenu_Disabled" +             image_selected="ClipboardSmallMenu_Press" +             image_unselected="ClipboardSmallMenu_Off" +             layout="topleft" +             left_delta="0" +             top_pad="13" +             name="clipboard_pos_btn" +             tool_tip="Paste options" +             width="19"/> +            <text               type="string"               length="1"               follows="left|top"               height="10"               layout="topleft"               name="label position" -             top_pad="10" +             tool_tip="Position (meters)" +             left_pad="8" +             top_delta="0"               width="121"> -                Position (meters) +                Position (m)              </text>              <spinner               follows="left|top" @@ -1449,12 +1473,12 @@ even though the user gets a free copy.               label="X"               label_width="10"               layout="topleft" -             left_delta="0" +             left_delta="-27"               max_val="512"               min_val="-256"               name="Pos X"               text_enabled_color="1 0 0.3 .7" -             top_pad="5" +             top_pad="8"               width="87" />              <spinner               follows="left|top" @@ -1485,17 +1509,31 @@ even though the user gets a free copy.               text_enabled_color="0 0.8 1 .65"               top_pad="3"               width="87" /> +            <menu_button +             menu_filename="menu_copy_paste_size.xml" +             follows="top|left" +             height="11" +             image_disabled="ClipboardSmallMenu_Disabled" +             image_selected="ClipboardSmallMenu_Press" +             image_unselected="ClipboardSmallMenu_Off" +             layout="topleft" +             left_delta="0" +             top_pad="13" +             name="clipboard_size_btn" +             tool_tip="Paste options" +             width="19"/>              <text               type="string"               length="1"               follows="left|top"               height="10"               layout="topleft" -             left_delta="0" +             left_pad="8" +             top_delta="0"               name="label size" -             top_pad="6" +             tool_tip="Size (meters)"               width="121"> -                Size (meters) +                Size (m)              </text>              <spinner               follows="left|top" @@ -1505,12 +1543,12 @@ even though the user gets a free copy.               label="X"               label_width="10"               layout="topleft" -             left_delta="0" +             left_delta="-27"               max_val="64"               min_val="0.01"               name="Scale X"               text_enabled_color="1 1 1 1" -             top_pad="5" +             top_pad="8"               width="87" />              <spinner               follows="left|top" @@ -1542,17 +1580,31 @@ even though the user gets a free copy.               text_enabled_color="1 1 1 1"               top_pad="3"               width="87" /> +            <menu_button +             menu_filename="menu_copy_paste_rot.xml" +             follows="top|left" +             height="11" +             image_disabled="ClipboardSmallMenu_Disabled" +             image_selected="ClipboardSmallMenu_Press" +             image_unselected="ClipboardSmallMenu_Off" +             layout="topleft" +             left_delta="0" +             top_pad="13" +             name="clipboard_rot_btn" +             tool_tip="Paste options" +             width="19"/>              <text               type="string"               length="1"               follows="left|top"               height="10"               layout="topleft" -             left_delta="0" +             left_pad="8" +             top_delta="0"               name="label rotation" -             top_pad="10" +             tool_tip="Rotation (degrees)"               width="121"> -                Rotation (degrees) +                Rotation (°)              </text>              <spinner               decimal_digits="2" @@ -1563,12 +1615,12 @@ even though the user gets a free copy.               label="X"               label_width="10"               layout="topleft" -             left_delta="0" +             left_delta="-27"               max_val="9999"               min_val="-9999"               name="Rot X"               text_enabled_color="1 1 1 1" -             top_pad="5" +             top_pad="8"               width="87" />              <spinner               decimal_digits="2" @@ -1614,13 +1666,23 @@ even though the user gets a free copy.               width="150">                  Prim Type              </text>--> + +            <view_border +             bevel_style="none" +             follows="top|left" +             layout="topleft" +             name="object_vertical" +             left="117" +             top="6" +             height="500" +             width="0"/>              <combo_box               height="19"               layout="topleft"               name="comboBaseType"               top="6"               left="125" -             width="150"> +             width="125">                  <combo_box.item                   label="Box"                   name="Box" @@ -1654,13 +1716,26 @@ even though the user gets a free copy.                   name="Sculpted"                   value="Sculpted" />              </combo_box> +            <menu_button +              menu_filename="menu_copy_paste_object.xml" +              follows="top|left" +              height="15" +              image_disabled="ClipboardMenu_Disabled" +              image_selected="ClipboardMenu_Press" +              image_unselected="ClipboardMenu_Off" +              layout="topleft" +              left_pad="8" +              top_delta="2" +              name="clipboard_obj_params_btn" +              tool_tip="Paste options" +              width="22"/>              <text               type="string"               length="1"               follows="left|top"               height="10"               layout="topleft" -             left_delta="0" +             left="125"               name="text cut"               top_pad="5"               width="150"> @@ -1700,7 +1775,7 @@ even though the user gets a free copy.               layout="topleft"               left="125"               name="text hollow" -             top_pad="6" +             top_pad="7"               width="68">                  Hollow              </text> @@ -1748,7 +1823,7 @@ even though the user gets a free copy.               layout="topleft"               left="125"               name="Hollow Shape" -             top_pad="4" +             top_pad="7"               width="150">                  Hollow Shape              </text> @@ -1784,7 +1859,7 @@ even though the user gets a free copy.               layout="topleft"               left_delta="0"               name="text twist" -             top_pad="5" +             top_pad="7"               width="150">                  Twist (begin/end)              </text> @@ -1826,12 +1901,12 @@ even though the user gets a free copy.               layout="topleft"               left="125"               name="scale_taper" -             top_pad="3" +             top_pad="7"               width="150">                  Taper              </text>              <text -			 visible="false" +             visible="false"               type="string"               length="1"               follows="left|top" @@ -1879,7 +1954,7 @@ even though the user gets a free copy.               layout="topleft"               left="125"               name="text topshear" -             top_pad="3" +             top_pad="5"               width="141">                  Top Shear              </text> @@ -1922,12 +1997,12 @@ even though the user gets a free copy.               layout="topleft"               left="125"               name="advanced_cut" -             top_pad="3" +             top_pad="7"               width="150">                  Profile Cut (begin/end)              </text>              <text -			 visible="false" +             visible="false"               type="string"               length="1"               follows="left|top" @@ -1986,7 +2061,7 @@ even though the user gets a free copy.               layout="topleft"               left="125"               name="text taper2" -             top_pad="3" +             top_pad="7"               width="150">                  Taper              </text> @@ -2029,7 +2104,7 @@ even though the user gets a free copy.               layout="topleft"               left="125"               name="text radius delta" -             top_pad="2" +             top_pad="7"               width="78">                  Radius              </text> @@ -2157,6 +2232,19 @@ even though the user gets a free copy.  	<panel.string name="None">None</panel.string>  	<panel.string name="Prim">Prim</panel.string>  	<panel.string name="Convex Hull">Convex Hull</panel.string> +            <menu_button +              menu_filename="menu_copy_paste_features.xml" +              follows="top|left" +              height="15" +              image_disabled="ClipboardMenu_Disabled" +              image_selected="ClipboardMenu_Press" +              image_unselected="ClipboardMenu_Off" +              layout="topleft" +              left="258" +              top="8" +              name="clipboard_features_params_btn" +              tool_tip="Paste options" +              width="22"/>              <text               type="string"               length="1" @@ -2309,6 +2397,15 @@ even though the user gets a free copy.               name="FlexForceZ"               top_pad="4"               width="128" /> +            <view_border +             bevel_style="none" +             follows="top|left" +             height="0" +             layout="topleft" +             left="8" +             name="object_horizontal" +             top_pad="10" +             width="278" />              <check_box               height="16" @@ -2317,7 +2414,7 @@ even though the user gets a free copy.               left="10"               name="Light Checkbox Ctrl"               tool_tip="Causes object to emit light" -             top_pad="15" +             top_pad="8"               width="60" />              <color_swatch               can_apply_immediately="true" @@ -2344,6 +2441,19 @@ even though the user gets a free copy.              name="light texture control"              tool_tip="Click to choose a projection image (only has effect with deferred rendering enabled)"              width="32" /> +         <menu_button +              menu_filename="menu_copy_paste_light.xml" +              follows="top|left" +              height="15" +              image_disabled="ClipboardMenu_Disabled" +              image_selected="ClipboardMenu_Press" +              image_unselected="ClipboardMenu_Off" +              layout="topleft" +              left="258" +              top_delta="0" +              name="clipboard_light_params_btn" +              tool_tip="Paste options" +              width="22"/>            <spinner               follows="left|top"               height="19" @@ -2353,7 +2463,7 @@ even though the user gets a free copy.               layout="topleft"               left="10"               name="Light Intensity" -             top_pad="3" +             top_pad="26"               width="128" />            <spinner bottom_delta="0"                     decimal_digits="3" @@ -2575,7 +2685,7 @@ even though the user gets a free copy.               border_visible="true"               bevel_style="in"               follows="left|top|right" -             height="325" +             height="335"               layout="topleft"               left="10"               name="contents_inventory" diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml new file mode 100644 index 0000000000..4c12180daf --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Color Menu"> +    <menu_item_call +     label="Copy" +     layout="topleft" +     name="params_copy" +     visible="true"> +       <on_click function="PanelFace.menuDoToSelected" parameter="color_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste" +     layout="topleft" +     name="params_paste" +     visible="true"> +       <on_click function="PanelFace.menuDoToSelected" parameter="color_paste" /> +       <on_enable function="PanelFace.menuEnable" parameter="color_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml new file mode 100644 index 0000000000..4823d74a26 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Features Menu"> +    <menu_item_call +     label="Copy" +     layout="topleft" +     name="params_copy" +     visible="true"> +       <on_click function="PanelVolume.menuDoToSelected" parameter="features_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste" +     layout="topleft" +     name="params_paste" +     visible="true"> +       <on_click function="PanelVolume.menuDoToSelected" parameter="features_paste" /> +       <on_enable function="PanelVolume.menuEnable" parameter="features_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml new file mode 100644 index 0000000000..5de23dfee3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Light Menu"> +    <menu_item_call +     label="Copy" +     layout="topleft" +     name="params_copy" +     visible="true"> +       <on_click function="PanelVolume.menuDoToSelected" parameter="light_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste" +     layout="topleft" +     name="params_paste" +     visible="true"> +       <on_click function="PanelVolume.menuDoToSelected" parameter="light_paste" /> +       <on_enable function="PanelVolume.menuEnable" parameter="light_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml new file mode 100644 index 0000000000..bdc4537a9d --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Object Menu"> +    <menu_item_call +     label="Copy" +     layout="topleft" +     name="params_copy" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="params_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste" +     layout="topleft" +     name="params_paste" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="params_paste" /> +       <on_enable function="PanelObject.menuEnable" parameter="params_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml new file mode 100644 index 0000000000..3ea95b281f --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Position Menu"> +    <menu_item_call +     label="Copy all" +     layout="topleft" +     name="psr_copy" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" /> +       <on_enable function="PanelObject.menuEnable" parameter="psr_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Copy position" +     layout="topleft" +     name="pos_copy" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="pos_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste all" +     layout="topleft" +     name="psr_paste" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" /> +       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" /> +    </menu_item_call> +    <menu_item_call +     label="Paste position" +     layout="topleft" +     name="pos_paste" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="pos_paste" /> +       <on_enable function="PanelObject.menuEnable" parameter="pos_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml new file mode 100644 index 0000000000..06ce80f897 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Rotation Menu"> +    <menu_item_call +     label="Copy all" +     layout="topleft" +     name="psr_copy" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" /> +       <on_enable function="PanelObject.menuEnable" parameter="rot_paste" /> +    </menu_item_call> +    <menu_item_call +     label="Copy rotation" +     layout="topleft" +     name="rot_copy" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="rot_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste all" +     layout="topleft" +     name="psr_paste" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" /> +       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" /> +    </menu_item_call> +    <menu_item_call +     label="Paste rotation" +     layout="topleft" +     name="rot_paste" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="rot_paste" /> +       <on_enable function="PanelObject.menuEnable" parameter="rot_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml new file mode 100644 index 0000000000..7082a0e65b --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Size Menu"> +    <menu_item_call +     label="Copy all" +     layout="topleft" +     name="psr_copy" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" /> +       <on_enable function="PanelObject.menuEnable" parameter="psr_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Copy size" +     layout="topleft" +     name="size_copy" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="size_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste all" +     layout="topleft" +     name="psr_paste" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" /> +       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" /> +    </menu_item_call> +    <menu_item_call +     label="Paste size" +     layout="topleft" +     name="size_paste" +     visible="true"> +       <on_click function="PanelObject.menuDoToSelected" parameter="size_paste" /> +       <on_enable function="PanelObject.menuEnable" parameter="size_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml new file mode 100644 index 0000000000..f358affc23 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Texture Menu"> +    <menu_item_call +     label="Copy" +     layout="topleft" +     name="params_copy" +     visible="true"> +       <on_click function="PanelFace.menuDoToSelected" parameter="texture_copy" /> +    </menu_item_call> +    <menu_item_call +     label="Paste" +     layout="topleft" +     name="params_paste" +     visible="true"> +       <on_click function="PanelFace.menuDoToSelected" parameter="texture_paste" /> +       <on_enable function="PanelFace.menuEnable" parameter="texture_paste" /> +    </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 2f4da4f9b7..6c7692848a 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8974,6 +8974,29 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran    <notification     icon="alertmodal.tga" +   name="FacePasteFailed" +   type="alertmodal"> +Paste failed. [REASON] +   <usetemplate +    name="okbutton" +    yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="FacePasteTexturePermissions" +   type="alertmodal"> +    You applied a texture with limited permissions, object will inherit permissions from texture. +    <usetemplate +     ignoretext="Paste: You applied a texture with limited permissions" +     name="notifyignore"/> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga"     name="ConfirmLeaveCall"     type="alertmodal">  Are you sure you want to leave this call? diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 90f32ae452..a33d425964 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -11,6 +11,32 @@           name="Texture"           top="0"           width="295"> +            <panel.string +             name="paste_error_face_selection_mismatch"> +              When multiple faces are copied, the target object must have the same number of faces selected. +            </panel.string> +            <panel.string +             name="paste_error_object_face_count_mismatch"> +              When all faces of an object are copied, the target object must have the same number of faces. +            </panel.string> +            <panel.string +             name="paste_error_inventory_not_found"> +              One or more texture not found in inventory. +            </panel.string> + +            <menu_button +             menu_filename="menu_copy_paste_color.xml" +             follows="top|left" +             height="15" +             image_disabled="ClipboardMenu_Disabled" +             image_selected="ClipboardMenu_Press" +             image_unselected="ClipboardMenu_Off" +             layout="topleft" +             left="258" +             top="8" +             name="clipboard_color_params_btn" +             tool_tip="Paste options" +             width="22"/>              <text               type="string"               length="1" @@ -36,7 +62,7 @@               name="colorswatch"               tool_tip="Click to open color picker"               top="20" -             width="64" /> +             width="54" />              <text               type="string"               length="1" @@ -84,7 +110,7 @@               left_delta="0"               name="glow"               top_pad="4" -             width="80" /> +             width="77" />              <check_box               height="19"               label="Full Bright" @@ -93,13 +119,22 @@               name="checkbox fullbright"               top_pad="4"               width="81" /> +            <view_border +             bevel_style="none" +             follows="top|left" +             height="0" +             layout="topleft" +             left="8" +             name="object_horizontal" +             top_pad="4" +             width="278" />              <combo_box               height="23"               layout="topleft"               left="10"               name="combobox matmedia" -             top_pad="5" -             width="100"> +             top_pad="17" +             width="90">                  <combo_box.item                   label="Materials"                   name="Materials" @@ -113,7 +148,7 @@              control_name="ComboMaterialType"              height="50"              layout="topleft" -            left_pad="20" +            left_pad="5"              top_delta="-10"              width="150"              visible = "false" @@ -139,7 +174,20 @@                  layout="topleft"                  top_pad="1"                  value="2"/> -            </radio_group>  +            </radio_group> +            <menu_button +                menu_filename="menu_copy_paste_texture.xml" +                follows="top|left" +                height="15" +                image_disabled="ClipboardMenu_Disabled" +                image_selected="ClipboardMenu_Press" +                image_unselected="ClipboardMenu_Off" +                layout="topleft" +                left="258" +                top_delta="0" +                name="clipboard_texture_params_btn" +                tool_tip="Paste options" +                width="22"/>              <check_box               control_name="SyncMaterialSettings"               follows="top|left" @@ -150,7 +198,7 @@               left="8"               name="checkbox_sync_settings"               tool_tip="Adjust all maps repeats simultaneously" -             top_pad="-16" +             top_pad="19"               width="160" />              <texture_picker               can_apply_immediately="true" @@ -771,14 +819,14 @@               top_delta="16"               width="260" />  			<button -			 left="10" -			 top="222" +       follows="left|top" +       layout="topleft" +			 left="9" +			 top="204"  			 height="20"  			 label="Align"  			 label_selected="Align current texture layers" -			 layout="topleft"  			 name="button align textures" -			 top_delta="0"  			 tool_tip="Align current texture layers"  			 width="66" />              <web_browser | 
