diff options
| author | Paul ProductEngine <pguslisty@productengine.com> | 2011-05-13 18:23:11 +0300 | 
|---|---|---|
| committer | Paul ProductEngine <pguslisty@productengine.com> | 2011-05-13 18:23:11 +0300 | 
| commit | 2d19b297a98d8be87c487f6b93e098dce9ca908c (patch) | |
| tree | fe7741b971bc3e4a8a2c9d1d5d41282cbc0fe00a /indra | |
| parent | 5e0fee32074643454ae3c947eae648c6333d7f48 (diff) | |
STORM-1202 FIXED Time spin control
Implemented time spin control which is like spin control, but shows and allows to edit time string in "hh:mm PM/AM" format.
Implemented according to the WLRS spec.
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/integration_tests/llui_libtest/llwidgetreg.cpp | 2 | ||||
| -rw-r--r-- | indra/llui/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llui/lllineeditor.cpp | 106 | ||||
| -rw-r--r-- | indra/llui/lllineeditor.h | 4 | ||||
| -rw-r--r-- | indra/llui/lltextvalidate.cpp | 33 | ||||
| -rw-r--r-- | indra/llui/lltextvalidate.h | 1 | ||||
| -rw-r--r-- | indra/llui/lltimectrl.cpp | 390 | ||||
| -rw-r--r-- | indra/llui/lltimectrl.h | 125 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/widgets/time.xml | 16 | 
9 files changed, 658 insertions, 21 deletions
| diff --git a/indra/integration_tests/llui_libtest/llwidgetreg.cpp b/indra/integration_tests/llui_libtest/llwidgetreg.cpp index 0d0d9fbff6..cbf6021119 100644 --- a/indra/integration_tests/llui_libtest/llwidgetreg.cpp +++ b/indra/integration_tests/llui_libtest/llwidgetreg.cpp @@ -49,6 +49,7 @@  #include "lltabcontainer.h"  #include "lltextbox.h"  #include "lltexteditor.h" +#include "lltimectrl.h"  #include "llflyoutbutton.h"  #include "llfiltereditor.h"  #include "lllayoutstack.h" @@ -92,6 +93,7 @@ void LLWidgetReg::initClass(bool register_widgets)  		//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"); diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 33ab2e93b5..72329c70fe 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -93,6 +93,7 @@ set(llui_SOURCE_FILES      lltextparser.cpp      lltextutil.cpp      lltextvalidate.cpp +    lltimectrl.cpp      lltransutil.cpp      lltoggleablemenu.cpp      lltooltip.cpp @@ -191,6 +192,7 @@ set(llui_HEADER_FILES      lltextparser.h      lltextutil.h      lltextvalidate.h +    lltimectrl.h      lltoggleablemenu.h      lltooltip.h      lltransutil.h diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index d99ee5a545..66c607e988 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -81,6 +81,7 @@ LLLineEditor::Params::Params()  :	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"), @@ -173,6 +174,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)  	updateTextPadding();  	setCursor(mText.length()); +	setPrevalidate(p.prevalidate_input_callback());  	setPrevalidate(p.prevalidate_callback());  	LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu> @@ -401,23 +403,16 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)  // 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 left_pos = llmin( mSelectionStart, cursor_pos ); +	S32 selection_length = llabs( mSelectionStart - cursor_pos ); +	const LLWString& text = mText.getWString(); +	const LLWString& substr = text.substr(left_pos, selection_length); + +	if (mPrevalidateInputFunc && mIsSelecting && !mPrevalidateInputFunc(substr)) +		return; -	S32 cursor_pos = -		mScrollHPos +  -		mGLFont->charFromPixelOffset( -			wtext, mScrollHPos, -			(F32)(local_mouse_x - mTextLeftEdge), -			(F32)(mTextRightEdge - mTextLeftEdge + 1)); // min-max range is inclusive  	setCursor(cursor_pos);  } @@ -501,6 +496,9 @@ BOOL LLLineEditor::canSelectAll() const  void LLLineEditor::selectAll()  { +	if (mPrevalidateInputFunc && !mPrevalidateInputFunc(mText.getWString())) +		return; +  	mSelectionStart = mText.length();  	mSelectionEnd = 0;  	setCursor(mSelectionEnd); @@ -586,6 +584,9 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)  		if (mask & MASK_SHIFT)  		{ +			// assume we're starting a drag select +			mIsSelecting = TRUE; +  			// Handle selection extension  			S32 old_cursor_pos = getCursor();  			setCursorAtLocalPos(x); @@ -620,8 +621,6 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)  				mSelectionStart = old_cursor_pos;  				mSelectionEnd = getCursor();  			} -			// assume we're starting a drag select -			mIsSelecting = TRUE;  		}  		else  		{ @@ -792,6 +791,9 @@ void LLLineEditor::removeChar()  {  	if( getCursor() > 0 )  	{ +		if (mPrevalidateInputFunc && !mPrevalidateInputFunc(mText.getWString().substr(getCursor()-1, 1))) +			return; +  		mText.erase(getCursor() - 1, 1);  		setCursor(getCursor() - 1); @@ -812,6 +814,9 @@ void LLLineEditor::addChar(const llwchar uni_char)  	}  	else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())  	{ +		if (mPrevalidateInputFunc && !mPrevalidateInputFunc(mText.getWString().substr(getCursor(), 1))) +			return; +  		mText.erase(getCursor(), 1);  	} @@ -860,6 +865,13 @@ void LLLineEditor::extendSelection( S32 new_cursor_pos )  		startSelection();  	} +	S32 left_pos = llmin( mSelectionStart, new_cursor_pos ); +	S32 selection_length = llabs( mSelectionStart - new_cursor_pos ); +	const LLWString& selection = mText.getWString(); + +	if ( mPrevalidateInputFunc && !mPrevalidateInputFunc(selection.substr(left_pos, selection_length))) +		return; +  	setCursor(new_cursor_pos);  	mSelectionEnd = getCursor();  } @@ -992,6 +1004,10 @@ void LLLineEditor::deleteSelection()  	{  		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  		S32 selection_length = llabs( mSelectionStart - mSelectionEnd ); +		const LLWString& selection = mText.getWString(); + +		if ( mPrevalidateInputFunc && !mPrevalidateInputFunc(selection.substr(left_pos, selection_length))) +			return;  		mText.erase(left_pos, selection_length);  		deselect(); @@ -1009,12 +1025,16 @@ void LLLineEditor::cut()  {  	if( canCut() )  	{ +		S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); +		S32 length = llabs( mSelectionStart - mSelectionEnd ); +		const LLWString& selection = mText.getWString(); + +		if ( mPrevalidateInputFunc && !mPrevalidateInputFunc(selection.substr(left_pos, length))) +			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(); @@ -1094,6 +1114,9 @@ void LLLineEditor::pasteHelper(bool is_primary)  		if (!paste.empty())  		{ +			if ( mPrevalidateInputFunc && !mPrevalidateInputFunc(paste) ) +				return; +  			// Prepare for possible rollback  			LLLineEditorRollback rollback(this); @@ -1441,6 +1464,11 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)  		LLLineEditorRollback rollback( this ); +		LLWString u_char; +		u_char.assign(1, uni_char); +		if (mPrevalidateInputFunc && !mPrevalidateInputFunc(u_char)) +			return handled; +  		addChar(uni_char);  		mKeystrokeTimer.reset(); @@ -1492,6 +1520,15 @@ void LLLineEditor::doDelete()  		}  		else if ( getCursor() < mText.length())  		{	 +			const LLWString& selection = mText.getWString(); + +			if ( mPrevalidateInputFunc && !mPrevalidateInputFunc(selection.substr(getCursor(), 1))) +			{ +				if( mKeystrokeCallback ) +					mKeystrokeCallback( this ); + +				return; +			}  			setCursor(getCursor() + 1);  			removeChar();  		} @@ -1839,6 +1876,27 @@ S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) const  	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()  { @@ -1932,6 +1990,12 @@ void LLLineEditor::setPrevalidate(LLTextValidate::validate_func_t func)  	updateAllowingLanguageInput();  } +void LLLineEditor::setPrevalidateInputText(LLTextValidate::validate_func_t func) +{ +	mPrevalidateInputFunc = func; +	updateAllowingLanguageInput(); +} +  // static  BOOL LLLineEditor::postvalidateFloat(const std::string &str)  { diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 7b5fa218f2..1e29fd0dbf 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -75,6 +75,7 @@ public:  		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; @@ -231,6 +232,7 @@ public:  	// Prevalidation controls which keystrokes can affect the editor  	void			setPrevalidate( LLTextValidate::validate_func_t func ); +	void			setPrevalidateInputText( LLTextValidate::validate_func_t func );  	static BOOL		postvalidateFloat(const std::string &str);  	// line history support: @@ -250,6 +252,7 @@ private:  	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); @@ -311,6 +314,7 @@ protected:  	S32			mLastSelectionEnd;  	LLTextValidate::validate_func_t mPrevalidateFunc; +	LLTextValidate::validate_func_t mPrevalidateInputFunc;  	LLFrameTimer mKeystrokeTimer;  	LLTimer		mTripleClickTimer; diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 4b9faa0560..234e600ccd 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -188,6 +188,39 @@ namespace LLTextValidate  		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); diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index 84644be30c..5c830d7db3 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -46,6 +46,7 @@ namespace LLTextValidate  	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);  diff --git a/indra/llui/lltimectrl.cpp b/indra/llui/lltimectrl.cpp new file mode 100644 index 0000000000..33e8db432f --- /dev/null +++ b/indra/llui/lltimectrl.cpp @@ -0,0 +1,390 @@ +/** + * @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; + +LLTimeCtrl::Params::Params() +:	label_width("label_width"), +	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()), +	mHours(HOURS_MIN), +	mMinutes(MINUTES_MIN) +{ +	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->setPrevalidateInputText(LLTextValidate::validateNonNegativeS32NoSpace); +	mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1)); +	mEditor->setText(LLStringExplicit("0: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 ); +} + +BOOL LLTimeCtrl::handleKeyHere(KEY key, MASK mask) +{ +	if (mEditor->hasFocus()) +	{ +		if(key == KEY_UP) +		{ +			onUpBtn(); +			return TRUE; +		} +		if(key == KEY_DOWN) +		{ +			onDownBtn(); +			return TRUE; +		} +	} +	return FALSE; +} + +void LLTimeCtrl::onUpBtn() +{ +	switch(getEditingPart()) +	{ +	case HOURS: +		increaseHours(); +		break; +	case MINUTES: +		increaseMinutes(); +		break; +	case DAYPART: +		switchDayPeriod(); +		break; +	default: +		break; +	} + +	buildTimeString(); +	mEditor->setText(mTimeString); +} + +void LLTimeCtrl::onDownBtn() +{ +	switch(getEditingPart()) +	{ +	case HOURS: +		decreaseHours(); +		break; +	case MINUTES: +		decreaseMinutes(); +		break; +	case DAYPART: +		switchDayPeriod(); +		break; +	default: +		break; +	} + +	buildTimeString(); +	mEditor->setText(mTimeString); +} + +void LLTimeCtrl::onFocusLost() +{ +	buildTimeString(); +	mEditor->setText(mTimeString); + +	LLUICtrl::onFocusLost(); +} + +void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor) +{ +	LLWString time_str = line_editor->getWText(); +	switch(getEditingPart()) +	{ +	case HOURS: +		validateHours(getHoursWString(time_str)); +		break; +	case MINUTES: +		validateMinutes(getMinutesWString(time_str)); +		break; +	default: +		break; +	} +} + +bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr) +{ +	if (!isHoursStringValid(getHoursWString(wstr)) || !isMinutesStringValid(getMinutesWString(wstr)) || !isPMAMStringValid(wstr)) +		return false; + +	return true; +} + +bool LLTimeCtrl::isHoursStringValid(const LLWString& wstr) +{ +	U32 hours; +	if ((!LLWStringUtil::convertToU32(wstr, hours) || (hours <= HOURS_MAX)) && wstr.length() < 3) +		return true; + +	return false; +} + +bool LLTimeCtrl::isMinutesStringValid(const LLWString& wstr) +{ +	U32 minutes; +	if (!LLWStringUtil::convertToU32(wstr, minutes) || (minutes <= MINUTES_MAX) && wstr.length() < 3) +		return true; + +	return false; +} + +void LLTimeCtrl::validateHours(const LLWString& wstr) +{ +	U32 hours; +	if (LLWStringUtil::convertToU32(wstr, hours) && (hours >= HOURS_MIN) && (hours <= HOURS_MAX)) +	{ +		mHours = hours; +	} +	else +	{ +		mHours = HOURS_MIN; +	} +} + +void LLTimeCtrl::validateMinutes(const LLWString& wstr) +{ +	U32 minutes; +	if (LLWStringUtil::convertToU32(wstr, minutes) && (minutes >= MINUTES_MIN) && (minutes <= MINUTES_MAX)) +	{ +		mMinutes = minutes; +	} +	else +	{ +		mMinutes = MINUTES_MIN; +	} +} + +bool LLTimeCtrl::isPMAMStringValid(const LLWString &wstr) +{ +	S32 len = wstr.length(); + +	bool valid = (wstr[--len] == 'M') && (wstr[--len] == 'P' || wstr[len] == 'A'); + +	return valid; +} + +LLWString LLTimeCtrl::getHoursWString(const LLWString& wstr) +{ +	size_t colon_index = wstr.find_first_of(':'); +	LLWString hours_str = wstr.substr(0, colon_index); + +	return hours_str; +} + +LLWString LLTimeCtrl::getMinutesWString(const LLWString& wstr) +{ +	size_t colon_index = wstr.find_first_of(':'); +	++colon_index; + +	int minutes_len = wstr.length() - colon_index - AMPM_LEN; +	LLWString minutes_str = wstr.substr(colon_index, minutes_len); + +	return minutes_str; +} + +void LLTimeCtrl::increaseMinutes() +{ +	if (++mMinutes > MINUTES_MAX) +	{ +		mMinutes = MINUTES_MIN; +	} +} + +void LLTimeCtrl::increaseHours() +{ +	if (++mHours > HOURS_MAX) +	{ +		mHours = HOURS_MIN; +	} +} + +void LLTimeCtrl::decreaseMinutes() +{ +	if (mMinutes-- == MINUTES_MIN) +	{ +		mMinutes = MINUTES_MAX; +	} +} + +void LLTimeCtrl::decreaseHours() +{ +	if (mHours-- == HOURS_MIN) +	{ +		mHours = HOURS_MAX; +		switchDayPeriod(); +	} +} + +void LLTimeCtrl::switchDayPeriod() +{ +	switch (mCurrentDayPeriod) +	{ +	case AM: +		mCurrentDayPeriod = PM; +		break; +	case PM: +		mCurrentDayPeriod = AM; +		break; +	} +} + +void LLTimeCtrl::buildTimeString() +{ +	std::stringstream time_buf; +	time_buf << mHours << ":"; + +	if (mMinutes < 10) +	{ +		time_buf << "0"; +	} + +	time_buf << mMinutes; +	time_buf << " "; + +	switch (mCurrentDayPeriod) +	{ +	case AM: +		time_buf << "AM"; +		break; +	case PM: +		time_buf << "PM"; +		break; +	} + +	mTimeString = time_buf.str(); +} + +LLTimeCtrl::EEditingPart LLTimeCtrl::getEditingPart() +{ +	S32 cur_pos = mEditor->getCursor(); +	LLWString time_str = mEditor->getWText(); + +	size_t colon_index = time_str.find_first_of(':'); + +	if (cur_pos <= colon_index) +	{ +		return HOURS; +	} +	else if (cur_pos > colon_index && cur_pos <= (time_str.length() - AMPM_LEN)) +	{ +		return MINUTES; +	} +	else if (cur_pos > (time_str.length() - AMPM_LEN)) +	{ +		return DAYPART; +	} + +	return NONE; +} diff --git a/indra/llui/lltimectrl.h b/indra/llui/lltimectrl.h new file mode 100644 index 0000000000..81d4477da4 --- /dev/null +++ b/indra/llui/lltimectrl.h @@ -0,0 +1,125 @@ +/** + * @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 +{ +public: +	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> +	{ +		Optional<S32> label_width; +		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(); +	}; +protected: +	LLTimeCtrl(const Params&); +	friend class LLUICtrlFactory; + +	U32 getHours() const	{ return mHours; } +	U32 getMinutes() const { return mMinutes; } + +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); + +	void	validateHours(const LLWString& wstr); +	void	validateMinutes(const LLWString& wstr); +	bool	isTimeStringValid(const LLWString& wstr); + +	bool	isPMAMStringValid(const LLWString& wstr); +	bool	isHoursStringValid(const LLWString& wstr); +	bool 	isMinutesStringValid(const LLWString& wstr); + +	LLWString getHoursWString(const LLWString& wstr); +	LLWString getMinutesWString(const LLWString& wstr); + +	void increaseMinutes(); +	void increaseHours(); + +	void decreaseMinutes(); +	void decreaseHours(); + +	void switchDayPeriod(); + +	void buildTimeString(); + +	EEditingPart getEditingPart(); + +	class LLTextBox*	mLabelBox; + +	class LLLineEditor*	mEditor; +	LLUIColor			mTextEnabledColor; +	LLUIColor			mTextDisabledColor; + +	class LLButton*		mUpBtn; +	class LLButton*		mDownBtn; + +	U32 			mHours; +	U32 			mMinutes; +	EDayPeriod 		mCurrentDayPeriod; + +	std::string	mTimeString; + +	BOOL			mAllowEdit; +}; +#endif /* LLTIMECTRL_H_ */ diff --git a/indra/newview/skins/default/xui/en/widgets/time.xml b/indra/newview/skins/default/xui/en/widgets/time.xml new file mode 100644 index 0000000000..b5bdd564a6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/time.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<time text_enabled_color="LabelTextColor" +         text_disabled_color="LabelDisabledColor" +         font="SansSerifSmall" +         label_width="40" > +  <time.up_button name="SpinCtrl Up" +                     image_unselected="Stepper_Up_Off" +                     image_selected="Stepper_Up_Press" +                     tab_stop="false" +                     follows="left|bottom" /> +  <time.down_button name="SpinCtrl Down" +                       image_unselected="Stepper_Down_Off" +                       image_selected="Stepper_Down_Press" +                       tab_stop="false" +                       follows="left|bottom" /> +</time> | 
