diff options
Diffstat (limited to 'indra/llui')
| -rw-r--r-- | indra/llui/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | indra/llui/llfloater.cpp | 69 | ||||
| -rw-r--r-- | indra/llui/llfloater.h | 13 | ||||
| -rw-r--r-- | indra/llui/llfolderview.cpp | 27 | ||||
| -rw-r--r-- | indra/llui/llfolderview.h | 11 | ||||
| -rw-r--r-- | indra/llui/llfolderviewitem.cpp | 1 | ||||
| -rw-r--r-- | indra/llui/lllineeditor.cpp | 57 | ||||
| -rw-r--r-- | indra/llui/lllineeditor.h | 7 | ||||
| -rw-r--r-- | indra/llui/llmenugl.cpp | 22 | ||||
| -rw-r--r-- | indra/llui/llmenugl.h | 3 | ||||
| -rw-r--r-- | indra/llui/llmultislider.cpp | 438 | ||||
| -rw-r--r-- | indra/llui/llmultislider.h | 52 | ||||
| -rw-r--r-- | indra/llui/llmultisliderctrl.cpp | 35 | ||||
| -rw-r--r-- | indra/llui/llmultisliderctrl.h | 28 | ||||
| -rw-r--r-- | indra/llui/llslider.cpp | 7 | ||||
| -rw-r--r-- | indra/llui/llslider.h | 4 | ||||
| -rw-r--r-- | indra/llui/llsliderctrl.cpp | 41 | ||||
| -rw-r--r-- | indra/llui/llsliderctrl.h | 4 | ||||
| -rw-r--r-- | indra/llui/llui.h | 5 | ||||
| -rw-r--r-- | indra/llui/llvirtualtrackball.cpp | 480 | ||||
| -rw-r--r-- | indra/llui/llvirtualtrackball.h | 160 | ||||
| -rw-r--r-- | indra/llui/llxyvector.cpp | 337 | ||||
| -rw-r--r-- | indra/llui/llxyvector.h | 122 | ||||
| -rw-r--r-- | indra/llui/tests/llurlentry_test.cpp | 5 | 
24 files changed, 1790 insertions, 142 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 2d2fa6588f..cce618487b 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -133,8 +133,10 @@ set(llui_SOURCE_FILES      llview.cpp      llviewquery.cpp      llviewereventrecorder.cpp +    llvirtualtrackball.cpp      llwindowshade.cpp      llxuiparser.cpp +    llxyvector.cpp      )  set(llui_HEADER_FILES @@ -250,8 +252,10 @@ set(llui_HEADER_FILES      llview.h      llviewereventrecorder.h      llviewquery.h +    llvirtualtrackball.h      llwindowshade.h      llxuiparser.h +    llxyvector.h      )  set_source_files_properties(${llui_HEADER_FILES} diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 42802cd339..e3bb36192c 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -37,6 +37,7 @@  #include "lluictrlfactory.h"  #include "llbutton.h"  #include "llcheckboxctrl.h" +#include "llcriticaldamp.h" // LLSmoothInterpolation  #include "lldir.h"  #include "lldraghandle.h"  #include "llfloaterreg.h" @@ -64,6 +65,10 @@  // use this to control "jumping" behavior when Ctrl-Tabbing  const S32 TABBED_FLOATER_OFFSET = 0; +const F32 LLFloater::CONTEXT_CONE_IN_ALPHA = 0.0f; +const F32 LLFloater::CONTEXT_CONE_OUT_ALPHA = 1.f; +const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f; +  namespace LLInitParam  {  	void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() @@ -2116,6 +2121,70 @@ void LLFloater::updateTitleButtons()  	}  } +void LLFloater::drawConeToOwner(F32 &context_cone_opacity, +                                F32 max_cone_opacity, +                                LLView *owner_view, +                                F32 fade_time, +                                F32 contex_cone_in_alpha, +                                F32 contex_cone_out_alpha) +{ +    if (owner_view +        && owner_view->isInVisibleChain() +        && hasFocus() +        && context_cone_opacity > 0.001f +        && gFocusMgr.childHasKeyboardFocus(this)) +    { +        // draw cone of context pointing back to owner (e.x. texture swatch) +        LLRect owner_rect; +        owner_view->localRectToOtherView(owner_view->getLocalRect(), &owner_rect, this); +        LLRect local_rect = getLocalRect(); + +        gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +        LLGLEnable(GL_CULL_FACE); +        gGL.begin(LLRender::QUADS); +        { +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); +            gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); +            gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); +            gGL.vertex2i(local_rect.mRight, local_rect.mTop); +            gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); +            gGL.vertex2i(local_rect.mLeft, local_rect.mTop); +            gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); +            gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); +            gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); + +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); +            gGL.vertex2i(local_rect.mRight, local_rect.mBottom); +            gGL.vertex2i(local_rect.mRight, local_rect.mTop); +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); +            gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); +            gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); + + +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); +            gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); +            gGL.vertex2i(local_rect.mRight, local_rect.mBottom); +            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); +            gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); +            gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); +        } +        gGL.end(); +    } + +    if (gFocusMgr.childHasMouseCapture(getDragHandle())) +    { +        context_cone_opacity = lerp(context_cone_opacity, max_cone_opacity, LLSmoothInterpolation::getInterpolant(fade_time)); +    } +    else +    { +        context_cone_opacity = lerp(context_cone_opacity, 0.f, LLSmoothInterpolation::getInterpolant(fade_time)); +    } +} +  void LLFloater::buildButtons(const Params& floater_params)  {  	static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 165f67499b..f8c04e8a2f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -395,6 +395,15 @@ protected:  	virtual void	updateTitleButtons(); +	// Draws a cone from this floater to parent floater or view (owner) +	// Modifies context_cone_opacity (interpolates according to fade time and returns new value) +	void			drawConeToOwner(F32 &context_cone_opacity, +									F32 max_cone_opacity, +									LLView *owner_view, +									F32 context_fade_time = CONTEXT_CONE_FADE_TIME, +									F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA, +									F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA); +  private:  	void			setForeground(BOOL b);	// called only by floaterview  	void			cleanupHandles(); // remove handles to dead floaters @@ -424,6 +433,10 @@ private:  	void			updateTransparency(LLView* view, ETypeTransparency transparency_type);  public: +	static const F32 CONTEXT_CONE_IN_ALPHA; +	static const F32 CONTEXT_CONE_OUT_ALPHA; +	static const F32 CONTEXT_CONE_FADE_TIME; +  	// Called when floater is opened, passes mKey  	// Public so external views or floaters can watch for this floater opening  	commit_signal_t mOpenSignal; diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index b05a9807d0..e718fcec46 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -148,7 +148,9 @@ LLFolderView::Params::Params()  :	title("title"),  	use_label_suffix("use_label_suffix"),  	allow_multiselect("allow_multiselect", true), +	allow_drag("allow_drag", true),  	show_empty_message("show_empty_message", true), +	suppress_folder_menu("suppress_folder_menu", false),  	use_ellipses("use_ellipses", false),      options_menu("options_menu", "")  { @@ -162,11 +164,13 @@ LLFolderView::LLFolderView(const Params& p)  	mScrollContainer( NULL ),  	mPopupMenuHandle(),  	mAllowMultiSelect(p.allow_multiselect), +	mAllowDrag(p.allow_drag),  	mShowEmptyMessage(p.show_empty_message),  	mShowFolderHierarchy(FALSE),  	mRenameItem( NULL ),  	mNeedsScroll( FALSE ),  	mUseLabelSuffix(p.use_label_suffix), +	mSuppressFolderMenu(p.suppress_folder_menu),  	mPinningSelectedItem(FALSE),  	mNeedsAutoSelect( FALSE ),  	mAutoSelectOverride(FALSE), @@ -1432,10 +1436,13 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )  	BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL;  	S32 count = mSelectedItems.size(); +  	LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); -	if (   handled +	bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected(); +	if ((handled  		&& ( count > 0 && (hasVisibleChildren()) ) // show menu only if selected items are visible -		&& menu ) +		&& menu ) && +		!hide_folder_menu)  	{  		if (mCallbackRegistrar)          { @@ -1449,7 +1456,7 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )  		if (mCallbackRegistrar)          {  			mCallbackRegistrar->popScope(); -	} +	    }  	}  	else  	{ @@ -1862,6 +1869,20 @@ void LLFolderView::updateMenu()  	}  } +bool LLFolderView::isFolderSelected() +{ +	selected_items_t::iterator item_iter; +	for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) +	{ +		LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*item_iter); +		if (folder != NULL) +		{ +			return true; +		} +	} +	return false; +} +  bool LLFolderView::selectFirstItem()  {  	for (folders_t::iterator iter = mFolders.begin(); diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 2926e160d0..6bb5e6c02e 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -90,9 +90,11 @@ public:  		Optional<std::string>   title;  		Optional<bool>			use_label_suffix,  								allow_multiselect, +								allow_drag,  								show_empty_message,  								use_ellipses, -								show_item_link_overlays; +								show_item_link_overlays, +								suppress_folder_menu;  		Mandatory<LLFolderViewModelInterface*>	view_model;  		Optional<LLFolderViewGroupedItemModel*> grouped_item_model;          Mandatory<std::string>   options_menu; @@ -123,6 +125,7 @@ public:  	void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); }  	bool getAllowMultiSelect() { return mAllowMultiSelect; } +	bool getAllowDrag() { return mAllowDrag; }  	// Close all folders in the view  	void closeAllFolders(); @@ -259,6 +262,8 @@ protected:  	void closeRenamer( void ); +	bool isFolderSelected(); +  	bool selectFirstItem();  	bool selectLastItem(); @@ -271,6 +276,7 @@ protected:  	selected_items_t				mSelectedItems;  	bool							mKeyboardSelection,  									mAllowMultiSelect, +									mAllowDrag,  									mShowEmptyMessage,  									mShowFolderHierarchy,  									mNeedsScroll, @@ -282,7 +288,8 @@ protected:  									mDragAndDropThisFrame,  									mShowItemLinkOverlays,  									mShowSelectionContext, -									mShowSingleSelection; +									mShowSingleSelection, +									mSuppressFolderMenu;  	// Renaming variables and methods  	LLFolderViewItem*				mRenameItem;  // The item currently being renamed diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 2de47f1a19..9a1f7de73b 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -557,6 +557,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )  			LLFolderView* root = getRoot();  		if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold()  +			&& root->getAllowDrag()  			&& root->getCurSelectedItem()  			&& root->startDrag())  		{ diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 3ad504d68d..70304cdfd2 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -96,6 +96,8 @@ LLLineEditor::Params::Params()  	ignore_tab("ignore_tab", true),  	is_password("is_password", false),  	cursor_color("cursor_color"), +	use_bg_color("use_bg_color", false), +	bg_color("bg_color"),  	text_color("text_color"),  	text_readonly_color("text_readonly_color"),  	text_tentative_color("text_tentative_color"), @@ -150,10 +152,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)  	mBgImageDisabled( p.background_image_disabled ),  	mBgImageFocused( p.background_image_focused ),  	mShowImageFocused( p.bg_image_always_focused ), +	mUseBgColor(p.use_bg_color),  	mHaveHistory(FALSE),  	mReplaceNewlinesWithSpaces( TRUE ),  	mLabel(p.label),  	mCursorColor(p.cursor_color()), +	mBgColor(p.bg_color()),  	mFgColor(p.text_color()),  	mReadOnlyFgColor(p.text_readonly_color()),  	mTentativeFgColor(p.text_tentative_color()), @@ -1688,37 +1692,42 @@ void LLLineEditor::doDelete()  void LLLineEditor::drawBackground()  { -	bool has_focus = hasFocus(); -	LLUIImage* image; -	if ( mReadOnly ) -	{ -		image = mBgImageDisabled; -	} -	else if ( has_focus || mShowImageFocused) +	F32 alpha = getCurrentTransparency(); +	if (mUseBgColor)  	{ -		image = mBgImageFocused; +		gl_rect_2d(getLocalRect(), mBgColor % alpha, TRUE);  	}  	else  	{ -		image = mBgImage; -	} - -	if (!image) return; -	 -	F32 alpha = getCurrentTransparency(); +		bool has_focus = hasFocus(); +		LLUIImage* image; +		if (mReadOnly) +		{ +			image = mBgImageDisabled; +		} +		else if (has_focus || mShowImageFocused) +		{ +			image = mBgImageFocused; +		} +		else +		{ +			image = mBgImage; +		} -	// optionally draw programmatic border -	if (has_focus) -	{ -		LLColor4 tmp_color = gFocusMgr.getFocusColor(); +		if (!image) return; +		// optionally draw programmatic border +		if (has_focus) +		{ +			LLColor4 tmp_color = gFocusMgr.getFocusColor(); +			tmp_color.setAlpha(alpha); +			image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), +				tmp_color, +				gFocusMgr.getFocusFlashWidth()); +		} +		LLColor4 tmp_color = UI_VERTEX_COLOR;  		tmp_color.setAlpha(alpha); -		image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), -						  tmp_color, -						  gFocusMgr.getFocusFlashWidth()); +		image->draw(getLocalRect(), tmp_color);  	} -	LLColor4 tmp_color = UI_VERTEX_COLOR; -	tmp_color.setAlpha(alpha); -	image->draw(getLocalRect(), tmp_color);  }  void LLLineEditor::draw() diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index f775d53e63..aa5779d45f 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -91,10 +91,12 @@ public:  										commit_on_focus_lost,  										ignore_tab,  										bg_image_always_focused, -										is_password; +										is_password, +										use_bg_color;  		// colors  		Optional<LLUIColor>				cursor_color, +										bg_color,  										text_color,  										text_readonly_color,  										text_tentative_color, @@ -368,6 +370,7 @@ protected:  	LLTimer		mTripleClickTimer;  	LLUIColor	mCursorColor; +	LLUIColor	mBgColor;  	LLUIColor	mFgColor;  	LLUIColor	mReadOnlyFgColor;  	LLUIColor	mTentativeFgColor; @@ -388,6 +391,8 @@ protected:  	BOOL 		mShowImageFocused; +	bool		mUseBgColor; +  	LLWString	mPreeditWString;  	LLWString	mPreeditOverwrittenWString;  	std::vector<S32> mPreeditPositions; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 732fa9feb1..5568a84494 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -2723,6 +2723,15 @@ void LLMenuGL::setItemVisible( const std::string& name, BOOL visible )  	}  } + +void LLMenuGL::setItemLabel(const std::string &name, const std::string &label) +{ +    LLMenuItemGL *item = getItem(name); + +    if (item) +        item->setLabel(label); +} +  void LLMenuGL::setItemLastSelected(LLMenuItemGL* item)  {  	if (getVisible()) @@ -2767,6 +2776,19 @@ LLMenuItemGL* LLMenuGL::getItem(S32 number)  	return NULL;  } +LLMenuItemGL* LLMenuGL::getItem(std::string name) +{ +    item_list_t::iterator item_iter; +    for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) +    { +        if ((*item_iter)->getName() == name) +        { +            return (*item_iter); +        } +    } +    return NULL; +} +  LLMenuItemGL* LLMenuGL::getHighlightedItem()  {  	item_list_t::iterator item_iter; diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 78f688642e..1f11f26192 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -468,6 +468,8 @@ public:  	void setEnabledSubMenus(BOOL enable);  	void setItemVisible( const std::string& name, BOOL visible); + +    void setItemLabel(const std::string &name, const std::string &label);  	// sets the left,bottom corner of menu, useful for popups  	void setLeftAndBottom(S32 left, S32 bottom); @@ -498,6 +500,7 @@ public:  	void			setItemLastSelected(LLMenuItemGL* item);	// must be in menu  	U32				getItemCount();				// number of menu items  	LLMenuItemGL*	getItem(S32 number);		// 0 = first item +    LLMenuItemGL*   getItem(std::string name);  	LLMenuItemGL*	getHighlightedItem();				  	LLMenuItemGL*	highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index 0aa3e17075..acfe4a0cba 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -54,13 +54,18 @@ LLMultiSlider::SliderParams::SliderParams()  LLMultiSlider::Params::Params()  :	max_sliders("max_sliders", 1),  	allow_overlap("allow_overlap", false), +	loop_overlap("loop_overlap", false), +	orientation("orientation"), +	overlap_threshold("overlap_threshold", 0),  	draw_track("draw_track", true),  	use_triangle("use_triangle", false),  	track_color("track_color"),  	thumb_disabled_color("thumb_disabled_color"), +	thumb_highlight_color("thumb_highlight_color"),  	thumb_outline_color("thumb_outline_color"),  	thumb_center_color("thumb_center_color"),  	thumb_center_selected_color("thumb_center_selected_color"), +	thumb_image("thumb_image"),  	triangle_color("triangle_color"),  	mouse_down_callback("mouse_down_callback"),  	mouse_up_callback("mouse_up_callback"), @@ -71,9 +76,9 @@ LLMultiSlider::Params::Params()  LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)  :	LLF32UICtrl(p),  	mMouseOffset( 0 ), -	mDragStartThumbRect( 0, getRect().getHeight(), p.thumb_width, 0 ),  	mMaxNumSliders(p.max_sliders),  	mAllowOverlap(p.allow_overlap), +	mLoopOverlap(p.loop_overlap),  	mDrawTrack(p.draw_track),  	mUseTriangle(p.use_triangle),  	mTrackColor(p.track_color()), @@ -83,12 +88,22 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)  	mDisabledThumbColor(p.thumb_disabled_color()),  	mTriangleColor(p.triangle_color()),  	mThumbWidth(p.thumb_width), +	mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),  	mMouseDownSignal(NULL),  	mMouseUpSignal(NULL)  {  	mValue.emptyMap();  	mCurSlider = LLStringUtil::null; -	 + +	if (mOrientation == HORIZONTAL) +	{ +		mDragStartThumbRect = LLRect(0, getRect().getHeight(), p.thumb_width, 0); +	} +	else +	{ +		mDragStartThumbRect = LLRect(0, p.thumb_width, getRect().getWidth(), 0); +	} +  	if (p.mouse_down_callback.isProvided())  	{  		setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); @@ -98,6 +113,15 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)  		setMouseUpCallback(initCommitCallback(p.mouse_up_callback));  	} +	if (p.overlap_threshold.isProvided() && p.overlap_threshold > mIncrement) +    { +        mOverlapThreshold = p.overlap_threshold - mIncrement; +    } +    else +    { +        mOverlapThreshold = 0; +    } +  	for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin();  		it != p.sliders.end();  		++it) @@ -111,6 +135,12 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)  			addSlider(it->value);  		}  	} + +	if (p.thumb_image.isProvided()) +	{ +		mThumbImagep = LLUI::getUIImage(p.thumb_image()); +	} +	mThumbHighlightColor = p.thumb_highlight_color.isProvided() ? p.thumb_highlight_color() : static_cast<LLUIColor>(gFocusMgr.getFocusColor());  }  LLMultiSlider::~LLMultiSlider() @@ -119,6 +149,16 @@ LLMultiSlider::~LLMultiSlider()  	delete mMouseUpSignal;  } +F32 LLMultiSlider::getNearestIncrement(F32 value) const +{ +    value = llclamp(value, mMinValue, mMaxValue); + +    // Round to nearest increment (bias towards rounding down) +    value -= mMinValue; +    value += mIncrement / 2.0001f; +    value -= fmod(value, mIncrement); +    return mMinValue + value; +}  void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event)  { @@ -127,13 +167,7 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from  		return;  	} -	value = llclamp( value, mMinValue, mMaxValue ); - -	// Round to nearest increment (bias towards rounding down) -	value -= mMinValue; -	value += mIncrement/2.0001f; -	value -= fmod(value, mIncrement); -	F32 newValue = mMinValue + value; +    F32 newValue = getNearestIncrement(value);  	// now, make sure no overlap  	// if we want that @@ -143,14 +177,40 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from  		// look at the current spot  		// and see if anything is there  		LLSD::map_iterator mIt = mValue.beginMap(); -		for(;mIt != mValue.endMap(); mIt++) { -			 -			F32 testVal = (F32)mIt->second.asReal() - newValue; -			if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD && -				mIt->first != name) { + +		// increment is our distance between points, use to eliminate round error +		F32 threshold = mOverlapThreshold + (mIncrement / 4); +		// If loop overlap is enabled, check if we overlap with points 'after' max value (project to lower) +		F32 loop_up_check = (mLoopOverlap && (value + threshold) > mMaxValue) ? (value + threshold - mMaxValue + mMinValue) : mMinValue - 1.0f; +		// If loop overlap is enabled, check if we overlap with points 'before' min value (project to upper) +		F32 loop_down_check = (mLoopOverlap && (value - threshold) < mMinValue) ? (value - threshold - mMinValue + mMaxValue) : mMaxValue + 1.0f; + +		for(;mIt != mValue.endMap(); mIt++) +		{ +			F32 locationVal = (F32)mIt->second.asReal(); +			// Check nearby values +			F32 testVal = locationVal - newValue; +			if (testVal > -threshold +				&& testVal < threshold +				&& mIt->first != name) +			{  				hit = true;  				break;  			} +			if (mLoopOverlap) +			{ +				// Check edge overlap values +				if (locationVal < loop_up_check) +				{ +					hit = true; +					break; +				} +				if (locationVal > loop_down_check) +				{ +					hit = true; +					break; +				} +			}  		}  		// if none found, stop @@ -170,13 +230,26 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from  	}  	F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue); +	if (mOrientation == HORIZONTAL) +	{ +		S32 left_edge = mThumbWidth/2; +		S32 right_edge = getRect().getWidth() - (mThumbWidth/2); -	S32 left_edge = mThumbWidth/2; -	S32 right_edge = getRect().getWidth() - (mThumbWidth/2); +		S32 x = left_edge + S32( t * (right_edge - left_edge) ); -	S32 x = left_edge + S32( t * (right_edge - left_edge) ); -	mThumbRects[name].mLeft = x - (mThumbWidth/2); -	mThumbRects[name].mRight = x + (mThumbWidth/2); +		mThumbRects[name].mLeft = x - (mThumbWidth / 2); +		mThumbRects[name].mRight = x + (mThumbWidth / 2); +	} +	else +	{ +		S32 bottom_edge = mThumbWidth/2; +		S32 top_edge = getRect().getHeight() - (mThumbWidth/2); + +		S32 x = bottom_edge + S32( t * (top_edge - bottom_edge) ); + +		mThumbRects[name].mTop = x + (mThumbWidth / 2); +		mThumbRects[name].mBottom = x - (mThumbWidth / 2); +	}  }  void LLMultiSlider::setValue(const LLSD& value) @@ -196,7 +269,11 @@ void LLMultiSlider::setValue(const LLSD& value)  F32 LLMultiSlider::getSliderValue(const std::string& name) const  { -	return (F32)mValue[name].asReal(); +	if (mValue.has(name)) +	{ +		return (F32)mValue[name].asReal(); +	} +	return 0;  }  void LLMultiSlider::setCurSlider(const std::string& name) @@ -206,6 +283,62 @@ void LLMultiSlider::setCurSlider(const std::string& name)  	}  } +F32 LLMultiSlider::getSliderValueFromPos(S32 xpos, S32 ypos) const +{ +    F32 t = 0; +    if (mOrientation == HORIZONTAL) +    { +        S32 left_edge = mThumbWidth / 2; +        S32 right_edge = getRect().getWidth() - (mThumbWidth / 2); + +        xpos += mMouseOffset; +        xpos = llclamp(xpos, left_edge, right_edge); + +        t = F32(xpos - left_edge) / (right_edge - left_edge); +    } +    else +    { +        S32 bottom_edge = mThumbWidth / 2; +        S32 top_edge = getRect().getHeight() - (mThumbWidth / 2); + +        ypos += mMouseOffset; +        ypos = llclamp(ypos, bottom_edge, top_edge); + +        t = F32(ypos - bottom_edge) / (top_edge - bottom_edge); +    } + +    return((t * (mMaxValue - mMinValue)) + mMinValue); +} + + +LLRect LLMultiSlider::getSliderThumbRect(const std::string& name) const +{ +    auto it = mThumbRects.find(name); +    if (it != mThumbRects.end()) +        return (*it).second; +    return LLRect(); +} + +void LLMultiSlider::setSliderThumbImage(const std::string &name) +{ +    if (!name.empty()) +    { +        mThumbImagep = LLUI::getUIImage(name); +    } +    else +        clearSliderThumbImage(); +} + +void LLMultiSlider::clearSliderThumbImage() +{ +    mThumbImagep = NULL; +} + +void LLMultiSlider::resetCurSlider() +{ +	mCurSlider = LLStringUtil::null; +} +  const std::string& LLMultiSlider::addSlider()  {  	return addSlider(mInitialValue); @@ -230,7 +363,14 @@ const std::string& LLMultiSlider::addSlider(F32 val)  	}  	// add a new thumb rect -	mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 ); +	if (mOrientation == HORIZONTAL) +	{ +		mThumbRects[newName.str()] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); +	} +	else +	{ +		mThumbRects[newName.str()] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); +	}  	// add the value and set the current slider to this one  	mValue.insert(newName.str(), initVal); @@ -242,21 +382,28 @@ const std::string& LLMultiSlider::addSlider(F32 val)  	return mCurSlider;  } -void LLMultiSlider::addSlider(F32 val, const std::string& name) +bool LLMultiSlider::addSlider(F32 val, const std::string& name)  {  	F32 initVal = val;  	if(mValue.size() >= mMaxNumSliders) { -		return; +		return false;  	}  	bool foundOne = findUnusedValue(initVal);  	if(!foundOne) { -		return; +		return false;  	}  	// add a new thumb rect -	mThumbRects[name] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 ); +	if (mOrientation == HORIZONTAL) +	{ +		mThumbRects[name] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); +	} +	else +	{ +		mThumbRects[name] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); +	}  	// add the value and set the current slider to this one  	mValue.insert(name, initVal); @@ -264,6 +411,8 @@ void LLMultiSlider::addSlider(F32 val, const std::string& name)  	// move the slider  	setSliderValue(mCurSlider, initVal, TRUE); + +	return true;  }  bool LLMultiSlider::findUnusedValue(F32& initVal) @@ -278,11 +427,13 @@ bool LLMultiSlider::findUnusedValue(F32& initVal)  		// look at the current spot  		// and see if anything is there +		F32 threshold = mAllowOverlap ? FLOAT_THRESHOLD : mOverlapThreshold + (mIncrement / 4);  		LLSD::map_iterator mIt = mValue.beginMap();  		for(;mIt != mValue.endMap(); mIt++) {  			F32 testVal = (F32)mIt->second.asReal() - initVal; -			if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD) { +			if(testVal > -threshold && testVal < threshold) +			{  				hit = true;  				break;  			} @@ -334,10 +485,15 @@ void LLMultiSlider::deleteSlider(const std::string& name)  void LLMultiSlider::clear()  { -	while(mThumbRects.size() > 0) { +	while(mThumbRects.size() > 0 && mValue.size() > 0) {  		deleteCurSlider();  	} +	if (mThumbRects.size() > 0 || mValue.size() > 0) +	{ +		LL_WARNS() << "Failed to fully clear Multi slider" << LL_ENDL; +	} +  	LLF32UICtrl::clear();  } @@ -345,14 +501,7 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)  {  	if( gFocusMgr.getMouseCapture() == this )  	{ -		S32 left_edge = mThumbWidth/2; -		S32 right_edge = getRect().getWidth() - (mThumbWidth/2); - -		x += mMouseOffset; -		x = llclamp( x, left_edge, right_edge ); - -		F32 t = F32(x - left_edge) / (right_edge - left_edge); -		setCurSliderValue(t * (mMaxValue - mMinValue) + mMinValue ); +		setCurSliderValue(getSliderValueFromPos(x, y));  		onCommit();  		getWindow()->setCursor(UI_CURSOR_ARROW); @@ -360,6 +509,24 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)  	}  	else  	{ +        if (getEnabled()) +        { +            mHoverSlider.clear(); +            std::map<std::string, LLRect>::iterator  mIt = mThumbRects.begin(); +            for (; mIt != mThumbRects.end(); mIt++) +            { +                if (mIt->second.pointInRect(x, y)) +                { +                    mHoverSlider = mIt->first; +                    break; +                } +            } +        } +        else +        { +            mHoverSlider.clear(); +        } +  		getWindow()->setCursor(UI_CURSOR_ARROW);  		LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL;		  	} @@ -416,20 +583,30 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)  			}  		} -		// Find the offset of the actual mouse location from the center of the thumb. -		if (mThumbRects[mCurSlider].pointInRect(x,y)) +		if (!mCurSlider.empty())  		{ -			mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x; -		} -		else -		{ -			mMouseOffset = 0; -		} +			// Find the offset of the actual mouse location from the center of the thumb. +			if (mThumbRects[mCurSlider].pointInRect(x,y)) +			{ +				if (mOrientation == HORIZONTAL) +				{ +					mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth / 2) - x; +				} +				else +				{ +					mMouseOffset = (mThumbRects[mCurSlider].mBottom + mThumbWidth / 2) - y; +				} +			} +			else +			{ +				mMouseOffset = 0; +			} -		// Start dragging the thumb -		// No handler needed for focus lost since this class has no state that depends on it. -		gFocusMgr.setMouseCapture( this ); -		mDragStartThumbRect = mThumbRects[mCurSlider];				 +			// Start dragging the thumb +			// No handler needed for focus lost since this class has no state that depends on it. +			gFocusMgr.setMouseCapture( this ); +			mDragStartThumbRect = mThumbRects[mCurSlider]; +		}  	}  	make_ui_sound("UISndClick"); @@ -462,6 +639,13 @@ BOOL	LLMultiSlider::handleKeyHere(KEY key, MASK mask)  	return handled;  } +/*virtual*/ +void LLMultiSlider::onMouseLeave(S32 x, S32 y, MASK mask) +{ +    mHoverSlider.clear(); +    LLF32UICtrl::onMouseLeave(x, y, mask); +} +  void LLMultiSlider::draw()  {  	static LLUICachedControl<S32> extra_triangle_height ("UIExtraTriangleHeight", 0); @@ -470,6 +654,7 @@ void LLMultiSlider::draw()  	std::map<std::string, LLRect>::iterator mIt;  	std::map<std::string, LLRect>::iterator curSldrIt; +	std::map<std::string, LLRect>::iterator hoverSldrIt;  	// Draw background and thumb. @@ -483,9 +668,18 @@ void LLMultiSlider::draw()  	// Track  	LLUIImagePtr thumb_imagep = LLUI::getUIImage("Rounded_Square"); -	static LLUICachedControl<S32> multi_track_height ("UIMultiTrackHeight", 0); -	S32 height_offset = (getRect().getHeight() - multi_track_height) / 2; -	LLRect track_rect(0, getRect().getHeight() - height_offset, getRect().getWidth(), height_offset ); +	static LLUICachedControl<S32> multi_track_height_width ("UIMultiTrackHeight", 0); +	S32 height_offset = 0; +	S32 width_offset = 0; +	if (mOrientation == HORIZONTAL) +	{ +		height_offset = (getRect().getHeight() - multi_track_height_width) / 2; +	} +	else +	{ +		width_offset = (getRect().getWidth() - multi_track_height_width) / 2; +	} +	LLRect track_rect(width_offset, getRect().getHeight() - height_offset, getRect().getWidth() - width_offset, height_offset);  	if(mDrawTrack) @@ -510,10 +704,11 @@ void LLMultiSlider::draw()  				mTriangleColor.get() % opacity, TRUE);  		}  	} -	else if (!thumb_imagep) +	else if (!thumb_imagep && !mThumbImagep)  	{  		// draw all the thumbs  		curSldrIt = mThumbRects.end(); +		hoverSldrIt = mThumbRects.end();  		for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {  			// choose the color @@ -522,15 +717,21 @@ void LLMultiSlider::draw()  				curSldrIt = mIt;  				continue; -				//curThumbColor = mThumbCenterSelectedColor; +			} +			if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this) +			{ +				// draw last, after current one +				hoverSldrIt = mIt; +				continue;  			}  			// the draw command  			gl_rect_2d(mIt->second, curThumbColor, TRUE);  		} -		// now draw the current slider -		if(curSldrIt != mThumbRects.end()) { +		// now draw the current and hover sliders +		if(curSldrIt != mThumbRects.end()) +		{  			gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor.get(), TRUE);  		} @@ -539,20 +740,57 @@ void LLMultiSlider::draw()  		{  			gl_rect_2d(mDragStartThumbRect, mThumbCenterColor.get() % opacity, FALSE);  		} +		else if (hoverSldrIt != mThumbRects.end()) +		{ +			gl_rect_2d(hoverSldrIt->second, mThumbCenterSelectedColor.get(), TRUE); +		}  	} -	else if( gFocusMgr.getMouseCapture() == this ) +	else  	{ -		// draw drag start -		thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); +		LLMouseHandler* capture = gFocusMgr.getMouseCapture(); +		if (capture == this) +		{ +			// draw drag start (ghost) +			if (mThumbImagep) +			{ +				mThumbImagep->draw(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); +			} +			else +			{ +				thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); +			} +		}  		// draw the highlight  		if (hasFocus())  		{ -			thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); +			if (!mCurSlider.empty()) +			{ +				if (mThumbImagep) +				{ +					mThumbImagep->drawBorder(mThumbRects[mCurSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth()); +				} +				else +				{ +					thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); +				} +			}  		} +        if (!mHoverSlider.empty()) +        { +            if (mThumbImagep) +            { +                mThumbImagep->drawBorder(mThumbRects[mHoverSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth()); +            } +            else +            { +                thumb_imagep->drawBorder(mThumbRects[mHoverSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); +            } +        }  		// draw the thumbs  		curSldrIt = mThumbRects.end(); +		hoverSldrIt = mThumbRects.end();  		for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++)   		{  			// choose the color @@ -563,46 +801,68 @@ void LLMultiSlider::draw()  				curSldrIt = mIt;  				continue;				  			} +			if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this)  +			{ +				// don't draw now, draw last, after current one +				hoverSldrIt = mIt; +				continue; +			}  			// the draw command -			thumb_imagep->drawSolid(mIt->second, curThumbColor); +			if (mThumbImagep) +			{ +				if (getEnabled()) +				{ +					mThumbImagep->draw(mIt->second); +				} +				else +				{ +					mThumbImagep->draw(mIt->second, LLColor4::grey % 0.8f); +				} +			} +			else if (capture == this) +			{ +				thumb_imagep->drawSolid(mIt->second, curThumbColor); +			} +			else +			{ +				thumb_imagep->drawSolid(mIt->second, curThumbColor % opacity); +			}  		} -		// draw cur slider last +		// draw cur and hover slider last  		if(curSldrIt != mThumbRects.end())   		{ -			thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get()); -		} -		 -	} -	else -	{  -		// draw highlight -		if (hasFocus()) -		{ -			thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); -		} - -		// draw thumbs -		curSldrIt = mThumbRects.end(); -		for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++)  -		{ -			 -			// choose the color -			curThumbColor = mThumbCenterColor.get(); -			if(mIt->first == mCurSlider)  +			if (mThumbImagep)  			{ -				curSldrIt = mIt; -				continue; -				//curThumbColor = mThumbCenterSelectedColor; -			}				 -			 -			thumb_imagep->drawSolid(mIt->second, curThumbColor % opacity); +				if (getEnabled()) +				{ +					mThumbImagep->draw(curSldrIt->second); +				} +				else +				{ +					mThumbImagep->draw(curSldrIt->second, LLColor4::grey % 0.8f); +				} +			} +			else if (capture == this) +			{ +				thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get()); +			} +			else +			{ +				thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity); +			}  		} - -		if(curSldrIt != mThumbRects.end())  +		if(hoverSldrIt != mThumbRects.end())   		{ -			thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity); +			if (mThumbImagep) +			{ +				mThumbImagep->draw(hoverSldrIt->second); +			} +			else +			{ +				thumb_imagep->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get()); +			}  		}  	} diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h index 2b422e89c9..99a78d6e09 100644 --- a/indra/llui/llmultislider.h +++ b/indra/llui/llmultislider.h @@ -47,16 +47,23 @@ public:  		Optional<S32>	max_sliders;  		Optional<bool>	allow_overlap, +						loop_overlap,  						draw_track,  						use_triangle; +		Optional<F32>	overlap_threshold; +  		Optional<LLUIColor>	track_color,  							thumb_disabled_color, +							thumb_highlight_color,  							thumb_outline_color,  							thumb_center_color,  							thumb_center_selected_color,  							triangle_color; +		Optional<std::string>	orientation, +								thumb_image; +  		Optional<CommitCallbackParam>	mouse_down_callback,  										mouse_up_callback;  		Optional<S32>		thumb_width; @@ -70,16 +77,27 @@ protected:  	friend class LLUICtrlFactory;  public:  	virtual ~LLMultiSlider(); + +    // Multi-slider rounds values to nearest increments (bias towards rounding down) +    F32					getNearestIncrement(F32 value) const; +  	void				setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE);  	F32					getSliderValue(const std::string& name) const; +	F32					getSliderValueFromPos(S32 xpos, S32 ypos) const; +    LLRect              getSliderThumbRect(const std::string& name) const; + +    void                setSliderThumbImage(const std::string &name); +    void                clearSliderThumbImage(); +  	const std::string&	getCurSlider() const					{ return mCurSlider; }  	F32					getCurSliderValue() const				{ return getSliderValue(mCurSlider); }  	void				setCurSlider(const std::string& name); +	void				resetCurSlider();  	void				setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); } -	/*virtual*/ void	setValue(const LLSD& value); -	/*virtual*/ LLSD	getValue() const		{ return mValue; } +	/*virtual*/ void	setValue(const LLSD& value) override; +	/*virtual*/ LLSD	getValue() const override { return mValue; }  	boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );  	boost::signals2::connection setMouseUpCallback(	const commit_signal_t::slot_type& cb ); @@ -87,24 +105,34 @@ public:  	bool				findUnusedValue(F32& initVal);  	const std::string&	addSlider();  	const std::string&	addSlider(F32 val); -	void				addSlider(F32 val, const std::string& name); +	bool				addSlider(F32 val, const std::string& name);  	void				deleteSlider(const std::string& name);  	void				deleteCurSlider()			{ deleteSlider(mCurSlider); } -	void				clear(); +	/*virtual*/ void	clear() override; + +	/*virtual*/ BOOL	handleHover(S32 x, S32 y, MASK mask) override; +	/*virtual*/ BOOL	handleMouseUp(S32 x, S32 y, MASK mask) override; +	/*virtual*/ BOOL	handleMouseDown(S32 x, S32 y, MASK mask) override; +	/*virtual*/ BOOL	handleKeyHere(KEY key, MASK mask) override; +	/*virtual*/ void	onMouseLeave(S32 x, S32 y, MASK mask) override; +	/*virtual*/ void	draw() override; + +	S32				getMaxNumSliders() { return mMaxNumSliders; } +	S32				getCurNumSliders() { return mValue.size(); } +	F32				getOverlapThreshold() { return mOverlapThreshold; } +	bool			canAddSliders() { return mValue.size() < mMaxNumSliders; } -	/*virtual*/ BOOL	handleHover(S32 x, S32 y, MASK mask); -	/*virtual*/ BOOL	handleMouseUp(S32 x, S32 y, MASK mask); -	/*virtual*/ BOOL	handleMouseDown(S32 x, S32 y, MASK mask); -	/*virtual*/ BOOL	handleKeyHere(KEY key, MASK mask); -	/*virtual*/ void	draw();  protected:  	LLSD			mValue;  	std::string		mCurSlider; +	std::string		mHoverSlider;  	static S32		mNameCounter;  	S32				mMaxNumSliders;  	BOOL			mAllowOverlap; +	BOOL			mLoopOverlap; +	F32				mOverlapThreshold;  	BOOL			mDrawTrack;  	BOOL			mUseTriangle;			/// hacked in toggle to use a triangle @@ -116,11 +144,15 @@ protected:  					mThumbRects;  	LLUIColor		mTrackColor;  	LLUIColor		mThumbOutlineColor; +	LLUIColor		mThumbHighlightColor;  	LLUIColor		mThumbCenterColor;  	LLUIColor		mThumbCenterSelectedColor;  	LLUIColor		mDisabledThumbColor;  	LLUIColor		mTriangleColor; -	 +	LLUIImagePtr	mThumbImagep; //blimps on the slider, for now no 'disabled' support + +	const EOrientation	mOrientation; +  	commit_signal_t*	mMouseDownSignal;  	commit_signal_t*	mMouseUpSignal;  }; diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index c460a08afc..20e2b569f1 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -53,6 +53,12 @@ LLMultiSliderCtrl::Params::Params()  	can_edit_text("can_edit_text", false),  	max_sliders("max_sliders", 1),  	allow_overlap("allow_overlap", false), +	loop_overlap("loop_overlap", false), +	orientation("orientation"), +	thumb_image("thumb_image"), +	thumb_width("thumb_width"), +	thumb_highlight_color("thumb_highlight_color"), +	overlap_threshold("overlap_threshold", 0),  	draw_track("draw_track", true),  	use_triangle("use_triangle", false),  	decimal_digits("decimal_digits", 3), @@ -167,6 +173,19 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)  	params.increment(p.increment);  	params.max_sliders(p.max_sliders);  	params.allow_overlap(p.allow_overlap); +	params.loop_overlap(p.loop_overlap); +	if (p.overlap_threshold.isProvided()) +	{ +		params.overlap_threshold = p.overlap_threshold; +	} +	params.orientation(p.orientation); +	params.thumb_image(p.thumb_image); +	params.thumb_highlight_color(p.thumb_highlight_color); +	if (p.thumb_width.isProvided()) +	{ +		// otherwise should be provided by template +		params.thumb_width(p.thumb_width); +	}  	params.draw_track(p.draw_track);  	params.use_triangle(p.use_triangle);  	params.control_name(p.control_name); @@ -213,6 +232,11 @@ void LLMultiSliderCtrl::setCurSlider(const std::string& name)  	mCurValue = mMultiSlider->getCurSliderValue();  } +void LLMultiSliderCtrl::resetCurSlider() +{ +	mMultiSlider->resetCurSlider(); +} +  BOOL LLMultiSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text )  {  	BOOL res = FALSE; @@ -269,6 +293,17 @@ const std::string& LLMultiSliderCtrl::addSlider(F32 val)  	return name;  } +bool LLMultiSliderCtrl::addSlider(F32 val, const std::string& name) +{ +	bool res = mMultiSlider->addSlider(val, name); +	if (res) +	{ +		mCurValue = mMultiSlider->getCurSliderValue(); +		updateText(); +	} +	return res; +} +  void LLMultiSliderCtrl::deleteSlider(const std::string& name)  {  	mMultiSlider->deleteSlider(name); diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h index b6a3542376..adb28676ec 100644 --- a/indra/llui/llmultisliderctrl.h +++ b/indra/llui/llmultisliderctrl.h @@ -51,14 +51,22 @@ public:  								text_width;  		Optional<bool>			show_text,  								can_edit_text; -		Optional<S32>			decimal_digits; +		Optional<S32>			decimal_digits, +								thumb_width;  		Optional<S32>			max_sliders;	  		Optional<bool>			allow_overlap, +								loop_overlap,  								draw_track,  								use_triangle; +		Optional<std::string>	orientation, +								thumb_image; + +		Optional<F32>			overlap_threshold; +  		Optional<LLUIColor>		text_color, -								text_disabled_color; +								text_disabled_color, +								thumb_highlight_color;  		Optional<CommitCallbackParam>	mouse_down_callback,  										mouse_up_callback; @@ -74,7 +82,7 @@ protected:  public:  	virtual ~LLMultiSliderCtrl(); -	F32				getSliderValue(const std::string& name) const; +    F32				getSliderValue(const std::string& name) const   { return mMultiSlider->getSliderValue(name); }  	void			setSliderValue(const std::string& name, F32 v, BOOL from_event = FALSE);  	virtual void	setValue(const LLSD& value ); @@ -84,6 +92,7 @@ public:  	const std::string& getCurSlider() const					{ return mMultiSlider->getCurSlider(); }  	F32				getCurSliderValue() const				{ return mCurValue; }  	void			setCurSlider(const std::string& name);		 +	void			resetCurSlider();  	void			setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mMultiSlider->getCurSlider(), val, from_event); }  	virtual void	setMinValue(const LLSD& min_value)	{ setMinValue((F32)min_value.asReal()); } @@ -98,15 +107,28 @@ public:  	void			setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);}  	void			setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);} +	F32				getNearestIncrement(F32 value) const { return mMultiSlider->getNearestIncrement(value); } +	F32			    getSliderValueFromPos(S32 x, S32 y) const { return mMultiSlider->getSliderValueFromPos(x, y); } +    LLRect          getSliderThumbRect(const std::string &name) const { return mMultiSlider->getSliderThumbRect(name); } + +    void            setSliderThumbImage(const std::string &name) { mMultiSlider->setSliderThumbImage(name); } +    void            clearSliderThumbImage() { mMultiSlider->clearSliderThumbImage(); } +  	/// for adding and deleting sliders  	const std::string&	addSlider();  	const std::string&	addSlider(F32 val); +	bool				addSlider(F32 val, const std::string& name);  	void			deleteSlider(const std::string& name);  	void			deleteCurSlider()			{ deleteSlider(mMultiSlider->getCurSlider()); }  	F32				getMinValue() const { return mMultiSlider->getMinValue(); }  	F32				getMaxValue() const { return mMultiSlider->getMaxValue(); } +	S32				getMaxNumSliders() { return mMultiSlider->getMaxNumSliders(); } +	S32				getCurNumSliders() { return mMultiSlider->getCurNumSliders(); } +	F32				getOverlapThreshold() { return mMultiSlider->getOverlapThreshold(); } +	bool			canAddSliders() { return mMultiSlider->canAddSliders(); } +  	void			setLabel(const std::string& label)				{ if (mLabelBox) mLabelBox->setText(label); }  	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }  	void			setDisabledLabelColor(const LLColor4& c)	{ mTextDisabledColor = c; } diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp index ebbb951ee6..62df5a2c38 100644 --- a/indra/llui/llslider.cpp +++ b/indra/llui/llslider.cpp @@ -42,7 +42,6 @@ static LLDefaultChildRegistry::Register<LLSlider> r1("slider_bar");  LLSlider::Params::Params()  :	orientation ("orientation", std::string ("horizontal")), -	track_color("track_color"),  	thumb_outline_color("thumb_outline_color"),  	thumb_center_color("thumb_center_color"),  	thumb_image("thumb_image"), @@ -60,7 +59,6 @@ LLSlider::LLSlider(const LLSlider::Params& p)  :	LLF32UICtrl(p),  	mMouseOffset( 0 ),  	mOrientation ((p.orientation() == "horizontal") ? HORIZONTAL : VERTICAL), -	mTrackColor(p.track_color()),  	mThumbOutlineColor(p.thumb_outline_color()),  	mThumbCenterColor(p.thumb_center_color()),  	mThumbImage(p.thumb_image), @@ -331,8 +329,9 @@ void LLSlider::draw()  		highlight_rect.set(track_rect.mLeft, track_rect.mTop, track_rect.mRight, track_rect.mBottom);  	} -	trackImage->draw(track_rect, LLColor4::white % alpha); -	trackHighlightImage->draw(highlight_rect, LLColor4::white % alpha); +	LLColor4 color = isInEnabledChain() ? LLColor4::white % alpha : LLColor4::white % (0.6f * alpha); +	trackImage->draw(track_rect, color); +	trackHighlightImage->draw(highlight_rect, color);  	// Thumb  	if (hasFocus()) diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h index 3b492d8182..484a5373b3 100644 --- a/indra/llui/llslider.h +++ b/indra/llui/llslider.h @@ -38,8 +38,7 @@ public:  	{  		Optional<std::string> orientation; -		Optional<LLUIColor>	track_color, -							thumb_outline_color, +		Optional<LLUIColor>	thumb_outline_color,  							thumb_center_color;  		Optional<LLUIImage*>	thumb_image, @@ -99,7 +98,6 @@ private:  	const EOrientation	mOrientation;  	LLRect		mThumbRect; -	LLUIColor	mTrackColor;  	LLUIColor	mThumbOutlineColor;  	LLUIColor	mThumbCenterColor; diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 0056cb6dc4..3b89a8ca63 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -283,6 +283,35 @@ void LLSliderCtrl::updateText()  	}  } +void LLSliderCtrl::updateSliderRect() +{ +    S32 right = getRect().getWidth(); +    S32 top = getRect().getHeight(); +    S32 bottom = 0; +    S32 left = 0; +    static LLUICachedControl<S32> sliderctrl_spacing("UISliderctrlSpacing", 0); +    if (mEditor) +    { +        LLRect editor_rect = mEditor->getRect(); +        S32 editor_width = editor_rect.getWidth(); +        editor_rect.mRight = right; +        editor_rect.mLeft = right - editor_width; +        mEditor->setRect(editor_rect); + +        right -= editor_width + sliderctrl_spacing; +    } +    if (mTextBox) +    { +        right -= mTextBox->getRect().getWidth() + sliderctrl_spacing; +    } +    if (mLabelBox) +    { +        left += mLabelBox->getRect().getWidth() + sliderctrl_spacing; +    } + +    mSlider->setRect(LLRect(left, top,right,bottom)); +} +  // static  void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata )  { @@ -404,6 +433,18 @@ void LLSliderCtrl::onCommit()  	LLF32UICtrl::onCommit();  } +void LLSliderCtrl::setRect(const LLRect& rect) +{ +    LLF32UICtrl::setRect(rect); +    updateSliderRect(); +} + +//virtual +void LLSliderCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +    LLF32UICtrl::reshape(width, height, called_from_parent); +    updateSliderRect(); +}  void LLSliderCtrl::setPrecision(S32 precision)  { diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index 2bb8668b90..541c167717 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -125,6 +125,9 @@ public:  		mSlider->setControlName(control_name, context);  	} +	/*virtual*/ void	setRect(const LLRect& rect); +	/*virtual*/ void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); +  	static void		onSliderCommit(LLUICtrl* caller, const LLSD& userdata);  	static void		onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); @@ -146,6 +149,7 @@ protected:  	}  private:  	void			updateText(); +	void			updateSliderRect();  	void			reportInvalidData();  	const LLFontGL*	mFont; diff --git a/indra/llui/llui.h b/indra/llui/llui.h index e1c51deba9..9856e551cc 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -33,7 +33,6 @@  #include "llcontrol.h"  #include "llcoord.h"  #include "llcontrol.h" -#include "llglslshader.h"  #include "llinitparam.h"  #include "llregistry.h"  #include "llrender2dutils.h" @@ -49,7 +48,6 @@  // for initparam specialization  #include "llfontgl.h" -  class LLUUID;  class LLWindow;  class LLView; @@ -77,7 +75,8 @@ enum EDragAndDropType  	DAD_MESH            = 15,  	DAD_WIDGET          = 16,  	DAD_PERSON          = 17, -	DAD_COUNT           = 18,   // number of types in this enum +    DAD_SETTINGS        = 18, +	DAD_COUNT           = 19,   // number of types in this enum  };  // Reasons for drags to be denied. diff --git a/indra/llui/llvirtualtrackball.cpp b/indra/llui/llvirtualtrackball.cpp new file mode 100644 index 0000000000..723643dd25 --- /dev/null +++ b/indra/llui/llvirtualtrackball.cpp @@ -0,0 +1,480 @@ +/** +* @file LLVirtualTrackball.cpp +* @author Andrey Lihatskiy +* @brief Implementation for LLVirtualTrackball +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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$ +*/ + +// A control for positioning the sun and the moon in the celestial sphere. + +#include "linden_common.h" +#include "llvirtualtrackball.h" +#include "llstring.h" +#include "llrect.h" +#include "lluictrlfactory.h" +#include "llrender.h" + +// Globals +static LLDefaultChildRegistry::Register<LLVirtualTrackball> register_virtual_trackball("sun_moon_trackball"); + +const LLVector3 VectorZero(1.0f, 0.0f, 0.0f); + +LLVirtualTrackball::Params::Params() +  : border("border"), +    image_moon_back("image_moon_back"), +    image_moon_front("image_moon_front"), +    image_sphere("image_sphere"), +    image_sun_back("image_sun_back"), +    image_sun_front("image_sun_front"), +    btn_rotate_top("button_rotate_top"), +    btn_rotate_bottom("button_rotate_bottom"), +    btn_rotate_left("button_rotate_left"), +    btn_rotate_right("button_rotate_right"), +    thumb_mode("thumb_mode"), +    lbl_N("labelN"), +    lbl_S("labelS"), +    lbl_W("labelW"), +    lbl_E("labelE"), +    increment_angle_mouse("increment_angle_mouse", 0.5f), +    increment_angle_btn("increment_angle_btn", 3.0f) +{ +} + +LLVirtualTrackball::LLVirtualTrackball(const LLVirtualTrackball::Params& p) +  : LLUICtrl(p), +    mImgMoonBack(p.image_moon_back), +    mImgMoonFront(p.image_moon_front), +    mImgSunBack(p.image_sun_back), +    mImgSunFront(p.image_sun_front), +    mImgSphere(p.image_sphere), +    mThumbMode(p.thumb_mode() == "moon" ? ThumbMode::MOON : ThumbMode::SUN), +    mIncrementMouse(DEG_TO_RAD * p.increment_angle_mouse()), +    mIncrementBtn(DEG_TO_RAD * p.increment_angle_btn()) +{ +    LLRect border_rect = getLocalRect(); +    S32 centerX = border_rect.getCenterX(); +    S32 centerY = border_rect.getCenterY(); +    U32 btn_size = 32; // width & height +    U32 axis_offset_lt = 16; // offset from the axis for left/top sides +    U32 axis_offset_rb = btn_size - axis_offset_lt; //  and for right/bottom + +    LLViewBorder::Params border = p.border; +    border.rect(border_rect); +    mBorder = LLUICtrlFactory::create<LLViewBorder>(border); +    addChild(mBorder); + +     +    LLButton::Params btn_rt = p.btn_rotate_top; +    btn_rt.rect(LLRect(centerX - axis_offset_lt, border_rect.mTop, centerX + axis_offset_rb, border_rect.mTop - btn_size)); +    btn_rt.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopClick, this)); +    btn_rt.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopClick, this)); +    btn_rt.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopMouseEnter, this)); +    mBtnRotateTop = LLUICtrlFactory::create<LLButton>(btn_rt); +    addChild(mBtnRotateTop); + +    LLTextBox::Params lbl_N = p.lbl_N; +    LLRect rect_N = btn_rt.rect; +    //rect_N.translate(btn_rt.rect().getWidth(), 0); +    lbl_N.rect = rect_N; +    lbl_N.initial_value(lbl_N.label()); +    mLabelN = LLUICtrlFactory::create<LLTextBox>(lbl_N); +    addChild(mLabelN); + + +    LLButton::Params btn_rr = p.btn_rotate_right; +    btn_rr.rect(LLRect(border_rect.mRight - btn_size, centerY + axis_offset_lt, border_rect.mRight, centerY - axis_offset_rb)); +    btn_rr.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightClick, this)); +    btn_rr.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightClick, this)); +    btn_rr.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightMouseEnter, this)); +    mBtnRotateRight = LLUICtrlFactory::create<LLButton>(btn_rr); +    addChild(mBtnRotateRight); + +    LLTextBox::Params lbl_E = p.lbl_E; +    LLRect rect_E = btn_rr.rect; +    //rect_E.translate(0, -1 * btn_rr.rect().getHeight()); +    lbl_E.rect = rect_E; +    lbl_E.initial_value(lbl_E.label()); +    mLabelE = LLUICtrlFactory::create<LLTextBox>(lbl_E); +    addChild(mLabelE); + + +    LLButton::Params btn_rb = p.btn_rotate_bottom; +    btn_rb.rect(LLRect(centerX - axis_offset_lt, border_rect.mBottom + btn_size, centerX + axis_offset_rb, border_rect.mBottom)); +    btn_rb.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomClick, this)); +    btn_rb.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomClick, this)); +    btn_rb.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomMouseEnter, this)); +    mBtnRotateBottom = LLUICtrlFactory::create<LLButton>(btn_rb); +    addChild(mBtnRotateBottom); + +    LLTextBox::Params lbl_S = p.lbl_S; +    LLRect rect_S = btn_rb.rect; +    //rect_S.translate(btn_rb.rect().getWidth(), 0); +    lbl_S.rect = rect_S; +    lbl_S.initial_value(lbl_S.label()); +    mLabelS = LLUICtrlFactory::create<LLTextBox>(lbl_S); +    addChild(mLabelS); + + +    LLButton::Params btn_rl = p.btn_rotate_left; +    btn_rl.rect(LLRect(border_rect.mLeft, centerY + axis_offset_lt, border_rect.mLeft + btn_size, centerY - axis_offset_rb)); +    btn_rl.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftClick, this)); +    btn_rl.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftClick, this)); +    btn_rl.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftMouseEnter, this)); +    mBtnRotateLeft = LLUICtrlFactory::create<LLButton>(btn_rl); +    addChild(mBtnRotateLeft); + +    LLTextBox::Params lbl_W = p.lbl_W; +    LLRect rect_W = btn_rl.rect; +    //rect_W.translate(0, -1* btn_rl.rect().getHeight()); +    lbl_W.rect = rect_W; +    lbl_W.initial_value(lbl_W.label()); +    mLabelW = LLUICtrlFactory::create<LLTextBox>(lbl_W); +    addChild(mLabelW); + + +    LLPanel::Params touch_area; +    touch_area.rect = LLRect(centerX - mImgSphere->getWidth() / 2, +                             centerY + mImgSphere->getHeight() / 2, +                             centerX + mImgSphere->getWidth() / 2, +                             centerY - mImgSphere->getHeight() / 2); +    mTouchArea = LLUICtrlFactory::create<LLPanel>(touch_area); +    addChild(mTouchArea); +} + +LLVirtualTrackball::~LLVirtualTrackball() +{ +} + +BOOL LLVirtualTrackball::postBuild() +{ +    return TRUE; +} + + +void LLVirtualTrackball::drawThumb(S32 x, S32 y, ThumbMode mode, bool upperHemi) +{ +    LLUIImage* thumb; +    if (mode == ThumbMode::SUN) +    { +        if (upperHemi) +        { +            thumb = mImgSunFront; +        } +        else +        { +            thumb = mImgSunBack; +        } +    } +    else +    { +        if (upperHemi) +        { +            thumb = mImgMoonFront; +        } +        else +        { +            thumb = mImgMoonBack; +        } +    } +    thumb->draw(LLRect(x - thumb->getWidth() / 2, +                       y + thumb->getHeight() / 2, +                       x + thumb->getWidth() / 2, +                       y - thumb->getHeight() / 2)); +} + +bool LLVirtualTrackball::pointInTouchCircle(S32 x, S32 y) const +{ +    S32 centerX = mTouchArea->getRect().getCenterX(); +    S32 centerY = mTouchArea->getRect().getCenterY(); + +    bool in_circle = pow(x - centerX, 2) + pow(y - centerY, 2) <= pow(mTouchArea->getRect().getWidth() / 2, 2); +    return in_circle; +} + +void LLVirtualTrackball::draw() +{ +    LLVector3 draw_point = VectorZero * mValue; + +    S32 halfwidth = mTouchArea->getRect().getWidth() / 2; +    S32 halfheight = mTouchArea->getRect().getHeight() / 2; +    draw_point.mV[VX] = (draw_point.mV[VX] + 1.0) * halfwidth + mTouchArea->getRect().mLeft; +    draw_point.mV[VY] = (draw_point.mV[VY] + 1.0) * halfheight + mTouchArea->getRect().mBottom; +    bool upper_hemisphere = (draw_point.mV[VZ] >= 0.f); + +    mImgSphere->draw(mTouchArea->getRect(), upper_hemisphere ? UI_VERTEX_COLOR : UI_VERTEX_COLOR % 0.5f); +    drawThumb(draw_point.mV[VX], draw_point.mV[VY], mThumbMode, upper_hemisphere); + + +    if (LLView::sDebugRects) +    { +        gGL.color4fv(LLColor4::red.mV); +        gl_circle_2d(mTouchArea->getRect().getCenterX(), mTouchArea->getRect().getCenterY(), mImgSphere->getWidth() / 2, 60, false); +        gl_circle_2d(draw_point.mV[VX], draw_point.mV[VY], mImgSunFront->getWidth() / 2, 12, false); +    } + +    // hide the direction labels when disabled +    BOOL enabled = isInEnabledChain(); +    mLabelN->setVisible(enabled); +    mLabelE->setVisible(enabled); +    mLabelS->setVisible(enabled); +    mLabelW->setVisible(enabled); + +    LLView::draw(); +} + +void LLVirtualTrackball::onRotateTopClick() +{ +    if (getEnabled()) +    { +        LLQuaternion delta; +        delta.setAngleAxis(mIncrementBtn, 1, 0, 0);  +        mValue *= delta; +        setValueAndCommit(mValue); + +        make_ui_sound("UISndClick"); +    } +} + +void LLVirtualTrackball::onRotateBottomClick() +{ +    if (getEnabled()) +    { +        LLQuaternion delta; +        delta.setAngleAxis(mIncrementBtn, -1, 0, 0); +        mValue *= delta; +        setValueAndCommit(mValue); + +        make_ui_sound("UISndClick"); +    } +} + +void LLVirtualTrackball::onRotateLeftClick() +{ +    if (getEnabled()) +    { +        LLQuaternion delta; +        delta.setAngleAxis(mIncrementBtn, 0, 1, 0); +        mValue *= delta; +        setValueAndCommit(mValue); + +        make_ui_sound("UISndClick"); +    } +} + +void LLVirtualTrackball::onRotateRightClick() +{ +    if (getEnabled()) +    { +        LLQuaternion delta; +        delta.setAngleAxis(mIncrementBtn, 0, -1, 0); +        mValue *= delta; +        setValueAndCommit(mValue); + +        make_ui_sound("UISndClick"); +    } +} + +void LLVirtualTrackball::onRotateTopMouseEnter() +{ +    mBtnRotateTop->setHighlight(true); +} + +void LLVirtualTrackball::onRotateBottomMouseEnter() +{ +    mBtnRotateBottom->setHighlight(true); +} + +void LLVirtualTrackball::onRotateLeftMouseEnter() +{ +    mBtnRotateLeft->setHighlight(true); +} + +void LLVirtualTrackball::onRotateRightMouseEnter() +{ +    mBtnRotateRight->setHighlight(true); +} + +void LLVirtualTrackball::setValue(const LLSD& value) +{ +	if (value.isArray() && value.size() == 4) +    { +        mValue.setValue(value); +    } +} + +void LLVirtualTrackball::setRotation(const LLQuaternion &value) +{ +    mValue = value; +} + +void LLVirtualTrackball::setValue(F32 x, F32 y, F32 z, F32 w) +{ +    mValue.set(x, y, z, w); +} + +void LLVirtualTrackball::setValueAndCommit(const LLQuaternion &value) +{ +	mValue = value; +    onCommit(); +} + +LLSD LLVirtualTrackball::getValue() const +{ +    return mValue.getValue(); +} + +LLQuaternion LLVirtualTrackball::getRotation() const +{ +	return mValue; +} + +BOOL LLVirtualTrackball::handleHover(S32 x, S32 y, MASK mask) +{ +    if (hasMouseCapture()) +    { +        if (mDragMode == DRAG_SCROLL) +        { // trackball (move to roll) mode +            LLQuaternion delta; + +            F32 rotX = x - mPrevX; +            F32 rotY = y - mPrevY; + +            if (abs(rotX) > 1) +            { +                F32 direction = (rotX < 0) ? -1 : 1; +                delta.setAngleAxis(mIncrementMouse * abs(rotX), 0, direction, 0);  // changing X - rotate around Y axis +                mValue *= delta; +            } + +            if (abs(rotY) > 1) +            { +                F32 direction = (rotY < 0) ? 1 : -1; // reverse for Y (value increases from bottom to top) +                delta.setAngleAxis(mIncrementMouse * abs(rotY), direction, 0, 0);  // changing Y - rotate around X axis +                mValue *= delta; +            } +        } +        else +        { // set on click mode +            if (!pointInTouchCircle(x, y)) +            { +                return TRUE; // don't drag outside the circle +            } + +            F32 radius = mTouchArea->getRect().getWidth() / 2; +            F32 xx = x - mTouchArea->getRect().getCenterX(); +            F32 yy = y - mTouchArea->getRect().getCenterY(); +            F32 dist = sqrt(pow(xx, 2) + pow(yy, 2)); + +            F32 azimuth = llclamp(acosf(xx / dist), 0.0f, F_PI); +            F32 altitude = llclamp(acosf(dist / radius), 0.0f, F_PI_BY_TWO); + +            if (yy < 0) +            { +                azimuth = F_TWO_PI - azimuth; +            } + +            LLVector3 draw_point = VectorZero * mValue; +            if (draw_point.mV[VZ] >= 0.f) +            { +                if (is_approx_zero(altitude)) // don't change the hemisphere +                { +                    altitude = F_APPROXIMATELY_ZERO; +                } +                altitude *= -1; +            } + +            mValue.setAngleAxis(altitude, 0, 1, 0); +            LLQuaternion az_quat; +            az_quat.setAngleAxis(azimuth, 0, 0, 1); +            mValue *= az_quat; +        } + +        mPrevX = x; +        mPrevY = y; +        onCommit(); +    } +    return TRUE; +} + +BOOL LLVirtualTrackball::handleMouseUp(S32 x, S32 y, MASK mask) +{ +    if (hasMouseCapture()) +    { +        mPrevX = 0; +        mPrevY = 0; +        gFocusMgr.setMouseCapture(NULL); +        make_ui_sound("UISndClickRelease"); +    } +    return LLView::handleMouseUp(x, y, mask); +} + +BOOL LLVirtualTrackball::handleMouseDown(S32 x, S32 y, MASK mask) +{ +    if (pointInTouchCircle(x, y)) +    { +        mPrevX = x; +        mPrevY = y; +        gFocusMgr.setMouseCapture(this); +        mDragMode = (mask == MASK_CONTROL) ? DRAG_SCROLL : DRAG_SET; +        make_ui_sound("UISndClick"); +    } +    return LLView::handleMouseDown(x, y, mask); +} + +BOOL LLVirtualTrackball::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ +    if (pointInTouchCircle(x, y)) +    { + +        //make_ui_sound("UISndClick"); +    } +    return LLView::handleRightMouseDown(x, y, mask); +} + +BOOL LLVirtualTrackball::handleKeyHere(KEY key, MASK mask) +{ +    BOOL handled = FALSE; +    switch (key) +    { +    case KEY_DOWN: +        onRotateTopClick(); +        handled = TRUE; +        break; +    case KEY_LEFT: +        onRotateRightClick(); +        handled = TRUE; +        break; +    case KEY_UP: +        onRotateBottomClick(); +        handled = TRUE; +        break; +    case KEY_RIGHT: +        onRotateLeftClick(); +        handled = TRUE; +        break; +    default: +        break; +    } +    return handled; +} + diff --git a/indra/llui/llvirtualtrackball.h b/indra/llui/llvirtualtrackball.h new file mode 100644 index 0000000000..2d4b1ece17 --- /dev/null +++ b/indra/llui/llvirtualtrackball.h @@ -0,0 +1,160 @@ +/** +* @file virtualtrackball.h +* @author Andrey Lihatskiy +* @brief Header file for LLVirtualTrackball +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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$ +*/ + +// A control for positioning the sun and the moon in the celestial sphere. + +#ifndef LL_LLVIRTUALTRACKBALL_H +#define LL_LLVIRTUALTRACKBALL_H + +#include "lluictrl.h" +#include "llpanel.h" +#include "lltextbox.h" +#include "llbutton.h" + +class LLVirtualTrackball +    : public LLUICtrl +{ +public: +    enum ThumbMode +    { +        SUN, +        MOON +    }; +    enum DragMode +    { +        DRAG_SET, +        DRAG_SCROLL +    }; + +    struct Params +        : public LLInitParam::Block<Params, LLUICtrl::Params> +    { +        Optional<LLViewBorder::Params>	    border; +        Optional<LLUIImage*>                image_moon_back, +            image_moon_front, +            image_sphere, +            image_sun_back, +            image_sun_front; + +        Optional<std::string>               thumb_mode; +        Optional<F32>                       increment_angle_mouse, +            increment_angle_btn; + +        Optional<LLTextBox::Params>         lbl_N, +            lbl_S, +            lbl_W, +            lbl_E; + +        Optional<LLButton::Params>          btn_rotate_top, +            btn_rotate_bottom, +            btn_rotate_left, +            btn_rotate_right; + +        Params(); +    }; + + +    virtual ~LLVirtualTrackball(); +    /*virtual*/ BOOL postBuild(); + +    virtual BOOL    handleHover(S32 x, S32 y, MASK mask); +    virtual BOOL    handleMouseUp(S32 x, S32 y, MASK mask); +    virtual BOOL    handleMouseDown(S32 x, S32 y, MASK mask); +    virtual BOOL    handleRightMouseDown(S32 x, S32 y, MASK mask); +    virtual BOOL    handleKeyHere(KEY key, MASK mask); + +    virtual void    draw(); + +    virtual void    setValue(const LLSD& value); +    void            setValue(F32 x, F32 y, F32 z, F32 w); +    virtual LLSD    getValue() const; + +    void            setRotation(const LLQuaternion &value); +    LLQuaternion    getRotation() const; + +protected: +    friend class LLUICtrlFactory; +    LLVirtualTrackball(const Params&); +    void onEditChange(); + +protected: +    LLTextBox*          mNLabel; +    LLTextBox*          mELabel; +    LLTextBox*          mSLabel; +    LLTextBox*          mWLabel; + +    LLButton*           mBtnRotateTop; +    LLButton*           mBtnRotateBottom; +    LLButton*           mBtnRotateLeft; +    LLButton*           mBtnRotateRight; + +    LLTextBox*          mLabelN; +    LLTextBox*          mLabelS; +    LLTextBox*          mLabelW; +    LLTextBox*          mLabelE; + +    LLPanel*            mTouchArea; +    LLViewBorder*       mBorder; + +private: +    void setValueAndCommit(const LLQuaternion &value); +    void drawThumb(S32 x, S32 y, ThumbMode mode, bool upperHemi = true); +    bool pointInTouchCircle(S32 x, S32 y) const; + +    void onRotateTopClick(); +    void onRotateBottomClick(); +    void onRotateLeftClick(); +    void onRotateRightClick(); + +    void onRotateTopMouseEnter(); +    void onRotateBottomMouseEnter(); +    void onRotateLeftMouseEnter(); +    void onRotateRightMouseEnter(); + +    S32 mPrevX; +    S32 mPrevY; + +    LLUIImage*     mImgMoonBack; +    LLUIImage*     mImgMoonFront; +    LLUIImage*     mImgSunBack; +    LLUIImage*     mImgSunFront; +    LLUIImage*     mImgBtnRotTop; +    LLUIImage*     mImgBtnRotLeft; +    LLUIImage*     mImgBtnRotRight; +    LLUIImage*     mImgBtnRotBottom; +    LLUIImage*     mImgSphere; + +    LLQuaternion   mValue; +    ThumbMode      mThumbMode; +    DragMode       mDragMode; + +    F32            mIncrementMouse; +    F32            mIncrementBtn; +}; + +#endif + diff --git a/indra/llui/llxyvector.cpp b/indra/llui/llxyvector.cpp new file mode 100644 index 0000000000..d7ba243e1d --- /dev/null +++ b/indra/llui/llxyvector.cpp @@ -0,0 +1,337 @@ +/** +* @file llxyvector.cpp +* @author Andrey Lihatskiy +* @brief Implementation for LLXYVector +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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$ +*/ + +// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane.  + +#include "linden_common.h" + +#include "llxyvector.h" + +#include "llstring.h" +#include "llrect.h" + +#include "lluictrlfactory.h" +#include "llrender.h" + +#include "llmath.h" + +// Globals +static LLDefaultChildRegistry::Register<LLXYVector> register_xy_vector("xy_vector"); + + +const F32 CENTER_CIRCLE_RADIUS = 2; +const S32 ARROW_ANGLE = 30; +const S32 ARROW_LENGTH_LONG = 10; +const S32 ARROW_LENGTH_SHORT = 6; + +LLXYVector::Params::Params() +  : x_entry("x_entry"), +    y_entry("y_entry"), +    touch_area("touch_area"), +    border("border"), +    edit_bar_height("edit_bar_height", 18), +    padding("padding", 4), +    min_val_x("min_val_x", -1.0f), +    max_val_x("max_val_x", 1.0f), +    increment_x("increment_x", 0.05f), +    min_val_y("min_val_y", -1.0f), +    max_val_y("max_val_y", 1.0f), +    increment_y("increment_y", 0.05f), +    label_width("label_width", 16), +    arrow_color("arrow_color", LLColor4::white), +    ghost_color("ghost_color"), +    area_color("area_color", LLColor4::grey4), +    grid_color("grid_color", LLColor4::grey % 0.25f), +    logarithmic("logarithmic", FALSE) +{ +} + +LLXYVector::LLXYVector(const LLXYVector::Params& p) +  : LLUICtrl(p), +    mArrowColor(p.arrow_color()), +    mAreaColor(p.area_color), +    mGridColor(p.grid_color), +    mMinValueX(p.min_val_x), +    mMaxValueX(p.max_val_x), +    mIncrementX(p.increment_x), +    mMinValueY(p.min_val_y), +    mMaxValueY(p.max_val_y), +    mIncrementY(p.increment_y), +    mLogarithmic(p.logarithmic), +    mValueX(0), +    mValueY(0) +{ +    mGhostColor = p.ghost_color.isProvided() ? p.ghost_color() % 0.3f : p.arrow_color() % 0.3f; + +    LLRect border_rect = getLocalRect(); +    LLViewBorder::Params params = p.border; +    params.rect(border_rect); +    mBorder = LLUICtrlFactory::create<LLViewBorder>(params); +    addChild(mBorder); + +    LLTextBox::Params x_label_params; +    x_label_params.initial_value(p.x_entry.label()); +    x_label_params.rect = LLRect(p.padding, +                                 border_rect.mTop - p.padding, +                                 p.label_width, +                                 border_rect.getHeight() - p.edit_bar_height); +    mXLabel = LLUICtrlFactory::create<LLTextBox>(x_label_params); +    addChild(mXLabel); +    LLLineEditor::Params x_params = p.x_entry; +    x_params.rect = LLRect(p.padding + p.label_width, +                           border_rect.mTop - p.padding, +                           border_rect.getCenterX(), +                           border_rect.getHeight() - p.edit_bar_height); +    x_params.commit_callback.function(boost::bind(&LLXYVector::onEditChange, this)); +    mXEntry = LLUICtrlFactory::create<LLLineEditor>(x_params); +    mXEntry->setPrevalidateInput(LLTextValidate::validateFloat); +    addChild(mXEntry); + +    LLTextBox::Params y_label_params; +    y_label_params.initial_value(p.y_entry.label()); +    y_label_params.rect = LLRect(border_rect.getCenterX() + p.padding, +                                 border_rect.mTop - p.padding, +                                 border_rect.getCenterX() + p.label_width, +                                 border_rect.getHeight() - p.edit_bar_height); +    mYLabel = LLUICtrlFactory::create<LLTextBox>(y_label_params); +    addChild(mYLabel); +    LLLineEditor::Params y_params = p.y_entry; +    y_params.rect = LLRect(border_rect.getCenterX() + p.padding + p.label_width, +                           border_rect.getHeight() - p.padding, +                           border_rect.getWidth() - p.padding, +                           border_rect.getHeight() - p.edit_bar_height); +    y_params.commit_callback.function(boost::bind(&LLXYVector::onEditChange, this)); +    mYEntry = LLUICtrlFactory::create<LLLineEditor>(y_params); +    mYEntry->setPrevalidateInput(LLTextValidate::validateFloat); +    addChild(mYEntry); + +    LLPanel::Params touch_area = p.touch_area; +    touch_area.rect = LLRect(p.padding, +                             border_rect.mTop - p.edit_bar_height - p.padding, +                             border_rect.getWidth() - p.padding, +                             p.padding); +    mTouchArea = LLUICtrlFactory::create<LLPanel>(touch_area); +    addChild(mTouchArea); +} + +LLXYVector::~LLXYVector() +{ +} + +BOOL LLXYVector::postBuild() +{ +    mLogScaleX = (2 * log(mMaxValueX)) / mTouchArea->getRect().getWidth(); +    mLogScaleY = (2 * log(mMaxValueY)) / mTouchArea->getRect().getHeight(); + +    return TRUE; +} + +void drawArrow(S32 tailX, S32 tailY, S32 tipX, S32 tipY, LLColor4 color) +{ +    gl_line_2d(tailX, tailY, tipX, tipY, color); + +    S32 dx = tipX - tailX; +    S32 dy = tipY - tailY; + +    S32 arrowLength = (abs(dx) < ARROW_LENGTH_LONG && abs(dy) < ARROW_LENGTH_LONG) ? ARROW_LENGTH_SHORT : ARROW_LENGTH_LONG; +    +    F32 theta = std::atan2(dy, dx); + +    F32 rad = ARROW_ANGLE * std::atan(1) * 4 / 180; +    F32 x = tipX - arrowLength * cos(theta + rad); +    F32 y = tipY - arrowLength * sin(theta + rad); +    F32 rad2 = -1 * ARROW_ANGLE * std::atan(1) * 4 / 180; +    F32 x2 = tipX - arrowLength * cos(theta + rad2); +    F32 y2 = tipY - arrowLength * sin(theta + rad2); +    gl_triangle_2d(tipX, tipY, x, y, x2, y2, color, true); +} + +void LLXYVector::draw() +{ +    S32 centerX = mTouchArea->getRect().getCenterX(); +    S32 centerY = mTouchArea->getRect().getCenterY(); +    S32 pointX; +    S32 pointY; + +    if (mLogarithmic) +    { +        pointX = (log(llabs(mValueX) + 1)) / mLogScaleX; +        pointX *= (mValueX < 0) ? -1 : 1; +        pointX += centerX; + +        pointY = (log(llabs(mValueY) + 1)) / mLogScaleY; +        pointY *= (mValueY < 0) ? -1 : 1; +        pointY += centerY; +    } +    else // linear +    { +        pointX = centerX + (mValueX * mTouchArea->getRect().getWidth() / (2 * mMaxValueX)); +        pointY = centerY + (mValueY * mTouchArea->getRect().getHeight() / (2 * mMaxValueY)); +    } + +    // fill +    gl_rect_2d(mTouchArea->getRect(), mAreaColor, true); + +    // draw grid +    gl_line_2d(centerX, mTouchArea->getRect().mTop, centerX, mTouchArea->getRect().mBottom, mGridColor); +    gl_line_2d(mTouchArea->getRect().mLeft, centerY, mTouchArea->getRect().mRight, centerY, mGridColor); + +    // draw ghost +    if (hasMouseCapture()) +    { +        drawArrow(centerX, centerY, mGhostX, mGhostY, mGhostColor); +    } +    else +    { +        mGhostX = pointX; +        mGhostY = pointY; +    } + +    if (abs(mValueX) >= mIncrementX || abs(mValueY) >= mIncrementY) +    { +        // draw the vector arrow +        drawArrow(centerX, centerY, pointX, pointY, mArrowColor); +    } +    else +    { +        // skip the arrow, set color for center circle +        gGL.color4fv(mArrowColor.get().mV); +    } + +    // draw center circle +    gl_circle_2d(centerX, centerY, CENTER_CIRCLE_RADIUS, 12, true); + +    LLView::draw(); +} + +void LLXYVector::onEditChange() +{ +    if (getEnabled()) +    { +        setValueAndCommit(mXEntry->getValue().asReal(), mYEntry->getValue().asReal()); +    } +} + +void LLXYVector::setValue(const LLSD& value) +{ +    if (value.isArray()) +    { +        setValue(value[0].asReal(), value[1].asReal()); +    } +} + +void LLXYVector::setValue(F32 x, F32 y) +{ +    mValueX = ll_round(llclamp(x, mMinValueX, mMaxValueX), mIncrementX); +    mValueY = ll_round(llclamp(y, mMinValueY, mMaxValueY), mIncrementY); + +    update(); +} + +void LLXYVector::setValueAndCommit(F32 x, F32 y) +{ +    if (mValueX != x || mValueY != y) +    { +        setValue(x, y); +        onCommit(); +    } +} + +LLSD LLXYVector::getValue() const +{ +    LLSD value; +    value.append(mValueX); +    value.append(mValueY); +    return value; +} + +void LLXYVector::update() +{ +    mXEntry->setValue(mValueX); +    mYEntry->setValue(mValueY); +} + +BOOL LLXYVector::handleHover(S32 x, S32 y, MASK mask) +{ +    if (hasMouseCapture()) +    { +        if (mLogarithmic) +        { +            F32 valueX = llfastpow(F_E, mLogScaleX*(llabs(x - mTouchArea->getRect().getCenterX()))) - 1; +            valueX *= (x < mTouchArea->getRect().getCenterX()) ? -1 : 1; + +            F32 valueY = llfastpow(F_E, mLogScaleY*(llabs(y - mTouchArea->getRect().getCenterY()))) - 1; +            valueY *= (y < mTouchArea->getRect().getCenterY()) ? -1 : 1; + +            setValueAndCommit(valueX, valueY); +        } +        else //linear +        { +            F32 valueX = 2 * mMaxValueX * F32(x - mTouchArea->getRect().getCenterX()) / mTouchArea->getRect().getWidth(); +            F32 valueY = 2 * mMaxValueY * F32(y - mTouchArea->getRect().getCenterY()) / mTouchArea->getRect().getHeight(); + +            setValueAndCommit(valueX, valueY); +        } +    } + +    return TRUE; +} + +BOOL LLXYVector::handleMouseUp(S32 x, S32 y, MASK mask) +{ +    if (hasMouseCapture()) +    { +        gFocusMgr.setMouseCapture(NULL); +        make_ui_sound("UISndClickRelease"); +    } + +    if (mTouchArea->getRect().pointInRect(x, y)) +    { +        return TRUE; +    } +    else +    { +        return LLUICtrl::handleMouseUp(x, y, mask); +    } +} + +BOOL LLXYVector::handleMouseDown(S32 x, S32 y, MASK mask) +{ + +    if (mTouchArea->getRect().pointInRect(x, y)) +    { +        gFocusMgr.setMouseCapture(this); +        make_ui_sound("UISndClick"); + +        return TRUE; +    } +    else +    { +        return LLUICtrl::handleMouseDown(x, y, mask); +    } +} + diff --git a/indra/llui/llxyvector.h b/indra/llui/llxyvector.h new file mode 100644 index 0000000000..bb3822dd26 --- /dev/null +++ b/indra/llui/llxyvector.h @@ -0,0 +1,122 @@ +/** +* @file llxyvector.h +* @author Andrey Lihatskiy +* @brief Header file for LLXYVector +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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$ +*/ + +// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane.  + +#ifndef LL_LLXYVECTOR_H +#define LL_LLXYVECTOR_H + +#include "lluictrl.h" +#include "llpanel.h" +#include "lltextbox.h" +#include "lllineeditor.h" + +class LLXYVector +    : public LLUICtrl +{ +public: +    struct Params +        : public LLInitParam::Block<Params, LLUICtrl::Params> +    { +        Optional<LLLineEditor::Params>		x_entry; +        Optional<LLLineEditor::Params>		y_entry; +        Optional<LLPanel::Params>		    touch_area; +        Optional<LLViewBorder::Params>	    border; +        Optional<S32>		                edit_bar_height; +        Optional<S32>		                padding; +        Optional<S32>		                label_width; +        Optional<F32>                       min_val_x; +        Optional<F32>                       max_val_x; +        Optional<F32>                       increment_x; +        Optional<F32>                       min_val_y; +        Optional<F32>                       max_val_y; +        Optional<F32>                       increment_y; +        Optional<LLUIColor>                 arrow_color; +        Optional<LLUIColor>                 ghost_color; +        Optional<LLUIColor>                 area_color; +        Optional<LLUIColor>                 grid_color; +        Optional<BOOL>                      logarithmic; + +        Params(); +    }; + + +    virtual ~LLXYVector(); +    /*virtual*/ BOOL postBuild(); + +    virtual BOOL	handleHover(S32 x, S32 y, MASK mask); +    virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask); +    virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask); + +    virtual void	draw(); + +    virtual void	setValue(const LLSD& value); +    void	        setValue(F32 x, F32 y); +    virtual LLSD	getValue() const; + +protected: +    friend class LLUICtrlFactory; +    LLXYVector(const Params&); +    void onEditChange(); + +protected: +    LLTextBox*          mXLabel; +    LLTextBox*          mYLabel; +    LLLineEditor*		mXEntry; +    LLLineEditor*	    mYEntry; +    LLPanel*            mTouchArea; +    LLViewBorder*		mBorder; + +private: +    void update(); +    void setValueAndCommit(F32 x, F32 y); + +    F32 mValueX; +    F32 mValueY; + +    F32 mMinValueX; +    F32 mMaxValueX; +    F32 mIncrementX; +    F32 mMinValueY; +    F32 mMaxValueY; +    F32 mIncrementY; + +    U32 mGhostX; +    U32 mGhostY; + +    LLUIColor mArrowColor; +    LLUIColor mGhostColor; +    LLUIColor mAreaColor; +    LLUIColor mGridColor; + +    BOOL mLogarithmic; +    F32 mLogScaleX; +    F32 mLogScaleY; +}; + +#endif + diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 119cbebc81..3c34fd269e 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -36,6 +36,11 @@  #include <boost/regex.hpp> +#if LL_WINDOWS +// because something pulls in window and lldxdiag dependencies which in turn need wbemuuid.lib +    #pragma comment(lib, "wbemuuid.lib") +#endif +  // namespace LLExperienceCache  // { | 
