summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/lllocalbitmaps.h2
-rw-r--r--indra/newview/llpanelface.cpp662
-rw-r--r--indra/newview/llpanelface.h29
-rw-r--r--indra/newview/llpanelobject.cpp558
-rw-r--r--indra/newview/llpanelobject.h50
-rw-r--r--indra/newview/skins/default/textures/icons/Paste.pngbin0 -> 530 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml176
-rw-r--r--indra/newview/skins/default/xui/en/menu_build_paste.xml38
-rw-r--r--indra/newview/skins/default/xui/en/menu_texture_paste.xml70
-rw-r--r--indra/newview/skins/default/xui/en/panel_tools_texture.xml63
11 files changed, 1606 insertions, 43 deletions
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 5742b5ad1a..13d0e377d7 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -38,6 +38,7 @@
#include "llfontgl.h"
// project includes
+#include "llagent.h" // gAgent
#include "llagentdata.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
@@ -45,10 +46,15 @@
#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 "llpanelobject.h" // LLPanelObject::canCopyTexture
#include "llradiogroup.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@@ -57,6 +63,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 +306,18 @@ BOOL LLPanelFace::postBuild()
{
mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this);
}
-
+
+ mBtnCopyFaces = getChild<LLButton>("copy_face_btn");
+ if(mBtnCopyFaces)
+ {
+ mBtnCopyFaces->setCommitCallback(boost::bind(&LLPanelFace::onCopyFaces, this));
+ }
+ mBtnPasteFaces = getChild<LLButton>("paste_face_btn");
+ if (mBtnPasteFaces)
+ {
+ mBtnPasteFaces->setCommitCallback(boost::bind(&LLPanelFace::onPasteFaces, this));
+ }
+ mBtnPasteMenu = getChild<LLMenuButton>("paste_face_gear_btn");
clearCtrls();
@@ -307,9 +326,22 @@ BOOL LLPanelFace::postBuild()
LLPanelFace::LLPanelFace()
: LLPanel(),
- mIsAlpha(false)
+ mIsAlpha(false),
+ mPasteColor(TRUE),
+ mPasteAlpha(TRUE),
+ mPasteGlow(TRUE),
+ mPasteDiffuse(TRUE),
+ mPasteNormal(TRUE),
+ mPasteSpecular(TRUE),
+ mPasteMapping(TRUE),
+ mPasteMedia(TRUE),
+ mPopulateAllTEs(TRUE)
{
USE_TEXTURE = LLTrans::getString("use_texture");
+
+ mEnableCallbackRegistrar.add("BuildFace.PasteCheckItem", boost::bind(&LLPanelFace::pasteCheckMenuItem, this, _2));
+ mCommitCallbackRegistrar.add("BuildFace.PasteDoToSelected", boost::bind(&LLPanelFace::pasteDoMenuItem, this, _2));
+ mEnableCallbackRegistrar.add("BuildFace.PasteEnable", boost::bind(&LLPanelFace::pasteEnabletMenuItem, this, _2));
}
@@ -1535,6 +1567,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
}
}
+ S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+ BOOL single_volume = (selected_count == 1);
+ mBtnCopyFaces->setEnabled(editable && single_volume);
+ mBtnPasteFaces->setEnabled(editable && (mClipboard.size() > 0));
+ mBtnPasteMenu->setEnabled(editable);
+
// Set variable values for numeric expressions
LLCalc* calcp = LLCalc::getInstance();
calcp->setVar(LLCalc::TEX_U_SCALE, childGetValue("TexScaleU").asReal());
@@ -1735,8 +1773,6 @@ void LLPanelFace::updateVisibility()
getChildView("bumpyRot")->setVisible(show_bumpiness);
getChildView("bumpyOffsetU")->setVisible(show_bumpiness);
getChildView("bumpyOffsetV")->setVisible(show_bumpiness);
-
-
}
// static
@@ -2850,3 +2886,621 @@ void LLPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identic
} max_diff_repeats_func;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats );
}
+
+static LLSD texture_clipboard;
+
+void LLPanelFace::onCopyFaces()
+{
+ 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;
+ }
+
+ mClipboard.clear();
+ std::map<LLUUID, LLUUID> asset_item_map;
+
+ S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+ mPopulateAllTEs = (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"]["glow"] = tep->getGlow();
+ 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 full_perm = LLPanelObject::isLibraryTexture(id) || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify());
+
+ 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 = LLPanelObject::getCopyPermInventoryTextureId(id);
+ // record value to avoid repeating inventory search when possible
+ asset_item_map[id] = item_id;
+ }
+ }
+
+ if (id.isNull()
+ || (!full_perm && item_id.isNull()))
+ {
+ if (!LLLocalBitmapMgr::getInstance()->isLocal(id))
+ {
+ te_data["te"].erase("imageid");
+ te_data["te"]["imageid"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
+ }
+ te_data["te"]["itemfullperm"] = true;
+ }
+ else
+ {
+ te_data["te"]["itemfullperm"] = full_perm;
+ // 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 && 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() && !LLPanelObject::canCopyTexture(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() && !LLPanelObject::canCopyTexture(id))
+ {
+ mat_data["SpecMap"] = LLUUID(gSavedSettings.getString( "DefaultObjectTexture" ));
+ mat_data["SpecMapNoCopy"] = true;
+ }
+
+ }
+
+ te_data["material"] = mat_data;
+ }
+
+ mClipboard.append(te_data);
+ }
+ }
+ }
+}
+
+void LLPanelFace::pasteFace(LLViewerObject* objectp, S32 te)
+{
+ LLSD te_data;
+ if ((mClipboard.size() == 1) && mPopulateAllTEs)
+ {
+ te_data = *(mClipboard.beginArray());
+ }
+ else if (mClipboard[te])
+ {
+ te_data = mClipboard[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();
+ if (mPasteDiffuse && 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;
+ }
+ }
+ }
+
+ // for case when item got removed from inventory after we pressed 'copy'
+ if (!itemp_res && !full_perm)
+ {
+ // todo: fix this, we are often searching same tuxter multiple times (equal to number of faces)
+ 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,
+ LLToolDragAndDrop::SOURCE_AGENT,
+ LLUUID::null);
+ }
+ else // one face
+ {
+ LLToolDragAndDrop::dropTextureOneFace(objectp,
+ te,
+ itemp_res,
+ 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);
+ }
+ }
+
+ // Color / Alpha
+ if ((mPasteColor || mPasteAlpha) && te_data["te"].has("colors"))
+ {
+ LLColor4 color = tep->getColor();
+
+ LLColor4 clip_color;
+ clip_color.setValue(te_data["te"]["colors"]);
+
+ // Color
+ if (mPasteColor)
+ {
+ color.mV[VRED] = clip_color.mV[VRED];
+ color.mV[VGREEN] = clip_color.mV[VGREEN];
+ color.mV[VBLUE] = clip_color.mV[VBLUE];
+ }
+
+ // Alpha
+ if (mPasteAlpha)
+ {
+ color.mV[VALPHA] = clip_color.mV[VALPHA];
+ }
+
+ objectp->setTEColor(te, color);
+ }
+
+ if (mPasteColor && te_data["te"].has("fullbright"))
+ {
+ objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger());
+ }
+
+
+ // Glow
+ if (mPasteGlow && te_data["te"].has("glow"))
+ {
+ objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal());
+ }
+
+ if (mPasteNormal && te_data["te"].has("bumpmap"))
+ {
+ objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger());
+ }
+ if (mPasteSpecular && te_data["te"].has("bumpshiny"))
+ {
+ objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger());
+ }
+ if (mPasteSpecular && te_data["te"].has("bumpfullbright"))
+ {
+ objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger());
+ }
+
+ // Texture map
+ if (mPasteMapping)
+ {
+ 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 (mPasteMedia && 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);
+
+ if (mPasteNormal)
+ {
+ // 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);
+ }
+
+ if (mPasteSpecular)
+ {
+ // 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());
+ }
+ }
+ }
+ }
+}
+
+struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor
+{
+ LLPanelFacePasteTexFunctor(LLPanelFace* panel) :
+ mPanelFace(panel){}
+
+ virtual bool apply(LLViewerObject* objectp, S32 te)
+ {
+ mPanelFace->pasteFace(objectp, te);
+ return true;
+ }
+private:
+ LLPanelFace *mPanelFace;
+};
+
+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::onPasteFaces()
+{
+ LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+
+ LLPanelFacePasteTexFunctor paste_func(this);
+ selected_objects->applyToTEs(&paste_func);
+
+ LLPanelFaceUpdateFunctor sendfunc(mPasteMedia);
+ selected_objects->applyToObjects(&sendfunc);
+
+ if (mPasteMedia)
+ {
+ LLPanelFaceNavigateHomeFunctor navigate_home_func;
+ selected_objects->applyToTEs(&navigate_home_func);
+ }
+}
+
+bool LLPanelFace::pasteCheckMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+
+ if ("Color" == command)
+ {
+ return mPasteColor;
+ }
+ if ("Transparency" == command)
+ {
+ return mPasteAlpha;
+ }
+ if ("Glow" == command)
+ {
+ return mPasteGlow;
+ }
+ if ("Diffuse" == command)
+ {
+ return mPasteDiffuse;
+ }
+ if ("Normal" == command)
+ {
+ return mPasteNormal;
+ }
+ if ("Specular" == command)
+ {
+ return mPasteSpecular;
+ }
+ if ("Mapping" == command)
+ {
+ return mPasteMapping;
+ }
+ if ("Media" == command)
+ {
+ return mPasteMedia;
+ }
+
+ return false;
+}
+
+void LLPanelFace::pasteDoMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+
+ if ("Color" == command)
+ {
+ mPasteColor = !mPasteColor;
+ }
+ if ("Transparency" == command)
+ {
+ mPasteAlpha = !mPasteAlpha;
+ }
+ if ("Glow" == command)
+ {
+ mPasteGlow = !mPasteGlow;
+ }
+ if ("Diffuse" == command)
+ {
+ mPasteDiffuse = !mPasteDiffuse;
+ }
+ if ("Normal" == command)
+ {
+ mPasteNormal = !mPasteNormal;
+ }
+ if ("Specular" == command)
+ {
+ mPasteSpecular = !mPasteSpecular;
+ }
+ if ("Mapping" == command)
+ {
+ mPasteMapping = !mPasteMapping;
+ }
+ if ("Media" == command)
+ {
+ mPasteMedia = !mPasteMedia;
+ }
+}
+
+bool LLPanelFace::pasteEnabletMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+
+ // Keep at least one option enabled
+ S32 num_enabled = mPasteColor
+ + mPasteAlpha
+ + mPasteGlow
+ + mPasteDiffuse
+ + mPasteNormal
+ + mPasteSpecular
+ + mPasteMapping
+ + mPasteMedia;
+ if ( num_enabled == 1)
+ {
+ if ("Color" == command && mPasteColor)
+ {
+ return false;
+ }
+ if ("Transparency" == command && mPasteAlpha)
+ {
+ return false;
+ }
+ if ("Glow" == command && mPasteGlow)
+ {
+ return false;
+ }
+ if ("Diffuse" == command && mPasteDiffuse)
+ {
+ return false;
+ }
+ if ("Normal" == command && mPasteNormal)
+ {
+ return false;
+ }
+ if ("Specular" == command && mPasteSpecular)
+ {
+ return false;
+ }
+ if ("Mapping" == command && mPasteMapping)
+ {
+ return false;
+ }
+ if ("Media" == command && mPasteMedia)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 2d57d89a44..770f10e2ee 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.
//
@@ -113,6 +114,8 @@ public:
LLRender::eTexIndex getTextureChannelToEdit();
+ void pasteFace(LLViewerObject* object, S32 te);
+
protected:
void getState();
@@ -205,9 +208,13 @@ protected:
static void onClickAutoFix(void*);
static void onAlignTexture(void*);
- static F32 valueGlow(LLViewerObject* object, S32 face);
+ void onCopyFaces();
+ void onPasteFaces();
+ bool pasteCheckMenuItem(const LLSD& userdata);
+ void pasteDoMenuItem(const LLSD& userdata);
+ bool pasteEnabletMenuItem(const LLSD& userdata);
-
+ static F32 valueGlow(LLViewerObject* object, S32 face);
private:
@@ -234,6 +241,22 @@ private:
F32 getCurrentShinyOffsetU();
F32 getCurrentShinyOffsetV();
+ LLButton *mBtnCopyFaces;
+ LLButton *mBtnPasteFaces;
+ LLMenuButton *mBtnPasteMenu;
+
+ LLSD mClipboard;
+ BOOL mPasteColor;
+ BOOL mPasteAlpha;
+ BOOL mPasteGlow;
+ BOOL mPasteDiffuse;
+ BOOL mPasteNormal;
+ BOOL mPasteSpecular;
+ BOOL mPasteMapping;
+ BOOL mPasteMedia;
+
+ BOOL mPopulateAllTEs;
+
// Update visibility of controls to match current UI mode
// (e.g. materials vs media editing)
//
@@ -497,6 +520,8 @@ public:
DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor);
+
+ DEF_EDIT_MAT_STATE(LLSD, const LLSD&, fromLLSD);
};
class LLSelectedTE
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 6bff95ab36..ac0122237f 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -32,6 +32,7 @@
// linden library includes
#include "llerror.h"
#include "llfontgl.h"
+#include "material_codes.h" // LL_MCODE_MASK
#include "llpermissionsflags.h"
#include "llstring.h"
#include "llvolume.h"
@@ -45,7 +46,10 @@
#include "llcolorswatch.h"
#include "llcombobox.h"
#include "llfocusmgr.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
#include "llmanipscale.h"
+#include "llmenubutton.h"
#include "llpreviewscript.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@@ -149,6 +153,31 @@ BOOL LLPanelObject::postBuild()
mCtrlRotZ = getChild<LLSpinCtrl>("Rot Z");
childSetCommitCallback("Rot Z",onCommitRotation,this);
+ // Copy/paste pos
+ mBtnCopyPos = getChild<LLButton>("copy_pos_btn");
+ mBtnCopyPos->setCommitCallback(boost::bind(&LLPanelObject::onCopyPos, this));
+ mBtnPastePos = getChild<LLButton>("paste_pos_btn");
+ mBtnPastePos->setCommitCallback(boost::bind(&LLPanelObject::onPastePos, this));
+
+ // Copy/paste size
+ mBtnCopySize = getChild<LLButton>("copy_size_btn");
+ mBtnCopySize->setCommitCallback(boost::bind(&LLPanelObject::onCopySize, this));
+ mBtnPasteSize = getChild<LLButton>("paste_size_btn");
+ mBtnPasteSize->setCommitCallback(boost::bind(&LLPanelObject::onPasteSize, this));
+
+ // Copy/paste rot
+ mBtnCopyRot = getChild<LLButton>("copy_rot_btn");
+ mBtnCopyRot->setCommitCallback(boost::bind(&LLPanelObject::onCopyRot, this));
+ mBtnPasteRot = getChild<LLButton>("paste_rot_btn");
+ mBtnPasteRot->setCommitCallback(boost::bind(&LLPanelObject::onPasteRot, this));;
+
+ // Copy/paste obj prams
+ mBtnCopyParams = getChild<LLButton>("copy_params_btn");
+ mBtnCopyParams->setCommitCallback(boost::bind(&LLPanelObject::onCopyParams, this));
+ mBtnPasteParams = getChild<LLButton>("paste_params_btn");
+ mBtnPasteParams->setCommitCallback(boost::bind(&LLPanelObject::onPasteParams, this));
+ mBtnPasteMenu = getChild<LLMenuButton>("paste_gear_btn");
+
//--------------------------------------------------------
// Base Type
@@ -285,8 +314,19 @@ LLPanelObject::LLPanelObject()
mSelectedType(MI_BOX),
mSculptTextureRevert(LLUUID::null),
mSculptTypeRevert(0),
- mSizeChanged(FALSE)
+ mSizeChanged(FALSE),
+ mHasParamsClipboard(FALSE),
+ mHasPosClipboard(FALSE),
+ mHasSizeClipboard(FALSE),
+ mHasRotClipboard(FALSE),
+ mPasteParametric(TRUE),
+ mPasteFlexible(TRUE),
+ mPastePhysics(TRUE),
+ mPasteLight(TRUE)
{
+ mEnableCallbackRegistrar.add("BuildObject.PasteCheckItem", boost::bind(&LLPanelObject::pasteCheckMenuItem, this, _2));
+ mCommitCallbackRegistrar.add("BuildObject.PasteDoToSelected", boost::bind(&LLPanelObject::pasteDoMenuItem, this, _2));
+ mEnableCallbackRegistrar.add("BuildObject.PasteEnable", boost::bind(&LLPanelObject::pasteEnabletMenuItem, this, _2));
}
@@ -378,6 +418,8 @@ void LLPanelObject::getState( )
mCtrlPosX->setEnabled(enable_move);
mCtrlPosY->setEnabled(enable_move);
mCtrlPosZ->setEnabled(enable_move);
+ mBtnCopyPos->setEnabled(enable_move);
+ mBtnPastePos->setEnabled(enable_move && mHasPosClipboard);
if (enable_scale)
{
@@ -403,6 +445,8 @@ void LLPanelObject::getState( )
mCtrlScaleX->setEnabled( enable_scale );
mCtrlScaleY->setEnabled( enable_scale );
mCtrlScaleZ->setEnabled( enable_scale );
+ mBtnCopySize->setEnabled( enable_scale );
+ mBtnPasteSize->setEnabled( enable_scale && mHasSizeClipboard );
LLQuaternion object_rot = objectp->getRotationEdit();
object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ]));
@@ -434,6 +478,12 @@ void LLPanelObject::getState( )
mCtrlRotX->setEnabled( enable_rotate );
mCtrlRotY->setEnabled( enable_rotate );
mCtrlRotZ->setEnabled( enable_rotate );
+ mBtnCopyRot->setEnabled( enable_rotate );
+ mBtnPasteRot->setEnabled( enable_rotate && mHasRotClipboard );
+
+ mBtnCopyParams->setEnabled( single_volume && enable_modify );
+ mBtnPasteParams->setEnabled( single_volume && enable_modify && mHasParamsClipboard );
+ mBtnPasteMenu->setEnabled( single_volume && enable_modify );
LLUUID owner_id;
std::string owner_name;
@@ -2000,3 +2050,509 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata)
self->sendSculpt();
}
+
+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));
+
+ LLStringUtil::format_map_t args;
+ args["VALUE"] = stringVec;
+ mBtnPastePos->setToolTip(getString("paste_position", args));
+
+ mBtnPastePos->setEnabled(TRUE);
+
+ mHasPosClipboard = 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));
+
+ LLStringUtil::format_map_t args;
+ args["VALUE"] = stringVec;
+ mBtnPasteSize->setToolTip(getString("paste_size", args));
+
+ mBtnPasteSize->setEnabled(TRUE);
+
+ mHasSizeClipboard = 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));
+
+ LLStringUtil::format_map_t args;
+ args["VALUE"] = stringVec;
+ mBtnPasteRot->setToolTip(getString("paste_rotation", args));
+
+ mBtnPasteRot->setEnabled(TRUE);
+
+ mHasRotClipboard = TRUE;
+}
+
+void LLPanelObject::onPastePos()
+{
+ if(!mHasPosClipboard) return;
+
+ // Clamp pos on non-attachments, just keep the prims within the region
+ if (!mObject->isAttachment())
+ {
+ mClipboardPos.mV[VX] = llclamp( mClipboardPos.mV[VX], 0.f, 256.f);
+ mClipboardPos.mV[VY] = llclamp( mClipboardPos.mV[VY], 0.f, 256.f);
+ //height will get properly clammed by sendPosition
+ }
+
+ mCtrlPosX->set( mClipboardPos.mV[VX] );
+ mCtrlPosY->set( mClipboardPos.mV[VY] );
+ mCtrlPosZ->set( mClipboardPos.mV[VZ] );
+
+ sendPosition(FALSE);
+}
+
+void LLPanelObject::onPasteSize()
+{
+ if(!mHasSizeClipboard) 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(!mHasRotClipboard) 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)
+ {
+ return;
+ }
+
+ mParamsClipboard.clear();
+
+ mParamsClipboard["is_phantom"] = objectp->flagPhantom();
+ mParamsClipboard["is_physical"] = objectp->flagUsePhysics();
+
+ // Parametrics
+ if (!objectp->isMesh())
+ {
+ getVolumeParams(mClipboardVolumeParams);
+ }
+
+ 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)
+ {
+ mParamsClipboard["flex"]["lod"] = attributes->getSimulateLOD();
+ mParamsClipboard["flex"]["gav"] = attributes->getGravity();
+ mParamsClipboard["flex"]["ten"] = attributes->getTension();
+ mParamsClipboard["flex"]["fri"] = attributes->getAirFriction();
+ mParamsClipboard["flex"]["sen"] = attributes->getWindSensitivity();
+ LLVector3 force = attributes->getUserForce();
+ mParamsClipboard["flex"]["forx"] = force.mV[0];
+ mParamsClipboard["flex"]["fory"] = force.mV[1];
+ mParamsClipboard["flex"]["forz"] = force.mV[2];
+ }
+ }
+
+ // Sculpted Prim
+ if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+
+ if (!objectp->isMesh())
+ {
+ LLUUID texture_id = sculpt_params->getSculptTexture();
+ if (canCopyTexture(texture_id))
+ {
+ LL_INFOS() << "copy texture " << LL_ENDL;
+ mParamsClipboard["sculpt"]["id"] = texture_id;
+ }
+ else
+ {
+ mParamsClipboard["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE);
+ }
+
+ mParamsClipboard["sculpt"]["type"] = sculpt_params->getSculptType();
+ }
+ }
+
+ // Light Source
+ if (volobjp && volobjp->getIsLight())
+ {
+ mParamsClipboard["light"]["intensity"] = volobjp->getLightIntensity();
+ mParamsClipboard["light"]["radius"] = volobjp->getLightRadius();
+ mParamsClipboard["light"]["falloff"] = volobjp->getLightFalloff();
+ LLColor3 color = volobjp->getLightSRGBColor();
+ mParamsClipboard["light"]["r"] = color.mV[0];
+ mParamsClipboard["light"]["g"] = color.mV[1];
+ mParamsClipboard["light"]["b"] = color.mV[2];
+
+ // Spotlight
+ if (volobjp->isLightSpotlight())
+ {
+ LLUUID id = volobjp->getLightTextureID();
+ if (id.notNull() && canCopyTexture(id))
+ {
+ mParamsClipboard["spot"]["id"] = id;
+ LLVector3 spot_params = volobjp->getSpotLightParams();
+ mParamsClipboard["spot"]["fov"] = spot_params.mV[0];
+ mParamsClipboard["spot"]["focus"] = spot_params.mV[1];
+ mParamsClipboard["spot"]["ambiance"] = spot_params.mV[2];
+ }
+ }
+ }
+
+ // Physics
+ {
+ mParamsClipboard["physics"]["shape"] = objectp->getPhysicsShapeType();
+ mParamsClipboard["physics"]["gravity"] = objectp->getPhysicsGravity();
+ mParamsClipboard["physics"]["friction"] = objectp->getPhysicsFriction();
+ mParamsClipboard["physics"]["density"] = objectp->getPhysicsDensity();
+ mParamsClipboard["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)
+ {
+ mParamsClipboard["physics"]["material"] = material_code;
+ }
+ }
+
+ mHasParamsClipboard = TRUE;
+}
+
+void LLPanelObject::onPasteParams()
+{
+ LLViewerObject* objectp = mObject;
+ if (!objectp || !mHasParamsClipboard)
+ {
+ return;
+ }
+
+ LLVOVolume *volobjp = NULL;
+ if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+ {
+ volobjp = (LLVOVolume *)objectp;
+ }
+
+ // Light Source
+ if (mPasteLight && volobjp)
+ {
+ if (mParamsClipboard.has("light"))
+ {
+ volobjp->setIsLight(TRUE);
+ volobjp->setLightIntensity((F32)mParamsClipboard["light"]["intensity"].asReal());
+ volobjp->setLightRadius((F32)mParamsClipboard["light"]["radius"].asReal());
+ volobjp->setLightFalloff((F32)mParamsClipboard["light"]["falloff"].asReal());
+ F32 r = (F32)mParamsClipboard["light"]["r"].asReal();
+ F32 g = (F32)mParamsClipboard["light"]["g"].asReal();
+ F32 b = (F32)mParamsClipboard["light"]["b"].asReal();
+ volobjp->setLightSRGBColor(LLColor3(r, g, b));
+ }
+ else
+ {
+ volobjp->setIsLight(FALSE);
+ }
+
+ if (mParamsClipboard.has("spot"))
+ {
+ volobjp->setLightTextureID(mParamsClipboard["spot"]["id"].asUUID());
+ LLVector3 spot_params;
+ spot_params.mV[0] = (F32)mParamsClipboard["spot"]["fov"].asReal();
+ spot_params.mV[1] = (F32)mParamsClipboard["spot"]["focus"].asReal();
+ spot_params.mV[2] = (F32)mParamsClipboard["spot"]["ambiance"].asReal();
+ volobjp->setSpotLightParams(spot_params);
+ }
+ }
+
+ // Physics
+ if (mPastePhysics)
+ {
+ bool is_root = objectp->isRoot();
+
+ // Not sure if phantom should go under physics, but doesn't fit elsewhere
+ BOOL is_phantom = mParamsClipboard["is_phantom"].asBoolean() && is_root;
+ LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom);
+
+ BOOL is_physical = mParamsClipboard["is_physical"].asBoolean() && is_root;
+ LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical);
+
+ if (mParamsClipboard.has("physics"))
+ {
+ objectp->setPhysicsShapeType((U8)mParamsClipboard["physics"]["shape"].asInteger());
+ U8 cur_material = objectp->getMaterial();
+ U8 material = (U8)mParamsClipboard["physics"]["material"].asInteger() | (cur_material & ~LL_MCODE_MASK);
+
+ objectp->setMaterial(material);
+ objectp->sendMaterialUpdate();
+ objectp->setPhysicsGravity(mParamsClipboard["physics"]["gravity"].asReal());
+ objectp->setPhysicsFriction(mParamsClipboard["physics"]["friction"].asReal());
+ objectp->setPhysicsDensity(mParamsClipboard["physics"]["density"].asReal());
+ objectp->setPhysicsRestitution(mParamsClipboard["physics"]["restitution"].asReal());
+ objectp->updateFlags(TRUE);
+ }
+ }
+
+ if (mPasteFlexible)
+ {
+ bool is_flexible = mParamsClipboard.has("flex");
+ if (is_flexible)
+ {
+ LLVOVolume *volobjp = (LLVOVolume *)objectp;
+ BOOL update_shape = FALSE;
+ if (!mPasteParametric)
+ {
+ // 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(mParamsClipboard["flex"]["lod"].asInteger());
+ new_attributes.setGravity(mParamsClipboard["flex"]["gav"].asReal());
+ new_attributes.setTension(mParamsClipboard["flex"]["ten"].asReal());
+ new_attributes.setAirFriction(mParamsClipboard["flex"]["fri"].asReal());
+ new_attributes.setWindSensitivity(mParamsClipboard["flex"]["sen"].asReal());
+ F32 fx = (F32)mParamsClipboard["flex"]["forx"].asReal();
+ F32 fy = (F32)mParamsClipboard["flex"]["fory"].asReal();
+ F32 fz = (F32)mParamsClipboard["flex"]["forz"].asReal();
+ LLVector3 force(fx, fy, fz);
+ new_attributes.setUserForce(force);
+ objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true);
+ }
+
+ if (!mPasteParametric && update_shape)
+ {
+ mObject->sendShapeUpdate();
+ LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
+ }
+ }
+ else if (!mPasteParametric)
+ {
+ LLVOVolume *volobjp = (LLVOVolume *)objectp;
+ if (volobjp->setIsFlexible(is_flexible))
+ {
+ mObject->sendShapeUpdate();
+ LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
+ }
+ }
+ }
+ // Parametric does updateVolume(), make sure we won't affect flexible
+ else if (mPasteParametric)
+ {
+ LLVOVolume *volobjp = (LLVOVolume *)objectp;
+ if (volobjp->isFlexible())
+ {
+ if (mClipboardVolumeParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE)
+ {
+ mClipboardVolumeParams.getPathParams().setCurveType(LL_PCODE_PATH_FLEXIBLE);
+ }
+ }
+ else if (mClipboardVolumeParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
+ {
+ mClipboardVolumeParams.getPathParams().setCurveType(LL_PCODE_PATH_LINE);
+ }
+ }
+
+ // Parametrics
+ if(mPasteParametric)
+ {
+ // Sculpted Prim
+ if (mParamsClipboard.has("sculpt"))
+ {
+ LLSculptParams sculpt_params;
+ LLUUID sculpt_id = mParamsClipboard["sculpt"]["id"].asUUID();
+ U8 sculpt_type = (U8)mParamsClipboard["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);
+ }
+ }
+
+ objectp->updateVolume(mClipboardVolumeParams);
+ }
+}
+
+bool LLPanelObject::pasteCheckMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+
+ if ("Parametric" == command)
+ {
+ return mPasteParametric;
+ }
+ if ("Flexible" == command)
+ {
+ return mPasteFlexible;
+ }
+ if ("Physics" == command)
+ {
+ return mPastePhysics;
+ }
+ if ("Light" == command)
+ {
+ return mPasteLight;
+ }
+
+ return false;
+}
+
+void LLPanelObject::pasteDoMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+
+ if ("Parametric" == command)
+ {
+ mPasteParametric = !mPasteParametric;
+ }
+ if ("Flexible" == command)
+ {
+ mPasteFlexible = !mPasteFlexible;
+ }
+ if ("Physics" == command)
+ {
+ mPastePhysics = !mPastePhysics;
+ }
+ if ("Light" == command)
+ {
+ mPasteLight = !mPasteLight;
+ }
+}
+
+bool LLPanelObject::pasteEnabletMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+
+ // Keep at least one option enabled
+ if (mPasteParametric + mPasteFlexible + mPastePhysics + mPasteLight == 1)
+ {
+ if ("Parametric" == command && mPasteParametric)
+ {
+ return false;
+ }
+ if ("Flexible" == command && mPasteFlexible)
+ {
+ return false;
+ }
+ if ("Physics" == command && mPastePhysics)
+ {
+ return false;
+ }
+ if ("Light" == command && mPasteLight)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//static
+bool LLPanelObject::isLibraryTexture(LLUUID image_id)
+{
+ if (gInventory.isObjectDescendentOf(image_id, gInventory.getLibraryRootFolderID())
+ || image_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture"))
+ || image_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID"))
+ || image_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID"))
+ || image_id == LLUUID(SCULPT_DEFAULT_TEXTURE))
+ {
+ return true;
+ }
+ return false;
+}
+
+//static
+LLUUID LLPanelObject::getCopyPermInventoryTextureId(LLUUID image_id)
+{
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLAssetIDMatches asset_id_matches(image_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;
+}
+
+// Static
+bool LLPanelObject::canCopyTexture(LLUUID image_id)
+{
+ // User is allowed to copy a texture if:
+ // library asset or default texture,
+ // or copy perm asset exists in user's inventory
+
+ return isLibraryTexture(image_id) || getCopyPermInventoryTextureId(image_id).notNull();
+}
diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h
index 8829f493fa..65f46a8ed3 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,15 @@ 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 +85,17 @@ public:
BOOL onDropSculpt(LLInventoryItem* item);
static void onCommitSculptType( LLUICtrl *ctrl, void* userdata);
+ bool pasteCheckMenuItem(const LLSD& userdata);
+ void pasteDoMenuItem(const LLSD& userdata);
+ bool pasteEnabletMenuItem(const LLSD& userdata);
+ static bool isLibraryTexture(LLUUID image_id);
+
+ // Finds copy-enabled texture with specified asset from inventory
+ // This can be performance unfriendly and doesn't warranty that
+ // the texture is original source of asset
+ static LLUUID getCopyPermInventoryTextureId(LLUUID image_id);
+ static bool canCopyTexture(LLUUID image_id);
+
protected:
void getState();
@@ -147,6 +168,16 @@ protected:
LLSpinCtrl* mCtrlRotY;
LLSpinCtrl* mCtrlRotZ;
+ LLButton *mBtnCopyPos;
+ LLButton *mBtnPastePos;
+ LLButton *mBtnCopySize;
+ LLButton *mBtnPasteSize;
+ LLButton *mBtnCopyRot;
+ LLButton *mBtnPasteRot;
+ LLButton *mBtnCopyParams;
+ LLButton *mBtnPasteParams;
+ LLMenuButton *mBtnPasteMenu;
+
LLCheckBoxCtrl *mCheckLock;
LLCheckBoxCtrl *mCheckPhysics;
LLCheckBoxCtrl *mCheckTemporary;
@@ -157,7 +188,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 +198,23 @@ 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;
+
+ BOOL mHasPosClipboard;
+ BOOL mHasSizeClipboard;
+ BOOL mHasRotClipboard;
+
+ LLSD mParamsClipboard;
+ LLVolumeParams mClipboardVolumeParams;
+ BOOL mHasParamsClipboard;
+
+ BOOL mPasteParametric;
+ BOOL mPasteFlexible;
+ BOOL mPastePhysics;
+ BOOL mPasteLight;
+
LLPointer<LLViewerObject> mObject;
LLPointer<LLViewerObject> mRootObject;
};
diff --git a/indra/newview/skins/default/textures/icons/Paste.png b/indra/newview/skins/default/textures/icons/Paste.png
new file mode 100644
index 0000000000..10211df427
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Paste.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 624dca48d2..d36a2f6d6c 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -184,6 +184,7 @@ with the same filename but different name
<texture name="Conv_log_inbox" file_name="icons/Conv_log_inbox.png" preload="false" />
<texture name="Copy" file_name="icons/Copy.png" preload="false" />
+ <texture name="Paste" file_name="icons/Paste.png" preload="false" />
<texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 0abee2ff80..425af16261 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -1397,6 +1397,18 @@ even though the user gets a free copy.
name="Object"
top="16"
width="295">
+ <panel.string name="paste_position">
+Paste Position
+[VALUE]
+ </panel.string>
+ <panel.string name="paste_size">
+Paste Size
+[VALUE]
+ </panel.string>
+ <panel.string name="paste_rotation">
+Paste Rotation
+[VALUE]
+ </panel.string>
<check_box
height="19"
label="Locked"
@@ -1456,6 +1468,21 @@ even though the user gets a free copy.
text_enabled_color="1 0 0.3 .7"
top_pad="5"
width="87" />
+ <button
+ top_delta="0"
+ left_pad="5"
+ height="19"
+ width="20"
+ follows="top|right"
+ layout="topleft"
+ tab_stop="false"
+ image_bottom_pad="1"
+ image_overlay="Copy"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="copy_pos_btn"
+ tool_tip="Copy Position" />
<spinner
follows="left|top"
height="19"
@@ -1464,13 +1491,28 @@ even though the user gets a free copy.
label="Y"
label_width="10"
layout="topleft"
- left_delta="0"
+ left="10"
max_val="512"
min_val="-256"
name="Pos Y"
text_enabled_color="EmphasisColor"
top_pad="3"
width="87" />
+ <button
+ top_delta="0"
+ left_pad="5"
+ height="19"
+ width="20"
+ follows="top|right"
+ layout="topleft"
+ tab_stop="false"
+ image_bottom_pad="1"
+ image_overlay="Paste"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="paste_pos_btn"
+ tool_tip="Paste Position" />
<spinner
follows="left|top"
height="19"
@@ -1479,7 +1521,7 @@ even though the user gets a free copy.
label="Z"
label_width="10"
layout="topleft"
- left_delta="0"
+ left="10"
max_val="4096"
name="Pos Z"
text_enabled_color="0 0.8 1 .65"
@@ -1512,6 +1554,21 @@ even though the user gets a free copy.
text_enabled_color="1 1 1 1"
top_pad="5"
width="87" />
+ <button
+ top_delta="0"
+ left_pad="5"
+ height="19"
+ width="20"
+ follows="top|right"
+ layout="topleft"
+ tab_stop="false"
+ image_bottom_pad="1"
+ image_overlay="Copy"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="copy_size_btn"
+ tool_tip="Copy Size" />
<spinner
follows="left|top"
height="19"
@@ -1520,13 +1577,28 @@ even though the user gets a free copy.
label="Y"
label_width="10"
layout="topleft"
- left_delta="0"
+ left="10"
max_val="64"
min_val="0.01"
name="Scale Y"
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
+ <button
+ top_delta="0"
+ left_pad="5"
+ height="19"
+ width="20"
+ follows="top|right"
+ layout="topleft"
+ tab_stop="false"
+ image_bottom_pad="1"
+ image_overlay="Paste"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="paste_size_btn"
+ tool_tip="Paste Size" />
<spinner
follows="left|top"
height="19"
@@ -1535,7 +1607,7 @@ even though the user gets a free copy.
label="Z"
label_width="10"
layout="topleft"
- left_delta="0"
+ left="10"
max_val="64"
min_val="0.01"
name="Scale Z"
@@ -1570,6 +1642,21 @@ even though the user gets a free copy.
text_enabled_color="1 1 1 1"
top_pad="5"
width="87" />
+ <button
+ top_delta="0"
+ left_pad="5"
+ height="19"
+ width="20"
+ follows="top|right"
+ layout="topleft"
+ tab_stop="false"
+ image_bottom_pad="1"
+ image_overlay="Copy"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="copy_rot_btn"
+ tool_tip="Copy Rotation" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -1579,13 +1666,28 @@ even though the user gets a free copy.
label="Y"
label_width="10"
layout="topleft"
- left_delta="0"
+ left="10"
max_val="9999"
min_val="-9999"
name="Rot Y"
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
+ <button
+ top_delta="0"
+ left_pad="5"
+ height="19"
+ width="20"
+ follows="top|right"
+ layout="topleft"
+ tab_stop="false"
+ image_bottom_pad="1"
+ image_overlay="Paste"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="paste_rot_btn"
+ tool_tip="Paste Rotation" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -1595,7 +1697,7 @@ even though the user gets a free copy.
label="Z"
label_width="10"
layout="topleft"
- left_delta="0"
+ left="10"
max_val="9999"
min_val="-9999"
name="Rot Z"
@@ -1608,18 +1710,52 @@ even though the user gets a free copy.
follows="left|top"
height="10"
layout="topleft"
- left="125"
+ left="135"
name="label basetype"
top="5"
width="150">
Prim Type
</text>-->
+ <button
+ follows="top|right"
+ height="23"
+ label="Copy"
+ layout="topleft"
+ left="135"
+ name="copy_params_btn"
+ tool_tip="Copy Parameters to Clipboard"
+ top="6"
+ width="53">
+ </button>
+ <button
+ follows="top|right"
+ height="23"
+ label="Paste"
+ layout="topleft"
+ left_pad="5"
+ name="paste_params_btn"
+ tool_tip="Paste Parameters from Clipboard"
+ width="53">
+ </button>
+ <menu_button
+ menu_filename="menu_build_paste.xml"
+ follows="top|left"
+ height="23"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="5"
+ name="paste_gear_btn"
+ tool_tip="Paste options"
+ width="31"/>
<combo_box
height="19"
layout="topleft"
name="comboBaseType"
- top="6"
- left="125"
+ top_pad="5"
+ left="135"
width="150">
<combo_box.item
label="Box"
@@ -1698,7 +1834,7 @@ even though the user gets a free copy.
follows="left|top"
height="10"
layout="topleft"
- left="125"
+ left="135"
name="text hollow"
top_pad="6"
width="68">
@@ -1722,7 +1858,7 @@ even though the user gets a free copy.
increment="5"
initial_value="0"
layout="topleft"
- left="125"
+ left="135"
max_val="95"
name="Scale 1"
top_pad="4"
@@ -1746,7 +1882,7 @@ even though the user gets a free copy.
follows="left|top"
height="15"
layout="topleft"
- left="125"
+ left="135"
name="Hollow Shape"
top_pad="4"
width="150">
@@ -1824,7 +1960,7 @@ even though the user gets a free copy.
follows="left|top"
height="10"
layout="topleft"
- left="125"
+ left="135"
name="scale_taper"
top_pad="3"
width="150">
@@ -1877,7 +2013,7 @@ even though the user gets a free copy.
follows="left|top"
height="10"
layout="topleft"
- left="125"
+ left="135"
name="text topshear"
top_pad="3"
width="141">
@@ -1920,7 +2056,7 @@ even though the user gets a free copy.
follows="left|top"
height="10"
layout="topleft"
- left="125"
+ left="135"
name="advanced_cut"
top_pad="3"
width="150">
@@ -1984,7 +2120,7 @@ even though the user gets a free copy.
follows="left|top"
height="10"
layout="topleft"
- left="125"
+ left="135"
name="text taper2"
top_pad="3"
width="150">
@@ -2027,7 +2163,7 @@ even though the user gets a free copy.
follows="left|top"
height="10"
layout="topleft"
- left="125"
+ left="135"
name="text radius delta"
top_pad="2"
width="78">
@@ -2052,7 +2188,7 @@ even though the user gets a free copy.
increment="0.05"
initial_value="0"
layout="topleft"
- left="125"
+ left="135"
min_val="-1"
name="Radius Offset"
top_pad="4"
@@ -2077,7 +2213,7 @@ even though the user gets a free copy.
height="141"
label="Sculpt Texture"
layout="topleft"
- left="125"
+ left="135"
name="sculpt texture control"
tool_tip="Click to choose a picture"
top="70"
@@ -2535,7 +2671,7 @@ even though the user gets a free copy.
top_pad="8"
width="132" />
</panel>
- <panel
+ <panel
label="Texture"
help_topic="toolbox_texture_tab"
name="Texture"
diff --git a/indra/newview/skins/default/xui/en/menu_build_paste.xml b/indra/newview/skins/default/xui/en/menu_build_paste.xml
new file mode 100644
index 0000000000..acbef528b8
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_build_paste.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Conversation Gear Menu">
+ <menu_item_check
+ label="Prim Parameters"
+ layout="topleft"
+ name="Parametric">
+ <on_check function="BuildObject.PasteCheckItem" parameter="Parametric" />
+ <on_click function="BuildObject.PasteDoToSelected" parameter="Parametric" />
+ <on_enable function="BuildObject.PasteEnable" parameter="Parametric" />
+ </menu_item_check>
+ <menu_item_check
+ label="Flexible"
+ layout="topleft"
+ name="Flexible">
+ <on_check function="BuildObject.PasteCheckItem" parameter="Flexible" />
+ <on_click function="BuildObject.PasteDoToSelected" parameter="Flexible" />
+ <on_enable function="BuildObject.PasteEnable" parameter="Flexible" />
+ </menu_item_check>
+ <menu_item_check
+ label="Physics"
+ layout="topleft"
+ name="Physics">
+ <on_check function="BuildObject.PasteCheckItem" parameter="Physics" />
+ <on_click function="BuildObject.PasteDoToSelected" parameter="Physics" />
+ <on_enable function="BuildObject.PasteEnable" parameter="Physics" />
+ </menu_item_check>
+ <menu_item_check
+ label="Light"
+ layout="topleft"
+ name="Light">
+ <on_check function="BuildObject.PasteCheckItem" parameter="Light" />
+ <on_click function="BuildObject.PasteDoToSelected" parameter="Light" />
+ <on_enable function="BuildObject.PasteEnable" parameter="Light" />
+ </menu_item_check>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_texture_paste.xml b/indra/newview/skins/default/xui/en/menu_texture_paste.xml
new file mode 100644
index 0000000000..be6535b989
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_texture_paste.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Conversation Gear Menu">
+ <menu_item_check
+ label="Color"
+ layout="topleft"
+ name="Color">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Color" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Color" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Color" />
+ </menu_item_check>
+ <menu_item_check
+ label="Transparency"
+ layout="topleft"
+ name="Transparency">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Transparency" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Transparency" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Transparency" />
+ </menu_item_check>
+ <menu_item_check
+ label="Glow"
+ layout="topleft"
+ name="Glow">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Glow" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Glow" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Glow" />
+ </menu_item_check>
+ <menu_item_check
+ label="Texture"
+ layout="topleft"
+ name="Diffuse">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Diffuse" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Diffuse" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Diffuse" />
+ </menu_item_check>
+ <menu_item_check
+ label="Bumpiness"
+ layout="topleft"
+ name="Normal">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Normal" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Normal" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Normal" />
+ </menu_item_check>
+ <menu_item_check
+ label="Shininess"
+ layout="topleft"
+ name="Specular">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Specular" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Specular" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Specular" />
+ </menu_item_check>
+ <menu_item_check
+ label="Mapping"
+ layout="topleft"
+ name="Mapping">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Mapping" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Mapping" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Mapping" />
+ </menu_item_check>
+ <menu_item_check
+ label="Media"
+ layout="topleft"
+ name="Media">
+ <on_check function="BuildFace.PasteCheckItem" parameter="Media" />
+ <on_click function="BuildFace.PasteDoToSelected" parameter="Media" />
+ <on_enable function="BuildFace.PasteEnable" parameter="Media" />
+ </menu_item_check>
+</toggleable_menu>
+
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..1819106970 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -43,7 +43,7 @@
follows="left|top"
height="10"
layout="topleft"
- left_pad="15"
+ left_pad="10"
name="color trans"
text_readonly_color="LabelDisabledColor"
top="6"
@@ -68,7 +68,7 @@
follows="left|top"
height="10"
layout="topleft"
- left_pad="15"
+ left_pad="13"
name="glow label"
text_readonly_color="LabelDisabledColor"
top="6"
@@ -84,7 +84,7 @@
left_delta="0"
name="glow"
top_pad="4"
- width="80" />
+ width="50" />
<check_box
height="19"
label="Full Bright"
@@ -93,12 +93,47 @@
name="checkbox fullbright"
top_pad="4"
width="81" />
+ <button
+ follows="top|right"
+ height="23"
+ label="Copy"
+ layout="topleft"
+ left="240"
+ name="copy_face_btn"
+ tool_tip="Copy Parameters to Clipboard"
+ top="6"
+ width="53">
+ </button>
+ <button
+ follows="top|right"
+ height="23"
+ label="Paste"
+ layout="topleft"
+ name="paste_face_btn"
+ tool_tip="Paste Parameters from Clipboard"
+ top_pad="5"
+ width="53">
+ </button>
+ <menu_button
+ menu_filename="menu_texture_paste.xml"
+ follows="top|left"
+ height="23"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_delta="20"
+ name="paste_face_gear_btn"
+ tool_tip="Paste options"
+ top_pad="5"
+ width="31"/>
<combo_box
height="23"
layout="topleft"
left="10"
name="combobox matmedia"
- top_pad="5"
+ top="70"
width="100">
<combo_box.item
label="Materials"
@@ -113,10 +148,10 @@
control_name="ComboMaterialType"
height="50"
layout="topleft"
- left_pad="20"
+ left_pad="5"
top_delta="-10"
width="150"
- visible = "false"
+ visible = "true"
name="radio_material_type">
<radio_item
label="Texture (diffuse)"
@@ -139,7 +174,7 @@
layout="topleft"
top_pad="1"
value="2"/>
- </radio_group>
+ </radio_group>
<check_box
control_name="SyncMaterialSettings"
follows="top|left"
@@ -158,7 +193,7 @@
fallback_image="materials_ui_x_24.png"
follows="left|top"
height="80"
- label="Texture "
+ label="Texture"
layout="topleft"
left="10"
name="texture control"
@@ -235,7 +270,7 @@
fallback_image="materials_ui_x_24.png"
follows="left|top"
height="80"
- label="Texture "
+ label="Texture"
layout="topleft"
left="10"
name="bumpytexture control"
@@ -349,7 +384,7 @@
fallback_image="materials_ui_x_24.png"
follows="left|top"
height="80"
- label="Texture "
+ label="Texture"
layout="topleft"
left="10"
name="shinytexture control"
@@ -771,14 +806,14 @@
top_delta="16"
width="260" />
<button
- left="10"
- top="222"
+ follows="left|top"
+ layout="topleft"
+ left="9"
+ top="192"
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