/** * @file llpanelmorph.cpp * @brief LLPanelMorph class implementation * * Copyright (c) 2001-2007, Linden Research, Inc. * * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlife.com/developers/opensource/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at http://secondlife.com/developers/opensource/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. */ // file include #include "llviewerprecompiledheaders.h" /* #include "llpanelmorph.h" // library includes #include "llerror.h" #include "llrect.h" #include "llstring.h" #include "llfontgl.h" // project includes #include "llui.h" #include "llspinctrl.h" #include "llcheckboxctrl.h" #include "lltextbox.h" #include "llbutton.h" //#include "lldraghandle.h" #include "llviewerwindow.h" #include "llviewerobject.h" #include "llresmgr.h" #include "llcontrol.h" #include "llagent.h" #include "llvoavatar.h" #include "lltoolmgr.h" #include "lltoolmorph.h" #include "llquantize.h" // // Constants // const S32 VPAD = 2; const S32 HPAD = 4; const S32 TITLE_WIDTH = 100; const S32 TITLE_HEIGHT = 16; const S32 CLOSE_BOX_SIZE = 16; const S32 LABEL_HOFF = 8; const S32 LABEL_WIDTH = 140; const S32 SPIN_WIDTH = 250; // minimum and maximum morph weight values (a UI/network constraint, not inherent to morphs) const F32 MORPH_WEIGHT_MIN = (-1.f); const F32 MORPH_WEIGHT_MAX = (1.f); // this is the magic number that morph values are quantized to for network transmission purposes // the 200 value is a result of encoding the weights as a string (and avoiding NULL terminators // and avoiding \n (the between-NV-pair delimiter). Map -1 to 1 to 50-250. HACK. JC const S32 MORPH_WEIGHT_OFFSET = (50); const S32 MORPH_WEIGHT_QUANTUM = ((MORPH_WEIGHT_MAX - MORPH_WEIGHT_MIN) / MAXSTRINGVAL); //#define MORPH_PANEL_SHOW_SPINNERS // // Globals // LLPanelMorph *gPanelMorph = NULL; // // Methods // //static //----------------------------------------------------------------------------- // LLPanelMorph() //----------------------------------------------------------------------------- LLPanelMorph::LLPanelMorph(const std::string& name, const LLRect& rect) : LLPanel( name, rect ) { mParamSpinners = NULL; mSexRadioGroup = NULL; mRect = rect; mMesh = NULL; setBackgroundVisible( TRUE ); } //----------------------------------------------------------------------------- // ~LLPanelMorph() //----------------------------------------------------------------------------- LLPanelMorph::~LLPanelMorph() { #ifdef MORPH_PANEL_SHOW_SPINNERS for (S32 i = 0; i < mNumParamSpinners; i++) { removeChild(mParamSpinners[i]); delete mParamSpinners[i]; } delete [] mParamSpinners; #endif } // static //----------------------------------------------------------------------------- // onCommitSexChange() //----------------------------------------------------------------------------- void LLPanelMorph::onCommitSexChange( void *data) { // LLRadioGroup *group = (LLRadioGroup *)data; // LLVOAvatar *avatarp = gAgent.getAvatarObject(); // // LLNameValue* avatarSexNV = avatarp->getNVPair("AvatarSex"); // if (!avatarSexNV) // { // avatarp->addNVPair( "AvatarSex U32 READ_WRITE SIM_SPACE_VIEWER 0"); // avatarSexNV = avatarp->getNVPair("AvatarSex"); // } // // avatarSexNV->setU32(gSavedSettings.getU32("AvatarSex")); // // avatarp->sendNVPairToSimulator("AvatarSex"); // // // preemptively update sex based on local value // avatarp->updateSex(); // // LLVisualParamHint::requestHintUpdates(); } // static //----------------------------------------------------------------------------- // onCommitMorphChange() //----------------------------------------------------------------------------- void LLPanelMorph::onCommitMorphChange( LLUICtrl* ctrl, void* userdata ) { //#ifdef MORPH_PANEL_SHOW_SPINNERS // LLVOAvatar *avatarp = gAgent.getAvatarObject(); // // LLPanelMorph* self = (LLPanelMorph*) userdata; // // S32 i = 0; // for(LLPolyMorphTarget* morphTargetp = self->mMesh->getFirstVisualParam(); // morphTargetp; // morphTargetp = self->mMesh->getNextVisualParam()) // { // for(S32 j = 0; j < self->mNumParamSpinners; j++) // { // if (!strcmp(self->mParamSpinners[j]->getName(), morphTargetp->getName())) // { // avatarp->mHeadMesh0.getMesh()->setDistortionWeight(morphTargetp, self->mParamSpinners[j]->get()); // } // } // i++; // } // avatarp->updateDistortions(); // avatarp->sendVisualParams(); //#endif } //----------------------------------------------------------------------------- // updateSpinners() //----------------------------------------------------------------------------- void LLPanelMorph::updateSpinners(LLPolyMesh *mesh) { if (mesh != mMesh) return; #ifdef MORPH_PANEL_SHOW_SPINNERS for(LLViewerVisualParam *param = (LLViewerVisualParam*)gAgent.getAvatarObject()->getFirstVisualParam(); param; param = gAgent.getAvatarObject()->getNextVisualParam()) { if (param->getID() == -1 || param->getGroup() != LLVisualParam::VISUAL_PARAM_GROUP_TWEAKABLE) continue; F32 paramWeight = gAgent.getAvatarObject()->getVisualParamWeight(morphTargetp); for (S32 i = 0; i < mNumParamSpinners; i++) { if (!strcmp(mParamSpinners[i]->getName() , morphTargetp->getName())) { mParamSpinners[i]->set(paramWeight); } } } #endif } //----------------------------------------------------------------------------- // createSpinners() //----------------------------------------------------------------------------- void LLPanelMorph::createSpinners(LLPolyMesh *mesh) { const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); S32 cur_y; S32 new_height; S32 control_focus = -1; if (mSexRadioGroup) { removeChild(mSexRadioGroup); delete mSexRadioGroup; } if (mParamSpinners) { for (S32 i = 0; i < mNumParamSpinners; i++) { if (mParamSpinners[i]->hasFocus()) { control_focus = i; mParamSpinners[i]->setFocus(FALSE); } } for (i = 0; i < mNumParamSpinners; i++) { removeChild(mParamSpinners[i]); delete mParamSpinners[i]; } delete [] mParamSpinners; mParamSpinners = NULL; } #ifdef MORPH_PANEL_SHOW_SPINNERS S32 numSpinners = 0; for(LLViewerVisualParam *param = (LLViewerVisualParam*)gAgent.getAvatarObject()->getFirstVisualParam(); param; param = gAgent.getAvatarObject()->getNextVisualParam()) { if(param->getID() != -1 && param->getGroup() == LLVisualParam::VISUAL_PARAM_GROUP_TWEAKABLE) { numSpinners++; } } if (numSpinners != 0) { mParamSpinners = new LLSpinCtrl*[numSpinners]; } // set focus back to control #n if (control_focus >= 0 && control_focus < numSpinners) { mParamSpinners[control_focus]->setFocus(TRUE); } new_height = numSpinners * (SPINCTRL_HEIGHT + VPAD) + (VPAD * 3) + CHECKBOXCTRL_HEIGHT + VPAD + VPAD; #else new_height = (VPAD * 3) + CHECKBOXCTRL_HEIGHT + VPAD + VPAD; #endif LLRect panelRect = getRect(); reshape(panelRect.getWidth(), new_height, TRUE); cur_y = new_height - VPAD - VPAD; LLRect radio_rect; radio_rect.setLeftTopAndSize(HPAD + LABEL_HOFF, cur_y, getRect().getWidth() - HPAD - HPAD - LABEL_HOFF, CHECKBOXCTRL_HEIGHT + VPAD); mSexRadioGroup = new LLRadioGroup("sex radio", radio_rect, "AvatarSex", &LLPanelMorph::onCommitSexChange, (void *)this); addChild(mSexRadioGroup); radio_rect.setLeftTopAndSize(HPAD + LABEL_HOFF, 0, (getRect().getWidth() - HPAD - HPAD - LABEL_HOFF) / 2.f, 0); mSexRadioGroup->addRadioButton("Female", "Female", radio_rect, font); radio_rect.setLeftTopAndSize(((getRect().getWidth() - HPAD - HPAD - LABEL_HOFF) / 2.f) + HPAD + LABEL_HOFF, 0, (getRect().getWidth() - HPAD - HPAD - LABEL_HOFF) / 2.f, 0); mSexRadioGroup->addRadioButton("Male", "Male", radio_rect, font); cur_y -= CHECKBOXCTRL_HEIGHT + VPAD + VPAD; #ifdef MORPH_PANEL_SHOW_SPINNERS S32 i = 0; for(LLViewerVisualParam *param = (LLViewerVisualParam*)gAgent.getAvatarObject()->getFirstVisualParam(); param; param = gAgent.getAvatarObject()->getNextVisualParam()) { if (param->getID() == -1 || param->getGroup() != LLVisualParam::VISUAL_PARAM_GROUP_TWEAKABLE) continue; LLRect spinnerRect; spinnerRect.setLeftTopAndSize(HPAD + LABEL_HOFF, cur_y, getRect().getWidth() - HPAD - HPAD - LABEL_HOFF, cur_y - SPINCTRL_HEIGHT); mParamSpinners[i] = new LLSpinCtrl(param->getName(), spinnerRect, font, param->getName(), &LLPanelMorph::onCommitMorphChange, this, param->getWeight(), param->getMinWeight(), param->getMaxWeight(), MORPH_WEIGHT_QUANTUM * 2, NULL, LABEL_WIDTH ); mParamSpinners[i]->setPrecision(2); mParamSpinners[i]->setFollowsTop(); mParamSpinners[i]->setFollowsLeft(); addChild(mParamSpinners[i]); cur_y -= VPAD + SPINCTRL_HEIGHT; i++; } mNumParamSpinners = numSpinners; #endif mMesh = mesh; } */