Anonymous avatar Anonymous committed 3d65313 Merge

Merge latest from viewer trunk

Comments (0)

Files changed (220)

 8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release
 8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release
 77e5a08344c95738ab879f9671b7758cddd712a3 DRTVWR-56_2.6.9-release
+77e5a08344c95738ab879f9671b7758cddd712a3 2.6.9-release
 8835e0e3c0d3a48244c287bc05811dfc2fba43ec 2.7.0-start
 43c7ee846b7eed80786acbbf35d03bd016a3e85d DRTVWR-59_2.7.0-beta1
 43c7ee846b7eed80786acbbf35d03bd016a3e85d 2.7.0-beta1
-77e5a08344c95738ab879f9671b7758cddd712a3 2.6.9-release
 54fd44ac92e4c61435ea33effe093a3527e18d98 2.7.1-start
 0c4d0c24278074f219e5a32e72b449e78301d11b DRTVWR-61_2.7.1-beta1
 0c4d0c24278074f219e5a32e72b449e78301d11b 2.7.1-beta1
-8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release
-8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release
-77e5a08344c95738ab879f9671b7758cddd712a3 DRTVWR-56_2.6.9-release
 9f79a6ed8fdcd2f3dac33ea6b3236eeb278dccfe 2.7.2-start
 e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb DRTVWR-63_2.7.2-beta1
 e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb 2.7.2-beta1
 6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start
 6af10678de4736222b2c3f7e010e984fb5b327de 2.7.4-start
-77e5a08344c95738ab879f9671b7758cddd712a3 2.6.9-release
+be963a4eef635542f9617d7f5fd22ba48fb71958 DRTVWR-67_2.7.4-beta1
+be963a4eef635542f9617d7f5fd22ba48fb71958 2.7.4-beta1
 a9abb9633a266c8d2fe62411cfd1c86d32da72bf DRTVWR-60_2.7.1-release
+be963a4eef635542f9617d7f5fd22ba48fb71958 DRTVWR-67_2.7.4-beta1
+be963a4eef635542f9617d7f5fd22ba48fb71958 2.7.4-beta1
 a9abb9633a266c8d2fe62411cfd1c86d32da72bf 2.7.1-release
-e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb DRTVWR-63_2.7.2-beta1
-e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb 2.7.2-beta1
 19a498fa62570f352d7d246f17e3c81cc1d82d8b 2.7.5-start
+09984bfa6cae17e0f72d02b75c1b7393c65eecfc DRTVWR-69_2.7.5-beta1
+09984bfa6cae17e0f72d02b75c1b7393c65eecfc 2.7.5-beta1
 # oz
 # ================
 
+snowstorm_project-windlight.build_debug_release_separately = true
+snowstorm_project-windlight.viewer_channel = "Second Life Project Windlight Region"
+snowstorm_project-windlight.login_channel  = "Second Life Project Windlight Region"
+
 oz_viewer-devreview.build_debug_release_separately = true
 oz_viewer-devreview.codeticket_add_context = false
 
             <map>
               <key>build</key>
               <map>
-                <key>arguments</key>
+                <key>filters</key>
                 <array>
-                  <string>|</string>
-                  <string>grep</string>
-                  <string>-v</string>
                   <string>setenv</string>
                 </array>
                 <key>command</key>
             <map>
               <key>build</key>
               <map>
-                <key>arguments</key>
+                <key>filters</key>
                 <array>
-                  <string>|</string>
-                  <string>grep</string>
-                  <string>-v</string>
                   <string>setenv</string>
                 </array>
                 <key>command</key>
             <map>
               <key>build</key>
               <map>
-                <key>arguments</key>
+                <key>filters</key>
                 <array>
-                  <string>|</string>
-                  <string>grep</string>
-                  <string>-v</string>
                   <string>setenv</string>
                 </array>
                 <key>command</key>

doc/contributions.txt

 Alexandrea Fride
     STORM-255
 	STORM-960
+	STORM-1327
+	STORM-1406
 Alissa Sabre
 	VWR-81
 	VWR-83
 	CT-193
 Ansariel Hiller
 	STORM-1101
+	VWR-25480
 Ardy Lay
 	STORM-859
 	VWR-19499
 	STORM-1236
 	STORM-1259
 	STORM-787
+	VWR-25480
+	STORM-1334
 	STORM-1313
 	STORM-899
 	STORM-1273
+	STORM-457
+	STORM-1452
+	STORM-1406
+	STORM-1327
+	STORM-1396
+	STORM-1292
+	STORM-1392
+	STORM-1302
+	STORM-1326
 Kage Pixel
 	VWR-11
 Ken March
 	SNOW-691
 TankMaster Finesmith
 	STORM-1100
+	STORM-1452
 Tayra Dagostino
 	SNOW-517
 	SNOW-543
 	STORM-825
 	STORM-859
 	STORM-1098
+	STORM-1393
 	VWR-20741
 	VWR-20933
 Zai Lynch

indra/integration_tests/llui_libtest/llwidgetreg.cpp

 #include "lltabcontainer.h"
 #include "lltextbox.h"
 #include "lltexteditor.h"
+#include "lltimectrl.h"
 #include "llflyoutbutton.h"
 #include "llfiltereditor.h"
 #include "lllayoutstack.h"
 		//LLDefaultChildRegistry::Register<LLPlaceHolderPanel> placeholder("placeholder");
 		LLDefaultChildRegistry::Register<LLTabContainer> tab_container("tab_container");
 		LLDefaultChildRegistry::Register<LLTextBox> text("text");
+		LLDefaultChildRegistry::Register<LLTimeCtrl> time("time");
 		LLDefaultChildRegistry::Register<LLTextEditor> simple_text_editor("simple_text_editor");
 		LLDefaultChildRegistry::Register<LLUICtrl> ui_ctrl("ui_ctrl");
 		LLDefaultChildRegistry::Register<LLStatView> stat_view("stat_view");

indra/llcharacter/llcharacter.cpp

 LLStringTable LLCharacter::sVisualParamNames(1024);
 
 std::vector< LLCharacter* > LLCharacter::sInstances;
-
+BOOL LLCharacter::sAllowInstancesChange = TRUE ;
 
 //-----------------------------------------------------------------------------
 // LLCharacter()
 	mAppearanceSerialNum( 0 ),
 	mSkeletonSerialNum( 0 )
 {
-	mMotionController.setCharacter( this );
+	llassert_always(sAllowInstancesChange) ;
 	sInstances.push_back(this);
+
+	mMotionController.setCharacter( this );	
 	mPauseRequest = new LLPauseRequestHandle();
 }
 
 // Class Destructor
 //-----------------------------------------------------------------------------
 LLCharacter::~LLCharacter()
-{
+{	
 	for (LLVisualParam *param = getFirstVisualParam(); 
 		param;
 		param = getNextVisualParam())
 	{
 		delete param;
 	}
-	std::vector<LLCharacter*>::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
-	if (iter != sInstances.end())
+
+	U32 i ;
+	U32 size = sInstances.size() ;
+	for(i = 0 ; i < size ; i++)
 	{
-		sInstances.erase(iter);
+		if(sInstances[i] == this)
+		{
+			break ;
+		}
 	}
+
+	llassert_always(i < size) ;
+
+	llassert_always(sAllowInstancesChange) ;
+	sInstances[i] = sInstances[size - 1] ;
+	sInstances.pop_back() ;
 }
 
 

indra/llcharacter/llcharacter.h

 	void			setSkeletonSerialNum( U32 num )	{ mSkeletonSerialNum = num; }
 
 	static std::vector< LLCharacter* > sInstances;
+	static BOOL sAllowInstancesChange ; //debug use
 
 protected:
 	LLMotionController	mMotionController;

indra/llcharacter/llkeyframemotion.cpp

 }
 
 //-----------------------------------------------------------------------------
-// getJoin()
+// getJoint()
 //-----------------------------------------------------------------------------
 LLJoint* LLKeyframeMotion::getJoint(U32 index)
 {
 	llassert_always (index < mJointStates.size());
 	LLJoint* joint = mJointStates[index]->getJoint();
-	llassert_always (joint);
+	
+	//Commented out 06-28-11 by Aura.
+	//llassert_always (joint);
 	return joint;
 }
 
 	S32 joint_num;
 	LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
 	LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]);
-
+	if ( !cur_joint )
+	{
+		return;
+	}
+	
 	F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
 
 	constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
 	for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
 	{
 		LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
+		if ( !cur_joint )
+		{
+			return;
+		}
 		constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
 	}
 
 	}
 
 	LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]);
+	if (! root_joint) 
+	{
+		return;
+	}
+	
 	LLVector3 root_pos = root_joint->getWorldPosition();
 //	LLQuaternion root_rot = 
 	root_joint->getParent()->getWorldRotation();
 	for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
 	{
 		LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
+		if (!cur_joint)
+		{
+			return;
+		}
+		
 		if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
 		{
 			// skip constraint
 
 	if (shared_data->mChainLength)
 	{
-		LLQuaternion end_rot = getJoint(shared_data->mJointStateIndices[0])->getWorldRotation();
+		LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
+		
+		if (!end_joint)
+		{
+			return;
+		}
+		
+		LLQuaternion end_rot = end_joint->getWorldRotation();
 
 		// slam start and end of chain to the proper positions (rest of chain stays put)
 		positions[0] = lerp(keyframe_source_pos, target_pos, weight);
 		// grab keyframe-specified positions of joints	
 		for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
 		{
-			LLVector3 kinematic_position = getJoint(shared_data->mJointStateIndices[joint_num])->getWorldPosition() + 
+			LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
+			
+			if (!cur_joint)
+			{
+				return;
+			}
+			
+			LLVector3 kinematic_position = cur_joint->getWorldPosition() + 
 				(source_to_target * constraint->mJointLengthFractions[joint_num]);
 
 			// convert intermediate joint positions to world coordinates
 		for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
 		{
 			LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
+			
+			if (!cur_joint)
+			{
+				return;
+			}
 			LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]);
+			if (!child_joint)
+			{
+				return;
+			}
+			
 			LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation();
 
 			LLQuaternion cur_rot = cur_joint->getWorldRotation();
 			cur_joint->setRotation(target_rot);
 		}
 
-		LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
 		LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
 
 		if (weight == 1.f)
 		//reset old joint rots
 		for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
 		{
-			getJoint(shared_data->mJointStateIndices[joint_num])->setRotation(old_rots[joint_num]);
+			LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
+			if (!cur_joint)
+			{
+				return;
+			}
+
+			cur_joint->setRotation(old_rots[joint_num]);
 		}
 	}
 	// simple positional constraint (pelvis only)
 				constraintp->mJointStateIndices[i] = -1;
 				for (U32 j = 0; j < mJointMotionList->getNumJointMotions(); j++)
 				{
-					if(getJoint(j) == joint)
+					LLJoint* constraint_joint = getJoint(j);
+					
+					if ( !constraint_joint )
+					{
+						llwarns << "Invalid joint " << j << llendl;
+						return FALSE;
+					}
+					
+					if(constraint_joint == joint)
 					{
 						constraintp->mJointStateIndices[i] = (S32)j;
 						break;

indra/llcharacter/llkeyframemotion.h

 private:
 	// private helper functions to wrap some asserts
 	LLPointer<LLJointState>& getJointState(U32 index);
-	LLJoint* getJoint(U32 index);
+	LLJoint* getJoint(U32 index );
 	
 public:
 	//-------------------------------------------------------------------------

indra/llmessage/lliosocket.cpp

 		port = PORT_EPHEMERAL;
 	}
 	rv->mPort = port;
-	rv->setOptions();
+	rv->setNonBlocking();
 	return rv;
 }
 
 	}
 	rv = ptr_t(new LLSocket(socket, pool));
 	rv->mPort = PORT_EPHEMERAL;
-	rv->setOptions();
+	rv->setNonBlocking();
 	return rv;
 }
 
 	{
 		return false;
 	}
-	apr_socket_timeout_set(mSocket, 1000);
+	setBlocking(1000);
 	ll_debug_socket("Blocking connect", mSocket);
 	if(ll_apr_warn_status(apr_socket_connect(mSocket, sa))) return false;
-	setOptions();
+	setNonBlocking();
 	return true;
 }
 
 	}
 }
 
-void LLSocket::setOptions()
+// See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4
+// for an explanation of how to get non-blocking sockets and timeouts with
+// consistent behavior across platforms.
+
+void LLSocket::setBlocking(S32 timeout)
+{
+	LLMemType m1(LLMemType::MTYPE_IO_TCP);
+	// set up the socket options
+	ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout));
+	ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 0));
+	ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
+	ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));
+
+}
+
+void LLSocket::setNonBlocking()
 {
 	LLMemType m1(LLMemType::MTYPE_IO_TCP);
 	// set up the socket options
 	ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0));
+	ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 1));
 	ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
 	ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));
 

indra/llmessage/lliosocket.h

 	LLSocket(apr_socket_t* socket, apr_pool_t* pool);
 
 	/** 
-	 * @brief Set default socket options.
+	 * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.
+	 * @param timeout Number of microseconds to wait on this socket. Any
+	 * negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE.
 	 */
-	void setOptions();
+	void setBlocking(S32 timeout);
+
+	/**
+	 * @brief Set default socket options, with SO_NONBLOCK = 1 and timeout = 0.
+	 */
+	void setNonBlocking();
 
 public:
 	/** 

indra/llrender/llgl.cpp

 		glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
 	}
 
+#if LL_WINDOWS
+	if (mIsATI)
+	{ //using multisample textures on ATI results in black screen for some reason
+		mHasTextureMultisample = FALSE;
+	}
+#endif
+
 	if (mHasFramebufferObject)
 	{
 		glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);

indra/llrender/llglslshader.cpp

 	// Create program
 	mProgramObject = glCreateProgramObjectARB();
 	
+	if (gGLManager.mGLVersion < 3.1f)
+	{ //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support)
+		mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
+	}
+
 	//compile new source
 	vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
 	for ( ; fileIter != mShaderFiles.end(); fileIter++ )
 		return FALSE;
 	}
 
+	if (gGLManager.mGLVersion < 3.1f)
+	{ //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
+		mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
+	}
+
 	// Map attributes and uniforms
 	if (success)
 	{

indra/llrender/llshadermgr.cpp

 	GLcharARB* text[1024];
 	GLuint count = 0;
 
-	if (gGLManager.mGLVersion < 3.f)
+	if (gGLManager.mGLVersion < 2.1f)
+	{
+		text[count++] = strdup("#version 110\n");
+	}
+	else if (gGLManager.mGLVersion < 3.f)
 	{
 		//set version to 1.20
 		text[count++] = strdup("#version 120\n");
 		text[count++] = strdup("{\n");
 		
 		
-		if (gGLManager.mGLVersion >= 3.f)
+		if (texture_index_channels == 1)
+		{ //don't use flow control, that's silly
+			text[count++] = strdup("return texture2D(tex0, texcoord);\n");
+			text[count++] = strdup("}\n");
+		}
+		else if (gGLManager.mGLVersion >= 3.f)
 		{ 
 			text[count++] = strdup("\tswitch (int(vary_texture_index+0.25))\n");
 			text[count++] = strdup("\t{\n");
 			}
 
 			text[count++] = strdup("\t}\n");
+			text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
+			text[count++] = strdup("}\n");
 		}
 		else
 		{
 				std::string if_str = llformat("if (ti == %d) return texture2D(tex%d, texcoord);\n", i, i);
 				text[count++] = strdup(if_str.c_str());
 			}
+
+			text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
+			text[count++] = strdup("}\n");
 		}			
-
-		text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
-		text[count++] = strdup("}\n");
 	}
 
 	//copy file into memory
 		}
 	}
 		
-	//free memory
-	for (GLuint i = 0; i < count; i++)
-	{
-		free(text[i]);
-	}
 	if (error == GL_NO_ERROR)
 	{
 		//check for errors
 				//an error occured, print log
 				LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
 				dumpObjectLog(ret);
+
+				std::stringstream ostr;
+				//dump shader source for debugging
+				for (GLuint i = 0; i < count; i++)
+				{
+					ostr << i << ": " << text[i];
+				}
+
+				LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+
 				ret = 0;
 			}
 		}
 	}
 	stop_glerror();
 
+	//free memory
+	for (GLuint i = 0; i < count; i++)
+	{
+		free(text[i]);
+	}
+
 	//successfully loaded, save results
 	if (ret)
 	{

indra/llui/CMakeLists.txt

     lltextparser.cpp
     lltextutil.cpp
     lltextvalidate.cpp
+    lltimectrl.cpp
     lltransutil.cpp
     lltoggleablemenu.cpp
     lltooltip.cpp
     lltextparser.h
     lltextutil.h
     lltextvalidate.h
+    lltimectrl.h
     lltoggleablemenu.h
     lltooltip.h
     lltransutil.h

indra/llui/llconsole.cpp

 
 void LLConsole::draw()
 {
+	// Units in pixels
+	static const F32 padding_horizontal = 10;
+	static const F32 padding_vertical = 3;
 	LLGLSUIDefault gls_ui;
 
 	// skip lines added more than mLinePersistTime ago
 	// draw remaining lines
 	F32 y_pos = 0.f;
 
-	LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square");
+	LLUIImagePtr imagep = LLUI::getUIImage("transparent");
 
-//	F32 console_opacity = llclamp(gSavedSettings.getF32("ConsoleBackgroundOpacity"), 0.f, 1.f);
 	F32 console_opacity = llclamp(LLUI::sSettingGroups["config"]->getF32("ConsoleBackgroundOpacity"), 0.f, 1.f);
-//	LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground");
 	LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground");
 	color.mV[VALPHA] *= console_opacity;
 
 
 	for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++)
 	{
-		S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + 8);
-		S32 target_width =  llfloor( (*paragraph_it).mMaxWidth +15);
+		S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + padding_vertical);
+		S32 target_width =  llfloor( (*paragraph_it).mMaxWidth + padding_horizontal);
 
 		y_pos += ((*paragraph_it).mLines.size()) * line_height;
 		imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color);
 				y_off += line_height;
 			}
 		}
-		y_pos  += 8;
+		y_pos  += padding_vertical;
 	}
 }
 

indra/llui/lllineeditor.cpp

 :	max_length(""),
     keystroke_callback("keystroke_callback"),
 	prevalidate_callback("prevalidate_callback"),
+	prevalidate_input_callback("prevalidate_input_callback"),
 	background_image("background_image"),
 	background_image_disabled("background_image_disabled"),
 	background_image_focused("background_image_focused"),
 	updateTextPadding();
 	setCursor(mText.length());
 
+	setPrevalidateInput(p.prevalidate_input_callback());
 	setPrevalidate(p.prevalidate_callback());
 
 	LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>
 // Picks a new cursor position based on the actual screen size of text being drawn.
 void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x )
 {
-	const llwchar* wtext = mText.getWString().c_str();
-	LLWString asterix_text;
-	if (mDrawAsterixes)
-	{
-		for (S32 i = 0; i < mText.length(); i++)
-		{
-			asterix_text += utf8str_to_wstring(PASSWORD_ASTERISK);
-		}
-		wtext = asterix_text.c_str();
-	}
+	S32 cursor_pos = calcCursorPos(local_mouse_x);
 
-	S32 cursor_pos =
-		mScrollHPos + 
-		mGLFont->charFromPixelOffset(
-			wtext, mScrollHPos,
-			(F32)(local_mouse_x - mTextLeftEdge),
-			(F32)(mTextRightEdge - mTextLeftEdge + 1)); // min-max range is inclusive
+	S32 left_pos = llmin( mSelectionStart, cursor_pos );
+	S32 length = llabs( mSelectionStart - cursor_pos );
+	const LLWString& substr = mText.getWString().substr(left_pos, length);
+
+	if (mIsSelecting && !prevalidateInput(substr))
+		return;
+
 	setCursor(cursor_pos);
 }
 
 
 void LLLineEditor::selectAll()
 {
+	if (!prevalidateInput(mText.getWString()))
+	{
+		return;
+	}
+
 	mSelectionStart = mText.length();
 	mSelectionEnd = 0;
 	setCursor(mSelectionEnd);
 
 		if (mask & MASK_SHIFT)
 		{
+			// assume we're starting a drag select
+			mIsSelecting = TRUE;
+
 			// Handle selection extension
 			S32 old_cursor_pos = getCursor();
 			setCursorAtLocalPos(x);
 				mSelectionStart = old_cursor_pos;
 				mSelectionEnd = getCursor();
 			}
-			// assume we're starting a drag select
-			mIsSelecting = TRUE;
 		}
 		else
 		{
 {
 	if( getCursor() > 0 )
 	{
+		if (!prevalidateInput(mText.getWString().substr(getCursor()-1, 1)))
+			return;
+
 		mText.erase(getCursor() - 1, 1);
 
 		setCursor(getCursor() - 1);
 	}
 	else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
 	{
+		if (!prevalidateInput(mText.getWString().substr(getCursor(), 1)))
+			return;
+
 		mText.erase(getCursor(), 1);
 	}
 
 		startSelection();
 	}
 	
+	S32 left_pos = llmin( mSelectionStart, new_cursor_pos );
+	S32 selection_length = llabs( mSelectionStart - new_cursor_pos );
+	const LLWString& selection = mText.getWString().substr(left_pos, selection_length);
+
+	if (!prevalidateInput(selection))
+		return;
+
 	setCursor(new_cursor_pos);
 	mSelectionEnd = getCursor();
 }
 {
 	if( !mReadOnly && hasSelection() )
 	{
-		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
-		S32 selection_length = llabs( mSelectionStart - mSelectionEnd );
+		S32 left_pos, selection_length;
+		getSelectionRange(&left_pos, &selection_length);
+		const LLWString& selection = mText.getWString().substr(left_pos, selection_length);
+
+		if (!prevalidateInput(selection))
+			return;
 
 		mText.erase(left_pos, selection_length);
 		deselect();
 {
 	if( canCut() )
 	{
+		S32 left_pos, length;
+		getSelectionRange(&left_pos, &length);
+		const LLWString& selection = mText.getWString().substr(left_pos, length);
+
+		if (!prevalidateInput(selection))
+			return;
+
 		// Prepare for possible rollback
 		LLLineEditorRollback rollback( this );
 
-
-		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
-		S32 length = llabs( mSelectionStart - mSelectionEnd );
 		gClipboard.copyFromSubstring( mText.getWString(), left_pos, length );
 		deleteSelection();
 
 
 		if (!paste.empty())
 		{
+			if (!prevalidateInput(paste))
+				return;
+
 			// Prepare for possible rollback
 			LLLineEditorRollback rollback(this);
 			
 
 		LLLineEditorRollback rollback( this );
 
+		{
+			LLWString u_char;
+			u_char.assign(1, uni_char);
+			if (!prevalidateInput(u_char))
+				return handled;
+		}
+
 		addChar(uni_char);
 
 		mKeystrokeTimer.reset();
 		}
 		else if ( getCursor() < mText.length())
 		{	
+			const LLWString& text_to_delete = mText.getWString().substr(getCursor(), 1);
+
+			if (!prevalidateInput(text_to_delete))
+			{
+				if( mKeystrokeCallback )
+					mKeystrokeCallback( this );
+
+				return;
+			}
 			setCursor(getCursor() + 1);
 			removeChar();
 		}
 	return result;
 }
 
+S32 LLLineEditor::calcCursorPos(S32 mouse_x)
+{
+	const llwchar* wtext = mText.getWString().c_str();
+	LLWString asterix_text;
+	if (mDrawAsterixes)
+	{
+		for (S32 i = 0; i < mText.length(); i++)
+		{
+			asterix_text += utf8str_to_wstring(PASSWORD_ASTERISK);
+		}
+		wtext = asterix_text.c_str();
+	}
+
+	S32 cur_pos = mScrollHPos +
+			mGLFont->charFromPixelOffset(
+				wtext, mScrollHPos,
+				(F32)(mouse_x - mTextLeftEdge),
+				(F32)(mTextRightEdge - mTextLeftEdge + 1)); // min-max range is inclusive
+
+	return cur_pos;
+}
 //virtual
 void LLLineEditor::clear()
 {
 	updateAllowingLanguageInput();
 }
 
+void LLLineEditor::setPrevalidateInput(LLTextValidate::validate_func_t func)
+{
+	mPrevalidateInputFunc = func;
+	updateAllowingLanguageInput();
+}
+
+bool LLLineEditor::prevalidateInput(const LLWString& wstr)
+{
+	if (mPrevalidateInputFunc && !mPrevalidateInputFunc(wstr))
+	{
+		return false;
+	}
+
+	return true;
+}
+
 // static
 BOOL LLLineEditor::postvalidateFloat(const std::string &str)
 {

indra/llui/lllineeditor.h

 		Optional<keystroke_callback_t>	keystroke_callback;
 
 		Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs>	prevalidate_callback;
+		Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs>	prevalidate_input_callback;
 		
 		Optional<LLViewBorder::Params>	border;
 
 
 	// Prevalidation controls which keystrokes can affect the editor
 	void			setPrevalidate( LLTextValidate::validate_func_t func );
+	// This method sets callback that prevents from:
+	// - deleting, selecting, typing, cutting, pasting characters that are not valid.
+	// Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed
+	// symbols, before existing text is modified, but setPrevalidate validates line after it was modified.
+	void			setPrevalidateInput(LLTextValidate::validate_func_t func);
 	static BOOL		postvalidateFloat(const std::string &str);
 
+	bool			prevalidateInput(const LLWString& wstr);
+
 	// line history support:
 	void			setEnableLineHistory( BOOL enabled ) { mHaveHistory = enabled; } // switches line history on or off 
 	void			updateHistory(); // stores current line in history
 	void			addChar(const llwchar c);
 	void			setCursorAtLocalPos(S32 local_mouse_x);
 	S32				findPixelNearestPos(S32 cursor_offset = 0) const;
+	S32				calcCursorPos(S32 mouse_x);
 	BOOL			handleSpecialKey(KEY key, MASK mask);
 	BOOL			handleSelectionKey(KEY key, MASK mask);
 	BOOL			handleControlKey(KEY key, MASK mask);
 	S32			mLastSelectionEnd;
 
 	LLTextValidate::validate_func_t mPrevalidateFunc;
+	LLTextValidate::validate_func_t mPrevalidateInputFunc;
 
 	LLFrameTimer mKeystrokeTimer;
 	LLTimer		mTripleClickTimer;

indra/llui/llmultislider.cpp

 				mIt->second.mTop + extra_triangle_height,
 				mIt->second.mLeft + mIt->second.getWidth() / 2, 
 				mIt->second.mBottom - extra_triangle_height,
-				mTriangleColor.get(), TRUE);
+				mTriangleColor.get() % opacity, TRUE);
 		}
 	}
 	else if (!thumb_imagep)

indra/llui/lltextvalidate.cpp

 		return success;
 	}
 
+	bool validateNonNegativeS32NoSpace(const LLWString &str)
+	{
+		LLLocale locale(LLLocale::USER_LOCALE);
+
+		LLWString test_str = str;
+		S32 len = test_str.length();
+		bool success = TRUE;
+		if(0 < len)
+		{
+			if('-' == test_str[0])
+			{
+				success = FALSE;
+			}
+			S32 i = 0;
+			while(success && (i < len))
+			{
+				if(!LLStringOps::isDigit(test_str[i]) || LLStringOps::isSpace(test_str[i++]))
+				{
+					success = FALSE;
+				}
+			}
+		}
+		if (success)
+		{
+			S32 val = strtol(wstring_to_utf8str(test_str).c_str(), NULL, 10);
+			if (val < 0)
+			{
+				success = FALSE;
+			}
+		}
+		return success;
+	}
+
 	bool validateAlphaNum(const LLWString &str)
 	{
 		LLLocale locale(LLLocale::USER_LOCALE);

indra/llui/lltextvalidate.h

 	bool	validateInt(const LLWString &str );
 	bool	validatePositiveS32(const LLWString &str);
 	bool	validateNonNegativeS32(const LLWString &str);
+	bool 	validateNonNegativeS32NoSpace(const LLWString &str);
 	bool	validateAlphaNum(const LLWString &str );
 	bool	validateAlphaNumSpace(const LLWString &str );
 	bool	validateASCIIPrintableNoPipe(const LLWString &str); 

indra/llui/lltimectrl.cpp

+/**
+ * @file lltimectrl.cpp
+ * @brief LLTimeCtrl base class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lltimectrl.h"
+
+#include "llui.h"
+#include "lluiconstants.h"
+
+#include "llbutton.h"
+#include "llfontgl.h"
+#include "lllineeditor.h"
+#include "llkeyboard.h"
+#include "llstring.h"
+#include "lltextbox.h"
+#include "lluictrlfactory.h"
+
+static LLDefaultChildRegistry::Register<LLTimeCtrl> time_r("time");
+
+const U32 AMPM_LEN = 3;
+const U32 MINUTES_MIN = 0;
+const U32 MINUTES_MAX = 59;
+const U32 HOURS_MIN = 1;
+const U32 HOURS_MAX = 12;
+const U32 MINUTES_PER_HOUR = 60;
+const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR;
+
+
+LLTimeCtrl::Params::Params()
+:	label_width("label_width"),
+	snap_to("snap_to"),
+	allow_text_entry("allow_text_entry", true),
+	text_enabled_color("text_enabled_color"),
+	text_disabled_color("text_disabled_color"),
+	up_button("up_button"),
+	down_button("down_button")
+{}
+
+LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p)
+:	LLUICtrl(p),
+	mLabelBox(NULL),
+	mTextEnabledColor(p.text_enabled_color()),
+	mTextDisabledColor(p.text_disabled_color()),
+	mTime(0),
+	mSnapToMin(5)
+{
+	static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
+	static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
+	static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
+	S32 centered_top = getRect().getHeight();
+	S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height;
+	S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40));
+	S32 editor_left = label_width + spinctrl_spacing;
+
+	//================= Label =================//
+	if( !p.label().empty() )
+	{
+		LLRect label_rect( 0, centered_top, label_width, centered_bottom );
+		LLTextBox::Params params;
+		params.name("TimeCtrl Label");
+		params.rect(label_rect);
+		params.initial_value(p.label());
+		if (p.font.isProvided())
+		{
+			params.font(p.font);
+		}
+		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
+		addChild(mLabelBox);
+
+		editor_left = label_rect.mRight + spinctrl_spacing;
+	}
+
+	S32 editor_right = getRect().getWidth() - spinctrl_btn_width - spinctrl_spacing;
+
+	//================= Editor ================//
+	LLRect editor_rect( editor_left, centered_top, editor_right, centered_bottom );
+	LLLineEditor::Params params;
+	params.name("SpinCtrl Editor");
+	params.rect(editor_rect);
+	if (p.font.isProvided())
+	{
+		params.font(p.font);
+	}
+
+	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
+	params.max_length.chars(8);
+	params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1));
+	mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
+	mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace);
+	mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1));
+	mEditor->setText(LLStringExplicit("12:00 AM"));
+	addChild(mEditor);
+
+	//================= Spin Buttons ==========//
+	LLButton::Params up_button_params(p.up_button);
+	up_button_params.rect = LLRect(editor_right + 1, getRect().getHeight(), editor_right + spinctrl_btn_width, getRect().getHeight() - spinctrl_btn_height);
+
+	up_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
+	up_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
+	mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
+	addChild(mUpBtn);
+
+	LLButton::Params down_button_params(p.down_button);
+	down_button_params.rect = LLRect(editor_right + 1, getRect().getHeight() - spinctrl_btn_height, editor_right + spinctrl_btn_width, getRect().getHeight() - 2 * spinctrl_btn_height);
+	down_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
+	down_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
+	mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
+	addChild(mDownBtn);
+
+	setUseBoundingRect( TRUE );
+}
+
+F32 LLTimeCtrl::getTime24() const
+{
+	// 0.0 - 23.99;
+	return mTime / 60.0f;
+}
+
+U32 LLTimeCtrl::getHours24() const
+{
+	return (U32) getTime24();
+}
+
+U32 LLTimeCtrl::getMinutes() const
+{
+	return mTime % MINUTES_PER_HOUR;
+}
+
+void LLTimeCtrl::setTime24(F32 time)
+{
+	time = llclamp(time, 0.0f, 23.99f); // fix out of range values
+	mTime = llround(time * MINUTES_PER_HOUR); // fixes values like 4.99999
+
+	updateText();
+}
+
+BOOL LLTimeCtrl::handleKeyHere(KEY key, MASK mask)
+{
+	if (mEditor->hasFocus())
+	{
+		if(key == KEY_UP)
+		{
+			onUpBtn();
+			return TRUE;
+		}
+		if(key == KEY_DOWN)
+		{
+			onDownBtn();
+			return TRUE;
+		}
+		if (key == KEY_RETURN)
+		{
+			onCommit();
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+void LLTimeCtrl::onUpBtn()
+{
+	switch(getEditingPart())
+	{
+	case HOURS:
+		increaseHours();
+		break;
+	case MINUTES:
+		increaseMinutes();
+		break;
+	case DAYPART:
+		switchDayPeriod();
+		break;
+	default:
+		break;
+	}
+
+	updateText();
+	onCommit();
+}
+
+void LLTimeCtrl::onDownBtn()
+{
+	switch(getEditingPart())
+	{
+	case HOURS:
+		decreaseHours();
+		break;
+	case MINUTES:
+		decreaseMinutes();
+		break;
+	case DAYPART:
+		switchDayPeriod();
+		break;
+	default:
+		break;
+	}
+
+	updateText();
+	onCommit();
+}
+
+void LLTimeCtrl::onFocusLost()
+{
+	updateText();
+	onCommit();
+	LLUICtrl::onFocusLost();
+}
+
+void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor)
+{
+	std::string time_str = line_editor->getText();
+	U32 h12 = parseHours(getHoursString(time_str));
+	U32 m = parseMinutes(getMinutesString(time_str));
+	bool pm = parseAMPM(getAMPMString(time_str));
+
+	if (h12 == 12)
+	{
+		h12 = 0;
+	}
+
+	U32 h24 = pm ? h12 + 12 : h12;
+
+	mTime = h24 * MINUTES_PER_HOUR + m;
+}
+
+bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr)
+{
+	std::string str = wstring_to_utf8str(wstr);
+
+	return isHoursStringValid(getHoursString(str)) &&
+		isMinutesStringValid(getMinutesString(str)) &&
+		isPMAMStringValid(getAMPMString(str));
+}
+
+void LLTimeCtrl::increaseMinutes()
+{
+	mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin);
+}
+
+void LLTimeCtrl::increaseHours()
+{
+	mTime = (mTime + MINUTES_PER_HOUR) % MINUTES_PER_DAY;
+}
+
+void LLTimeCtrl::decreaseMinutes()
+{
+	if (mTime < mSnapToMin)
+	{
+		mTime = MINUTES_PER_DAY - mTime;
+	}
+
+	mTime -= (mTime % mSnapToMin) ? mTime % mSnapToMin : mSnapToMin;
+}
+
+void LLTimeCtrl::decreaseHours()
+{
+	if (mTime < MINUTES_PER_HOUR)
+	{
+		mTime = 23 * MINUTES_PER_HOUR + mTime;
+	}
+	else
+	{
+		mTime -= MINUTES_PER_HOUR;
+	}
+}
+
+bool LLTimeCtrl::isPM() const
+{
+	return mTime >= (MINUTES_PER_DAY / 2);
+}
+
+void LLTimeCtrl::switchDayPeriod()
+{
+	if (isPM())
+	{
+		mTime -= MINUTES_PER_DAY / 2;
+	}
+	else
+	{
+		mTime += MINUTES_PER_DAY / 2;
+	}
+}
+
+void LLTimeCtrl::updateText()
+{
+	U32 h24 = getHours24();
+	U32 m = getMinutes();
+	U32 h12 = h24 > 12 ? h24 - 12 : h24;
+
+	if (h12 == 0)
+		h12 = 12;
+
+	mEditor->setText(llformat("%d:%02d %s", h12, m, isPM() ? "PM":"AM"));
+}
+
+LLTimeCtrl::EEditingPart LLTimeCtrl::getEditingPart()
+{
+	S32 cur_pos = mEditor->getCursor();
+	std::string time_str = mEditor->getText();
+
+	S32 colon_index = time_str.find_first_of(':');
+
+	if (cur_pos <= colon_index)
+	{
+		return HOURS;
+	}
+	else if (cur_pos > colon_index && cur_pos <= (S32)(time_str.length() - AMPM_LEN))
+	{
+		return MINUTES;
+	}
+	else if (cur_pos > (S32)(time_str.length() - AMPM_LEN))
+	{
+		return DAYPART;
+	}
+
+	return NONE;
+}
+
+// static
+std::string LLTimeCtrl::getHoursString(const std::string& str)
+{
+	size_t colon_index = str.find_first_of(':');
+	std::string hours_str = str.substr(0, colon_index);
+
+	return hours_str;
+}
+
+// static
+std::string LLTimeCtrl::getMinutesString(const std::string& str)
+{
+	size_t colon_index = str.find_first_of(':');
+	++colon_index;
+
+	int minutes_len = str.length() - colon_index - AMPM_LEN;
+	std::string minutes_str = str.substr(colon_index, minutes_len);
+
+	return minutes_str;
+}
+
+// static
+std::string LLTimeCtrl::getAMPMString(const std::string& str)
+{
+	return str.substr(str.size() - 2, 2); // returns last two characters
+}
+
+// static
+bool LLTimeCtrl::isHoursStringValid(const std::string& str)
+{
+	U32 hours;
+	if ((!LLStringUtil::convertToU32(str, hours) || (hours <= HOURS_MAX)) && str.length() < 3)
+		return true;
+
+	return false;
+}
+
+// static
+bool LLTimeCtrl::isMinutesStringValid(const std::string& str)
+{
+	U32 minutes;
+	if (!LLStringUtil::convertToU32(str, minutes) || (minutes <= MINUTES_MAX) && str.length() < 3)
+		return true;
+
+	return false;
+}
+
+// static
+bool LLTimeCtrl::isPMAMStringValid(const std::string& str)
+{
+	S32 len = str.length();
+
+	bool valid = (str[--len] == 'M') && (str[--len] == 'P' || str[len] == 'A');
+
+	return valid;
+}
+
+// static
+U32 LLTimeCtrl::parseHours(const std::string& str)
+{
+	U32 hours;
+	if (LLStringUtil::convertToU32(str, hours) && (hours >= HOURS_MIN) && (hours <= HOURS_MAX))
+	{
+		return hours;
+	}
+	else
+	{
+		return HOURS_MIN;
+	}
+}
+
+// static
+U32 LLTimeCtrl::parseMinutes(const std::string& str)
+{
+	U32 minutes;
+	if (LLStringUtil::convertToU32(str, minutes) && (minutes >= MINUTES_MIN) && (minutes <= MINUTES_MAX))
+	{
+		return minutes;
+	}
+	else
+	{
+		return MINUTES_MIN;
+	}
+}
+
+// static
+bool LLTimeCtrl::parseAMPM(const std::string& str)
+{
+	return str == "PM";
+}

indra/llui/lltimectrl.h

+/**
+ * @file lltimectrl.h
+ * @brief Time control
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLTIMECTRL_H_
+#define LLTIMECTRL_H_
+
+#include "stdtypes.h"
+#include "llbutton.h"
+#include "v4color.h"
+#include "llrect.h"
+
+class LLLineEditor;
+
+class LLTimeCtrl
+: public LLUICtrl
+{
+	LOG_CLASS(LLTimeCtrl);
+public:
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<S32> label_width;
+		Optional<S32> snap_to;
+		Optional<bool> allow_text_entry;
+
+		Optional<LLUIColor> text_enabled_color;
+		Optional<LLUIColor> text_disabled_color;
+
+		Optional<LLButton::Params> up_button;
+		Optional<LLButton::Params> down_button;
+
+		Params();
+	};
+
+	F32 getTime24() const;		// 0.0 - 24.0
+	U32 getHours24() const;		// 0 - 23
+	U32 getMinutes() const;		// 0 - 59
+
+	void setTime24(F32 time);	// 0.0 - 23.98(3)
+
+protected:
+	LLTimeCtrl(const Params&);
+	friend class LLUICtrlFactory;
+
+private:
+
+	enum EDayPeriod
+	{
+		AM,
+		PM
+	};
+
+	enum EEditingPart
+	{
+		HOURS,
+		MINUTES,
+		DAYPART,
+		NONE
+	};
+
+	virtual void	onFocusLost();
+	virtual BOOL	handleKeyHere(KEY key, MASK mask);
+
+	void	onUpBtn();
+	void	onDownBtn();
+	void	onTextEntry(LLLineEditor* line_editor);
+
+	bool	isTimeStringValid(const LLWString& wstr);
+
+	void increaseMinutes();
+	void increaseHours();
+
+	void decreaseMinutes();
+	void decreaseHours();
+
+	bool isPM() const;
+	void switchDayPeriod();
+
+	void updateText();
+
+	EEditingPart getEditingPart();
+
+	static std::string getHoursString(const std::string& str);
+	static std::string getMinutesString(const std::string& str);
+	static std::string getAMPMString(const std::string& str);
+
+	static bool isHoursStringValid(const std::string& str);
+	static bool isMinutesStringValid(const std::string& str);
+	static bool isPMAMStringValid(const std::string& str);
+
+	static U32		parseHours(const std::string& str);
+	static U32		parseMinutes(const std::string& str);
+	static bool		parseAMPM(const std::string& str);
+
+	class LLTextBox*	mLabelBox;
+
+	class LLLineEditor*	mEditor;
+	LLUIColor			mTextEnabledColor;
+	LLUIColor			mTextDisabledColor;
+
+	class LLButton*		mUpBtn;
+	class LLButton*		mDownBtn;
+
+	U32				mTime;				// minutes since midnight: 0 - 1439
+	U32				mSnapToMin;			// interval in minutes to snap to
+
+	BOOL			mAllowEdit;
+};
+#endif /* LLTIMECTRL_H_ */

indra/newview/CMakeLists.txt

     llchiclet.cpp
     llclassifiedinfo.cpp
     llclassifiedstatsresponder.cpp
-    llcloud.cpp
     llcofwearables.cpp
     llcolorswatch.cpp
     llcommanddispatcherlistener.cpp
     llcurrencyuimanager.cpp
     llcylinder.cpp
     lldateutil.cpp
+    lldaycyclemanager.cpp
     lldebugmessagebox.cpp
     lldebugview.cpp
     lldelayedgestureerror.cpp
     lldrawpoolwlsky.cpp
     lldriverparam.cpp
     lldynamictexture.cpp
+    llenvmanager.cpp
     llemote.cpp
     lleventnotifier.cpp
     lleventpoll.cpp
     llfloaterbuyland.cpp
     llfloatercamera.cpp
     llfloatercolorpicker.cpp
-    llfloaterdaycycle.cpp
+    llfloaterdeleteenvpreset.cpp
     llfloaterdisplayname.cpp
-    llfloaterenvsettings.cpp
+    llfloatereditdaycycle.cpp
+    llfloatereditsky.cpp
+    llfloatereditwater.cpp
+    llfloaterenvironmentsettings.cpp
     llfloaterevent.cpp
     llfloaterfonttest.cpp
     llfloatergesture.cpp
     llfloateruipreview.cpp
     llfloaterurlentry.cpp
     llfloatervoiceeffect.cpp
-    llfloaterwater.cpp
     llfloaterwebcontent.cpp
     llfloaterwhitelistentry.cpp
-    llfloaterwindlight.cpp
     llfloaterwindowsize.cpp
     llfloaterworldmap.cpp
     llfolderview.cpp
     llproductinforequest.cpp
     llprogressview.cpp
     llrecentpeople.cpp
+    llregioninfomodel.cpp
     llregionposition.cpp
     llremoteparcelrequest.cpp
     llsavedsettingsglue.cpp
     llviewerfloaterreg.cpp
     llviewerfoldertype.cpp
     llviewergenericmessage.cpp
-    llviewergesture.cpp    
+    llviewergesture.cpp
     llviewerhelp.cpp
     llviewerhelputil.cpp
     llviewerhome.cpp
     llvoavatardefines.cpp
     llvoavatarself.cpp
     llvocache.cpp
-    llvoclouds.cpp
     llvograss.cpp
     llvoground.cpp
     llvoicecallhandler.cpp
     llwind.cpp
     llwlanimator.cpp
     llwldaycycle.cpp
+    llwlhandlers.cpp
     llwlparammanager.cpp
     llwlparamset.cpp
     llworld.cpp
     llchiclet.h
     llclassifiedinfo.h
     llclassifiedstatsresponder.h
-    llcloud.h
     llcofwearables.h
     llcolorswatch.h
     llcommanddispatcherlistener.h
     llcurrencyuimanager.h
     llcylinder.h
     lldateutil.h
+    lldaycyclemanager.h
     lldebugmessagebox.h
     lldebugview.h
     lldelayedgestureerror.h
     lldrawpoolalpha.h
     lldrawpoolavatar.h
     lldrawpoolbump.h
-    lldrawpoolclouds.h
     lldrawpoolground.h
     lldrawpoolsimple.h
     lldrawpoolsky.h
     lldriverparam.h
     lldynamictexture.h
     llemote.h
+    llenvmanager.h
     lleventnotifier.h
     lleventpoll.h
     llexpandabletextbox.h
     llfloaterbuyland.h
     llfloatercamera.h
     llfloatercolorpicker.h
-    llfloaterdaycycle.h
+    llfloaterdeleteenvpreset.h
     llfloaterdisplayname.h
-    llfloaterenvsettings.h
+    llfloatereditdaycycle.h
+    llfloatereditsky.h
+    llfloatereditwater.h
+    llfloaterenvironmentsettings.h
     llfloaterevent.h
     llfloaterfonttest.h
     llfloatergesture.h
     llfloateruipreview.h
     llfloaterurlentry.h
     llfloatervoiceeffect.h
-    llfloaterwater.h
     llfloaterwebcontent.h
     llfloaterwhitelistentry.h
-    llfloaterwindlight.h
     llfloaterwindowsize.h
     llfloaterworldmap.h
     llfolderview.h
     llproductinforequest.h
     llprogressview.h
     llrecentpeople.h
+    llregioninfomodel.h
     llregionposition.h
     llremoteparcelrequest.h
     llresourcedata.h
     llsurface.h
     llsurfacepatch.h
     llsyswellitem.h
-    llsyswellwindow.h    
+    llsyswellwindow.h
     lltable.h
     llteleporthistory.h
     llteleporthistorystorage.h
     llviewerfloaterreg.h
     llviewerfoldertype.h
     llviewergenericmessage.h
-    llviewergesture.h    
+    llviewergesture.h
     llviewerhelp.h
     llviewerhome.h
     llviewerinventory.h
     llvoavatardefines.h
     llvoavatarself.h
     llvocache.h
-    llvoclouds.h
     llvograss.h
     llvoground.h
     llvoicechannel.h
     llwind.h
     llwlanimator.h
     llwldaycycle.h
+    llwlhandlers.h
     llwlparammanager.h
     llwlparamset.h
     llworld.h
     # precompiled header configuration
     # llviewerprecompiledheaders.cpp generates
     # the .pch file.
-    # All sources added to viewer_SOURCE_FILES 
+    # All sources added to viewer_SOURCE_FILES
     # at this point use it.
     if(USE_PRECOMPILED_HEADERS)
         set_source_files_properties(llviewerprecompiledheaders.cpp
             )
         set(viewer_SOURCE_FILES "${viewer_SOURCE_FILES}" llviewerprecompiledheaders.cpp)
     endif(USE_PRECOMPILED_HEADERS)
-    
+
     # Add resource files to the project.
     # viewerRes.rc is the only buildable file, but
     # the rest are all dependencies of it.
     set_source_files_properties(${viewer_RESOURCE_FILES}
                                 PROPERTIES HEADER_FILE_ONLY TRUE)
 
-    set(viewer_RESOURCE_FILES 
-        res/viewerRes.rc 
+    set(viewer_RESOURCE_FILES
+        res/viewerRes.rc
         ${viewer_RESOURCE_FILES}
         )
 
 
     if (NOT STANDALONE)
         list(APPEND viewer_SOURCE_FILES ${viewer_RESOURCE_FILES})
-    endif (NOT STANDALONE)      
+    endif (NOT STANDALONE)
 
     find_library(DINPUT_LIBRARY dinput8 ${DIRECTX_LIBRARY_DIR})
     find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR})
         ${SHARED_LIB_STAGING_DIR}/Debug/libtcmalloc_minimal-debug.dll
         )
      endif(USE_GOOGLE_PERFTOOLS)
- 
+
 
     set(COPY_INPUT_DEPENDENCIES
       # The following commented dependencies are determined at variably at build time. Can't do this here.
         --grid=${GRID}
         --source=${CMAKE_CURRENT_SOURCE_DIR}
         --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat
-      DEPENDS 
+      DEPENDS
         ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
         stage_third_party_libs
         ${COPY_INPUT_DEPENDENCIES}
       COMMENT "Performing viewer_manifest copy"
       )
-    
-    add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${CMAKE_CFG_INTDIR}/copy_touched.bat) 
+
+    add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${CMAKE_CFG_INTDIR}/copy_touched.bat)
 
     add_dependencies(${VIEWER_BINARY_NAME} stage_third_party_libs llcommon copy_w_viewer_manifest)
-    
+
     if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
       add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
     endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
-        
-    add_dependencies(${VIEWER_BINARY_NAME} 
-      SLPlugin 
-      windows-updater 
+
+    add_dependencies(${VIEWER_BINARY_NAME}
+      SLPlugin
+      windows-updater