diff options
-rw-r--r-- | indra/newview/lllocalbitmaps.h | 2 | ||||
-rw-r--r-- | indra/newview/llpanelface.cpp | 717 | ||||
-rw-r--r-- | indra/newview/llpanelface.h | 36 | ||||
-rw-r--r-- | indra/newview/llpanelobject.cpp | 149 | ||||
-rw-r--r-- | indra/newview/llpanelobject.h | 23 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_tools.xml | 64 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml | 21 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml | 21 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_copy_paste_size.xml | 21 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_texture_paste.xml | 70 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_tools_texture.xml | 63 |
11 files changed, 1152 insertions, 35 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..369861fa25 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,676 @@ 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 = LLPanelFace::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 = LLPanelFace::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() && !LLPanelFace::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() && !LLPanelFace::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; +} + +//static +bool LLPanelFace::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 LLPanelFace::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 LLPanelFace::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/llpanelface.h b/indra/newview/llpanelface.h index 2d57d89a44..dbf3531332 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,15 @@ public: LLRender::eTexIndex getTextureChannelToEdit(); + void pasteFace(LLViewerObject* object, S32 te); + 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(); @@ -205,9 +215,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 +248,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 +527,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..e6bbac8247 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 + mMenuPastePos = getChild<LLMenuButton>("paste_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 + mMenuPasteSize = getChild<LLMenuButton>("paste_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 + mMenuPasteRot = getChild<LLMenuButton>("paste_rot_btn"); mLabelRotation = getChild<LLTextBox>("label rotation"); mCtrlRotX = getChild<LLSpinCtrl>("Rot X"); childSetCommitCallback("Rot X",onCommitRotation,this); @@ -285,8 +289,13 @@ LLPanelObject::LLPanelObject() mSelectedType(MI_BOX), mSculptTextureRevert(LLUUID::null), mSculptTypeRevert(0), + mHasPosClipboard(FALSE), + mHasSizeClipboard(FALSE), + mHasRotClipboard(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 +382,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_POS); } - + mMenuPastePos->setEnabled(enable_move); mLabelPosition->setEnabled( enable_move ); mCtrlPosX->setEnabled(enable_move); mCtrlPosY->setEnabled(enable_move); @@ -399,6 +408,7 @@ void LLPanelObject::getState( ) calcp->setVar(LLCalc::Z_SCALE, 0.f); } + mMenuPasteSize->setEnabled(enable_scale); mLabelSize->setEnabled( enable_scale ); mCtrlScaleX->setEnabled( enable_scale ); mCtrlScaleY->setEnabled( enable_scale ); @@ -430,6 +440,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_ROT); } + mMenuPasteRot->setEnabled(enable_rotate); mLabelRotation->setEnabled( enable_rotate ); mCtrlRotX->setEnabled( enable_rotate ); mCtrlRotY->setEnabled( enable_rotate ); @@ -1644,6 +1655,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 +2013,135 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata) self->sendSculpt(); } + +void LLPanelObject::menuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste + if (command == "pos_paste") + { + onPastePos(); + } + else if (command == "size_paste") + { + onPasteSize(); + } + else if (command == "rot_paste") + { + onPasteRot(); + } + // copy + else if (command == "pos_copy") + { + onCopyPos(); + } + else if (command == "size_copy") + { + onCopySize(); + } + else if (command == "rot_copy") + { + onCopyRot(); + } +} + +bool LLPanelObject::menuEnableItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + if (command == "pos_paste") + { + return mHasPosClipboard; + } + else if (command == "size_paste") + { + return mHasSizeClipboard; + } + else if (command == "rot_paste") + { + return mHasRotClipboard; + } + 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)); + + 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)); + + 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)); + + mHasRotClipboard = TRUE; +} + +void LLPanelObject::onPastePos() +{ + if (!mHasPosClipboard) 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 (!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); +} diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 8829f493fa..e8f8d0eb9a 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,12 @@ 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(); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -75,6 +82,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(); @@ -131,17 +141,20 @@ protected: LLTextBox* mLabelRevolutions; LLSpinCtrl* mSpinRevolutions; + LLMenuButton* mMenuPastePos; LLTextBox* mLabelPosition; LLSpinCtrl* mCtrlPosX; LLSpinCtrl* mCtrlPosY; LLSpinCtrl* mCtrlPosZ; + LLMenuButton* mMenuPasteSize; LLTextBox* mLabelSize; LLSpinCtrl* mCtrlScaleX; LLSpinCtrl* mCtrlScaleY; LLSpinCtrl* mCtrlScaleZ; BOOL mSizeChanged; + LLMenuButton* mMenuPasteRot; LLTextBox* mLabelRotation; LLSpinCtrl* mCtrlRotX; LLSpinCtrl* mCtrlRotY; @@ -157,7 +170,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 +180,14 @@ 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; + LLPointer<LLViewerObject> mObject; LLPointer<LLViewerObject> mRootObject; }; diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 0abee2ff80..2397be6b61 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1430,6 +1430,18 @@ 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" /> + <menu_button + menu_filename="menu_copy_paste_pos.xml" + follows="top|left" + height="11" + image_disabled="OptionsMenu_Disabled" + image_selected="OptionsMenu_Press" + image_unselected="OptionsMenu_Off" + layout="topleft" + top_pad="10" + name="paste_pos_btn" + tool_tip="Paste options" + width="19"/> <text type="string" length="1" @@ -1437,9 +1449,11 @@ even though the user gets a free copy. height="10" layout="topleft" name="label position" - top_pad="10" + tool_tip="Position (meters)" + left_pad="3" + top_delta="0" width="121"> - Position (meters) + Position </text> <spinner follows="left|top" @@ -1449,7 +1463,7 @@ even though the user gets a free copy. label="X" label_width="10" layout="topleft" - left_delta="0" + left_delta="-22" max_val="512" min_val="-256" name="Pos X" @@ -1485,17 +1499,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="OptionsMenu_Disabled" + image_selected="OptionsMenu_Press" + image_unselected="OptionsMenu_Off" + layout="topleft" + left_delta="0" + top_pad="10" + name="paste_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="3" + top_delta="0" name="label size" - top_pad="6" + tool_tip="Size (meters)" width="121"> - Size (meters) + Size </text> <spinner follows="left|top" @@ -1505,7 +1533,7 @@ even though the user gets a free copy. label="X" label_width="10" layout="topleft" - left_delta="0" + left_delta="-22" max_val="64" min_val="0.01" name="Scale X" @@ -1542,17 +1570,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="OptionsMenu_Disabled" + image_selected="OptionsMenu_Press" + image_unselected="OptionsMenu_Off" + layout="topleft" + left_delta="0" + top_pad="10" + name="paste_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="3" + top_delta="0" name="label rotation" - top_pad="10" + tool_tip="Rotation (degrees)" width="121"> - Rotation (degrees) + Rotation </text> <spinner decimal_digits="2" @@ -1563,7 +1605,7 @@ even though the user gets a free copy. label="X" label_width="10" layout="topleft" - left_delta="0" + left_delta="-22" max_val="9999" min_val="-9999" name="Rot X" 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..c2763af603 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Position Menu"> + <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 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..dcfb3faeca --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Rotation Menu"> + <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 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..58d71b12d5 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Size Menu"> + <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 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_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 |