diff options
Diffstat (limited to 'indra/llui')
46 files changed, 3566 insertions, 1122 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 772f173f17..20c3456a56 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -12,7 +12,6 @@ include(LLRender)  include(LLWindow)  include(LLVFS)  include(LLXML) -include(LLXUIXML)  include_directories(      ${LLCOMMON_INCLUDE_DIRS} @@ -24,7 +23,6 @@ include_directories(      ${LLWINDOW_INCLUDE_DIRS}      ${LLVFS_INCLUDE_DIRS}      ${LLXML_INCLUDE_DIRS} -    ${LLXUIXML_INCLUDE_DIRS}      )  set(llui_SOURCE_FILES @@ -83,7 +81,6 @@ set(llui_SOURCE_FILES      llscrolllistcolumn.cpp      llscrolllistctrl.cpp      llscrolllistitem.cpp -    llsdparam.cpp      llsearcheditor.cpp      llslider.cpp      llsliderctrl.cpp @@ -100,11 +97,13 @@ set(llui_SOURCE_FILES      lltextutil.cpp      lltextvalidate.cpp      lltimectrl.cpp +    lltrans.cpp      lltransutil.cpp      lltoggleablemenu.cpp      lltoolbar.cpp      lltooltip.cpp      llui.cpp +    lluicolor.cpp      lluicolortable.cpp      lluictrl.cpp      lluictrlfactory.cpp @@ -121,6 +120,7 @@ set(llui_SOURCE_FILES      llview.cpp      llviewquery.cpp      llwindowshade.cpp +    llxuiparser.cpp      )  set(llui_HEADER_FILES @@ -189,7 +189,6 @@ set(llui_HEADER_FILES      llscrolllistcolumn.h      llscrolllistctrl.h      llscrolllistitem.h -    llsdparam.h      llsliderctrl.h      llslider.h      llspinctrl.h @@ -208,6 +207,7 @@ set(llui_HEADER_FILES      lltoggleablemenu.h      lltoolbar.h      lltooltip.h +    lltrans.h      lltransutil.h      lluicolortable.h      lluiconstants.h @@ -215,6 +215,7 @@ set(llui_HEADER_FILES      lluictrl.h      lluifwd.h      llui.h +    lluicolor.h      lluiimage.h      lluistring.h      llundo.h @@ -228,6 +229,7 @@ set(llui_HEADER_FILES      llview.h      llviewquery.h      llwindowshade.h +    llxuiparser.h      )  set_source_files_properties(${llui_HEADER_FILES} diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 7a5f9f9fd6..c025cd7939 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -976,7 +976,7 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child)  			gGL.matrixMode(LLRender::MM_MODELVIEW);  			LLUI::pushMatrix();  			{ -				LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom, 0.f); +				LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom);  				child->draw();  			} diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index f0d92d597a..705fe16559 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -908,9 +908,9 @@ void LLButton::draw()  		// Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.  		mLastDrawCharsCount = mGLFont->render(label, 0,  			(F32)x, -			(F32)(mBottomVPad + y_offset), +			(F32)(getRect().getHeight() / 2 + mBottomVPad),  			label_color % alpha, -			mHAlign, LLFontGL::BOTTOM, +			mHAlign, LLFontGL::VCENTER,  			LLFontGL::NORMAL,  			mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,  			S32_MAX, text_width, diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 6910b962a1..14173fdbb0 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -34,109 +34,113 @@  #include "llview.h"  #include "llwindow.h" -// Global singleton -LLClipboard gClipboard; - - -LLClipboard::LLClipboard() +LLClipboard::LLClipboard() : +	mGeneration(0)  { -	mSourceItem = NULL; +	reset();  } -  LLClipboard::~LLClipboard()  { +	reset();  } - -void LLClipboard::copyFromSubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +void LLClipboard::reset()  { -	mSourceID = source_id; -	mString = src.substr(pos, len); -	LLView::getWindow()->copyTextToClipboard( mString ); +	// Increment the clipboard count +	mGeneration++; +	// Clear the clipboard +	mObjects.clear(); +	mCutMode = false; +	mString = LLWString();  } -void LLClipboard::copyFromString(const LLWString &src, const LLUUID& source_id ) +// Copy the input uuid to the LL clipboard +bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type)  { -	mSourceID = source_id; -	mString = src; -	LLView::getWindow()->copyTextToClipboard( mString ); +	reset(); +	return addToClipboard(src, type);  } -const LLWString& LLClipboard::getPasteWString( LLUUID* source_id ) +// Add the input uuid to the LL clipboard +// Convert the uuid to string and concatenate that string to the system clipboard if legit +bool LLClipboard::addToClipboard(const LLUUID& src, const LLAssetType::EType type)  { -	if( mSourceID.notNull() ) +	bool res = false; +	if (src.notNull())  	{ -		LLWString temp_string; -		LLView::getWindow()->pasteTextFromClipboard(temp_string); - -		if( temp_string != mString ) +		res = true; +		if (LLAssetType::lookupIsAssetIDKnowable(type))  		{ -			mSourceID.setNull(); -			mString = temp_string; +			LLWString source = utf8str_to_wstring(src.asString()); +			res = addToClipboard(source, 0, source.size()); +		} +		if (res) +		{ +			mObjects.push_back(src); +			mGeneration++;  		}  	} -	else -	{ -		LLView::getWindow()->pasteTextFromClipboard(mString); -	} +	return res; +} -	if( source_id ) +bool LLClipboard::pasteFromClipboard(std::vector<LLUUID>& inv_objects) const +{ +	bool res = false; +	S32 count = mObjects.size(); +	if (count > 0)  	{ -		*source_id = mSourceID; +		res = true; +		inv_objects.clear(); +		for (S32 i = 0; i < count; i++) +		{ +			inv_objects.push_back(mObjects[i]); +		}  	} - -	return mString; +	return res;  } +// Returns true if the LL Clipboard has pasteable items in it +bool LLClipboard::hasContents() const +{ +	return (mObjects.size() > 0); +} -BOOL LLClipboard::canPasteString() const +// Returns true if the input uuid is in the list of clipboard objects +bool LLClipboard::isOnClipboard(const LLUUID& object) const  { -	return LLView::getWindow()->isClipboardTextAvailable(); +	std::vector<LLUUID>::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object); +	return (iter != mObjects.end());  } +// Copy the input string to the LL and the system clipboard +bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) +{ +	return addToClipboard(src, pos, len, use_primary); +} -void LLClipboard::copyFromPrimarySubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +// Concatenate the input string to the LL and the system clipboard +bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary)  { -	mSourceID = source_id;  	mString = src.substr(pos, len); -	LLView::getWindow()->copyTextToPrimary( mString ); +	return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString));  } - -const LLWString& LLClipboard::getPastePrimaryWString( LLUUID* source_id ) +// Copy the System clipboard to the output string. +// Manage the LL Clipboard / System clipboard consistency +bool LLClipboard::pasteFromClipboard(LLWString &dst, bool use_primary)  { -	if( mSourceID.notNull() ) -	{ -		LLWString temp_string; -		LLView::getWindow()->pasteTextFromPrimary(temp_string); - -		if( temp_string != mString ) -		{ -			mSourceID.setNull(); -			mString = temp_string; -		} -	} -	else -	{ -		LLView::getWindow()->pasteTextFromPrimary(mString); -	} - -	if( source_id ) +	bool res = (use_primary ? LLView::getWindow()->pasteTextFromPrimary(dst) : LLView::getWindow()->pasteTextFromClipboard(dst)); +	if (res)  	{ -		*source_id = mSourceID; +		mString = dst;  	} - -	return mString; +	return res;  } - -BOOL LLClipboard::canPastePrimaryString() const +// Return true if there's something on the System clipboard +bool LLClipboard::isTextAvailable(bool use_primary) const  { -	return LLView::getWindow()->isPrimaryTextAvailable(); +	return (use_primary ? LLView::getWindow()->isPrimaryTextAvailable() : LLView::getWindow()->isClipboardTextAvailable());  } -void LLClipboard::setSourceObject(const LLUUID& source_id, LLAssetType::EType type)  -{ -	mSourceItem = new LLInventoryObject (source_id, LLUUID::null, type, ""); -} diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 9371b94284..fd2e7610df 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -27,46 +27,68 @@  #ifndef LL_LLCLIPBOARD_H  #define LL_LLCLIPBOARD_H +#include <boost/function.hpp>  #include "llstring.h"  #include "lluuid.h"  #include "stdenums.h" +#include "llsingleton.h" +#include "llassettype.h"  #include "llinventory.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLClipboard +// +// This class is used to cut/copy/paste text strings and inventory items around  +// the world. Use LLClipboard::instance().method() to use its methods. +// Note that the text and UUIDs are loosely coupled only. There are few cases +// where the viewer does offer a serialized version of the UUID on the clipboard. +// In those case, the text is overridden when copying/cutting the item.  +// In all other cases, the text and the UUIDs are very much independent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLClipboard +class LLClipboard : public LLSingleton<LLClipboard>  {  public:  	LLClipboard();  	~LLClipboard(); +	 +	// Clears the clipboard +	void reset(); +	// Returns the state of the clipboard so client can know if it has been modified (comparing with tracked state) +	int	getGeneration() const { return mGeneration; } -	/* We support two flavors of clipboard.  The default is the explicitly -	   copy-and-pasted clipboard.  The second is the so-called 'primary' clipboard -	   which is implicitly copied upon selection on platforms which expect this -	   (i.e. X11/Linux). */ - -	void		copyFromSubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); -	void		copyFromString(const LLWString ©_from, const LLUUID& source_id = LLUUID::null ); -	BOOL		canPasteString() const; -	const LLWString&	getPasteWString(LLUUID* source_id = NULL); +	// Text strings management: +	// ------------------------ +	// We support two flavors of text clipboards. The default is the explicitly +	// copy-and-pasted clipboard. The second is the so-called 'primary' clipboard +	// which is implicitly copied upon selection on platforms which expect this +	// (i.e. X11/Linux, Mac). +	bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); +	bool addToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); +	bool pasteFromClipboard(LLWString& dst, bool use_primary = false); +	bool isTextAvailable(bool use_primary = false) const; +	 +	// Object list management: +	// ----------------------- +	// Clears and adds one single object to the clipboard +	bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); +	// Adds one object to the current list of objects on the clipboard +	bool addToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); +	// Gets a copy of the objects on the clipboard +	bool pasteFromClipboard(std::vector<LLUUID>& inventory_objects) const; +	 +	bool hasContents() const;										// True if the clipboard has pasteable objects +	bool isOnClipboard(const LLUUID& object) const;					// True if the input object uuid is on the clipboard -	void		copyFromPrimarySubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); -	BOOL		canPastePrimaryString() const; -	const LLWString&	getPastePrimaryWString(LLUUID* source_id = NULL);	 +	bool isCutMode() const { return mCutMode; } +	void setCutMode(bool mode) { mCutMode = mode; mGeneration++; } -	// Support clipboard for object known only by their uuid and asset type -	void		  setSourceObject(const LLUUID& source_id, LLAssetType::EType type); -	const LLInventoryObject* getSourceObject() { return mSourceItem; } -	  private: -	LLUUID      mSourceID; -	LLWString	mString; -	LLInventoryObject* mSourceItem; +	std::vector<LLUUID> mObjects;		// Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat) +	LLWString mString;					// The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment) if the asset type is knowable. +	bool mCutMode;						// This is a convenience flag for the viewer. +	int mGeneration;					// Incremented when the clipboard changes so that interested parties can check for changes on the clipboard.	  }; - -// Global singleton -extern LLClipboard gClipboard; - -  #endif  // LL_LLCLIPBOARD_H diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 89d8842393..806d2ef3f6 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -613,7 +613,7 @@ void LLComboBox::showList()  	}  	mList->setOrigin(rect.mLeft, rect.mBottom);  	mList->reshape(rect.getWidth(), rect.getHeight()); -	mList->translateIntoRect(root_view_local, FALSE); +	mList->translateIntoRect(root_view_local);  	// Make sure we didn't go off bottom of screen  	S32 x, y; diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp index e01e331acf..e08ccb0b78 100644 --- a/indra/llui/llcontainerview.cpp +++ b/indra/llui/llcontainerview.cpp @@ -196,24 +196,24 @@ void LLContainerView::arrange(S32 width, S32 height, BOOL called_from_parent)  	if (total_height < height)  		total_height = height; +	LLRect my_rect = getRect();  	if (followsTop())  	{ -		// HACK: casting away const. Should use setRect or some helper function instead. -		const_cast<LLRect&>(getRect()).mBottom = getRect().mTop - total_height; +		my_rect.mBottom = my_rect.mTop - total_height;  	}  	else  	{ -		// HACK: casting away const. Should use setRect or some helper function instead. -		const_cast<LLRect&>(getRect()).mTop = getRect().mBottom + total_height; +		my_rect.mTop = my_rect.mBottom + total_height;  	} -	// HACK: casting away const. Should use setRect or some helper function instead. -		const_cast<LLRect&>(getRect()).mRight = getRect().mLeft + width; + +	my_rect.mRight = my_rect.mLeft + width; +	setRect(my_rect);  	top = total_height;  	if (mShowLabel) -		{ -			top -= 20; -		} +	{ +		top -= 20; +	}  	bottom = top; diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index 42e6c3c786..5f69c6af31 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -244,7 +244,7 @@ void LLDragHandleTop::reshapeTitleBox()  	const LLFontGL* font = LLFontGL::getFontSansSerif();  	S32 title_width = getRect().getWidth();  	title_width -= LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth(); -	S32 title_height = llround(font->getLineHeight()); +	S32 title_height = font->getLineHeight();  	LLRect title_rect;  	title_rect.setLeftTopAndSize(   		LEFT_PAD,  diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 33548151fd..8ca1e685a9 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -68,10 +68,10 @@ namespace LLInitParam  {  	void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues()  	{ -		declare("none",       LLFloaterEnums::OPEN_POSITIONING_NONE); -		declare("cascading",  LLFloaterEnums::OPEN_POSITIONING_CASCADING); -		declare("centered",   LLFloaterEnums::OPEN_POSITIONING_CENTERED); -		declare("specified",  LLFloaterEnums::OPEN_POSITIONING_SPECIFIED); +		declare("relative",   LLFloaterEnums::POSITIONING_RELATIVE); +		declare("cascading",  LLFloaterEnums::POSITIONING_CASCADING); +		declare("centered",   LLFloaterEnums::POSITIONING_CENTERED); +		declare("specified",  LLFloaterEnums::POSITIONING_SPECIFIED);  	}  } @@ -177,9 +177,7 @@ LLFloater::Params::Params()  	save_visibility("save_visibility", false),  	can_dock("can_dock", false),  	show_title("show_title", true), -	open_positioning("open_positioning", LLFloaterEnums::OPEN_POSITIONING_NONE), -	specified_left("specified_left"), -	specified_bottom("specified_bottom"), +	positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE),  	header_height("header_height", 0),  	legacy_header_height("legacy_header_height", 0),  	close_image("close_image"), @@ -249,9 +247,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)  	mCanClose(p.can_close),  	mDragOnLeft(p.can_drag_on_left),  	mResizable(p.can_resize), -	mOpenPositioning(p.open_positioning), -	mSpecifiedLeft(p.specified_left), -	mSpecifiedBottom(p.specified_bottom), +	mPositioning(p.positioning),  	mMinWidth(p.min_width),  	mMinHeight(p.min_height),  	mHeaderHeight(p.header_height), @@ -270,6 +266,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)  	mMinimizeSignal(NULL)  //	mNotificationContext(NULL)  { +	mPosition.setFloater(*this);  //	mNotificationContext = new LLFloaterNotificationContext(getHandle());  	// Clicks stop here. @@ -546,10 +543,18 @@ LLFloater::~LLFloater()  void LLFloater::storeRectControl()  { -	if( mRectControl.size() > 1 ) +	if (!mRectControl.empty())  	{  		getControlGroup()->setRect( mRectControl, getRect() );  	} +	if (!mPosXControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) +	{ +		getControlGroup()->setF32( mPosXControl, mPosition.mX ); +	} +	if (!mPosYControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) +	{ +		getControlGroup()->setF32( mPosYControl, mPosition.mY ); +	}  }  void LLFloater::storeVisibilityControl() @@ -568,23 +573,6 @@ void LLFloater::storeDockStateControl()  	}  } -LLRect LLFloater::getSavedRect() const -{ -	LLRect rect; - -	if (mRectControl.size() > 1) -	{ -		rect = getControlGroup()->getRect(mRectControl); -	} - -	return rect; -} - -bool LLFloater::hasSavedRect() const -{ -	return !getSavedRect().isEmpty(); -} -  // static  std::string LLFloater::getControlName(const std::string& name, const LLSD& key)  { @@ -862,7 +850,7 @@ void LLFloater::applyControlsAndPosition(LLFloater* other)  	{  		if (!applyRectControl())  		{ -			applyPositioning(other); +			applyPositioning(other, true);  		}  	}  } @@ -871,29 +859,68 @@ bool LLFloater::applyRectControl()  {  	bool saved_rect = false; +	LLRect screen_rect = calcScreenRect(); +	mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); +	  	LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName);  	if (last_in_group && last_in_group != this)  	{  		// other floaters in our group, position ourselves relative to them and don't save the rect  		mRectControl.clear(); -		mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP; +		mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;  	} -	else if (mRectControl.size() > 1) +	else  	{ -		// If we have a saved rect, use it -		const LLRect& rect = getControlGroup()->getRect(mRectControl); -		saved_rect = rect.notEmpty(); -		if (saved_rect) +		bool rect_specified = false; +		if (!mRectControl.empty())  		{ -			setOrigin(rect.mLeft, rect.mBottom); - -			if (mResizable) +			// If we have a saved rect, use it +			const LLRect& rect = getControlGroup()->getRect(mRectControl); +			if (rect.notEmpty()) saved_rect = true; +			if (saved_rect)  			{ -				reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); +				setOrigin(rect.mLeft, rect.mBottom); + +				if (mResizable) +				{ +					reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); +				} +				mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; +				LLRect screen_rect = calcScreenRect(); +				mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); +				rect_specified = true;  			}  		} + +		LLControlVariablePtr x_control = getControlGroup()->getControl(mPosXControl); +		LLControlVariablePtr y_control = getControlGroup()->getControl(mPosYControl); +		if (x_control.notNull()  +			&& y_control.notNull() +			&& !x_control->isDefault() +			&& !y_control->isDefault()) +		{ +			mPosition.mX = x_control->getValue().asReal(); +			mPosition.mY = y_control->getValue().asReal(); +			mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; +			applyRelativePosition(); + +			saved_rect = true; +		} + +		// remember updated position +		if (rect_specified) +		{ +			storeRectControl(); +		} +	} + +	if (saved_rect) +	{ +		// propagate any derived positioning data back to settings file +		storeRectControl();  	} +  	return saved_rect;  } @@ -910,50 +937,56 @@ bool LLFloater::applyDockState()  	return docked;  } -void LLFloater::applyPositioning(LLFloater* other) +void LLFloater::applyPositioning(LLFloater* other, bool on_open)  {  	// Otherwise position according to the positioning code -	switch (mOpenPositioning) +	switch (mPositioning)  	{ -	case LLFloaterEnums::OPEN_POSITIONING_CENTERED: +	case LLFloaterEnums::POSITIONING_CENTERED:  		center();  		break; -	case LLFloaterEnums::OPEN_POSITIONING_SPECIFIED: -		{ -			// Translate relative to snap rect -			setOrigin(mSpecifiedLeft, mSpecifiedBottom); -			const LLRect& snap_rect = gFloaterView->getSnapRect(); -			translate(snap_rect.mLeft, snap_rect.mBottom); -			translateIntoRect(snap_rect, FALSE); -		} +	case LLFloaterEnums::POSITIONING_SPECIFIED:  		break; -	case LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP: -	case LLFloaterEnums::OPEN_POSITIONING_CASCADING: -		if (other != NULL && other != this) +	case LLFloaterEnums::POSITIONING_CASCADING: +		if (!on_open)  		{ -			stackWith(*other); +			applyRelativePosition();  		} -		else +		// fall through +	case LLFloaterEnums::POSITIONING_CASCADE_GROUP: +		if (on_open)  		{ -			static const U32 CASCADING_FLOATER_HOFFSET = 0; -			static const U32 CASCADING_FLOATER_VOFFSET = 0; +			if (other != NULL && other != this) +			{ +				stackWith(*other); +			} +			else +			{ +				static const U32 CASCADING_FLOATER_HOFFSET = 0; +				static const U32 CASCADING_FLOATER_VOFFSET = 0; -			const LLRect& snap_rect = gFloaterView->getSnapRect(); +				const LLRect& snap_rect = gFloaterView->getSnapRect(); -			const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET; -			const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET; +				const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET; +				const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET; -			S32 rect_height = getRect().getHeight(); -			setOrigin(horizontal_offset, vertical_offset - rect_height); +				S32 rect_height = getRect().getHeight(); +				setOrigin(horizontal_offset, vertical_offset - rect_height); -			translate(snap_rect.mLeft, snap_rect.mBottom); -			translateIntoRect(snap_rect, FALSE); +				translate(snap_rect.mLeft, snap_rect.mBottom); +			} +			setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);  		}  		break; -	case LLFloaterEnums::OPEN_POSITIONING_NONE: +	case LLFloaterEnums::POSITIONING_RELATIVE: +		{ +			applyRelativePosition(); + +			break; +		}  	default:  		// Do nothing  		break; @@ -1071,7 +1104,9 @@ void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)  	if (by_user && !isMinimized())  	{  		storeRectControl(); -		mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE; +		mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; +		LLRect screen_rect = calcScreenRect(); +		mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();  	}  	// if not minimized, adjust all snapped dependents to new shape @@ -1249,6 +1284,7 @@ void LLFloater::setMinimized(BOOL minimize)  		// Reshape *after* setting mMinimized  		reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE ); +		applyPositioning(NULL, false);  	}  	make_ui_sound("UISndWindowClose"); @@ -1589,7 +1625,7 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock)  		if (mDocked)  		{  			setMinimized(FALSE); -			mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE; +			mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;  		}  		updateTitleButtons(); @@ -1623,7 +1659,7 @@ void LLFloater::onClickTearOff(LLFloater* self)  		self->openFloater(self->getKey());  		// only force position for floaters that don't have that data saved -		if (self->mRectControl.size() <= 1) +		if (self->mRectControl.empty())  		{  			new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight());  			self->setRect(new_rect); @@ -1681,6 +1717,8 @@ LLFloater* LLFloater::getClosableFloaterFromFocus()  	{  		if (it->hasFocus())  		{ +			LLFloater& floater = *it; +			focused_floater = &floater;  			break;  		}  	} @@ -1800,7 +1838,7 @@ void LLFloater::draw()  				const LLFontGL* font = LLFontGL::getFontSansSerif();  				LLRect r = getRect(); -				gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1,  +				gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - font->getLineHeight() - 1,   					titlebar_focus_color % alpha, 0, TRUE);  			}  		} @@ -2161,19 +2199,14 @@ LLFloaterView::LLFloaterView (const Params& p)  	mSnapOffsetBottom(0),  	mSnapOffsetRight(0)  { +	mSnapView = getHandle();  }  // By default, adjust vertical.  void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)  { -	S32 old_right = mLastSnapRect.mRight; -	S32 old_top = mLastSnapRect.mTop; -  	LLView::reshape(width, height, called_from_parent); -	S32 new_right = getSnapRect().mRight; -	S32 new_top = getSnapRect().mTop; -  	mLastSnapRect = getSnapRect();  	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) @@ -2186,35 +2219,39 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)  			continue;  		} -		if (!floaterp->isMinimized()) +		if (!floaterp->isMinimized() && floaterp->getCanDrag())  		{ -			LLRect r = floaterp->getRect(); +			LLRect old_rect = floaterp->getRect(); +			floaterp->applyPositioning(NULL, false); +			LLRect new_rect = floaterp->getRect(); -			// Compute absolute distance from each edge of screen -			S32 left_offset = llabs(r.mLeft - 0); -			S32 right_offset = llabs(old_right - r.mRight); +			//LLRect r = floaterp->getRect(); -			S32 top_offset = llabs(old_top - r.mTop); -			S32 bottom_offset = llabs(r.mBottom - 0); +			//// Compute absolute distance from each edge of screen +			//S32 left_offset = llabs(r.mLeft - 0); +			//S32 right_offset = llabs(old_right - r.mRight); -			S32 translate_x = 0; -			S32 translate_y = 0; +			//S32 top_offset = llabs(old_top - r.mTop); +			//S32 bottom_offset = llabs(r.mBottom - 0); -			if (left_offset > right_offset) -			{ -				translate_x = new_right - old_right; -			} +			S32 translate_x = new_rect.mLeft - old_rect.mLeft; +			S32 translate_y = new_rect.mBottom - old_rect.mBottom; -			if (top_offset < bottom_offset) -			{ -				translate_y = new_top - old_top; -			} +			//if (left_offset > right_offset) +			//{ +			//	translate_x = new_right - old_right; +			//} + +			//if (top_offset < bottom_offset) +			//{ +			//	translate_y = new_top - old_top; +			//}  			// don't reposition immovable floaters -			if (floaterp->getCanDrag()) -			{ -				floaterp->translate(translate_x, translate_y); -			} +			//if (floaterp->getCanDrag()) +			//{ +			//	floaterp->translate(translate_x, translate_y); +			//}  			BOOST_FOREACH(LLHandle<LLFloater> dependent_floater, floaterp->mDependents)  			{  				if (dependent_floater.get()) @@ -2641,6 +2678,8 @@ void LLFloaterView::refresh()  	}  } +const S32 FLOATER_MIN_VISIBLE_PIXELS = 16; +  void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside)  {  	if (floater->getParent() != this) @@ -2694,7 +2733,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out  	}  	// move window fully onscreen -	if (floater->translateIntoRect( getSnapRect(), allow_partial_outside )) +	if (floater->translateIntoRect( getSnapRect(), allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX ))  	{  		floater->clearSnapTarget();  	} @@ -2908,9 +2947,11 @@ void LLFloater::setInstanceName(const std::string& name)  		std::string ctrl_name = getControlName(mInstanceName, mKey);  		// save_rect and save_visibility only apply to registered floaters -		if (!mRectControl.empty()) +		if (mSaveRect)  		{  			mRectControl = LLFloaterReg::declareRectControl(ctrl_name); +			mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name); +			mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name);  		}  		if (!mVisibilityControl.empty())  		{ @@ -2967,7 +3008,10 @@ void LLFloater::initFromParams(const LLFloater::Params& p)  	LLPanel::initFromParams(p);  	// override any follows flags -	setFollows(FOLLOWS_NONE); +	if (mPositioning != LLFloaterEnums::POSITIONING_SPECIFIED) +	{ +		setFollows(FOLLOWS_NONE); +	}  	mTitle = p.title;  	mShortTitle = p.short_title; @@ -2986,14 +3030,9 @@ void LLFloater::initFromParams(const LLFloater::Params& p)  	mSingleInstance = p.single_instance;  	mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance; -	mOpenPositioning = p.open_positioning; -	mSpecifiedLeft = p.specified_left; -	mSpecifiedBottom = p.specified_bottom; +	mPositioning = p.positioning; -	if (p.save_rect && mRectControl.empty()) -	{ -		mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set -	} +	mSaveRect = p.save_rect;  	if (p.save_visibility)  	{  		mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set @@ -3108,7 +3147,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str  		params.rect.left.set(0);  	}  	params.from_xui = true; -	applyXUILayout(params, parent); +	applyXUILayout(params, parent, parent == gFloaterView ? gFloaterView->getSnapRect() : parent->getLocalRect());   	initFromParams(params);  	initFloater(params); @@ -3267,5 +3306,140 @@ void LLFloater::stackWith(LLFloater& other)  	next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());  	setShape(next_rect); + +	if (!other.getHost()) +	{ +		other.mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP; +		other.setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); +	}  } +void LLFloater::applyRelativePosition() +{ +	LLRect snap_rect = gFloaterView->getSnapRect(); +	LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); +	snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); +	LLRect floater_screen_rect = calcScreenRect(); + +	LLCoordGL new_center = mPosition.convert(); +	LLCoordGL cur_center(floater_screen_rect.getCenterX(), floater_screen_rect.getCenterY()); +	translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY); +} + + +LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater) +:	coord_t((S32)x, (S32)y) +{ +	mFloater = floater.getHandle(); +} + + +LLCoordFloater::LLCoordFloater(const LLCoordCommon& other, LLFloater& floater) +{ +	mFloater = floater.getHandle(); +	convertFromCommon(other); +} + +LLCoordFloater& LLCoordFloater::operator=(const LLCoordFloater& other) +{ +	mFloater = other.mFloater; +	coord_t::operator =(other); +	return *this; +} + +void LLCoordFloater::setFloater(LLFloater& floater) +{ +	mFloater = floater.getHandle(); +} + +bool LLCoordFloater::operator==(const LLCoordFloater& other) const  +{  +	return mX == other.mX && mY == other.mY && mFloater == other.mFloater;  +} + +LLCoordCommon LL_COORD_FLOATER::convertToCommon() const +{ +	const LLCoordFloater& self = static_cast<const LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); + +	LLRect snap_rect = gFloaterView->getSnapRect(); +	LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); +	snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + +	LLFloater* floaterp = mFloater.get(); +	S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; +	S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; +	LLCoordCommon out; +	if (self.mX < -0.5f) +	{ +		out.mX = llround(rescale(self.mX, -1.f, -0.5f, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft)); +	} +	else if (self.mX > 0.5f) +	{ +		out.mX = llround(rescale(self.mX, 0.5f, 1.f, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS)); +	} +	else +	{ +		out.mX = llround(rescale(self.mX, -0.5f, 0.5f, snap_rect.mLeft, snap_rect.mRight - floater_width)); +	} + +	if (self.mY < -0.5f) +	{ +		out.mY = llround(rescale(self.mY, -1.f, -0.5f, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom)); +	} +	else if (self.mY > 0.5f) +	{ +		out.mY = llround(rescale(self.mY, 0.5f, 1.f, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS)); +	} +	else +	{ +		out.mY = llround(rescale(self.mY, -0.5f, 0.5f, snap_rect.mBottom, snap_rect.mTop - floater_height)); +	} + +	// return center point instead of lower left +	out.mX += floater_width / 2; +	out.mY += floater_height / 2; + +	return out; +} + +void LL_COORD_FLOATER::convertFromCommon(const LLCoordCommon& from) +{ +	LLCoordFloater& self = static_cast<LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); +	LLRect snap_rect = gFloaterView->getSnapRect(); +	LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); +	snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + + +	LLFloater* floaterp = mFloater.get(); +	S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; +	S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; + +	S32 from_x = from.mX - floater_width / 2; +	S32 from_y = from.mY - floater_height / 2; + +	if (from_x < snap_rect.mLeft) +	{ +		self.mX = rescale(from_x, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft, -1.f, -0.5f); +	} +	else if (from_x + floater_width > snap_rect.mRight) +	{ +		self.mX = rescale(from_x, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); +	} +	else +	{ +		self.mX = rescale(from_x, snap_rect.mLeft, snap_rect.mRight - floater_width, -0.5f, 0.5f); +	} + +	if (from_y < snap_rect.mBottom) +	{ +		self.mY = rescale(from_y, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom, -1.f, -0.5f); +	} +	else if (from_y + floater_height > snap_rect.mTop) +	{ +		self.mY = rescale(from_y, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); +	} +	else +	{ +		self.mY = rescale(from_y, snap_rect.mBottom, snap_rect.mTop - floater_height, -0.5f, 0.5f); +	} +} diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 59b35d206f..64d6dcea04 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -64,12 +64,12 @@ namespace LLFloaterEnums  {  	enum EOpenPositioning  	{ -		OPEN_POSITIONING_NONE, -		OPEN_POSITIONING_CASCADING, -		OPEN_POSITIONING_CASCADE_GROUP, -		OPEN_POSITIONING_CENTERED, -		OPEN_POSITIONING_SPECIFIED, -		OPEN_POSITIONING_COUNT +		POSITIONING_RELATIVE, +		POSITIONING_CASCADING, +		POSITIONING_CASCADE_GROUP, +		POSITIONING_CENTERED, +		POSITIONING_SPECIFIED, +		POSITIONING_COUNT  	};  } @@ -82,6 +82,37 @@ namespace LLInitParam  	};  } +struct LL_COORD_FLOATER +{ +	typedef F32 value_t; + +	LLCoordCommon convertToCommon() const; +	void convertFromCommon(const LLCoordCommon& from); +protected: +	LLHandle<LLFloater> mFloater; +}; + +struct LLCoordFloater : LLCoord<LL_COORD_FLOATER> +{ +	typedef LLCoord<LL_COORD_FLOATER> coord_t; + +	LLCoordFloater() {} +	LLCoordFloater(F32 x, F32 y, LLFloater& floater); +	LLCoordFloater(const LLCoordCommon& other, LLFloater& floater); + +	LLCoordFloater& operator=(const LLCoordCommon& other) +	{ +		convertFromCommon(other); +		return *this; +	} + +	LLCoordFloater& operator=(const LLCoordFloater& other); + +	bool operator==(const LLCoordFloater& other) const; +	bool operator!=(const LLCoordFloater& other) const { return !(*this == other); } + +	void setFloater(LLFloater& floater); +};  class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater>  { @@ -132,10 +163,7 @@ public:  								can_dock,  								show_title; -		Optional<LLFloaterEnums::EOpenPositioning>	open_positioning; -		Optional<S32>								specified_left; -		Optional<S32>								specified_bottom; - +		Optional<LLFloaterEnums::EOpenPositioning>	positioning;  		Optional<S32>			header_height,  								legacy_header_height; // HACK see initFromXML() @@ -184,7 +212,7 @@ public:  	bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL);  	/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); -	/*virtual*/ BOOL canSnapTo(const LLView* other_view); +	/*virtual*/ BOOL canSnapTo(const LLView* other_view);   	/*virtual*/ void setSnappedTo(const LLView* snap_view);  	/*virtual*/ void setFocus( BOOL b );  	/*virtual*/ void setIsChrome(BOOL is_chrome); @@ -241,8 +269,6 @@ public:  	BOOL			isResizable() const				{ return mResizable; }  	void			setResizeLimits( S32 min_width, S32 min_height );  	void			getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; } -	LLRect			getSavedRect() const; -	bool			hasSavedRect() const;  	static std::string		getControlName(const std::string& name, const LLSD& key);  	static LLControlGroup*	getControlGroup(); @@ -324,7 +350,7 @@ public:  	void			enableResizeCtrls(bool enable, bool width = true, bool height = true); -	bool			isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mOpenPositioning); } +	bool			isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); }  protected:  	void			applyControlsAndPosition(LLFloater* other); @@ -332,7 +358,9 @@ protected:  	virtual bool	applyRectControl();  	bool			applyDockState(); -	void			applyPositioning(LLFloater* other); +	void			applyPositioning(LLFloater* other, bool on_open); +	void			applyRelativePosition(); +  	void			storeRectControl();  	void			storeVisibilityControl();  	void			storeDockStateControl(); @@ -396,7 +424,10 @@ public:  	commit_signal_t* mMinimizeSignal;  protected: +	bool			mSaveRect;  	std::string		mRectControl; +	std::string		mPosXControl; +	std::string		mPosYControl;  	std::string		mVisibilityControl;  	std::string		mDocStateControl;  	LLSD			mKey;				// Key used for retrieving instances; set (for now) by LLFLoaterReg @@ -422,9 +453,8 @@ private:  	BOOL			mDragOnLeft;  	BOOL			mResizable; -	LLFloaterEnums::EOpenPositioning	mOpenPositioning; -	S32									mSpecifiedLeft; -	S32									mSpecifiedBottom; +	LLFloaterEnums::EOpenPositioning	mPositioning; +	LLCoordFloater	mPosition;  	S32				mMinWidth;  	S32				mMinHeight; diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index e144b68f5e..9115eb7174 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -96,7 +96,9 @@ LLFloater* LLFloaterReg::getLastFloaterCascading()  		{  			LLFloater* inst = *iter; -			if (inst->getVisible() && inst->isPositioning(LLFloaterEnums::OPEN_POSITIONING_CASCADING)) +			if (inst->getVisible()  +				&& (inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADING) +					|| inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADE_GROUP)))  			{  				if (candidate_rect.mTop > inst->getRect().mTop)  				{ @@ -358,9 +360,7 @@ void LLFloaterReg::restoreVisibleInstances()  //static  std::string LLFloaterReg::getRectControlName(const std::string& name)  { -	std::string res = std::string("floater_rect_") + name; -	LLStringUtil::replaceChar( res, ' ', '_' ); -	return res; +	return std::string("floater_rect_") + getBaseControlName(name);  }  //static @@ -368,19 +368,48 @@ std::string LLFloaterReg::declareRectControl(const std::string& name)  {  	std::string controlname = getRectControlName(name);  	LLFloater::getControlGroup()->declareRect(controlname, LLRect(), -												 llformat("Window Position and Size for %s", name.c_str()), +												 llformat("Window Size for %s", name.c_str()),  												 TRUE);  	return controlname;  } +std::string LLFloaterReg::declarePosXControl(const std::string& name) +{ +	std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_x"; +	LLFloater::getControlGroup()->declareF32(controlname,  +											10.f, +											llformat("Window X Position for %s", name.c_str()), +											TRUE); +	return controlname; +} + +std::string LLFloaterReg::declarePosYControl(const std::string& name) +{ +	std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_y"; +	LLFloater::getControlGroup()->declareF32(controlname, +											10.f, +											llformat("Window Y Position for %s", name.c_str()), +											TRUE); + +	return controlname; +} + +  //static  std::string LLFloaterReg::getVisibilityControlName(const std::string& name)  { -	std::string res = std::string("floater_vis_") + name; +	return std::string("floater_vis_") + getBaseControlName(name); +} + +//static  +std::string LLFloaterReg::getBaseControlName(const std::string& name) +{ +	std::string res(name);  	LLStringUtil::replaceChar( res, ' ', '_' );  	return res;  } +  //static  std::string LLFloaterReg::declareVisibilityControl(const std::string& name)  { diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 534cf8b40a..a1e1f8a988 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -115,9 +115,11 @@ public:  	// Control Variables  	static std::string getRectControlName(const std::string& name);  	static std::string declareRectControl(const std::string& name); +	static std::string declarePosXControl(const std::string& name); +	static std::string declarePosYControl(const std::string& name);  	static std::string getVisibilityControlName(const std::string& name);  	static std::string declareVisibilityControl(const std::string& name); - +	static std::string getBaseControlName(const std::string& name);  	static std::string declareDockStateControl(const std::string& name);  	static std::string getDockStateControlName(const std::string& name); diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 2f1c2a47c9..4c730286da 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -36,7 +36,7 @@  #include "llcriticaldamp.h"  #include "boost/foreach.hpp" -static const F32 MIN_FRACTIONAL_SIZE = 0.0001f; +static const F32 MIN_FRACTIONAL_SIZE = 0.0f;  static const F32 MAX_FRACTIONAL_SIZE = 1.f;  static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack"); @@ -113,7 +113,26 @@ S32 LLLayoutPanel::getLayoutDim() const  					? getRect().getWidth()  					: getRect().getHeight()));  } -  + +S32 LLLayoutPanel::getTargetDim() const +{ +	return mTargetDim; +} + +void LLLayoutPanel::setTargetDim(S32 value) +{ +	LLRect new_rect(getRect()); +	if (mOrientation == LLLayoutStack::HORIZONTAL) +	{ +		new_rect.mRight = new_rect.mLeft + value; +	} +	else +	{ +		new_rect.mTop = new_rect.mBottom + value; +	} +	setShape(new_rect, true); +} +  S32 LLLayoutPanel::getVisibleDim() const  {  	F32 min_dim = getRelevantMinDim(); @@ -129,6 +148,12 @@ void LLLayoutPanel::setOrientation( LLLayoutStack::ELayoutOrientation orientatio  		? getRect().getWidth()  		: getRect().getHeight())); +	if (mAutoResize == FALSE  +		&& mUserResize == TRUE  +		&& mMinDim == -1 ) +	{ +		setMinDim(layout_dim); +	}  	mTargetDim = llmax(layout_dim, getMinDim());  } @@ -166,12 +191,15 @@ void LLLayoutPanel::handleReshape(const LLRect& new_rect, bool by_user)  	LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());  	if (stackp)  	{ -		stackp->mNeedsLayout = true;  		if (by_user) -		{ -			// tell layout stack to account for new shape +		{	// tell layout stack to account for new shape +			 +			// make sure that panels have already been auto resized +			stackp->updateLayout(); +			// now apply requested size to panel  			stackp->updatePanelRect(this, new_rect);  		} +		stackp->mNeedsLayout = true;  	}  	LLPanel::handleReshape(new_rect, by_user);  } @@ -235,7 +263,6 @@ void LLLayoutStack::draw()  			drawChild(panelp, 0, 0, !clip_rect.isEmpty());  		}  	} -	mAnimatedThisFrame = false;  }  void LLLayoutStack::removeChild(LLView* view) @@ -304,9 +331,8 @@ void LLLayoutStack::updateLayout()  	if (!mNeedsLayout) return; -	bool animation_in_progress = animatePanels(); +	bool continue_animating = animatePanels();  	F32 total_visible_fraction = 0.f; -	F32 total_open_fraction = 0.f;  	S32 space_to_distribute = (mOrientation == HORIZONTAL)  							? getRect().getWidth()  							: getRect().getHeight(); @@ -318,20 +344,17 @@ void LLLayoutStack::updateLayout()  		if (panelp->mAutoResize)  		{  			panelp->mTargetDim = panelp->getRelevantMinDim(); -			if (!panelp->mCollapsed && panelp->getVisible()) -			{ -				total_open_fraction += panelp->mFractionalSize; -			}  		}  		space_to_distribute -= panelp->getVisibleDim() + llround((F32)mPanelSpacing * panelp->getVisibleAmount()); -		total_visible_fraction += panelp->mFractionalSize; +		total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor();  	} -	llassert(total_visible_fraction < 1.01f); +	llassert(total_visible_fraction < 1.05f);  	// don't need spacing after last panel  	space_to_distribute += panelp ? llround((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0; +	S32 remaining_space = space_to_distribute;  	F32 fraction_distributed = 0.f;  	if (space_to_distribute > 0 && total_visible_fraction > 0.f)  	{	// give space proportionally to visible auto resize panels @@ -343,26 +366,23 @@ void LLLayoutStack::updateLayout()  				S32 delta = llround((F32)space_to_distribute * fraction_to_distribute);  				fraction_distributed += fraction_to_distribute;  				panelp->mTargetDim += delta; +				remaining_space -= delta;  			}  		}  	} -	if (fraction_distributed < total_visible_fraction) -	{	// distribute any left over pixels to non-collapsed, visible panels -		F32 fraction_left = total_visible_fraction - fraction_distributed; -		S32 space_left = llround((F32)space_to_distribute * (fraction_left / total_visible_fraction)); +	// distribute any left over pixels to non-collapsed, visible panels +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +	{ +		if (remaining_space == 0) break; -		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +		if (panelp->mAutoResize  +			&& !panelp->mCollapsed  +			&& panelp->getVisible())  		{ -			if (panelp->mAutoResize  -				&& !panelp->mCollapsed  -				&& panelp->getVisible()) -			{ -				S32 space_for_panel = llmax(0, llround((F32)space_left * (panelp->mFractionalSize / total_open_fraction))); -				panelp->mTargetDim += space_for_panel; -				space_left -= space_for_panel; -				total_open_fraction -= panelp->mFractionalSize; -			} +			S32 space_for_panel = remaining_space > 0 ? 1 : -1; +			panelp->mTargetDim += space_for_panel; +			remaining_space -= space_for_panel;  		}  	} @@ -416,7 +436,7 @@ void LLLayoutStack::updateLayout()  	// clear animation flag at end, since panel resizes will set it  	// and leave it set if there is any animation in progress -	mNeedsLayout = animation_in_progress; +	mNeedsLayout = continue_animating;  } // end LLLayoutStack::updateLayout  LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const @@ -489,38 +509,52 @@ void LLLayoutStack::updateClass()  	for (instance_iter it = beginInstances(); it != endInstances(); ++it)  	{  		it->updateLayout(); +		it->mAnimatedThisFrame = false;  	}  }  void LLLayoutStack::updateFractionalSizes()  { -	F32 total_resizable_dim = 0; -	S32 num_auto_resize_panels = 0; +	F32 total_resizable_dim = 0.f;  	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)  	{  		if (panelp->mAutoResize)  		{  			total_resizable_dim += llmax(0, panelp->getLayoutDim() - panelp->getRelevantMinDim()); -			num_auto_resize_panels++;  		}  	} -	F32 total_fractional_size = 0.f; -	  	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)  	{  		if (panelp->mAutoResize)  		{  			F32 panel_resizable_dim = llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim()));  			panelp->mFractionalSize = panel_resizable_dim > 0.f  -										? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE) -										: MIN_FRACTIONAL_SIZE; -			total_fractional_size += panelp->mFractionalSize; +				? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE) +				: MIN_FRACTIONAL_SIZE;  			llassert(!llisnan(panelp->mFractionalSize));  		}  	} +	normalizeFractionalSizes(); +} + + +void LLLayoutStack::normalizeFractionalSizes() +{ +	S32 num_auto_resize_panels = 0; +	F32 total_fractional_size = 0.f; +	 +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +	{ +		if (panelp->mAutoResize) +		{ +			total_fractional_size += panelp->mFractionalSize; +			num_auto_resize_panels++; +		} +	} +  	if (total_fractional_size == 0.f)  	{ // equal distribution  		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) @@ -545,7 +579,7 @@ void LLLayoutStack::updateFractionalSizes()  bool LLLayoutStack::animatePanels()  { -	bool animation_in_progress = false; +	bool continue_animating = false;  	//  	// animate visibility @@ -565,14 +599,15 @@ bool LLLayoutStack::animatePanels()  					}  				} -				animation_in_progress = true; +				mAnimatedThisFrame = true; +				continue_animating = true;  			}  			else  			{  				if (panelp->mVisibleAmt != 1.f)  				{  					panelp->mVisibleAmt = 1.f; -					animation_in_progress = true; +					mAnimatedThisFrame = true;  				}  			}  		} @@ -589,14 +624,15 @@ bool LLLayoutStack::animatePanels()  					}  				} -				animation_in_progress = true; +				continue_animating = true; +				mAnimatedThisFrame = true;  			}  			else  			{  				if (panelp->mVisibleAmt != 0.f)  				{  					panelp->mVisibleAmt = 0.f; -					animation_in_progress = true; +					mAnimatedThisFrame = true;  				}  			}  		} @@ -604,22 +640,31 @@ bool LLLayoutStack::animatePanels()  		F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f;  		if (panelp->mCollapseAmt != collapse_state)  		{ -			if (!mAnimatedThisFrame) +			if (mAnimate)  			{ -				panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); -			} -			animation_in_progress = true; +				if (!mAnimatedThisFrame) +				{ +					panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); +				} -			if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f) +				if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f) +				{ +					panelp->mCollapseAmt = collapse_state; +				} + +				mAnimatedThisFrame = true; +				continue_animating = true; +			} +			else  			{  				panelp->mCollapseAmt = collapse_state; +				mAnimatedThisFrame = true;  			}  		}  	} -	mAnimatedThisFrame = true; - -	return animation_in_progress; +	if (mAnimatedThisFrame) mNeedsLayout = true; +	return continue_animating;  }  void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& new_rect ) @@ -632,7 +677,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  	F32 total_visible_fraction = 0.f;  	F32 delta_auto_resize_headroom = 0.f; -	F32 total_auto_resize_headroom = 0.f; +	F32 original_auto_resize_headroom = 0.f;  	LLLayoutPanel* other_resize_panel = NULL;  	LLLayoutPanel* following_panel = NULL; @@ -641,8 +686,11 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  	{  		if (panelp->mAutoResize)  		{ -			total_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim()); -			total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor(); +			original_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim()); +			if (panelp->getVisible() && !panelp->mCollapsed) +			{ +				total_visible_fraction += panelp->mFractionalSize; +			}  		}  		if (panelp == resized_panel) @@ -656,18 +704,25 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  		}  	} -	if (resized_panel->mAutoResize == FALSE) + +	if (resized_panel->mAutoResize)  	{ -		delta_auto_resize_headroom += -delta_dim; +		if (!other_resize_panel || !other_resize_panel->mAutoResize) +		{ +			delta_auto_resize_headroom += delta_dim;	 +		}  	} -	if (other_resize_panel && other_resize_panel->mAutoResize == FALSE) +	else   	{ -		delta_auto_resize_headroom += delta_dim; +		if (!other_resize_panel || other_resize_panel->mAutoResize) +		{ +			delta_auto_resize_headroom -= delta_dim; +		}  	}  	F32 fraction_given_up = 0.f;  	F32 fraction_remaining = 1.f; -	F32 updated_auto_resize_headroom = total_auto_resize_headroom + delta_auto_resize_headroom; +	F32 updated_auto_resize_headroom = original_auto_resize_headroom + delta_auto_resize_headroom;  	enum  	{ @@ -691,14 +746,15 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  		case BEFORE_RESIZED_PANEL:  			if (panelp->mAutoResize)  			{	// freeze current size as fraction of overall auto_resize space -				F32 fractional_adjustment_factor = total_auto_resize_headroom / updated_auto_resize_headroom; +				F32 fractional_adjustment_factor = updated_auto_resize_headroom == 0.f +													? 1.f +													: original_auto_resize_headroom / updated_auto_resize_headroom;  				F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor,  													MIN_FRACTIONAL_SIZE,  													MAX_FRACTIONAL_SIZE); -				F32 fraction_delta = (new_fractional_size - panelp->mFractionalSize); -				fraction_given_up -= fraction_delta; +				fraction_given_up -= new_fractional_size - panelp->mFractionalSize;  				fraction_remaining -= panelp->mFractionalSize; -				panelp->mFractionalSize += fraction_delta; +				panelp->mFractionalSize = new_fractional_size;  				llassert(!llisnan(panelp->mFractionalSize));  			}  			else @@ -711,7 +767,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  			{	// freeze new size as fraction  				F32 new_fractional_size = (updated_auto_resize_headroom == 0.f)  					? MAX_FRACTIONAL_SIZE -					: llclamp((F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); +					: llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);  				fraction_given_up -= new_fractional_size - panelp->mFractionalSize;  				fraction_remaining -= panelp->mFractionalSize;  				panelp->mFractionalSize = new_fractional_size; @@ -720,7 +776,6 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  			else  			{	// freeze new size as original size  				panelp->mTargetDim = new_dim; -				fraction_remaining -= fraction_given_up;  			}  			which_panel = NEXT_PANEL;  			break; @@ -728,14 +783,14 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  			if (panelp->mAutoResize)  			{  				fraction_remaining -= panelp->mFractionalSize; -				if (fraction_given_up != 0.f) +				if (resized_panel->mAutoResize)  				{  					panelp->mFractionalSize = llclamp(panelp->mFractionalSize + fraction_given_up, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);  					fraction_given_up = 0.f;  				}  				else  				{ -					F32 new_fractional_size = llclamp((F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom)  +					F32 new_fractional_size = llclamp(total_visible_fraction * (F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom)   														/ updated_auto_resize_headroom,  													MIN_FRACTIONAL_SIZE,  													MAX_FRACTIONAL_SIZE); @@ -750,7 +805,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  			which_panel = AFTER_RESIZED_PANEL;  			break;  		case AFTER_RESIZED_PANEL: -			if (panelp->mAutoResize) +			if (panelp->mAutoResize && fraction_given_up != 0.f)  			{  				panelp->mFractionalSize = llclamp(panelp->mFractionalSize + (panelp->mFractionalSize / fraction_remaining) * fraction_given_up,  												MIN_FRACTIONAL_SIZE, @@ -760,6 +815,8 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  			break;  		}  	} +	updateLayout(); +	normalizeFractionalSizes();  }  void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent) diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index efe93f6def..648cd5fdce 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -72,7 +72,7 @@ public:  	/*virtual*/ void draw();  	/*virtual*/ void removeChild(LLView*);  	/*virtual*/ BOOL postBuild(); -	/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0); +	/*virtual*/ bool addChild(LLView* child, S32 tab_groupdatefractuiona = 0);  	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); @@ -112,6 +112,7 @@ private:  	LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;  	LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const;  	void updateFractionalSizes(); +	void normalizeFractionalSizes();  	void updatePanelRect( LLLayoutPanel* param1, const LLRect& new_rect );  	S32 mPanelSpacing; @@ -154,10 +155,12 @@ public:  	void setVisible(BOOL visible);  	S32 getLayoutDim() const; -	S32 getMinDim() const { return (mMinDim >= 0 || mAutoResize) ? llmax(0, mMinDim) : getLayoutDim(); } +	S32 getTargetDim() const; +	void setTargetDim(S32 value); +	S32 getMinDim() const { return llmax(0, mMinDim); }  	void setMinDim(S32 value) { mMinDim = value; } -	S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : mMinDim; } +	S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : getMinDim(); }  	void setExpandedMinDim(S32 value) { mExpandedMinDim = value; }  	S32 getRelevantMinDim() const diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 06dfc90d83..d0fbf4b913 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1047,7 +1047,7 @@ void LLLineEditor::cut()  		// Prepare for possible rollback  		LLLineEditorRollback rollback( this ); -		gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length );  		deleteSelection();  		// Validate new string and rollback the if needed. @@ -1078,13 +1078,13 @@ void LLLineEditor::copy()  	{  		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  		S32 length = llabs( mSelectionStart - mSelectionEnd ); -		gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length );  	}  }  BOOL LLLineEditor::canPaste() const  { -	return !mReadOnly && gClipboard.canPasteString();  +	return !mReadOnly && LLClipboard::instance().isTextAvailable();   }  void LLLineEditor::paste() @@ -1115,14 +1115,7 @@ void LLLineEditor::pasteHelper(bool is_primary)  	if (can_paste_it)  	{  		LLWString paste; -		if (is_primary) -		{ -			paste = gClipboard.getPastePrimaryWString(); -		} -		else  -		{ -			paste = gClipboard.getPasteWString(); -		} +		LLClipboard::instance().pasteFromClipboard(paste, is_primary);  		if (!paste.empty())  		{ @@ -1209,13 +1202,13 @@ void LLLineEditor::copyPrimary()  	{  		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  		S32 length = llabs( mSelectionStart - mSelectionEnd ); -		gClipboard.copyFromPrimarySubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length, true);  	}  }  BOOL LLLineEditor::canPastePrimary() const  { -	return !mReadOnly && gClipboard.canPastePrimaryString();  +	return !mReadOnly && LLClipboard::instance().isTextAvailable(true);   }  void LLLineEditor::updatePrimary() @@ -1630,7 +1623,7 @@ void LLLineEditor::draw()  	LLRect background( 0, getRect().getHeight(), getRect().getWidth(), 0 );  	background.stretch( -mBorderThickness ); -	S32 lineeditor_v_pad = llround((background.getHeight() - mGLFont->getLineHeight())/2); +	S32 lineeditor_v_pad = (background.getHeight() - mGLFont->getLineHeight()) / 2;  	drawBackground(); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 95ecbb1c94..ff6928ffda 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -317,7 +317,7 @@ void LLMenuItemGL::setJumpKey(KEY key)  // virtual   U32 LLMenuItemGL::getNominalHeight( void ) const   {  -	return llround(mFont->getLineHeight()) + MENU_ITEM_PADDING;  +	return mFont->getLineHeight() + MENU_ITEM_PADDING;  }  //virtual @@ -508,19 +508,19 @@ void LLMenuItemGL::draw( void )  	{  		if( !mDrawBoolLabel.empty() )  		{ -			mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +			mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  						   LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		} -		mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +		mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  					   LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		if( !mDrawAccelLabel.empty() )  		{ -			mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +			mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  						   LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		}  		if( !mDrawBranchLabel.empty() )  		{ -			mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +			mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  						   LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		}  	} @@ -1966,7 +1966,7 @@ void LLMenuGL::arrange( void )  		// *FIX: create the item first and then ask for its dimensions?  		S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate -		S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING; +		S32 spillover_item_height = LLFontGL::getFontSansSerif()->getLineHeight() + MENU_ITEM_PADDING;  		// Scrolling support  		item_list_t::iterator first_visible_item_iter; @@ -3082,7 +3082,7 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)  		mouse_y + MOUSE_CURSOR_PADDING,   		CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2,   		CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2); -	menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect, FALSE ); +	menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect );  	menu->getParent()->sendChildToFront(menu);  } @@ -3425,7 +3425,7 @@ void LLMenuHolderGL::draw()  		LLUI::pushMatrix();  		{ -			LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f); +			LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom);  			selecteditem->getMenu()->drawBackground(selecteditem, interpolant);  			selecteditem->draw();  		} diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index f3a48835b1..aa5f577897 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -349,7 +349,7 @@ void LLMultiFloater::setVisible(BOOL visible)  BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)  { -	if (key == 'W' && mask == (MASK_CONTROL|MASK_SHIFT)) +	if (key == 'W' && mask == MASK_CONTROL)  	{  		LLFloater* floater = getActiveFloater();  		// is user closeable and is system closeable diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index d232e27ef2..09480968a6 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -399,6 +399,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par  :	mName(p.name),  	mType(p.type),  	mMessage(p.value), +	mFooter(p.footer.value),  	mLabel(p.label),  	mIcon(p.icon),  	mURL(p.url.value), @@ -870,6 +871,16 @@ std::string LLNotification::getMessage() const  	return message;  } +std::string LLNotification::getFooter() const +{ +	if (!mTemplatep) +		return std::string(); + +	std::string footer = mTemplatep->mFooter; +	LLStringUtil::format(footer, mSubstitutions); +	return footer; +} +  std::string LLNotification::getLabel() const  {  	std::string label = mTemplatep->mLabel; @@ -1412,6 +1423,7 @@ void addPathIfExists(const std::string& new_path, std::vector<std::string>& path  bool LLNotifications::loadTemplates()  { +	llinfos << "Reading notifications template" << llendl;  	std::vector<std::string> search_paths;  	std::string skin_relative_path = gDirUtilp->getDirDelimiter() + LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + "notifications.xml"; @@ -1484,6 +1496,8 @@ bool LLNotifications::loadTemplates()  		mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification));  	} +	llinfos << "...done" << llendl; +  	return true;  } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 462d69be2e..4ae02b943f 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -509,6 +509,7 @@ public:  	std::string getType() const;  	std::string getMessage() const; +	std::string getFooter() const;  	std::string getLabel() const;  	std::string getURL() const;  	S32 getURLOption() const; @@ -690,7 +691,7 @@ typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;  // Abstract base class (interface) for a channel; also used for the master container.  // This lets us arrange channels into a call hierarchy. -// We maintain a heirarchy of notification channels; events are always started at the top +// We maintain a hierarchy of notification channels; events are always started at the top  // and propagated through the hierarchy only if they pass a filter.  // Any channel can be created with a parent. A null parent (empty string) means it's  // tied to the root of the tree (the LLNotifications class itself). diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index fb50c9c123..72973789db 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -167,6 +167,17 @@ struct LLNotificationTemplate  		{}  	}; +	struct Footer : public LLInitParam::Block<Footer> +	{ +		Mandatory<std::string> value; + +		Footer() +		:	value("value") +		{ +			addSynonym(value, ""); +		} +	}; +  	struct Params : public LLInitParam::Block<Params>  	{  		Mandatory<std::string>			name; @@ -184,7 +195,8 @@ struct LLNotificationTemplate  		Optional<FormRef>				form_ref;  		Optional<ENotificationPriority,   			NotificationPriorityValues> priority; -		Multiple<Tag>		tags; +		Multiple<Tag>					tags; +		Optional<Footer>				footer;  		Params() @@ -202,7 +214,8 @@ struct LLNotificationTemplate  			url("url"),  			unique("unique"),  			form_ref(""), -			tags("tag") +			tags("tag"), +			footer("footer")  		{}  	}; @@ -231,6 +244,8 @@ struct LLNotificationTemplate      // The text used to display the notification. Replaceable parameters      // are enclosed in square brackets like this [].      std::string mMessage; +    // The text used to display the notification, but under the form. +    std::string mFooter;  	// The label for the notification; used for   	// certain classes of notification (those with a window and a window title).   	// Also used when a notification pops up underneath the current one. diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index ad4cc20d9a..9b7e30bb04 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -378,19 +378,24 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height  	if (!mHideScrollbar)  	{ -		if( *visible_height < doc_height ) +		// Note: 1 pixel change can happen on final animation and should not trigger  +		// the display of sliders. +		if ((doc_height - *visible_height) > 1)  		{  			*show_v_scrollbar = TRUE;  			*visible_width -= scrollbar_size;  		} - -		if( *visible_width < doc_width ) +		if ((doc_width - *visible_width) > 1)  		{  			*show_h_scrollbar = TRUE;  			*visible_height -= scrollbar_size; +			// The view inside the scroll container should not be extended +			// to container's full height to ensure the correct computation +			// of *show_v_scrollbar after subtracting horizontal scrollbar_size. +  			// Must retest now that visible_height has changed -			if( !*show_v_scrollbar && (*visible_height < doc_height) ) +			if( !*show_v_scrollbar && ((doc_height - *visible_height) > 1) )  			{  				*show_v_scrollbar = TRUE;  				*visible_width -= scrollbar_size; diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 3aa79cc255..d87c95b3d7 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -91,7 +91,7 @@ public:  	void			setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; }  	LLRect			getVisibleContentRect();  	LLRect			getContentWindowRect(); -	const LLRect&	getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } +	virtual const LLRect	getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; }  	void			pageUp(S32 overlap = 0);  	void			pageDown(S32 overlap = 0);  	void			goToTop(); @@ -116,6 +116,9 @@ public:  	bool autoScroll(S32 x, S32 y); +protected: +	LLView*		mScrolledView; +  private:  	// internal scrollbar handlers  	virtual void scrollHorizontal( S32 new_pos ); @@ -124,7 +127,6 @@ private:  	void calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const;  	LLScrollbar* mScrollbar[SCROLLBAR_COUNT]; -	LLView*		mScrolledView;  	S32			mSize;  	BOOL		mIsOpaque;  	LLUIColor	mBackgroundColor; diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 9d25c7180d..8000efad0e 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -232,7 +232,7 @@ BOOL LLScrollListText::getVisible() const  //virtual   S32 LLScrollListText::getHeight() const  { -	return llround(mFont->getLineHeight()); +	return mFont->getLineHeight();  } @@ -306,7 +306,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col  			break;  		}  		LLRect highlight_rect(left - 2,  -				llround(mFont->getLineHeight()) + 1,  +				mFont->getLineHeight() + 1,   				left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,   				1);  		mRoundedRectImage->draw(highlight_rect, highlight_color); @@ -329,7 +329,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col  		break;  	}  	mFont->render(mText.getWString(), 0,  -					start_x, 2.f, +					start_x, 0.f,  					display_color,  					mFontAlignment,  					LLFontGL::BOTTOM,  diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 466fac33ea..b3e1b63db5 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -2504,7 +2504,7 @@ void	LLScrollListCtrl::copy()  	{  		buffer += (*itor)->getContentsCSV() + "\n";  	} -	gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); +	LLClipboard::instance().copyToClipboard(utf8str_to_wstring(buffer), 0, buffer.length());  }  // virtual diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp index d95752e31c..5a1e96ab03 100644 --- a/indra/llui/llscrolllistitem.cpp +++ b/indra/llui/llscrolllistitem.cpp @@ -138,7 +138,7 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const  		LLUI::pushMatrix();  		{ -			LLUI::translate((F32) cur_x, (F32) rect.mBottom, 0.0f); +			LLUI::translate((F32) cur_x, (F32) rect.mBottom);  			cell->draw( fg_color, highlight_color );  		} diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h index 611df729b4..13655b5873 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -33,10 +33,10 @@  #include "v4color.h"  #include "llinitparam.h"  #include "llscrolllistcell.h" +#include "llcoord.h"  #include <vector> -class LLCoordGL;  class LLCheckBoxCtrl;  class LLResizeBar;  class LLScrollListCtrl; diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp deleted file mode 100644 index 0e29873bb0..0000000000 --- a/indra/llui/llsdparam.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/**  - * @file llsdparam.cpp - * @brief parameter block abstraction for creating complex objects and  - * parsing construction parameters from xml and LLSD - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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" - -// Project includes -#include "llsdparam.h" -#include "llsdutil.h" - -static 	LLInitParam::Parser::parser_read_func_map_t sReadFuncs; -static 	LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; -static 	LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; -static const LLSD NO_VALUE_MARKER; - -LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); - -// -// LLParamSDParser -// -LLParamSDParser::LLParamSDParser() -: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) -{ -	using boost::bind; - -	if (sReadFuncs.empty()) -	{ -		registerParserFuncs<LLInitParam::Flag>(readFlag, &LLParamSDParser::writeFlag); -		registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>); -		registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param); -		registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); -		registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>); -		registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>); -		registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>); -		registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>); -		registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>); -		registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>); -		registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>); -	} -} - -// special case handling of U32 due to ambiguous LLSD::assign overload -bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -{ -	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); -	if (!sdparser.mWriteRootSD) return false; -	 -	parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); -	LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); -	sd_to_write.assign((S32)*((const U32*)val_ptr)); - -	return true; -} - -bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -{ -	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); -	if (!sdparser.mWriteRootSD) return false; - -	parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); -	LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - -	return true; -} - -void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack) -{ -	mCurReadSD = &sd; -	block.submitValue(name_stack, *this); -} - -void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent) -{ -	mCurReadSD = NULL; -	mNameStack.clear(); -	setParseSilently(silent); - -	LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); -	//readSDValues(sd, block); -} - -void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) -{ -	mNameStack.clear(); -	mWriteRootSD = &sd; - -	name_stack_t name_stack; -	block.serializeBlock(*this, name_stack); -} - -/*virtual*/ std::string LLParamSDParser::getCurrentElementName() -{ -	std::string full_name = "sd"; -	for (name_stack_t::iterator it = mNameStack.begin();	 -		it != mNameStack.end(); -		++it) -	{ -		full_name += llformat("[%s]", it->first.c_str()); -	} - -	return full_name; -} - - -bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); -	return self.mCurReadSD == &NO_VALUE_MARKER; -} - - -bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((S32*)val_ptr) = self.mCurReadSD->asInteger(); -    return true; -} - -bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((U32*)val_ptr) = self.mCurReadSD->asInteger(); -    return true; -} - -bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((F32*)val_ptr) = self.mCurReadSD->asReal(); -    return true; -} - -bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((F64*)val_ptr) = self.mCurReadSD->asReal(); -    return true; -} - -bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((bool*)val_ptr) = self.mCurReadSD->asBoolean(); -    return true; -} - -bool LLParamSDParser::readString(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((std::string*)val_ptr) = self.mCurReadSD->asString(); -    return true; -} - -bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); -    return true; -} - -bool LLParamSDParser::readDate(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLDate*)val_ptr) = self.mCurReadSD->asDate(); -    return true; -} - -bool LLParamSDParser::readURI(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLURI*)val_ptr) = self.mCurReadSD->asURI(); -    return true; -} - -bool LLParamSDParser::readSD(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLSD*)val_ptr) = *self.mCurReadSD; -    return true; -} - -// static -LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range) -{ -	LLSD* sd_to_write = &input; -	 -	for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; -		it != name_stack_range.second; -		++it) -	{ -		bool new_traversal = it->second; - -		LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; - -		if (child_sd->isArray()) -		{ -			if (new_traversal) -			{ -				// write to new element at end -				sd_to_write = &(*child_sd)[child_sd->size()]; -			} -			else -			{ -				// write to last of existing elements, or first element if empty -				sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; -			} -		} -		else -		{ -			if (new_traversal  -				&& child_sd->isDefined()  -				&& !child_sd->isArray()) -			{ -				// copy child contents into first element of an array -				LLSD new_array = LLSD::emptyArray(); -				new_array.append(*child_sd); -				// assign array to slot that previously held the single value -				*child_sd = new_array; -				// return next element in that array -				sd_to_write = &((*child_sd)[1]); -			} -			else -			{ -				sd_to_write = child_sd; -			} -		} -		it->second = false; -	} -	 -	return *sd_to_write; -} - -//static -void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack) -{ -	if (sd.isMap()) -	{ -		for (LLSD::map_const_iterator it = sd.beginMap(); -			it != sd.endMap(); -			++it) -		{ -			stack.push_back(make_pair(it->first, true)); -			readSDValues(cb, it->second, stack); -			stack.pop_back(); -		} -	} -	else if (sd.isArray()) -	{ -		for (LLSD::array_const_iterator it = sd.beginArray(); -			it != sd.endArray(); -			++it) -		{ -			stack.back().second = true; -			readSDValues(cb, *it, stack); -		} -	} -	else if (sd.isUndefined()) -	{ -		if (!cb.empty()) -		{ -			cb(NO_VALUE_MARKER, stack); -		} -	} -	else -	{ -		if (!cb.empty()) -		{ -			cb(sd, stack); -		} -	} -} - -//static -void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) -{ -	LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); -	readSDValues(cb, sd, stack); -} -namespace LLInitParam -{ -	// LLSD specialization -	// block param interface -	bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) -	{ -		LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); - -		LLSD::String string; - -		if (p.readValue<LLSD::String>(string)) -		{ -			sd = string; -			return true; -		} -		return false; -	} - -	//static -	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) -	{ -		p.writeValue<LLSD::String>(sd.asString(), name_stack); -	} - -	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const -	{ -		// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) -		Parser::name_stack_t stack; -		LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); -	} -} diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h deleted file mode 100644 index 3dfc6d020e..0000000000 --- a/indra/llui/llsdparam.h +++ /dev/null @@ -1,126 +0,0 @@ -/**  - * @file llsdparam.h - * @brief parameter block abstraction for creating complex objects and  - * parsing construction parameters from xml and LLSD - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 LL_LLSDPARAM_H -#define LL_LLSDPARAM_H - -#include "llinitparam.h" -#include "boost/function.hpp" - -struct LLParamSDParserUtilities -{ -	static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); - -	typedef boost::function<void (const LLSD&, LLInitParam::Parser::name_stack_t&)> read_sd_cb_t; -	static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); -	static void readSDValues(read_sd_cb_t cb, const LLSD& sd); -}; - -class LLParamSDParser  -:	public LLInitParam::Parser -{ -LOG_CLASS(LLParamSDParser); - -typedef LLInitParam::Parser parser_t; - -public: -	LLParamSDParser(); -	void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); -	void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); - -	/*virtual*/ std::string getCurrentElementName(); - -private: -	void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); - -	template<typename T> -	static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -	{ -		LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); -		if (!sdparser.mWriteRootSD) return false; -		 -		LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); -		LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - -		sd_to_write.assign(*((const T*)val_ptr)); -		return true; -	} - -	static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); -	static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - -	static bool readFlag(Parser& parser, void* val_ptr); -	static bool readS32(Parser& parser, void* val_ptr); -	static bool readU32(Parser& parser, void* val_ptr); -	static bool readF32(Parser& parser, void* val_ptr); -	static bool readF64(Parser& parser, void* val_ptr); -	static bool readBool(Parser& parser, void* val_ptr); -	static bool readString(Parser& parser, void* val_ptr); -	static bool readUUID(Parser& parser, void* val_ptr); -	static bool readDate(Parser& parser, void* val_ptr); -	static bool readURI(Parser& parser, void* val_ptr); -	static bool readSD(Parser& parser, void* val_ptr); - -	Parser::name_stack_t	mNameStack; -	const LLSD*				mCurReadSD; -	LLSD*					mWriteRootSD; -	LLSD*					mCurWriteSD; -}; - - -extern LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR; -template<typename T> -class LLSDParamAdapter : public T -{ -public: -	LLSDParamAdapter() {} -	LLSDParamAdapter(const LLSD& sd) -	{ -		LLFastTimer _(FTM_SD_PARAM_ADAPTOR); -		LLParamSDParser parser; -		// don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it -		bool parse_silently = true; -		parser.readSD(sd, *this, parse_silently); -	} - -	operator LLSD() const -	{ -		LLParamSDParser parser; -		LLSD sd; -		parser.writeSD(sd, *this); -		return sd; -	} -		 -	LLSDParamAdapter(const T& val) -	: T(val) -	{ -		T::operator=(val); -	} -}; - -#endif // LL_LLSDPARAM_H - diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index ec4db14790..04cce7878e 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -272,7 +272,7 @@ LLRect LLStatBar::getRequiredRect()  	{  		if (mDisplayHistory)  		{ -			rect.mTop = 67; +			rect.mTop = 35 + mStatp->getNumBins();  		}  		else  		{ diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0040be45c7..7aeeae298f 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1192,7 +1192,10 @@ void LLTextBase::reflow()  		// shrink document to minimum size (visible portion of text widget)  		// to force inlined widgets with follows set to shrink -		mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight()); +		if (mWordWrap) +		{ +			mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight()); +		}  		S32 cur_top = 0; @@ -2157,7 +2160,7 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const  	{   		// return default height rect in upper left  		local_rect = content_window_rect; -		local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight()); +		local_rect.mBottom = local_rect.mTop - mDefaultFont->getLineHeight();  		return local_rect;  	} @@ -2380,6 +2383,9 @@ S32 LLTextBase::getEditableIndex(S32 index, bool increasing_direction)  void LLTextBase::updateRects()  { +	LLRect old_text_rect = mVisibleTextRect; +	mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); +  	if (mLineInfoList.empty())   	{  		mTextBoundingRect = LLRect(0, mVPad, mHPad, 0); @@ -2395,10 +2401,24 @@ void LLTextBase::updateRects()  		}  		mTextBoundingRect.mTop += mVPad; -		// subtract a pixel off the bottom to deal with rounding errors in measuring font height -		mTextBoundingRect.mBottom -= 1; -		S32 delta_pos = -mTextBoundingRect.mBottom; +		S32 delta_pos = 0; +		 +		switch(mVAlign) +		{ +		case LLFontGL::TOP: +			delta_pos = llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom); +			break; +		case LLFontGL::VCENTER: +			delta_pos = (llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom) + (mVisibleTextRect.mBottom - mTextBoundingRect.mBottom)) / 2; +			break; +		case LLFontGL::BOTTOM: +			delta_pos = mVisibleTextRect.mBottom - mTextBoundingRect.mBottom; +			break; +		case LLFontGL::BASELINE: +			// do nothing +			break; +		}  		// move line segments to fit new document rect  		for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it)  		{ @@ -2408,8 +2428,9 @@ void LLTextBase::updateRects()  	}  	// update document container dimensions according to text contents -	LLRect doc_rect = mTextBoundingRect; +	LLRect doc_rect;  	// use old mVisibleTextRect constraint document to width of viewable region +	doc_rect.mBottom = llmin(mVisibleTextRect.mBottom,  mTextBoundingRect.mBottom);  	doc_rect.mLeft = 0;  	// allow horizontal scrolling? @@ -2419,11 +2440,22 @@ void LLTextBase::updateRects()  	doc_rect.mRight = mScroller   		? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight)  		: mVisibleTextRect.getWidth(); +	doc_rect.mTop = llmax(mVisibleTextRect.mTop, mTextBoundingRect.mTop);  	if (!mScroller)  	{  		// push doc rect to top of text widget -		doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); +		switch(mVAlign) +		{ +		case LLFontGL::TOP: +			doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); +			break; +		case LLFontGL::VCENTER: +			doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); +		case LLFontGL::BOTTOM: +		default: +			break; +		}  	}  	mDocumentView->setShape(doc_rect); @@ -2431,7 +2463,6 @@ void LLTextBase::updateRects()  	//update mVisibleTextRect *after* mDocumentView has been resized  	// so that scrollbars are added if document needs to scroll  	// since mVisibleTextRect does not include scrollbars -	LLRect old_text_rect = mVisibleTextRect;  	mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect();  	//FIXME: replace border with image?  	if (mBorderVisible) @@ -2444,9 +2475,27 @@ void LLTextBase::updateRects()  	}  	// update document container again, using new mVisibleTextRect (that has scrollbars enabled as needed) +	doc_rect.mBottom = llmin(mVisibleTextRect.mBottom,  mTextBoundingRect.mBottom); +	doc_rect.mLeft = 0;  	doc_rect.mRight = mScroller   		? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight)  		: mVisibleTextRect.getWidth(); +	doc_rect.mTop = llmax(mVisibleTextRect.mTop, mTextBoundingRect.mTop); +	if (!mScroller) +	{ +		// push doc rect to top of text widget +		switch(mVAlign) +		{ +		case LLFontGL::TOP: +			doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); +			break; +		case LLFontGL::VCENTER: +			doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); +		case LLFontGL::BOTTOM: +		default: +			break; +		} +	}  	mDocumentView->setShape(doc_rect);  } @@ -2560,8 +2609,7 @@ BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE;  BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; }  const std::string&	LLTextSegment::getName() const   { -	static std::string empty_string(""); -	return empty_string;  +	return LLStringUtil::null;  }  void LLTextSegment::onMouseCaptureLost() {}  void LLTextSegment::screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const {} @@ -2578,7 +2626,7 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e  	mToken(NULL),  	mEditor(editor)  { -	mFontHeight = llceil(mStyle->getFont()->getLineHeight()); +	mFontHeight = mStyle->getFont()->getLineHeight();  	LLUIImagePtr image = mStyle->getImage();  	if (image.notNull()) @@ -2594,7 +2642,7 @@ LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32  {  	mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); -	mFontHeight = llceil(mStyle->getFont()->getLineHeight()); +	mFontHeight = mStyle->getFont()->getLineHeight();  }  LLNormalTextSegment::~LLNormalTextSegment() @@ -2962,11 +3010,11 @@ LLLineBreakTextSegment::LLLineBreakTextSegment(S32 pos):LLTextSegment(pos,pos+1)  {  	LLStyleSP s( new LLStyle(LLStyle::Params().visible(true))); -	mFontHeight = llceil(s->getFont()->getLineHeight()); +	mFontHeight = s->getFont()->getLineHeight();  }  LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLTextSegment(pos,pos+1)  { -	mFontHeight = llceil(style->getFont()->getLineHeight()); +	mFontHeight = style->getFont()->getLineHeight();  }  LLLineBreakTextSegment::~LLLineBreakTextSegment()  { @@ -3003,7 +3051,7 @@ static const S32 IMAGE_HPAD = 3;  bool LLImageTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const  {  	width = 0; -	height = llceil(mStyle->getFont()->getLineHeight());; +	height = mStyle->getFont()->getLineHeight();  	LLUIImagePtr image = mStyle->getImage();  	if( num_chars>0 && image.notNull()) diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3a23ce1cac..9720dded6c 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1332,7 +1332,7 @@ void LLTextEditor::cut()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromSubstring( getWText(), left_pos, length, mSourceID ); +	LLClipboard::instance().copyToClipboard( getWText(), left_pos, length);  	deleteSelection( FALSE );  	onKeyStroke(); @@ -1352,12 +1352,12 @@ void LLTextEditor::copy()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromSubstring(getWText(), left_pos, length, mSourceID); +	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length);  }  BOOL LLTextEditor::canPaste() const  { -	return !mReadOnly && gClipboard.canPasteString(); +	return !mReadOnly && LLClipboard::instance().isTextAvailable();  }  // paste from clipboard @@ -1393,16 +1393,8 @@ void LLTextEditor::pasteHelper(bool is_primary)  		return;  	} -	LLUUID source_id;  	LLWString paste; -	if (is_primary) -	{ -		paste = gClipboard.getPastePrimaryWString(&source_id); -	} -	else  -	{ -		paste = gClipboard.getPasteWString(&source_id); -	} +	LLClipboard::instance().pasteFromClipboard(paste, is_primary);  	if (paste.empty())  	{ @@ -1475,12 +1467,12 @@ void LLTextEditor::copyPrimary()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromPrimarySubstring(getWText(), left_pos, length, mSourceID); +	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true);  }  BOOL LLTextEditor::canPastePrimary() const  { -	return !mReadOnly && gClipboard.canPastePrimaryString(); +	return !mReadOnly && LLClipboard::instance().isTextAvailable(true);  }  void LLTextEditor::updatePrimary() @@ -1992,7 +1984,7 @@ void LLTextEditor::drawPreeditMarker()  		return;  	} -	const S32 line_height = llround( mDefaultFont->getLineHeight() ); +	const S32 line_height = mDefaultFont->getLineHeight();  	S32 line_start = getLineStart(cur_line);  	S32 line_y = mVisibleTextRect.mTop - line_height; @@ -2715,7 +2707,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect      const LLWString textString(getWText());  	const llwchar * const text = textString.c_str(); -	const S32 line_height = llround(mDefaultFont->getLineHeight()); +	const S32 line_height = mDefaultFont->getLineHeight();  	if (coord)  	{ @@ -2818,7 +2810,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length)  S32 LLTextEditor::getPreeditFontSize() const  { -	return llround(mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]); +	return llround((F32)mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);  }  BOOL LLTextEditor::isDirty() const diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 9b31a6449d..81ea0ebf0c 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -827,7 +827,7 @@ void LLToolBar::draw()  	// rect may have shifted during layout  	LLUI::popMatrix();  	LLUI::pushMatrix(); -	LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom, 0.f); +	LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom);  	// Position the caret   	LLIconCtrl* caret = getChild<LLIconCtrl>("caret"); diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 23cdd9ad9a..f737d48abf 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -180,6 +180,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)  	params.font = p.font;  	params.use_ellipses = true;  	params.wrap = p.wrap; +	params.font_valign = LLFontGL::VCENTER;  	params.parse_urls = false; // disallow hyperlinks in tooltips, as they want to spawn their own explanatory tooltips  	mTextBox = LLUICtrlFactory::create<LLTextBox> (params);  	addChild(mTextBox); @@ -190,7 +191,6 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)  	{  		LLButton::Params icon_params;  		icon_params.name = "tooltip_info"; -		icon_params.label(""); // provid label but set to empty so name does not overwrite it -angela  		LLRect icon_rect;  		LLUIImage* imagep = p.image;  		TOOLTIP_ICON_SIZE = (imagep ? imagep->getWidth() : 16); @@ -291,6 +291,12 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  	S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth());  	S32 text_height = mTextBox->getTextPixelHeight();  	mTextBox->reshape(text_width, text_height); +	if (mInfoButton) +	{ +		LLRect text_rect = mTextBox->getRect(); +		LLRect icon_rect = mInfoButton->getRect(); +		mTextBox->translate(0, icon_rect.getCenterY() - text_rect.getCenterY()); +	}  	// reshape tooltip panel to fit text box  	LLRect tooltip_rect = calcBoundingRect(); @@ -299,6 +305,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  	tooltip_rect.mBottom = 0;  	tooltip_rect.mLeft = 0; +	mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); +  	setShape(tooltip_rect);  } diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp new file mode 100644 index 0000000000..5388069c24 --- /dev/null +++ b/indra/llui/lltrans.cpp @@ -0,0 +1,295 @@ +/** + * @file lltrans.cpp + * @brief LLTrans implementation + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 "lltrans.h" + +#include "llfasttimer.h"	// for call count statistics +#include "llxuiparser.h" +#include "llsd.h" +#include "llxmlnode.h" + +#include <map> + +LLTrans::template_map_t LLTrans::sStringTemplates; +LLStringUtil::format_map_t LLTrans::sDefaultArgs; + +struct StringDef : public LLInitParam::Block<StringDef> +{ +	Mandatory<std::string> name; +	Mandatory<std::string> value; + +	StringDef() +	:	name("name"), +		value("value") +	{} +}; + +struct StringTable : public LLInitParam::Block<StringTable> +{ +	Multiple<StringDef> strings; +	StringTable() +	:	strings("string") +	{} +}; + +//static  +bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set<std::string>& default_args) +{ +	std::string xml_filename = "(strings file)"; +	if (!root->hasName("strings")) +	{ +		llerrs << "Invalid root node name in " << xml_filename  +			<< ": was " << root->getName() << ", expected \"strings\"" << llendl; +	} + +	StringTable string_table; +	LLXUIParser parser; +	parser.readXUI(root, string_table, xml_filename); + +	if (!string_table.validateBlock()) +	{ +		llerrs << "Problem reading strings: " << xml_filename << llendl; +		return false; +	} +	 +	sStringTemplates.clear(); +	sDefaultArgs.clear(); +	 +	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); +		it != string_table.strings.end(); +		++it) +	{ +		LLTransTemplate xml_template(it->name, it->value); +		sStringTemplates[xml_template.mName] = xml_template; +		 +		std::set<std::string>::const_iterator iter = default_args.find(xml_template.mName); +		if (iter != default_args.end()) +		{ +			std::string name = *iter; +			if (name[0] != '[') +				name = llformat("[%s]",name.c_str()); +			sDefaultArgs[name] = xml_template.mText; +		} +	} + +	return true; +} + + +//static +bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root) +{ +	std::string xml_filename = "(language strings file)"; +	if (!root->hasName("strings")) +	{ +		llerrs << "Invalid root node name in " << xml_filename  +		<< ": was " << root->getName() << ", expected \"strings\"" << llendl; +	} +	 +	StringTable string_table; +	LLXUIParser parser; +	parser.readXUI(root, string_table, xml_filename); +	 +	if (!string_table.validateBlock()) +	{ +		llerrs << "Problem reading strings: " << xml_filename << llendl; +		return false; +	} +		 +	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); +		it != string_table.strings.end(); +		++it) +	{ +		// share the same map with parseStrings() so we can search the strings using the same getString() function.- angela +		LLTransTemplate xml_template(it->name, it->value); +		sStringTemplates[xml_template.mName] = xml_template; +	} +	 +	return true; +} + + + +static LLFastTimer::DeclareTimer FTM_GET_TRANS("Translate string"); + +//static  +std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) +{ +	// Don't care about time as much as call count.  Make sure we're not +	// calling LLTrans::getString() in an inner loop. JC +	LLFastTimer timer(FTM_GET_TRANS); +	 +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format_map_t args = sDefaultArgs; +		args.insert(msg_args.begin(), msg_args.end()); +		LLStringUtil::format(text, args); +		 +		return text; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; +		return "MissingString("+xml_desc+")"; +	} +} + +//static +std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args) +{ +	// Don't care about time as much as call count.  Make sure we're not +	// calling LLTrans::getString() in an inner loop. JC +	LLFastTimer timer(FTM_GET_TRANS); + +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format(text, msg_args); +		return text; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; +		return "MissingString("+xml_desc+")"; +	} +} + +//static  +bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) +{ +	LLFastTimer timer(FTM_GET_TRANS); +	 +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format_map_t args = sDefaultArgs; +		args.insert(msg_args.begin(), msg_args.end()); +		LLStringUtil::format(text, args); +		result = text; +		return true; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;	 +		return false; +	} +} + +//static +bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args) +{ +	LLFastTimer timer(FTM_GET_TRANS); + +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format(text, msg_args); +		result = text; +		return true; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;	 +		return false; +	} +} + +//static +std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count) +{ +	// Compute which string identifier to use +	const char* form = ""; +	if (language == "ru") // Russian +	{ +		// From GNU ngettext() +		// Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; +		if (count % 10 == 1 +			&& count % 100 != 11) +		{ +			// singular, "1 item" +			form = "A"; +		} +		else if (count % 10 >= 2 +			&& count % 10 <= 4 +			&& (count % 100 < 10 || count % 100 >= 20) ) +		{ +			// special case "2 items", "23 items", but not "13 items" +			form = "B"; +		} +		else +		{ +			// English-style plural, "5 items" +			form = "C"; +		} +	} +	else if (language == "fr" || language == "pt") // French, Brazilian Portuguese +	{ +		// French and Portuguese treat zero as a singular "0 item" not "0 items" +		if (count == 0 || count == 1) +		{ +			form = "A"; +		} +		else +		{ +			// English-style plural +			form = "B"; +		} +	} +	else // default +	{ +		// languages like English with 2 forms, singular and plural +		if (count == 1) +		{ +			// "1 item" +			form = "A"; +		} +		else +		{ +			// "2 items", also use plural for "0 items" +			form = "B"; +		} +	} + +	// Translate that string +	LLStringUtil::format_map_t args; +	args["[COUNT]"] = llformat("%d", count); + +	// Look up "AgeYearsB" or "AgeWeeksC" including the "form" +	std::string key = llformat("%s%s", xml_desc.c_str(), form); +	return getString(key, args); +} + +void LLTrans::setDefaultArg(const std::string& name, const std::string& value) +{ +	sDefaultArgs[name] = value; +} diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h new file mode 100644 index 0000000000..128b51d383 --- /dev/null +++ b/indra/llui/lltrans.h @@ -0,0 +1,133 @@ +/** + * @file lltrans.h + * @brief LLTrans definition + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 LL_TRANS_H +#define LL_TRANS_H + +#include <map> + +#include "llpointer.h" +#include "llstring.h" + +class LLXMLNode; + +class LLSD; + +/** + * @brief String template loaded from strings.xml + */ +class LLTransTemplate +{ +public: +	LLTransTemplate(const std::string& name = LLStringUtil::null, const std::string& text = LLStringUtil::null) : mName(name), mText(text) {} + +	std::string mName; +	std::string mText; +}; + +/** + * @brief Localized strings class + * This class is used to retrieve translations of strings used to build larger ones, as well as + * strings with a general usage that don't belong to any specific floater. For example, + * "Owner:", "Retrieving..." used in the place of a not yet known name, etc. + */ +class LLTrans +{ +public: +	LLTrans(); + +	/** +	 * @brief Parses the xml root that holds the strings. Used once on startup +// *FIXME	 * @param xml_filename Filename to parse +	 * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" +	 * @returns true if the file was parsed successfully, true if something went wrong +	 */ +	static bool parseStrings(LLPointer<LLXMLNode> & root, const std::set<std::string>& default_args); + +	static bool parseLanguageStrings(LLPointer<LLXMLNode> & root); + +	/** +	 * @brief Returns a translated string +	 * @param xml_desc String's description +	 * @param args A list of substrings to replace in the string +	 * @returns Translated string +	 */ +	static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); +	static std::string getString(const std::string &xml_desc, const LLSD& args); +	static bool findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& args); +	static bool findString(std::string &result, const std::string &xml_desc, const LLSD& args); + +	// Returns translated string with [COUNT] replaced with a number, following +	// special per-language logic for plural nouns.  For example, some languages +	// may have different plurals for 0, 1, 2 and > 2. +	// See "AgeWeeksA", "AgeWeeksB", etc. in strings.xml for examples. +	static std::string getCountString(const std::string& language, const std::string& xml_desc, S32 count); + +	/** +	 * @brief Returns a translated string +	 * @param xml_desc String's description +	 * @returns Translated string +	 */ +	static std::string getString(const std::string &xml_desc) +	{ +		LLStringUtil::format_map_t empty; +		return getString(xml_desc, empty); +	} + +	static bool findString(std::string &result, const std::string &xml_desc) +	{ +		LLStringUtil::format_map_t empty; +		return findString(result, xml_desc, empty); +	} + +	static std::string getKeyboardString(const char* keystring) +	{ +		std::string key_str(keystring); +		std::string trans_str; +		return findString(trans_str, key_str) ? trans_str : key_str;  +	} + +	// get the default args +	static const LLStringUtil::format_map_t& getDefaultArgs() +	{ +		return sDefaultArgs; +	} + +	static void setDefaultArg(const std::string& name, const std::string& value); + +	// insert default args into an arg list +	static void getArgs(LLStringUtil::format_map_t& args) +	{ +		args.insert(sDefaultArgs.begin(), sDefaultArgs.end()); +	} +	 +private: +	typedef std::map<std::string, LLTransTemplate > template_map_t; +	static template_map_t sStringTemplates; +	static LLStringUtil::format_map_t sDefaultArgs; +}; + +#endif diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 6b74c5a6be..b5e27616b7 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -972,43 +972,53 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor  // Draw gray and white checkerboard with black border  void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)  { -	// Initialize the first time this is called. -	const S32 PIXELS = 32; -	static GLubyte checkerboard[PIXELS * PIXELS]; -	static BOOL first = TRUE; -	if( first ) -	{ -		for( S32 i = 0; i < PIXELS; i++ ) +	if (!LLGLSLShader::sNoFixedFunction) +	{  +		// Initialize the first time this is called. +		const S32 PIXELS = 32; +		static GLubyte checkerboard[PIXELS * PIXELS]; +		static BOOL first = TRUE; +		if( first )  		{ -			for( S32 j = 0; j < PIXELS; j++ ) +			for( S32 i = 0; i < PIXELS; i++ )  			{ -				checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF; +				for( S32 j = 0; j < PIXELS; j++ ) +				{ +					checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF; +				}  			} +			first = FALSE;  		} -		first = FALSE; -	} -	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -	// ...white squares -	gGL.color4f( 1.f, 1.f, 1.f, alpha ); -	gl_rect_2d(rect); +		// ...white squares +		gGL.color4f( 1.f, 1.f, 1.f, alpha ); +		gl_rect_2d(rect); -	// ...gray squares -	gGL.color4f( .7f, .7f, .7f, alpha ); -	gGL.flush(); +		// ...gray squares +		gGL.color4f( .7f, .7f, .7f, alpha ); +		gGL.flush(); -	if (!LLGLSLShader::sNoFixedFunction) -	{ //polygon stipple is deprecated  		glPolygonStipple( checkerboard );  		LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);  		gl_rect_2d(rect);  	}  	else -	{ -		gl_rect_2d(rect); +	{ //polygon stipple is deprecated, use "Checker" texture +		LLPointer<LLUIImage> img = LLUI::getUIImage("Checker"); +		gGL.getTexUnit(0)->bind(img->getImage()); +		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); +		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + +		LLColor4 color(1.f, 1.f, 1.f, alpha); +		LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f); + +		gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), +			img->getImage(), color, uv_rect);  	} +	  	gGL.flush();  } @@ -1688,21 +1698,22 @@ void LLUI::translate(F32 x, F32 y, F32 z)  	gGL.translateUI(x,y,z);  	LLFontGL::sCurOrigin.mX += (S32) x;  	LLFontGL::sCurOrigin.mY += (S32) y; -	LLFontGL::sCurOrigin.mZ += z; +	LLFontGL::sCurDepth += z;  }  //static  void LLUI::pushMatrix()  {  	gGL.pushUIMatrix(); -	LLFontGL::sOriginStack.push_back(LLFontGL::sCurOrigin); +	LLFontGL::sOriginStack.push_back(std::make_pair(LLFontGL::sCurOrigin, LLFontGL::sCurDepth));  }  //static  void LLUI::popMatrix()  {  	gGL.popUIMatrix(); -	LLFontGL::sCurOrigin = *LLFontGL::sOriginStack.rbegin(); +	LLFontGL::sCurOrigin = LLFontGL::sOriginStack.back().first; +	LLFontGL::sCurDepth = LLFontGL::sOriginStack.back().second;  	LLFontGL::sOriginStack.pop_back();  } @@ -1712,7 +1723,7 @@ void LLUI::loadIdentity()  	gGL.loadUIIdentity();   	LLFontGL::sCurOrigin.mX = 0;  	LLFontGL::sCurOrigin.mY = 0; -	LLFontGL::sCurOrigin.mZ = 0; +	LLFontGL::sCurDepth = 0.f;  }  //static @@ -1735,10 +1746,7 @@ void LLUI::setMousePositionScreen(S32 x, S32 y)  	screen_x = llround((F32)x * sGLScaleFactor.mV[VX]);  	screen_y = llround((F32)y * sGLScaleFactor.mV[VY]); -	LLCoordWindow window_point; -	LLView::getWindow()->convertCoords(LLCoordGL(screen_x, screen_y), &window_point); - -	LLView::getWindow()->setCursorPosition(window_point); +	LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert());  }  //static  @@ -1746,8 +1754,7 @@ void LLUI::getMousePositionScreen(S32 *x, S32 *y)  {  	LLCoordWindow cursor_pos_window;  	getWindow()->getCursorPosition(&cursor_pos_window); -	LLCoordGL cursor_pos_gl; -	getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl); +	LLCoordGL cursor_pos_gl(cursor_pos_window.convert());  	*x = llround((F32)cursor_pos_gl.mX / sGLScaleFactor.mV[VX]);  	*y = llround((F32)cursor_pos_gl.mY / sGLScaleFactor.mV[VX]);  } @@ -2052,7 +2059,7 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)  	// Start at spawn position (using left/top)  	view->setOrigin( local_x, local_y - view->getRect().getHeight());  	// Make sure we're on-screen and not overlapping the mouse -	view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE ); +	view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect );  }  LLView* LLUI::resolvePath(LLView* context, const std::string& path) diff --git a/indra/llui/lluicolor.cpp b/indra/llui/lluicolor.cpp new file mode 100644 index 0000000000..f9bb80f8c5 --- /dev/null +++ b/indra/llui/lluicolor.cpp @@ -0,0 +1,87 @@ +/**  + * @file lluicolor.cpp + * @brief brief LLUIColor class implementation file + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 "lluicolor.h" + +LLUIColor::LLUIColor() +	:mColorPtr(NULL) +{ +} + + +LLUIColor::LLUIColor(const LLColor4& color) +:	mColor(color),  +	mColorPtr(NULL) +{ +} + +LLUIColor::LLUIColor(const LLUIColor* color) +:	mColorPtr(color) +{ +} + +void LLUIColor::set(const LLColor4& color) +{ +	mColor = color; +	mColorPtr = NULL; +} + +void LLUIColor::set(const LLUIColor* color) +{ +	mColorPtr = color; +} + +const LLColor4& LLUIColor::get() const +{ +	return (mColorPtr == NULL ? mColor : mColorPtr->get()); +} + +LLUIColor::operator const LLColor4& () const +{ +	return get(); +} + +const LLColor4& LLUIColor::operator()() const +{ +	return get(); +} + +bool LLUIColor::isReference() const +{ +	return mColorPtr != NULL; +} + +namespace LLInitParam +{ +	// used to detect equivalence with default values on export +	bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) +	{ +		// do not detect value equivalence, treat pointers to colors as distinct from color values +		return (a.mColorPtr == NULL && b.mColorPtr == NULL ? a.mColor == b.mColor : a.mColorPtr == b.mColorPtr); +	} +} diff --git a/indra/llui/lluicolor.h b/indra/llui/lluicolor.h new file mode 100644 index 0000000000..97ebea854a --- /dev/null +++ b/indra/llui/lluicolor.h @@ -0,0 +1,71 @@ +/**  + * @file lluicolor.h + * @brief brief LLUIColor class header file + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 LL_LLUICOLOR_H_ +#define LL_LLUICOLOR_H_ + +#include "v4color.h" + +namespace LLInitParam +{ +	template<typename T, bool> +	struct ParamCompare; +} + +class LLUIColor +{ +public: +	LLUIColor(); +	LLUIColor(const LLColor4& color); +	LLUIColor(const LLUIColor* color); + +	void set(const LLColor4& color); +	void set(const LLUIColor* color); + +	const LLColor4& get() const; + +	operator const LLColor4& () const; +	const LLColor4& operator()() const; + +	bool isReference() const; + +private: +	friend struct LLInitParam::ParamCompare<LLUIColor, false>; + +	const LLUIColor* mColorPtr; +	LLColor4 mColor; +}; + +namespace LLInitParam +{ +	template<> +	struct ParamCompare<LLUIColor, false> +	{ +		static bool equals(const LLUIColor& a, const LLUIColor& b); +	}; +} + +#endif diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index ac69d3bf85..c4e073ccdb 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -128,17 +128,13 @@ void LLUIString::updateResult() const  	}  	mResult = mOrig; -	// get the defailt args + local args -	if (!mArgs || mArgs->empty()) +	// get the default args + local args +	LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs(); +	if (mArgs && !mArgs->empty())  	{ -		LLStringUtil::format(mResult, LLTrans::getDefaultArgs()); -	} -	else -	{ -		LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs();  		combined_args.insert(mArgs->begin(), mArgs->end()); -		LLStringUtil::format(mResult, combined_args);  	} +	LLStringUtil::format(mResult, combined_args);  }  void LLUIString::updateWResult() const diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index e1ee0a5b14..54843227b7 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1106,7 +1106,7 @@ void LLView::drawChildren()  				{  					LLUI::pushMatrix();  					{ -						LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); +						LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom);  						// flag the fact we are in draw here, in case overridden draw() method attempts to remove this widget  						viewp->mInDraw = true;  						viewp->draw(); @@ -1159,7 +1159,7 @@ void LLView::drawDebugRect()  		if (getUseBoundingRect())  		{ -			LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f); +			LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom);  		}  		LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect; @@ -1231,7 +1231,7 @@ void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_dr  			gGL.matrixMode(LLRender::MM_MODELVIEW);  			LLUI::pushMatrix();  			{ -				LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset, 0.f); +				LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset);  				childp->draw();  			}  			LLUI::popMatrix(); @@ -1300,7 +1300,10 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)  			S32 delta_x = child_rect.mLeft - viewp->getRect().mLeft;  			S32 delta_y = child_rect.mBottom - viewp->getRect().mBottom;  			viewp->translate( delta_x, delta_y ); -			viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); +			if (child_rect.getWidth() != viewp->getRect().getWidth() || child_rect.getHeight() != viewp->getRect().getHeight()) +			{ +				viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); +			}  		}  	} @@ -1616,59 +1619,30 @@ LLView* LLView::findNextSibling(LLView* child)  } -LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, BOOL allow_partial_outside) +LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, S32 min_overlap_pixels)  {  	LLCoordGL delta; -	if (allow_partial_outside) -	{ -		const S32 KEEP_ONSCREEN_PIXELS = 16; +	const S32 KEEP_ONSCREEN_PIXELS_WIDTH = llmin(min_overlap_pixels, input.getWidth()); +	const S32 KEEP_ONSCREEN_PIXELS_HEIGHT = llmin(min_overlap_pixels, input.getHeight()); -		if( input.mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft ) -		{ -			delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS); -		} -		else -		if( input.mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight ) -		{ -			delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS); -		} +	if( input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft ) +	{ +		delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH); +	} +	else if( input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight ) +	{ +		delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH); +	} -		if( input.mTop > constraint.mTop ) -		{ -			delta.mY = constraint.mTop - input.mTop; -		} -		else -		if( input.mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom ) -		{ -			delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS); -		} +	if( input.mTop > constraint.mTop ) +	{ +		delta.mY = constraint.mTop - input.mTop;  	}  	else +	if( input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom )  	{ -		if( input.mLeft < constraint.mLeft ) -		{ -			delta.mX = constraint.mLeft - input.mLeft; -		} -		else -		if( input.mRight > constraint.mRight ) -		{ -			delta.mX = constraint.mRight - input.mRight; -			// compensate for left edge possible going off screen -			delta.mX += llmax( 0, input.getWidth() - constraint.getWidth() ); -		} - -		if( input.mTop > constraint.mTop ) -		{ -			delta.mY = constraint.mTop - input.mTop; -		} -		else -		if( input.mBottom < constraint.mBottom ) -		{ -			delta.mY = constraint.mBottom - input.mBottom; -			// compensate for top edge possible going off screen -			delta.mY -= llmax( 0, input.getHeight() - constraint.getHeight() ); -		} +		delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT);  	}  	return delta; @@ -1677,9 +1651,9 @@ LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, BO  // Moves the view so that it is entirely inside of constraint.  // If the view will not fit because it's too big, aligns with the top and left.  // (Why top and left?  That's where the drag bars are for floaters.) -BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside ) +BOOL LLView::translateIntoRect(const LLRect& constraint, S32 min_overlap_pixels)  { -	LLCoordGL translation = getNeededTranslation(getRect(), constraint, allow_partial_outside); +	LLCoordGL translation = getNeededTranslation(getRect(), constraint, min_overlap_pixels);  	if (translation.mX != 0 || translation.mY != 0)  	{ @@ -1691,9 +1665,9 @@ BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outs  // move this view into "inside" but not onto "exclude"  // NOTE: if this view is already contained in "inside", we ignore the "exclude" rect -BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside ) +BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels)  { -	LLCoordGL translation = getNeededTranslation(getRect(), inside, allow_partial_outside); +	LLCoordGL translation = getNeededTranslation(getRect(), inside, min_overlap_pixels);  	if (translation.mX != 0 || translation.mY != 0)  	{ @@ -1861,7 +1835,10 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()  void	LLView::setShape(const LLRect& new_rect, bool by_user)  { -	handleReshape(new_rect, by_user); +	if (new_rect != getRect()) +	{ +		handleReshape(new_rect, by_user); +	}  }  void LLView::handleReshape(const LLRect& new_rect, bool by_user) @@ -2251,145 +2228,163 @@ static bool get_last_child_rect(LLView* parent, LLRect *rect)  }  //static -void LLView::applyXUILayout(LLView::Params& p, LLView* parent) +void LLView::applyXUILayout(LLView::Params& p, LLView* parent, LLRect layout_rect)  { +	if (!parent) return; +  	const S32 VPAD = 4;  	const S32 MIN_WIDGET_HEIGHT = 10;  	// *NOTE:  This will confuse export of floater/panel coordinates unless  	// the default is also "topleft".  JC -	if (p.layout().empty() && parent) +	if (p.layout().empty())  	{  		p.layout = parent->getLayout();  	} -	if (parent) +	if (layout_rect.isEmpty())  	{ -		LLRect parent_rect = parent->getLocalRect(); -		// overwrite uninitialized rect params, using context -		LLRect default_rect = parent->getLocalRect(); +		layout_rect = parent->getLocalRect(); +	} -		bool layout_topleft = (p.layout() == "topleft"); +	// overwrite uninitialized rect params, using context +	LLRect default_rect = parent->getLocalRect(); -		// convert negative or centered coordinates to parent relative values -		// Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock() -		if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth(); -		if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth(); -		if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight(); -		if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight(); +	bool layout_topleft = (p.layout() == "topleft"); +	// convert negative or centered coordinates to parent relative values +	// Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock() +	if (p.rect.left.isProvided())  +	{ +		p.rect.left = p.rect.left + ((p.rect.left >= 0) ? layout_rect.mLeft : layout_rect.mRight); +	} +	if (p.rect.right.isProvided()) +	{ +		p.rect.right = p.rect.right + ((p.rect.right >= 0) ? layout_rect.mLeft : layout_rect.mRight); +	} +	if (p.rect.bottom.isProvided())  +	{ +		p.rect.bottom = p.rect.bottom + ((p.rect.bottom >= 0) ? layout_rect.mBottom : layout_rect.mTop);  		if (layout_topleft)  		{  			//invert top to bottom -			if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top; -			if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom; +			p.rect.bottom = layout_rect.mBottom + layout_rect.mTop - p.rect.bottom;  		} - -		// DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels -		if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) +	} +	if (p.rect.top.isProvided()) +	{ +		p.rect.top = p.rect.top + ((p.rect.top >= 0) ? layout_rect.mBottom : layout_rect.mTop); +		if (layout_topleft)  		{ -			p.rect.height = MIN_WIDGET_HEIGHT; +			//invert top to bottom +			p.rect.top = layout_rect.mBottom + layout_rect.mTop - p.rect.top;  		} +	} + +	// DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels +	if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) +	{ +		p.rect.height = MIN_WIDGET_HEIGHT; +	} -		default_rect.translate(0, default_rect.getHeight()); +	default_rect.translate(0, default_rect.getHeight()); -		// If there was a recently constructed child, use its rectangle -		get_last_child_rect(parent, &default_rect); +	// If there was a recently constructed child, use its rectangle +	get_last_child_rect(parent, &default_rect); -		if (layout_topleft) +	if (layout_topleft) +	{ +		// Invert the sense of bottom_delta for topleft layout +		if (p.bottom_delta.isProvided())  		{ -			// Invert the sense of bottom_delta for topleft layout -			if (p.bottom_delta.isProvided()) -			{ -				p.bottom_delta = -p.bottom_delta; -			} -			else if (p.top_pad.isProvided())  -			{ -				p.bottom_delta = -(p.rect.height + p.top_pad); -			} -			else if (p.top_delta.isProvided()) -			{ -				p.bottom_delta = -					-(p.top_delta + p.rect.height - default_rect.getHeight()); -			} -			else if (!p.left_delta.isProvided() -					 && !p.left_pad.isProvided()) -			{ -				// set default position is just below last rect -				p.bottom_delta.set(-(p.rect.height + VPAD), false); -			} -			else -			{ -				p.bottom_delta.set(0, false); -			} -	 -			// default to same left edge -			if (!p.left_delta.isProvided()) -			{ -				p.left_delta.set(0, false); -			} -			if (p.left_pad.isProvided()) -			{ -				// left_pad is based on prior widget's right edge -				p.left_delta.set(p.left_pad + default_rect.getWidth(), false); -			} -			 -			default_rect.translate(p.left_delta, p.bottom_delta);				 +			p.bottom_delta = -p.bottom_delta;  		} -		else -		{	 -			// set default position is just below last rect -			if (!p.bottom_delta.isProvided()) -			{ -				p.bottom_delta.set(-(p.rect.height + VPAD), false); -			} -			if (!p.left_delta.isProvided()) -			{ -				p.left_delta.set(0, false); -			} -			default_rect.translate(p.left_delta, p.bottom_delta); +		else if (p.top_pad.isProvided())  +		{ +			p.bottom_delta = -(p.rect.height + p.top_pad);  		} - -		// this handles case where *both* x and x_delta are provided -		// ignore x in favor of default x + x_delta -		if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); -		if (p.left_delta.isProvided()) p.rect.left.set(0, false); - -		// selectively apply rectangle defaults, making sure that -		// params are not flagged as having been "provided" -		// as rect params are overconstrained and rely on provided flags -		if (!p.rect.left.isProvided()) +		else if (p.top_delta.isProvided())  		{ -			p.rect.left.set(default_rect.mLeft, false); -			//HACK: get around the fact that setting a rect param component value won't invalidate the existing rect object value -			p.rect.paramChanged(p.rect.left, true); +			p.bottom_delta = +				-(p.top_delta + p.rect.height - default_rect.getHeight());  		} -		if (!p.rect.bottom.isProvided()) +		else if (!p.left_delta.isProvided() +					&& !p.left_pad.isProvided())  		{ -			p.rect.bottom.set(default_rect.mBottom, false); -			p.rect.paramChanged(p.rect.bottom, true); +			// set default position is just below last rect +			p.bottom_delta.set(-(p.rect.height + VPAD), false);  		} -		if (!p.rect.top.isProvided()) +		else  		{ -			p.rect.top.set(default_rect.mTop, false); -			p.rect.paramChanged(p.rect.top, true); +			p.bottom_delta.set(0, false);  		} -		if (!p.rect.right.isProvided()) +	 +		// default to same left edge +		if (!p.left_delta.isProvided())  		{ -			p.rect.right.set(default_rect.mRight, false); -			p.rect.paramChanged(p.rect.right, true); - +			p.left_delta.set(0, false);  		} -		if (!p.rect.width.isProvided()) +		if (p.left_pad.isProvided())  		{ -			p.rect.width.set(default_rect.getWidth(), false); -			p.rect.paramChanged(p.rect.width, true); +			// left_pad is based on prior widget's right edge +			p.left_delta.set(p.left_pad + default_rect.getWidth(), false);  		} -		if (!p.rect.height.isProvided()) +			 +		default_rect.translate(p.left_delta, p.bottom_delta);				 +	} +	else +	{	 +		// set default position is just below last rect +		if (!p.bottom_delta.isProvided()) +		{ +			p.bottom_delta.set(-(p.rect.height + VPAD), false); +		} +		if (!p.left_delta.isProvided())  		{ -			p.rect.height.set(default_rect.getHeight(), false); -			p.rect.paramChanged(p.rect.height, true); +			p.left_delta.set(0, false);  		} +		default_rect.translate(p.left_delta, p.bottom_delta); +	} + +	// this handles case where *both* x and x_delta are provided +	// ignore x in favor of default x + x_delta +	if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); +	if (p.left_delta.isProvided()) p.rect.left.set(0, false); + +	// selectively apply rectangle defaults, making sure that +	// params are not flagged as having been "provided" +	// as rect params are overconstrained and rely on provided flags +	if (!p.rect.left.isProvided()) +	{ +		p.rect.left.set(default_rect.mLeft, false); +		//HACK: get around the fact that setting a rect param component value won't invalidate the existing rect object value +		p.rect.paramChanged(p.rect.left, true); +	} +	if (!p.rect.bottom.isProvided()) +	{ +		p.rect.bottom.set(default_rect.mBottom, false); +		p.rect.paramChanged(p.rect.bottom, true); +	} +	if (!p.rect.top.isProvided()) +	{ +		p.rect.top.set(default_rect.mTop, false); +		p.rect.paramChanged(p.rect.top, true); +	} +	if (!p.rect.right.isProvided()) +	{ +		p.rect.right.set(default_rect.mRight, false); +		p.rect.paramChanged(p.rect.right, true); + +	} +	if (!p.rect.width.isProvided()) +	{ +		p.rect.width.set(default_rect.getWidth(), false); +		p.rect.paramChanged(p.rect.width, true); +	} +	if (!p.rect.height.isProvided()) +	{ +		p.rect.height.set(default_rect.getHeight(), false); +		p.rect.paramChanged(p.rect.height, true);  	}  } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index f1fac5f69c..1c35349510 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -370,8 +370,8 @@ public:  	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);  	virtual void	translate( S32 x, S32 y );  	void			setOrigin( S32 x, S32 y )	{ mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); } -	BOOL			translateIntoRect( const LLRect& constraint, BOOL allow_partial_outside ); -	BOOL			translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside ); +	BOOL			translateIntoRect( const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); +	BOOL			translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels = S32_MAX);  	void			centerWithin(const LLRect& bounds);  	void	setShape(const LLRect& new_rect, bool by_user = false); @@ -505,7 +505,7 @@ public:  	// Set up params after XML load before calling new(),  	// usually to adjust layout. -	static void applyXUILayout(Params& p, LLView* parent); +	static void applyXUILayout(Params& p, LLView* parent, LLRect layout_rect = LLRect());  	// For re-export of floaters and panels, convert the coordinate system  	// to be top-left based. diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp new file mode 100644 index 0000000000..afc76024d1 --- /dev/null +++ b/indra/llui/llxuiparser.cpp @@ -0,0 +1,1756 @@ +/**  + * @file llxuiparser.cpp + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 "llxuiparser.h" + +#include "llxmlnode.h" + +#ifdef LL_STANDALONE +#include <expat.h> +#else +#include "expat/expat.h" +#endif + +#include <fstream> +#include <boost/tokenizer.hpp> +//#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/classic_core.hpp> + +#include "lluicolor.h" + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +const S32 MAX_STRING_ATTRIBUTE_SIZE = 40; + +static 	LLInitParam::Parser::parser_read_func_map_t sXSDReadFuncs; +static 	LLInitParam::Parser::parser_write_func_map_t sXSDWriteFuncs; +static 	LLInitParam::Parser::parser_inspect_func_map_t sXSDInspectFuncs; + +static 	LLInitParam::Parser::parser_read_func_map_t sSimpleXUIReadFuncs; +static 	LLInitParam::Parser::parser_write_func_map_t sSimpleXUIWriteFuncs; +static 	LLInitParam::Parser::parser_inspect_func_map_t sSimpleXUIInspectFuncs; + +const char* NO_VALUE_MARKER = "no_value"; + +const S32 LINE_NUMBER_HERE = 0; + +struct MaxOccursValues : public LLInitParam::TypeValuesHelper<U32, MaxOccursValues> +{ +	static void declareValues() +	{ +		declare("unbounded", U32_MAX); +	} +}; + +struct Occurs : public LLInitParam::Block<Occurs> +{ +	Optional<U32>					minOccurs; +	Optional<U32, MaxOccursValues>	maxOccurs; + +	Occurs() +	:	minOccurs("minOccurs", 0), +		maxOccurs("maxOccurs", U32_MAX) + +	{} +}; + + +typedef enum +{ +	USE_REQUIRED, +	USE_OPTIONAL +} EUse; + +namespace LLInitParam +{ +	template<> +	struct TypeValues<EUse> : public TypeValuesHelper<EUse> +	{ +		static void declareValues() +		{ +			declare("required", USE_REQUIRED); +			declare("optional", USE_OPTIONAL); +		} +	}; +} + +struct Element; +struct Group; +struct Choice; +struct Sequence; +struct Any; + +struct Attribute : public LLInitParam::Block<Attribute> +{ +	Mandatory<std::string>	name; +	Mandatory<std::string>	type; +	Mandatory<EUse>			use; +	 +	Attribute() +	:	name("name"), +		type("type"), +		use("use") +	{} +}; + +struct Any : public LLInitParam::Block<Any, Occurs> +{ +	Optional<std::string> _namespace; + +	Any() +	:	_namespace("namespace") +	{} +}; + +struct All : public LLInitParam::Block<All, Occurs> +{ +	Multiple< Lazy<Element> > elements; + +	All() +	:	elements("element") +	{ +		maxOccurs = 1; +	} +}; + +struct Choice : public LLInitParam::ChoiceBlock<Choice, Occurs> +{ +	Alternative< Lazy<Element> >	element; +	Alternative< Lazy<Group> >		group; +	Alternative< Lazy<Choice> >		choice; +	Alternative< Lazy<Sequence> >	sequence; +	Alternative< Lazy<Any> >		any; + +	Choice() +	:	element("element"), +		group("group"), +		choice("choice"), +		sequence("sequence"), +		any("any") +	{} + +}; + +struct Sequence : public LLInitParam::ChoiceBlock<Sequence, Occurs> +{ +	Alternative< Lazy<Element> >	element; +	Alternative< Lazy<Group> >		group; +	Alternative< Lazy<Choice> >		choice; +	Alternative< Lazy<Sequence> >	sequence; +	Alternative< Lazy<Any> >		any; +}; + +struct GroupContents : public LLInitParam::ChoiceBlock<GroupContents, Occurs> +{ +	Alternative<All>		all; +	Alternative<Choice>		choice; +	Alternative<Sequence>	sequence; + +	GroupContents() +	:	all("all"), +		choice("choice"), +		sequence("sequence") +	{} +}; + +struct Group : public LLInitParam::Block<Group, GroupContents> +{ +	Optional<std::string>	name, +							ref; + +	Group() +	:	name("name"), +		ref("ref") +	{} +}; + +struct Restriction : public LLInitParam::Block<Restriction> +{ +}; + +struct Extension : public LLInitParam::Block<Extension> +{ +}; + +struct SimpleContent : public LLInitParam::ChoiceBlock<SimpleContent> +{ +	Alternative<Restriction> restriction; +	Alternative<Extension> extension; + +	SimpleContent() +	:	restriction("restriction"), +		extension("extension") +	{} +}; + +struct SimpleType : public LLInitParam::Block<SimpleType> +{ +	// TODO +}; + +struct ComplexContent : public LLInitParam::Block<ComplexContent, SimpleContent> +{ +	Optional<bool> mixed; + +	ComplexContent() +	:	mixed("mixed", true) +	{} +}; + +struct ComplexTypeContents : public LLInitParam::ChoiceBlock<ComplexTypeContents> +{ +	Alternative<SimpleContent>	simple_content; +	Alternative<ComplexContent> complex_content; +	Alternative<Group>			group; +	Alternative<All>			all; +	Alternative<Choice>			choice; +	Alternative<Sequence>		sequence; + +	ComplexTypeContents() +	:	simple_content("simpleContent"), +		complex_content("complexContent"), +		group("group"), +		all("all"), +		choice("choice"), +		sequence("sequence") +	{} +}; + +struct ComplexType : public LLInitParam::Block<ComplexType, ComplexTypeContents> +{ +	Optional<std::string>			name; +	Optional<bool>					mixed; + +	Multiple<Attribute>				attribute; +	Multiple< Lazy<Element> >			elements; + +	ComplexType() +	:	name("name"), +		attribute("xs:attribute"), +		elements("xs:element"), +		mixed("mixed") +	{ +	} +}; + +struct ElementContents : public LLInitParam::ChoiceBlock<ElementContents, Occurs> +{ +	Alternative<SimpleType>		simpleType; +	Alternative<ComplexType>	complexType; + +	ElementContents() +	:	simpleType("simpleType"), +		complexType("complexType") +	{} +}; + +struct Element : public LLInitParam::Block<Element, ElementContents> +{ +	Optional<std::string>	name, +							ref, +							type; + +	Element() +	:	name("xs:name"), +		ref("xs:ref"), +		type("xs:type") +	{} +}; + +struct Schema : public LLInitParam::Block<Schema> +{ +private: +	Mandatory<std::string>	targetNamespace, +							xmlns, +							xs; + +public: +	Optional<std::string>	attributeFormDefault, +							elementFormDefault; + +	Mandatory<Element>		root_element; +	 +	void setNameSpace(const std::string& ns) {targetNamespace = ns; xmlns = ns;} + +	Schema(const std::string& ns = LLStringUtil::null) +	:	attributeFormDefault("attributeFormDefault"), +		elementFormDefault("elementFormDefault"), +		xs("xmlns:xs"), +		targetNamespace("targetNamespace"), +		xmlns("xmlns"), +		root_element("xs:element") +	{ +		attributeFormDefault = "unqualified"; +		elementFormDefault = "qualified"; +		xs = "http://www.w3.org/2001/XMLSchema"; +		if (!ns.empty()) +		{ +			setNameSpace(ns); +		}; +	} + +}; + +// +// LLXSDWriter +// +LLXSDWriter::LLXSDWriter() +: Parser(sXSDReadFuncs, sXSDWriteFuncs, sXSDInspectFuncs) +{ +	registerInspectFunc<bool>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4)); +	registerInspectFunc<std::string>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<U8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4)); +	registerInspectFunc<S8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4)); +	registerInspectFunc<U16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4)); +	registerInspectFunc<S16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4)); +	registerInspectFunc<U32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4)); +	registerInspectFunc<S32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4)); +	registerInspectFunc<F32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4)); +	registerInspectFunc<F64>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4)); +	registerInspectFunc<LLColor4>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<LLUIColor>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<LLUUID>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<LLSD>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +} + +void LLXSDWriter::writeXSD(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace) +{ +	Schema schema(xml_namespace); + +	schema.root_element.name = type_name; +	Choice& choice = schema.root_element.complexType.choice; + +	choice.minOccurs = 0; +	choice.maxOccurs = "unbounded"; + +	mSchemaNode = node; +	//node->setName("xs:schema"); +	//node->createChild("attributeFormDefault", true)->setStringValue("unqualified"); +	//node->createChild("elementFormDefault", true)->setStringValue("qualified"); +	//node->createChild("targetNamespace", true)->setStringValue(xml_namespace); +	//node->createChild("xmlns:xs", true)->setStringValue("http://www.w3.org/2001/XMLSchema"); +	//node->createChild("xmlns", true)->setStringValue(xml_namespace); + +	//node = node->createChild("xs:complexType", false); +	//node->createChild("name", true)->setStringValue(type_name); +	//node->createChild("mixed", true)->setStringValue("true"); + +	//mAttributeNode = node; +	//mElementNode = node->createChild("xs:choice", false); +	//mElementNode->createChild("minOccurs", true)->setStringValue("0"); +	//mElementNode->createChild("maxOccurs", true)->setStringValue("unbounded"); +	block.inspectBlock(*this); + +	// duplicate element choices +	LLXMLNodeList children; +	mElementNode->getChildren("xs:element", children, FALSE); +	for (LLXMLNodeList::iterator child_it = children.begin(); child_it != children.end(); ++child_it) +	{ +		LLXMLNodePtr child_copy = child_it->second->deepCopy(); +		std::string child_name; +		child_copy->getAttributeString("name", child_name); +		child_copy->setAttributeString("name", type_name + "." + child_name); +		mElementNode->addChild(child_copy); +	} + +	LLXMLNodePtr element_declaration_node = mSchemaNode->createChild("xs:element", false); +	element_declaration_node->createChild("name", true)->setStringValue(type_name); +	element_declaration_node->createChild("type", true)->setStringValue(type_name); +} + +void LLXSDWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values) +{ +	name_stack_t non_empty_names; +	std::string attribute_name; +	for (name_stack_t::const_iterator it = stack.begin(); +		it != stack.end(); +		++it) +	{ +		const std::string& name = it->first; +		if (!name.empty()) +		{ +			non_empty_names.push_back(*it); +		} +	} + +	for (name_stack_t::const_iterator it = non_empty_names.begin(); +		it != non_empty_names.end(); +		++it) +	{ +		if (!attribute_name.empty()) +		{ +			attribute_name += "."; +		} +		attribute_name += it->first; +	} + +	// only flag non-nested attributes as mandatory, nested attributes have variant syntax +	// that can't be properly constrained in XSD +	// e.g. <foo mandatory.value="bar"/> vs <foo><mandatory value="bar"/></foo> +	bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1; + +	// don't bother supporting "Multiple" params as xml attributes +	if (max_count <= 1) +	{ +		// add compound attribute to root node +		addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values); +	} + +	// now generated nested elements for compound attributes +	if (non_empty_names.size() > 1 && !attribute_mandatory) +	{ +		std::string element_name; + +		// traverse all but last element, leaving that as an attribute name +		name_stack_t::const_iterator end_it = non_empty_names.end(); +		end_it--; + +		for (name_stack_t::const_iterator it = non_empty_names.begin(); +			it != end_it; +			++it) +		{ +			if (it != non_empty_names.begin()) +			{ +				element_name += "."; +			} +			element_name += it->first; +		} + +		std::string short_attribute_name = non_empty_names.back().first; + +		LLXMLNodePtr complex_type_node; + +		// find existing element node here, starting at tail of child list +		if (mElementNode->mChildren.notNull()) +		{ +			for(LLXMLNodePtr element = mElementNode->mChildren->tail; +				element.notNull();  +				element = element->mPrev) +			{ +				std::string name; +				if(element->getAttributeString("name", name) && name == element_name) +				{ +					complex_type_node = element->mChildren->head; +					break; +				} +			} +		} +		//create complex_type node +		// +		//<xs:element +        //    maxOccurs="1" +        //    minOccurs="0" +        //    name="name"> +        //       <xs:complexType> +        //       </xs:complexType> +        //</xs:element> +		if(complex_type_node.isNull()) +		{ +			complex_type_node = mElementNode->createChild("xs:element", false); + +			complex_type_node->createChild("minOccurs", true)->setIntValue(min_count); +			complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count); +			complex_type_node->createChild("name",		true)->setStringValue(element_name); +			complex_type_node = complex_type_node->createChild("xs:complexType", false); +		} + +		addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values); +	} +} + +void LLXSDWriter::addAttributeToSchema(LLXMLNodePtr type_declaration_node, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values) +{ +	if (!attribute_name.empty()) +	{ +		LLXMLNodePtr new_enum_type_node; +		if (possible_values != NULL) +		{ +			// custom attribute type, for example +			//<xs:simpleType> +			 // <xs:restriction +			 //    base="xs:string"> +			 //     <xs:enumeration +			 //      value="a" /> +			 //     <xs:enumeration +			 //      value="b" /> +			 //   </xs:restriction> +			 // </xs:simpleType> +			new_enum_type_node = new LLXMLNode("xs:simpleType", false); + +			LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false); +			restriction_node->createChild("base", true)->setStringValue("xs:string"); + +			for (std::vector<std::string>::const_iterator it = possible_values->begin(); +				it != possible_values->end(); +				++it) +			{ +				LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false); +				enum_node->createChild("value", true)->setStringValue(*it); +			} +		} + +		string_set_t& attributes_written = mAttributesWritten[type_declaration_node]; + +		string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name); + +		// attribute not yet declared +		if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it)) +		{ +			attributes_written.insert(found_it, attribute_name); + +			LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false); + +			// attribute name +			attribute_node->createChild("name", true)->setStringValue(attribute_name); + +			if (new_enum_type_node.notNull()) +			{ +				attribute_node->addChild(new_enum_type_node); +			} +			else +			{ +				// simple attribute type +				attribute_node->createChild("type", true)->setStringValue(type); +			} + +			// required or optional +			attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional"); +		} +		 // attribute exists...handle collision of same name attributes with potentially different types +		else +		{ +			LLXMLNodePtr attribute_declaration; +			if (type_declaration_node.notNull()) +			{ +				for(LLXMLNodePtr node = type_declaration_node->mChildren->tail;  +					node.notNull();  +					node = node->mPrev) +				{ +					std::string name; +					if (node->getAttributeString("name", name) && name == attribute_name) +					{ +						attribute_declaration = node; +						break; +					} +				} +			} + +			bool new_type_is_enum = new_enum_type_node.notNull(); +			bool existing_type_is_enum = !attribute_declaration->hasAttribute("type"); + +			// either type is enum, revert to string in collision +			// don't bother to check for enum equivalence +			if (new_type_is_enum || existing_type_is_enum) +			{ +				if (attribute_declaration->hasAttribute("type")) +				{ +					attribute_declaration->setAttributeString("type", "xs:string"); +				} +				else +				{ +					attribute_declaration->createChild("type", true)->setStringValue("xs:string"); +				} +				attribute_declaration->deleteChildren("xs:simpleType"); +			} +			else  +			{ +				// check for collision of different standard types +				std::string existing_type; +				attribute_declaration->getAttributeString("type", existing_type); +				// if current type is not the same as the new type, revert to strnig +				if (existing_type != type) +				{ +					// ...than use most general type, string +					attribute_declaration->setAttributeString("type", "string"); +				} +			} +		} +	} +} + +// +// LLXUIXSDWriter +// +void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& path, const LLInitParam::BaseBlock& block) +{ +	std::string file_name(path); +	file_name += type_name + ".xsd"; +	LLXMLNodePtr root_nodep = new LLXMLNode(); + +	LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui"); + +	// add includes for all possible children +	const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); +	const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); + +	// add choices for valid children +	if (widget_registryp) +	{ +		// add include declarations for all valid children +		for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); +		     it != widget_registryp->currentRegistrar().endItems(); +		     ++it) +		{ +			std::string widget_name = it->first; +			if (widget_name == type_name) +			{ +				continue; +			} +			LLXMLNodePtr nodep = new LLXMLNode("xs:include", false); +			nodep->createChild("schemaLocation", true)->setStringValue(widget_name + ".xsd"); +			 +			// add to front of schema +			mSchemaNode->addChild(nodep, mSchemaNode); +		} + +		for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); +			it != widget_registryp->currentRegistrar().endItems(); +			++it) +		{ +			std::string widget_name = it->first; +			//<xs:element name="widget_name" type="widget_name"> +			LLXMLNodePtr widget_node = mElementNode->createChild("xs:element", false); +			widget_node->createChild("name", true)->setStringValue(widget_name); +			widget_node->createChild("type", true)->setStringValue(widget_name); +		} +	} + +	LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w"); +	LLXMLNode::writeHeaderToFile(xsd_file); +	root_nodep->writeToFile(xsd_file); +	fclose(xsd_file); +} + +static 	LLInitParam::Parser::parser_read_func_map_t sXUIReadFuncs; +static 	LLInitParam::Parser::parser_write_func_map_t sXUIWriteFuncs; +static 	LLInitParam::Parser::parser_inspect_func_map_t sXUIInspectFuncs; + +// +// LLXUIParser +// +LLXUIParser::LLXUIParser() +:	Parser(sXUIReadFuncs, sXUIWriteFuncs, sXUIInspectFuncs), +	mCurReadDepth(0) +{ +	if (sXUIReadFuncs.empty()) +	{ +		registerParserFuncs<LLInitParam::Flag>(readFlag, writeFlag); +		registerParserFuncs<bool>(readBoolValue, writeBoolValue); +		registerParserFuncs<std::string>(readStringValue, writeStringValue); +		registerParserFuncs<U8>(readU8Value, writeU8Value); +		registerParserFuncs<S8>(readS8Value, writeS8Value); +		registerParserFuncs<U16>(readU16Value, writeU16Value); +		registerParserFuncs<S16>(readS16Value, writeS16Value); +		registerParserFuncs<U32>(readU32Value, writeU32Value); +		registerParserFuncs<S32>(readS32Value, writeS32Value); +		registerParserFuncs<F32>(readF32Value, writeF32Value); +		registerParserFuncs<F64>(readF64Value, writeF64Value); +		registerParserFuncs<LLColor4>(readColor4Value, writeColor4Value); +		registerParserFuncs<LLUIColor>(readUIColorValue, writeUIColorValue); +		registerParserFuncs<LLUUID>(readUUIDValue, writeUUIDValue); +		registerParserFuncs<LLSD>(readSDValue, writeSDValue); +	} +} + +static LLFastTimer::DeclareTimer FTM_PARSE_XUI("XUI Parsing"); +const LLXMLNodePtr DUMMY_NODE = new LLXMLNode(); + +void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent) +{ +	LLFastTimer timer(FTM_PARSE_XUI); +	mNameStack.clear(); +	mRootNodeName = node->getName()->mString; +	mCurFileName = filename; +	mCurReadDepth = 0; +	setParseSilently(silent); + +	if (node.isNull()) +	{ +		parserWarning("Invalid node"); +	} +	else +	{ +		readXUIImpl(node, block); +	} +} + +bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> sep("."); + +	bool values_parsed = false; +	bool silent = mCurReadDepth > 0; + +	if (nodep->getFirstChild().isNull()  +		&& nodep->mAttributes.empty()  +		&& nodep->getSanitizedValue().empty()) +	{ +		// empty node, just parse as flag +		mCurReadNode = DUMMY_NODE; +		return block.submitValue(mNameStack, *this, silent); +	} + +	// submit attributes for current node +	values_parsed |= readAttributes(nodep, block); + +	// treat text contents of xml node as "value" parameter +	std::string text_contents = nodep->getSanitizedValue(); +	if (!text_contents.empty()) +	{ +		mCurReadNode = nodep; +		mNameStack.push_back(std::make_pair(std::string("value"), true)); +		// child nodes are not necessarily valid parameters (could be a child widget) +		// so don't complain once we've recursed +		if (!block.submitValue(mNameStack, *this, true)) +		{ +			mNameStack.pop_back(); +			block.submitValue(mNameStack, *this, silent); +		} +		else +		{ +			mNameStack.pop_back(); +		} +	} + +	// then traverse children +	// child node must start with last name of parent node (our "scope") +	// for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>" +	// which equates to the following nesting: +	// button +	//     param +	//         nested_param1 +	//         nested_param2 +	//             nested_param3	 +	mCurReadDepth++; +	for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) +	{ +		std::string child_name(childp->getName()->mString); +		S32 num_tokens_pushed = 0; + +		// for non "dotted" child nodes	check to see if child node maps to another widget type +		// and if not, treat as a child element of the current node +		// e.g. <button><rect left="10"/></button> will interpret <rect> as "button.rect" +		// since there is no widget named "rect" +		if (child_name.find(".") == std::string::npos)  +		{ +			mNameStack.push_back(std::make_pair(child_name, true)); +			num_tokens_pushed++; +		} +		else +		{ +			// parse out "dotted" name into individual tokens +			tokenizer name_tokens(child_name, sep); + +			tokenizer::iterator name_token_it = name_tokens.begin(); +			if(name_token_it == name_tokens.end())  +			{ +				childp = childp->getNextSibling(); +				continue; +			} + +			// check for proper nesting +			if (mNameStack.empty()) +			{ +				if (*name_token_it != mRootNodeName) +				{ +					childp = childp->getNextSibling(); +					continue; +				} +			} +			else if(mNameStack.back().first != *name_token_it) +			{ +				childp = childp->getNextSibling(); +				continue; +			} + +			// now ignore first token +			++name_token_it;  + +			// copy remaining tokens on to our running token list +			for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) +			{ +				mNameStack.push_back(std::make_pair(*token_to_push, true)); +				num_tokens_pushed++; +			} +		} + +		// recurse and visit children XML nodes +		if(readXUIImpl(childp, block)) +		{ +			// child node successfully parsed, remove from DOM + +			values_parsed = true; +			LLXMLNodePtr node_to_remove = childp; +			childp = childp->getNextSibling(); + +			nodep->deleteChild(node_to_remove); +		} +		else +		{ +			childp = childp->getNextSibling(); +		} + +		while(num_tokens_pushed-- > 0) +		{ +			mNameStack.pop_back(); +		} +	} +	mCurReadDepth--; +	return values_parsed; +} + +bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> sep("."); + +	bool any_parsed = false; +	bool silent = mCurReadDepth > 0; + +	for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin();  +		attribute_it != nodep->mAttributes.end();  +		++attribute_it) +	{ +		S32 num_tokens_pushed = 0; +		std::string attribute_name(attribute_it->first->mString); +		mCurReadNode = attribute_it->second; + +		tokenizer name_tokens(attribute_name, sep); +		// copy remaining tokens on to our running token list +		for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) +		{ +			mNameStack.push_back(std::make_pair(*token_to_push, true)); +			num_tokens_pushed++; +		} + +		// child nodes are not necessarily valid attributes, so don't complain once we've recursed +		any_parsed |= block.submitValue(mNameStack, *this, silent); +		 +		while(num_tokens_pushed-- > 0) +		{ +			mNameStack.pop_back(); +		} +	} + +	return any_parsed; +} + +void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::BaseBlock* diff_block) +{ +	mWriteRootNode = node; +	name_stack_t name_stack = Parser::name_stack_t(); +	block.serializeBlock(*this, name_stack, diff_block); +	mOutNodes.clear(); +} + +// go from a stack of names to a specific XML node +LLXMLNodePtr LLXUIParser::getNode(name_stack_t& stack) +{ +	LLXMLNodePtr out_node = mWriteRootNode; + +	name_stack_t::iterator next_it = stack.begin(); +	for (name_stack_t::iterator it = stack.begin(); +		it != stack.end(); +		it = next_it) +	{ +		++next_it; +		if (it->first.empty()) +		{ +			it->second = false; +			continue; +		} + +		out_nodes_t::iterator found_it = mOutNodes.find(it->first); + +		// node with this name not yet written +		if (found_it == mOutNodes.end() || it->second) +		{ +			// make an attribute if we are the last element on the name stack +			bool is_attribute = next_it == stack.end(); +			LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute); +			out_node->addChild(new_node); +			mOutNodes[it->first] = new_node; +			out_node = new_node; +			it->second = false; +		} +		else +		{ +			out_node = found_it->second; +		} +	} + +	return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node); +} + +bool LLXUIParser::readFlag(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode == DUMMY_NODE; +} + +bool LLXUIParser::writeFlag(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	// just create node +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	return node.notNull(); +} + +bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ +	S32 value; +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	bool success = self.mCurReadNode->getBoolValue(1, &value); +	*((bool*)val_ptr) = (value != FALSE); +	return success; +} + +bool LLXUIParser::writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setBoolValue(*((bool*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	*((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue(); +	return true; +} + +bool LLXUIParser::writeStringValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		const std::string* string_val = reinterpret_cast<const std::string*>(val_ptr); +		if (string_val->find('\n') != std::string::npos  +			|| string_val->size() > MAX_STRING_ATTRIBUTE_SIZE) +		{ +			// don't write strings with newlines into attributes +			std::string attribute_name = node->getName()->mString; +			LLXMLNodePtr parent_node = node->mParent; +			parent_node->deleteChild(node); +			// write results in text contents of node +			if (attribute_name == "value") +			{ +				// "value" is implicit, just write to parent +				node = parent_node; +			} +			else +			{ +				// create a child that is not an attribute, but with same name +				node = parent_node->createChild(attribute_name.c_str(), false); +			} +		} +		node->setStringValue(*string_val); +		return true; +	} +	return false; +} + +bool LLXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getByteValue(1, (U8*)val_ptr); +} + +bool LLXUIParser::writeU8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setUnsignedValue(*((U8*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	S32 value; +	if(self.mCurReadNode->getIntValue(1, &value)) +	{ +		*((S8*)val_ptr) = value; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeS8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setIntValue(*((S8*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	U32 value; +	if(self.mCurReadNode->getUnsignedValue(1, &value)) +	{ +		*((U16*)val_ptr) = value; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeU16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setUnsignedValue(*((U16*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	S32 value; +	if(self.mCurReadNode->getIntValue(1, &value)) +	{ +		*((S16*)val_ptr) = value; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeS16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setIntValue(*((S16*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); +} + +bool LLXUIParser::writeU32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setUnsignedValue(*((U32*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getIntValue(1, (S32*)val_ptr); +} + +bool LLXUIParser::writeS32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setIntValue(*((S32*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr); +} + +bool LLXUIParser::writeF32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setFloatValue(*((F32*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr); +} + +bool LLXUIParser::writeF64Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setDoubleValue(*((F64*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLColor4* colorp = (LLColor4*)val_ptr; +	if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3) +	{ +		return true; +	} + +	return false; +} + +bool LLXUIParser::writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		LLColor4 color = *((LLColor4*)val_ptr); +		node->setFloatValue(4, color.mV); +		return true; +	} +	return false; +} + +bool LLXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLUIColor* param = (LLUIColor*)val_ptr; +	LLColor4 color; +	bool success =  self.mCurReadNode->getFloatValue(4, color.mV) >= 3; +	if (success) +	{ +		param->set(color); +		return true; +	} +	return false; +} + +bool LLXUIParser::writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		LLUIColor color = *((LLUIColor*)val_ptr); +		//RN: don't write out the color that is represented by a function +		// rely on param block exporting to get the reference to the color settings +		if (color.isReference()) return false; +		node->setFloatValue(4, color.get().mV); +		return true; +	} +	return false; +} + +bool LLXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLUUID temp_id; +	// LLUUID::set is destructive, so use temporary value +	if (temp_id.set(self.mCurReadNode->getSanitizedValue())) +	{ +		*(LLUUID*)(val_ptr) = temp_id; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setStringValue(((LLUUID*)val_ptr)->asString()); +		return true; +	} +	return false; +} + +bool LLXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	*((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue()); +	return true; +} + +bool LLXUIParser::writeSDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); + +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		std::string string_val = ((LLSD*)val_ptr)->asString(); +		if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE) +		{ +			// don't write strings with newlines into attributes +			std::string attribute_name = node->getName()->mString; +			LLXMLNodePtr parent_node = node->mParent; +			parent_node->deleteChild(node); +			// write results in text contents of node +			if (attribute_name == "value") +			{ +				// "value" is implicit, just write to parent +				node = parent_node; +			} +			else +			{ +				node = parent_node->createChild(attribute_name.c_str(), false); +			} +		} + +		node->setStringValue(string_val); +		return true; +	} +	return false; +} + +/*virtual*/ std::string LLXUIParser::getCurrentElementName() +{ +	std::string full_name; +	for (name_stack_t::iterator it = mNameStack.begin();	 +		it != mNameStack.end(); +		++it) +	{ +		full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." +	} + +	return full_name; +} + +void LLXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS +	// use Visual Studo friendly formatting of output message for easy access to originating xml +	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); +	utf16str += '\n'; +	OutputDebugString(utf16str.c_str()); +#else +	Parser::parserWarning(message); +#endif +} + +void LLXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS +	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); +	utf16str += '\n'; +	OutputDebugString(utf16str.c_str()); +#else +	Parser::parserError(message); +#endif +} + + +// +// LLSimpleXUIParser +// + +struct ScopedFile +{ +	ScopedFile( const std::string& filename, const char* accessmode ) +	{ +		mFile = LLFile::fopen(filename, accessmode); +	} + +	~ScopedFile() +	{ +		fclose(mFile); +		mFile = NULL; +	} + +	S32 getRemainingBytes() +	{ +		if (!isOpen()) return 0; + +		S32 cur_pos = ftell(mFile); +		fseek(mFile, 0L, SEEK_END); +		S32 file_size = ftell(mFile); +		fseek(mFile, cur_pos, SEEK_SET); +		return file_size - cur_pos; +	} + +	bool isOpen() { return mFile != NULL; } + +	LLFILE* mFile; +}; +LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t element_cb) +:	Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs), +	mCurReadDepth(0), +	mElementCB(element_cb) +{ +	if (sSimpleXUIReadFuncs.empty()) +	{ +		registerParserFuncs<LLInitParam::Flag>(readFlag); +		registerParserFuncs<bool>(readBoolValue); +		registerParserFuncs<std::string>(readStringValue); +		registerParserFuncs<U8>(readU8Value); +		registerParserFuncs<S8>(readS8Value); +		registerParserFuncs<U16>(readU16Value); +		registerParserFuncs<S16>(readS16Value); +		registerParserFuncs<U32>(readU32Value); +		registerParserFuncs<S32>(readS32Value); +		registerParserFuncs<F32>(readF32Value); +		registerParserFuncs<F64>(readF64Value); +		registerParserFuncs<LLColor4>(readColor4Value); +		registerParserFuncs<LLUIColor>(readUIColorValue); +		registerParserFuncs<LLUUID>(readUUIDValue); +		registerParserFuncs<LLSD>(readSDValue); +	} +} + +LLSimpleXUIParser::~LLSimpleXUIParser() +{ +} + + +bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) +{ +	LLFastTimer timer(FTM_PARSE_XUI); + +	mParser = XML_ParserCreate(NULL); +	XML_SetUserData(mParser, this); +	XML_SetElementHandler(			mParser,	startElementHandler, endElementHandler); +	XML_SetCharacterDataHandler(	mParser,	characterDataHandler); + +	mOutputStack.push_back(std::make_pair(&block, 0)); +	mNameStack.clear(); +	mCurFileName = filename; +	mCurReadDepth = 0; +	setParseSilently(silent); + +	ScopedFile file(filename, "rb"); +	if( !file.isOpen() ) +	{ +		LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; +		XML_ParserFree( mParser ); +		return false; +	} + +	S32 bytes_read = 0; +	 +	S32 buffer_size = file.getRemainingBytes(); +	void* buffer = XML_GetBuffer(mParser, buffer_size); +	if( !buffer )  +	{ +		LL_WARNS("ReadXUI") << "Unable to allocate XML buffer while reading file " << filename << LL_ENDL; +		XML_ParserFree( mParser ); +		return false; +	} + +	bytes_read = (S32)fread(buffer, 1, buffer_size, file.mFile); +	if( bytes_read <= 0 ) +	{ +		LL_WARNS("ReadXUI") << "Error while reading file  " << filename << LL_ENDL; +		XML_ParserFree( mParser ); +		return false; +	} +	 +	mEmptyLeafNode.push_back(false); + +	if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) ) +	{ +		LL_WARNS("ReadXUI") << "Error while parsing file  " << filename << LL_ENDL; +		XML_ParserFree( mParser ); +		return false; +	} + +	mEmptyLeafNode.pop_back(); + +	XML_ParserFree( mParser ); +	return true; +} + +void LLSimpleXUIParser::startElementHandler(void *userData, const char *name, const char **atts) +{ +	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); +	self->startElement(name, atts); +} + +void LLSimpleXUIParser::endElementHandler(void *userData, const char *name) +{ +	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); +	self->endElement(name); +} + +void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int len) +{ +	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); +	self->characterData(s, len); +} + +void LLSimpleXUIParser::characterData(const char *s, int len) +{ +	mTextContents += std::string(s, len); +} + +void LLSimpleXUIParser::startElement(const char *name, const char **atts) +{ +	processText(); + +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> sep("."); + +	if (mElementCB)  +	{ +		LLInitParam::BaseBlock* blockp = mElementCB(*this, name); +		if (blockp) +		{ +			mOutputStack.push_back(std::make_pair(blockp, 0)); +		} +	} + +	mOutputStack.back().second++; +	S32 num_tokens_pushed = 0; +	std::string child_name(name); + +	if (mOutputStack.back().second == 1) +	{	// root node for this block +		mScope.push_back(child_name); +	} +	else +	{	// compound attribute +		if (child_name.find(".") == std::string::npos)  +		{ +			mNameStack.push_back(std::make_pair(child_name, true)); +			num_tokens_pushed++; +			mScope.push_back(child_name); +		} +		else +		{ +			// parse out "dotted" name into individual tokens +			tokenizer name_tokens(child_name, sep); + +			tokenizer::iterator name_token_it = name_tokens.begin(); +			if(name_token_it == name_tokens.end())  +			{ +				return; +			} + +			// check for proper nesting +			if(!mScope.empty() && *name_token_it != mScope.back()) +			{ +				return; +			} + +			// now ignore first token +			++name_token_it;  + +			// copy remaining tokens on to our running token list +			for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) +			{ +				mNameStack.push_back(std::make_pair(*token_to_push, true)); +				num_tokens_pushed++; +			} +			mScope.push_back(mNameStack.back().first); +		} +	} + +	// parent node is not empty +	mEmptyLeafNode.back() = false; +	// we are empty if we have no attributes +	mEmptyLeafNode.push_back(atts[0] == NULL); + +	mTokenSizeStack.push_back(num_tokens_pushed); +	readAttributes(atts); + +} + +void LLSimpleXUIParser::endElement(const char *name) +{ +	bool has_text = processText(); + +	// no text, attributes, or children +	if (!has_text && mEmptyLeafNode.back()) +	{ +		// submit this as a valueless name (even though there might be text contents we haven't seen yet) +		mCurAttributeValueBegin = NO_VALUE_MARKER; +		mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); +	} + +	if (--mOutputStack.back().second == 0) +	{ +		if (mOutputStack.empty()) +		{ +			LL_ERRS("ReadXUI") << "Parameter block output stack popped while empty." << LL_ENDL; +		} +		mOutputStack.pop_back(); +	} + +	S32 num_tokens_to_pop = mTokenSizeStack.back(); +	mTokenSizeStack.pop_back(); +	while(num_tokens_to_pop-- > 0) +	{ +		mNameStack.pop_back(); +	} +	mScope.pop_back(); +	mEmptyLeafNode.pop_back(); +} + +bool LLSimpleXUIParser::readAttributes(const char **atts) +{ +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> sep("."); + +	bool any_parsed = false; +	for(S32 i = 0; atts[i] && atts[i+1]; i += 2 ) +	{ +		std::string attribute_name(atts[i]); +		mCurAttributeValueBegin = atts[i+1]; +		 +		S32 num_tokens_pushed = 0; +		tokenizer name_tokens(attribute_name, sep); +		// copy remaining tokens on to our running token list +		for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) +		{ +			mNameStack.push_back(std::make_pair(*token_to_push, true)); +			num_tokens_pushed++; +		} + +		// child nodes are not necessarily valid attributes, so don't complain once we've recursed +		any_parsed |= mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); +		 +		while(num_tokens_pushed-- > 0) +		{ +			mNameStack.pop_back(); +		} +	} +	return any_parsed; +} + +bool LLSimpleXUIParser::processText() +{ +	if (!mTextContents.empty()) +	{ +		LLStringUtil::trim(mTextContents); +		if (!mTextContents.empty()) +		{ +			mNameStack.push_back(std::make_pair(std::string("value"), true)); +			mCurAttributeValueBegin = mTextContents.c_str(); +			mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); +			mNameStack.pop_back(); +		} +		mTextContents.clear(); +		return true; +	} +	return false; +} + +/*virtual*/ std::string LLSimpleXUIParser::getCurrentElementName() +{ +	std::string full_name; +	for (name_stack_t::iterator it = mNameStack.begin();	 +		it != mNameStack.end(); +		++it) +	{ +		full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." +	} + +	return full_name; +} + +void LLSimpleXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS +	// use Visual Studo friendly formatting of output message for easy access to originating xml +	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str()); +	utf16str += '\n'; +	OutputDebugString(utf16str.c_str()); +#else +	Parser::parserWarning(message); +#endif +} + +void LLSimpleXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS +	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str()); +	utf16str += '\n'; +	OutputDebugString(utf16str.c_str()); +#else +	Parser::parserError(message); +#endif +} + +bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return self.mCurAttributeValueBegin == NO_VALUE_MARKER; +} + +bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	if (!strcmp(self.mCurAttributeValueBegin, "true"))  +	{ +		*((bool*)val_ptr) = true; +		return true; +	} +	else if (!strcmp(self.mCurAttributeValueBegin, "false")) +	{ +		*((bool*)val_ptr) = false; +		return true; +	} + +	return false; +} + +bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	*((std::string*)val_ptr) = self.mCurAttributeValueBegin; +	return true; +} + +bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; +} +	 +bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	LLColor4 value; + +	if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) +	{ +		*(LLColor4*)(val_ptr) = value; +		return true; +	} +	return false; +} + +bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	LLColor4 value; +	LLUIColor* colorp = (LLUIColor*)val_ptr; + +	if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) +	{ +		colorp->set(value); +		return true; +	} +	return false; +} + +bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	LLUUID temp_id; +	// LLUUID::set is destructive, so use temporary value +	if (temp_id.set(std::string(self.mCurAttributeValueBegin))) +	{ +		*(LLUUID*)(val_ptr) = temp_id; +		return true; +	} +	return false; +} + +bool LLSimpleXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	*((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); +	return true; +} diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h new file mode 100644 index 0000000000..d7cd256967 --- /dev/null +++ b/indra/llui/llxuiparser.h @@ -0,0 +1,242 @@ +/**  + * @file llxuiparser.h + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 LLXUIPARSER_H +#define LLXUIPARSER_H + +#include "llinitparam.h" +#include "llregistry.h" +#include "llpointer.h" + +#include <boost/function.hpp> +#include <iosfwd> +#include <stack> +#include <set> + + + +class LLView; + + +typedef LLPointer<class LLXMLNode> LLXMLNodePtr; + + +// lookup widget type by name +class LLWidgetTypeRegistry +:	public LLRegistrySingleton<std::string, const std::type_info*, LLWidgetTypeRegistry> +{}; + + +// global static instance for registering all widget types +typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc; + +typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t; + +class LLChildRegistryRegistry +: public LLRegistrySingleton<const std::type_info*, widget_registry_t, LLChildRegistryRegistry> +{}; + + + +class LLXSDWriter : public LLInitParam::Parser +{ +	LOG_CLASS(LLXSDWriter); +public: +	void writeXSD(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); + +	/*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + +	LLXSDWriter(); + +protected: +	void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values); +	void addAttributeToSchema(LLXMLNodePtr nodep, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values); +	LLXMLNodePtr mAttributeNode; +	LLXMLNodePtr mElementNode; +	LLXMLNodePtr mSchemaNode; + +	typedef std::set<std::string> string_set_t; +	typedef std::map<LLXMLNodePtr, string_set_t> attributes_map_t; +	attributes_map_t	mAttributesWritten; +}; + + + +// NOTE: DOES NOT WORK YET +// should support child widgets for XUI +class LLXUIXSDWriter : public LLXSDWriter +{ +public: +	void writeXSD(const std::string& name, const std::string& path, const LLInitParam::BaseBlock& block); +}; + + +class LLXUIParserImpl; + +class LLXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLXUIParser); + +public: +	LLXUIParser(); +	typedef LLInitParam::Parser::name_stack_t name_stack_t; + +	/*virtual*/ std::string getCurrentElementName(); +	/*virtual*/ void parserWarning(const std::string& message); +	/*virtual*/ void parserError(const std::string& message); + +	void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename = LLStringUtil::null, bool silent=false); +	void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL); + +private: +	bool readXUIImpl(LLXMLNodePtr node, LLInitParam::BaseBlock& block); +	bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + +	//reader helper functions +	static bool readFlag(Parser& parser, void* val_ptr); +	static bool readBoolValue(Parser& parser, void* val_ptr); +	static bool readStringValue(Parser& parser, void* val_ptr); +	static bool readU8Value(Parser& parser, void* val_ptr); +	static bool readS8Value(Parser& parser, void* val_ptr); +	static bool readU16Value(Parser& parser, void* val_ptr); +	static bool readS16Value(Parser& parser, void* val_ptr); +	static bool readU32Value(Parser& parser, void* val_ptr); +	static bool readS32Value(Parser& parser, void* val_ptr); +	static bool readF32Value(Parser& parser, void* val_ptr); +	static bool readF64Value(Parser& parser, void* val_ptr); +	static bool readColor4Value(Parser& parser, void* val_ptr); +	static bool readUIColorValue(Parser& parser, void* val_ptr); +	static bool readUUIDValue(Parser& parser, void* val_ptr); +	static bool readSDValue(Parser& parser, void* val_ptr); + +	//writer helper functions +	static bool writeFlag(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeStringValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeU8Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeS8Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeU16Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeS16Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeU32Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeS32Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeF32Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeF64Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeSDValue(Parser& parser, const void* val_ptr, name_stack_t&); + +	LLXMLNodePtr getNode(name_stack_t& stack); + +private: +	Parser::name_stack_t			mNameStack; +	LLXMLNodePtr					mCurReadNode; +	// Root of the widget XML sub-tree, for example, "line_editor" +	LLXMLNodePtr					mWriteRootNode; +	 +	typedef std::map<std::string, LLXMLNodePtr>	out_nodes_t; +	out_nodes_t						mOutNodes; +	LLXMLNodePtr					mLastWrittenChild; +	S32								mCurReadDepth; +	std::string						mCurFileName; +	std::string						mRootNodeName; +}; + +// LLSimpleXUIParser is a streamlined SAX-based XUI parser that does not support localization  +// or parsing of a tree of independent param blocks, such as child widgets. +// Use this for reading non-localized files that only need a single param block as a result. +// +// NOTE: In order to support nested block parsing, we need callbacks for start element that +// push new blocks contexts on the mScope stack. +// NOTE: To support localization without building a DOM, we need to enforce consistent  +// ordering of child elements from base file to localized diff file.  Then we can use a pair +// of coroutines to perform matching of xml nodes during parsing.  Not sure if the overhead +// of coroutines would offset the gain from SAX parsing +class LLSimpleXUIParserImpl; + +class LLSimpleXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLSimpleXUIParser); +public: +	typedef LLInitParam::Parser::name_stack_t name_stack_t; +	typedef LLInitParam::BaseBlock* (*element_start_callback_t)(LLSimpleXUIParser&, const char* block_name); + +	LLSimpleXUIParser(element_start_callback_t element_cb = NULL); +	virtual ~LLSimpleXUIParser(); + +	/*virtual*/ std::string getCurrentElementName(); +	/*virtual*/ void parserWarning(const std::string& message); +	/*virtual*/ void parserError(const std::string& message); + +	bool readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent=false); + + +private: +	//reader helper functions +	static bool readFlag(Parser&, void* val_ptr); +	static bool readBoolValue(Parser&, void* val_ptr); +	static bool readStringValue(Parser&, void* val_ptr); +	static bool readU8Value(Parser&, void* val_ptr); +	static bool readS8Value(Parser&, void* val_ptr); +	static bool readU16Value(Parser&, void* val_ptr); +	static bool readS16Value(Parser&, void* val_ptr); +	static bool readU32Value(Parser&, void* val_ptr); +	static bool readS32Value(Parser&, void* val_ptr); +	static bool readF32Value(Parser&, void* val_ptr); +	static bool readF64Value(Parser&, void* val_ptr); +	static bool readColor4Value(Parser&, void* val_ptr); +	static bool readUIColorValue(Parser&, void* val_ptr); +	static bool readUUIDValue(Parser&, void* val_ptr); +	static bool readSDValue(Parser&, void* val_ptr); + +private: +	static void startElementHandler(void *userData, const char *name, const char **atts); +	static void endElementHandler(void *userData, const char *name); +	static void characterDataHandler(void *userData, const char *s, int len); + +	void startElement(const char *name, const char **atts); +	void endElement(const char *name); +	void characterData(const char *s, int len); +	bool readAttributes(const char **atts); +	bool processText(); + +	Parser::name_stack_t			mNameStack; +	struct XML_ParserStruct*		mParser; +	LLXMLNodePtr					mLastWrittenChild; +	S32								mCurReadDepth; +	std::string						mCurFileName; +	std::string						mTextContents; +	const char*						mCurAttributeValueBegin; +	std::vector<S32>				mTokenSizeStack; +	std::vector<std::string>		mScope; +	std::vector<bool>				mEmptyLeafNode; +	element_start_callback_t		mElementCB; + +	std::vector<std::pair<LLInitParam::BaseBlock*, S32> > mOutputStack; +}; + + +#endif //LLXUIPARSER_H diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index c75df86891..cb3b7abb14 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -105,28 +105,6 @@ LLStyle::Params::Params()  namespace LLInitParam  { -	Param::Param(BaseBlock* enclosing_block) -	:	mIsProvided(false) -	{ -		const U8* my_addr = reinterpret_cast<const U8*>(this); -		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); -		mEnclosingBlockOffset = (U16)(my_addr - block_addr); -	} - -	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){} -	void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} -	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} -	 -	void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) -	{ -		descriptor.mCurrentBlockPtr = this; -	} -	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } -	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {} -	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_value, S32 max_value) const { return true; } -	bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } -	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } -  	ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)  	:	super_t(color)  	{} diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index c1fb050206..8f0a48018f 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -70,21 +70,6 @@ S32 LLUIImage::getHeight() const  	return 0;  } -namespace LLInitParam -{ -	BlockDescriptor::BlockDescriptor() {} -	ParamDescriptor::ParamDescriptor(param_handle_t p,  -						merge_func_t merge_func,  -						deserialize_func_t deserialize_func,  -						serialize_func_t serialize_func, -						validation_func_t validation_func, -						inspect_func_t inspect_func, -						S32 min_count, -						S32 max_count){} -	ParamDescriptor::~ParamDescriptor() {} - -} -  namespace tut  {  	struct LLUrlEntryData diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp index 7183413463..963473c92a 100644 --- a/indra/llui/tests/llurlmatch_test.cpp +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -63,40 +63,6 @@ S32 LLUIImage::getHeight() const  namespace LLInitParam  { -	BlockDescriptor::BlockDescriptor() {} -	ParamDescriptor::ParamDescriptor(param_handle_t p,  -						merge_func_t merge_func,  -						deserialize_func_t deserialize_func,  -						serialize_func_t serialize_func, -						validation_func_t validation_func, -						inspect_func_t inspect_func, -						S32 min_count, -						S32 max_count){} -	ParamDescriptor::~ParamDescriptor() {} - -	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){} -	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} -	void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} - -	void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) -	{ -		descriptor.mCurrentBlockPtr = this; -	} - -	Param::Param(BaseBlock* enclosing_block) -	:	mIsProvided(false) -	{ -		const U8* my_addr = reinterpret_cast<const U8*>(this); -		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); -		mEnclosingBlockOffset = 0x7FFFffff & ((U32)(my_addr - block_addr)); -	} - -	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } -	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {} -	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const { return true; } -	bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } -	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } -  	ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)  	:	super_t(color)  	{}  | 
